From 966dc11fcc48866a24d9b3fd16eeebb3f5e05931 Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Fri, 6 May 2005 05:25:00 -0700 Subject: [PATCH 001/155] [IA64] Fix stack placement when INIT hits in kernel mode. Without this patch, the stack is placed _below_ the current task structure, which is risky at best. Tony, I think this patch needs to go into 2.6.12, since it fixes a real bug. Without it, INIT may case secondary errors, which would be most unpleasant. Signed-off-by: David Mosberger-Tang Signed-off-by: Tony Luck --- arch/ia64/kernel/minstate.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h index 1dbc7b2497c9..f6d8a010d99b 100644 --- a/arch/ia64/kernel/minstate.h +++ b/arch/ia64/kernel/minstate.h @@ -41,7 +41,7 @@ (pKStk) addl r3=THIS_CPU(ia64_mca_data),r3;; \ (pKStk) ld8 r3 = [r3];; \ (pKStk) addl r3=IA64_MCA_CPU_INIT_STACK_OFFSET,r3;; \ -(pKStk) addl sp=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r3; \ +(pKStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r3; \ (pUStk) mov ar.rsc=0; /* set enforced lazy mode, pl 0, little-endian, loadrs=0 */ \ (pUStk) addl r22=IA64_RBS_OFFSET,r1; /* compute base of register backing store */ \ ;; \ @@ -50,7 +50,6 @@ (pUStk) mov r23=ar.bspstore; /* save ar.bspstore */ \ (pUStk) dep r22=-1,r22,61,3; /* compute kernel virtual addr of RBS */ \ ;; \ -(pKStk) addl r1=-IA64_PT_REGS_SIZE,r1; /* if in kernel mode, use sp (r12) */ \ (pUStk) mov ar.bspstore=r22; /* switch to kernel RBS */ \ ;; \ (pUStk) mov r18=ar.bsp; \ From 66302f211a21bb9439a2ae7f7b6a4c386bb10ecd Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Tue, 12 Apr 2005 11:04:00 -0700 Subject: [PATCH 002/155] [IA64] fix "section mismatch" compile-time-error I noticed this typo when trying to compile a kernel which had CONFIG_HOTPLUG turned off. In that case, __devinit is no longer a no-op and the compiler then detects a section-conflict. Fix by using __devinitdata instead of __devinit. Same patch also submitted by Darren Williams to fix compilation error using sim_defconfig (which has CONFIG_HOTPLUG=n). Signed-off-by: David Mosberger-Tang Signed-off-by: Darren Williams Signed-off-by: Tony Luck --- arch/ia64/kernel/smpboot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 0d5ee57c9865..3865f088ffa2 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -624,7 +624,7 @@ static struct { __u16 thread_id; __u16 proc_fixed_addr; __u8 valid; -}mt_info[NR_CPUS] __devinit; +} mt_info[NR_CPUS] __devinitdata; #ifdef CONFIG_HOTPLUG_CPU static inline void From bfd68594082d8384781c242aa72a7950b5cf51aa Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Wed, 4 May 2005 06:42:00 -0700 Subject: [PATCH 003/155] [IA64] Avoid .spillpsp directive in handcoded assembly Some time ago, GAS was fixed to bring the .spillpsp directive in line with the Intel assembler manual (there was some disagreement as to whether or not there is a built-in 16-byte offset). Unfortunately, there are two places in the kernel where this directive is used in handwritten assembly files and those of course relied on the "buggy" behavior. As a result, when using a "fixed" assembler, the kernel picks up the UNaT bits from the wrong place (off by 16) and randomly sets NaT bits on the scratch registers. This can be noticed easily by looking at a coredump and finding various scratch registers with unexpected NaT values. The patch below fixes this by using the .spillsp directive instead, which works correctly no matter what assembler is in use. Signed-off-by: David Mosberger-Tang Signed-off-by: Tony Luck --- arch/ia64/kernel/entry.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 81c45d447394..d99316c9be28 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -1182,7 +1182,7 @@ ENTRY(notify_resume_user) ;; (pNonSys) mov out2=0 // out2==0 => not a syscall .fframe 16 - .spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!) + .spillsp ar.unat, 16 st8 [sp]=r9,-16 // allocate space for ar.unat and save it st8 [out1]=loc1,-8 // save ar.pfs, out1=&sigscratch .body @@ -1208,7 +1208,7 @@ GLOBAL_ENTRY(sys_rt_sigsuspend) adds out2=8,sp // out2=&sigscratch->ar_pfs ;; .fframe 16 - .spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!) + .spillsp ar.unat, 16 st8 [sp]=r9,-16 // allocate space for ar.unat and save it st8 [out2]=loc1,-8 // save ar.pfs, out2=&sigscratch .body From 67594feb4b68074d8807f5566536e06db9130679 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 17 May 2005 13:04:49 -0500 Subject: [PATCH 004/155] [CIFS] missing break needed to handle < when mount option "mapchars" specified Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/README | 4 ++-- fs/cifs/misc.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/cifs/README b/fs/cifs/README index e74df0c73256..34b0cf7111f3 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -371,7 +371,7 @@ A partial list of the supported mount options follows: on newly created files, directories, and devices (create, mkdir, mknod) which will result in the server setting the uid and gid to the default (usually the server uid of the - usern who mounted the share). Letting the server (rather than + user who mounted the share). Letting the server (rather than the client) set the uid and gid is the default. This parameter has no effect if the CIFS Unix Extensions are not negotiated. @@ -384,7 +384,7 @@ A partial list of the supported mount options follows: client (e.g. when the application is doing large sequential reads bigger than page size without rereading the same data) this can provide better performance than the default - behavior which caches reads (reaadahead) and writes + behavior which caches reads (readahead) and writes (writebehind) through the local Linux client pagecache if oplock (caching token) is granted and held. Note that direct allows write operations larger than page size diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index db14b503d89e..072b4ee8c53e 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -571,6 +571,7 @@ cifs_convertUCSpath(char *target, const __le16 * source, int maxlen, break; case UNI_LESSTHAN: target[j] = '<'; + break; default: len = cp->uni2char(src_char, &target[j], NLS_MAX_CHARSET_SIZE); From b2aeb9d565be5ef00fb9f921c6d2459c74d90cdf Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 17 May 2005 13:16:18 -0500 Subject: [PATCH 005/155] [CIFS] Fix oops in cifs_unlink. Caused in some cases when renaming over existing, newly created, file. Samba bugzilla: 2697 Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/dir.c | 3 ++- fs/cifs/inode.c | 24 +++++++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index e3137aa48cdd..3f3538d4a1fa 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -392,7 +392,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name rc = 0; d_add(direntry, NULL); } else { - cERROR(1,("Error 0x%x or on cifs_get_inode_info in lookup",rc)); + cERROR(1,("Error 0x%x on cifs_get_inode_info in lookup of %s", + rc,full_path)); /* BB special case check for Access Denied - watch security exposure of returning dir info implicitly via different rc if file exists or not but no access BB */ diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 670947288262..b8b78cbb34c9 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -422,7 +422,8 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { - direntry->d_inode->i_nlink--; + if(direntry->d_inode) + direntry->d_inode->i_nlink--; } else if (rc == -ENOENT) { d_drop(direntry); } else if (rc == -ETXTBSY) { @@ -440,7 +441,8 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, netfid); - direntry->d_inode->i_nlink--; + if(direntry->d_inode) + direntry->d_inode->i_nlink--; } } else if (rc == -EACCES) { /* try only if r/o attribute set in local lookup data? */ @@ -494,7 +496,8 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (!rc) { - direntry->d_inode->i_nlink--; + if(direntry->d_inode) + direntry->d_inode->i_nlink--; } else if (rc == -ETXTBSY) { int oplock = FALSE; __u16 netfid; @@ -514,17 +517,20 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); CIFSSMBClose(xid, pTcon, netfid); - direntry->d_inode->i_nlink--; + if(direntry->d_inode) + direntry->d_inode->i_nlink--; } /* BB if rc = -ETXTBUSY goto the rename logic BB */ } } } - cifsInode = CIFS_I(direntry->d_inode); - cifsInode->time = 0; /* will force revalidate to get info when - needed */ - direntry->d_inode->i_ctime = inode->i_ctime = inode->i_mtime = - current_fs_time(inode->i_sb); + if(direntry->d_inode) { + cifsInode = CIFS_I(direntry->d_inode); + cifsInode->time = 0; /* will force revalidate to get info + when needed */ + direntry->d_inode->i_ctime = current_fs_time(inode->i_sb); + } + inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb); cifsInode = CIFS_I(inode); cifsInode->time = 0; /* force revalidate of dir as well */ From 02a017a9f37ae6842e065da919b5952eb847e869 Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Tue, 10 May 2005 11:35:00 -0700 Subject: [PATCH 006/155] [IA64] Correct convert_to_non_syscall() convert_to_non_syscall() has the same problem that unwind_to_user() used to have. Fix it likewise. Signed-off-by: David Mosberger-Tang Signed-off-by: Tony Luck --- arch/ia64/kernel/ptrace.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 907464ee7273..08c8a5eb25ab 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -692,16 +692,30 @@ convert_to_non_syscall (struct task_struct *child, struct pt_regs *pt, unsigned long cfm) { struct unw_frame_info info, prev_info; - unsigned long ip, pr; + unsigned long ip, sp, pr; unw_init_from_blocked_task(&info, child); while (1) { prev_info = info; if (unw_unwind(&info) < 0) return; - if (unw_get_rp(&info, &ip) < 0) + + unw_get_sp(&info, &sp); + if ((long)((unsigned long)child + IA64_STK_OFFSET - sp) + < IA64_PT_REGS_SIZE) { + dprintk("ptrace.%s: ran off the top of the kernel " + "stack\n", __FUNCTION__); return; - if (ip < FIXADDR_USER_END) + } + if (unw_get_pr (&prev_info, &pr) < 0) { + unw_get_rp(&prev_info, &ip); + dprintk("ptrace.%s: failed to read " + "predicate register (ip=0x%lx)\n", + __FUNCTION__, ip); + return; + } + if (unw_is_intr_frame(&info) + && (pr & (1UL << PRED_USER_STACK))) break; } From 056b5033fb8d16095fb074fc910fad90186374f3 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 9 May 2005 14:52:00 -0700 Subject: [PATCH 007/155] [PATCH] update sn2 maintainer Now that I'm no longer at SGI and don't have access to Altix equipment, it's time to pass on the job of patch monkey to someone else. Greg Edwards has foolishly^Wkindly volunteered for the job, so here's a patch to update the MAINTAINERS file with the appropriate information. Signed-off-by: Jesse Barnes Signed-off-by: Tony Luck --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5b8483334de1..97bc927d2c55 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1023,8 +1023,8 @@ W: http://www.ia64-linux.org/ S: Maintained SN-IA64 (Itanium) SUB-PLATFORM -P: Jesse Barnes -M: jbarnes@sgi.com +P: Greg Edwards +M: edwardsg@sgi.com L: linux-altix@sgi.com L: linux-ia64@vger.kernel.org W: http://www.sgi.com/altix From bb68c12b40c3c745381d7ce61d7b2e371f157505 Mon Sep 17 00:00:00 2001 From: Russ Anderson <(rja@sgi.com)> Date: Mon, 9 May 2005 15:03:00 -0700 Subject: [PATCH 008/155] [IA64-SGI] cpe interrupts are not being enabled. acpi_request_vector() is called in ia64_mca_init() to get the cpe_vector. The problem is that acpi_request_vector() looks in platform_intr_list[] to get the vector, but platform_intr_list[] is not initialized with a valid vector until later (in sn_setup()). Without a valid vector the code defaults to polling mode. This patch moves the call to acpi_request_vector() from ia64_mca_init() to ia64_mca_late_init(), which is after platform_intr_list[] is initialized. Signed-off-by: Russ Anderson (rja@sgi.com) Signed-off-by: Tony Luck --- arch/ia64/kernel/mca.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c index 4d6c7b8f667b..2c75741dcc66 100644 --- a/arch/ia64/kernel/mca.c +++ b/arch/ia64/kernel/mca.c @@ -1390,8 +1390,7 @@ ia64_mca_init(void) register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction); #ifdef CONFIG_ACPI - /* Setup the CPEI/P vector and handler */ - cpe_vector = acpi_request_vector(ACPI_INTERRUPT_CPEI); + /* Setup the CPEI/P handler */ register_percpu_irq(IA64_CPEP_VECTOR, &mca_cpep_irqaction); #endif @@ -1436,6 +1435,7 @@ ia64_mca_late_init(void) #ifdef CONFIG_ACPI /* Setup the CPEI/P vector and handler */ + cpe_vector = acpi_request_vector(ACPI_INTERRUPT_CPEI); init_timer(&cpe_poll_timer); cpe_poll_timer.function = ia64_mca_cpe_poll; From 8eac3757158ccd9c6b43f44f228a5762fec33781 Mon Sep 17 00:00:00 2001 From: Russ Anderson <(rja@sgi.com)> Date: Mon, 16 May 2005 15:19:00 -0700 Subject: [PATCH 009/155] [IA64-SGI] Make Altix SAL call to POD reentrant Change the SAL call for POD mode to be reentrant. This change is SN specific. Signed-off-by: Russ Anderson (rja@sgi.com) Signed-off-by: Tony Luck --- include/asm-ia64/sn/sn_sal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index 56d74ca76b5d..94cc5392533a 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -472,7 +472,7 @@ static inline u64 ia64_sn_pod_mode(void) { struct ia64_sal_retval isrv; - SAL_CALL(isrv, SN_SAL_POD_MODE, 0, 0, 0, 0, 0, 0, 0); + SAL_CALL_REENTRANT(isrv, SN_SAL_POD_MODE, 0, 0, 0, 0, 0, 0, 0); if (isrv.status) return 0; return isrv.v0; From 6872ec548970e9fb3ccd61013f84f9bb8b30fa9a Mon Sep 17 00:00:00 2001 From: Russ Anderson <(rja@sgi.com)> Date: Mon, 16 May 2005 15:30:00 -0700 Subject: [PATCH 010/155] [IS64-SGI] Set Altix error handling features The 2.6 kernel has CPE error thresholding. This patch lets SAL know of this error handling feature. The changes are SN specific. Signed-off-by: Russ Anderson (rja@sgi.com) Signed-off-by: Tony Luck --- arch/ia64/sn/kernel/setup.c | 2 ++ include/asm-ia64/sn/sn_sal.h | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index 4fb44984afe6..e64cb8175f7a 100644 --- a/arch/ia64/sn/kernel/setup.c +++ b/arch/ia64/sn/kernel/setup.c @@ -271,6 +271,8 @@ void __init sn_setup(char **cmdline_p) int major = sn_sal_rev_major(), minor = sn_sal_rev_minor(); extern void sn_cpu_init(void); + ia64_sn_plat_set_error_handling_features(); + /* * If the generic code has enabled vga console support - lets * get rid of it again. This is a kludge for the fact that ACPI diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h index 94cc5392533a..eb0395ad0d6a 100644 --- a/include/asm-ia64/sn/sn_sal.h +++ b/include/asm-ia64/sn/sn_sal.h @@ -115,6 +115,13 @@ #define SAL_IROUTER_INTR_XMIT SAL_CONSOLE_INTR_XMIT #define SAL_IROUTER_INTR_RECV SAL_CONSOLE_INTR_RECV +/* + * Error Handling Features + */ +#define SAL_ERR_FEAT_MCA_SLV_TO_OS_INIT_SLV 0x1 +#define SAL_ERR_FEAT_LOG_SBES 0x2 +#define SAL_ERR_FEAT_MFR_OVERRIDE 0x4 +#define SAL_ERR_FEAT_SBE_THRESHOLD 0xffff0000 /* * SAL Error Codes @@ -341,6 +348,25 @@ ia64_sn_plat_cpei_handler(void) return ret_stuff.status; } +/* + * Set Error Handling Features + */ +static inline u64 +ia64_sn_plat_set_error_handling_features(void) +{ + struct ia64_sal_retval ret_stuff; + + ret_stuff.status = 0; + ret_stuff.v0 = 0; + ret_stuff.v1 = 0; + ret_stuff.v2 = 0; + SAL_CALL_REENTRANT(ret_stuff, SN_SAL_SET_ERROR_HANDLING_FEATURES, + (SAL_ERR_FEAT_MCA_SLV_TO_OS_INIT_SLV | SAL_ERR_FEAT_LOG_SBES), + 0, 0, 0, 0, 0, 0); + + return ret_stuff.status; +} + /* * Checks for console input. */ From b1a45695bde0204597957e448923f09ce271ca80 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 17 May 2005 16:07:23 -0500 Subject: [PATCH 011/155] [CIFS] fix casts of unicode strings to match function definition Signed-off-by: Steve French (sfrench@us.ibm.com) --- fs/cifs/cifsproto.h | 2 +- fs/cifs/cifssmb.c | 56 ++++++++++++++++++++++----------------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 0010511083fc..ea239dea571e 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -228,7 +228,7 @@ extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const struct nls_table *nls_codepage, int remap_special_chars); #endif /* CONFIG_CIFS_EXPERIMENTAL */ -extern int cifs_convertUCSpath(char *target, const __u16 *source, int maxlen, +extern int cifs_convertUCSpath(char *target, const __le16 *source, int maxlen, const struct nls_table * codepage); extern int cifsConvertToUCS(__le16 * target, const char *source, int maxlen, const struct nls_table * cp, int mapChars); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 741ff0c69f37..3c628bf667a5 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -567,7 +567,7 @@ DelFileRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->fileName, fileName, + cifsConvertToUCS((__le16 *) pSMB->fileName, fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -665,7 +665,7 @@ MkDirRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUCS((__u16 *) pSMB->DirName, name, + name_len = cifsConvertToUCS((__le16 *) pSMB->DirName, name, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -719,7 +719,7 @@ openRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { count = 1; /* account for one byte pad to word boundary */ name_len = - cifsConvertToUCS((__u16 *) (pSMB->fileName + 1), + cifsConvertToUCS((__le16 *) (pSMB->fileName + 1), fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -1141,7 +1141,7 @@ renameRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->OldFileName, fromName, + cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -1149,7 +1149,7 @@ renameRetry: /* protocol requires ASCII signature byte on Unicode string */ pSMB->OldFileName[name_len + 1] = 0x00; name_len2 = - cifsConvertToUCS((__u16 *) &pSMB->OldFileName[name_len + 2], + cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2], toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ @@ -1236,10 +1236,10 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, /* unicode only call */ if(target_name == NULL) { sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid); - len_of_str = cifsConvertToUCS((__u16 *)rename_info->target_name, + len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name, dummy_string, 24, nls_codepage, remap); } else { - len_of_str = cifsConvertToUCS((__u16 *)rename_info->target_name, + len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name, target_name, PATH_MAX, nls_codepage, remap); } rename_info->target_name_len = cpu_to_le32(2 * len_of_str); @@ -1296,7 +1296,7 @@ copyRetry: pSMB->Flags = cpu_to_le16(flags & COPY_TREE); if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUCS((__u16 *) pSMB->OldFileName, + name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ @@ -1304,7 +1304,7 @@ copyRetry: pSMB->OldFileName[name_len] = 0x04; /* pad */ /* protocol requires ASCII signature byte on Unicode string */ pSMB->OldFileName[name_len + 1] = 0x00; - name_len2 = cifsConvertToUCS((__u16 *)&pSMB->OldFileName[name_len + 2], + name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ @@ -1453,7 +1453,7 @@ createHardLinkRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { - name_len = cifsConvertToUCS((__u16 *) pSMB->FileName, toName, + name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -1476,7 +1476,7 @@ createHardLinkRetry: data_offset = (char *) (&pSMB->hdr.Protocol) + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = - cifsConvertToUCS((__u16 *) data_offset, fromName, PATH_MAX, + cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX, nls_codepage, remap); name_len_target++; /* trailing null */ name_len_target *= 2; @@ -1546,14 +1546,14 @@ winCreateHardLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->OldFileName, fromName, + cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; pSMB->OldFileName[name_len] = 0; /* pad */ pSMB->OldFileName[name_len + 1] = 0x04; name_len2 = - cifsConvertToUCS((__u16 *)&pSMB->OldFileName[name_len + 2], + cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], toName, PATH_MAX, nls_codepage, remap); name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ; name_len2 *= 2; /* convert to bytes */ @@ -1939,7 +1939,7 @@ queryAclRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -2024,7 +2024,7 @@ setAclRetry: return rc; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -2188,7 +2188,7 @@ QPathInfoRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -2269,7 +2269,7 @@ UnixQPathInfoRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -2350,7 +2350,7 @@ findUniqueRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX + cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len++; /* trailing null */ @@ -2435,7 +2435,7 @@ findFirstRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName,searchName, + cifsConvertToUCS((__le16 *) pSMB->FileName,searchName, PATH_MAX, nls_codepage, remap); /* We can not add the asterik earlier in case it got remapped to 0xF03A as if it were part of the @@ -2726,7 +2726,7 @@ GetInodeNumberRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX,nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -2837,7 +2837,7 @@ getDFSRetry: if (ses->capabilities & CAP_UNICODE) { pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; name_len = - cifsConvertToUCS((__u16 *) pSMB->RequestFileName, + cifsConvertToUCS((__le16 *) pSMB->RequestFileName, searchName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -3369,7 +3369,7 @@ SetEOFRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -3627,7 +3627,7 @@ SetTimesRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -3708,7 +3708,7 @@ SetAttrLgcyRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - ConvertToUCS((wchar_t *) pSMB->fileName, fileName, + ConvertToUCS((__le16 *) pSMB->fileName, fileName, PATH_MAX, nls_codepage); name_len++; /* trailing null */ name_len *= 2; @@ -3759,7 +3759,7 @@ setPermsRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -3904,7 +3904,7 @@ QAllEAsRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((wchar_t *) pSMB->FileName, searchName, + cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -4047,7 +4047,7 @@ QEARetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, searchName, + cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; @@ -4194,7 +4194,7 @@ SetEARetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifsConvertToUCS((__u16 *) pSMB->FileName, fileName, + cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, PATH_MAX, nls_codepage, remap); name_len++; /* trailing null */ name_len *= 2; From a1ecf7f6e65637ba4470405ad39794710dbf85d4 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Wed, 18 May 2005 16:06:00 -0700 Subject: [PATCH 012/155] [IA64] alternate perfmon handler Patch from Charles Spirakis Some linux customers want to optimize their applications on the latest hardware but are not yet willing to upgrade to the latest kernel. This patch provides a way to plug in an alternate, basic, and GPL'ed PMU subsystem to help with their monitoring needs or for specialty work. It can also be used in case of serious unexpected bugs in perfmon. Mutual exclusion between the two subsystems is guaranteed, hence no conflict can arise from both subsystem being present. Acked-by: Stephane Eranian Signed-off-by: Tony Luck --- arch/ia64/kernel/perfmon.c | 175 +++++++++++++++++++++++++++++++++---- include/asm-ia64/perfmon.h | 8 ++ 2 files changed, 168 insertions(+), 15 deletions(-) diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 71c101601e3e..ab9682f8b044 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -11,7 +11,7 @@ * Version Perfmon-2.x is a rewrite of perfmon-1.x * by Stephane Eranian, Hewlett Packard Co. * - * Copyright (C) 1999-2003, 2005 Hewlett Packard Co + * Copyright (C) 1999-2005 Hewlett Packard Co * Stephane Eranian * David Mosberger-Tang * @@ -497,6 +497,9 @@ typedef struct { static pfm_stats_t pfm_stats[NR_CPUS]; static pfm_session_t pfm_sessions; /* global sessions information */ +static spinlock_t pfm_alt_install_check; +static pfm_intr_handler_desc_t *pfm_alt_intr_handler; + static struct proc_dir_entry *perfmon_dir; static pfm_uuid_t pfm_null_uuid = {0,}; @@ -606,6 +609,7 @@ DEFINE_PER_CPU(unsigned long, pfm_syst_info); DEFINE_PER_CPU(struct task_struct *, pmu_owner); DEFINE_PER_CPU(pfm_context_t *, pmu_ctx); DEFINE_PER_CPU(unsigned long, pmu_activation_number); +EXPORT_SYMBOL_GPL(per_cpu__pfm_syst_info); /* forward declaration */ @@ -1325,7 +1329,7 @@ pfm_reserve_session(struct task_struct *task, int is_syswide, unsigned int cpu) error_conflict: DPRINT(("system wide not possible, conflicting session [%d] on CPU%d\n", pfm_sessions.pfs_sys_session[cpu]->pid, - smp_processor_id())); + cpu)); abort: UNLOCK_PFS(flags); @@ -5555,26 +5559,32 @@ pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs) int ret; this_cpu = get_cpu(); - min = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min; - max = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max; + if (likely(!pfm_alt_intr_handler)) { + min = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min; + max = pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max; - start_cycles = ia64_get_itc(); + start_cycles = ia64_get_itc(); - ret = pfm_do_interrupt_handler(irq, arg, regs); + ret = pfm_do_interrupt_handler(irq, arg, regs); - total_cycles = ia64_get_itc(); + total_cycles = ia64_get_itc(); - /* - * don't measure spurious interrupts - */ - if (likely(ret == 0)) { - total_cycles -= start_cycles; + /* + * don't measure spurious interrupts + */ + if (likely(ret == 0)) { + total_cycles -= start_cycles; - if (total_cycles < min) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min = total_cycles; - if (total_cycles > max) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max = total_cycles; + if (total_cycles < min) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_min = total_cycles; + if (total_cycles > max) pfm_stats[this_cpu].pfm_ovfl_intr_cycles_max = total_cycles; - pfm_stats[this_cpu].pfm_ovfl_intr_cycles += total_cycles; + pfm_stats[this_cpu].pfm_ovfl_intr_cycles += total_cycles; + } } + else { + (*pfm_alt_intr_handler->handler)(irq, arg, regs); + } + put_cpu_no_resched(); return IRQ_HANDLED; } @@ -6425,6 +6435,141 @@ static struct irqaction perfmon_irqaction = { .name = "perfmon" }; +static void +pfm_alt_save_pmu_state(void *data) +{ + struct pt_regs *regs; + + regs = ia64_task_regs(current); + + DPRINT(("called\n")); + + /* + * should not be necessary but + * let's take not risk + */ + pfm_clear_psr_up(); + pfm_clear_psr_pp(); + ia64_psr(regs)->pp = 0; + + /* + * This call is required + * May cause a spurious interrupt on some processors + */ + pfm_freeze_pmu(); + + ia64_srlz_d(); +} + +void +pfm_alt_restore_pmu_state(void *data) +{ + struct pt_regs *regs; + + regs = ia64_task_regs(current); + + DPRINT(("called\n")); + + /* + * put PMU back in state expected + * by perfmon + */ + pfm_clear_psr_up(); + pfm_clear_psr_pp(); + ia64_psr(regs)->pp = 0; + + /* + * perfmon runs with PMU unfrozen at all times + */ + pfm_unfreeze_pmu(); + + ia64_srlz_d(); +} + +int +pfm_install_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl) +{ + int ret, i; + int reserve_cpu; + + /* some sanity checks */ + if (hdl == NULL || hdl->handler == NULL) return -EINVAL; + + /* do the easy test first */ + if (pfm_alt_intr_handler) return -EBUSY; + + /* one at a time in the install or remove, just fail the others */ + if (!spin_trylock(&pfm_alt_install_check)) { + return -EBUSY; + } + + /* reserve our session */ + for_each_online_cpu(reserve_cpu) { + ret = pfm_reserve_session(NULL, 1, reserve_cpu); + if (ret) goto cleanup_reserve; + } + + /* save the current system wide pmu states */ + ret = on_each_cpu(pfm_alt_save_pmu_state, NULL, 0, 1); + if (ret) { + DPRINT(("on_each_cpu() failed: %d\n", ret)); + goto cleanup_reserve; + } + + /* officially change to the alternate interrupt handler */ + pfm_alt_intr_handler = hdl; + + spin_unlock(&pfm_alt_install_check); + + return 0; + +cleanup_reserve: + for_each_online_cpu(i) { + /* don't unreserve more than we reserved */ + if (i >= reserve_cpu) break; + + pfm_unreserve_session(NULL, 1, i); + } + + spin_unlock(&pfm_alt_install_check); + + return ret; +} +EXPORT_SYMBOL_GPL(pfm_install_alt_pmu_interrupt); + +int +pfm_remove_alt_pmu_interrupt(pfm_intr_handler_desc_t *hdl) +{ + int i; + int ret; + + if (hdl == NULL) return -EINVAL; + + /* cannot remove someone else's handler! */ + if (pfm_alt_intr_handler != hdl) return -EINVAL; + + /* one at a time in the install or remove, just fail the others */ + if (!spin_trylock(&pfm_alt_install_check)) { + return -EBUSY; + } + + pfm_alt_intr_handler = NULL; + + ret = on_each_cpu(pfm_alt_restore_pmu_state, NULL, 0, 1); + if (ret) { + DPRINT(("on_each_cpu() failed: %d\n", ret)); + } + + for_each_online_cpu(i) { + pfm_unreserve_session(NULL, 1, i); + } + + spin_unlock(&pfm_alt_install_check); + + return 0; +} +EXPORT_SYMBOL_GPL(pfm_remove_alt_pmu_interrupt); + /* * perfmon initialization routine, called from the initcall() table */ diff --git a/include/asm-ia64/perfmon.h b/include/asm-ia64/perfmon.h index ed5416c5b1ac..7f3333dd00e4 100644 --- a/include/asm-ia64/perfmon.h +++ b/include/asm-ia64/perfmon.h @@ -177,6 +177,10 @@ typedef union { extern long perfmonctl(int fd, int cmd, void *arg, int narg); +typedef struct { + void (*handler)(int irq, void *arg, struct pt_regs *regs); +} pfm_intr_handler_desc_t; + extern void pfm_save_regs (struct task_struct *); extern void pfm_load_regs (struct task_struct *); @@ -187,6 +191,10 @@ extern void pfm_syst_wide_update_task(struct task_struct *, unsigned long info, extern void pfm_inherit(struct task_struct *task, struct pt_regs *regs); extern void pfm_init_percpu(void); extern void pfm_handle_work(void); +extern int pfm_install_alt_pmu_interrupt(pfm_intr_handler_desc_t *h); +extern int pfm_remove_alt_pmu_interrupt(pfm_intr_handler_desc_t *h); + + /* * Reset PMD register flags From fe12e25ebdd195a57d3fd655061fd2525609b16b Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Wed, 18 May 2005 17:09:06 -0700 Subject: [PATCH 013/155] [IA64] initialize spinlock pfm_alt_install_check I applied the penultimate version of the perfmon patch, which didn't have the initialization of the new spinlock that was added. Signed-off-by: Tony Luck --- arch/ia64/kernel/perfmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index ab9682f8b044..0e58ec7db128 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -497,7 +497,7 @@ typedef struct { static pfm_stats_t pfm_stats[NR_CPUS]; static pfm_session_t pfm_sessions; /* global sessions information */ -static spinlock_t pfm_alt_install_check; +static spinlock_t pfm_alt_install_check = SPIN_LOCK_UNLOCKED; static pfm_intr_handler_desc_t *pfm_alt_intr_handler; static struct proc_dir_entry *perfmon_dir; From d11cf326bd5e785cc5a3f5a3d3f4e3a5522f4fb7 Mon Sep 17 00:00:00 2001 From: Zhang Yanmin Date: Sun, 22 May 2005 17:47:00 -0700 Subject: [PATCH 014/155] [IA64] sys_mmap doesn't follow posix.1 when parameter len=0 In IA64 kernel, sys_mmap calls do_mmap2 and do_mmap2 returns addr if len=0, which means the mmap sys call succeeds. Posix.1 says: The mmap() function shall fail if: [EINVAL] The value of len is zero. Here is a patch to fix it. Signed-off-by: Zhang Yanmin Acked-by: David Mosberger Signed-off-by: Tony Luck --- arch/ia64/kernel/sys_ia64.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c index a8cf6d8a509c..770fab37928e 100644 --- a/arch/ia64/kernel/sys_ia64.c +++ b/arch/ia64/kernel/sys_ia64.c @@ -182,13 +182,6 @@ do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, un } } - /* - * A zero mmap always succeeds in Linux, independent of whether or not the - * remaining arguments are valid. - */ - if (len == 0) - goto out; - /* Careful about overflows.. */ len = PAGE_ALIGN(len); if (!len || len > TASK_SIZE) { From aa8f0dc6c3dbf1cf3ff58f3e945c981be134814d Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 26 May 2005 21:54:27 -0400 Subject: [PATCH 015/155] libata: Fix use-after-iounmap Jens Axboe pointed out that the iounmap() call in libata was occurring too early, and some drivers (ahci, probably others) were using ioremap'd memory after it had been unmapped. The patch should address that problem by way of improving the libata driver API: * move ->host_stop() call after all ->port_stop() calls have occurred. * create default helper function ata_host_stop(), and move iounmap() call there. * add ->host_stop_prewalk() hook, use it in sata_qstor.c (hi Mark). sata_qstor appears to require the host-stop-before-port-stop ordering that existed prior to applying the attached patch. --- drivers/scsi/ahci.c | 2 ++ drivers/scsi/ata_piix.c | 2 ++ drivers/scsi/libata-core.c | 15 +++++++++++---- drivers/scsi/sata_nv.c | 2 ++ drivers/scsi/sata_promise.c | 1 + drivers/scsi/sata_qstor.c | 2 ++ drivers/scsi/sata_sil.c | 1 + drivers/scsi/sata_sis.c | 1 + drivers/scsi/sata_svw.c | 1 + drivers/scsi/sata_sx4.c | 2 ++ drivers/scsi/sata_uli.c | 1 + drivers/scsi/sata_via.c | 1 + drivers/scsi/sata_vsc.c | 1 + include/linux/libata.h | 1 + 14 files changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index da5bd33d982d..8b468a628700 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -289,6 +289,8 @@ static void ahci_host_stop(struct ata_host_set *host_set) { struct ahci_host_priv *hpriv = host_set->private_data; kfree(hpriv); + + ata_host_stop(host_set); } static int ahci_port_start(struct ata_port *ap) diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 3867f91ef8c7..54c52349adc5 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -153,6 +153,7 @@ static struct ata_port_operations piix_pata_ops = { .port_start = ata_port_start, .port_stop = ata_port_stop, + .host_stop = ata_host_stop, }; static struct ata_port_operations piix_sata_ops = { @@ -180,6 +181,7 @@ static struct ata_port_operations piix_sata_ops = { .port_start = ata_port_start, .port_stop = ata_port_stop, + .host_stop = ata_host_stop, }; static struct ata_port_info piix_port_info[] = { diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index ee9b96da841e..2b41cd3a8ec6 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -3321,6 +3321,13 @@ void ata_port_stop (struct ata_port *ap) dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma); } +void ata_host_stop (struct ata_host_set *host_set) +{ + if (host_set->mmio_base) + iounmap(host_set->mmio_base); +} + + /** * ata_host_remove - Unregister SCSI host structure with upper layers * @ap: Port to unregister @@ -3877,10 +3884,6 @@ void ata_pci_remove_one (struct pci_dev *pdev) } free_irq(host_set->irq, host_set); - if (host_set->ops->host_stop) - host_set->ops->host_stop(host_set); - if (host_set->mmio_base) - iounmap(host_set->mmio_base); for (i = 0; i < host_set->n_ports; i++) { ap = host_set->ports[i]; @@ -3899,6 +3902,9 @@ void ata_pci_remove_one (struct pci_dev *pdev) scsi_host_put(ap->host); } + if (host_set->ops->host_stop) + host_set->ops->host_stop(host_set); + kfree(host_set); pci_release_regions(pdev); @@ -3996,6 +4002,7 @@ EXPORT_SYMBOL_GPL(ata_chk_err); EXPORT_SYMBOL_GPL(ata_exec_command); EXPORT_SYMBOL_GPL(ata_port_start); EXPORT_SYMBOL_GPL(ata_port_stop); +EXPORT_SYMBOL_GPL(ata_host_stop); EXPORT_SYMBOL_GPL(ata_interrupt); EXPORT_SYMBOL_GPL(ata_qc_prep); EXPORT_SYMBOL_GPL(ata_bmdma_setup); diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index 69009f853a49..b0403ccd8a25 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -329,6 +329,8 @@ static void nv_host_stop (struct ata_host_set *host_set) host->host_desc->disable_hotplug(host_set); kfree(host); + + ata_host_stop(host_set); } static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c index c4e9e0298122..b18c90582e67 100644 --- a/drivers/scsi/sata_promise.c +++ b/drivers/scsi/sata_promise.c @@ -122,6 +122,7 @@ static struct ata_port_operations pdc_ata_ops = { .scr_write = pdc_sata_scr_write, .port_start = pdc_port_start, .port_stop = pdc_port_stop, + .host_stop = ata_host_stop, }; static struct ata_port_info pdc_port_info[] = { diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c index dfd362104717..1383e8a28d72 100644 --- a/drivers/scsi/sata_qstor.c +++ b/drivers/scsi/sata_qstor.c @@ -536,6 +536,8 @@ static void qs_host_stop(struct ata_host_set *host_set) writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ + + ata_host_stop(host_set); } static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe) diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c index 2b2ff48be396..238580d244e6 100644 --- a/drivers/scsi/sata_sil.c +++ b/drivers/scsi/sata_sil.c @@ -161,6 +161,7 @@ static struct ata_port_operations sil_ops = { .scr_write = sil_scr_write, .port_start = ata_port_start, .port_stop = ata_port_stop, + .host_stop = ata_host_stop, }; static struct ata_port_info sil_port_info[] = { diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c index 5105ddd08447..e418b89c6b9d 100644 --- a/drivers/scsi/sata_sis.c +++ b/drivers/scsi/sata_sis.c @@ -114,6 +114,7 @@ static struct ata_port_operations sis_ops = { .scr_write = sis_scr_write, .port_start = ata_port_start, .port_stop = ata_port_stop, + .host_stop = ata_host_stop, }; static struct ata_port_info sis_port_info = { diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c index 05075bd3a893..edef1fa969fc 100644 --- a/drivers/scsi/sata_svw.c +++ b/drivers/scsi/sata_svw.c @@ -313,6 +313,7 @@ static struct ata_port_operations k2_sata_ops = { .scr_write = k2_sata_scr_write, .port_start = ata_port_start, .port_stop = ata_port_stop, + .host_stop = ata_host_stop, }; static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base) diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c index 70118650c461..140cea05de3f 100644 --- a/drivers/scsi/sata_sx4.c +++ b/drivers/scsi/sata_sx4.c @@ -245,6 +245,8 @@ static void pdc20621_host_stop(struct ata_host_set *host_set) iounmap(dimm_mmio); kfree(hpriv); + + ata_host_stop(host_set); } static int pdc_port_start(struct ata_port *ap) diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c index 0bff4f475f26..a71fb54eebd3 100644 --- a/drivers/scsi/sata_uli.c +++ b/drivers/scsi/sata_uli.c @@ -113,6 +113,7 @@ static struct ata_port_operations uli_ops = { .port_start = ata_port_start, .port_stop = ata_port_stop, + .host_stop = ata_host_stop, }; static struct ata_port_info uli_port_info = { diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c index 3a7830667277..f43183c19a12 100644 --- a/drivers/scsi/sata_via.c +++ b/drivers/scsi/sata_via.c @@ -134,6 +134,7 @@ static struct ata_port_operations svia_sata_ops = { .port_start = ata_port_start, .port_stop = ata_port_stop, + .host_stop = ata_host_stop, }; static struct ata_port_info svia_port_info = { diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 2c28f0ad73c2..f67c34330ae9 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -230,6 +230,7 @@ static struct ata_port_operations vsc_sata_ops = { .scr_write = vsc_sata_scr_write, .port_start = ata_port_start, .port_stop = ata_port_stop, + .host_stop = ata_host_stop, }; static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base) diff --git a/include/linux/libata.h b/include/linux/libata.h index 1f7e2039a04e..e74f301e9bae 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -410,6 +410,7 @@ extern u8 ata_chk_err(struct ata_port *ap); extern void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf); extern int ata_port_start (struct ata_port *ap); extern void ata_port_stop (struct ata_port *ap); +extern void ata_host_stop (struct ata_host_set *host_set); extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs); extern void ata_qc_prep(struct ata_queued_cmd *qc); extern int ata_qc_issue_prot(struct ata_queued_cmd *qc); From 7003c05d77593f567e9940e68a944d846228fd7a Mon Sep 17 00:00:00 2001 From: "domen@coderock.org" Date: Fri, 8 Apr 2005 09:53:09 +0200 Subject: [PATCH 016/155] [PATCH] drivers/scsi/sata_vsc: add #include req'd for DMA_32BIT_MASK constant The previous patch did not compile cleanly on all architectures so here's a fixed one which #includes . Use the DMA_{64,32}BIT_MASK constants from dma-mapping.h when calling pci_set_dma_mask() or pci_set_consistent_dma_mask() This patch includes dma-mapping.h explicitly because it caused errors on some architectures otherwise. See http://marc.theaimsgroup.com/?t=108001993000001&r=1&w=2 for details Signed-off-by: Tobias Klauser Signed-off-by: Domen Puncer diff -puN drivers/scsi/sata_vsc.c~dma_mask-drivers_scsi_sata_vsc drivers/scsi/sata_vsc.c --- drivers/scsi/sata_vsc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c index 2c28f0ad73c2..05e0130a9f3c 100644 --- a/drivers/scsi/sata_vsc.c +++ b/drivers/scsi/sata_vsc.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "scsi.h" #include #include From 87507cfdd2cde397c9da8f6e7ec23b2b47ec53d6 Mon Sep 17 00:00:00 2001 From: "domen@coderock.org" Date: Fri, 8 Apr 2005 09:53:06 +0200 Subject: [PATCH 017/155] [PATCH] drivers/scsi/ahci: add #include req'd for the DMA_{64,32}BIT_MASK constants The previous patch did not compile cleanly on all architectures so here's a fixed one which #includes . Use the DMA_{64,32}BIT_MASK constants from dma-mapping.h when calling pci_set_dma_mask() or pci_set_consistent_dma_mask() This patch includes dma-mapping.h explicitly because it caused errors on some architectures otherwise. See http://marc.theaimsgroup.com/?t=108001993000001&r=1&w=2 for details Signed-off-by: Tobias Klauser Signed-off-by: Domen Puncer diff -puN drivers/scsi/ahci.c~dma_mask-drivers_scsi_ahci drivers/scsi/ahci.c --- drivers/scsi/ahci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c index da5bd33d982d..8263b3a5d8d7 100644 --- a/drivers/scsi/ahci.c +++ b/drivers/scsi/ahci.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "scsi.h" #include #include From 271b74d0b886301f297407dd7ae11b99607f8089 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sat, 28 May 2005 02:11:06 -0500 Subject: [PATCH 018/155] Input: Fix a warning in psmouse-base.c Signed-off-by: Andrew Morton Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index cd8509549eac..c9f8e16ca578 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -972,7 +972,7 @@ static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) return -EINVAL; if (!strncmp(val, "any", 3)) { - *((unsigned int *)kp->arg) = -1UL; + *((unsigned int *)kp->arg) = -1U; return 0; } From 668d1e6093110f7534e661e2ff43d54c74659b6d Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 28 May 2005 02:11:12 -0500 Subject: [PATCH 019/155] Input: This patch adds dummy gameport_register_port, gameport_unregister_port and gameport_set_phys functions to gameport.h for the case when a driver can't use gameport. This fixes the compilation of some OSS drivers with GAMEPORT=n without the need to #if inside every single driver. This patch also removes the non-working and now obsolete SOUND_GAMEPORT. This patch is also an alternative solution for ALSA drivers with similar problems (but #if's inside the drivers might have the advantage of saving some more bytes of gameport is not available). The only user-visible change is that for GAMEPORT=m the affected OSS drivers are now allowed to be built statically (but they won't have gameport support). Signed-off-by: Adrian Bunk Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/input/gameport/Kconfig | 20 -------------------- include/linux/gameport.h | 28 +++++++++++++++++++++++++--- sound/oss/Kconfig | 12 ++++++------ 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig index 6282f460aba0..1d93f5092904 100644 --- a/drivers/input/gameport/Kconfig +++ b/drivers/input/gameport/Kconfig @@ -68,23 +68,3 @@ config GAMEPORT_CS461X depends on PCI endif - -# Yes, SOUND_GAMEPORT looks a bit odd. Yes, it ends up being turned on -# in every .config. Please don't touch it. It is here to handle an -# unusual dependency between GAMEPORT and sound drivers. -# -# Some sound drivers call gameport functions. If GAMEPORT is -# not selected, empty stubs are provided for the functions and all is -# well. -# If GAMEPORT is built in, everything is fine. -# If GAMEPORT is a module, however, it would need to be loaded for the -# sound driver to be able to link properly. Therefore, the sound -# driver must be a module as well in that case. Since there's no way -# to express that directly in Kconfig, we use SOUND_GAMEPORT to -# express it. SOUND_GAMEPORT boils down to "if GAMEPORT is 'm', -# anything that depends on SOUND_GAMEPORT must be 'm' as well. if -# GAMEPORT is 'y' or 'n', it can be anything". -config SOUND_GAMEPORT - tristate - default m if GAMEPORT=m - default y diff --git a/include/linux/gameport.h b/include/linux/gameport.h index b1272f822cfa..cd623eccdbea 100644 --- a/include/linux/gameport.h +++ b/include/linux/gameport.h @@ -67,6 +67,8 @@ int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mo void gameport_close(struct gameport *gameport); void gameport_rescan(struct gameport *gameport); +#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) + void __gameport_register_port(struct gameport *gameport, struct module *owner); static inline void gameport_register_port(struct gameport *gameport) { @@ -75,6 +77,29 @@ static inline void gameport_register_port(struct gameport *gameport) void gameport_unregister_port(struct gameport *gameport); +void gameport_set_phys(struct gameport *gameport, const char *fmt, ...) + __attribute__ ((format (printf, 2, 3))); + +#else + +static inline void gameport_register_port(struct gameport *gameport) +{ + return; +} + +static inline void gameport_unregister_port(struct gameport *gameport) +{ + return; +} + +static inline void gameport_set_phys(struct gameport *gameport, + const char *fmt, ...) +{ + return; +} + +#endif + static inline struct gameport *gameport_allocate_port(void) { struct gameport *gameport = kcalloc(1, sizeof(struct gameport), GFP_KERNEL); @@ -92,9 +117,6 @@ static inline void gameport_set_name(struct gameport *gameport, const char *name strlcpy(gameport->name, name, sizeof(gameport->name)); } -void gameport_set_phys(struct gameport *gameport, const char *fmt, ...) - __attribute__ ((format (printf, 2, 3))); - /* * Use the following fucntions to manipulate gameport's per-port * driver-specific data. diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index a9602f89d6b1..e537bd66a707 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -112,7 +112,7 @@ config SOUND_BCM_CS4297A config SOUND_ES1370 tristate "Ensoniq AudioPCI (ES1370)" - depends on SOUND_PRIME!=n && SOUND && PCI && SOUND_GAMEPORT + depends on SOUND_PRIME!=n && SOUND && PCI help Say Y or M if you have a PCI sound card utilizing the Ensoniq ES1370 chipset, such as Ensoniq's AudioPCI (non-97). To find @@ -125,7 +125,7 @@ config SOUND_ES1370 config SOUND_ES1371 tristate "Creative Ensoniq AudioPCI 97 (ES1371)" - depends on SOUND_PRIME!=n && SOUND && PCI && SOUND_GAMEPORT + depends on SOUND_PRIME!=n && SOUND && PCI help Say Y or M if you have a PCI sound card utilizing the Ensoniq ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if @@ -138,7 +138,7 @@ config SOUND_ES1371 config SOUND_ESSSOLO1 tristate "ESS Technology Solo1" - depends on SOUND_PRIME!=n && SOUND && SOUND_GAMEPORT && PCI + depends on SOUND_PRIME!=n && SOUND && PCI help Say Y or M if you have a PCI sound card utilizing the ESS Technology Solo1 chip. To find out if your sound card uses a @@ -179,7 +179,7 @@ config SOUND_HARMONY config SOUND_SONICVIBES tristate "S3 SonicVibes" - depends on SOUND_PRIME!=n && SOUND && SOUND_GAMEPORT + depends on SOUND_PRIME!=n && SOUND help Say Y or M if you have a PCI sound card utilizing the S3 SonicVibes chipset. To find out if your sound card uses a @@ -226,7 +226,7 @@ config SOUND_AU1550_AC97 config SOUND_TRIDENT tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core" - depends on SOUND_PRIME!=n && SOUND && SOUND_GAMEPORT + depends on SOUND_PRIME!=n && SOUND ---help--- Say Y or M if you have a PCI sound card utilizing the Trident 4DWave-DX/NX chipset or your mother board chipset has SiS 7018 @@ -739,7 +739,7 @@ config SOUND_NM256 config SOUND_MAD16 tristate "OPTi MAD16 and/or Mozart based cards" - depends on SOUND_OSS && SOUND_GAMEPORT + depends on SOUND_OSS ---help--- Answer Y if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi 82C928 or 82C929 or 82C931) audio interface chip. These chips are From 39fa58007a54b09c91cb7bf3ce3cfcc4957f92ff Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sat, 28 May 2005 02:11:16 -0500 Subject: [PATCH 020/155] Input: Add a missing KERN_INFO message designation, fix behavior when only a keyboard part of the controller is detected. Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-x86ia64io.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index f64867808fea..0327472393de 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -227,7 +227,7 @@ static int i8042_pnp_init(void) int result_kbd, result_aux; if (i8042_nopnp) { - printk("i8042: PNP detection disabled\n"); + printk(KERN_INFO "i8042: PNP detection disabled\n"); return 0; } @@ -265,7 +265,7 @@ static int i8042_pnp_init(void) i8042_pnp_kbd_irq = i8042_kbd_irq; } - if (result_aux > 0 && !i8042_pnp_aux_irq) { + if (!i8042_pnp_aux_irq) { printk(KERN_WARNING "PNP: PS/2 controller doesn't have AUX irq; using default %#x\n", i8042_aux_irq); i8042_pnp_aux_irq = i8042_aux_irq; } From be15692310ec0e93998d763931089cb21386a058 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sat, 28 May 2005 02:11:19 -0500 Subject: [PATCH 021/155] Input: Remove (now) unused variable in i8042.c Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 8e63e464d361..8f5b123e2ebc 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -802,8 +802,6 @@ static int i8042_controller_init(void) */ static void i8042_controller_reset(void) { - unsigned char param; - /* * Reset the controller if requested. */ From 2673c836ab9a44b02d45ae5c1c44c03df138dba4 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sat, 28 May 2005 02:11:27 -0500 Subject: [PATCH 022/155] Input: Only write the CTR in i8042 resume function. Reading it is wrong, since it may (will) contain nonsensical data. Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 48 +++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 8f5b123e2ebc..5900de3c3f4f 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -698,6 +698,26 @@ static void i8042_timer_func(unsigned long data) i8042_interrupt(0, NULL, NULL); } +static int i8042_ctl_test(void) +{ + unsigned char param; + + if (!i8042_reset) + return 0; + + if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { + printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); + return -1; + } + + if (param != I8042_RET_CTL_TEST) { + printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", + param, I8042_RET_CTL_TEST); + return -1; + } + + return 0; +} /* * i8042_controller init initializes the i8042 controller, and, @@ -719,21 +739,8 @@ static int i8042_controller_init(void) return -1; } - if (i8042_reset) { - - unsigned char param; - - if (i8042_command(¶m, I8042_CMD_CTL_TEST)) { - printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n"); - return -1; - } - - if (param != I8042_RET_CTL_TEST) { - printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n", - param, I8042_RET_CTL_TEST); - return -1; - } - } + if (i8042_ctl_test()) + return -1; /* * Save the CTR for restoral on unload / reboot. @@ -806,9 +813,7 @@ static void i8042_controller_reset(void) * Reset the controller if requested. */ - if (i8042_reset) - if (i8042_command(¶m, I8042_CMD_CTL_TEST)) - printk(KERN_ERR "i8042.c: i8042 controller reset timeout.\n"); + i8042_ctl_test(); /* * Disable MUX mode if present. @@ -920,8 +925,11 @@ static int i8042_resume(struct device *dev, u32 level) if (level != RESUME_ENABLE) return 0; - if (i8042_controller_init()) { - printk(KERN_ERR "i8042: resume failed\n"); + if (i8042_ctl_test()) + return -1; + + if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { + printk(KERN_ERR "i8042: Can't write CTR\n"); return -1; } From 5a72afc03ccc29458502cf032f5c34e5ee004ae7 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 28 May 2005 02:11:32 -0500 Subject: [PATCH 023/155] Input: Tone down the severity of a printk() in i386/ia64 arch code for i386, it's printed on many machines and usually is not a cause for worry. Signed-off-by: Dmitry Torokhov Signed-off-by: Vojtech Pavlik --- drivers/input/serio/i8042-x86ia64io.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 0327472393de..819e47754dab 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -241,7 +241,7 @@ static int i8042_pnp_init(void) #if defined(__ia64__) return -ENODEV; #else - printk(KERN_WARNING "PNP: No PS/2 controller found. Probing ports directly.\n"); + printk(KERN_INFO "PNP: No PS/2 controller found. Probing ports directly.\n"); return 0; #endif } From 74af42bb729651855f78ea27498250724689130e Mon Sep 17 00:00:00 2001 From: Kurt Garloff Date: Sat, 28 May 2005 02:11:38 -0500 Subject: [PATCH 024/155] Input: Avoid double unregistering of i8042 PnP driver. This can happen when no i8042 controller (not PnP, not legacy) is present. From: Kurt Garloff Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-x86ia64io.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 819e47754dab..f4c5f7745422 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -215,11 +215,15 @@ static struct pnp_driver i8042_pnp_aux_driver = { static void i8042_pnp_exit(void) { - if (i8042_pnp_kbd_registered) + if (i8042_pnp_kbd_registered) { + i8042_pnp_kbd_registered = 0; pnp_unregister_driver(&i8042_pnp_kbd_driver); + } - if (i8042_pnp_aux_registered) + if (i8042_pnp_aux_registered) { + i8042_pnp_aux_registered = 0; pnp_unregister_driver(&i8042_pnp_aux_driver); + } } static int i8042_pnp_init(void) From 7741e9317137a7456baa9c09ad8308c80c23b8db Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sat, 28 May 2005 02:11:42 -0500 Subject: [PATCH 025/155] Input: Workaround for Sunrex K8561 IR Keyboard/Mouse. The mouse sends an incorrect ID and wasn't recognized. Reported-by: Stefan Seyfried Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index c9f8e16ca578..019034b21a0b 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -518,13 +518,16 @@ static int psmouse_probe(struct psmouse *psmouse) /* * First, we check if it's a mouse. It should send 0x00 or 0x03 * in case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer. + * Sunrex K8561 IR Keyboard/Mouse reports 0xff on second and subsequent + * ID queries, probably due to a firmware bug. */ param[0] = 0xa5; if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID)) return -1; - if (param[0] != 0x00 && param[0] != 0x03 && param[0] != 0x04) + if (param[0] != 0x00 && param[0] != 0x03 && + param[0] != 0x04 && param[0] != 0xff) return -1; /* From f24949e8e0b9bed223ad9a435bf37e91ee8d0db7 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sat, 28 May 2005 02:11:49 -0500 Subject: [PATCH 026/155] Input: Fix button mapping in joydev - BTN_TRIGGER was being mapped twice, resulting in it being the last (instead of first) button on a joystick. Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/input/joydev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 7d7527f8b02d..627d343dfba1 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -422,7 +422,7 @@ static struct input_handle *joydev_connect(struct input_handler *handler, struct joydev->nkey++; } - for (i = 0; i < BTN_JOYSTICK - BTN_MISC + 1; i++) + for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++) if (test_bit(i + BTN_MISC, dev->keybit)) { joydev->keymap[i] = joydev->nkey; joydev->keypam[joydev->nkey] = i + BTN_MISC; From a07461ec0cffb105c7e7b7404520ea2c74129db0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 28 May 2005 02:12:00 -0500 Subject: [PATCH 027/155] Input: gunze - fix out-of-bound array access reported by Adrian Bunk. Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/gunze.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c index c9d0a153671c..53a27e43dd23 100644 --- a/drivers/input/touchscreen/gunze.c +++ b/drivers/input/touchscreen/gunze.c @@ -68,8 +68,7 @@ static void gunze_process_packet(struct gunze* gunze, struct pt_regs *regs) if (gunze->idx != GUNZE_MAX_LENGTH || gunze->data[5] != ',' || (gunze->data[0] != 'T' && gunze->data[0] != 'R')) { - gunze->data[10] = 0; - printk(KERN_WARNING "gunze.c: bad packet: >%s<\n", gunze->data); + printk(KERN_WARNING "gunze.c: bad packet: >%.*s<\n", GUNZE_MAX_LENGTH, gunze->data); return; } From 59311de3fb5f293b2e99d7f52e0ab5572759951d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 28 May 2005 02:12:05 -0500 Subject: [PATCH 028/155] Input: automatically disable MUX mode on Toshiba Satellite P10 because it interferes with ALPS touchpad detection and causes horrible death on reboot. Since P10 does not have external PS/2 ports MUX mode does not have any advantages over legacy mode anyway. Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-x86ia64io.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index f4c5f7745422..c97ad98171fe 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -88,9 +88,11 @@ static struct dmi_system_id __initdata i8042_dmi_noloop_table[] = { }; /* - * Some Fujitsu notebooks are ahving trouble with touhcpads if + * Some Fujitsu notebooks are having trouble with touchpads if * active multiplexing mode is activated. Luckily they don't have * external PS/2 ports so we can safely disable it. + * ... apparently some Toshibas don't like MUX mode either and + * die horrible death on reboot. */ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { { @@ -121,6 +123,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "FMVLT70H"), }, }, + { + .ident = "Toshiba P10", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), + DMI_MATCH(DMI_PRODUCT_NAME, "Satellite P10"), + }, + }, { } }; From b4ff99b60c5e17b1031deb20c9d7688ebe6c9659 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 28 May 2005 02:12:10 -0500 Subject: [PATCH 029/155] Input: yet another model that does not play nicely when i8042 is put in MUX mode - Fujitsu Lifebook S6230 Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-x86ia64io.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index c97ad98171fe..0487ecbb8a49 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -116,6 +116,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S Series"), }, }, + { + .ident = "Fujitsu Lifebook S6230", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook S6230"), + }, + }, { .ident = "Fujitsu T70H", .matches = { From 409b7506759430f7c3841d425ca1f8a31eeadece Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 28 May 2005 02:12:18 -0500 Subject: [PATCH 030/155] Input: synaptics - reduce verboseness of synaptics driver - there is no reason one driver should take 10 lines in dmesg. Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 39 +++++---------------------------- 1 file changed, 5 insertions(+), 34 deletions(-) diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 69832f8fb720..36c721227b68 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -143,39 +143,6 @@ static int synaptics_identify(struct psmouse *psmouse) return -1; } -static void print_ident(struct synaptics_data *priv) -{ - printk(KERN_INFO "Synaptics Touchpad, model: %ld\n", SYN_ID_MODEL(priv->identity)); - printk(KERN_INFO " Firmware: %ld.%ld\n", SYN_ID_MAJOR(priv->identity), - SYN_ID_MINOR(priv->identity)); - if (SYN_MODEL_ROT180(priv->model_id)) - printk(KERN_INFO " 180 degree mounted touchpad\n"); - if (SYN_MODEL_PORTRAIT(priv->model_id)) - printk(KERN_INFO " portrait touchpad\n"); - printk(KERN_INFO " Sensor: %ld\n", SYN_MODEL_SENSOR(priv->model_id)); - if (SYN_MODEL_NEWABS(priv->model_id)) - printk(KERN_INFO " new absolute packet format\n"); - if (SYN_MODEL_PEN(priv->model_id)) - printk(KERN_INFO " pen detection\n"); - - if (SYN_CAP_EXTENDED(priv->capabilities)) { - printk(KERN_INFO " Touchpad has extended capability bits\n"); - if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) - printk(KERN_INFO " -> %d multi-buttons, i.e. besides standard buttons\n", - (int)(SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap))); - if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) - printk(KERN_INFO " -> middle button\n"); - if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) - printk(KERN_INFO " -> four buttons\n"); - if (SYN_CAP_MULTIFINGER(priv->capabilities)) - printk(KERN_INFO " -> multifinger detection\n"); - if (SYN_CAP_PALMDETECT(priv->capabilities)) - printk(KERN_INFO " -> palm detection\n"); - if (SYN_CAP_PASS_THROUGH(priv->capabilities)) - printk(KERN_INFO " -> pass-through port\n"); - } -} - static int synaptics_query_hardware(struct psmouse *psmouse) { int retries = 0; @@ -666,7 +633,11 @@ int synaptics_init(struct psmouse *psmouse) priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; - print_ident(priv); + printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx\n", + SYN_ID_MODEL(priv->identity), + SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), + priv->model_id, priv->capabilities, priv->ext_cap); + set_input_params(&psmouse->dev, priv); psmouse->protocol_handler = synaptics_process_byte; From dcefb396c2af4d52fba48dc58b4021794b042046 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Sat, 28 May 2005 00:51:24 -0400 Subject: [PATCH 031/155] [PATCH] Fix up pwc driver compilation. The neutering of the pwc driver was incomplete. It still references some now-dead files.. Signed-off-by: Dave Jones Signed-off-by: Linus Torvalds --- drivers/usb/media/pwc/pwc-ctrl.c | 2 -- drivers/usb/media/pwc/pwc-uncompress.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/usb/media/pwc/pwc-ctrl.c b/drivers/usb/media/pwc/pwc-ctrl.c index 3e1e4fe20d85..53099190952c 100644 --- a/drivers/usb/media/pwc/pwc-ctrl.c +++ b/drivers/usb/media/pwc/pwc-ctrl.c @@ -48,8 +48,6 @@ #include "pwc-uncompress.h" #include "pwc-kiara.h" #include "pwc-timon.h" -#include "pwc-dec1.h" -#include "pwc-dec23.h" /* Request types: video */ #define SET_LUM_CTL 0x01 diff --git a/drivers/usb/media/pwc/pwc-uncompress.c b/drivers/usb/media/pwc/pwc-uncompress.c index c596083f06ba..bc3b1635eab0 100644 --- a/drivers/usb/media/pwc/pwc-uncompress.c +++ b/drivers/usb/media/pwc/pwc-uncompress.c @@ -29,8 +29,6 @@ #include "pwc.h" #include "pwc-uncompress.h" -#include "pwc-dec1.h" -#include "pwc-dec23.h" int pwc_decompress(struct pwc_device *pdev) { From c5924b7d97430657fa07ebf1a208c7e8cf135ef3 Mon Sep 17 00:00:00 2001 From: Oliver Korpilla Date: Fri, 27 May 2005 12:52:55 -0700 Subject: [PATCH 032/155] [PATCH] x86_64: signal.c build fix For unspecified reasons, arch/x86_64/kernel/signal.c apparently needs ia32_unistd.h. Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/signal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c index 3fdcdba0fec5..429c0269dc4e 100644 --- a/arch/x86_64/kernel/signal.c +++ b/arch/x86_64/kernel/signal.c @@ -28,6 +28,7 @@ #include #include #include +#include /* #define DEBUG_SIG 1 */ From d6649bc76a57523209a6b2ee4844c9078a4dd8bb Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 27 May 2005 12:52:56 -0700 Subject: [PATCH 033/155] [PATCH] ppc32: small cpufreq update This patch adds a missing attribute to pmac cpufreq so that "scaling_available_frequencies" works. It also cleans up the duplicate definitions for low and high speed constants. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: John Clemens Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/platforms/pmac_cpufreq.c | 32 +++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c index f7fb2786cd50..48e482c8bd0d 100644 --- a/arch/ppc/platforms/pmac_cpufreq.c +++ b/arch/ppc/platforms/pmac_cpufreq.c @@ -85,14 +85,11 @@ static int no_schedule; static int has_cpu_l2lve; -#define PMAC_CPU_LOW_SPEED 1 -#define PMAC_CPU_HIGH_SPEED 0 - /* There are only two frequency states for each processor. Values * are in kHz for the time being. */ -#define CPUFREQ_HIGH PMAC_CPU_HIGH_SPEED -#define CPUFREQ_LOW PMAC_CPU_LOW_SPEED +#define CPUFREQ_HIGH 0 +#define CPUFREQ_LOW 1 static struct cpufreq_frequency_table pmac_cpu_freqs[] = { {CPUFREQ_HIGH, 0}, @@ -100,6 +97,11 @@ static struct cpufreq_frequency_table pmac_cpu_freqs[] = { {0, CPUFREQ_TABLE_END}, }; +static struct freq_attr* pmac_cpu_freqs_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + static inline void local_delay(unsigned long ms) { if (no_schedule) @@ -355,7 +357,7 @@ static int __pmac do_set_cpu_speed(int speed_mode, int notify) static unsigned long prev_l3cr; freqs.old = cur_freq; - freqs.new = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; + freqs.new = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq; freqs.cpu = smp_processor_id(); if (freqs.old == freqs.new) @@ -363,7 +365,7 @@ static int __pmac do_set_cpu_speed(int speed_mode, int notify) if (notify) cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - if (speed_mode == PMAC_CPU_LOW_SPEED && + if (speed_mode == CPUFREQ_LOW && cpu_has_feature(CPU_FTR_L3CR)) { l3cr = _get_L3CR(); if (l3cr & L3CR_L3E) { @@ -371,8 +373,8 @@ static int __pmac do_set_cpu_speed(int speed_mode, int notify) _set_L3CR(0); } } - set_speed_proc(speed_mode == PMAC_CPU_LOW_SPEED); - if (speed_mode == PMAC_CPU_HIGH_SPEED && + set_speed_proc(speed_mode == CPUFREQ_LOW); + if (speed_mode == CPUFREQ_HIGH && cpu_has_feature(CPU_FTR_L3CR)) { l3cr = _get_L3CR(); if ((prev_l3cr & L3CR_L3E) && l3cr != prev_l3cr) @@ -380,7 +382,7 @@ static int __pmac do_set_cpu_speed(int speed_mode, int notify) } if (notify) cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - cur_freq = (speed_mode == PMAC_CPU_HIGH_SPEED) ? hi_freq : low_freq; + cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq; return 0; } @@ -423,7 +425,8 @@ static int __pmac pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = cur_freq; - return cpufreq_frequency_table_cpuinfo(policy, &pmac_cpu_freqs[0]); + cpufreq_frequency_table_get_attr(pmac_cpu_freqs, policy->cpu); + return cpufreq_frequency_table_cpuinfo(policy, pmac_cpu_freqs); } static u32 __pmac read_gpio(struct device_node *np) @@ -457,7 +460,7 @@ static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, u32 state) no_schedule = 1; sleep_freq = cur_freq; if (cur_freq == low_freq) - do_set_cpu_speed(PMAC_CPU_HIGH_SPEED, 0); + do_set_cpu_speed(CPUFREQ_HIGH, 0); return 0; } @@ -473,8 +476,8 @@ static int __pmac pmac_cpufreq_resume(struct cpufreq_policy *policy) * is that we force a switch to whatever it was, which is * probably high speed due to our suspend() routine */ - do_set_cpu_speed(sleep_freq == low_freq ? PMAC_CPU_LOW_SPEED - : PMAC_CPU_HIGH_SPEED, 0); + do_set_cpu_speed(sleep_freq == low_freq ? + CPUFREQ_LOW : CPUFREQ_HIGH, 0); no_schedule = 0; return 0; @@ -488,6 +491,7 @@ static struct cpufreq_driver pmac_cpufreq_driver = { .suspend = pmac_cpufreq_suspend, .resume = pmac_cpufreq_resume, .flags = CPUFREQ_PM_NO_WARN, + .attr = pmac_cpu_freqs_attr, .name = "powermac", .owner = THIS_MODULE, }; From 9ae250d175e1cbff82223ce2c07897c790c5b948 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 27 May 2005 12:52:57 -0700 Subject: [PATCH 034/155] [PATCH] ppc32: Fix Alsa PowerMac driver on old machines The g5 support code broke some earlier models unfortunately as those bail out early from the detect function, before the point where I added the code to locate the PCI device for use with DMA allocations. This patch fixes it. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/ppc/pmac.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index 32d94754acf8..080ef3928465 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -876,7 +876,7 @@ static void __init detect_byte_swap(pmac_t *chip) */ static int __init snd_pmac_detect(pmac_t *chip) { - struct device_node *sound; + struct device_node *sound = NULL; unsigned int *prop, l; struct macio_chip* macio; @@ -906,20 +906,22 @@ static int __init snd_pmac_detect(pmac_t *chip) chip->is_pbook_G3 = 1; chip->node = find_devices("awacs"); if (chip->node) - return 0; /* ok */ + sound = chip->node; /* * powermac G3 models have a node called "davbus" * with a child called "sound". */ - chip->node = find_devices("davbus"); + if (!chip->node) + chip->node = find_devices("davbus"); /* * if we didn't find a davbus device, try 'i2s-a' since * this seems to be what iBooks have */ if (! chip->node) { chip->node = find_devices("i2s-a"); - if (chip->node && chip->node->parent && chip->node->parent->parent) { + if (chip->node && chip->node->parent && + chip->node->parent->parent) { if (device_is_compatible(chip->node->parent->parent, "K2-Keylargo")) chip->is_k2 = 1; @@ -928,9 +930,11 @@ static int __init snd_pmac_detect(pmac_t *chip) if (! chip->node) return -ENODEV; - sound = find_devices("sound"); - while (sound && sound->parent != chip->node) - sound = sound->next; + if (!sound) { + sound = find_devices("sound"); + while (sound && sound->parent != chip->node) + sound = sound->next; + } if (! sound) return -ENODEV; prop = (unsigned int *) get_property(sound, "sub-frame", NULL); @@ -1019,7 +1023,8 @@ static int __init snd_pmac_detect(pmac_t *chip) } } if (chip->pdev == NULL) - printk(KERN_WARNING "snd-powermac: can't locate macio PCI device !\n"); + printk(KERN_WARNING "snd-powermac: can't locate macio PCI" + " device !\n"); detect_byte_swap(chip); @@ -1027,7 +1032,8 @@ static int __init snd_pmac_detect(pmac_t *chip) are available */ prop = (unsigned int *) get_property(sound, "sample-rates", &l); if (! prop) - prop = (unsigned int *) get_property(sound, "output-frame-rates", &l); + prop = (unsigned int *) get_property(sound, + "output-frame-rates", &l); if (prop) { int i; chip->freqs_ok = 0; @@ -1054,7 +1060,8 @@ static int __init snd_pmac_detect(pmac_t *chip) /* * exported - boolean info callbacks for ease of programming */ -int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 2; @@ -1063,7 +1070,8 @@ int snd_pmac_boolean_stereo_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * return 0; } -int snd_pmac_boolean_mono_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +int snd_pmac_boolean_mono_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->count = 1; From 9db29258893b08a838e5ecfa4a0933c9c1f2e305 Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Fri, 27 May 2005 12:52:58 -0700 Subject: [PATCH 035/155] [PATCH] ppc64 iSeries: make virtual DVD-RAMs writable again It appears that another test has been added in the Uniform CDROM layer that must be passed before a DVD-RAM is considered writeable. This patch implements an emulation of the needed packet command for the viocd driver. Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/cdrom/viocd.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index fcca26c89bbc..38dd9ffbe8bc 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -488,6 +488,20 @@ static int viocd_packet(struct cdrom_device_info *cdi, & (CDC_DVD_RAM | CDC_RAM)) != 0; } break; + case GPCMD_GET_CONFIGURATION: + if (cgc->cmd[3] == CDF_RWRT) { + struct rwrt_feature_desc *rfd = (struct rwrt_feature_desc *)(cgc->buffer + sizeof(struct feature_header)); + + if ((buflen >= + (sizeof(struct feature_header) + sizeof(*rfd))) && + (cdi->ops->capability & ~cdi->mask + & (CDC_DVD_RAM | CDC_RAM))) { + rfd->feature_code = cpu_to_be16(CDF_RWRT); + rfd->curr = 1; + ret = 0; + } + } + break; default: if (cgc->sense) { /* indicate Unknown code */ From 70ffc71c5c42c8ac62d951e80d9799bd5764f2f5 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 27 May 2005 12:52:59 -0700 Subject: [PATCH 036/155] [PATCH] arch/i386/kernel/cpu/intel_cacheinfo.c: section fix num_cache_leaves is used in __devexit cache_remove_dev() and can therefore not be __devinit. Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/cpu/intel_cacheinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c index aeb5b4ef8c8b..a710dc4eb20e 100644 --- a/arch/i386/kernel/cpu/intel_cacheinfo.c +++ b/arch/i386/kernel/cpu/intel_cacheinfo.c @@ -118,7 +118,7 @@ struct _cpuid4_info { }; #define MAX_CACHE_LEAVES 4 -static unsigned short __devinitdata num_cache_leaves; +static unsigned short num_cache_leaves; static int __devinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf) { From b60c1f6ffd88850079ae419aa933ab0eddbd5535 Mon Sep 17 00:00:00 2001 From: John Hawkes Date: Fri, 27 May 2005 12:53:00 -0700 Subject: [PATCH 037/155] [PATCH] drop note_interrupt() for per-CPU for proper scaling The "unhandled interrupts" catcher, note_interrupt(), increments a global desc->irq_count and grossly damages scaling of very large systems, e.g., >192p ia64 Altix, because of this highly contented cacheline, especially for timer interrupts. 384p is severely crippled, and 512p is unuseable. All calls to note_interrupt() can be disabled by booting with "noirqdebug", but this disables the useful interrupt checking for all interrupts. I propose eliminating note_interrupt() for all per-CPU interrupts. This was the behavior of linux-2.6.10 and earlier, but in 2.6.11 a code restructuring added a call to note_interrupt() for per-CPU interrupts. Besides, note_interrupt() is a bit racy for concurrent CPU calls anyway, as the desc->irq_count++ increment isn't atomic (which, if done, would make scaling even worse). Signed-off-by: John Hawkes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/irq/handle.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index 06b5a6323998..436c7d93c00a 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c @@ -119,8 +119,6 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs) */ desc->handler->ack(irq); action_ret = handle_IRQ_event(irq, regs, desc->action); - if (!noirqdebug) - note_interrupt(irq, desc, action_ret); desc->handler->end(irq); return 1; } From 49f384b82b03416dd7e4fc77847a959fe3247362 Mon Sep 17 00:00:00 2001 From: "Siddha, Suresh B" Date: Fri, 27 May 2005 12:53:01 -0700 Subject: [PATCH 038/155] [PATCH] x86: fix smp_num_siblings on buggy BIOSes This fixes 'smp_num_siblings' value on the systems with a buggy bios, which sets number of siblings to '2' even when HT is disabled. (more details are at http://bugzilla.kernel.org/show_bug.cgi?id=4359) I am planning to do more cleanup in this area (like moving smp_num_siblings to per cpuinfo) shortly. Signed-off-by: Suresh Siddha Signed-off-by: Venkatesh Pallipadi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/smpboot.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 35bfe138cb1a..bc1bb6919e6a 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -1074,8 +1074,10 @@ static void __init smp_boot_cpus(unsigned int max_cpus) cpu_set(cpu, cpu_sibling_map[cpu]); } - if (siblings != smp_num_siblings) + if (siblings != smp_num_siblings) { printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings); + smp_num_siblings = siblings; + } if (c->x86_num_cores > 1) { for (i = 0; i < NR_CPUS; i++) { From b16eeb47292597a8bf3ad53fdaf1f727f57bd8e4 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Fri, 27 May 2005 12:53:02 -0700 Subject: [PATCH 039/155] [PATCH] ppc32: Fix cpufreq vs. sleep issue Recent kernels occasionally trigger a PMU timeout on some mac laptops, typically on wakeup from sleep. This seem to be caused by either a too big latency caused by the cpufreq switch on wakeup from sleep or by an interrupt beeing lost due to the reset of the interrupt controller done during wakeup. This patch makes that code more robust by stopping PMU auto poll activity around cpufreq changes on machines that use the PMU for such changes (long latency switching involving a CPU hard reset and flush of all caches) and by removing the reset of the open pic interrupt controller on wakeup (that can cause the loss of an interrupt and Darwin doesn't do it, so it must not be necessary). Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/platforms/pmac_cpufreq.c | 4 ++++ arch/ppc/syslib/open_pic.c | 4 +--- drivers/macintosh/via-pmu.c | 8 ++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c index 48e482c8bd0d..937f46df711e 100644 --- a/arch/ppc/platforms/pmac_cpufreq.c +++ b/arch/ppc/platforms/pmac_cpufreq.c @@ -271,6 +271,8 @@ static int __pmac pmu_set_cpu_speed(int low_speed) #ifdef DEBUG_FREQ printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); #endif + pmu_suspend(); + /* Disable all interrupt sources on openpic */ pic_prio = openpic_get_priority(); openpic_set_priority(0xf); @@ -345,6 +347,8 @@ static int __pmac pmu_set_cpu_speed(int low_speed) debug_calc_bogomips(); #endif + pmu_resume(); + preempt_enable(); return 0; diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c index 9d4ed68b5804..000ba47c67cb 100644 --- a/arch/ppc/syslib/open_pic.c +++ b/arch/ppc/syslib/open_pic.c @@ -275,7 +275,7 @@ static void __init openpic_enable_sie(void) } #endif -#if defined(CONFIG_EPIC_SERIAL_MODE) || defined(CONFIG_PM) +#if defined(CONFIG_EPIC_SERIAL_MODE) static void openpic_reset(void) { openpic_setfield(&OpenPIC->Global.Global_Configuration0, @@ -993,8 +993,6 @@ int openpic_resume(struct sys_device *sysdev) return 0; } - openpic_reset(); - /* OpenPIC sometimes seem to need some time to be fully back up... */ do { openpic_set_spurious(OPENPIC_VEC_SPURIOUS); diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index e654aa5eecd4..bb9f4044c74d 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -2421,7 +2421,7 @@ pmac_wakeup_devices(void) /* Re-enable local CPU interrupts */ local_irq_enable(); - mdelay(100); + mdelay(10); preempt_enable(); /* Re-enable clock spreading on some machines */ @@ -2549,7 +2549,9 @@ powerbook_sleep_Core99(void) return ret; } - printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1)); + /* Stop environment and ADB interrupts */ + pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0); + pmu_wait_complete(&req); /* Tell PMU what events will wake us up */ pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS, @@ -2611,8 +2613,6 @@ powerbook_sleep_Core99(void) pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask); pmu_wait_complete(&req); - printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1)); - pmac_wakeup_devices(); return 0; From 8bd7f125e2f217c8aa3dff005ae291c81246c340 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Fri, 27 May 2005 12:53:03 -0700 Subject: [PATCH 040/155] [PATCH] swsusp: ahd_dv_0 can't be stopped This driver wants to set PF_NOFREEZE. Cc: James Bottomley Cc: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/scsi/aic7xxx/aic79xx_osm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 550c9921691a..7c02b7dc7098 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -2488,7 +2488,7 @@ ahd_linux_dv_thread(void *data) sprintf(current->comm, "ahd_dv_%d", ahd->unit); #else daemonize("ahd_dv_%d", ahd->unit); - current->flags |= PF_FREEZE; + current->flags |= PF_NOFREEZE; #endif unlock_kernel(); From c1e4c8d3ee3300f363a52fd4cf3d90fdf5098f5a Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Fri, 27 May 2005 12:53:03 -0700 Subject: [PATCH 041/155] [PATCH] fix jumpy mouse cursor on console Do not send empty events to gpm. (Keyboards are assumed to have scroll wheel these days, that makes them part-mouse. That means typing on keyboard generates empty mouse events). From: Dmitry Torokhov Signed-off-by: Pavel Machek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/input/mousedev.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 564974ce5793..96fb9870834a 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -101,6 +101,7 @@ struct mousedev_list { unsigned char ready, buffer, bufsiz; unsigned char imexseq, impsseq; enum mousedev_emul mode; + unsigned long last_buttons; }; #define MOUSEDEV_SEQ_LEN 6 @@ -224,7 +225,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h spin_lock_irqsave(&list->packet_lock, flags); p = &list->packets[list->head]; - if (list->ready && p->buttons != packet->buttons) { + if (list->ready && p->buttons != mousedev->packet.buttons) { unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN; if (new_head != list->tail) { p = &list->packets[list->head = new_head]; @@ -249,10 +250,13 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h p->dz += packet->dz; p->buttons = mousedev->packet.buttons; - list->ready = 1; + if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons) + list->ready = 1; spin_unlock_irqrestore(&list->packet_lock, flags); - kill_fasync(&list->fasync, SIGIO, POLL_IN); + + if (list->ready) + kill_fasync(&list->fasync, SIGIO, POLL_IN); } wake_up_interruptible(&mousedev->wait); @@ -477,9 +481,10 @@ static void mousedev_packet(struct mousedev_list *list, signed char *ps2_data) } if (!p->dx && !p->dy && !p->dz) { - if (list->tail == list->head) + if (list->tail == list->head) { list->ready = 0; - else + list->last_buttons = p->buttons; + } else list->tail = (list->tail + 1) % PACKET_QUEUE_LEN; } From 346e399b2a3a01b323fa74a0937e2d855479833b Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Sat, 28 May 2005 15:51:46 -0700 Subject: [PATCH 042/155] [PATCH] intelfb section fix On Nov 16 2004 a change to intelfbdrv.c was commited (as part of 0.9.2 it looks like) that added __initdata to all of the module param variables that seems to create the opportunity for an oops. I've recently been chasing an OOPS (http://marc.theaimsgroup.com/?l=linux-kernel&m=111552250920370&w=2) I created by reading every file on the /sys file system and I've traced it back to this code in the intelfbdrv. Though I had root privs in my initial problem report, it turns out they are un-necessary to generate the oops - all you've got to do is "cat /sys/module/intelfb/parameters/mode" enough times and eventually it will oops. This is because sysfs automatically exports all module_param declarations to the sysfs file system.. which means those variables can be dynamically evaluated at any later time, which of course means marking them __initdata is a bad idea ;).. when they happen to be char *'s it is an especially bad idea ;). Applying the patch below clears up the OOPS for me. Signed-off-by: Patrick McManus Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/intelfb/intelfbdrv.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c index 549e22939260..25f9a9a65c24 100644 --- a/drivers/video/intelfb/intelfbdrv.c +++ b/drivers/video/intelfb/intelfbdrv.c @@ -228,17 +228,17 @@ MODULE_DESCRIPTION( MODULE_LICENSE("Dual BSD/GPL"); MODULE_DEVICE_TABLE(pci, intelfb_pci_table); -static int accel __initdata = 1; -static int vram __initdata = 4; -static int hwcursor __initdata = 1; -static int mtrr __initdata = 1; -static int fixed __initdata = 0; -static int noinit __initdata = 0; -static int noregister __initdata = 0; -static int probeonly __initdata = 0; -static int idonly __initdata = 0; -static int bailearly __initdata = 0; -static char *mode __initdata = NULL; +static int accel = 1; +static int vram = 4; +static int hwcursor = 1; +static int mtrr = 1; +static int fixed = 0; +static int noinit = 0; +static int noregister = 0; +static int probeonly = 0; +static int idonly = 0; +static int bailearly = 0; +static char *mode = NULL; module_param(accel, bool, S_IRUGO); MODULE_PARM_DESC(accel, "Enable console acceleration"); From 5212dd58e67e4b8009107d69a9de45dd2e687496 Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sat, 28 May 2005 15:51:47 -0700 Subject: [PATCH 043/155] [PATCH] input: Fix fast scrolling scancodes in atkbd.c Signed-off-by: Vojtech Pavlik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/input/keyboard/atkbd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 79c332f16fc7..af0446c6de82 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -171,9 +171,9 @@ static struct { unsigned char set2; } atkbd_scroll_keys[] = { { ATKBD_SCR_1, 0xc5 }, - { ATKBD_SCR_2, 0xa9 }, - { ATKBD_SCR_4, 0xb6 }, - { ATKBD_SCR_8, 0xa7 }, + { ATKBD_SCR_2, 0x9d }, + { ATKBD_SCR_4, 0xa4 }, + { ATKBD_SCR_8, 0x9b }, { ATKBD_SCR_CLICK, 0xe0 }, { ATKBD_SCR_LEFT, 0xcb }, { ATKBD_SCR_RIGHT, 0xd2 }, From 203fe8b3d1f5b1b527e86f6dbe5b75960acb7f4f Mon Sep 17 00:00:00 2001 From: Manu Abraham Date: Sat, 28 May 2005 15:51:48 -0700 Subject: [PATCH 044/155] [PATCH] dvb: Fix Mini DiSEqC bug The bug was visible as a warning with gcc-3.4.4 (prerelease) Message: drivers/media/dvb/bt8xx/dst.c:1349: warning: initialization from incompatible pointer type. Signed-off-by: Manu Abraham Cc: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index d047e349d706..2efc6f1caf84 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -915,13 +915,11 @@ static int dst_tone_power_cmd(struct dst_state* state) paket[2] = 0x02; else paket[2] = 0; - if (state->minicmd == SEC_MINI_A) - paket[3] = 0x02; - else - paket[3] = 0; + paket[3] = state->tx_tuna[3]; paket[7] = dst_check_sum (paket, 7); dst_command(state, paket, 8); + return 0; } @@ -1134,6 +1132,29 @@ static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) return 0; } +static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) +{ + struct dst_state *state = fe->demodulator_priv; + + if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) + return 0; + + state->minicmd = minicmd; + + switch (minicmd) { + case SEC_MINI_A: + state->tx_tuna[3] = 0x02; + break; + case SEC_MINI_B: + state->tx_tuna[3] = 0xff; + break; + } + dst_tone_power_cmd(state); + + return 0; +} + + static int dst_init(struct dvb_frontend* fe) { struct dst_state* state = (struct dst_state*) fe->demodulator_priv; @@ -1346,7 +1367,7 @@ static struct dvb_frontend_ops dst_dvbs_ops = { .read_signal_strength = dst_read_signal_strength, .read_snr = dst_read_snr, - .diseqc_send_burst = dst_set_tone, + .diseqc_send_burst = dst_send_burst, .diseqc_send_master_cmd = dst_set_diseqc, .set_voltage = dst_set_voltage, .set_tone = dst_set_tone, From 0eac3e486e1f246a9d59fee9251cc69e409cb58e Mon Sep 17 00:00:00 2001 From: Manu Abraham Date: Sat, 28 May 2005 15:51:50 -0700 Subject: [PATCH 045/155] [PATCH] dvb: Remove unnecessary casts Cleanup unnecessary (and undesirable) casts, demodulator_priv is already a void*. Suggestion from Andrew Morton Signed-off-by: Manu Abraham Cc: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 2efc6f1caf84..e5e8c3e869c5 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -978,7 +978,7 @@ static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage); static int dst_write_tuna(struct dvb_frontend* fe) { - struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + struct dst_state* state = fe->demodulator_priv; int retval; u8 reply; @@ -1046,7 +1046,7 @@ static int dst_write_tuna(struct dvb_frontend* fe) static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) { - struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + struct dst_state* state = fe->demodulator_priv; u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; if (state->dst_type == DST_TYPE_IS_TERR) @@ -1064,7 +1064,7 @@ static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) { u8 *val; int need_cmd; - struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + struct dst_state* state = fe->demodulator_priv; state->voltage = voltage; @@ -1105,7 +1105,7 @@ static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { u8 *val; - struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + struct dst_state* state = fe->demodulator_priv; state->tone = tone; @@ -1157,7 +1157,7 @@ static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) static int dst_init(struct dvb_frontend* fe) { - struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + struct dst_state* state = fe->demodulator_priv; static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 }; static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 }; static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; @@ -1189,7 +1189,7 @@ static int dst_init(struct dvb_frontend* fe) static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status) { - struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + struct dst_state* state = fe->demodulator_priv; *status = 0; if (state->diseq_flags & HAS_LOCK) { @@ -1203,7 +1203,7 @@ static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status) static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength) { - struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + struct dst_state* state = fe->demodulator_priv; dst_get_signal(state); *strength = state->decode_strength; @@ -1213,7 +1213,7 @@ static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength) static int dst_read_snr(struct dvb_frontend* fe, u16* snr) { - struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + struct dst_state* state = fe->demodulator_priv; dst_get_signal(state); *snr = state->decode_snr; @@ -1223,7 +1223,7 @@ static int dst_read_snr(struct dvb_frontend* fe, u16* snr) static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + struct dst_state* state = fe->demodulator_priv; dst_set_freq(state, p->frequency); if (verbose > 4) @@ -1249,7 +1249,7 @@ static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + struct dst_state* state = fe->demodulator_priv; p->frequency = state->decode_freq; p->inversion = state->inversion; @@ -1269,7 +1269,7 @@ static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet static void dst_release(struct dvb_frontend* fe) { - struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + struct dst_state* state = fe->demodulator_priv; kfree(state); } From 8f6da8f166228c1720d16216a9d82d630c58de57 Mon Sep 17 00:00:00 2001 From: Manu Abraham Date: Sat, 28 May 2005 15:51:51 -0700 Subject: [PATCH 046/155] [PATCH] dvb: Fix LNB power switching Signed-off-by: Manu Abraham Cc: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 40 +++++++++++++---------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index e5e8c3e869c5..33cca69d67a7 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -906,10 +906,7 @@ static int dst_tone_power_cmd(struct dst_state* state) if (state->dst_type == DST_TYPE_IS_TERR) return 0; - if (state->voltage == SEC_VOLTAGE_OFF) - paket[4] = 0; - else - paket[4] = 1; + paket[4] = state->tx_tuna[4]; if (state->tone == SEC_TONE_ON) paket[2] = 0x02; @@ -1062,7 +1059,6 @@ static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) { - u8 *val; int need_cmd; struct dst_state* state = fe->demodulator_priv; @@ -1072,29 +1068,23 @@ static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) return 0; need_cmd = 0; - val = &state->tx_tuna[0]; - val[8] &= ~0x40; switch (voltage) { - case SEC_VOLTAGE_13: - if ((state->diseq_flags & HAS_POWER) == 0) + case SEC_VOLTAGE_13: + case SEC_VOLTAGE_18: + if ((state->diseq_flags & HAS_POWER) == 0) + need_cmd = 1; + state->diseq_flags |= HAS_POWER; + state->tx_tuna[4] = 0x01; + break; + + case SEC_VOLTAGE_OFF: need_cmd = 1; - state->diseq_flags |= HAS_POWER; - break; + state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); + state->tx_tuna[4] = 0x00; + break; - case SEC_VOLTAGE_18: - if ((state->diseq_flags & HAS_POWER) == 0) - need_cmd = 1; - state->diseq_flags |= HAS_POWER; - val[8] |= 0x40; - break; - - case SEC_VOLTAGE_OFF: - need_cmd = 1; - state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); - break; - - default: - return -EINVAL; + default: + return -EINVAL; } if (need_cmd) dst_tone_power_cmd(state); From 86360a3edeb6b7b6230dc13ef6835d2851409502 Mon Sep 17 00:00:00 2001 From: Manu Abraham Date: Sat, 28 May 2005 15:51:51 -0700 Subject: [PATCH 047/155] [PATCH] dvb: Fix 22k tone control Signed-off-by: Manu Abraham Cc: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 33cca69d67a7..8104240a2208 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -907,12 +907,7 @@ static int dst_tone_power_cmd(struct dst_state* state) return 0; paket[4] = state->tx_tuna[4]; - - if (state->tone == SEC_TONE_ON) - paket[2] = 0x02; - else - paket[2] = 0; - + paket[2] = state->tx_tuna[2]; paket[3] = state->tx_tuna[3]; paket[7] = dst_check_sum (paket, 7); dst_command(state, paket, 8); @@ -1094,7 +1089,6 @@ static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { - u8 *val; struct dst_state* state = fe->demodulator_priv; state->tone = tone; @@ -1102,20 +1096,17 @@ static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) if (state->dst_type == DST_TYPE_IS_TERR) return 0; - val = &state->tx_tuna[0]; - - val[8] &= ~0x1; - switch (tone) { - case SEC_TONE_OFF: - break; + case SEC_TONE_OFF: + state->tx_tuna[2] = 0xff; + break; - case SEC_TONE_ON: - val[8] |= 1; - break; + case SEC_TONE_ON: + state->tx_tuna[2] = 0x02; + break; - default: - return -EINVAL; + default: + return -EINVAL; } dst_tone_power_cmd(state); From 226d97ec3e47b54ecc13f6ea3c300dc6a1b290c3 Mon Sep 17 00:00:00 2001 From: Manu Abraham Date: Sat, 28 May 2005 15:51:52 -0700 Subject: [PATCH 048/155] [PATCH] dvb: Small cleanup Miscellaneous cleanup Signed-off-by: Manu Abraham Cc: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/media/dvb/bt8xx/dst.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 8104240a2208..1339912c308b 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1041,7 +1041,7 @@ static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* struct dst_state* state = fe->demodulator_priv; u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; - if (state->dst_type == DST_TYPE_IS_TERR) + if (state->dst_type != DST_TYPE_IS_SAT) return 0; if (cmd->msg_len == 0 || cmd->msg_len > 4) @@ -1059,7 +1059,7 @@ static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) state->voltage = voltage; - if (state->dst_type == DST_TYPE_IS_TERR) + if (state->dst_type != DST_TYPE_IS_SAT) return 0; need_cmd = 0; @@ -1093,7 +1093,7 @@ static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) state->tone = tone; - if (state->dst_type == DST_TYPE_IS_TERR) + if (state->dst_type != DST_TYPE_IS_SAT) return 0; switch (tone) { @@ -1117,7 +1117,7 @@ static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd) { struct dst_state *state = fe->demodulator_priv; - if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) + if (state->dst_type != DST_TYPE_IS_SAT) return 0; state->minicmd = minicmd; From b9e0d0696c9e86d4e40b23039feefb8c377cb524 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sat, 28 May 2005 15:51:53 -0700 Subject: [PATCH 049/155] [PATCH] uml: fix a couple of warnings Eliminate an unused variable warning in ptrace.c and a size mismatch warning by adding a cast to __pa. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/ptrace.c | 19 +++---------------- include/asm-um/page.h | 8 +++++++- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 2925e15324de..71af4d503899 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -322,11 +322,9 @@ void syscall_trace(union uml_pt_regs *regs, int entryexit) UPT_SYSCALL_ARG2(regs), UPT_SYSCALL_ARG3(regs), UPT_SYSCALL_ARG4(regs)); - else { - int res = UPT_SYSCALL_RET(regs); - audit_syscall_exit(current, AUDITSC_RESULT(res), - res); - } + else audit_syscall_exit(current, + AUDITSC_RESULT(UPT_SYSCALL_RET(regs)), + UPT_SYSCALL_RET(regs)); } /* Fake a debug trap */ @@ -356,14 +354,3 @@ void syscall_trace(union uml_pt_regs *regs, int entryexit) current->exit_code = 0; } } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/include/asm-um/page.h b/include/asm-um/page.h index 504ea8e486b0..5afee8a8cdf3 100644 --- a/include/asm-um/page.h +++ b/include/asm-um/page.h @@ -98,7 +98,13 @@ extern unsigned long uml_physmem; extern unsigned long to_phys(void *virt); extern void *to_virt(unsigned long phys); -#define __pa(virt) to_phys((void *) virt) + +/* Cast to unsigned long before casting to void * to avoid a warning from + * mmap_kmem about cutting a long long down to a void *. Not sure that + * casting is the right thing, but 32-bit UML can't have 64-bit virtual + * addresses + */ +#define __pa(virt) to_phys((void *) (unsigned long) virt) #define __va(phys) to_virt((unsigned long) phys) #define page_to_pfn(page) ((page) - mem_map) From 6770cb61ff6d557613a8382b28f9b0a919fb112f Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sat, 28 May 2005 15:51:54 -0700 Subject: [PATCH 050/155] [PATCH] uml: turn off kmalloc always on a fatal signal We should turn off kmalloc when getting a fatal signal regardless of the mode we're in. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/um/kernel/main.c b/arch/um/kernel/main.c index a17c49703f9b..939e3b708670 100644 --- a/arch/um/kernel/main.c +++ b/arch/um/kernel/main.c @@ -71,7 +71,7 @@ static __init void do_uml_initcalls(void) static void last_ditch_exit(int sig) { - CHOOSE_MODE(kmalloc_ok = 0, (void) 0); + kmalloc_ok = 0; signal(SIGINT, SIG_DFL); signal(SIGTERM, SIG_DFL); signal(SIGHUP, SIG_DFL); From a2e4b972c99685d9d7b869c4bf8d8b258ff5b60c Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sat, 28 May 2005 15:51:54 -0700 Subject: [PATCH 051/155] [PATCH] uml: remove 2_5compat.h Remove old useless header that was used in Ye Olde Times during 2.4->2.5 porting to abstract differences. It's definitions are no more used anyway, so let's finally kill it. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/drivers/ssl.c | 1 - arch/um/drivers/stdio_console.c | 1 - arch/um/drivers/ubd_kern.c | 1 - arch/um/include/2_5compat.h | 24 ------------------------ arch/um/kernel/exec_kern.c | 1 - arch/um/kernel/process_kern.c | 2 -- arch/um/kernel/trap_kern.c | 1 - fs/hostfs/hostfs_kern.c | 1 - 8 files changed, 32 deletions(-) delete mode 100644 arch/um/include/2_5compat.h diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c index a2bac429f3d4..b32a77010fbe 100644 --- a/arch/um/drivers/ssl.c +++ b/arch/um/drivers/ssl.c @@ -22,7 +22,6 @@ #include "init.h" #include "irq_user.h" #include "mconsole_kern.h" -#include "2_5compat.h" static int ssl_version = 1; diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c index 361d0be342b3..afbe1e71ed83 100644 --- a/arch/um/drivers/stdio_console.c +++ b/arch/um/drivers/stdio_console.c @@ -28,7 +28,6 @@ #include "irq_user.h" #include "mconsole_kern.h" #include "init.h" -#include "2_5compat.h" #define MAX_TTYS (16) diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 88f956c34fed..7e98e3e168c1 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -49,7 +49,6 @@ #include "irq_user.h" #include "irq_kern.h" #include "ubd_user.h" -#include "2_5compat.h" #include "os.h" #include "mem.h" #include "mem_kern.h" diff --git a/arch/um/include/2_5compat.h b/arch/um/include/2_5compat.h deleted file mode 100644 index abdb015a4d71..000000000000 --- a/arch/um/include/2_5compat.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#ifndef __2_5_COMPAT_H__ -#define __2_5_COMPAT_H__ - -#define INIT_HARDSECT(arr, maj, sizes) - -#define SET_PRI(task) do ; while(0) - -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index 49ddabe69be7..efd222ffe20e 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec_kern.c @@ -16,7 +16,6 @@ #include "kern.h" #include "irq_user.h" #include "tlb.h" -#include "2_5compat.h" #include "os.h" #include "time_user.h" #include "choose-mode.h" diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index c1adf7ba3fd1..ccb6dd6565ec 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -43,7 +43,6 @@ #include "tlb.h" #include "frame_kern.h" #include "sigcontext.h" -#include "2_5compat.h" #include "os.h" #include "mode.h" #include "mode_kern.h" @@ -189,7 +188,6 @@ void default_idle(void) while(1){ /* endless idle loop with no priority at all */ - SET_PRI(current); /* * although we are an idle CPU, we do not want to diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 1de22d8a313a..c20aef120598 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -23,7 +23,6 @@ #include "kern.h" #include "chan_kern.h" #include "mconsole_kern.h" -#include "2_5compat.h" #include "mem.h" #include "mem_kern.h" diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 14a0d339d036..4bf43ea87c46 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -23,7 +23,6 @@ #include "kern_util.h" #include "kern.h" #include "user_util.h" -#include "2_5compat.h" #include "init.h" struct hostfs_inode_info { From 0894e27e7999bdbad2e65734caa1d5de65e7d890 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sat, 28 May 2005 15:51:55 -0700 Subject: [PATCH 052/155] [PATCH] uml: single-space a help message One of the ubd driver help strings was bust. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/drivers/ubd_kern.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 7e98e3e168c1..2a7f6892c55c 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -439,9 +439,9 @@ static int udb_setup(char *str) __setup("udb", udb_setup); __uml_help(udb_setup, "udb\n" -" This option is here solely to catch ubd -> udb typos, which can be\n\n" -" to impossible to catch visually unless you specifically look for\n\n" -" them. The only result of any option starting with 'udb' is an error\n\n" +" This option is here solely to catch ubd -> udb typos, which can be\n" +" to impossible to catch visually unless you specifically look for\n" +" them. The only result of any option starting with 'udb' is an error\n" " in the boot output.\n\n" ); From 92515da73a5df50db45111b8659ac463b4800236 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sat, 28 May 2005 15:51:56 -0700 Subject: [PATCH 053/155] [PATCH] uml: fix segfault on exit with CONFIG_GCOV We need to disable signals on exit in all cases, not just when rebooting. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/main.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/arch/um/kernel/main.c b/arch/um/kernel/main.c index 939e3b708670..e42e6364ca13 100644 --- a/arch/um/kernel/main.c +++ b/arch/um/kernel/main.c @@ -87,7 +87,7 @@ int main(int argc, char **argv, char **envp) { char **new_argv; sigset_t mask; - int ret, i; + int ret, i, err; /* Enable all signals except SIGIO - in some environments, we can * enter with some signals blocked @@ -160,27 +160,29 @@ int main(int argc, char **argv, char **envp) */ change_sig(SIGPROF, 0); + /* This signal stuff used to be in the reboot case. However, + * sometimes a SIGVTALRM can come in when we're halting (reproducably + * when writing out gcov information, presumably because that takes + * some time) and cause a segfault. + */ + + /* stop timers and set SIG*ALRM to be ignored */ + disable_timer(); + + /* disable SIGIO for the fds and set SIGIO to be ignored */ + err = deactivate_all_fds(); + if(err) + printf("deactivate_all_fds failed, errno = %d\n", -err); + + /* Let any pending signals fire now. This ensures + * that they won't be delivered after the exec, when + * they are definitely not expected. + */ + unblock_signals(); + /* Reboot */ if(ret){ - int err; - printf("\n"); - - /* stop timers and set SIG*ALRM to be ignored */ - disable_timer(); - - /* disable SIGIO for the fds and set SIGIO to be ignored */ - err = deactivate_all_fds(); - if(err) - printf("deactivate_all_fds failed, errno = %d\n", - -err); - - /* Let any pending signals fire now. This ensures - * that they won't be delivered after the exec, when - * they are definitely not expected. - */ - unblock_signals(); - execvp(new_argv[0], new_argv); perror("Failed to exec kernel"); ret = 1; From 7590d3ec1cda7d504c25103bde0c9911f93810e9 Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Sat, 28 May 2005 15:51:57 -0700 Subject: [PATCH 054/155] [PATCH] uml: remove unused code This removes two now unused files and a couple of unused functions. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/initrd_kern.c | 59 ----------------------------------- arch/um/kernel/initrd_user.c | 46 --------------------------- arch/um/kernel/process_kern.c | 34 -------------------- 3 files changed, 139 deletions(-) delete mode 100644 arch/um/kernel/initrd_kern.c delete mode 100644 arch/um/kernel/initrd_user.c diff --git a/arch/um/kernel/initrd_kern.c b/arch/um/kernel/initrd_kern.c deleted file mode 100644 index fc568af468b9..000000000000 --- a/arch/um/kernel/initrd_kern.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include "linux/init.h" -#include "linux/bootmem.h" -#include "linux/initrd.h" -#include "asm/types.h" -#include "user_util.h" -#include "kern_util.h" -#include "initrd.h" -#include "init.h" -#include "os.h" - -/* Changed by uml_initrd_setup, which is a setup */ -static char *initrd __initdata = NULL; - -static int __init read_initrd(void) -{ - void *area; - long long size; - int err; - - if(initrd == NULL) return 0; - err = os_file_size(initrd, &size); - if(err) return 0; - area = alloc_bootmem(size); - if(area == NULL) return 0; - if(load_initrd(initrd, area, size) == -1) return 0; - initrd_start = (unsigned long) area; - initrd_end = initrd_start + size; - return 0; -} - -__uml_postsetup(read_initrd); - -static int __init uml_initrd_setup(char *line, int *add) -{ - initrd = line; - return 0; -} - -__uml_setup("initrd=", uml_initrd_setup, -"initrd=\n" -" This is used to boot UML from an initrd image. The argument is the\n" -" name of the file containing the image.\n\n" -); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/initrd_user.c b/arch/um/kernel/initrd_user.c deleted file mode 100644 index cb90681e151c..000000000000 --- a/arch/um/kernel/initrd_user.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include -#include -#include -#include - -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "initrd.h" -#include "os.h" - -int load_initrd(char *filename, void *buf, int size) -{ - int fd, n; - - fd = os_open_file(filename, of_read(OPENFLAGS()), 0); - if(fd < 0){ - printk("Opening '%s' failed - err = %d\n", filename, -fd); - return(-1); - } - n = os_read_file(fd, buf, size); - if(n != size){ - printk("Read of %d bytes from '%s' failed, err = %d\n", size, - filename, -n); - return(-1); - } - - os_close_file(fd); - return(0); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index ccb6dd6565ec..804c6bbdf67c 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -54,18 +54,6 @@ */ struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; -struct task_struct *get_task(int pid, int require) -{ - struct task_struct *ret; - - read_lock(&tasklist_lock); - ret = find_task_by_pid(pid); - read_unlock(&tasklist_lock); - - if(require && (ret == NULL)) panic("get_task couldn't find a task\n"); - return(ret); -} - int external_pid(void *t) { struct task_struct *task = t ? t : current; @@ -210,11 +198,6 @@ int page_size(void) return(PAGE_SIZE); } -unsigned long page_mask(void) -{ - return(PAGE_MASK); -} - void *um_virt_to_phys(struct task_struct *task, unsigned long addr, pte_t *pte_out) { @@ -347,11 +330,6 @@ char *uml_strdup(char *string) return(new); } -void *get_init_task(void) -{ - return(&init_thread_union.thread_info.task); -} - int copy_to_user_proc(void __user *to, void *from, int size) { return(copy_to_user(to, from, size)); @@ -478,15 +456,3 @@ unsigned long arch_align_stack(unsigned long sp) return sp & ~0xf; } #endif - - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ From 34a1a63e37ee8d60bdb842476d9337cdff5413d9 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sat, 28 May 2005 15:51:57 -0700 Subject: [PATCH 055/155] [PATCH] uml: add modversions support Actually, the real support was added by some earlier patches. Now we simply re-enable the config. option. I've actually tested it and it works well. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- init/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/init/Kconfig b/init/Kconfig index d920baed109a..a7660ccc693f 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -442,7 +442,7 @@ config OBSOLETE_MODPARM config MODVERSIONS bool "Module versioning support (EXPERIMENTAL)" - depends on MODULES && EXPERIMENTAL && !UML + depends on MODULES && EXPERIMENTAL help Usually, you have to use modules compiled with your kernel. Saying Y here makes it sometimes possible to use modules From 567b56508f7367e161d6d861ef214a900ab45ce9 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sat, 28 May 2005 15:51:58 -0700 Subject: [PATCH 056/155] [PATCH] uml: add MOD_LICENSE to random driver Add a MODULE_LICENSE("GPL") to the driver, remove some unused macros and add the GPL license (it's GPL-licensed anyway since it's a GPL-derivative, apart that Jeff Dike releases GPL software, in case anybody is wondering). Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/drivers/random.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c index d43e9fab05a7..f9e22198e011 100644 --- a/arch/um/drivers/random.c +++ b/arch/um/drivers/random.c @@ -1,5 +1,10 @@ -/* Much of this ripped from hw_random.c */ - +/* Copyright (C) 2005 Jeff Dike */ +/* Much of this ripped from drivers/char/hw_random.c, see there for other + * copyright. + * + * This software may be used and distributed according to the terms + * of the GNU General Public License, incorporated herein by reference. + */ #include #include #include @@ -12,8 +17,6 @@ */ #define RNG_VERSION "1.0.0" #define RNG_MODULE_NAME "random" -#define RNG_DRIVER_NAME RNG_MODULE_NAME " virtual driver " RNG_VERSION -#define PFX RNG_MODULE_NAME ": " #define RNG_MISCDEV_MINOR 183 /* official */ @@ -98,7 +101,7 @@ static int __init rng_init (void) err = misc_register (&rng_miscdev); if (err) { - printk (KERN_ERR PFX "misc device register failed\n"); + printk (KERN_ERR RNG_MODULE_NAME ": misc device register failed\n"); goto err_out_cleanup_hw; } @@ -120,3 +123,6 @@ static void __exit rng_cleanup (void) module_init (rng_init); module_exit (rng_cleanup); + +MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver"); +MODULE_LICENSE("GPL"); From 37fce857bec00d26d0e8251c909da2bd8736c949 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sat, 28 May 2005 15:51:59 -0700 Subject: [PATCH 057/155] [PATCH] uml: split CONFIG_FRAME_POINTER from DEBUG_INFO Until now, FRAME_POINTER was set = DEBUG_INFO for UML. Change it to be the default way, so that it can be enabled alone (for instance to get better backtraces on crashes). The call-trace dumper which uses the frame pointer is not yet in, I'm going to introduce it in a separate patch. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/Kconfig.debug | 4 ---- lib/Kconfig.debug | 3 ++- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/um/Kconfig.debug b/arch/um/Kconfig.debug index b89989de364d..bd41e4286d0d 100644 --- a/arch/um/Kconfig.debug +++ b/arch/um/Kconfig.debug @@ -2,10 +2,6 @@ menu "Kernel hacking" source "lib/Kconfig.debug" -config FRAME_POINTER - bool - default y if DEBUG_INFO - config PT_PROXY bool "Enable ptrace proxy" depends on XTERM_CHAN && DEBUG_INFO && MODE_TT diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index ac23847ce0e3..0c421295e613 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -151,7 +151,8 @@ config DEBUG_FS config FRAME_POINTER bool "Compile the kernel with frame pointers" - depends on DEBUG_KERNEL && ((X86 && !X86_64) || CRIS || M68K || M68KNOMMU || FRV) + depends on DEBUG_KERNEL && ((X86 && !X86_64) || CRIS || M68K || M68KNOMMU || FRV || UML) + default y if DEBUG_INFO && UML help If you say Y here the resulting kernel image will be slightly larger and slower, but it will give very useful debugging information. From b3461034d7d46455060c8476910be22b6b0fc313 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sat, 28 May 2005 15:52:00 -0700 Subject: [PATCH 058/155] [PATCH] uml: stack dump fix Copy (and adapt) to UML the stack code dumper used in i386 when CONFIG_FRAME_POINTER is enabled. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/sysrq.h | 3 +- arch/um/kernel/sysrq.c | 21 ++++++---- arch/um/sys-i386/sysrq.c | 80 +++++++++++++++++++++++++++++++++++- arch/um/sys-ppc/sysrq.c | 14 +------ arch/um/sys-x86_64/sysrq.c | 11 +---- include/asm-um/thread_info.h | 7 ++-- 6 files changed, 100 insertions(+), 36 deletions(-) diff --git a/arch/um/include/sysrq.h b/arch/um/include/sysrq.h index 2ce9423460b3..c8d332b56b98 100644 --- a/arch/um/include/sysrq.h +++ b/arch/um/include/sysrq.h @@ -1,6 +1,7 @@ #ifndef __UM_SYSRQ_H #define __UM_SYSRQ_H -extern void show_trace(unsigned long *stack); +struct task_struct; +extern void show_trace(struct task_struct* task, unsigned long *stack); #endif diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c index e630438f9e73..f80850091e79 100644 --- a/arch/um/kernel/sysrq.c +++ b/arch/um/kernel/sysrq.c @@ -3,6 +3,7 @@ * Licensed under the GPL */ +#include "linux/config.h" #include "linux/sched.h" #include "linux/kernel.h" #include "linux/module.h" @@ -12,14 +13,14 @@ #include "sysrq.h" #include "user_util.h" -void show_trace(unsigned long * stack) +/* Catch non-i386 SUBARCH's. */ +#if !defined(CONFIG_UML_X86) || defined(CONFIG_64BIT) +void show_trace(struct task_struct *task, unsigned long * stack) { - /* XXX: Copy the CONFIG_FRAME_POINTER stack-walking backtrace from - * arch/i386/kernel/traps.c, and then move this to sys-i386/sysrq.c.*/ unsigned long addr; if (!stack) { - stack = (unsigned long*) &stack; + stack = (unsigned long*) &stack; WARN_ON(1); } @@ -35,6 +36,7 @@ void show_trace(unsigned long * stack) } printk("\n"); } +#endif /* * stack dumps generator - this is used by arch-independent code. @@ -44,7 +46,7 @@ void dump_stack(void) { unsigned long stack; - show_trace(&stack); + show_trace(current, &stack); } EXPORT_SYMBOL(dump_stack); @@ -59,7 +61,11 @@ void show_stack(struct task_struct *task, unsigned long *esp) int i; if (esp == NULL) { - if (task != current) { + if (task != current && task != NULL) { + /* XXX: Isn't this bogus? I.e. isn't this the + * *userspace* stack of this task? If not so, use this + * even when task == current (as in i386). + */ esp = (unsigned long *) KSTK_ESP(task); /* Which one? No actual difference - just coding style.*/ //esp = (unsigned long *) PT_REGS_IP(&task->thread.regs); @@ -77,5 +83,6 @@ void show_stack(struct task_struct *task, unsigned long *esp) printk("%08lx ", *stack++); } - show_trace(esp); + printk("Call Trace: \n"); + show_trace(current, esp); } diff --git a/arch/um/sys-i386/sysrq.c b/arch/um/sys-i386/sysrq.c index 281fc7b8ca00..e3706d15c4f5 100644 --- a/arch/um/sys-i386/sysrq.c +++ b/arch/um/sys-i386/sysrq.c @@ -3,12 +3,15 @@ * Licensed under the GPL */ +#include "linux/config.h" #include "linux/kernel.h" #include "linux/smp.h" #include "linux/sched.h" +#include "linux/kallsyms.h" #include "asm/ptrace.h" #include "sysrq.h" +/* This is declared by */ void show_regs(struct pt_regs *regs) { printk("\n"); @@ -31,5 +34,80 @@ void show_regs(struct pt_regs *regs) 0xffff & PT_REGS_DS(regs), 0xffff & PT_REGS_ES(regs)); - show_trace((unsigned long *) ®s); + show_trace(NULL, (unsigned long *) ®s); } + +/* Copied from i386. */ +static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) +{ + return p > (void *)tinfo && + p < (void *)tinfo + THREAD_SIZE - 3; +} + +/* Adapted from i386 (we also print the address we read from). */ +static inline unsigned long print_context_stack(struct thread_info *tinfo, + unsigned long *stack, unsigned long ebp) +{ + unsigned long addr; + +#ifdef CONFIG_FRAME_POINTER + while (valid_stack_ptr(tinfo, (void *)ebp)) { + addr = *(unsigned long *)(ebp + 4); + printk("%08lx: [<%08lx>]", ebp + 4, addr); + print_symbol(" %s", addr); + printk("\n"); + ebp = *(unsigned long *)ebp; + } +#else + while (valid_stack_ptr(tinfo, stack)) { + addr = *stack; + if (__kernel_text_address(addr)) { + printk("%08lx: [<%08lx>]", (unsigned long) stack, addr); + print_symbol(" %s", addr); + printk("\n"); + } + stack++; + } +#endif + return ebp; +} + +void show_trace(struct task_struct* task, unsigned long * stack) +{ + unsigned long ebp; + struct thread_info *context; + + /* Turn this into BUG_ON if possible. */ + if (!stack) { + stack = (unsigned long*) &stack; + printk("show_trace: got NULL stack, implicit assumption task == current"); + WARN_ON(1); + } + + if (!task) + task = current; + + if (task != current) { + //ebp = (unsigned long) KSTK_EBP(task); + /* Which one? No actual difference - just coding style.*/ + ebp = (unsigned long) PT_REGS_EBP(&task->thread.regs); + } else { + asm ("movl %%ebp, %0" : "=r" (ebp) : ); + } + + context = (struct thread_info *) + ((unsigned long)stack & (~(THREAD_SIZE - 1))); + print_context_stack(context, stack, ebp); + + /*while (((long) stack & (THREAD_SIZE-1)) != 0) { + addr = *stack; + if (__kernel_text_address(addr)) { + printk("%08lx: [<%08lx>]", (unsigned long) stack, addr); + print_symbol(" %s", addr); + printk("\n"); + } + stack++; + }*/ + printk("\n"); +} + diff --git a/arch/um/sys-ppc/sysrq.c b/arch/um/sys-ppc/sysrq.c index 82d6e9335bb6..2f816f1a0ff4 100644 --- a/arch/um/sys-ppc/sysrq.c +++ b/arch/um/sys-ppc/sysrq.c @@ -27,17 +27,5 @@ void show_regs(struct pt_regs_subarch *regs) 0xffff & regs->xds, 0xffff & regs->xes); #endif - show_trace(®s->gpr[1]); + show_trace(current, ®s->gpr[1]); } - - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/sys-x86_64/sysrq.c b/arch/um/sys-x86_64/sysrq.c index ddf74691a610..d0a25af19a5b 100644 --- a/arch/um/sys-x86_64/sysrq.c +++ b/arch/um/sys-x86_64/sysrq.c @@ -36,14 +36,5 @@ void __show_regs(struct pt_regs * regs) void show_regs(struct pt_regs *regs) { __show_regs(regs); - show_trace((unsigned long *) ®s); + show_trace(current, (unsigned long *) ®s); } - -/* Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h index a10ea155907e..e4f0198240c5 100644 --- a/include/asm-um/thread_info.h +++ b/include/asm-um/thread_info.h @@ -41,18 +41,17 @@ struct thread_info { #define init_thread_info (init_thread_union.thread_info) #define init_stack (init_thread_union.stack) +#define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE) /* how to get the thread information struct from C */ static inline struct thread_info *current_thread_info(void) { struct thread_info *ti; - unsigned long mask = PAGE_SIZE * - (1 << CONFIG_KERNEL_STACK_ORDER) - 1; - ti = (struct thread_info *) (((unsigned long) &ti) & ~mask); + unsigned long mask = THREAD_SIZE - 1; + ti = (struct thread_info *) (((unsigned long) &ti) & ~mask); return ti; } /* thread information allocation */ -#define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE) #define alloc_thread_info(tsk) \ ((struct thread_info *) kmalloc(THREAD_SIZE, GFP_KERNEL)) #define free_thread_info(ti) kfree(ti) From affac4bcbba617d7329b04c7882bc49a9826e12f Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sat, 28 May 2005 15:52:00 -0700 Subject: [PATCH 059/155] [PATCH] uml: fix PREEMPT_ACTIVE This is a continuation for UML of: http://linux.bkbits.net:8080/linux-2.5/cset@41791ab52lfMuF2i3V-eTIGRBbDYKQ Signed-off-by: Paolo 'Blaisorblade' Giarrusso Cc: Paul Mackerras Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-um/thread_info.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h index e4f0198240c5..1feaaf148ef1 100644 --- a/include/asm-um/thread_info.h +++ b/include/asm-um/thread_info.h @@ -61,7 +61,7 @@ static inline struct thread_info *current_thread_info(void) #endif -#define PREEMPT_ACTIVE 0x4000000 +#define PREEMPT_ACTIVE 0x10000000 #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ #define TIF_SIGPENDING 1 /* signal pending */ From 37053cc84d51a790a6e5c3987665902cdab122a5 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Sat, 28 May 2005 15:52:01 -0700 Subject: [PATCH 060/155] [PATCH] sh: PREEMPT_ACTIVE fix Port Paulus's ppc64 fix to sh: When the generic IRQ stuff went in, it seems that HARDIRQ_BITS got bumped from 9 (for ppc64) up to 12. Consequently, the PREEMPT_ACTIVE bit is now within HARDIRQ_MASK, and I get in_interrupt() falsely returning true when PREEMPT_ACTIVE is set, and thus a BUG_ON tripping in arch/ppc64/mm/tlb.c. Signed-off-by: Paul Mundt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-sh/thread_info.h | 2 +- include/asm-sh64/thread_info.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/asm-sh/thread_info.h b/include/asm-sh/thread_info.h index d82f883d8e6d..4bbbd9f3c37e 100644 --- a/include/asm-sh/thread_info.h +++ b/include/asm-sh/thread_info.h @@ -27,7 +27,7 @@ struct thread_info { #endif -#define PREEMPT_ACTIVE 0x4000000 +#define PREEMPT_ACTIVE 0x10000000 /* * macros/functions for gaining access to the thread information structure diff --git a/include/asm-sh64/thread_info.h b/include/asm-sh64/thread_info.h index e65f394da472..8a32d6bd0b79 100644 --- a/include/asm-sh64/thread_info.h +++ b/include/asm-sh64/thread_info.h @@ -73,7 +73,7 @@ static inline struct thread_info *current_thread_info(void) #define THREAD_SIZE 8192 -#define PREEMPT_ACTIVE 0x4000000 +#define PREEMPT_ACTIVE 0x10000000 /* thread information flags */ #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ From 8f28e8fa46625310102aea06fac61ba04c8b5b88 Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sat, 28 May 2005 15:52:02 -0700 Subject: [PATCH 061/155] [PATCH] irq code: Add coherence test for PREEMPT_ACTIVE After porting this fixlet to UML: http://linux.bkbits.net:8080/linux-2.5/cset@41791ab52lfMuF2i3V-eTIGRBbDYKQ , I've also added a warning which should refuse compilation with insane values for PREEMPT_ACTIVE... maybe we should simply move PREEMPT_ACTIVE out of architectures using GENERIC_IRQS. Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/hardirq.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h index ebc712e91066..8336dba18971 100644 --- a/include/linux/hardirq.h +++ b/include/linux/hardirq.h @@ -43,13 +43,17 @@ #define __IRQ_MASK(x) ((1UL << (x))-1) #define PREEMPT_MASK (__IRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT) -#define HARDIRQ_MASK (__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT) #define SOFTIRQ_MASK (__IRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) +#define HARDIRQ_MASK (__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT) #define PREEMPT_OFFSET (1UL << PREEMPT_SHIFT) #define SOFTIRQ_OFFSET (1UL << SOFTIRQ_SHIFT) #define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT) +#if PREEMPT_ACTIVE < (1 << (HARDIRQ_SHIFT + HARDIRQ_BITS)) +#error PREEMPT_ACTIVE is too low! +#endif + #define hardirq_count() (preempt_count() & HARDIRQ_MASK) #define softirq_count() (preempt_count() & SOFTIRQ_MASK) #define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK)) From f767b02f35a3db5c1b1c6454992c070510cef07f Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sat, 28 May 2005 15:52:03 -0700 Subject: [PATCH 062/155] [PATCH] uml: fixlet for arch_prctl_skas Fix it a bit (after some cross checking with "man arch_prctl"). There were: *) typos FS/GS and back *) FS in place of FS_BASE (and the same for GS) *) the procedure used put_user on &addr, where addr was the parameter (i.e. changed its param with put_user, completely useless) rather than interpreting addr as a pointer, as requested in this case (see the man page). Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/sys-x86_64/syscalls.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c index d4a59657fb99..6f44f40204ed 100644 --- a/arch/um/sys-x86_64/syscalls.c +++ b/arch/um/sys-x86_64/syscalls.c @@ -133,23 +133,27 @@ static long arch_prctl_tt(int code, unsigned long addr) #ifdef CONFIG_MODE_SKAS +/* XXX: Must also call arch_prctl in the host, beside saving the segment bases! */ static long arch_prctl_skas(int code, unsigned long addr) { long ret = 0; switch(code){ - case ARCH_SET_GS: - current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr; - break; case ARCH_SET_FS: current->thread.regs.regs.skas.regs[FS_BASE / sizeof(unsigned long)] = addr; break; + case ARCH_SET_GS: + current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr; + break; case ARCH_GET_FS: - ret = put_user(current->thread.regs.regs.skas.regs[GS / sizeof(unsigned long)], &addr); + ret = put_user(current->thread.regs.regs.skas. + regs[FS_BASE / sizeof(unsigned long)], + (unsigned long __user *)addr); break; case ARCH_GET_GS: - ret = put_user(current->thread.regs.regs.skas.regs[FS / sizeof(unsigned \ -long)], &addr); + ret = put_user(current->thread.regs.regs.skas. + regs[GS_BASE / sizeof(unsigned long)], + (unsigned long __user *)addr); break; default: ret = -EINVAL; From 8e21683bb458c73c6fe87844202a64eac730995e Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Sat, 28 May 2005 15:52:04 -0700 Subject: [PATCH 063/155] [PATCH] uml: remove jail mode + other leftovers This var is currently useless, as it's apparent from reading the code. Until 2.6.11 it was used in some code related to jail mode, in the same proc.: if(jail){ while(!reading) sched_yield(); } jail mode has been dropped, together with that use, so let's finish dropping this. Also, remove some other useless definitions I met. Acked-by: Jeff Dike Signed-off-by: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/tt/process_kern.c | 8 +------- arch/um/kernel/um_arch.c | 6 ------ include/asm-um/pgtable.h | 8 -------- 3 files changed, 1 insertion(+), 21 deletions(-) diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index df810ca8fc12..776310fd5b8b 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -32,10 +32,6 @@ void *switch_to_tt(void *prev, void *next, void *last) unsigned long flags; int err, vtalrm, alrm, prof, cpu; char c; - /* jailing and SMP are incompatible, so this doesn't need to be - * made per-cpu - */ - static int reading; from = prev; to = next; @@ -59,13 +55,11 @@ void *switch_to_tt(void *prev, void *next, void *last) c = 0; set_current(to); - reading = 0; err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); if(err != sizeof(c)) panic("write of switch_pipe failed, err = %d", -err); - reading = 1; - if(from->thread.mode.tt.switch_pipe[0] == -1) + if(from->thread.mode.tt.switch_pipe[0] == -1) os_kill_process(os_getpid(), 0); err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c)); diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 4d10ec372a67..418427107b29 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -111,12 +111,6 @@ struct seq_operations cpuinfo_op = { .show = show_cpuinfo, }; -pte_t * __bad_pagetable(void) -{ - panic("Someone should implement __bad_pagetable"); - return(NULL); -} - /* Set in linux_main */ unsigned long host_task_size; unsigned long task_size; diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h index 510e513c7f88..a88040920311 100644 --- a/include/asm-um/pgtable.h +++ b/include/asm-um/pgtable.h @@ -114,17 +114,9 @@ extern unsigned long end_iomem; extern unsigned long pg0[1024]; /* - * BAD_PAGETABLE is used when we need a bogus page-table, while - * BAD_PAGE is used for a bogus page. - * * ZERO_PAGE is a global shared page that is always zero: used * for zero-mapped memory areas etc.. */ -extern pte_t __bad_page(void); -extern pte_t * __bad_pagetable(void); - -#define BAD_PAGETABLE __bad_pagetable() -#define BAD_PAGE __bad_page() #define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page) From 94b9f46d61904422c498bf4cf9a90cc14398d311 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sat, 28 May 2005 15:52:05 -0700 Subject: [PATCH 064/155] [PATCH] ppc32: Fix uImage make target to report success correctly The existing make rule when building a uImage would check to see if the image file existed to report 'is ready' or 'not made'. However make appeared to compute the file list before the rule was executed. Signed-off-by: Chris Clark Signed-off-by: Kumar Gala Signed-off-by: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/boot/images/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/ppc/boot/images/Makefile b/arch/ppc/boot/images/Makefile index f850fb0fb511..c9ac5f5fa9e4 100644 --- a/arch/ppc/boot/images/Makefile +++ b/arch/ppc/boot/images/Makefile @@ -22,7 +22,8 @@ targets += uImage $(obj)/uImage: $(obj)/vmlinux.gz $(Q)rm -f $@ $(call if_changed,uimage) - @echo ' Image: $@' $(if $(wildcard $@),'is ready','not made') + @echo -n ' Image: $@ ' + @if [ -f $@ ]; then echo 'is ready' ; else echo 'not made'; fi # Files generated that shall be removed upon make clean clean-files := sImage vmapus vmlinux* miboot* zImage* uImage From 252fcaed48fc5473b3fc3cafbf977244b0cbf670 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sat, 28 May 2005 15:52:06 -0700 Subject: [PATCH 065/155] [PATCH] ppc32: Fix some minor issues related to FSL Book-E KGDB support Some debug registers needed to be initialized early on to allow proper support for KGDB. Additionally, we need to setup the ppc.md_early_serial_map function pointer on boards that have serial support for KGDB. Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/kernel/head_fsl_booke.S | 15 ++++++++++++++- arch/ppc/platforms/85xx/mpc8540_ads.c | 3 +++ arch/ppc/platforms/85xx/mpc85xx_cds_common.c | 3 +++ arch/ppc/platforms/85xx/sbc8560.c | 3 +++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S index f22ddce36135..ce36e88ba627 100644 --- a/arch/ppc/kernel/head_fsl_booke.S +++ b/arch/ppc/kernel/head_fsl_booke.S @@ -232,7 +232,8 @@ skpinv: addi r6,r6,1 /* Increment */ tlbwe /* 7. Jump to KERNELBASE mapping */ - li r7,0 + lis r7,MSR_KERNEL@h + ori r7,r7,MSR_KERNEL@l bl 1f /* Find our address */ 1: mflr r9 rlwimi r6,r9,0,20,31 @@ -293,6 +294,18 @@ skpinv: addi r6,r6,1 /* Increment */ mtspr SPRN_HID0, r2 #endif +#if !defined(CONFIG_BDI_SWITCH) + /* + * The Abatron BDI JTAG debugger does not tolerate others + * mucking with the debug registers. + */ + lis r2,DBCR0_IDM@h + mtspr SPRN_DBCR0,r2 + /* clear any residual debug events */ + li r2,-1 + mtspr SPRN_DBSR,r2 +#endif + /* * This is where the main kernel code starts. */ diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c index 4d857d6d633d..583838ab02d8 100644 --- a/arch/ppc/platforms/85xx/mpc8540_ads.c +++ b/arch/ppc/platforms/85xx/mpc8540_ads.c @@ -210,6 +210,9 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, #if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG) ppc_md.progress = gen550_progress; #endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */ +#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_KGDB) + ppc_md.early_serial_map = mpc85xx_early_serial_map; +#endif /* CONFIG_SERIAL_8250 && CONFIG_KGDB */ if (ppc_md.progress) ppc_md.progress("mpc8540ads_init(): exit", 0); diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index 6c020d67ad70..11fb758d269f 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -459,6 +459,9 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, #if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG) ppc_md.progress = gen550_progress; #endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */ +#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_KGDB) + ppc_md.early_serial_map = mpc85xx_early_serial_map; +#endif /* CONFIG_SERIAL_8250 && CONFIG_KGDB */ if (ppc_md.progress) ppc_md.progress("mpc85xx_cds_init(): exit", 0); diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c index 9ab05e590c3e..7b9e1543e175 100644 --- a/arch/ppc/platforms/85xx/sbc8560.c +++ b/arch/ppc/platforms/85xx/sbc8560.c @@ -221,6 +221,9 @@ platform_init(unsigned long r3, unsigned long r4, unsigned long r5, #if defined(CONFIG_SERIAL_8250) && defined(CONFIG_SERIAL_TEXT_DEBUG) ppc_md.progress = gen550_progress; #endif /* CONFIG_SERIAL_8250 && CONFIG_SERIAL_TEXT_DEBUG */ +#if defined(CONFIG_SERIAL_8250) && defined(CONFIG_KGDB) + ppc_md.early_serial_map = sbc8560_early_serial_map; +#endif /* CONFIG_SERIAL_8250 && CONFIG_KGDB */ if (ppc_md.progress) ppc_md.progress("sbc8560_init(): exit", 0); From ed36959621451da7195be83b87878b060ce64724 Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sat, 28 May 2005 15:52:07 -0700 Subject: [PATCH 066/155] [PATCH] ppc32: Add VIA IDE support to MPC8555 CDS platform Add support for the VIA IDE controller that exists on the MPC8555 CDS system. Updated the config for the system to enable support by default. Signed-off-by: Scott Hall Signed-off-by: Kumar Gala Cc: Bartlomiej Zolnierkiewicz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/configs/mpc8555_cds_defconfig | 117 ++++++++++++---- arch/ppc/platforms/85xx/mpc85xx_cds_common.c | 138 ++++++++++++++++++- arch/ppc/platforms/85xx/mpc85xx_cds_common.h | 3 + arch/ppc/syslib/Makefile | 2 +- arch/ppc/syslib/ppc85xx_setup.c | 16 +++ 5 files changed, 248 insertions(+), 28 deletions(-) diff --git a/arch/ppc/configs/mpc8555_cds_defconfig b/arch/ppc/configs/mpc8555_cds_defconfig index 728bd9e1a8fa..15abebf46b96 100644 --- a/arch/ppc/configs/mpc8555_cds_defconfig +++ b/arch/ppc/configs/mpc8555_cds_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.11-rc1 -# Thu Jan 20 01:25:35 2005 +# Linux kernel version: 2.6.12-rc4 +# Tue May 17 11:56:01 2005 # CONFIG_MMU=y CONFIG_GENERIC_HARDIRQS=y @@ -11,6 +11,7 @@ CONFIG_HAVE_DEC_LOCK=y CONFIG_PPC=y CONFIG_PPC32=y CONFIG_GENERIC_NVRAM=y +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y # # Code maturity level options @@ -18,6 +19,7 @@ CONFIG_GENERIC_NVRAM=y CONFIG_EXPERIMENTAL=y CONFIG_CLEAN_COMPILE=y CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 # # General setup @@ -29,12 +31,14 @@ CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set -CONFIG_LOG_BUF_SHIFT=14 # CONFIG_HOTPLUG is not set CONFIG_KOBJECT_UEVENT=y # CONFIG_IKCONFIG is not set CONFIG_EMBEDDED=y # CONFIG_KALLSYMS is not set +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_BASE_FULL=y CONFIG_FUTEX=y # CONFIG_EPOLL is not set # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set @@ -44,6 +48,7 @@ CONFIG_CC_ALIGN_LABELS=0 CONFIG_CC_ALIGN_LOOPS=0 CONFIG_CC_ALIGN_JUMPS=0 # CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 # # Loadable module support @@ -62,10 +67,12 @@ CONFIG_CC_ALIGN_JUMPS=0 CONFIG_E500=y CONFIG_BOOKE=y CONFIG_FSL_BOOKE=y +# CONFIG_PHYS_64BIT is not set CONFIG_SPE=y CONFIG_MATH_EMULATION=y # CONFIG_CPU_FREQ is not set CONFIG_PPC_GEN550=y +# CONFIG_PM is not set CONFIG_85xx=y CONFIG_PPC_INDIRECT_PCI_BE=y @@ -76,6 +83,7 @@ CONFIG_PPC_INDIRECT_PCI_BE=y CONFIG_MPC8555_CDS=y # CONFIG_MPC8560_ADS is not set # CONFIG_SBC8560 is not set +# CONFIG_STX_GP3 is not set CONFIG_MPC8555=y CONFIG_85xx_PCI2=y @@ -90,6 +98,7 @@ CONFIG_CPM2=y CONFIG_BINFMT_ELF=y # CONFIG_BINFMT_MISC is not set # CONFIG_CMDLINE_BOOL is not set +CONFIG_ISA_DMA_API=y # # Bus options @@ -104,10 +113,6 @@ CONFIG_PCI_NAMES=y # # CONFIG_PCCARD is not set -# -# PC-card bridges -# - # # Advanced setup # @@ -180,7 +185,59 @@ CONFIG_IOSCHED_CFQ=y # # ATA/ATAPI/MFM/RLL support # -# CONFIG_IDE is not set +CONFIG_IDE=y +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_IDE_SATA is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +CONFIG_IDE_GENERIC=y +CONFIG_BLK_DEV_IDEPCI=y +CONFIG_IDEPCI_SHARE_IRQ=y +# CONFIG_BLK_DEV_OFFBOARD is not set +CONFIG_BLK_DEV_GENERIC=y +# CONFIG_BLK_DEV_OPTI621 is not set +# CONFIG_BLK_DEV_SL82C105 is not set +CONFIG_BLK_DEV_IDEDMA_PCI=y +# CONFIG_BLK_DEV_IDEDMA_FORCED is not set +CONFIG_IDEDMA_PCI_AUTO=y +# CONFIG_IDEDMA_ONLYDISK is not set +# CONFIG_BLK_DEV_AEC62XX is not set +# CONFIG_BLK_DEV_ALI15X3 is not set +# CONFIG_BLK_DEV_AMD74XX is not set +# CONFIG_BLK_DEV_CMD64X is not set +# CONFIG_BLK_DEV_TRIFLEX is not set +# CONFIG_BLK_DEV_CY82C693 is not set +# CONFIG_BLK_DEV_CS5520 is not set +# CONFIG_BLK_DEV_CS5530 is not set +# CONFIG_BLK_DEV_HPT34X is not set +# CONFIG_BLK_DEV_HPT366 is not set +# CONFIG_BLK_DEV_SC1200 is not set +# CONFIG_BLK_DEV_PIIX is not set +# CONFIG_BLK_DEV_NS87415 is not set +# CONFIG_BLK_DEV_PDC202XX_OLD is not set +# CONFIG_BLK_DEV_PDC202XX_NEW is not set +# CONFIG_BLK_DEV_SVWKS is not set +# CONFIG_BLK_DEV_SIIMAGE is not set +# CONFIG_BLK_DEV_SLC90E66 is not set +# CONFIG_BLK_DEV_TRM290 is not set +CONFIG_BLK_DEV_VIA82CXXX=y +# CONFIG_IDE_ARM is not set +CONFIG_BLK_DEV_IDEDMA=y +# CONFIG_IDEDMA_IVB is not set +CONFIG_IDEDMA_AUTO=y +# CONFIG_BLK_DEV_HD is not set # # SCSI device support @@ -220,7 +277,6 @@ CONFIG_NET=y # CONFIG_PACKET=y # CONFIG_PACKET_MMAP is not set -# CONFIG_NETLINK_DEV is not set CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -369,14 +425,6 @@ CONFIG_INPUT=y # CONFIG_INPUT_EVDEV is not set # CONFIG_INPUT_EVBUG is not set -# -# Input I/O drivers -# -# CONFIG_GAMEPORT is not set -CONFIG_SOUND_GAMEPORT=y -# CONFIG_SERIO is not set -# CONFIG_SERIO_I8042 is not set - # # Input Device Drivers # @@ -386,6 +434,13 @@ CONFIG_SOUND_GAMEPORT=y # CONFIG_INPUT_TOUCHSCREEN is not set # CONFIG_INPUT_MISC is not set +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y + # # Character devices # @@ -406,6 +461,7 @@ CONFIG_SERIAL_8250_NR_UARTS=4 CONFIG_SERIAL_CORE=y CONFIG_SERIAL_CORE_CONSOLE=y # CONFIG_SERIAL_CPM is not set +# CONFIG_SERIAL_JSM is not set CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 @@ -433,6 +489,11 @@ CONFIG_GEN_RTC=y # CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set +# +# TPM devices +# +# CONFIG_TCG_TPM is not set + # # I2C support # @@ -456,11 +517,11 @@ CONFIG_I2C_CHARDEV=y # CONFIG_I2C_AMD8111 is not set # CONFIG_I2C_I801 is not set # CONFIG_I2C_I810 is not set +# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_ISA is not set CONFIG_I2C_MPC=y # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_PARPORT_LIGHT is not set -# CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_PROSAVAGE is not set # CONFIG_I2C_SAVAGE4 is not set # CONFIG_SCx200_ACB is not set @@ -483,7 +544,9 @@ CONFIG_I2C_MPC=y # CONFIG_SENSORS_ASB100 is not set # CONFIG_SENSORS_DS1621 is not set # CONFIG_SENSORS_FSCHER is not set +# CONFIG_SENSORS_FSCPOS is not set # CONFIG_SENSORS_GL518SM is not set +# CONFIG_SENSORS_GL520SM is not set # CONFIG_SENSORS_IT87 is not set # CONFIG_SENSORS_LM63 is not set # CONFIG_SENSORS_LM75 is not set @@ -494,9 +557,11 @@ CONFIG_I2C_MPC=y # CONFIG_SENSORS_LM85 is not set # CONFIG_SENSORS_LM87 is not set # CONFIG_SENSORS_LM90 is not set +# CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_SIS5595 is not set # CONFIG_SENSORS_SMSC47M1 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_W83781D is not set @@ -506,10 +571,12 @@ CONFIG_I2C_MPC=y # # Other I2C Chip support # +# CONFIG_SENSORS_DS1337 is not set # CONFIG_SENSORS_EEPROM is not set # CONFIG_SENSORS_PCF8574 is not set # CONFIG_SENSORS_PCF8591 is not set # CONFIG_SENSORS_RTC8564 is not set +# CONFIG_SENSORS_M41T00 is not set # CONFIG_I2C_DEBUG_CORE is not set # CONFIG_I2C_DEBUG_ALGO is not set # CONFIG_I2C_DEBUG_BUS is not set @@ -538,7 +605,6 @@ CONFIG_I2C_MPC=y # Graphics support # # CONFIG_FB is not set -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set # # Sound @@ -548,13 +614,9 @@ CONFIG_I2C_MPC=y # # USB support # -# CONFIG_USB is not set CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y - -# -# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information -# +# CONFIG_USB is not set # # USB Gadget Support @@ -585,6 +647,10 @@ CONFIG_JBD=y CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set + +# +# XFS support +# # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -646,7 +712,6 @@ CONFIG_NFS_FS=y # CONFIG_NFSD is not set CONFIG_ROOT_NFS=y CONFIG_LOCKD=y -# CONFIG_EXPORTFS is not set CONFIG_SUNRPC=y # CONFIG_RPCSEC_GSS_KRB5 is not set # CONFIG_RPCSEC_GSS_SPKM3 is not set @@ -698,7 +763,9 @@ CONFIG_CRC32=y # # Kernel hacking # +# CONFIG_PRINTK_TIME is not set # CONFIG_DEBUG_KERNEL is not set +CONFIG_LOG_BUF_SHIFT=14 # CONFIG_KGDB_CONSOLE is not set # CONFIG_SERIAL_TEXT_DEBUG is not set diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index 11fb758d269f..c2a512735183 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -181,6 +182,7 @@ void __init mpc85xx_cds_init_IRQ(void) { bd_t *binfo = (bd_t *) __res; + int i; /* Determine the Physical Address of the OpenPIC regs */ phys_addr_t OpenPIC_PAddr = binfo->bi_immr_base + MPC85xx_OPENPIC_OFFSET; @@ -198,6 +200,13 @@ mpc85xx_cds_init_IRQ(void) */ openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET); + openpic_hookup_cascade(PIRQ0A, "82c59 cascade", i8259_irq); + + for (i = 0; i < NUM_8259_INTERRUPTS; i++) + irq_desc[i].handler = &i8259_pic; + + i8259_init(0); + #ifdef CONFIG_CPM2 /* Setup CPM2 PIC */ cpm2_init_IRQ(); @@ -231,7 +240,7 @@ mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) * interrupt on slot */ { { 0, 1, 2, 3 }, /* 16 - PMC */ - { 3, 0, 0, 0 }, /* 17 P2P (Tsi320) */ + { 0, 1, 2, 3 }, /* 17 P2P (Tsi320) */ { 0, 1, 2, 3 }, /* 18 - Slot 1 */ { 1, 2, 3, 0 }, /* 19 - Slot 2 */ { 2, 3, 0, 1 }, /* 20 - Slot 3 */ @@ -280,13 +289,135 @@ mpc85xx_exclude_device(u_char bus, u_char devfn) return PCIBIOS_DEVICE_NOT_FOUND; #endif /* We explicitly do not go past the Tundra 320 Bridge */ - if (bus == 1) + if ((bus == 1) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL)) return PCIBIOS_DEVICE_NOT_FOUND; if ((bus == 0) && (PCI_SLOT(devfn) == ARCADIA_2ND_BRIDGE_IDSEL)) return PCIBIOS_DEVICE_NOT_FOUND; else return PCIBIOS_SUCCESSFUL; } + +void __init +mpc85xx_cds_enable_via(struct pci_controller *hose) +{ + u32 pci_class; + u16 vid, did; + + early_read_config_dword(hose, 0, 0x88, PCI_CLASS_REVISION, &pci_class); + if ((pci_class >> 16) != PCI_CLASS_BRIDGE_PCI) + return; + + /* Configure P2P so that we can reach bus 1 */ + early_write_config_byte(hose, 0, 0x88, PCI_PRIMARY_BUS, 0); + early_write_config_byte(hose, 0, 0x88, PCI_SECONDARY_BUS, 1); + early_write_config_byte(hose, 0, 0x88, PCI_SUBORDINATE_BUS, 0xff); + + early_read_config_word(hose, 1, 0x10, PCI_VENDOR_ID, &vid); + early_read_config_word(hose, 1, 0x10, PCI_DEVICE_ID, &did); + + if ((vid != PCI_VENDOR_ID_VIA) || + (did != PCI_DEVICE_ID_VIA_82C686)) + return; + + /* Enable USB and IDE functions */ + early_write_config_byte(hose, 1, 0x10, 0x48, 0x08); +} + +void __init +mpc85xx_cds_fixup_via(struct pci_controller *hose) +{ + u32 pci_class; + u16 vid, did; + + early_read_config_dword(hose, 0, 0x88, PCI_CLASS_REVISION, &pci_class); + if ((pci_class >> 16) != PCI_CLASS_BRIDGE_PCI) + return; + + /* + * Force the backplane P2P bridge to have a window + * open from 0x00000000-0x00001fff in PCI I/O space. + * This allows legacy I/O (i8259, etc) on the VIA + * southbridge to be accessed. + */ + early_write_config_byte(hose, 0, 0x88, PCI_IO_BASE, 0x00); + early_write_config_word(hose, 0, 0x88, PCI_IO_BASE_UPPER16, 0x0000); + early_write_config_byte(hose, 0, 0x88, PCI_IO_LIMIT, 0x10); + early_write_config_word(hose, 0, 0x88, PCI_IO_LIMIT_UPPER16, 0x0000); + + early_read_config_word(hose, 1, 0x10, PCI_VENDOR_ID, &vid); + early_read_config_word(hose, 1, 0x10, PCI_DEVICE_ID, &did); + if ((vid != PCI_VENDOR_ID_VIA) || + (did != PCI_DEVICE_ID_VIA_82C686)) + return; + + /* + * Since the P2P window was forced to cover the fixed + * legacy I/O addresses, it is necessary to manually + * place the base addresses for the IDE and USB functions + * within this window. + */ + /* Function 1, IDE */ + early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_0, 0x1ff8); + early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_1, 0x1ff4); + early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_2, 0x1fe8); + early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_3, 0x1fe4); + early_write_config_dword(hose, 1, 0x11, PCI_BASE_ADDRESS_4, 0x1fd0); + + /* Function 2, USB ports 0-1 */ + early_write_config_dword(hose, 1, 0x12, PCI_BASE_ADDRESS_4, 0x1fa0); + + /* Function 3, USB ports 2-3 */ + early_write_config_dword(hose, 1, 0x13, PCI_BASE_ADDRESS_4, 0x1f80); + + /* Function 5, Power Management */ + early_write_config_dword(hose, 1, 0x15, PCI_BASE_ADDRESS_0, 0x1e00); + early_write_config_dword(hose, 1, 0x15, PCI_BASE_ADDRESS_1, 0x1dfc); + early_write_config_dword(hose, 1, 0x15, PCI_BASE_ADDRESS_2, 0x1df8); + + /* Function 6, AC97 Interface */ + early_write_config_dword(hose, 1, 0x16, PCI_BASE_ADDRESS_0, 0x1c00); +} + +void __init +mpc85xx_cds_pcibios_fixup(void) +{ + struct pci_dev *dev = NULL; + u_char c; + + if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C586_1, NULL))) { + /* + * U-Boot does not set the enable bits + * for the IDE device. Force them on here. + */ + pci_read_config_byte(dev, 0x40, &c); + c |= 0x03; /* IDE: Chip Enable Bits */ + pci_write_config_byte(dev, 0x40, c); + + /* + * Since only primary interface works, force the + * IDE function to standard primary IDE interrupt + * w/ 8259 offset + */ + dev->irq = 14; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } + + /* + * Force legacy USB interrupt routing + */ + if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C586_2, NULL))) { + dev->irq = 10; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 10); + } + + if ((dev = pci_find_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C586_2, dev))) { + dev->irq = 11; + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11); + } +} #endif /* CONFIG_PCI */ TODC_ALLOC(); @@ -308,6 +439,9 @@ mpc85xx_cds_setup_arch(void) printk("mpc85xx_cds_setup_arch\n"); + /* VIA IDE configuration */ + ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup; + #ifdef CONFIG_CPM2 cpm2_reset(); #endif diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.h b/arch/ppc/platforms/85xx/mpc85xx_cds_common.h index 7627d77504bd..12b292c6ae32 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.h +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.h @@ -77,4 +77,7 @@ #define MPC85XX_PCI2_IO_SIZE 0x01000000 +#define NR_8259_INTS 16 +#define CPM_IRQ_OFFSET NR_8259_INTS + #endif /* __MACH_MPC85XX_CDS_H__ */ diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index dd418ea3426c..46cbb3e39d4c 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -97,7 +97,7 @@ obj-$(CONFIG_MPC10X_OPENPIC) += open_pic.o obj-$(CONFIG_40x) += dcr.o obj-$(CONFIG_BOOKE) += dcr.o obj-$(CONFIG_85xx) += open_pic.o ppc85xx_common.o ppc85xx_setup.o \ - ppc_sys.o mpc85xx_sys.o \ + ppc_sys.o i8259.o mpc85xx_sys.o \ mpc85xx_devices.o ifeq ($(CONFIG_85xx),y) obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o diff --git a/arch/ppc/syslib/ppc85xx_setup.c b/arch/ppc/syslib/ppc85xx_setup.c index 152c3ef1312a..f3277f469e78 100644 --- a/arch/ppc/syslib/ppc85xx_setup.c +++ b/arch/ppc/syslib/ppc85xx_setup.c @@ -132,6 +132,12 @@ mpc85xx_halt(void) } #ifdef CONFIG_PCI + +#if defined(CONFIG_MPC8555_CDS) +extern void mpc85xx_cds_enable_via(struct pci_controller *hose); +extern void mpc85xx_cds_fixup_via(struct pci_controller *hose); +#endif + static void __init mpc85xx_setup_pci1(struct pci_controller *hose) { @@ -302,8 +308,18 @@ mpc85xx_setup_hose(void) ppc_md.pci_exclude_device = mpc85xx_exclude_device; +#if defined(CONFIG_MPC8555_CDS) + /* Pre pciauto_bus_scan VIA init */ + mpc85xx_cds_enable_via(hose_a); +#endif + hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno); +#if defined(CONFIG_MPC8555_CDS) + /* Post pciauto_bus_scan VIA fixup */ + mpc85xx_cds_fixup_via(hose_a); +#endif + #ifdef CONFIG_85xx_PCI2 hose_b = pcibios_alloc_controller(); From a6dbba77a9d4b47c60d60c4f07fa79b3ca93a1d5 Mon Sep 17 00:00:00 2001 From: Vitaly Bordug Date: Sat, 28 May 2005 15:52:09 -0700 Subject: [PATCH 067/155] [PATCH] ppc32: Support for 82xx PQII on-chip PCI bridge This patch adds on-chip PCI bridge support for the PQ2 family. The incomplete existent code is updated with interrupt handling stuff and board-specific bits for 8272ADS and PQ2FADS; the related files were renamed (from m8260_pci to m82xx_pci) to be of more generic fashion. This is tested with 8266ADS and 8272ADS, should work on PQ2FADS as well. Signed-off-by: Vitaly Bordug Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/Kconfig | 4 +- arch/ppc/platforms/pq2ads.h | 41 ++- arch/ppc/syslib/Makefile | 2 +- arch/ppc/syslib/m8260_pci.c | 193 -------------- arch/ppc/syslib/m8260_pci.h | 76 ------ arch/ppc/syslib/m8260_pci_erratum9.c | 10 +- arch/ppc/syslib/m8260_setup.c | 11 +- arch/ppc/syslib/m82xx_pci.c | 383 +++++++++++++++++++++++++++ arch/ppc/syslib/m82xx_pci.h | 92 +++++++ include/asm-ppc/cpm2.h | 46 ++++ include/asm-ppc/m8260_pci.h | 1 + include/asm-ppc/mpc8260.h | 2 +- 12 files changed, 558 insertions(+), 303 deletions(-) delete mode 100644 arch/ppc/syslib/m8260_pci.c delete mode 100644 arch/ppc/syslib/m8260_pci.h create mode 100644 arch/ppc/syslib/m82xx_pci.c create mode 100644 arch/ppc/syslib/m82xx_pci.h diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 600f23d7fd33..6e6377a69d5b 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -1143,12 +1143,12 @@ config PCI_QSPAN config PCI_8260 bool - depends on PCI && 8260 && !8272 + depends on PCI && 8260 default y config 8260_PCI9 bool " Enable workaround for MPC826x erratum PCI 9" - depends on PCI_8260 + depends on PCI_8260 && !ADS8272 default y choice diff --git a/arch/ppc/platforms/pq2ads.h b/arch/ppc/platforms/pq2ads.h index cf5e5dd06d63..067d9a5aebc1 100644 --- a/arch/ppc/platforms/pq2ads.h +++ b/arch/ppc/platforms/pq2ads.h @@ -49,10 +49,10 @@ /* PCI interrupt controller */ #define PCI_INT_STAT_REG 0xF8200000 #define PCI_INT_MASK_REG 0xF8200004 -#define PIRQA (NR_SIU_INTS + 0) -#define PIRQB (NR_SIU_INTS + 1) -#define PIRQC (NR_SIU_INTS + 2) -#define PIRQD (NR_SIU_INTS + 3) +#define PIRQA (NR_CPM_INTS + 0) +#define PIRQB (NR_CPM_INTS + 1) +#define PIRQC (NR_CPM_INTS + 2) +#define PIRQD (NR_CPM_INTS + 3) /* * PCI memory map definitions for MPC8266ADS-PCI. @@ -68,28 +68,23 @@ * 0x00000000-0x1FFFFFFF 0x00000000-0x1FFFFFFF MPC8266 local memory */ -/* window for a PCI master to access MPC8266 memory */ -#define PCI_SLV_MEM_LOCAL 0x00000000 /* Local base */ -#define PCI_SLV_MEM_BUS 0x00000000 /* PCI base */ +/* All the other PCI memory map definitions reside at syslib/m82xx_pci.h + Here we should redefine what is unique for this board */ +#define M82xx_PCI_SLAVE_MEM_LOCAL 0x00000000 /* Local base */ +#define M82xx_PCI_SLAVE_MEM_BUS 0x00000000 /* PCI base */ +#define M82xx_PCI_SLAVE_MEM_SIZE 0x10000000 /* 256 Mb */ -/* window for the processor to access PCI memory with prefetching */ -#define PCI_MSTR_MEM_LOCAL 0x80000000 /* Local base */ -#define PCI_MSTR_MEM_BUS 0x80000000 /* PCI base */ -#define PCI_MSTR_MEM_SIZE 0x20000000 /* 512MB */ +#define M82xx_PCI_SLAVE_SEC_WND_SIZE ~(0x40000000 - 1U) /* 2 x 512Mb */ +#define M82xx_PCI_SLAVE_SEC_WND_BASE 0x80000000 /* PCI Memory base */ -/* window for the processor to access PCI memory without prefetching */ -#define PCI_MSTR_MEMIO_LOCAL 0xA0000000 /* Local base */ -#define PCI_MSTR_MEMIO_BUS 0xA0000000 /* PCI base */ -#define PCI_MSTR_MEMIO_SIZE 0x20000000 /* 512MB */ +#if defined(CONFIG_ADS8272) +#define PCI_INT_TO_SIU SIU_INT_IRQ2 +#elif defined(CONFIG_PQ2FADS) +#define PCI_INT_TO_SIU SIU_INT_IRQ6 +#else +#warning PCI Bridge will be without interrupts support +#endif -/* window for the processor to access PCI I/O */ -#define PCI_MSTR_IO_LOCAL 0xF4000000 /* Local base */ -#define PCI_MSTR_IO_BUS 0x00000000 /* PCI base */ -#define PCI_MSTR_IO_SIZE 0x04000000 /* 64MB */ - -#define _IO_BASE PCI_MSTR_IO_LOCAL -#define _ISA_MEM_BASE PCI_MSTR_MEMIO_LOCAL -#define PCI_DRAM_OFFSET PCI_SLV_MEM_BUS #endif /* CONFIG_PCI */ #endif /* __MACH_ADS8260_DEFS */ diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index 46cbb3e39d4c..96acf85800d4 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -81,7 +81,7 @@ obj-$(CONFIG_SBC82xx) += todc_time.o obj-$(CONFIG_SPRUCE) += cpc700_pic.o indirect_pci.o pci_auto.o \ todc_time.o obj-$(CONFIG_8260) += m8260_setup.o -obj-$(CONFIG_PCI_8260) += m8260_pci.o indirect_pci.o +obj-$(CONFIG_PCI_8260) += m82xx_pci.o indirect_pci.o pci_auto.o obj-$(CONFIG_8260_PCI9) += m8260_pci_erratum9.o obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o ifeq ($(CONFIG_PPC_GEN550),y) diff --git a/arch/ppc/syslib/m8260_pci.c b/arch/ppc/syslib/m8260_pci.c deleted file mode 100644 index 057cc3f8ff37..000000000000 --- a/arch/ppc/syslib/m8260_pci.c +++ /dev/null @@ -1,193 +0,0 @@ -/* - * (C) Copyright 2003 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * (C) Copyright 2004 Red Hat, Inc. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * 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 "m8260_pci.h" - - -/* PCI bus configuration registers. - */ - -static void __init m8260_setup_pci(struct pci_controller *hose) -{ - volatile cpm2_map_t *immap = cpm2_immr; - unsigned long pocmr; - u16 tempShort; - -#ifndef CONFIG_ATC /* already done in U-Boot */ - /* - * Setting required to enable IRQ1-IRQ7 (SIUMCR [DPPC]), - * and local bus for PCI (SIUMCR [LBPC]). - */ - immap->im_siu_conf.siu_82xx.sc_siumcr = 0x00640000; -#endif - - /* Make PCI lowest priority */ - /* Each 4 bits is a device bus request and the MS 4bits - is highest priority */ - /* Bus 4bit value - --- ---------- - CPM high 0b0000 - CPM middle 0b0001 - CPM low 0b0010 - PCI reguest 0b0011 - Reserved 0b0100 - Reserved 0b0101 - Internal Core 0b0110 - External Master 1 0b0111 - External Master 2 0b1000 - External Master 3 0b1001 - The rest are reserved */ - immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x61207893; - - /* Park bus on core while modifying PCI Bus accesses */ - immap->im_siu_conf.siu_82xx.sc_ppc_acr = 0x6; - - /* - * Set up master window that allows the CPU to access PCI space. This - * window is set up using the first SIU PCIBR registers. - */ - immap->im_memctl.memc_pcimsk0 = MPC826x_PCI_MASK; - immap->im_memctl.memc_pcibr0 = MPC826x_PCI_BASE | PCIBR_ENABLE; - - /* Disable machine check on no response or target abort */ - immap->im_pci.pci_emr = cpu_to_le32(0x1fe7); - /* Release PCI RST (by default the PCI RST signal is held low) */ - immap->im_pci.pci_gcr = cpu_to_le32(PCIGCR_PCI_BUS_EN); - - /* give it some time */ - mdelay(1); - - /* - * Set up master window that allows the CPU to access PCI Memory (prefetch) - * space. This window is set up using the first set of Outbound ATU registers. - */ - immap->im_pci.pci_potar0 = cpu_to_le32(MPC826x_PCI_LOWER_MEM >> 12); - immap->im_pci.pci_pobar0 = cpu_to_le32((MPC826x_PCI_LOWER_MEM - MPC826x_PCI_MEM_OFFSET) >> 12); - pocmr = ((MPC826x_PCI_UPPER_MEM - MPC826x_PCI_LOWER_MEM) >> 12) ^ 0xfffff; - immap->im_pci.pci_pocmr0 = cpu_to_le32(pocmr | POCMR_ENABLE | POCMR_PREFETCH_EN); - - /* - * Set up master window that allows the CPU to access PCI Memory (non-prefetch) - * space. This window is set up using the second set of Outbound ATU registers. - */ - immap->im_pci.pci_potar1 = cpu_to_le32(MPC826x_PCI_LOWER_MMIO >> 12); - immap->im_pci.pci_pobar1 = cpu_to_le32((MPC826x_PCI_LOWER_MMIO - MPC826x_PCI_MMIO_OFFSET) >> 12); - pocmr = ((MPC826x_PCI_UPPER_MMIO - MPC826x_PCI_LOWER_MMIO) >> 12) ^ 0xfffff; - immap->im_pci.pci_pocmr1 = cpu_to_le32(pocmr | POCMR_ENABLE); - - /* - * Set up master window that allows the CPU to access PCI IO space. This window - * is set up using the third set of Outbound ATU registers. - */ - immap->im_pci.pci_potar2 = cpu_to_le32(MPC826x_PCI_IO_BASE >> 12); - immap->im_pci.pci_pobar2 = cpu_to_le32(MPC826x_PCI_LOWER_IO >> 12); - pocmr = ((MPC826x_PCI_UPPER_IO - MPC826x_PCI_LOWER_IO) >> 12) ^ 0xfffff; - immap->im_pci.pci_pocmr2 = cpu_to_le32(pocmr | POCMR_ENABLE | POCMR_PCI_IO); - - /* - * Set up slave window that allows PCI masters to access MPC826x local memory. - * This window is set up using the first set of Inbound ATU registers - */ - - immap->im_pci.pci_pitar0 = cpu_to_le32(MPC826x_PCI_SLAVE_MEM_LOCAL >> 12); - immap->im_pci.pci_pibar0 = cpu_to_le32(MPC826x_PCI_SLAVE_MEM_BUS >> 12); - pocmr = ((MPC826x_PCI_SLAVE_MEM_SIZE-1) >> 12) ^ 0xfffff; - immap->im_pci.pci_picmr0 = cpu_to_le32(pocmr | PICMR_ENABLE | PICMR_PREFETCH_EN); - - /* See above for description - puts PCI request as highest priority */ - immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x03124567; - - /* Park the bus on the PCI */ - immap->im_siu_conf.siu_82xx.sc_ppc_acr = PPC_ACR_BUS_PARK_PCI; - - /* Host mode - specify the bridge as a host-PCI bridge */ - early_write_config_word(hose, 0, 0, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_HOST); - - /* Enable the host bridge to be a master on the PCI bus, and to act as a PCI memory target */ - early_read_config_word(hose, 0, 0, PCI_COMMAND, &tempShort); - early_write_config_word(hose, 0, 0, PCI_COMMAND, - tempShort | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY); -} - -void __init m8260_find_bridges(void) -{ - extern int pci_assign_all_busses; - struct pci_controller * hose; - - pci_assign_all_busses = 1; - - hose = pcibios_alloc_controller(); - - if (!hose) - return; - - ppc_md.pci_swizzle = common_swizzle; - - hose->first_busno = 0; - hose->bus_offset = 0; - hose->last_busno = 0xff; - - setup_m8260_indirect_pci(hose, - (unsigned long)&cpm2_immr->im_pci.pci_cfg_addr, - (unsigned long)&cpm2_immr->im_pci.pci_cfg_data); - - m8260_setup_pci(hose); - hose->pci_mem_offset = MPC826x_PCI_MEM_OFFSET; - - hose->io_base_virt = ioremap(MPC826x_PCI_IO_BASE, - MPC826x_PCI_IO_SIZE); - isa_io_base = (unsigned long) hose->io_base_virt; - - /* setup resources */ - pci_init_resource(&hose->mem_resources[0], - MPC826x_PCI_LOWER_MEM, - MPC826x_PCI_UPPER_MEM, - IORESOURCE_MEM|IORESOURCE_PREFETCH, "PCI prefetchable memory"); - - pci_init_resource(&hose->mem_resources[1], - MPC826x_PCI_LOWER_MMIO, - MPC826x_PCI_UPPER_MMIO, - IORESOURCE_MEM, "PCI memory"); - - pci_init_resource(&hose->io_resource, - MPC826x_PCI_LOWER_IO, - MPC826x_PCI_UPPER_IO, - IORESOURCE_IO, "PCI I/O"); -} diff --git a/arch/ppc/syslib/m8260_pci.h b/arch/ppc/syslib/m8260_pci.h deleted file mode 100644 index d1352120acd7..000000000000 --- a/arch/ppc/syslib/m8260_pci.h +++ /dev/null @@ -1,76 +0,0 @@ - -#ifndef _PPC_KERNEL_M8260_PCI_H -#define _PPC_KERNEL_M8260_PCI_H - -#include - -/* - * Local->PCI map (from CPU) controlled by - * MPC826x master window - * - * 0x80000000 - 0xBFFFFFFF Total CPU2PCI space PCIBR0 - * - * 0x80000000 - 0x9FFFFFFF PCI Mem with prefetch (Outbound ATU #1) - * 0xA0000000 - 0xAFFFFFFF PCI Mem w/o prefetch (Outbound ATU #2) - * 0xB0000000 - 0xB0FFFFFF 32-bit PCI IO (Outbound ATU #3) - * - * PCI->Local map (from PCI) - * MPC826x slave window controlled by - * - * 0x00000000 - 0x07FFFFFF MPC826x local memory (Inbound ATU #1) - */ - -/* - * Slave window that allows PCI masters to access MPC826x local memory. - * This window is set up using the first set of Inbound ATU registers - */ - -#ifndef MPC826x_PCI_SLAVE_MEM_LOCAL -#define MPC826x_PCI_SLAVE_MEM_LOCAL (((struct bd_info *)__res)->bi_memstart) -#define MPC826x_PCI_SLAVE_MEM_BUS (((struct bd_info *)__res)->bi_memstart) -#define MPC826x_PCI_SLAVE_MEM_SIZE (((struct bd_info *)__res)->bi_memsize) -#endif - -/* - * This is the window that allows the CPU to access PCI address space. - * It will be setup with the SIU PCIBR0 register. All three PCI master - * windows, which allow the CPU to access PCI prefetch, non prefetch, - * and IO space (see below), must all fit within this window. - */ -#ifndef MPC826x_PCI_BASE -#define MPC826x_PCI_BASE 0x80000000 -#define MPC826x_PCI_MASK 0xc0000000 -#endif - -#ifndef MPC826x_PCI_LOWER_MEM -#define MPC826x_PCI_LOWER_MEM 0x80000000 -#define MPC826x_PCI_UPPER_MEM 0x9fffffff -#define MPC826x_PCI_MEM_OFFSET 0x00000000 -#endif - -#ifndef MPC826x_PCI_LOWER_MMIO -#define MPC826x_PCI_LOWER_MMIO 0xa0000000 -#define MPC826x_PCI_UPPER_MMIO 0xafffffff -#define MPC826x_PCI_MMIO_OFFSET 0x00000000 -#endif - -#ifndef MPC826x_PCI_LOWER_IO -#define MPC826x_PCI_LOWER_IO 0x00000000 -#define MPC826x_PCI_UPPER_IO 0x00ffffff -#define MPC826x_PCI_IO_BASE 0xb0000000 -#define MPC826x_PCI_IO_SIZE 0x01000000 -#endif - -#ifndef _IO_BASE -#define _IO_BASE isa_io_base -#endif - -#ifdef CONFIG_8260_PCI9 -struct pci_controller; -extern void setup_m8260_indirect_pci(struct pci_controller* hose, - u32 cfg_addr, u32 cfg_data); -#else -#define setup_m8260_indirect_pci setup_indirect_pci -#endif - -#endif /* _PPC_KERNEL_M8260_PCI_H */ diff --git a/arch/ppc/syslib/m8260_pci_erratum9.c b/arch/ppc/syslib/m8260_pci_erratum9.c index 9c0582d639e0..1dc7e4e1d491 100644 --- a/arch/ppc/syslib/m8260_pci_erratum9.c +++ b/arch/ppc/syslib/m8260_pci_erratum9.c @@ -31,7 +31,7 @@ #include #include -#include "m8260_pci.h" +#include "m82xx_pci.h" #ifdef CONFIG_8260_PCI9 /*#include */ /* included in asm/io.h */ @@ -248,11 +248,11 @@ EXPORT_SYMBOL(idma_pci9_read_le); static inline int is_pci_mem(unsigned long addr) { - if (addr >= MPC826x_PCI_LOWER_MMIO && - addr <= MPC826x_PCI_UPPER_MMIO) + if (addr >= M82xx_PCI_LOWER_MMIO && + addr <= M82xx_PCI_UPPER_MMIO) return 1; - if (addr >= MPC826x_PCI_LOWER_MEM && - addr <= MPC826x_PCI_UPPER_MEM) + if (addr >= M82xx_PCI_LOWER_MEM && + addr <= M82xx_PCI_UPPER_MEM) return 1; return 0; } diff --git a/arch/ppc/syslib/m8260_setup.c b/arch/ppc/syslib/m8260_setup.c index 23ea3f694de2..fda75d79050c 100644 --- a/arch/ppc/syslib/m8260_setup.c +++ b/arch/ppc/syslib/m8260_setup.c @@ -34,7 +34,8 @@ unsigned char __res[sizeof(bd_t)]; extern void cpm2_reset(void); -extern void m8260_find_bridges(void); +extern void pq2_find_bridges(void); +extern void pq2pci_init_irq(void); extern void idma_pci9_init(void); /* Place-holder for board-specific init */ @@ -56,7 +57,7 @@ m8260_setup_arch(void) idma_pci9_init(); #endif #ifdef CONFIG_PCI_8260 - m8260_find_bridges(); + pq2_find_bridges(); #endif #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) @@ -173,6 +174,12 @@ m8260_init_IRQ(void) * in case the boot rom changed something on us. */ cpm2_immr->im_intctl.ic_siprr = 0x05309770; + +#if defined(CONFIG_PCI) && (defined(CONFIG_ADS8272) || defined(CONFIG_PQ2FADS)) + /* Initialize stuff for the 82xx CPLD IC and install demux */ + pq2pci_init_irq(); +#endif + } /* diff --git a/arch/ppc/syslib/m82xx_pci.c b/arch/ppc/syslib/m82xx_pci.c new file mode 100644 index 000000000000..5e7a7edcea74 --- /dev/null +++ b/arch/ppc/syslib/m82xx_pci.c @@ -0,0 +1,383 @@ +/* + * + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2004 Red Hat, Inc. + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 "m82xx_pci.h" + +/* + * Interrupt routing + */ + +static inline int +pq2pci_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin) +{ + static char pci_irq_table[][4] = + /* + * PCI IDSEL/INTPIN->INTLINE + * A B C D + */ + { + { PIRQA, PIRQB, PIRQC, PIRQD }, /* IDSEL 22 - PCI slot 0 */ + { PIRQD, PIRQA, PIRQB, PIRQC }, /* IDSEL 23 - PCI slot 1 */ + { PIRQC, PIRQD, PIRQA, PIRQB }, /* IDSEL 24 - PCI slot 2 */ + }; + + const long min_idsel = 22, max_idsel = 24, irqs_per_slot = 4; + return PCI_IRQ_TABLE_LOOKUP; +} + +static void +pq2pci_mask_irq(unsigned int irq) +{ + int bit = irq - NR_CPM_INTS; + + *(volatile unsigned long *) PCI_INT_MASK_REG |= (1 << (31 - bit)); + return; +} + +static void +pq2pci_unmask_irq(unsigned int irq) +{ + int bit = irq - NR_CPM_INTS; + + *(volatile unsigned long *) PCI_INT_MASK_REG &= ~(1 << (31 - bit)); + return; +} + +static void +pq2pci_mask_and_ack(unsigned int irq) +{ + int bit = irq - NR_CPM_INTS; + + *(volatile unsigned long *) PCI_INT_MASK_REG |= (1 << (31 - bit)); + return; +} + +static void +pq2pci_end_irq(unsigned int irq) +{ + int bit = irq - NR_CPM_INTS; + + *(volatile unsigned long *) PCI_INT_MASK_REG &= ~(1 << (31 - bit)); + return; +} + +struct hw_interrupt_type pq2pci_ic = { + "PQ2 PCI", + NULL, + NULL, + pq2pci_unmask_irq, + pq2pci_mask_irq, + pq2pci_mask_and_ack, + pq2pci_end_irq, + 0 +}; + +static irqreturn_t +pq2pci_irq_demux(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long stat, mask, pend; + int bit; + + for(;;) { + stat = *(volatile unsigned long *) PCI_INT_STAT_REG; + mask = *(volatile unsigned long *) PCI_INT_MASK_REG; + pend = stat & ~mask & 0xf0000000; + if (!pend) + break; + for (bit = 0; pend != 0; ++bit, pend <<= 1) { + if (pend & 0x80000000) + __do_IRQ(NR_CPM_INTS + bit, regs); + } + } + + return IRQ_HANDLED; +} + +static struct irqaction pq2pci_irqaction = { + .handler = pq2pci_irq_demux, + .flags = SA_INTERRUPT, + .mask = CPU_MASK_NONE, + .name = "PQ2 PCI cascade", +}; + + +void +pq2pci_init_irq(void) +{ + int irq; + volatile cpm2_map_t *immap = cpm2_immr; +#if defined CONFIG_ADS8272 + /* configure chip select for PCI interrupt controller */ + immap->im_memctl.memc_br3 = PCI_INT_STAT_REG | 0x00001801; + immap->im_memctl.memc_or3 = 0xffff8010; +#elif defined CONFIG_PQ2FADS + immap->im_memctl.memc_br8 = PCI_INT_STAT_REG | 0x00001801; + immap->im_memctl.memc_or8 = 0xffff8010; +#endif + for (irq = NR_CPM_INTS; irq < NR_CPM_INTS + 4; irq++) + irq_desc[irq].handler = &pq2pci_ic; + + /* make PCI IRQ level sensitive */ + immap->im_intctl.ic_siexr &= + ~(1 << (14 - (PCI_INT_TO_SIU - SIU_INT_IRQ1))); + + /* mask all PCI interrupts */ + *(volatile unsigned long *) PCI_INT_MASK_REG |= 0xfff00000; + + /* install the demultiplexer for the PCI cascade interrupt */ + setup_irq(PCI_INT_TO_SIU, &pq2pci_irqaction); + return; +} + +static int +pq2pci_exclude_device(u_char bus, u_char devfn) +{ + return PCIBIOS_SUCCESSFUL; +} + +/* PCI bus configuration registers. + */ +static void +pq2ads_setup_pci(struct pci_controller *hose) +{ + __u32 val; + volatile cpm2_map_t *immap = cpm2_immr; + bd_t* binfo = (bd_t*) __res; + u32 sccr = immap->im_clkrst.car_sccr; + uint pci_div,freq,time; + /* PCI int lowest prio */ + /* Each 4 bits is a device bus request and the MS 4bits + is highest priority */ + /* Bus 4bit value + --- ---------- + CPM high 0b0000 + CPM middle 0b0001 + CPM low 0b0010 + PCI reguest 0b0011 + Reserved 0b0100 + Reserved 0b0101 + Internal Core 0b0110 + External Master 1 0b0111 + External Master 2 0b1000 + External Master 3 0b1001 + The rest are reserved + */ + immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x61207893; + /* park bus on core */ + immap->im_siu_conf.siu_82xx.sc_ppc_acr = PPC_ACR_BUS_PARK_CORE; + /* + * Set up master windows that allow the CPU to access PCI space. These + * windows are set up using the two SIU PCIBR registers. + */ + + immap->im_memctl.memc_pcimsk0 = M82xx_PCI_PRIM_WND_SIZE; + immap->im_memctl.memc_pcibr0 = M82xx_PCI_PRIM_WND_BASE | PCIBR_ENABLE; + +#ifdef M82xx_PCI_SEC_WND_SIZE + immap->im_memctl.memc_pcimsk1 = M82xx_PCI_SEC_WND_SIZE; + immap->im_memctl.memc_pcibr1 = M82xx_PCI_SEC_WND_BASE | PCIBR_ENABLE; +#endif + +#if defined CONFIG_ADS8272 + immap->im_siu_conf.siu_82xx.sc_siumcr = + (immap->im_siu_conf.siu_82xx.sc_siumcr & + ~(SIUMCR_BBD | SIUMCR_ESE | SIUMCR_PBSE | + SIUMCR_CDIS | SIUMCR_DPPC11 | SIUMCR_L2CPC11 | + SIUMCR_LBPC11 | SIUMCR_APPC11 | + SIUMCR_CS10PC11 | SIUMCR_BCTLC11 | SIUMCR_MMR11)) | + SIUMCR_DPPC11 | SIUMCR_L2CPC01 | SIUMCR_LBPC00 | + SIUMCR_APPC10 | SIUMCR_CS10PC00 | + SIUMCR_BCTLC00 | SIUMCR_MMR11 ; + +#elif defined CONFIG_PQ2FADS + /* + * Setting required to enable IRQ1-IRQ7 (SIUMCR [DPPC]), + * and local bus for PCI (SIUMCR [LBPC]). + */ + immap->im_siu_conf.siu_82xx.sc_siumcr = (immap->im_siu_conf.sc_siumcr & + ~(SIUMCR_L2PC11 | SIUMCR_LBPC11 | SIUMCR_CS10PC11 | SIUMCR_APPC11) | + SIUMCR_BBD | SIUMCR_LBPC01 | SIUMCR_DPPC11 | SIUMCR_APPC10; +#endif + /* Enable PCI */ + immap->im_pci.pci_gcr = cpu_to_le32(PCIGCR_PCI_BUS_EN); + + pci_div = ( (sccr & SCCR_PCI_MODCK) ? 2 : 1) * + ( ( (sccr & SCCR_PCIDF_MSK) >> SCCR_PCIDF_SHIFT) + 1); + freq = (uint)((2*binfo->bi_cpmfreq)/(pci_div)); + time = (int)666666/freq; + /* due to PCI Local Bus spec, some devices needs to wait such a long + time after RST deassertion. More specifically, 0.508s for 66MHz & twice more for 33 */ + printk("%s: The PCI bus is %d Mhz.\nWaiting %s after deasserting RST...\n",__FILE__,freq, + (time==1) ? "0.5 seconds":"1 second" ); + + { + int i; + for(i=0;i<(500*time);i++) + udelay(1000); + } + + /* setup ATU registers */ + immap->im_pci.pci_pocmr0 = cpu_to_le32(POCMR_ENABLE | POCMR_PCI_IO | + ((~(M82xx_PCI_IO_SIZE - 1U)) >> POTA_ADDR_SHIFT)); + immap->im_pci.pci_potar0 = cpu_to_le32(M82xx_PCI_LOWER_IO >> POTA_ADDR_SHIFT); + immap->im_pci.pci_pobar0 = cpu_to_le32(M82xx_PCI_IO_BASE >> POTA_ADDR_SHIFT); + + /* Set-up non-prefetchable window */ + immap->im_pci.pci_pocmr1 = cpu_to_le32(POCMR_ENABLE | ((~(M82xx_PCI_MMIO_SIZE-1U)) >> POTA_ADDR_SHIFT)); + immap->im_pci.pci_potar1 = cpu_to_le32(M82xx_PCI_LOWER_MMIO >> POTA_ADDR_SHIFT); + immap->im_pci.pci_pobar1 = cpu_to_le32((M82xx_PCI_LOWER_MMIO - M82xx_PCI_MMIO_OFFSET) >> POTA_ADDR_SHIFT); + + /* Set-up prefetchable window */ + immap->im_pci.pci_pocmr2 = cpu_to_le32(POCMR_ENABLE |POCMR_PREFETCH_EN | + (~(M82xx_PCI_MEM_SIZE-1U) >> POTA_ADDR_SHIFT)); + immap->im_pci.pci_potar2 = cpu_to_le32(M82xx_PCI_LOWER_MEM >> POTA_ADDR_SHIFT); + immap->im_pci.pci_pobar2 = cpu_to_le32((M82xx_PCI_LOWER_MEM - M82xx_PCI_MEM_OFFSET) >> POTA_ADDR_SHIFT); + + /* Inbound transactions from PCI memory space */ + immap->im_pci.pci_picmr0 = cpu_to_le32(PICMR_ENABLE | PICMR_PREFETCH_EN | + ((~(M82xx_PCI_SLAVE_MEM_SIZE-1U)) >> PITA_ADDR_SHIFT)); + immap->im_pci.pci_pibar0 = cpu_to_le32(M82xx_PCI_SLAVE_MEM_BUS >> PITA_ADDR_SHIFT); + immap->im_pci.pci_pitar0 = cpu_to_le32(M82xx_PCI_SLAVE_MEM_LOCAL>> PITA_ADDR_SHIFT); + +#if defined CONFIG_ADS8272 + /* PCI int highest prio */ + immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x01236745; +#elif defined CONFIG_PQ2FADS + immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x03124567; +#endif + /* park bus on PCI */ + immap->im_siu_conf.siu_82xx.sc_ppc_acr = PPC_ACR_BUS_PARK_PCI; + + /* Enable bus mastering and inbound memory transactions */ + early_read_config_dword(hose, hose->first_busno, 0, PCI_COMMAND, &val); + val &= 0xffff0000; + val |= PCI_COMMAND_MEMORY|PCI_COMMAND_MASTER; + early_write_config_dword(hose, hose->first_busno, 0, PCI_COMMAND, val); + +} + +void __init pq2_find_bridges(void) +{ + extern int pci_assign_all_busses; + struct pci_controller * hose; + int host_bridge; + + pci_assign_all_busses = 1; + + hose = pcibios_alloc_controller(); + + if (!hose) + return; + + ppc_md.pci_swizzle = common_swizzle; + + hose->first_busno = 0; + hose->bus_offset = 0; + hose->last_busno = 0xff; + +#ifdef CONFIG_ADS8272 + hose->set_cfg_type = 1; +#endif + + setup_m8260_indirect_pci(hose, + (unsigned long)&cpm2_immr->im_pci.pci_cfg_addr, + (unsigned long)&cpm2_immr->im_pci.pci_cfg_data); + + /* Make sure it is a supported bridge */ + early_read_config_dword(hose, + 0, + PCI_DEVFN(0,0), + PCI_VENDOR_ID, + &host_bridge); + switch (host_bridge) { + case PCI_DEVICE_ID_MPC8265: + break; + case PCI_DEVICE_ID_MPC8272: + break; + default: + printk("Attempting to use unrecognized host bridge ID" + " 0x%08x.\n", host_bridge); + break; + } + + pq2ads_setup_pci(hose); + + hose->io_space.start = M82xx_PCI_LOWER_IO; + hose->io_space.end = M82xx_PCI_UPPER_IO; + hose->mem_space.start = M82xx_PCI_LOWER_MEM; + hose->mem_space.end = M82xx_PCI_UPPER_MMIO; + hose->pci_mem_offset = M82xx_PCI_MEM_OFFSET; + + isa_io_base = + (unsigned long) ioremap(M82xx_PCI_IO_BASE, + M82xx_PCI_IO_SIZE); + hose->io_base_virt = (void *) isa_io_base; + + /* setup resources */ + pci_init_resource(&hose->mem_resources[0], + M82xx_PCI_LOWER_MEM, + M82xx_PCI_UPPER_MEM, + IORESOURCE_MEM|IORESOURCE_PREFETCH, "PCI prefetchable memory"); + + pci_init_resource(&hose->mem_resources[1], + M82xx_PCI_LOWER_MMIO, + M82xx_PCI_UPPER_MMIO, + IORESOURCE_MEM, "PCI memory"); + + pci_init_resource(&hose->io_resource, + M82xx_PCI_LOWER_IO, + M82xx_PCI_UPPER_IO, + IORESOURCE_IO | 1, "PCI I/O"); + + ppc_md.pci_exclude_device = pq2pci_exclude_device; + hose->last_busno = pciauto_bus_scan(hose, hose->first_busno); + + ppc_md.pci_map_irq = pq2pci_map_irq; + ppc_md.pcibios_fixup = NULL; + ppc_md.pcibios_fixup_bus = NULL; + +} diff --git a/arch/ppc/syslib/m82xx_pci.h b/arch/ppc/syslib/m82xx_pci.h new file mode 100644 index 000000000000..924f73f8e595 --- /dev/null +++ b/arch/ppc/syslib/m82xx_pci.h @@ -0,0 +1,92 @@ + +#ifndef _PPC_KERNEL_M82XX_PCI_H +#define _PPC_KERNEL_M82XX_PCI_H + +#include +/* + * Local->PCI map (from CPU) controlled by + * MPC826x master window + * + * 0xF6000000 - 0xF7FFFFFF IO space + * 0x80000000 - 0xBFFFFFFF CPU2PCI memory space PCIBR0 + * + * 0x80000000 - 0x9FFFFFFF PCI Mem with prefetch (Outbound ATU #1) + * 0xA0000000 - 0xBFFFFFFF PCI Mem w/o prefetch (Outbound ATU #2) + * 0xF6000000 - 0xF7FFFFFF 32-bit PCI IO (Outbound ATU #3) + * + * PCI->Local map (from PCI) + * MPC826x slave window controlled by + * + * 0x00000000 - 0x07FFFFFF MPC826x local memory (Inbound ATU #1) + */ + +/* + * Slave window that allows PCI masters to access MPC826x local memory. + * This window is set up using the first set of Inbound ATU registers + */ + +#ifndef M82xx_PCI_SLAVE_MEM_LOCAL +#define M82xx_PCI_SLAVE_MEM_LOCAL (((struct bd_info *)__res)->bi_memstart) +#define M82xx_PCI_SLAVE_MEM_BUS (((struct bd_info *)__res)->bi_memstart) +#define M82xx_PCI_SLAVE_MEM_SIZE (((struct bd_info *)__res)->bi_memsize) +#endif + +/* + * This is the window that allows the CPU to access PCI address space. + * It will be setup with the SIU PCIBR0 register. All three PCI master + * windows, which allow the CPU to access PCI prefetch, non prefetch, + * and IO space (see below), must all fit within this window. + */ + +#ifndef M82xx_PCI_LOWER_MEM +#define M82xx_PCI_LOWER_MEM 0x80000000 +#define M82xx_PCI_UPPER_MEM 0x9fffffff +#define M82xx_PCI_MEM_OFFSET 0x00000000 +#define M82xx_PCI_MEM_SIZE 0x20000000 +#endif + +#ifndef M82xx_PCI_LOWER_MMIO +#define M82xx_PCI_LOWER_MMIO 0xa0000000 +#define M82xx_PCI_UPPER_MMIO 0xafffffff +#define M82xx_PCI_MMIO_OFFSET 0x00000000 +#define M82xx_PCI_MMIO_SIZE 0x20000000 +#endif + +#ifndef M82xx_PCI_LOWER_IO +#define M82xx_PCI_LOWER_IO 0x00000000 +#define M82xx_PCI_UPPER_IO 0x01ffffff +#define M82xx_PCI_IO_BASE 0xf6000000 +#define M82xx_PCI_IO_SIZE 0x02000000 +#endif + +#ifndef M82xx_PCI_PRIM_WND_SIZE +#define M82xx_PCI_PRIM_WND_SIZE ~(M82xx_PCI_IO_SIZE - 1U) +#define M82xx_PCI_PRIM_WND_BASE (M82xx_PCI_IO_BASE) +#endif + +#ifndef M82xx_PCI_SEC_WND_SIZE +#define M82xx_PCI_SEC_WND_SIZE ~(M82xx_PCI_MEM_SIZE + M82xx_PCI_MMIO_SIZE - 1U) +#define M82xx_PCI_SEC_WND_BASE (M82xx_PCI_LOWER_MEM) +#endif + +#ifndef POTA_ADDR_SHIFT +#define POTA_ADDR_SHIFT 12 +#endif + +#ifndef PITA_ADDR_SHIFT +#define PITA_ADDR_SHIFT 12 +#endif + +#ifndef _IO_BASE +#define _IO_BASE isa_io_base +#endif + +#ifdef CONFIG_8260_PCI9 +struct pci_controller; +extern void setup_m8260_indirect_pci(struct pci_controller* hose, + u32 cfg_addr, u32 cfg_data); +#else +#define setup_m8260_indirect_pci setup_indirect_pci +#endif + +#endif /* _PPC_KERNEL_M8260_PCI_H */ diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h index 42fd1068cf2a..c5883dbed63f 100644 --- a/include/asm-ppc/cpm2.h +++ b/include/asm-ppc/cpm2.h @@ -1039,6 +1039,52 @@ typedef struct im_idma { #define CMXSCR_TS4CS_CLK7 0x00000006 /* SCC4 Tx Clock Source is CLK7 */ #define CMXSCR_TS4CS_CLK8 0x00000007 /* SCC4 Tx Clock Source is CLK8 */ +/*----------------------------------------------------------------------- + * SIUMCR - SIU Module Configuration Register 4-31 + */ +#define SIUMCR_BBD 0x80000000 /* Bus Busy Disable */ +#define SIUMCR_ESE 0x40000000 /* External Snoop Enable */ +#define SIUMCR_PBSE 0x20000000 /* Parity Byte Select Enable */ +#define SIUMCR_CDIS 0x10000000 /* Core Disable */ +#define SIUMCR_DPPC00 0x00000000 /* Data Parity Pins Configuration*/ +#define SIUMCR_DPPC01 0x04000000 /* - " - */ +#define SIUMCR_DPPC10 0x08000000 /* - " - */ +#define SIUMCR_DPPC11 0x0c000000 /* - " - */ +#define SIUMCR_L2CPC00 0x00000000 /* L2 Cache Pins Configuration */ +#define SIUMCR_L2CPC01 0x01000000 /* - " - */ +#define SIUMCR_L2CPC10 0x02000000 /* - " - */ +#define SIUMCR_L2CPC11 0x03000000 /* - " - */ +#define SIUMCR_LBPC00 0x00000000 /* Local Bus Pins Configuration */ +#define SIUMCR_LBPC01 0x00400000 /* - " - */ +#define SIUMCR_LBPC10 0x00800000 /* - " - */ +#define SIUMCR_LBPC11 0x00c00000 /* - " - */ +#define SIUMCR_APPC00 0x00000000 /* Address Parity Pins Configuration*/ +#define SIUMCR_APPC01 0x00100000 /* - " - */ +#define SIUMCR_APPC10 0x00200000 /* - " - */ +#define SIUMCR_APPC11 0x00300000 /* - " - */ +#define SIUMCR_CS10PC00 0x00000000 /* CS10 Pin Configuration */ +#define SIUMCR_CS10PC01 0x00040000 /* - " - */ +#define SIUMCR_CS10PC10 0x00080000 /* - " - */ +#define SIUMCR_CS10PC11 0x000c0000 /* - " - */ +#define SIUMCR_BCTLC00 0x00000000 /* Buffer Control Configuration */ +#define SIUMCR_BCTLC01 0x00010000 /* - " - */ +#define SIUMCR_BCTLC10 0x00020000 /* - " - */ +#define SIUMCR_BCTLC11 0x00030000 /* - " - */ +#define SIUMCR_MMR00 0x00000000 /* Mask Masters Requests */ +#define SIUMCR_MMR01 0x00004000 /* - " - */ +#define SIUMCR_MMR10 0x00008000 /* - " - */ +#define SIUMCR_MMR11 0x0000c000 /* - " - */ +#define SIUMCR_LPBSE 0x00002000 /* LocalBus Parity Byte Select Enable*/ + +/*----------------------------------------------------------------------- + * SCCR - System Clock Control Register 9-8 +*/ +#define SCCR_PCI_MODE 0x00000100 /* PCI Mode */ +#define SCCR_PCI_MODCK 0x00000080 /* Value of PCI_MODCK pin */ +#define SCCR_PCIDF_MSK 0x00000078 /* PCI division factor */ +#define SCCR_PCIDF_SHIFT 3 + + #endif /* __CPM2__ */ #endif /* __KERNEL__ */ diff --git a/include/asm-ppc/m8260_pci.h b/include/asm-ppc/m8260_pci.h index 163a6b91d5b2..bf9e05dd54b5 100644 --- a/include/asm-ppc/m8260_pci.h +++ b/include/asm-ppc/m8260_pci.h @@ -19,6 +19,7 @@ * Define the vendor/device ID for the MPC8265. */ #define PCI_DEVICE_ID_MPC8265 ((0x18C0 << 16) | PCI_VENDOR_ID_MOTOROLA) +#define PCI_DEVICE_ID_MPC8272 ((0x18C1 << 16) | PCI_VENDOR_ID_MOTOROLA) #define M8265_PCIBR0 0x101ac #define M8265_PCIBR1 0x101b0 diff --git a/include/asm-ppc/mpc8260.h b/include/asm-ppc/mpc8260.h index d820894e5991..89eb8a2ac693 100644 --- a/include/asm-ppc/mpc8260.h +++ b/include/asm-ppc/mpc8260.h @@ -41,7 +41,7 @@ #endif #ifdef CONFIG_PCI_8260 -#include +#include #endif /* Make sure the memory translation stuff is there if PCI not used. From 91f9855a7afbb160ba1709bf342858732138abad Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sat, 28 May 2005 15:52:12 -0700 Subject: [PATCH 068/155] [PATCH] ppc32: Fix building MPC8555 CDS when CONFIG_PCI is disabled The patch that introduced support for the VIA chipset broke building if CONFIG_PCI is disabled. Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/platforms/85xx/mpc85xx_cds_common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index c2a512735183..3ac0321eed03 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -439,9 +439,6 @@ mpc85xx_cds_setup_arch(void) printk("mpc85xx_cds_setup_arch\n"); - /* VIA IDE configuration */ - ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup; - #ifdef CONFIG_CPM2 cpm2_reset(); #endif @@ -462,6 +459,9 @@ mpc85xx_cds_setup_arch(void) loops_per_jiffy = freq / HZ; #ifdef CONFIG_PCI + /* VIA IDE configuration */ + ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup; + /* setup PCI host bridges */ mpc85xx_setup_hose(); #endif From 92b4dc16257fef814ddf1c8d1d2a20f67f67ee4b Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sat, 28 May 2005 15:52:13 -0700 Subject: [PATCH 069/155] [PATCH] ppc32: Simplified load string emulation error checking The error checking for emulation of load string instructions was overly generous and would cause certain valid forms of the instructions to be treated as illegal. We drop the range checking since the architecture allows this to be boundedly undefined. Tests on CPUs that support these instructions appear not do cause illegal instruction traps on range errors and just allow the execution to occur. Thanks to Kim Phillips for debugging this and figuring out what real HW was doing. Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/kernel/traps.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index f8e7e324a173..c65731e8bc65 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c @@ -408,12 +408,7 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword) /* Early out if we are an invalid form of lswx */ if ((instword & INST_STRING_MASK) == INST_LSWX) - if ((rA >= rT) || (NB_RB >= rT) || (rT == rA) || (rT == NB_RB)) - return -EINVAL; - - /* Early out if we are an invalid form of lswi */ - if ((instword & INST_STRING_MASK) == INST_LSWI) - if ((rA >= rT) || (rT == rA)) + if ((rT == rA) || (rT == NB_RB)) return -EINVAL; EA = (rA == 0) ? 0 : regs->gpr[rA]; From ff945023c6a455679165b14d298316e262ceeb1f Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sat, 28 May 2005 15:52:14 -0700 Subject: [PATCH 070/155] [PATCH] ppc32: MPC834x BCSR_SIZE too small for use in a BAT. The call to io_block_mapping was creating an invalid BAT entry because the value of BCSR_SIZE (32K) is too small to be used in a BAT (128K min). This change removes the io_block_mapping call since these registers can easily be mapped using ioremap at the point of use. Signed-off-by: Randy Vinson Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/platforms/83xx/mpc834x_sys.c | 1 - arch/ppc/platforms/83xx/mpc834x_sys.h | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c index b3b0f51979d2..e6348b5a1ddc 100644 --- a/arch/ppc/platforms/83xx/mpc834x_sys.c +++ b/arch/ppc/platforms/83xx/mpc834x_sys.c @@ -127,7 +127,6 @@ mpc834x_sys_map_io(void) { /* we steal the lowest ioremap addr for virt space */ io_block_mapping(VIRT_IMMRBAR, immrbar, 1024*1024, _PAGE_IO); - io_block_mapping(BCSR_VIRT_ADDR, BCSR_PHYS_ADDR, BCSR_SIZE, _PAGE_IO); } int diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.h b/arch/ppc/platforms/83xx/mpc834x_sys.h index f4d055ae19c1..49db0f4c847e 100644 --- a/arch/ppc/platforms/83xx/mpc834x_sys.h +++ b/arch/ppc/platforms/83xx/mpc834x_sys.h @@ -26,7 +26,6 @@ #define VIRT_IMMRBAR ((uint)0xfe000000) #define BCSR_PHYS_ADDR ((uint)0xf8000000) -#define BCSR_VIRT_ADDR ((uint)0xfe100000) #define BCSR_SIZE ((uint)(32 * 1024)) #ifdef CONFIG_PCI From f9e4a005827ec0b33f0c61fec1634a5a3421decd Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sat, 28 May 2005 15:52:15 -0700 Subject: [PATCH 071/155] [PATCH] ppc32: Add soft reset to MPC834x This change allows mpc83xx_restart to issue a software reset. Signed-off-by: Randy Vinson Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/platforms/83xx/mpc834x_sys.h | 6 ++++++ arch/ppc/syslib/ppc83xx_setup.c | 28 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.h b/arch/ppc/platforms/83xx/mpc834x_sys.h index 49db0f4c847e..a2f6e49d7151 100644 --- a/arch/ppc/platforms/83xx/mpc834x_sys.h +++ b/arch/ppc/platforms/83xx/mpc834x_sys.h @@ -28,6 +28,12 @@ #define BCSR_PHYS_ADDR ((uint)0xf8000000) #define BCSR_SIZE ((uint)(32 * 1024)) +#define BCSR_MISC_REG2_OFF 0x07 +#define BCSR_MISC_REG2_PORESET 0x01 + +#define BCSR_MISC_REG3_OFF 0x08 +#define BCSR_MISC_REG3_CNFLOCK 0x80 + #ifdef CONFIG_PCI /* PCI interrupt controller */ #define PIRQA MPC83xx_IRQ_IRQ4 diff --git a/arch/ppc/syslib/ppc83xx_setup.c b/arch/ppc/syslib/ppc83xx_setup.c index c28f9d679484..843cf8873e60 100644 --- a/arch/ppc/syslib/ppc83xx_setup.c +++ b/arch/ppc/syslib/ppc83xx_setup.c @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -117,7 +118,34 @@ mpc83xx_early_serial_map(void) void mpc83xx_restart(char *cmd) { + volatile unsigned char __iomem *reg; + unsigned char tmp; + + reg = ioremap(BCSR_PHYS_ADDR, BCSR_SIZE); + local_irq_disable(); + + /* + * Unlock the BCSR bits so a PRST will update the contents. + * Otherwise the reset asserts but doesn't clear. + */ + tmp = in_8(reg + BCSR_MISC_REG3_OFF); + tmp |= BCSR_MISC_REG3_CNFLOCK; /* low true, high false */ + out_8(reg + BCSR_MISC_REG3_OFF, tmp); + + /* + * Trigger a reset via a low->high transition of the + * PORESET bit. + */ + tmp = in_8(reg + BCSR_MISC_REG2_OFF); + tmp &= ~BCSR_MISC_REG2_PORESET; + out_8(reg + BCSR_MISC_REG2_OFF, tmp); + + udelay(1); + + tmp |= BCSR_MISC_REG2_PORESET; + out_8(reg + BCSR_MISC_REG2_OFF, tmp); + for(;;); } From 6cf2b3fc9934a56ceeb393ea5d0149e0bebc80fa Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sat, 28 May 2005 15:52:15 -0700 Subject: [PATCH 072/155] [PATCH] ppc32: i8259 PIC should not be initialized if PCI is not configured Trying to initialize the i8259 PIC will not work if CONFIG_PCI is not enabled. The kernel hangs if the initialization is tried. Signed-off-by: Kumar Gala Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc/platforms/85xx/mpc85xx_cds_common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c index 3ac0321eed03..e7cfa498568c 100644 --- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c +++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c @@ -200,12 +200,14 @@ mpc85xx_cds_init_IRQ(void) */ openpic_init(MPC85xx_OPENPIC_IRQ_OFFSET); +#ifdef CONFIG_PCI openpic_hookup_cascade(PIRQ0A, "82c59 cascade", i8259_irq); for (i = 0; i < NUM_8259_INTERRUPTS; i++) irq_desc[i].handler = &i8259_pic; i8259_init(0); +#endif #ifdef CONFIG_CPM2 /* Setup CPM2 PIC */ From 7d6064d44bc79e328f2794ee7322ba2676511e2b Mon Sep 17 00:00:00 2001 From: Vojtech Pavlik Date: Sun, 29 May 2005 01:27:44 -0500 Subject: [PATCH 073/155] Input: Fix fast scrolling scancodes in atkbd.c Signed-off-by: Vojtech Pavlik Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/atkbd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 79c332f16fc7..af0446c6de82 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -171,9 +171,9 @@ static struct { unsigned char set2; } atkbd_scroll_keys[] = { { ATKBD_SCR_1, 0xc5 }, - { ATKBD_SCR_2, 0xa9 }, - { ATKBD_SCR_4, 0xb6 }, - { ATKBD_SCR_8, 0xa7 }, + { ATKBD_SCR_2, 0x9d }, + { ATKBD_SCR_4, 0xa4 }, + { ATKBD_SCR_8, 0x9b }, { ATKBD_SCR_CLICK, 0xe0 }, { ATKBD_SCR_LEFT, 0xcb }, { ATKBD_SCR_RIGHT, 0xd2 }, From 7238cfb3342078ad6d1dd06c7b567da428672476 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Sun, 29 May 2005 14:48:20 -0400 Subject: [PATCH 074/155] libata: bump version --- drivers/scsi/libata.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h index 6518226b8f87..d90430bbb0de 100644 --- a/drivers/scsi/libata.h +++ b/drivers/scsi/libata.h @@ -26,7 +26,7 @@ #define __LIBATA_H__ #define DRV_NAME "libata" -#define DRV_VERSION "1.10" /* must be exactly four chars */ +#define DRV_VERSION "1.11" /* must be exactly four chars */ struct ata_scsi_args { u16 *id; From d8a33ac435c43a1a404b2ec560ef1d1536710c36 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 29 May 2005 14:13:47 -0700 Subject: [PATCH 075/155] [BRIDGE]: features change notification Resend of earlier patch (no changes) from Catalin used to provide device feature change notification. Signed-off-by: Catalin BOIE Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/netdevice.h | 1 + include/linux/notifier.h | 1 + net/core/dev.c | 12 ++++++++++++ net/core/ethtool.c | 8 +++++++- 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index b25bd02720d3..d8c65ecef9d9 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -913,6 +913,7 @@ extern void dev_mc_discard(struct net_device *dev); extern void dev_set_promiscuity(struct net_device *dev, int inc); extern void dev_set_allmulti(struct net_device *dev, int inc); extern void netdev_state_change(struct net_device *dev); +extern void netdev_features_change(struct net_device *dev); /* Load a device via the kmod */ extern void dev_load(const char *name); extern void dev_mcast_init(void); diff --git a/include/linux/notifier.h b/include/linux/notifier.h index 9303a003e9ab..5937dd6053c3 100644 --- a/include/linux/notifier.h +++ b/include/linux/notifier.h @@ -56,6 +56,7 @@ extern int notifier_call_chain(struct notifier_block **n, unsigned long val, voi #define NETDEV_CHANGEADDR 0x0008 #define NETDEV_GOING_DOWN 0x0009 #define NETDEV_CHANGENAME 0x000A +#define NETDEV_FEAT_CHANGE 0x000B #define SYS_DOWN 0x0001 /* Notify of system down */ #define SYS_RESTART SYS_DOWN diff --git a/net/core/dev.c b/net/core/dev.c index d4d9e2680adb..f15a3ffff635 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -760,6 +760,18 @@ int dev_change_name(struct net_device *dev, char *newname) return err; } +/** + * netdev_features_change - device changes fatures + * @dev: device to cause notification + * + * Called to indicate a device has changed features. + */ +void netdev_features_change(struct net_device *dev) +{ + notifier_call_chain(&netdev_chain, NETDEV_FEAT_CHANGE, dev); +} +EXPORT_SYMBOL(netdev_features_change); + /** * netdev_state_change - device changes state * @dev: device to cause notification diff --git a/net/core/ethtool.c b/net/core/ethtool.c index f05fde97c43d..252bfc6f03f4 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -682,6 +682,7 @@ int dev_ethtool(struct ifreq *ifr) void __user *useraddr = ifr->ifr_data; u32 ethcmd; int rc; + int old_features; /* * XXX: This can be pushed down into the ethtool_* handlers that @@ -703,6 +704,8 @@ int dev_ethtool(struct ifreq *ifr) if ((rc = dev->ethtool_ops->begin(dev)) < 0) return rc; + old_features = dev->features; + switch (ethcmd) { case ETHTOOL_GSET: rc = ethtool_get_settings(dev, useraddr); @@ -712,7 +715,6 @@ int dev_ethtool(struct ifreq *ifr) break; case ETHTOOL_GDRVINFO: rc = ethtool_get_drvinfo(dev, useraddr); - break; case ETHTOOL_GREGS: rc = ethtool_get_regs(dev, useraddr); @@ -801,6 +803,10 @@ int dev_ethtool(struct ifreq *ifr) if(dev->ethtool_ops->complete) dev->ethtool_ops->complete(dev); + + if (old_features != dev->features) + netdev_features_change(dev); + return rc; ioctl: From 81e8157583c559c27aac75c708d40a35f563d734 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 29 May 2005 14:14:35 -0700 Subject: [PATCH 076/155] [BRIDGE]: make dev->features unsigned The features field in netdevice is really a bitmask, and bitmask's should be unsigned. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- net/core/ethtool.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index d8c65ecef9d9..470af8c1a4a0 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -401,7 +401,7 @@ struct net_device } reg_state; /* Net device features */ - int features; + unsigned long features; #define NETIF_F_SG 1 /* Scatter/gather IO. */ #define NETIF_F_IP_CSUM 2 /* Can checksum only TCP/UDP over IPv4. */ #define NETIF_F_NO_CSUM 4 /* Does not require checksum. F.e. loopack. */ diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 252bfc6f03f4..2a56a5218363 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -682,7 +682,7 @@ int dev_ethtool(struct ifreq *ifr) void __user *useraddr = ifr->ifr_data; u32 ethcmd; int rc; - int old_features; + unsigned long old_features; /* * XXX: This can be pushed down into the ethtool_* handlers that From 81d35307dd468b92fe8c58797abb13c62e3e64dd Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 29 May 2005 14:15:17 -0700 Subject: [PATCH 077/155] [BRIDGE]: set features based on enslaved devices Make features of the bridge pseudo-device be a subset of the underlying devices. Motivated by Xen and others who use bridging to do failover. Signed-off-by: Catalin BOIE Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_device.c | 15 +++++++-------- net/bridge/br_if.c | 23 +++++++++++++++++++++++ net/bridge/br_notify.c | 9 +++++++++ net/bridge/br_private.h | 1 + 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index d9b72fde433c..f564ee99782d 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -21,10 +21,7 @@ static struct net_device_stats *br_dev_get_stats(struct net_device *dev) { - struct net_bridge *br; - - br = dev->priv; - + struct net_bridge *br = netdev_priv(dev); return &br->statistics; } @@ -54,9 +51,11 @@ int br_dev_xmit(struct sk_buff *skb, struct net_device *dev) static int br_dev_open(struct net_device *dev) { - netif_start_queue(dev); + struct net_bridge *br = netdev_priv(dev); - br_stp_enable_bridge(dev->priv); + br_features_recompute(br); + netif_start_queue(dev); + br_stp_enable_bridge(br); return 0; } @@ -67,7 +66,7 @@ static void br_dev_set_multicast_list(struct net_device *dev) static int br_dev_stop(struct net_device *dev) { - br_stp_disable_bridge(dev->priv); + br_stp_disable_bridge(netdev_priv(dev)); netif_stop_queue(dev); @@ -76,7 +75,7 @@ static int br_dev_stop(struct net_device *dev) static int br_change_mtu(struct net_device *dev, int new_mtu) { - if ((new_mtu < 68) || new_mtu > br_min_mtu(dev->priv)) + if (new_mtu < 68 || new_mtu > br_min_mtu(netdev_priv(dev))) return -EINVAL; dev->mtu = new_mtu; diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 69872bf3b87e..91bb895375f4 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -314,6 +314,28 @@ int br_min_mtu(const struct net_bridge *br) return mtu; } +/* + * Recomputes features using slave's features + */ +void br_features_recompute(struct net_bridge *br) +{ + struct net_bridge_port *p; + unsigned long features, checksum; + + features = NETIF_F_SG | NETIF_F_FRAGLIST + | NETIF_F_HIGHDMA | NETIF_F_TSO; + checksum = NETIF_F_IP_CSUM; /* least commmon subset */ + + list_for_each_entry(p, &br->port_list, list) { + if (!(p->dev->features + & (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM))) + checksum = 0; + features &= p->dev->features; + } + + br->dev->features = features | checksum | NETIF_F_LLTX; +} + /* called with RTNL */ int br_add_if(struct net_bridge *br, struct net_device *dev) { @@ -368,6 +390,7 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) spin_lock_bh(&br->lock); br_stp_recalculate_bridge_id(br); + br_features_recompute(br); spin_unlock_bh(&br->lock); return 0; diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index f8fb49e34764..917311c6828b 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -65,6 +65,15 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v } break; + case NETDEV_FEAT_CHANGE: + if (br->dev->flags & IFF_UP) + br_features_recompute(br); + + /* could do recursive feature change notification + * but who would care?? + */ + break; + case NETDEV_DOWN: if (br->dev->flags & IFF_UP) br_stp_disable_port(p); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 54d63f1372a0..bdf95a74d8cd 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -174,6 +174,7 @@ extern int br_add_if(struct net_bridge *br, extern int br_del_if(struct net_bridge *br, struct net_device *dev); extern int br_min_mtu(const struct net_bridge *br); +extern void br_features_recompute(struct net_bridge *br); /* br_input.c */ extern int br_handle_frame_finish(struct sk_buff *skb); From 85967bb46dd1f8f2c49b85a313866c00ac0c9b59 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 29 May 2005 14:15:55 -0700 Subject: [PATCH 078/155] [BRIDGE]: prevent bad forwarding table updates Avoid poisoning of the bridge forwarding table by frames that have been dropped by filtering. This prevents spoofed source addresses on hostile side of bridge from causing packet leakage, a small but possible security risk. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_input.c | 6 ++++-- net/bridge/br_stp_bpdu.c | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 2b1cce46cab4..2aa5dda24a08 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -54,6 +54,9 @@ int br_handle_frame_finish(struct sk_buff *skb) struct net_bridge_fdb_entry *dst; int passedup = 0; + /* insert into forwarding database after filtering to avoid spoofing */ + br_fdb_update(p->br, p, eth_hdr(skb)->h_source); + if (br->dev->flags & IFF_PROMISC) { struct sk_buff *skb2; @@ -108,8 +111,7 @@ int br_handle_frame(struct net_bridge_port *p, struct sk_buff **pskb) if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) goto err; - if (p->state == BR_STATE_LEARNING || - p->state == BR_STATE_FORWARDING) + if (p->state == BR_STATE_LEARNING) br_fdb_update(p->br, p, eth_hdr(skb)->h_source); if (p->br->stp_enabled && diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index b91a875aca01..d071f1c9ad0b 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -140,6 +140,9 @@ int br_stp_handle_bpdu(struct sk_buff *skb) struct net_bridge *br = p->br; unsigned char *buf; + /* insert into forwarding database after filtering to avoid spoofing */ + br_fdb_update(p->br, p, eth_hdr(skb)->h_source); + /* need at least the 802 and STP headers */ if (!pskb_may_pull(skb, sizeof(header)+1) || memcmp(skb->data, header, sizeof(header))) From 7ce54e3f428b33af714271140601c87b8bf2c544 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 29 May 2005 14:16:48 -0700 Subject: [PATCH 079/155] [BRIDGE]: receive path optimization This improves the bridge local receive path by avoiding going through another softirq. The bridge receive path is already being called from a netif_receive_skb() there is no point in going through another receiveq round trip. Recursion is limited because bridge can never be a port of a bridge so handle_bridge() always returns. Signed-off-by: David S. Miller --- net/bridge/br_input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 2aa5dda24a08..8f5f2e730992 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -26,7 +26,7 @@ static int br_pass_frame_up_finish(struct sk_buff *skb) #ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug = 0; #endif - netif_rx(skb); + netif_receive_skb(skb); return 0; } From 4cafd3f533475c976879d85773735c004f09f576 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 29 May 2005 14:56:34 -0700 Subject: [PATCH 080/155] [TG3]: Add basic selftest infrastructure Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f10dd74988c4..088ed9f634e5 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -133,6 +133,8 @@ /* number of ETHTOOL_GSTATS u64's */ #define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64)) +#define TG3_NUM_TEST 6 + static char version[] __devinitdata = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; @@ -316,6 +318,17 @@ static struct { { "nic_tx_threshold_hit" } }; +static struct { + const char string[ETH_GSTRING_LEN]; +} ethtool_test_keys[TG3_NUM_TEST] = { + { "nvram test (online) " }, + { "link test (online) " }, + { "register test (offline)" }, + { "memory test (offline)" }, + { "loopback test (offline)" }, + { "interrupt test (offline)" }, +}; + static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val) { if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) { @@ -7199,12 +7212,20 @@ static int tg3_get_stats_count (struct net_device *dev) return TG3_NUM_STATS; } +static int tg3_get_test_count (struct net_device *dev) +{ + return TG3_NUM_TEST; +} + static void tg3_get_strings (struct net_device *dev, u32 stringset, u8 *buf) { switch (stringset) { case ETH_SS_STATS: memcpy(buf, ðtool_stats_keys, sizeof(ethtool_stats_keys)); break; + case ETH_SS_TEST: + memcpy(buf, ðtool_test_keys, sizeof(ethtool_test_keys)); + break; default: WARN_ON(1); /* we need a WARN() */ break; @@ -7218,6 +7239,11 @@ static void tg3_get_ethtool_stats (struct net_device *dev, memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats)); } +static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, + u64 *data) +{ +} + static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct mii_ioctl_data *data = if_mii(ifr); @@ -7331,6 +7357,8 @@ static struct ethtool_ops tg3_ethtool_ops = { .get_tso = ethtool_op_get_tso, .set_tso = tg3_set_tso, #endif + .self_test_count = tg3_get_test_count, + .self_test = tg3_self_test, .get_strings = tg3_get_strings, .get_stats_count = tg3_get_stats_count, .get_ethtool_stats = tg3_get_ethtool_stats, From 566f86adb336637d03900f53b886d879aa5f5d56 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 29 May 2005 14:56:58 -0700 Subject: [PATCH 081/155] [TG3]: Add nvram test Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 088ed9f634e5..ab2fa213b301 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7239,9 +7239,59 @@ static void tg3_get_ethtool_stats (struct net_device *dev, memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats)); } +#define NVRAM_TEST_SIZE 0x100 + +static int tg3_test_nvram(struct tg3 *tp) +{ + u32 *buf, csum; + int i, j, err = 0; + + buf = kmalloc(NVRAM_TEST_SIZE, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + for (i = 0, j = 0; i < NVRAM_TEST_SIZE; i += 4, j++) { + u32 val; + + if ((err = tg3_nvram_read(tp, i, &val)) != 0) + break; + buf[j] = cpu_to_le32(val); + } + if (i < NVRAM_TEST_SIZE) + goto out; + + err = -EIO; + if (cpu_to_be32(buf[0]) != TG3_EEPROM_MAGIC) + goto out; + + /* Bootstrap checksum at offset 0x10 */ + csum = calc_crc((unsigned char *) buf, 0x10); + if(csum != cpu_to_le32(buf[0x10/4])) + goto out; + + /* Manufacturing block starts at offset 0x74, checksum at 0xfc */ + csum = calc_crc((unsigned char *) &buf[0x74/4], 0x88); + if (csum != cpu_to_le32(buf[0xfc/4])) + goto out; + + err = 0; + +out: + kfree(buf); + return err; +} + static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *data) { + struct tg3 *tp = netdev_priv(dev); + + memset(data, 0, sizeof(u64) * TG3_NUM_TEST); + + if (tg3_test_nvram(tp) != 0) { + etest->flags |= ETH_TEST_FL_FAILED; + data[0] = 1; + } } static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) From ca43007a92662621e5819912fc31c346e3a2eed8 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 29 May 2005 14:57:23 -0700 Subject: [PATCH 082/155] [TG3]: Add link test Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index ab2fa213b301..30349c5fd73c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7281,6 +7281,32 @@ out: return err; } +#define TG3_SERDES_TIMEOUT_SEC 2 +#define TG3_COPPER_TIMEOUT_SEC 6 + +static int tg3_test_link(struct tg3 *tp) +{ + int i, max; + + if (!netif_running(tp->dev)) + return -ENODEV; + + if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) + max = TG3_SERDES_TIMEOUT_SEC; + else + max = TG3_COPPER_TIMEOUT_SEC; + + for (i = 0; i < max; i++) { + if (netif_carrier_ok(tp->dev)) + return 0; + + if (msleep_interruptible(1000)) + break; + } + + return -EIO; +} + static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *data) { @@ -7292,6 +7318,10 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, etest->flags |= ETH_TEST_FL_FAILED; data[0] = 1; } + if (tg3_test_link(tp) != 0) { + etest->flags |= ETH_TEST_FL_FAILED; + data[1] = 1; + } } static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) From 944d980ecaabe44616a9e2d50101ce774f517bb6 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 29 May 2005 14:57:48 -0700 Subject: [PATCH 083/155] [TG3]: Add parameter to tg3_halt Add a reset kind parameter to tg3_halt() so that the RESET_KIND_SUSPEND parameter can be passed to tg3_halt() before doing offline tests. All other calls to tg3_halt() will use the RESET_KIND_SHUTDOWN parameter. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 30349c5fd73c..73f6e962ed5e 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3083,7 +3083,7 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id, } static int tg3_init_hw(struct tg3 *); -static int tg3_halt(struct tg3 *, int); +static int tg3_halt(struct tg3 *, int, int); #ifdef CONFIG_NET_POLL_CONTROLLER static void tg3_poll_controller(struct net_device *dev) @@ -3107,7 +3107,7 @@ static void tg3_reset_task(void *_data) restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER; tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER; - tg3_halt(tp, 0); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 0); tg3_init_hw(tp); tg3_netif_start(tp); @@ -3453,7 +3453,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); - tg3_halt(tp, 1); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_set_mtu(dev, tp, new_mtu); @@ -4144,19 +4144,19 @@ static void tg3_stop_fw(struct tg3 *tp) } /* tp->lock is held. */ -static int tg3_halt(struct tg3 *tp, int silent) +static int tg3_halt(struct tg3 *tp, int kind, int silent) { int err; tg3_stop_fw(tp); - tg3_write_sig_pre_reset(tp, RESET_KIND_SHUTDOWN); + tg3_write_sig_pre_reset(tp, kind); tg3_abort_hw(tp, silent); err = tg3_chip_reset(tp); - tg3_write_sig_legacy(tp, RESET_KIND_SHUTDOWN); - tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); + tg3_write_sig_legacy(tp, kind); + tg3_write_sig_post_reset(tp, kind); if (err) return err; @@ -5997,7 +5997,7 @@ static int tg3_test_msi(struct tg3 *tp) spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); - tg3_halt(tp, 1); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); err = tg3_init_hw(tp); spin_unlock(&tp->tx_lock); @@ -6073,7 +6073,7 @@ static int tg3_open(struct net_device *dev) err = tg3_init_hw(tp); if (err) { - tg3_halt(tp, 1); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); } else { if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) @@ -6117,7 +6117,7 @@ static int tg3_open(struct net_device *dev) pci_disable_msi(tp->pdev); tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; } - tg3_halt(tp, 1); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); tg3_free_consistent(tp); @@ -6390,7 +6390,7 @@ static int tg3_close(struct net_device *dev) tg3_disable_ints(tp); - tg3_halt(tp, 1); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_free_rings(tp); tp->tg3_flags &= ~(TG3_FLAG_INIT_COMPLETE | @@ -7110,7 +7110,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e tp->tx_pending = ering->tx_pending; if (netif_running(dev)) { - tg3_halt(tp, 1); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_init_hw(tp); tg3_netif_start(tp); } @@ -7153,7 +7153,7 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam tp->tg3_flags &= ~TG3_FLAG_TX_PAUSE; if (netif_running(dev)) { - tg3_halt(tp, 1); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); tg3_init_hw(tp); tg3_netif_start(tp); } @@ -9586,7 +9586,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, (tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { pci_save_state(tp->pdev); tw32(MEMARB_MODE, MEMARB_MODE_ENABLE); - tg3_halt(tp, 1); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); } err = tg3_test_dma(tp); @@ -9713,7 +9713,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state) spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); - tg3_halt(tp, 1); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); From a71116d1f3b85a69fe3a3acec9223fefb4b1fc66 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 29 May 2005 14:58:11 -0700 Subject: [PATCH 084/155] [TG3]: Add register test Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 73f6e962ed5e..4589f8f90119 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7307,6 +7307,219 @@ static int tg3_test_link(struct tg3 *tp) return -EIO; } +/* Only test the commonly used registers */ +static int tg3_test_registers(struct tg3 *tp) +{ + int i, is_5705; + u32 offset, read_mask, write_mask, val, save_val, read_val; + static struct { + u16 offset; + u16 flags; +#define TG3_FL_5705 0x1 +#define TG3_FL_NOT_5705 0x2 +#define TG3_FL_NOT_5788 0x4 + u32 read_mask; + u32 write_mask; + } reg_tbl[] = { + /* MAC Control Registers */ + { MAC_MODE, TG3_FL_NOT_5705, + 0x00000000, 0x00ef6f8c }, + { MAC_MODE, TG3_FL_5705, + 0x00000000, 0x01ef6b8c }, + { MAC_STATUS, TG3_FL_NOT_5705, + 0x03800107, 0x00000000 }, + { MAC_STATUS, TG3_FL_5705, + 0x03800100, 0x00000000 }, + { MAC_ADDR_0_HIGH, 0x0000, + 0x00000000, 0x0000ffff }, + { MAC_ADDR_0_LOW, 0x0000, + 0x00000000, 0xffffffff }, + { MAC_RX_MTU_SIZE, 0x0000, + 0x00000000, 0x0000ffff }, + { MAC_TX_MODE, 0x0000, + 0x00000000, 0x00000070 }, + { MAC_TX_LENGTHS, 0x0000, + 0x00000000, 0x00003fff }, + { MAC_RX_MODE, TG3_FL_NOT_5705, + 0x00000000, 0x000007fc }, + { MAC_RX_MODE, TG3_FL_5705, + 0x00000000, 0x000007dc }, + { MAC_HASH_REG_0, 0x0000, + 0x00000000, 0xffffffff }, + { MAC_HASH_REG_1, 0x0000, + 0x00000000, 0xffffffff }, + { MAC_HASH_REG_2, 0x0000, + 0x00000000, 0xffffffff }, + { MAC_HASH_REG_3, 0x0000, + 0x00000000, 0xffffffff }, + + /* Receive Data and Receive BD Initiator Control Registers. */ + { RCVDBDI_JUMBO_BD+0, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { RCVDBDI_JUMBO_BD+4, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { RCVDBDI_JUMBO_BD+8, TG3_FL_NOT_5705, + 0x00000000, 0x00000003 }, + { RCVDBDI_JUMBO_BD+0xc, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { RCVDBDI_STD_BD+0, 0x0000, + 0x00000000, 0xffffffff }, + { RCVDBDI_STD_BD+4, 0x0000, + 0x00000000, 0xffffffff }, + { RCVDBDI_STD_BD+8, 0x0000, + 0x00000000, 0xffff0002 }, + { RCVDBDI_STD_BD+0xc, 0x0000, + 0x00000000, 0xffffffff }, + + /* Receive BD Initiator Control Registers. */ + { RCVBDI_STD_THRESH, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { RCVBDI_STD_THRESH, TG3_FL_5705, + 0x00000000, 0x000003ff }, + { RCVBDI_JUMBO_THRESH, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + + /* Host Coalescing Control Registers. */ + { HOSTCC_MODE, TG3_FL_NOT_5705, + 0x00000000, 0x00000004 }, + { HOSTCC_MODE, TG3_FL_5705, + 0x00000000, 0x000000f6 }, + { HOSTCC_RXCOL_TICKS, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { HOSTCC_RXCOL_TICKS, TG3_FL_5705, + 0x00000000, 0x000003ff }, + { HOSTCC_TXCOL_TICKS, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { HOSTCC_TXCOL_TICKS, TG3_FL_5705, + 0x00000000, 0x000003ff }, + { HOSTCC_RXMAX_FRAMES, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { HOSTCC_RXMAX_FRAMES, TG3_FL_5705 | TG3_FL_NOT_5788, + 0x00000000, 0x000000ff }, + { HOSTCC_TXMAX_FRAMES, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { HOSTCC_TXMAX_FRAMES, TG3_FL_5705 | TG3_FL_NOT_5788, + 0x00000000, 0x000000ff }, + { HOSTCC_RXCOAL_TICK_INT, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { HOSTCC_TXCOAL_TICK_INT, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { HOSTCC_RXCOAL_MAXF_INT, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { HOSTCC_RXCOAL_MAXF_INT, TG3_FL_5705 | TG3_FL_NOT_5788, + 0x00000000, 0x000000ff }, + { HOSTCC_TXCOAL_MAXF_INT, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { HOSTCC_TXCOAL_MAXF_INT, TG3_FL_5705 | TG3_FL_NOT_5788, + 0x00000000, 0x000000ff }, + { HOSTCC_STAT_COAL_TICKS, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { HOSTCC_STATS_BLK_HOST_ADDR, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { HOSTCC_STATS_BLK_HOST_ADDR+4, TG3_FL_NOT_5705, + 0x00000000, 0xffffffff }, + { HOSTCC_STATUS_BLK_HOST_ADDR, 0x0000, + 0x00000000, 0xffffffff }, + { HOSTCC_STATUS_BLK_HOST_ADDR+4, 0x0000, + 0x00000000, 0xffffffff }, + { HOSTCC_STATS_BLK_NIC_ADDR, 0x0000, + 0xffffffff, 0x00000000 }, + { HOSTCC_STATUS_BLK_NIC_ADDR, 0x0000, + 0xffffffff, 0x00000000 }, + + /* Buffer Manager Control Registers. */ + { BUFMGR_MB_POOL_ADDR, 0x0000, + 0x00000000, 0x007fff80 }, + { BUFMGR_MB_POOL_SIZE, 0x0000, + 0x00000000, 0x007fffff }, + { BUFMGR_MB_RDMA_LOW_WATER, 0x0000, + 0x00000000, 0x0000003f }, + { BUFMGR_MB_MACRX_LOW_WATER, 0x0000, + 0x00000000, 0x000001ff }, + { BUFMGR_MB_HIGH_WATER, 0x0000, + 0x00000000, 0x000001ff }, + { BUFMGR_DMA_DESC_POOL_ADDR, TG3_FL_NOT_5705, + 0xffffffff, 0x00000000 }, + { BUFMGR_DMA_DESC_POOL_SIZE, TG3_FL_NOT_5705, + 0xffffffff, 0x00000000 }, + + /* Mailbox Registers */ + { GRCMBOX_RCVSTD_PROD_IDX+4, 0x0000, + 0x00000000, 0x000001ff }, + { GRCMBOX_RCVJUMBO_PROD_IDX+4, TG3_FL_NOT_5705, + 0x00000000, 0x000001ff }, + { GRCMBOX_RCVRET_CON_IDX_0+4, 0x0000, + 0x00000000, 0x000007ff }, + { GRCMBOX_SNDHOST_PROD_IDX_0+4, 0x0000, + 0x00000000, 0x000001ff }, + + { 0xffff, 0x0000, 0x00000000, 0x00000000 }, + }; + + if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) + is_5705 = 1; + else + is_5705 = 0; + + for (i = 0; reg_tbl[i].offset != 0xffff; i++) { + if (is_5705 && (reg_tbl[i].flags & TG3_FL_NOT_5705)) + continue; + + if (!is_5705 && (reg_tbl[i].flags & TG3_FL_5705)) + continue; + + if ((tp->tg3_flags2 & TG3_FLG2_IS_5788) && + (reg_tbl[i].flags & TG3_FL_NOT_5788)) + continue; + + offset = (u32) reg_tbl[i].offset; + read_mask = reg_tbl[i].read_mask; + write_mask = reg_tbl[i].write_mask; + + /* Save the original register content */ + save_val = tr32(offset); + + /* Determine the read-only value. */ + read_val = save_val & read_mask; + + /* Write zero to the register, then make sure the read-only bits + * are not changed and the read/write bits are all zeros. + */ + tw32(offset, 0); + + val = tr32(offset); + + /* Test the read-only and read/write bits. */ + if (((val & read_mask) != read_val) || (val & write_mask)) + goto out; + + /* Write ones to all the bits defined by RdMask and WrMask, then + * make sure the read-only bits are not changed and the + * read/write bits are all ones. + */ + tw32(offset, read_mask | write_mask); + + val = tr32(offset); + + /* Test the read-only bits. */ + if ((val & read_mask) != read_val) + goto out; + + /* Test the read/write bits. */ + if ((val & write_mask) != write_mask) + goto out; + + tw32(offset, save_val); + } + + return 0; + +out: + printk(KERN_ERR PFX "Register test failed at offset %x\n", offset); + tw32(offset, save_val); + return -EIO; +} + static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *data) { @@ -7322,6 +7535,34 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, etest->flags |= ETH_TEST_FL_FAILED; data[1] = 1; } + if (etest->flags & ETH_TEST_FL_OFFLINE) { + if (netif_running(dev)) + tg3_netif_stop(tp); + + spin_lock_irq(&tp->lock); + spin_lock(&tp->tx_lock); + + tg3_halt(tp, RESET_KIND_SUSPEND, 1); + tg3_nvram_lock(tp); + tg3_halt_cpu(tp, RX_CPU_BASE); + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + tg3_halt_cpu(tp, TX_CPU_BASE); + tg3_nvram_unlock(tp); + + if (tg3_test_registers(tp) != 0) { + etest->flags |= ETH_TEST_FL_FAILED; + data[2] = 1; + } + + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); + if (netif_running(dev)) { + tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; + tg3_init_hw(tp); + tg3_netif_start(tp); + } + spin_unlock(&tp->tx_lock); + spin_unlock_irq(&tp->lock); + } } static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) From 7942e1dbd7252b480ed238096dca617189d293df Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 29 May 2005 14:58:36 -0700 Subject: [PATCH 085/155] [TG3]: Add memory test Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4589f8f90119..49cb7b3e2835 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7520,6 +7520,62 @@ out: return -EIO; } +static int tg3_do_mem_test(struct tg3 *tp, u32 offset, u32 len) +{ + static u32 test_pattern[] = { 0x00000000, 0xffffffff, 0xaa55a55a }; + int i; + u32 j; + + for (i = 0; i < sizeof(test_pattern)/sizeof(u32); i++) { + for (j = 0; j < len; j += 4) { + u32 val; + + tg3_write_mem(tp, offset + j, test_pattern[i]); + tg3_read_mem(tp, offset + j, &val); + if (val != test_pattern[i]) + return -EIO; + } + } + return 0; +} + +static int tg3_test_memory(struct tg3 *tp) +{ + static struct mem_entry { + u32 offset; + u32 len; + } mem_tbl_570x[] = { + { 0x00000000, 0x01000}, + { 0x00002000, 0x1c000}, + { 0xffffffff, 0x00000} + }, mem_tbl_5705[] = { + { 0x00000100, 0x0000c}, + { 0x00000200, 0x00008}, + { 0x00000b50, 0x00400}, + { 0x00004000, 0x00800}, + { 0x00006000, 0x01000}, + { 0x00008000, 0x02000}, + { 0x00010000, 0x0e000}, + { 0xffffffff, 0x00000} + }; + struct mem_entry *mem_tbl; + int err = 0; + int i; + + if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) + mem_tbl = mem_tbl_5705; + else + mem_tbl = mem_tbl_570x; + + for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) { + if ((err = tg3_do_mem_test(tp, mem_tbl[i].offset, + mem_tbl[i].len)) != 0) + break; + } + + return err; +} + static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *data) { @@ -7553,6 +7609,10 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, etest->flags |= ETH_TEST_FL_FAILED; data[2] = 1; } + if (tg3_test_memory(tp) != 0) { + etest->flags |= ETH_TEST_FL_FAILED; + data[3] = 1; + } tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); if (netif_running(dev)) { From c76949a6826fc11efcd6bb1abdca1ae02761071d Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 29 May 2005 14:58:59 -0700 Subject: [PATCH 086/155] [TG3]: Add loopback test The test will loopback one packet in MAC loopback mode and verify the packet data. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 49cb7b3e2835..2a771fd4c7cd 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7576,6 +7576,117 @@ static int tg3_test_memory(struct tg3 *tp) return err; } +static int tg3_test_loopback(struct tg3 *tp) +{ + u32 mac_mode, send_idx, rx_start_idx, rx_idx, tx_idx, opaque_key; + u32 desc_idx; + struct sk_buff *skb, *rx_skb; + u8 *tx_data; + dma_addr_t map; + int num_pkts, tx_len, rx_len, i, err; + struct tg3_rx_buffer_desc *desc; + + if (!netif_running(tp->dev)) + return -ENODEV; + + err = -EIO; + + tg3_abort_hw(tp, 1); + + /* Clearing this flag to keep interrupts disabled */ + tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; + tg3_reset_hw(tp); + + mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) | + MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY | + MAC_MODE_PORT_MODE_GMII; + tw32(MAC_MODE, mac_mode); + + tx_len = 1514; + skb = dev_alloc_skb(tx_len); + tx_data = skb_put(skb, tx_len); + memcpy(tx_data, tp->dev->dev_addr, 6); + memset(tx_data + 6, 0x0, 8); + + tw32(MAC_RX_MTU_SIZE, tx_len + 4); + + for (i = 14; i < tx_len; i++) + tx_data[i] = (u8) (i & 0xff); + + map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE); + + tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | + HOSTCC_MODE_NOW); + + udelay(10); + + rx_start_idx = tp->hw_status->idx[0].rx_producer; + + send_idx = 0; + num_pkts = 0; + + tg3_set_txd(tp, send_idx, map, tx_len, 0, 1); + + send_idx++; + num_pkts++; + + tw32_tx_mbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, send_idx); + tr32(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW); + + udelay(10); + + for (i = 0; i < 10; i++) { + tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE | + HOSTCC_MODE_NOW); + + udelay(10); + + tx_idx = tp->hw_status->idx[0].tx_consumer; + rx_idx = tp->hw_status->idx[0].rx_producer; + if ((tx_idx == send_idx) && + (rx_idx == (rx_start_idx + num_pkts))) + break; + } + + pci_unmap_single(tp->pdev, map, tx_len, PCI_DMA_TODEVICE); + dev_kfree_skb(skb); + + if (tx_idx != send_idx) + goto out; + + if (rx_idx != rx_start_idx + num_pkts) + goto out; + + desc = &tp->rx_rcb[rx_start_idx]; + desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; + opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; + if (opaque_key != RXD_OPAQUE_RING_STD) + goto out; + + if ((desc->err_vlan & RXD_ERR_MASK) != 0 && + (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) + goto out; + + rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; + if (rx_len != tx_len) + goto out; + + rx_skb = tp->rx_std_buffers[desc_idx].skb; + + map = pci_unmap_addr(&tp->rx_std_buffers[desc_idx], mapping); + pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE); + + for (i = 14; i < tx_len; i++) { + if (*(rx_skb->data + i) != (u8) (i & 0xff)) + goto out; + } + err = 0; + + /* tg3_free_rings will unmap and free the rx_skb */ +out: + return err; +} + static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *data) { @@ -7613,6 +7724,10 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, etest->flags |= ETH_TEST_FL_FAILED; data[3] = 1; } + if (tg3_test_loopback(tp) != 0) { + etest->flags |= ETH_TEST_FL_FAILED; + data[4] = 1; + } tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); if (netif_running(dev)) { From d4bc3927d284784b3f0bff05b4eed2242cc3e226 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 29 May 2005 14:59:20 -0700 Subject: [PATCH 087/155] [TG3]: Add interrupt test This test uses the previously added tg3_test_interrupt() to perform the test. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 2a771fd4c7cd..82afd26a829f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5894,6 +5894,9 @@ static int tg3_test_interrupt(struct tg3 *tp) int err, i; u32 int_mbox = 0; + if (!netif_running(dev)) + return -ENODEV; + tg3_disable_ints(tp); free_irq(tp->pdev->irq, dev); @@ -7729,6 +7732,15 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, data[4] = 1; } + spin_unlock(&tp->tx_lock); + spin_unlock_irq(&tp->lock); + if (tg3_test_interrupt(tp) != 0) { + etest->flags |= ETH_TEST_FL_FAILED; + data[5] = 1; + } + spin_lock_irq(&tp->lock); + spin_lock(&tp->tx_lock); + tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); if (netif_running(dev)) { tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE; From 1b62815193f6c20c60958e5347751155833e3d35 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 29 May 2005 14:59:49 -0700 Subject: [PATCH 088/155] [TG3]: Fix bug in tg3_load_firmware_cpu Add tg3_nvram_lock() and tg3_nvram_unlock() calls around tg3_halt_cpu(). It is possible that the bootcode may be loading code from nvram during this call and stopping the cpu without getting the lock may cause uncompleted nvram data to be left in the nvram data register. Subsequent calls to read/write nvram data will fail. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 82afd26a829f..fc9b5cd957aa 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4370,7 +4370,12 @@ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_b */ tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG; + /* It is possible that bootcode is still loading at this point. + * Get the nvram lock first before halting the cpu. + */ + tg3_nvram_lock(tp); err = tg3_halt_cpu(tp, cpu_base); + tg3_nvram_unlock(tp); if (err) goto out; From 8f937c6099858eee15fae14009dcbd05177fa91d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 29 May 2005 20:23:46 -0700 Subject: [PATCH 089/155] [IPV4]: Primary and secondary addresses Add an option to make secondary IP addresses get promoted when primary IP addresses are removed from the device. It defaults to off to preserve existing behavior. Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- include/linux/inetdevice.h | 2 ++ include/linux/sysctl.h | 1 + net/ipv4/devinet.c | 34 +++++++++++++++++++++++++++++----- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 6fafb27877a7..7e1e15f934f3 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -29,6 +29,7 @@ struct ipv4_devconf int no_xfrm; int no_policy; int force_igmp_version; + int promote_secondaries; void *sysctl; }; @@ -71,6 +72,7 @@ struct in_device #define IN_DEV_SEC_REDIRECTS(in_dev) (ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects) #define IN_DEV_IDTAG(in_dev) ((in_dev)->cnf.tag) #define IN_DEV_MEDIUM_ID(in_dev) ((in_dev)->cnf.medium_id) +#define IN_DEV_PROMOTE_SECONDARIES(in_dev) (ipv4_devconf.promote_secondaries || (in_dev)->cnf.promote_secondaries) #define IN_DEV_RX_REDIRECTS(in_dev) \ ((IN_DEV_FORWARD(in_dev) && \ diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 772998147e3e..23032d9d6071 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -399,6 +399,7 @@ enum NET_IPV4_CONF_FORCE_IGMP_VERSION=17, NET_IPV4_CONF_ARP_ANNOUNCE=18, NET_IPV4_CONF_ARP_IGNORE=19, + NET_IPV4_CONF_PROMOTE_SECONDARIES=20, __NET_IPV4_CONF_MAX }; diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 3cc96730c4ed..478a30179a52 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -233,11 +233,14 @@ int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b) static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy) { + struct in_ifaddr *promote = NULL; struct in_ifaddr *ifa1 = *ifap; ASSERT_RTNL(); - /* 1. Deleting primary ifaddr forces deletion all secondaries */ + /* 1. Deleting primary ifaddr forces deletion all secondaries + * unless alias promotion is set + **/ if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) { struct in_ifaddr *ifa; @@ -251,11 +254,16 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, continue; } - *ifap1 = ifa->ifa_next; + if (!IN_DEV_PROMOTE_SECONDARIES(in_dev)) { + *ifap1 = ifa->ifa_next; - rtmsg_ifa(RTM_DELADDR, ifa); - notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa); - inet_free_ifa(ifa); + rtmsg_ifa(RTM_DELADDR, ifa); + notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa); + inet_free_ifa(ifa); + } else { + promote = ifa; + break; + } } } @@ -281,6 +289,13 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, if (!in_dev->ifa_list) inetdev_destroy(in_dev); } + + if (promote && IN_DEV_PROMOTE_SECONDARIES(in_dev)) { + /* not sure if we should send a delete notify first? */ + promote->ifa_flags &= ~IFA_F_SECONDARY; + rtmsg_ifa(RTM_NEWADDR, promote); + notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote); + } } static int inet_insert_ifa(struct in_ifaddr *ifa) @@ -1384,6 +1399,15 @@ static struct devinet_sysctl_table { .proc_handler = &ipv4_doint_and_flush, .strategy = &ipv4_doint_and_flush_strategy, }, + { + .ctl_name = NET_IPV4_CONF_PROMOTE_SECONDARIES, + .procname = "promote_secondaries", + .data = &ipv4_devconf.promote_secondaries, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &ipv4_doint_and_flush, + .strategy = &ipv4_doint_and_flush_strategy, + }, }, .devinet_dev = { { From 79165121bc09c209451487d977df910c4ff6fc94 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Sun, 29 May 2005 20:24:30 -0700 Subject: [PATCH 090/155] [NET]: Add is_multicast_ether_addr() in include/linux/etherdevice.h This patch adds is_multicast_ether_addr() to go along with is_valid_ether_addr() and friends. It then changes is_valid_ether_addr() to use the new macro, and fixes up the comment on that function to move implementation details out of the API doco. Signed-off-by: Michael Ellerman Signed-off-by: David S. Miller --- include/linux/etherdevice.h | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 220748b7abea..a1478258d002 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -55,19 +55,33 @@ static inline int is_zero_ether_addr(const u8 *addr) return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]); } +/** + * is_multicast_ether_addr - Determine if the given Ethernet address is a + * multicast address. + * + * @addr: Pointer to a six-byte array containing the Ethernet address + * + * Return true if the address is a multicast address. + */ +static inline int is_multicast_ether_addr(const u8 *addr) +{ + return addr[0] & 0x01; +} + /** * is_valid_ether_addr - Determine if the given Ethernet address is valid * @addr: Pointer to a six-byte array containing the Ethernet address * * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not - * a multicast address, and is not FF:FF:FF:FF:FF:FF. The multicast - * and FF:FF:... tests are combined into the single test "!(addr[0]&1)". + * a multicast address, and is not FF:FF:FF:FF:FF:FF. * * Return true if the address is valid. */ static inline int is_valid_ether_addr(const u8 *addr) { - return !(addr[0]&1) && !is_zero_ether_addr(addr); + /* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to + * explicitly check for it here. */ + return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr); } /** @@ -83,6 +97,6 @@ static inline void random_ether_addr(u8 *addr) addr [0] &= 0xfe; /* clear multicast bit */ addr [0] |= 0x02; /* set local assignment bit (IEEE802) */ } -#endif +#endif /* __KERNEL__ */ #endif /* _LINUX_ETHERDEVICE_H */ From 37e20a66db02eff9adbeee043af990cca85d0034 Mon Sep 17 00:00:00 2001 From: "Pravin B. Shelar" Date: Sun, 29 May 2005 20:26:44 -0700 Subject: [PATCH 091/155] [IPV4]: Kill MULTIPATHHOLDROUTE flag. It cannot work properly, so just ignore it in drr and rr multipath algorithms just like the random multipath algorithm does. Suggested by Herbert Xu. Signed-off by: Pravin B. Shelar Signed-off-by: David S. Miller --- include/net/route.h | 3 --- net/ipv4/multipath_drr.c | 18 +----------------- net/ipv4/multipath_rr.c | 20 -------------------- 3 files changed, 1 insertion(+), 40 deletions(-) diff --git a/include/net/route.h b/include/net/route.h index efe92b239ef1..d34ca8fc6756 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -181,9 +181,6 @@ static inline int ip_route_newports(struct rtable **rp, u16 sport, u16 dport, memcpy(&fl, &(*rp)->fl, sizeof(fl)); fl.fl_ip_sport = sport; fl.fl_ip_dport = dport; -#if defined(CONFIG_IP_ROUTE_MULTIPATH_CACHED) - fl.flags |= FLOWI_FLAG_MULTIPATHOLDROUTE; -#endif ip_rt_put(*rp); *rp = NULL; return ip_route_output_flow(rp, &fl, sk, 0); diff --git a/net/ipv4/multipath_drr.c b/net/ipv4/multipath_drr.c index 9349686131fc..cf2e6bcf7973 100644 --- a/net/ipv4/multipath_drr.c +++ b/net/ipv4/multipath_drr.c @@ -57,7 +57,6 @@ struct multipath_device { static struct multipath_device state[MULTIPATH_MAX_DEVICECANDIDATES]; static DEFINE_SPINLOCK(state_lock); -static struct rtable *last_selection = NULL; static int inline __multipath_findslot(void) { @@ -111,11 +110,6 @@ struct notifier_block drr_dev_notifier = { .notifier_call = drr_dev_event, }; -static void drr_remove(struct rtable *rt) -{ - if (last_selection == rt) - last_selection = NULL; -} static void drr_safe_inc(atomic_t *usecount) { @@ -144,14 +138,6 @@ static void drr_select_route(const struct flowi *flp, int devidx = -1; int cur_min_devidx = -1; - /* if necessary and possible utilize the old alternative */ - if ((flp->flags & FLOWI_FLAG_MULTIPATHOLDROUTE) != 0 && - last_selection != NULL) { - result = last_selection; - *rp = result; - return; - } - /* 1. make sure all alt. nexthops have the same GC related data */ /* 2. determine the new candidate to be returned */ result = NULL; @@ -229,12 +215,10 @@ static void drr_select_route(const struct flowi *flp, } *rp = result; - last_selection = result; } static struct ip_mp_alg_ops drr_ops = { .mp_alg_select_route = drr_select_route, - .mp_alg_remove = drr_remove, }; static int __init drr_init(void) @@ -244,7 +228,7 @@ static int __init drr_init(void) if (err) return err; - err = multipath_alg_register(&drr_ops, IP_MP_ALG_RR); + err = multipath_alg_register(&drr_ops, IP_MP_ALG_DRR); if (err) goto fail; diff --git a/net/ipv4/multipath_rr.c b/net/ipv4/multipath_rr.c index 554a82568160..061b6b253982 100644 --- a/net/ipv4/multipath_rr.c +++ b/net/ipv4/multipath_rr.c @@ -47,29 +47,12 @@ #include #include -#define MULTIPATH_MAX_CANDIDATES 40 - -static struct rtable* last_used = NULL; - -static void rr_remove(struct rtable *rt) -{ - if (last_used == rt) - last_used = NULL; -} - static void rr_select_route(const struct flowi *flp, struct rtable *first, struct rtable **rp) { struct rtable *nh, *result, *min_use_cand = NULL; int min_use = -1; - /* if necessary and possible utilize the old alternative */ - if ((flp->flags & FLOWI_FLAG_MULTIPATHOLDROUTE) != 0 && - last_used != NULL) { - result = last_used; - goto out; - } - /* 1. make sure all alt. nexthops have the same GC related data * 2. determine the new candidate to be returned */ @@ -90,15 +73,12 @@ static void rr_select_route(const struct flowi *flp, if (!result) result = first; -out: - last_used = result; result->u.dst.__use++; *rp = result; } static struct ip_mp_alg_ops rr_ops = { .mp_alg_select_route = rr_select_route, - .mp_alg_remove = rr_remove, }; static int __init rr_init(void) From 69f6a0fafcdf0bfe85af182695d6d38f80f9d549 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Sun, 29 May 2005 20:27:24 -0700 Subject: [PATCH 092/155] [NET]: Add ethtool support for NETIF_F_HW_CSUM. Signed-off-by: Jon Mason Signed-off-by: David S. Miller --- include/linux/ethtool.h | 1 + net/core/ethtool.c | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index c85b210490ea..a0ab26aab450 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -256,6 +256,7 @@ struct net_device; u32 ethtool_op_get_link(struct net_device *dev); u32 ethtool_op_get_tx_csum(struct net_device *dev); int ethtool_op_set_tx_csum(struct net_device *dev, u32 data); +int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data); u32 ethtool_op_get_sg(struct net_device *dev); int ethtool_op_set_sg(struct net_device *dev, u32 data); u32 ethtool_op_get_tso(struct net_device *dev); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 2a56a5218363..8ec484894d68 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -29,7 +29,7 @@ u32 ethtool_op_get_link(struct net_device *dev) u32 ethtool_op_get_tx_csum(struct net_device *dev) { - return (dev->features & NETIF_F_IP_CSUM) != 0; + return (dev->features & (NETIF_F_IP_CSUM | NETIF_F_HW_CSUM)) != 0; } int ethtool_op_set_tx_csum(struct net_device *dev, u32 data) @@ -42,6 +42,15 @@ int ethtool_op_set_tx_csum(struct net_device *dev, u32 data) return 0; } +int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data) +{ + if (data) + dev->features |= NETIF_F_HW_CSUM; + else + dev->features &= ~NETIF_F_HW_CSUM; + + return 0; +} u32 ethtool_op_get_sg(struct net_device *dev) { return (dev->features & NETIF_F_SG) != 0; @@ -823,3 +832,4 @@ EXPORT_SYMBOL(ethtool_op_get_tx_csum); EXPORT_SYMBOL(ethtool_op_set_sg); EXPORT_SYMBOL(ethtool_op_set_tso); EXPORT_SYMBOL(ethtool_op_set_tx_csum); +EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum); From 6c94d3611be61e4cff33b311f1a626d93d1d3e92 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 29 May 2005 20:28:01 -0700 Subject: [PATCH 093/155] [IPV6]: Clear up user copy warning in flowlabel code. We are intentionally ignoring the copy_to_user() value, make it clear to the compiler too. Noted by Jeff Garzik. Signed-off-by: David S. Miller --- net/ipv6/ip6_flowlabel.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index a93f6dc51979..0e5f7499debb 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -535,10 +535,12 @@ release: if (err) goto done; - /* Do not check for fault */ - if (!freq.flr_label) - copy_to_user(&((struct in6_flowlabel_req __user *) optval)->flr_label, - &fl->label, sizeof(fl->label)); + if (!freq.flr_label) { + if (copy_to_user(&((struct in6_flowlabel_req __user *) optval)->flr_label, + &fl->label, sizeof(fl->label))) { + /* Intentionally ignore fault. */ + } + } sfl1->fl = fl; sfl1->next = np->ipv6_fl_list; From d1102b59ca7b3a3c58912330a4ae38f549c8d569 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 29 May 2005 20:28:25 -0700 Subject: [PATCH 094/155] [NET]: Use %lx for netdev->features sysfs formatting. Signed-off-by: David S. Miller --- net/core/net-sysfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 060f703659e8..910eb4c05a47 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -21,6 +21,7 @@ #define to_net_dev(class) container_of(class, struct net_device, class_dev) static const char fmt_hex[] = "%#x\n"; +static const char fmt_long_hex[] = "%#lx\n"; static const char fmt_dec[] = "%d\n"; static const char fmt_ulong[] = "%lu\n"; @@ -91,7 +92,7 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL) \ NETDEVICE_ATTR(addr_len, fmt_dec); NETDEVICE_ATTR(iflink, fmt_dec); NETDEVICE_ATTR(ifindex, fmt_dec); -NETDEVICE_ATTR(features, fmt_hex); +NETDEVICE_ATTR(features, fmt_long_hex); NETDEVICE_ATTR(type, fmt_dec); /* use same locking rules as GIFHWADDR ioctl's */ From 9bb7bc942d3da606f184ac6a4dfc7e4d470c831b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 30 May 2005 15:35:26 -0700 Subject: [PATCH 095/155] [NETFILTER]: Fix deadlock with ip_queue and tcp local input path. When we have ip_queue being used from LOCAL_IN, then we end up with a situation where the verdicts coming back from userspace traverse the TCP input path from syscall context. While this seems to work most of the time, there's an ugly deadlock: syscall context is interrupted by the timer interrupt. When the timer interrupt leaves, the timer softirq get's scheduled and calls tcp_delack_timer() and alike. They themselves do bh_lock_sock(sk), which is already held from somewhere else -> boom. I've now tested the suggested solution by Patrick McHardy and Herbert Xu to simply use local_bh_{en,dis}able(). Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- net/ipv4/netfilter/ip_queue.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index e5746b674413..eda1fba431a4 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -3,6 +3,7 @@ * communicating with userspace via netlink. * * (C) 2000-2002 James Morris + * (C) 2003-2005 Netfilter Core Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,6 +18,7 @@ * 2005-01-10: Added /proc counter for dropped packets; fixed so * packets aren't delivered to user space if they're going * to be dropped. + * 2005-05-26: local_bh_{disable,enable} around nf_reinject (Harald Welte) * */ #include @@ -71,7 +73,15 @@ static DECLARE_MUTEX(ipqnl_sem); static void ipq_issue_verdict(struct ipq_queue_entry *entry, int verdict) { + /* TCP input path (and probably other bits) assume to be called + * from softirq context, not from syscall, like ipq_issue_verdict is + * called. TCP input path deadlocks with locks taken from timer + * softirq, e.g. We therefore emulate this by local_bh_disable() */ + + local_bh_disable(); nf_reinject(entry->skb, entry->info, verdict); + local_bh_enable(); + kfree(entry); } From 208d89843b7b03978d8e748b8b991c1be81c4f43 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 30 May 2005 15:50:15 -0700 Subject: [PATCH 096/155] [IPV4]: Fix BUG() in 2.6.x, udp_poll(), fragments + CONFIG_HIGHMEM Steven Hand wrote: > > Reconstructed forward trace: > > net/ipv4/udp.c:1334 spin_lock_irq() > net/ipv4/udp.c:1336 udp_checksum_complete() > net/core/skbuff.c:1069 skb_shinfo(skb)->nr_frags > 1 > net/core/skbuff.c:1086 kunmap_skb_frag() > net/core/skbuff.h:1087 local_bh_enable() > kernel/softirq.c:0140 WARN_ON(irqs_disabled()); The receive queue lock is never taken in IRQs (and should never be) so we can simply substitute bh for irq. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/udp.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 4a6952e3fee9..7c24e64b443f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -738,7 +738,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) unsigned long amount; amount = 0; - spin_lock_irq(&sk->sk_receive_queue.lock); + spin_lock_bh(&sk->sk_receive_queue.lock); skb = skb_peek(&sk->sk_receive_queue); if (skb != NULL) { /* @@ -748,7 +748,7 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) */ amount = skb->len - sizeof(struct udphdr); } - spin_unlock_irq(&sk->sk_receive_queue.lock); + spin_unlock_bh(&sk->sk_receive_queue.lock); return put_user(amount, (int __user *)arg); } @@ -848,12 +848,12 @@ csum_copy_err: /* Clear queue. */ if (flags&MSG_PEEK) { int clear = 0; - spin_lock_irq(&sk->sk_receive_queue.lock); + spin_lock_bh(&sk->sk_receive_queue.lock); if (skb == skb_peek(&sk->sk_receive_queue)) { __skb_unlink(skb, &sk->sk_receive_queue); clear = 1; } - spin_unlock_irq(&sk->sk_receive_queue.lock); + spin_unlock_bh(&sk->sk_receive_queue.lock); if (clear) kfree_skb(skb); } @@ -1334,7 +1334,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) struct sk_buff_head *rcvq = &sk->sk_receive_queue; struct sk_buff *skb; - spin_lock_irq(&rcvq->lock); + spin_lock_bh(&rcvq->lock); while ((skb = skb_peek(rcvq)) != NULL) { if (udp_checksum_complete(skb)) { UDP_INC_STATS_BH(UDP_MIB_INERRORS); @@ -1345,7 +1345,7 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) break; } } - spin_unlock_irq(&rcvq->lock); + spin_unlock_bh(&rcvq->lock); /* nothing to see, move along */ if (skb == NULL) From 05fda3b1d88ebac1fc866fc3ed5b7ef5a4672fa6 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Tue, 31 May 2005 17:01:11 +1000 Subject: [PATCH 097/155] [PATCH] ppc64: actually call prom_send_capabilities When I sent in the patch adding the code for the kernel to tell the firmware about its capabilities on pSeries machines, I included the function to give the capabilities to firmware but somehow forgot the hunk that adds the call to the new function. This patch adds the call. Signed-off-by: Paul Mackerras Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/prom_init.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index 6f79b7b9b445..bc53967a8643 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c @@ -1880,6 +1880,12 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long prom_setprop(_prom->chosen, "linux,platform", &getprop_rval, sizeof(getprop_rval)); + /* + * On pSeries, inform the firmware about our capabilities + */ + if (RELOC(of_platform) & PLATFORM_PSERIES) + prom_send_capabilities(); + /* * On pSeries, copy the CPU hold code */ From 4e7c6816d680d1945916db047a47847afe4b9b02 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 31 May 2005 17:47:36 +0200 Subject: [PATCH 098/155] [PATCH] Relax idecd dma alignment check Only the address needs alignment of mask bits, length should work with a relaxed alignment check. Signed-off-by: Jens Axboe [ This is take 2: make the length check be for 16-byte alignment, not just word alignment. That should hopefully keep everybody happy, while still allowing CD writing with DMA ] Signed-off-by: Linus Torvalds --- drivers/ide/ide-cd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 78e3e7b24d7d..39f3e9101ed4 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1936,7 +1936,7 @@ static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) * NOTE! The "len" and "addr" checks should possibly have * separate masks. */ - if ((rq->data_len & mask) || (addr & mask)) + if ((rq->data_len & 15) || (addr & mask)) info->dma = 0; } From fffcc150a21853651ea890a605832c5cccbb6279 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Tue, 31 May 2005 10:38:32 -0700 Subject: [PATCH 099/155] [IA64] Use "PER_CPU" form of EXPORT macro I was gently reminded that there are per-cpu forms of the EXPORT_SYMBOL macros. Signed-off-by: Tony Luck --- arch/ia64/kernel/perfmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 0e58ec7db128..6407bff6bfd7 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -609,7 +609,7 @@ DEFINE_PER_CPU(unsigned long, pfm_syst_info); DEFINE_PER_CPU(struct task_struct *, pmu_owner); DEFINE_PER_CPU(pfm_context_t *, pmu_ctx); DEFINE_PER_CPU(unsigned long, pmu_activation_number); -EXPORT_SYMBOL_GPL(per_cpu__pfm_syst_info); +EXPORT_PER_CPU_SYMBOL_GPL(pfm_syst_info); /* forward declaration */ From 4a4e5787e0b721021fe0a456ddc987a04cebfc8d Mon Sep 17 00:00:00 2001 From: "R.Marek@sh.cvut.cz" Date: Thu, 21 Apr 2005 09:07:56 +0000 Subject: [PATCH 100/155] [PATCH] I2C: ALI1563 SMBus driver fix This patch fixes "grave" bugs in i2c-ali1563 driver. It seems on recent chipset revisions the HSTS_DONE is set only for block transfers, so we must detect the end of ordinary transaction other way. Also due to missing and mask, setting other transfer modes was not possible. Moreover the continous byte mode transfer uses DAT0 for command rather than CMD command. All those changes were tested with help of Chunhao Huang from Winbond. I'm willing to maintain the driver. Second patch adds me as maintainer if this is neccessary. Signed-Off-By: Rudolf Marek Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 6 +++++ drivers/i2c/busses/i2c-ali1563.c | 46 +++++++++++++++++++++----------- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 97bc927d2c55..65ad8251e4bc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -239,6 +239,12 @@ L: linux-usb-devel@lists.sourceforge.net W: http://www.linux-usb.org/SpeedTouch/ S: Maintained +ALI1563 I2C DRIVER +P: Rudolf Marek +M: r.marek@sh.cvut.cz +L: sensors@stimpy.netroedge.com +S: Maintained + ALPHA PORT P: Richard Henderson M: rth@twiddle.net diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 35710818fe47..fdd881aee618 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -2,6 +2,7 @@ * i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge * * Copyright (C) 2004 Patrick Mochel + * 2005 Rudolf Marek * * The 1563 southbridge is deceptively similar to the 1533, with a * few notable exceptions. One of those happens to be the fact they @@ -57,10 +58,11 @@ #define HST_CNTL2_BLOCK 0x05 +#define HST_CNTL2_SIZEMASK 0x38 static unsigned short ali1563_smba; -static int ali1563_transaction(struct i2c_adapter * a) +static int ali1563_transaction(struct i2c_adapter * a, int size) { u32 data; int timeout; @@ -73,7 +75,7 @@ static int ali1563_transaction(struct i2c_adapter * a) data = inb_p(SMB_HST_STS); if (data & HST_STS_BAD) { - dev_warn(&a->dev,"ali1563: Trying to reset busy device\n"); + dev_err(&a->dev, "ali1563: Trying to reset busy device\n"); outb_p(data | HST_STS_BAD,SMB_HST_STS); data = inb_p(SMB_HST_STS); if (data & HST_STS_BAD) @@ -94,19 +96,31 @@ static int ali1563_transaction(struct i2c_adapter * a) if (timeout && !(data & HST_STS_BAD)) return 0; - dev_warn(&a->dev, "SMBus Error: %s%s%s%s%s\n", - timeout ? "Timeout " : "", - data & HST_STS_FAIL ? "Transaction Failed " : "", - data & HST_STS_BUSERR ? "No response or Bus Collision " : "", - data & HST_STS_DEVERR ? "Device Error " : "", - !(data & HST_STS_DONE) ? "Transaction Never Finished " : ""); - if (!(data & HST_STS_DONE)) + if (!timeout) { + dev_err(&a->dev, "Timeout - Trying to KILL transaction!\n"); /* Issue 'kill' to host controller */ outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2); - else - /* Issue timeout to reset all devices on bus */ + data = inb_p(SMB_HST_STS); + } + + /* device error - no response, ignore the autodetection case */ + if ((data & HST_STS_DEVERR) && (size != HST_CNTL2_QUICK)) { + dev_err(&a->dev, "Device error!\n"); + } + + /* bus collision */ + if (data & HST_STS_BUSERR) { + dev_err(&a->dev, "Bus collision!\n"); + /* Issue timeout, hoping it helps */ outb_p(HST_CNTL1_TIMEOUT,SMB_HST_CNTL1); + } + + if (data & HST_STS_FAIL) { + dev_err(&a->dev, "Cleaning fail after KILL!\n"); + outb_p(0x0,SMB_HST_CNTL2); + } + return -1; } @@ -149,7 +163,7 @@ static int ali1563_block_start(struct i2c_adapter * a) if (timeout && !(data & HST_STS_BAD)) return 0; - dev_warn(&a->dev, "SMBus Error: %s%s%s%s%s\n", + dev_err(&a->dev, "SMBus Error: %s%s%s%s%s\n", timeout ? "Timeout " : "", data & HST_STS_FAIL ? "Transaction Failed " : "", data & HST_STS_BUSERR ? "No response or Bus Collision " : "", @@ -242,13 +256,15 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr, } outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD); - outb_p(inb_p(SMB_HST_CNTL2) | (size << 3), SMB_HST_CNTL2); + outb_p((inb_p(SMB_HST_CNTL2) & ~HST_CNTL2_SIZEMASK) | (size << 3), SMB_HST_CNTL2); /* Write the command register */ + switch(size) { case HST_CNTL2_BYTE: if (rw== I2C_SMBUS_WRITE) - outb_p(cmd, SMB_HST_CMD); + /* Beware it uses DAT0 register and not CMD! */ + outb_p(cmd, SMB_HST_DAT0); break; case HST_CNTL2_BYTE_DATA: outb_p(cmd, SMB_HST_CMD); @@ -268,7 +284,7 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr, goto Done; } - if ((error = ali1563_transaction(a))) + if ((error = ali1563_transaction(a, size))) goto Done; if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK)) From 1e9a47b62f7daf5a94fdd74a94dd4e076f44909a Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 26 May 2005 05:55:55 -0700 Subject: [PATCH 101/155] [PATCH] USB: sl811-hcd fixes Various fixes to the sl811-hcd driver: * Fix small glitches that crept in during recent evolution of usbcore's hcd glue layer, coupling endpoint state records to usbcore and active urbs. (As noted by folk whose boards weren't stuck on 2.6.9 kernels...) * Cope with various system-specific issues: - Some configurations (e.g. a CF-card uses this chip) have iospace addresses for the two registers, rather than memory mapped ones. - Some configurations do interesting things with IRQs; maybe the line is shared, or it doesn't support level triggering. - Not all boards can drive the chip reset line in software. * Address a potential race during unlinking. * Tweak probe/remove section info to handle the case where this segment of a platform bus is hotpluggable (e.g. CF card). (The basic problem is that CONFIG_HOTPLUG is global, which is wrong since not all busses can hotplug even on hotplug-friendly systems...) Also export the driver, so that the CF driver can depend on it. Also removed some annoying end-of-line whitespace. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/sl811-hcd.c | 148 +++++++++++++++++++---------------- 1 file changed, 82 insertions(+), 66 deletions(-) diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index a374b7692073..99d43f758ad0 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -2,8 +2,8 @@ * SL811HS HCD (Host Controller Driver) for USB. * * Copyright (C) 2004 Psion Teklogix (for NetBook PRO) - * Copyright (C) 2004 David Brownell - * + * Copyright (C) 2004-2005 David Brownell + * * Periodic scheduling is based on Roman's OHCI code * Copyright (C) 1999 Roman Weissgaerber * @@ -15,7 +15,7 @@ * For documentation, see the SL811HS spec and the "SL811HS Embedded Host" * document (providing significant pieces missing from that spec); plus * the SL811S spec if you want peripheral side info. - */ + */ /* * Status: Passed basic stress testing, works with hubs, mice, keyboards, @@ -67,7 +67,7 @@ MODULE_DESCRIPTION("SL811HS USB Host Controller Driver"); MODULE_LICENSE("GPL"); -#define DRIVER_VERSION "15 Dec 2004" +#define DRIVER_VERSION "19 May 2005" #ifndef DEBUG @@ -121,6 +121,10 @@ static void port_power(struct sl811 *sl811, int is_on) /* reset as thoroughly as we can */ if (sl811->board && sl811->board->reset) sl811->board->reset(hcd->self.controller); + else { + sl811_write(sl811, SL11H_CTLREG1, SL11H_CTL1MASK_SE0); + mdelay(20); + } sl811_write(sl811, SL11H_IRQ_ENABLE, 0); sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); @@ -443,6 +447,7 @@ static void finish_request( spin_lock(&urb->lock); if (urb->status == -EINPROGRESS) urb->status = status; + urb->hcpriv = NULL; spin_unlock(&urb->lock); spin_unlock(&sl811->lock); @@ -472,7 +477,7 @@ static void finish_request( if (*prev) *prev = ep->next; sl811->load[i] -= ep->load; - } + } ep->branch = PERIODIC_SIZE; sl811->periodic_count--; sl811_to_hcd(sl811)->self.bandwidth_allocated @@ -661,9 +666,9 @@ retry: #ifdef QUIRK2 /* this may no longer be necessary ... */ - if (irqstat == 0 && ret == IRQ_NONE) { + if (irqstat == 0) { irqstat = checkdone(sl811); - if (irqstat /* && irq != ~0 */ ) + if (irqstat) sl811->stat_lost++; } #endif @@ -722,7 +727,8 @@ retry: if (sl811->active_a) { sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0); finish_request(sl811, sl811->active_a, - container_of(sl811->active_a->hep->urb_list.next, + container_of(sl811->active_a + ->hep->urb_list.next, struct urb, urb_list), NULL, -ESHUTDOWN); sl811->active_a = NULL; @@ -731,7 +737,8 @@ retry: if (sl811->active_b) { sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0); finish_request(sl811, sl811->active_b, - container_of(sl811->active_b->hep->urb_list.next, + container_of(sl811->active_b + ->hep->urb_list.next, struct urb, urb_list), NULL, -ESHUTDOWN); sl811->active_b = NULL; @@ -761,7 +768,7 @@ retry: goto retry; } - if (sl811->periodic_count == 0 && list_empty(&sl811->async)) + if (sl811->periodic_count == 0 && list_empty(&sl811->async)) sofirq_off(sl811); sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); @@ -796,7 +803,7 @@ static int balance(struct sl811 *sl811, u16 period, u16 load) } if (j < PERIODIC_SIZE) continue; - branch = i; + branch = i; } } return branch; @@ -890,6 +897,7 @@ static int sl811h_urb_enqueue( break; } + ep->hep = hep; hep->hcpriv = ep; } @@ -961,15 +969,16 @@ fail: static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) { struct sl811 *sl811 = hcd_to_sl811(hcd); - struct usb_host_endpoint *hep = urb->hcpriv; + struct usb_host_endpoint *hep; unsigned long flags; struct sl811h_ep *ep; int retval = 0; - if (!hep) - return -EINVAL; - spin_lock_irqsave(&sl811->lock, flags); + hep = urb->hcpriv; + if (!hep) + goto fail; + ep = hep->hcpriv; if (ep) { /* finish right away if this urb can't be active ... @@ -1017,6 +1026,7 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) VDBG("dequeue, urb %p active %s; wait4irq\n", urb, (sl811->active_a == ep) ? "A" : "B"); } else +fail: retval = -EINVAL; spin_unlock_irqrestore(&sl811->lock, flags); return retval; @@ -1576,6 +1586,9 @@ sl811h_start(struct usb_hcd *hcd) if (sl811->board && sl811->board->power) hub_set_power_budget(udev, sl811->board->power * 2); + /* enable power and interupts */ + port_power(sl811, 1); + return 0; } @@ -1618,7 +1631,7 @@ static struct hc_driver sl811h_hc_driver = { /*-------------------------------------------------------------------------*/ -static int __init_or_module +static int __devexit sl811h_remove(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); @@ -1631,21 +1644,20 @@ sl811h_remove(struct device *dev) remove_debug_file(sl811); usb_remove_hcd(hcd); - iounmap(sl811->data_reg); + /* some platforms may use IORESOURCE_IO */ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - release_mem_region(res->start, 1); + if (res) + iounmap(sl811->data_reg); - iounmap(sl811->addr_reg); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, 1); + if (res) + iounmap(sl811->addr_reg); usb_put_hcd(hcd); return 0; } -#define resource_len(r) (((r)->end - (r)->start) + 1) - -static int __init +static int __devinit sl811h_probe(struct device *dev) { struct usb_hcd *hcd; @@ -1656,7 +1668,7 @@ sl811h_probe(struct device *dev) void __iomem *addr_reg; void __iomem *data_reg; int retval; - u8 tmp; + u8 tmp, ioaddr = 0; /* basic sanity checks first. board-specific init logic should * have initialized these three resources and probably board @@ -1664,13 +1676,8 @@ sl811h_probe(struct device *dev) * minimal sanity checking. */ pdev = container_of(dev, struct platform_device, dev); - if (pdev->num_resources < 3) - return -ENODEV; - - addr = platform_get_resource(pdev, IORESOURCE_MEM, 0); - data = platform_get_resource(pdev, IORESOURCE_MEM, 1); irq = platform_get_irq(pdev, 0); - if (!addr || !data || irq < 0) + if (pdev->num_resources < 3 || irq < 0) return -ENODEV; /* refuse to confuse usbcore */ @@ -1679,24 +1686,31 @@ sl811h_probe(struct device *dev) return -EINVAL; } - if (!request_mem_region(addr->start, 1, hcd_name)) { - retval = -EBUSY; - goto err1; - } - addr_reg = ioremap(addr->start, resource_len(addr)); - if (addr_reg == NULL) { - retval = -ENOMEM; - goto err2; - } + /* the chip may be wired for either kind of addressing */ + addr = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data = platform_get_resource(pdev, IORESOURCE_MEM, 1); + retval = -EBUSY; + if (!addr || !data) { + addr = platform_get_resource(pdev, IORESOURCE_IO, 0); + data = platform_get_resource(pdev, IORESOURCE_IO, 1); + if (!addr || !data) + return -ENODEV; + ioaddr = 1; - if (!request_mem_region(data->start, 1, hcd_name)) { - retval = -EBUSY; - goto err3; - } - data_reg = ioremap(data->start, resource_len(addr)); - if (data_reg == NULL) { - retval = -ENOMEM; - goto err4; + addr_reg = (void __iomem *) addr->start; + data_reg = (void __iomem *) data->start; + } else { + addr_reg = ioremap(addr->start, 1); + if (addr_reg == NULL) { + retval = -ENOMEM; + goto err2; + } + + data_reg = ioremap(data->start, 1); + if (data_reg == NULL) { + retval = -ENOMEM; + goto err4; + } } /* allocate and initialize hcd */ @@ -1737,12 +1751,14 @@ sl811h_probe(struct device *dev) goto err6; } - /* sl811s would need a different handler for this irq */ -#ifdef CONFIG_ARM - /* Cypress docs say the IRQ is IRQT_HIGH ... */ - set_irq_type(irq, IRQT_RISING); -#endif - retval = usb_add_hcd(hcd, irq, SA_INTERRUPT); + /* The chip's IRQ is level triggered, active high. A requirement + * for platform device setup is to cope with things like signal + * inverters (e.g. CF is active low) or working only with edge + * triggers (e.g. most ARM CPUs). Initial driver stress testing + * was on a system with single edge triggering, so most sorts of + * triggering arrangement should work. + */ + retval = usb_add_hcd(hcd, irq, SA_INTERRUPT | SA_SHIRQ); if (retval != 0) goto err6; @@ -1752,14 +1768,12 @@ sl811h_probe(struct device *dev) err6: usb_put_hcd(hcd); err5: - iounmap(data_reg); + if (!ioaddr) + iounmap(data_reg); err4: - release_mem_region(data->start, 1); - err3: - iounmap(addr_reg); + if (!ioaddr) + iounmap(addr_reg); err2: - release_mem_region(addr->start, 1); - err1: DBG("init error, %d\n", retval); return retval; } @@ -1767,7 +1781,7 @@ sl811h_probe(struct device *dev) #ifdef CONFIG_PM /* for this device there's no useful distinction between the controller - * and its root hub, except that the root hub only gets direct PM calls + * and its root hub, except that the root hub only gets direct PM calls * when CONFIG_USB_SUSPEND is enabled. */ @@ -1821,20 +1835,22 @@ sl811h_resume(struct device *dev, u32 phase) #endif -static struct device_driver sl811h_driver = { +/* this driver is exported so sl811_cs can depend on it */ +struct device_driver sl811h_driver = { .name = (char *) hcd_name, .bus = &platform_bus_type, .probe = sl811h_probe, - .remove = sl811h_remove, + .remove = __devexit_p(sl811h_remove), .suspend = sl811h_suspend, .resume = sl811h_resume, }; +EXPORT_SYMBOL(sl811h_driver); /*-------------------------------------------------------------------------*/ - -static int __init sl811h_init(void) + +static int __init sl811h_init(void) { if (usb_disabled()) return -ENODEV; @@ -1844,8 +1860,8 @@ static int __init sl811h_init(void) } module_init(sl811h_init); -static void __exit sl811h_cleanup(void) -{ +static void __exit sl811h_cleanup(void) +{ driver_unregister(&sl811h_driver); } module_exit(sl811h_cleanup); From c6de2b64eb575a3f9326969ec5fcdc6032b38e42 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 26 May 2005 05:55:55 -0700 Subject: [PATCH 102/155] [PATCH] USB: add sl811_cs support This adds support for a CF-card USB Host adapter, the Ratoc REX-CFU1U, by wrapping a PCMCIA driver around the existing "sl811-hcd" platform driver. This CF card is especially useful for PDAs, which currently tend to have no other solution for USB host capability. From: Botond Botyanszki Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/Kconfig | 11 + drivers/usb/host/Makefile | 1 + drivers/usb/host/sl811_cs.c | 442 ++++++++++++++++++++++++++++++++++++ 3 files changed, 454 insertions(+) create mode 100644 drivers/usb/host/sl811_cs.c diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 3196c3265ff5..19e598c9641f 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -124,3 +124,14 @@ config USB_SL811_HCD To compile this driver as a module, choose M here: the module will be called sl811-hcd. +config USB_SL811_CS + tristate "CF/PCMCIA support for SL811HS HCD" + depends on USB_SL811_HCD && PCMCIA + default N + help + Wraps a PCMCIA driver around the SL811HS HCD, supporting the RATOC + REX-CFU1U CF card (often used with PDAs). If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called "sl811_cs". + diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index a574ca06cf6b..5dbd3e7a27c7 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o +obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c new file mode 100644 index 000000000000..6e173265095c --- /dev/null +++ b/drivers/usb/host/sl811_cs.c @@ -0,0 +1,442 @@ +/* + * PCMCIA driver for SL811HS (as found in REX-CFU1U) + * Filename: sl811_cs.c + * Author: Yukio Yamamoto + * + * Port to sl811-hcd and 2.6.x by + * Botond Botyanszki + * Simon Pickering + * + * Last update: 2005-05-12 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +MODULE_AUTHOR("Botond Botyanszki"); +MODULE_DESCRIPTION("REX-CFU1U PCMCIA driver for 2.6"); +MODULE_LICENSE("GPL"); + + +/*====================================================================*/ +/* MACROS */ +/*====================================================================*/ + +#if defined(DEBUG) || defined(CONFIG_USB_DEBUG) || defined(PCMCIA_DEBUG) + +static int pc_debug = 0; +module_param(pc_debug, int, 0644); + +#define DBG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG "sl811_cs: " args) + +#else +#define DBG(n, args...) do{}while(0) +#endif /* no debugging */ + +#define INFO(args...) printk(KERN_INFO "sl811_cs: " args) + +#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444) + +#define CS_CHECK(fn, ret) \ + do { \ + last_fn = (fn); \ + if ((last_ret = (ret)) != 0) \ + goto cs_failed; \ + } while (0) + +/*====================================================================*/ +/* VARIABLES */ +/*====================================================================*/ + +static const char driver_name[DEV_NAME_LEN] = "sl811_cs"; + +static dev_link_t *dev_list = NULL; + +static int irq_list[4] = { -1 }; +static int irq_list_count; + +module_param_array(irq_list, int, &irq_list_count, 0444); + +INT_MODULE_PARM(irq_mask, 0xdeb8); + +typedef struct local_info_t { + dev_link_t link; + dev_node_t node; +} local_info_t; + +/*====================================================================*/ + +static void release_platform_dev(struct device * dev) +{ + DBG(0, "sl811_cs platform_dev release\n"); + dev->parent = NULL; +} + +static struct sl811_platform_data platform_data = { + .potpg = 100, + .power = 50, /* == 100mA */ + // .reset = ... FIXME: invoke CF reset on the card +}; + +static struct resource resources[] = { + [0] = { + .flags = IORESOURCE_IRQ, + }, + [1] = { + // .name = "address", + .flags = IORESOURCE_IO, + }, + [2] = { + // .name = "data", + .flags = IORESOURCE_IO, + }, +}; + +extern struct device_driver sl811h_driver; + +static struct platform_device platform_dev = { + .id = -1, + .dev = { + .platform_data = &platform_data, + .release = release_platform_dev, + }, + .resource = resources, + .num_resources = ARRAY_SIZE(resources), +}; + +static int sl811_hc_init(struct device *parent, ioaddr_t base_addr, int irq) +{ + if (platform_dev.dev.parent) + return -EBUSY; + platform_dev.dev.parent = parent; + + /* finish seting up the platform device */ + resources[0].start = irq; + + resources[1].start = base_addr; + resources[1].end = base_addr; + + resources[2].start = base_addr + 1; + resources[2].end = base_addr + 1; + + /* The driver core will probe for us. We know sl811-hcd has been + * initialized already because of the link order dependency. + */ + platform_dev.name = sl811h_driver.name; + return platform_device_register(&platform_dev); +} + +/*====================================================================*/ + +static void sl811_cs_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DBG(0, "sl811_cs_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) { + if (*linkp == link) + break; + } + if (*linkp == NULL) + return; + + /* Break the link with Card Services */ + if (link->handle) + pcmcia_deregister_client(link->handle); + + /* Unlink device structure, and free it */ + *linkp = link->next; + /* This points to the parent local_info_t struct */ + kfree(link->priv); +} + +static void sl811_cs_release(dev_link_t * link) +{ + + DBG(0, "sl811_cs_release(0x%p)\n", link); + + if (link->open) { + DBG(1, "sl811_cs: release postponed, '%s' still open\n", + link->dev->dev_name); + link->state |= DEV_STALE_CONFIG; + return; + } + + /* Unlink the device chain */ + link->dev = NULL; + + platform_device_unregister(&platform_dev); + pcmcia_release_configuration(link->handle); + if (link->io.NumPorts1) + pcmcia_release_io(link->handle, &link->io); + if (link->irq.AssignedIRQ) + pcmcia_release_irq(link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + + if (link->state & DEV_STALE_LINK) + sl811_cs_detach(link); +} + +static void sl811_cs_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + struct device *parent = &handle_to_dev(handle); + local_info_t *dev = link->priv; + tuple_t tuple; + cisparse_t parse; + int last_fn, last_ret; + u_char buf[64]; + config_info_t conf; + cistpl_cftable_entry_t dflt = { 0 }; + + DBG(0, "sl811_cs_config(0x%p)\n", link); + + tuple.DesiredTuple = CISTPL_CONFIG; + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple)); + CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse)); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* Look up the current Vcc */ + CS_CHECK(GetConfigurationInfo, + pcmcia_get_configuration_info(handle, &conf)); + link->conf.Vcc = conf.Vcc; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple)); + while (1) { + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + + if (pcmcia_get_tuple_data(handle, &tuple) != 0 + || pcmcia_parse_tuple(handle, &tuple, &parse) + != 0) + goto next_entry; + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { + dflt = *cfg; + } + + if (cfg->index == 0) + goto next_entry; + + link->conf.ConfigIndex = cfg->index; + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1<vcc.param[CISTPL_POWER_VNOM]/10000 + != conf.Vcc) + goto next_entry; + } else if (dflt.vcc.present & (1<vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; + + /* we need an interrupt */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) + link->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; + + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + + if (pcmcia_request_io(link->handle, &link->io) != 0) + goto next_entry; + } + break; + +next_entry: + if (link->io.NumPorts1) + pcmcia_release_io(link->handle, &link->io); + last_ret = pcmcia_get_next_tuple(handle, &tuple); + } + + /* require an IRQ and two registers */ + if (!link->io.NumPorts1 || link->io.NumPorts1 < 2) + goto cs_failed; + if (link->conf.Attributes & CONF_ENABLE_IRQ) + CS_CHECK(RequestIRQ, + pcmcia_request_irq(link->handle, &link->irq)); + else + goto cs_failed; + + CS_CHECK(RequestConfiguration, + pcmcia_request_configuration(link->handle, &link->conf)); + + sprintf(dev->node.dev_name, driver_name); + dev->node.major = dev->node.minor = 0; + link->dev = &dev->node; + + printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", + dev->node.dev_name, link->conf.ConfigIndex, + link->conf.Vcc/10, link->conf.Vcc%10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + printk(", irq %d", link->irq.AssignedIRQ); + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1-1); + printk("\n"); + + link->state &= ~DEV_CONFIG_PENDING; + + if (sl811_hc_init(parent, link->io.BasePort1, link->irq.AssignedIRQ) + < 0) { +cs_failed: + printk("sl811_cs_config failed\n"); + cs_error(link->handle, last_fn, last_ret); + sl811_cs_release(link); + link->state &= ~DEV_CONFIG_PENDING; + } +} + +static int +sl811_cs_event(event_t event, int priority, event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + + DBG(1, "sl811_cs_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) + sl811_cs_release(link); + break; + + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + sl811_cs_config(link); + break; + + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + pcmcia_release_configuration(link->handle); + break; + + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) + pcmcia_request_configuration(link->handle, &link->conf); + DBG(0, "reset sl811-hcd here?\n"); + break; + } + return 0; +} + +static dev_link_t *sl811_cs_attach(void) +{ + local_info_t *local; + dev_link_t *link; + client_reg_t client_reg; + int ret, i; + + local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) + return NULL; + memset(local, 0, sizeof(local_info_t)); + link = &local->link; + link->priv = local; + + /* Initialize */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < irq_list_count; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = NULL; + + link->conf.Attributes = 0; + link->conf.Vcc = 33; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = (dev_info_t *) &driver_name; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &sl811_cs_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = pcmcia_register_client(&link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + sl811_cs_detach(link); + return NULL; + } + + return link; +} + +static struct pcmcia_driver sl811_cs_driver = { + .owner = THIS_MODULE, + .drv = { + .name = (char *)driver_name, + }, + .attach = sl811_cs_attach, + .detach = sl811_cs_detach, +}; + +/*====================================================================*/ + +static int __init init_sl811_cs(void) +{ + return pcmcia_register_driver(&sl811_cs_driver); +} +module_init(init_sl811_cs); + +static void __exit exit_sl811_cs(void) +{ + pcmcia_unregister_driver(&sl811_cs_driver); +} +module_exit(exit_sl811_cs); From 47900743a56dc41a053107d64054aca3e1b42157 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Tue, 17 May 2005 15:12:13 +0100 Subject: [PATCH 103/155] [PATCH] USB: ftdi_sio: new PID for ELV UM100 ftdi_sio: Add PID for "ELV USB Module UM100". PID sent by Armin Laugher. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 3 +++ drivers/usb/serial/ftdi_sio.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 52394f08a947..051c3a77b41b 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -364,6 +364,7 @@ static struct usb_device_id id_table_8U232AM [] = { { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0, 0x3ff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0, 0x3ff) }, { USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0, 0x3ff) }, { USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0, 0x3ff) }, { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0, 0x3ff) }, @@ -475,6 +476,7 @@ static struct usb_device_id id_table_FT232BM [] = { { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) }, + { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, @@ -618,6 +620,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) }, { USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) }, { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) }, { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) }, diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index a52bb13a9ce4..8866376823a5 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -144,6 +144,8 @@ /* ELV USB Module UO100 (PID sent by Stefan Frings) */ #define FTDI_ELV_UO100_PID 0xFB58 /* Product Id */ +/* ELV USB Module UM100 (PID sent by Arnim Laeuger) */ +#define FTDI_ELV_UM100_PID 0xFB5A /* Product Id */ /* * Definitions for ID TECH (www.idt-net.com) devices From 06299db3e7f857a4985cf70dc1a5049ec12482c1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 26 May 2005 05:55:55 -0700 Subject: [PATCH 104/155] [PATCH] USB: fix usb-serial generic initialization At module load time, if a generic device is found, the tty information for the device is not set up properly (as the tty structures aren't initialized yet.) This can cause big problems for things like udev. This patch fixes this. Thanks to Kay Sievers for the original patch for this problem. Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb-serial.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 4536f63faaea..5da76dd8fb28 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1297,13 +1297,6 @@ static int __init usb_serial_init(void) goto exit_bus; } - /* register the generic driver, if we should */ - result = usb_serial_generic_register(debug); - if (result < 0) { - err("%s - registering generic driver failed", __FUNCTION__); - goto exit_generic; - } - usb_serial_tty_driver->owner = THIS_MODULE; usb_serial_tty_driver->driver_name = "usbserial"; usb_serial_tty_driver->devfs_name = "usb/tts/"; @@ -1329,17 +1322,24 @@ static int __init usb_serial_init(void) goto exit_tty; } + /* register the generic driver, if we should */ + result = usb_serial_generic_register(debug); + if (result < 0) { + err("%s - registering generic driver failed", __FUNCTION__); + goto exit_generic; + } + info(DRIVER_DESC " " DRIVER_VERSION); return result; +exit_generic: + usb_deregister(&usb_serial_driver); + exit_tty: tty_unregister_driver(usb_serial_tty_driver); exit_reg_driver: - usb_serial_generic_deregister(); - -exit_generic: bus_unregister(&usb_serial_bus_type); exit_bus: From 7a8cb869f31de525bc34095f51f8c8a43ffcb6a9 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Mon, 23 May 2005 19:50:32 +0900 Subject: [PATCH 105/155] [PATCH] PCI Hotplug: shpchp driver doesn't program _HPP values properly Current shpchp driver doesn't seem to program _HPP values properly. The following patch fixes this issue. Signed-off-by: Kenji Kaneshige Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchprm_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c index 243a51d88b86..18aa65a206a6 100644 --- a/drivers/pci/hotplug/shpchprm_acpi.c +++ b/drivers/pci/hotplug/shpchprm_acpi.c @@ -1626,7 +1626,7 @@ int shpchprm_set_hpp( pci_bus->number = func->bus; devfn = PCI_DEVFN(func->device, func->function); - ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); + ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus); if (ab) { if (ab->_hpp) { From 2ac2610b26c9da72820443328ff2c56c7b8c87b8 Mon Sep 17 00:00:00 2001 From: Kenji Kaneshige Date: Fri, 27 May 2005 16:08:14 +0900 Subject: [PATCH 106/155] [PATCH] PCI Hotplug: SHPCHP driver doesn't enable PERR and SERR properly Current shpchp driver doesn't seem to program command register to enable PERR and SERR properly. The following patch fixes this issue. Signed-off-by: Kenji Kaneshige Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchprm_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/hotplug/shpchprm_acpi.c b/drivers/pci/hotplug/shpchprm_acpi.c index 18aa65a206a6..7957cdc72cd0 100644 --- a/drivers/pci/hotplug/shpchprm_acpi.c +++ b/drivers/pci/hotplug/shpchprm_acpi.c @@ -1681,7 +1681,7 @@ void shpchprm_enable_card( | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; bcmd = bcommand = bcommand | PCI_BRIDGE_CTL_NO_ISA; - ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); + ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus); if (ab) { if (ab->_hpp) { if (ab->_hpp->enable_perr) { From af00f9811e0ccbd3db84ddc4cffb0da942653393 Mon Sep 17 00:00:00 2001 From: Andy Currid Date: Mon, 23 May 2005 08:55:45 -0700 Subject: [PATCH 107/155] [PATCH] PCI: amd74xx patch for new NVIDIA device IDs Here's the 2.6 amd74xx patch for NVIDIA MCP51. Signed-off-by: Andy Currid Signed-off-by: Greg Kroah-Hartman --- drivers/ide/pci/amd74xx.c | 3 +++ include/linux/pci_ids.h | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c index 47225e324356..4e0f13d1d060 100644 --- a/drivers/ide/pci/amd74xx.c +++ b/drivers/ide/pci/amd74xx.c @@ -72,6 +72,7 @@ static struct amd_ide_chip { { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 }, + { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, AMD_UDMA_133 }, { 0 } }; @@ -487,6 +488,7 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = { /* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"), /* 13 */ DECLARE_NV_DEV("NFORCE-CK804"), /* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"), + /* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"), }; static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) @@ -521,6 +523,7 @@ static struct pci_device_id amd74xx_pci_tbl[] = { #endif { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 }, { 0, }, }; MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 7ccbc2e4272c..b0d6134e1ee6 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1230,6 +1230,12 @@ #define PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL 0x0258 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL 0x0259 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL 0x025B +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE 0x0265 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA 0x0266 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2 0x0267 +#define PCI_DEVICE_ID_NVIDIA_NVENET_12 0x0268 +#define PCI_DEVICE_ID_NVIDIA_NVENET_13 0x0269 +#define PCI_DEVICE_ID_NVIDIA_MCP51_AUDIO 0x026B #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800 0x0280 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X 0x0281 #define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE 0x0282 From bcc488ab02254a6e60d749187a632dc3d642d4f8 Mon Sep 17 00:00:00 2001 From: Scott Murray Date: Fri, 27 May 2005 16:48:52 -0400 Subject: [PATCH 108/155] [PATCH] PCI Hotplug: more CPCI updates Here is my third attempt at a patch to further update the CompactPCI hotplug driver infrastructure to address the pci_enable_device issue discussed on the list as well as a few other issues I discovered during some more testing. This version addresses a few more issues pointed out by Prarit Bhargava. Changes include: - cpci_enable_device and its recursive calling of pci_enable_device on new devices removed. - Use list_rwsem to avoid slot status change races between disable_slot and check_slots. - Fixed oopsing in cpci_hp_unregister_bus caused by calling list_del on a slot after calling pci_hp_deregister. - Removed kfree calls in cleanup_slots since release_slot will have done it already. - Reworked init_slots a bit to fix latch and adapter file updating on subsequent calls to cpci_hp_start. - Improved sanity checking in cpci_hp_register_controller. - Now shut things down correctly in cpci_hotplug_exit. - Switch to pci_get_slot instead of deprecated pci_find_slot. - A bunch of CodingStyle fixes. Signed-off-by: Scott Murray Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/cpci_hotplug_core.c | 308 +++++++++++------------- drivers/pci/hotplug/cpci_hotplug_pci.c | 144 +++++------ 2 files changed, 195 insertions(+), 257 deletions(-) diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c index 9e9dab7fe86a..8132d946c384 100644 --- a/drivers/pci/hotplug/cpci_hotplug_core.c +++ b/drivers/pci/hotplug/cpci_hotplug_core.c @@ -1,7 +1,7 @@ /* * CompactPCI Hot Plug Driver * - * Copyright (C) 2002 SOMA Networks, Inc. + * Copyright (C) 2002,2005 SOMA Networks, Inc. * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001 IBM Corp. * @@ -45,10 +45,10 @@ #define dbg(format, arg...) \ do { \ - if(cpci_debug) \ + if (cpci_debug) \ printk (KERN_DEBUG "%s: " format "\n", \ MY_NAME , ## arg); \ - } while(0) + } while (0) #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) @@ -111,10 +111,8 @@ enable_slot(struct hotplug_slot *hotplug_slot) dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); - if(controller->ops->set_power) { + if (controller->ops->set_power) retval = controller->ops->set_power(slot, 1); - } - return retval; } @@ -126,37 +124,41 @@ disable_slot(struct hotplug_slot *hotplug_slot) dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + down_write(&list_rwsem); + /* Unconfigure device */ dbg("%s - unconfiguring slot %s", __FUNCTION__, slot->hotplug_slot->name); - if((retval = cpci_unconfigure_slot(slot))) { + if ((retval = cpci_unconfigure_slot(slot))) { err("%s - could not unconfigure slot %s", __FUNCTION__, slot->hotplug_slot->name); - return retval; + goto disable_error; } dbg("%s - finished unconfiguring slot %s", __FUNCTION__, slot->hotplug_slot->name); /* Clear EXT (by setting it) */ - if(cpci_clear_ext(slot)) { + if (cpci_clear_ext(slot)) { err("%s - could not clear EXT for slot %s", __FUNCTION__, slot->hotplug_slot->name); retval = -ENODEV; + goto disable_error; } cpci_led_on(slot); - if(controller->ops->set_power) { - retval = controller->ops->set_power(slot, 0); - } + if (controller->ops->set_power) + if ((retval = controller->ops->set_power(slot, 0))) + goto disable_error; - if(update_adapter_status(slot->hotplug_slot, 0)) { + if (update_adapter_status(slot->hotplug_slot, 0)) warn("failure to update adapter file"); - } - if(slot->extracting) { + if (slot->extracting) { slot->extracting = 0; atomic_dec(&extracting); } +disable_error: + up_write(&list_rwsem); return retval; } @@ -165,9 +167,8 @@ cpci_get_power_status(struct slot *slot) { u8 power = 1; - if(controller->ops->get_power) { + if (controller->ops->get_power) power = controller->ops->get_power(slot); - } return power; } @@ -237,9 +238,8 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) int status = -ENOMEM; int i; - if(!(controller && bus)) { + if (!(controller && bus)) return -ENODEV; - } /* * Create a structure for each slot, and register that slot @@ -316,32 +316,30 @@ int cpci_hp_unregister_bus(struct pci_bus *bus) { struct slot *slot; - struct list_head *tmp; - struct list_head *next; - int status; + struct slot *tmp; + int status = 0; down_write(&list_rwsem); - if(!slots) { + if (!slots) { up_write(&list_rwsem); return -1; } - list_for_each_safe(tmp, next, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->bus == bus) { - dbg("deregistering slot %s", slot->hotplug_slot->name); - status = pci_hp_deregister(slot->hotplug_slot); - if(status) { - err("pci_hp_deregister failed with error %d", - status); - return status; - } - + list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) { + if (slot->bus == bus) { list_del(&slot->slot_list); slots--; + + dbg("deregistering slot %s", slot->hotplug_slot->name); + status = pci_hp_deregister(slot->hotplug_slot); + if (status) { + err("pci_hp_deregister failed with error %d", + status); + break; + } } } up_write(&list_rwsem); - return 0; + return status; } /* This is the interrupt mode interrupt handler */ @@ -351,7 +349,7 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs) dbg("entered cpci_hp_intr"); /* Check to see if it was our interrupt */ - if((controller->irq_flags & SA_SHIRQ) && + if ((controller->irq_flags & SA_SHIRQ) && !controller->ops->check_irq(controller->dev_id)) { dbg("exited cpci_hp_intr, not our interrupt"); return IRQ_NONE; @@ -373,38 +371,30 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs) * INS bits of the cold-inserted devices. */ static int -init_slots(void) +init_slots(int clear_ins) { struct slot *slot; - struct list_head *tmp; struct pci_dev* dev; dbg("%s - enter", __FUNCTION__); down_read(&list_rwsem); - if(!slots) { + if (!slots) { up_read(&list_rwsem); return -1; } - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); + list_for_each_entry(slot, &slot_list, slot_list) { dbg("%s - looking at slot %s", __FUNCTION__, slot->hotplug_slot->name); - if(cpci_check_and_clear_ins(slot)) { + if (clear_ins && cpci_check_and_clear_ins(slot)) dbg("%s - cleared INS for slot %s", __FUNCTION__, slot->hotplug_slot->name); - dev = pci_find_slot(slot->bus->number, PCI_DEVFN(slot->number, 0)); - if(dev) { - if(update_adapter_status(slot->hotplug_slot, 1)) { - warn("failure to update adapter file"); - } - if(update_latch_status(slot->hotplug_slot, 1)) { - warn("failure to update latch file"); - } - slot->dev = dev; - } else { - err("%s - no driver attached to device in slot %s", - __FUNCTION__, slot->hotplug_slot->name); - } + dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0)); + if (dev) { + if (update_adapter_status(slot->hotplug_slot, 1)) + warn("failure to update adapter file"); + if (update_latch_status(slot->hotplug_slot, 1)) + warn("failure to update latch file"); + slot->dev = dev; } } up_read(&list_rwsem); @@ -416,26 +406,28 @@ static int check_slots(void) { struct slot *slot; - struct list_head *tmp; int extracted; int inserted; u16 hs_csr; down_read(&list_rwsem); - if(!slots) { + if (!slots) { up_read(&list_rwsem); err("no slots registered, shutting down"); return -1; } extracted = inserted = 0; - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); + list_for_each_entry(slot, &slot_list, slot_list) { dbg("%s - looking at slot %s", __FUNCTION__, slot->hotplug_slot->name); - if(cpci_check_and_clear_ins(slot)) { - /* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */ - if(slot->dev) { - warn("slot %s already inserted", slot->hotplug_slot->name); + if (cpci_check_and_clear_ins(slot)) { + /* + * Some broken hardware (e.g. PLX 9054AB) asserts + * ENUM# twice... + */ + if (slot->dev) { + warn("slot %s already inserted", + slot->hotplug_slot->name); inserted++; continue; } @@ -452,7 +444,7 @@ check_slots(void) /* Configure device */ dbg("%s - configuring slot %s", __FUNCTION__, slot->hotplug_slot->name); - if(cpci_configure_slot(slot)) { + if (cpci_configure_slot(slot)) { err("%s - could not configure slot %s", __FUNCTION__, slot->hotplug_slot->name); continue; @@ -465,13 +457,11 @@ check_slots(void) dbg("%s - slot %s HS_CSR (2) = %04x", __FUNCTION__, slot->hotplug_slot->name, hs_csr); - if(update_latch_status(slot->hotplug_slot, 1)) { + if (update_latch_status(slot->hotplug_slot, 1)) warn("failure to update latch file"); - } - if(update_adapter_status(slot->hotplug_slot, 1)) { + if (update_adapter_status(slot->hotplug_slot, 1)) warn("failure to update adapter file"); - } cpci_led_off(slot); @@ -481,7 +471,7 @@ check_slots(void) __FUNCTION__, slot->hotplug_slot->name, hs_csr); inserted++; - } else if(cpci_check_ext(slot)) { + } else if (cpci_check_ext(slot)) { /* Process extraction request */ dbg("%s - slot %s extracted", __FUNCTION__, slot->hotplug_slot->name); @@ -491,27 +481,25 @@ check_slots(void) dbg("%s - slot %s HS_CSR = %04x", __FUNCTION__, slot->hotplug_slot->name, hs_csr); - if(!slot->extracting) { - if(update_latch_status(slot->hotplug_slot, 0)) { + if (!slot->extracting) { + if (update_latch_status(slot->hotplug_slot, 0)) { warn("failure to update latch file"); - } - atomic_inc(&extracting); slot->extracting = 1; + atomic_inc(&extracting); } extracted++; - } else if(slot->extracting) { + } else if (slot->extracting) { hs_csr = cpci_get_hs_csr(slot); - if(hs_csr == 0xffff) { + if (hs_csr == 0xffff) { /* * Hmmm, we're likely hosed at this point, should we * bother trying to tell the driver or not? */ err("card in slot %s was improperly removed", slot->hotplug_slot->name); - if(update_adapter_status(slot->hotplug_slot, 0)) { + if (update_adapter_status(slot->hotplug_slot, 0)) warn("failure to update adapter file"); - } slot->extracting = 0; atomic_dec(&extracting); } @@ -520,10 +508,9 @@ check_slots(void) up_read(&list_rwsem); dbg("inserted=%d, extracted=%d, extracting=%d", inserted, extracted, atomic_read(&extracting)); - if(inserted || extracted) { + if (inserted || extracted) return extracted; - } - else if(!atomic_read(&extracting)) { + else if (!atomic_read(&extracting)) { err("cannot find ENUM# source, shutting down"); return -1; } @@ -541,12 +528,12 @@ event_thread(void *data) unlock_kernel(); dbg("%s - event thread started", __FUNCTION__); - while(1) { + while (1) { dbg("event thread sleeping"); down_interruptible(&event_semaphore); dbg("event thread woken, thread_finished = %d", thread_finished); - if(thread_finished || signal_pending(current)) + if (thread_finished || signal_pending(current)) break; do { rc = check_slots(); @@ -558,7 +545,9 @@ event_thread(void *data) thread_finished = 1; break; } - } while(atomic_read(&extracting) != 0); + } while (atomic_read(&extracting) && !thread_finished); + if (thread_finished) + break; /* Re-enable ENUM# interrupt */ dbg("%s - re-enabling irq", __FUNCTION__); @@ -579,21 +568,21 @@ poll_thread(void *data) daemonize("cpci_hp_polld"); unlock_kernel(); - while(1) { - if(thread_finished || signal_pending(current)) + while (1) { + if (thread_finished || signal_pending(current)) break; - if(controller->ops->query_enum()) { + if (controller->ops->query_enum()) { do { rc = check_slots(); - if(rc > 0) { + if (rc > 0) { /* Give userspace a chance to handle extraction */ msleep(500); - } else if(rc < 0) { + } else if (rc < 0) { dbg("%s - error checking slots", __FUNCTION__); thread_finished = 1; break; } - } while(atomic_read(&extracting) != 0); + } while (atomic_read(&extracting) && !thread_finished); } msleep(100); } @@ -612,12 +601,11 @@ cpci_start_thread(void) init_MUTEX_LOCKED(&thread_exit); thread_finished = 0; - if(controller->irq) { + if (controller->irq) pid = kernel_thread(event_thread, NULL, 0); - } else { + else pid = kernel_thread(poll_thread, NULL, 0); - } - if(pid < 0) { + if (pid < 0) { err("Can't start up our thread"); return -1; } @@ -630,9 +618,8 @@ cpci_stop_thread(void) { thread_finished = 1; dbg("thread finish command given"); - if(controller->irq) { + if (controller->irq) up(&event_semaphore); - } dbg("wait for thread to exit"); down(&thread_exit); } @@ -642,45 +629,67 @@ cpci_hp_register_controller(struct cpci_hp_controller *new_controller) { int status = 0; - if(!controller) { - controller = new_controller; - if(controller->irq) { - if(request_irq(controller->irq, - cpci_hp_intr, - controller->irq_flags, - MY_NAME, controller->dev_id)) { - err("Can't get irq %d for the hotplug cPCI controller", controller->irq); - status = -ENODEV; - } - dbg("%s - acquired controller irq %d", __FUNCTION__, - controller->irq); + if (controller) + return -1; + if (!(new_controller && new_controller->ops)) + return -EINVAL; + if (new_controller->irq) { + if (!(new_controller->ops->enable_irq && + new_controller->ops->disable_irq)) + status = -EINVAL; + if (request_irq(new_controller->irq, + cpci_hp_intr, + new_controller->irq_flags, + MY_NAME, + new_controller->dev_id)) { + err("Can't get irq %d for the hotplug cPCI controller", + new_controller->irq); + status = -ENODEV; } - } else { - err("cPCI hotplug controller already registered"); - status = -1; + dbg("%s - acquired controller irq %d", + __FUNCTION__, new_controller->irq); } + if (!status) + controller = new_controller; return status; } +static void +cleanup_slots(void) +{ + struct slot *slot; + struct slot *tmp; + + /* + * Unregister all of our slots with the pci_hotplug subsystem, + * and free up all memory that we had allocated. + */ + down_write(&list_rwsem); + if (!slots) + goto cleanup_null; + list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) { + list_del(&slot->slot_list); + pci_hp_deregister(slot->hotplug_slot); + } +cleanup_null: + up_write(&list_rwsem); + return; +} + int cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller) { int status = 0; - if(controller) { - if(atomic_read(&extracting) != 0) { - return -EBUSY; - } - if(!thread_finished) { + if (controller) { + if (!thread_finished) cpci_stop_thread(); - } - if(controller->irq) { + if (controller->irq) free_irq(controller->irq, controller->dev_id); - } controller = NULL; - } else { + cleanup_slots(); + } else status = -ENODEV; - } return status; } @@ -691,32 +700,28 @@ cpci_hp_start(void) int status; dbg("%s - enter", __FUNCTION__); - if(!controller) { + if (!controller) return -ENODEV; - } down_read(&list_rwsem); - if(list_empty(&slot_list)) { + if (list_empty(&slot_list)) { up_read(&list_rwsem); return -ENODEV; } up_read(&list_rwsem); - if(first) { - status = init_slots(); - if(status) { - return status; - } + status = init_slots(first); + if (first) first = 0; - } + if (status) + return status; status = cpci_start_thread(); - if(status) { + if (status) return status; - } dbg("%s - thread started", __FUNCTION__); - if(controller->irq) { + if (controller->irq) { /* Start enum interrupt processing */ dbg("%s - enabling irq", __FUNCTION__); controller->ops->enable_irq(); @@ -728,13 +733,9 @@ cpci_hp_start(void) int cpci_hp_stop(void) { - if(!controller) { + if (!controller) return -ENODEV; - } - if(atomic_read(&extracting) != 0) { - return -EBUSY; - } - if(controller->irq) { + if (controller->irq) { /* Stop enum interrupt processing */ dbg("%s - disabling irq", __FUNCTION__); controller->ops->disable_irq(); @@ -743,34 +744,6 @@ cpci_hp_stop(void) return 0; } -static void __exit -cleanup_slots(void) -{ - struct list_head *tmp; - struct slot *slot; - - /* - * Unregister all of our slots with the pci_hotplug subsystem, - * and free up all memory that we had allocated. - */ - down_write(&list_rwsem); - if(!slots) { - goto null_cleanup; - } - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - list_del(&slot->slot_list); - pci_hp_deregister(slot->hotplug_slot); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - kfree(slot); - } - null_cleanup: - up_write(&list_rwsem); - return; -} - int __init cpci_hotplug_init(int debug) { @@ -784,7 +757,8 @@ cpci_hotplug_exit(void) /* * Clean everything up. */ - cleanup_slots(); + cpci_hp_stop(); + cpci_hp_unregister_controller(controller); } EXPORT_SYMBOL_GPL(cpci_hp_register_controller); diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c index 69eb4fc54f2f..c878028ad215 100644 --- a/drivers/pci/hotplug/cpci_hotplug_pci.c +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c @@ -1,7 +1,7 @@ /* * CompactPCI Hot Plug Driver PCI functions * - * Copyright (C) 2002 by SOMA Networks, Inc. + * Copyright (C) 2002,2005 by SOMA Networks, Inc. * * All rights reserved. * @@ -38,10 +38,10 @@ extern int cpci_debug; #define dbg(format, arg...) \ do { \ - if(cpci_debug) \ + if (cpci_debug) \ printk (KERN_DEBUG "%s: " format "\n", \ MY_NAME , ## arg); \ - } while(0) + } while (0) #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) @@ -57,16 +57,15 @@ u8 cpci_get_attention_status(struct slot* slot) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return 0; - } - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return 0; - } + return hs_csr & 0x0008 ? 1 : 0; } @@ -78,27 +77,22 @@ int cpci_set_attention_status(struct slot* slot, int status) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return 0; - } - - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return 0; - } - if(status) { + if (status) hs_csr |= HS_CSR_LOO; - } else { + else hs_csr &= ~HS_CSR_LOO; - } - if(pci_bus_write_config_word(slot->bus, + if (pci_bus_write_config_word(slot->bus, slot->devfn, hs_cap + 2, - hs_csr)) { + hs_csr)) return 0; - } return 1; } @@ -110,16 +104,13 @@ u16 cpci_get_hs_csr(struct slot* slot) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return 0xFFFF; - } - - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return 0xFFFF; - } return hs_csr; } @@ -132,24 +123,22 @@ int cpci_check_and_clear_ins(struct slot* slot) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return 0; - } - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return 0; - } - if(hs_csr & HS_CSR_INS) { + if (hs_csr & HS_CSR_INS) { /* Clear INS (by setting it) */ - if(pci_bus_write_config_word(slot->bus, + if (pci_bus_write_config_word(slot->bus, slot->devfn, hs_cap + 2, - hs_csr)) { + hs_csr)) ins = 0; - } - ins = 1; + else + ins = 1; } return ins; } @@ -163,18 +152,15 @@ int cpci_check_ext(struct slot* slot) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return 0; - } - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return 0; - } - if(hs_csr & HS_CSR_EXT) { + if (hs_csr & HS_CSR_EXT) ext = 1; - } return ext; } @@ -186,23 +172,20 @@ int cpci_clear_ext(struct slot* slot) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return -ENODEV; - } - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return -ENODEV; - } - if(hs_csr & HS_CSR_EXT) { + if (hs_csr & HS_CSR_EXT) { /* Clear EXT (by setting it) */ - if(pci_bus_write_config_word(slot->bus, + if (pci_bus_write_config_word(slot->bus, slot->devfn, hs_cap + 2, - hs_csr)) { + hs_csr)) return -ENODEV; - } } return 0; } @@ -215,18 +198,16 @@ int cpci_led_on(struct slot* slot) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return -ENODEV; - } - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return -ENODEV; - } - if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) { + if ((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) { hs_csr |= HS_CSR_LOO; - if(pci_bus_write_config_word(slot->bus, + if (pci_bus_write_config_word(slot->bus, slot->devfn, hs_cap + 2, hs_csr)) { @@ -246,18 +227,16 @@ int cpci_led_off(struct slot* slot) hs_cap = pci_bus_find_capability(slot->bus, slot->devfn, PCI_CAP_ID_CHSWP); - if(!hs_cap) { + if (!hs_cap) return -ENODEV; - } - if(pci_bus_read_config_word(slot->bus, + if (pci_bus_read_config_word(slot->bus, slot->devfn, hs_cap + 2, - &hs_csr)) { + &hs_csr)) return -ENODEV; - } - if(hs_csr & HS_CSR_LOO) { + if (hs_csr & HS_CSR_LOO) { hs_csr &= ~HS_CSR_LOO; - if(pci_bus_write_config_word(slot->bus, + if (pci_bus_write_config_word(slot->bus, slot->devfn, hs_cap + 2, hs_csr)) { @@ -274,19 +253,6 @@ int cpci_led_off(struct slot* slot) * Device configuration functions */ -static void cpci_enable_device(struct pci_dev *dev) -{ - struct pci_bus *bus; - - pci_enable_device(dev); - if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - bus = dev->subordinate; - list_for_each_entry(dev, &bus->devices, bus_list) { - cpci_enable_device(dev); - } - } -} - int cpci_configure_slot(struct slot* slot) { unsigned char busnr; @@ -294,14 +260,14 @@ int cpci_configure_slot(struct slot* slot) dbg("%s - enter", __FUNCTION__); - if(slot->dev == NULL) { + if (slot->dev == NULL) { dbg("pci_dev null, finding %02x:%02x:%x", slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn)); - slot->dev = pci_find_slot(slot->bus->number, slot->devfn); + slot->dev = pci_get_slot(slot->bus, slot->devfn); } /* Still NULL? Well then scan for it! */ - if(slot->dev == NULL) { + if (slot->dev == NULL) { int n; dbg("pci_dev still null"); @@ -311,10 +277,10 @@ int cpci_configure_slot(struct slot* slot) */ n = pci_scan_slot(slot->bus, slot->devfn); dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n); - if(n > 0) + if (n > 0) pci_bus_add_devices(slot->bus); - slot->dev = pci_find_slot(slot->bus->number, slot->devfn); - if(slot->dev == NULL) { + slot->dev = pci_get_slot(slot->bus, slot->devfn); + if (slot->dev == NULL) { err("Could not find PCI device for slot %02x", slot->number); return 1; } @@ -329,8 +295,6 @@ int cpci_configure_slot(struct slot* slot) pci_bus_assign_resources(slot->dev->bus); - cpci_enable_device(slot->dev); - dbg("%s - exit", __FUNCTION__); return 0; } @@ -341,15 +305,15 @@ int cpci_unconfigure_slot(struct slot* slot) struct pci_dev *dev; dbg("%s - enter", __FUNCTION__); - if(!slot->dev) { + if (!slot->dev) { err("No device for slot %02x\n", slot->number); return -ENODEV; } for (i = 0; i < 8; i++) { - dev = pci_find_slot(slot->bus->number, + dev = pci_get_slot(slot->bus, PCI_DEVFN(PCI_SLOT(slot->devfn), i)); - if(dev) { + if (dev) { pci_remove_bus_device(dev); slot->dev = NULL; } From 8d91640606c47551771a9b27664f249f4b176613 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 31 May 2005 14:39:26 -0700 Subject: [PATCH 109/155] [PATCH] x86_64: More fixes for compilation without CONFIG_ACPI Suggested by Alexander Nyberg Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/kernel/io_apic.c | 1 + arch/x86_64/kernel/mpparse.c | 1 + arch/x86_64/kernel/time.c | 2 ++ 3 files changed, 4 insertions(+) diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 80e9b498c443..afd87e64d0a8 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -37,6 +37,7 @@ #include #include #include +#include #define __apicdebuginit __init diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c index f86d9db94bfc..61a63be6b294 100644 --- a/arch/x86_64/kernel/mpparse.c +++ b/arch/x86_64/kernel/mpparse.c @@ -30,6 +30,7 @@ #include #include #include +#include /* Have we found an MP table */ int smp_found_config; diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index 735b6767c8ed..fb8c809b4cd9 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c @@ -27,7 +27,9 @@ #include #include #include +#ifdef CONFIG_ACPI #include /* for PM timer frequency */ +#endif #include #include #include From 9c2be6a0fa186e2cb0cf14f41f20b08a5809a026 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 31 May 2005 14:39:26 -0700 Subject: [PATCH 110/155] [PATCH] x86_64 CONFIG_ACPI=n build fix Make CONFIG_X86_PM_TIMER dependent on CONFIG_ACPI Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86_64/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index 0f430d9d3632..289f448ac89c 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -305,6 +305,7 @@ config HPET_TIMER config X86_PM_TIMER bool "PM timer" + depends on ACPI default y help Support the ACPI PM timer for time keeping. This is slow, From adaa765d76f58b47e10a4760f2c0bc86de5479b9 Mon Sep 17 00:00:00 2001 From: Alexander Nyberg Date: Tue, 31 May 2005 14:39:27 -0700 Subject: [PATCH 111/155] [PATCH] acpi build fix: x86 setup.c This is a neverending story linux/acpi.h contains empty declarations for acpi_boot_init() & acpi_boot_table_init() but they are nested inside #ifdef CONFIG_ACPI. So we'll have to #ifdef in arch/i386/kernel/setup.c: setup_arch() Signed-off-by: Alexander Nyberg Cc: "Brown, Len" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/i386/kernel/setup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 945ec73163c8..2bfbddebdbf8 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -1502,11 +1502,13 @@ void __init setup_arch(char **cmdline_p) if (efi_enabled) efi_map_memmap(); +#ifdef CONFIG_ACPI_BOOT /* * Parse the ACPI tables for possible boot-time SMP configuration. */ acpi_boot_table_init(); acpi_boot_init(); +#endif #ifdef CONFIG_X86_LOCAL_APIC if (smp_found_config) From 2e214953295dd33fc62d43ac7ec91997afad75bb Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Tue, 31 May 2005 14:39:28 -0700 Subject: [PATCH 112/155] [PATCH] h8300 sleep problem h8300 appears to sleep (halt) when need_resched IS set. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/h8300/kernel/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c index 134aec1c6d19..b5f83e9f04db 100644 --- a/arch/h8300/kernel/process.c +++ b/arch/h8300/kernel/process.c @@ -54,7 +54,7 @@ asmlinkage void ret_from_fork(void); void default_idle(void) { while(1) { - if (need_resched()) { + if (!need_resched()) { local_irq_enable(); __asm__("sleep"); local_irq_disable(); From f50734569c25c4e902bd3d0fb2e5bd93a200cc75 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 31 May 2005 14:39:29 -0700 Subject: [PATCH 113/155] [PATCH] ppc64: allow timer based profiling on iseries We used to have an iseries specific profiler that used /proc/profile. Now thats gone we can use the generic timer based stuff. Signed-off-by: Anton Blanchard Acked-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ppc64/kernel/time.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index 3d54745108c7..33364a7d2cd2 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c @@ -325,9 +325,7 @@ int timer_interrupt(struct pt_regs * regs) irq_enter(); -#ifndef CONFIG_PPC_ISERIES profile_tick(CPU_PROFILING, regs); -#endif lpaca->lppaca.int_dword.fields.decr_int = 0; From ae92ef8a442421356950a0a8dfdc35e8e783000e Mon Sep 17 00:00:00 2001 From: Roman Zippel Date: Tue, 31 May 2005 14:39:29 -0700 Subject: [PATCH 114/155] [PATCH] flush icache in correct context flush_icache_range() is used in two different situation - in binfmt_elf.c & co for user space mappings and module.c for kernel modules. On m68k flush_icache_range() doesn't know which data to flush, as it has separate address spaces and the pointer argument can be valid in either address space. First I considered splitting flush_icache_range(), but this patch is simpler. Setting the correct context gives flush_icache_range() enough information to flush the correct data. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/module.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/module.c b/kernel/module.c index 5734ab09d3f9..83b3d376708c 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1758,6 +1758,7 @@ sys_init_module(void __user *umod, const char __user *uargs) { struct module *mod; + mm_segment_t old_fs = get_fs(); int ret = 0; /* Must have permission */ @@ -1775,6 +1776,9 @@ sys_init_module(void __user *umod, return PTR_ERR(mod); } + /* flush the icache in correct context */ + set_fs(KERNEL_DS); + /* Flush the instruction cache, since we've played with text */ if (mod->module_init) flush_icache_range((unsigned long)mod->module_init, @@ -1783,6 +1787,8 @@ sys_init_module(void __user *umod, flush_icache_range((unsigned long)mod->module_core, (unsigned long)mod->module_core + mod->core_size); + set_fs(old_fs); + /* Now sew it into the lists. They won't access us, since strong_try_module_get() will fail. */ stop_machine_run(__link_module, mod, NR_CPUS); From 97d3a00f77fa527886d53dd943017654ce142186 Mon Sep 17 00:00:00 2001 From: Peter Chubb Date: Tue, 31 May 2005 14:39:30 -0700 Subject: [PATCH 115/155] [PATCH] pcdp.c build fix In file included from drivers/firmware/pcdp.c:18: drivers/firmware/pcdp.h:48: error: field `addr' has incomplete type drivers/firmware/pcdp.c: In function `setup_serial_console': drivers/firmware/pcdp.c:27: error: `ACPI_ADR_SPACE_SYSTEM_MEMORY' undeclared (first use in this function) Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/firmware/pcdp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c index 6d5df6c2efa2..df1b721154d2 100644 --- a/drivers/firmware/pcdp.c +++ b/drivers/firmware/pcdp.c @@ -11,6 +11,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include From e74d633dc5f56bf059f870370b2f36b021298652 Mon Sep 17 00:00:00 2001 From: Goffredo Baroncelli Date: Tue, 31 May 2005 14:39:31 -0700 Subject: [PATCH 116/155] [PATCH] UDF filesystem: array '__mon_yday' declared as not static in fs/udf/udftime.c the global array '__mon_yday' is not static, and it conflicts with the glibc one when the kernel is compiled as user mode. Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/udf/udftime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c index 457a8fe28575..85d8dbe843f1 100644 --- a/fs/udf/udftime.c +++ b/fs/udf/udftime.c @@ -46,7 +46,7 @@ #endif /* How many days come before each month (0-12). */ -const unsigned short int __mon_yday[2][13] = +static const unsigned short int __mon_yday[2][13] = { /* Normal years. */ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, From 0451eb074eef30240c6c06dacf2911bee26831e1 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 31 May 2005 15:15:58 -0700 Subject: [PATCH 117/155] [PKT_SCHED]: Fix dsmark to count ignored indices while walking Unused indices which are ignored while walking must still be counted to avoid dumping the same index twice. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/sched/sch_dsmark.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index 8a3db9d95bab..acbe9d2b3e15 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -163,14 +163,15 @@ static void dsmark_walk(struct Qdisc *sch,struct qdisc_walker *walker) return; for (i = 0; i < p->indices; i++) { if (p->mask[i] == 0xff && !p->value[i]) - continue; + goto ignore; if (walker->count >= walker->skip) { if (walker->fn(sch, i+1, walker) < 0) { walker->stop = 1; break; } } - walker->count++; +ignore: + walker->count++; } } From 486b53e59ca8cd07d91ad88375c1c884b15cc9bd Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 31 May 2005 15:16:52 -0700 Subject: [PATCH 118/155] [PKT_SCHED]: make dsmark try using pfifo instead of noop while grafting Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/sched/sch_dsmark.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index acbe9d2b3e15..a8c948f62978 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -73,8 +73,13 @@ static int dsmark_graft(struct Qdisc *sch,unsigned long arg, DPRINTK("dsmark_graft(sch %p,[qdisc %p],new %p,old %p)\n",sch,p,new, old); - if (!new) - new = &noop_qdisc; + + if (new == NULL) { + new = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops); + if (new == NULL) + new = &noop_qdisc; + } + sch_tree_lock(sch); *old = xchg(&p->q,new); if (*old) From 08e9cd1fc559c00bc05df3fc551efe3b87c57ee3 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 31 May 2005 15:17:28 -0700 Subject: [PATCH 119/155] [PKT_SCHED]: Disable dsmark debugging messages by default Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/sched/sch_dsmark.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index a8c948f62978..d8bd2a569c7c 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -18,7 +18,7 @@ #include -#if 1 /* control */ +#if 0 /* control */ #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args) #else #define DPRINTK(format,args...) From 7c963ad1d113790a8c723a178988b675868f3abe Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 31 May 2005 16:57:59 -0700 Subject: [PATCH 120/155] [SPARC64]: Fix streaming buffer flushing on PCI and SBUS. Firstly, if the direction is TODEVICE, then dirty data in the streaming cache is impossible so we can elide the flush-flag synchronization in that case. Next, the context allocator is broken. It is highly likely that contexts get used multiple times for different dma mappings, which confuses the strbuf flushing code and makes it run inefficiently. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci_iommu.c | 90 +++++++++++++++++++++++++------- arch/sparc64/kernel/pci_psycho.c | 2 +- arch/sparc64/kernel/pci_sabre.c | 2 +- arch/sparc64/kernel/pci_schizo.c | 2 +- arch/sparc64/kernel/sbus.c | 20 ++++--- include/asm-sparc64/iommu.h | 2 + include/asm-sparc64/pbm.h | 8 +-- 7 files changed, 94 insertions(+), 32 deletions(-) diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index 33ca56c90da2..1807876f8c36 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c @@ -196,6 +196,34 @@ static iopte_t *alloc_consistent_cluster(struct pci_iommu *iommu, unsigned long return NULL; } +static int iommu_alloc_ctx(struct pci_iommu *iommu) +{ + int lowest = iommu->ctx_lowest_free; + int sz = IOMMU_NUM_CTXS - lowest; + int n = find_next_zero_bit(iommu->ctx_bitmap, sz, lowest); + + if (unlikely(n == sz)) { + n = find_next_zero_bit(iommu->ctx_bitmap, lowest, 1); + if (unlikely(n == lowest)) { + printk(KERN_WARNING "IOMMU: Ran out of contexts.\n"); + n = 0; + } + } + if (n) + __set_bit(n, iommu->ctx_bitmap); + + return n; +} + +static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx) +{ + if (likely(ctx)) { + __clear_bit(ctx, iommu->ctx_bitmap); + if (ctx < iommu->ctx_lowest_free) + iommu->ctx_lowest_free = ctx; + } +} + /* Allocate and map kernel buffer of size SIZE using consistent mode * DMA for PCI device PDEV. Return non-NULL cpu-side address if * successful and set *DMA_ADDRP to the PCI side dma address. @@ -236,7 +264,7 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad npages = size >> IO_PAGE_SHIFT; ctx = 0; if (iommu->iommu_ctxflush) - ctx = iommu->iommu_cur_ctx++; + ctx = iommu_alloc_ctx(iommu); first_page = __pa(first_page); while (npages--) { iopte_val(*iopte) = (IOPTE_CONSISTENT(ctx) | @@ -317,6 +345,8 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_ } } + iommu_free_ctx(iommu, ctx); + spin_unlock_irqrestore(&iommu->lock, flags); order = get_order(size); @@ -360,7 +390,7 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direct base_paddr = __pa(oaddr & IO_PAGE_MASK); ctx = 0; if (iommu->iommu_ctxflush) - ctx = iommu->iommu_cur_ctx++; + ctx = iommu_alloc_ctx(iommu); if (strbuf->strbuf_enabled) iopte_protection = IOPTE_STREAMING(ctx); else @@ -380,39 +410,55 @@ bad: return PCI_DMA_ERROR_CODE; } -static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages) +static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction) { int limit; - PCI_STC_FLUSHFLAG_INIT(strbuf); if (strbuf->strbuf_ctxflush && iommu->iommu_ctxflush) { unsigned long matchreg, flushreg; + u64 val; flushreg = strbuf->strbuf_ctxflush; matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); - limit = 100000; + if (pci_iommu_read(matchreg) == 0) + goto do_flush_sync; + pci_iommu_write(flushreg, ctx); - for(;;) { - if (((long)pci_iommu_read(matchreg)) >= 0L) - break; - limit--; - if (!limit) - break; - udelay(1); + if ((val = pci_iommu_read(matchreg)) == 0) + goto do_flush_sync; + + val &= 0xffff; + while (val) { + if (val & 0x1) + pci_iommu_write(flushreg, ctx); + val >>= 1; } - if (!limit) + val = pci_iommu_read(matchreg); + if (unlikely(val)) { printk(KERN_WARNING "pci_strbuf_flush: ctx flush " - "timeout vaddr[%08x] ctx[%lx]\n", - vaddr, ctx); + "timeout matchreg[%lx] ctx[%lx]\n", + val, ctx); + goto do_page_flush; + } } else { unsigned long i; + do_page_flush: for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE) pci_iommu_write(strbuf->strbuf_pflush, vaddr); } +do_flush_sync: + /* If the device could not have possibly put dirty data into + * the streaming cache, no flush-flag synchronization needs + * to be performed. + */ + if (direction == PCI_DMA_TODEVICE) + return; + + PCI_STC_FLUSHFLAG_INIT(strbuf); pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); (void) pci_iommu_read(iommu->write_complete_reg); @@ -466,7 +512,7 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int /* Step 1: Kick data out of streaming buffers if necessary. */ if (strbuf->strbuf_enabled) - pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); + pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); /* Step 2: Clear out first TSB entry. */ iopte_make_dummy(iommu, base); @@ -474,6 +520,8 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, npages, ctx); + iommu_free_ctx(iommu, ctx); + spin_unlock_irqrestore(&iommu->lock, flags); } @@ -613,7 +661,7 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int /* Step 4: Choose a context if necessary. */ ctx = 0; if (iommu->iommu_ctxflush) - ctx = iommu->iommu_cur_ctx++; + ctx = iommu_alloc_ctx(iommu); /* Step 5: Create the mappings. */ if (strbuf->strbuf_enabled) @@ -678,7 +726,7 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, /* Step 1: Kick data out of streaming buffers if necessary. */ if (strbuf->strbuf_enabled) - pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); + pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); /* Step 2: Clear out first TSB entry. */ iopte_make_dummy(iommu, base); @@ -686,6 +734,8 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, npages, ctx); + iommu_free_ctx(iommu, ctx); + spin_unlock_irqrestore(&iommu->lock, flags); } @@ -724,7 +774,7 @@ void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size } /* Step 2: Kick data out of streaming buffers. */ - pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); + pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -768,7 +818,7 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, i i--; npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - bus_addr) >> IO_PAGE_SHIFT; - pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); + pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); spin_unlock_irqrestore(&iommu->lock, flags); } diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 3567fa879e1f..534320ef0db2 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -1212,7 +1212,7 @@ static void __init psycho_iommu_init(struct pci_controller_info *p) /* Setup initial software IOMMU state. */ spin_lock_init(&iommu->lock); - iommu->iommu_cur_ctx = 0; + iommu->ctx_lowest_free = 1; /* Register addresses. */ iommu->iommu_control = p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL; diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 5525d1ec4af8..53d333b4a4e8 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -1265,7 +1265,7 @@ static void __init sabre_iommu_init(struct pci_controller_info *p, /* Setup initial software IOMMU state. */ spin_lock_init(&iommu->lock); - iommu->iommu_cur_ctx = 0; + iommu->ctx_lowest_free = 1; /* Register addresses. */ iommu->iommu_control = p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL; diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index e93fcadc3722..5753175b94e6 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1753,7 +1753,7 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) /* Setup initial software IOMMU state. */ spin_lock_init(&iommu->lock); - iommu->iommu_cur_ctx = 0; + iommu->ctx_lowest_free = 1; /* Register addresses, SCHIZO has iommu ctx flushing. */ iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL; diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index 76ea6455433f..89f5e019f24c 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -117,17 +117,25 @@ static void iommu_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages #define STRBUF_TAG_VALID 0x02UL -static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages) +static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages, int direction) { unsigned long n; int limit; - iommu->strbuf_flushflag = 0UL; n = npages; while (n--) upa_writeq(base + (n << IO_PAGE_SHIFT), iommu->strbuf_regs + STRBUF_PFLUSH); + /* If the device could not have possibly put dirty data into + * the streaming cache, no flush-flag synchronization needs + * to be performed. + */ + if (direction == SBUS_DMA_TODEVICE) + return; + + iommu->strbuf_flushflag = 0UL; + /* Whoopee cushion! */ upa_writeq(__pa(&iommu->strbuf_flushflag), iommu->strbuf_regs + STRBUF_FSYNC); @@ -421,7 +429,7 @@ void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size, spin_lock_irqsave(&iommu->lock, flags); free_streaming_cluster(iommu, dma_base, size >> IO_PAGE_SHIFT); - sbus_strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT); + sbus_strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT, direction); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -584,7 +592,7 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int iommu = sdev->bus->iommu; spin_lock_irqsave(&iommu->lock, flags); free_streaming_cluster(iommu, dvma_base, size >> IO_PAGE_SHIFT); - sbus_strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT); + sbus_strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT, direction); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -596,7 +604,7 @@ void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t base, size_t size = (IO_PAGE_ALIGN(base + size) - (base & IO_PAGE_MASK)); spin_lock_irqsave(&iommu->lock, flags); - sbus_strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT); + sbus_strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT, direction); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -620,7 +628,7 @@ void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - base; spin_lock_irqsave(&iommu->lock, flags); - sbus_strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT); + sbus_strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT, direction); spin_unlock_irqrestore(&iommu->lock, flags); } diff --git a/include/asm-sparc64/iommu.h b/include/asm-sparc64/iommu.h index 5fd16e42a045..0de7a3da79cd 100644 --- a/include/asm-sparc64/iommu.h +++ b/include/asm-sparc64/iommu.h @@ -16,4 +16,6 @@ #define IOPTE_CACHE 0x0000000000000010UL /* Cached (in UPA E-cache) */ #define IOPTE_WRITE 0x0000000000000002UL /* Writeable */ +#define IOMMU_NUM_CTXS 4096 + #endif /* !(_SPARC_IOMMU_H) */ diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h index 92999631c819..4c15610a2bac 100644 --- a/include/asm-sparc64/pbm.h +++ b/include/asm-sparc64/pbm.h @@ -15,6 +15,7 @@ #include #include #include +#include /* The abstraction used here is that there are PCI controllers, * each with one (Sabre) or two (PSYCHO/SCHIZO) PCI bus modules @@ -40,9 +41,6 @@ struct pci_iommu { */ spinlock_t lock; - /* Context allocator. */ - unsigned int iommu_cur_ctx; - /* IOMMU page table, a linear array of ioptes. */ iopte_t *page_table; /* The page table itself. */ int page_table_sz_bits; /* log2 of ow many pages does it map? */ @@ -87,6 +85,10 @@ struct pci_iommu { u16 flush; } alloc_info[PBM_NCLUSTERS]; + /* CTX allocation. */ + unsigned long ctx_lowest_free; + unsigned long ctx_bitmap[IOMMU_NUM_CTXS / (sizeof(unsigned long) * 8)]; + /* Here a PCI controller driver describes the areas of * PCI memory space where DMA to/from physical memory * are addressed. Drivers interrogate the PCI layer From 36839836e8132731e0cadddce452423036a1d5b3 Mon Sep 17 00:00:00 2001 From: Edgar E Iglesias Date: Tue, 31 May 2005 17:08:05 -0700 Subject: [PATCH 121/155] [IPSEC]: Fix esp_decap_data size verification in esp4. Signed-off-by: Edgar E Iglesias Signed-off-by: David S. Miller --- net/ipv4/esp4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 053a883247ba..eae84cc39d3f 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -478,7 +478,7 @@ static int __init esp4_init(void) { struct xfrm_decap_state decap; - if (sizeof(struct esp_decap_data) < + if (sizeof(struct esp_decap_data) > sizeof(decap.decap_data)) { extern void decap_data_too_small(void); From 7eb53d88230e23f83b2e20a78955e1412fa7bb26 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:42 -0700 Subject: [PATCH 122/155] [CPUFREQ] powernow-k7: don't print khz element of FSB. Signed-off-by: Dave Jones --- arch/i386/kernel/cpu/cpufreq/powernow-k7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c index 913f652623d9..80f01b00bada 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c @@ -592,7 +592,7 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) printk(KERN_WARNING PFX "can not determine bus frequency\n"); return -EINVAL; } - dprintk("FSB: %3d.%03d MHz\n", fsb/1000, fsb%1000); + dprintk("FSB: %3dMHz\n", fsb/1000); if (dmi_check_system(powernow_dmi_table) || acpi_force) { printk (KERN_INFO PFX "PSB/PST known to be broken. Trying ACPI instead\n"); From 78ee998fd46ed4cc647ee442d2a5492f389ee27a Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:43 -0700 Subject: [PATCH 123/155] [CPUFREQ] cpufreq-core: reduce warning messages. cpufreq core is printing out messages at KERN_WARNING level that the core recovers from without intervention, and that the system administrator can do nothing about. Patch below reduces the severity of these messages to debug. Signed-off-by: Matt Domsch Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 8e561313d094..03b5fb2ddcf4 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -258,7 +258,7 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state) (likely(cpufreq_cpu_data[freqs->cpu]->cur)) && (unlikely(freqs->old != cpufreq_cpu_data[freqs->cpu]->cur))) { - printk(KERN_WARNING "Warning: CPU frequency is %u, " + dprintk(KERN_WARNING "Warning: CPU frequency is %u, " "cpufreq assumed %u kHz.\n", freqs->old, cpufreq_cpu_data[freqs->cpu]->cur); freqs->old = cpufreq_cpu_data[freqs->cpu]->cur; } @@ -814,7 +814,7 @@ static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq, unsigne { struct cpufreq_freqs freqs; - printk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing " + dprintk(KERN_WARNING "Warning: CPU frequency out of sync: cpufreq and timing " "core thinks of %u, is %u kHz.\n", old_freq, new_freq); freqs.cpu = cpu; @@ -923,7 +923,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, u32 state) struct cpufreq_freqs freqs; if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN)) - printk(KERN_DEBUG "Warning: CPU frequency is %u, " + dprintk(KERN_DEBUG "Warning: CPU frequency is %u, " "cpufreq assumed %u kHz.\n", cur_freq, cpu_policy->cur); @@ -1004,7 +1004,7 @@ static int cpufreq_resume(struct sys_device * sysdev) struct cpufreq_freqs freqs; if (!(cpufreq_driver->flags & CPUFREQ_PM_NO_WARN)) - printk(KERN_WARNING "Warning: CPU frequency" + dprintk(KERN_WARNING "Warning: CPU frequency" "is %u, cpufreq assumed %u kHz.\n", cur_freq, cpu_policy->cur); From 8282864a96ef0a7b88ee9e4b357e08504131394d Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:43 -0700 Subject: [PATCH 124/155] [CPUFREQ] speedstep-centrino: Pentium 4 - M (HT) support The Pentium 4 - Ms (HT) with CPUID 0xF34 and 0xF41 seem to support centrino-like enhanced speedstep; however, no "table" support is possible. Therefore, put NULL entries into speedstep-centrino.c Signed-off-by: Dominik Brodowski Signed-off-by: Dave Jones --- arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c index 07d5612dc00f..7dcbf70fc16f 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c @@ -54,6 +54,8 @@ enum { CPU_DOTHAN_A1, CPU_DOTHAN_A2, CPU_DOTHAN_B0, + CPU_MP4HT_D0, + CPU_MP4HT_E0, }; static const struct cpu_id cpu_ids[] = { @@ -61,6 +63,8 @@ static const struct cpu_id cpu_ids[] = { [CPU_DOTHAN_A1] = { 6, 13, 1 }, [CPU_DOTHAN_A2] = { 6, 13, 2 }, [CPU_DOTHAN_B0] = { 6, 13, 6 }, + [CPU_MP4HT_D0] = {15, 3, 4 }, + [CPU_MP4HT_E0] = {15, 4, 1 }, }; #define N_IDS (sizeof(cpu_ids)/sizeof(cpu_ids[0])) @@ -226,6 +230,8 @@ static struct cpu_model models[] = { &cpu_ids[CPU_DOTHAN_A1], NULL, 0, NULL }, { &cpu_ids[CPU_DOTHAN_A2], NULL, 0, NULL }, { &cpu_ids[CPU_DOTHAN_B0], NULL, 0, NULL }, + { &cpu_ids[CPU_MP4HT_D0], NULL, 0, NULL }, + { &cpu_ids[CPU_MP4HT_E0], NULL, 0, NULL }, { NULL, } }; From 6fe711658fcf92d39d84c0b7e6332ed6625dc520 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:44 -0700 Subject: [PATCH 125/155] [CPUFREQ] ondemand: trivial clean-ups Trivial ondemand governor clean-ups: - change from sampling_rate_in_HZ() to the official function usecs_to_jiffies(). - use for_each_online_cpu() to instead of using "if (cpu_online(i))" Signed-off-by: Eric Piel Signed-off-by: Venkatesh Pallipadi Signed-off-by: Dominik Brodowski Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq_ondemand.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 8d83a21c6477..0bc0bff55d26 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -57,7 +57,6 @@ static unsigned int def_sampling_rate; #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) #define DEF_SAMPLING_DOWN_FACTOR (10) #define TRANSITION_LATENCY_LIMIT (10 * 1000) -#define sampling_rate_in_HZ(x) (((x * HZ) < (1000 * 1000))?1:((x * HZ) / (1000 * 1000))) static void do_dbs_timer(void *data); @@ -281,7 +280,7 @@ static void dbs_check_cpu(int cpu) /* Scale idle ticks by 100 and compare with up and down ticks */ idle_ticks *= 100; up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) * - sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate); + usecs_to_jiffies(dbs_tuners_ins.sampling_rate); if (idle_ticks < up_idle_ticks) { __cpufreq_driver_target(policy, policy->max, @@ -328,7 +327,7 @@ static void dbs_check_cpu(int cpu) freq_down_sampling_rate = dbs_tuners_ins.sampling_rate * dbs_tuners_ins.sampling_down_factor; down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) * - sampling_rate_in_HZ(freq_down_sampling_rate); + usecs_to_jiffies(freq_down_sampling_rate); if (idle_ticks > down_idle_ticks ) { freq_down_step = (5 * policy->max) / 100; @@ -348,11 +347,10 @@ static void do_dbs_timer(void *data) { int i; down(&dbs_sem); - for (i = 0; i < NR_CPUS; i++) - if (cpu_online(i)) - dbs_check_cpu(i); + for_each_online_cpu(i) + dbs_check_cpu(i); schedule_delayed_work(&dbs_work, - sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate)); + usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); up(&dbs_sem); } @@ -360,7 +358,7 @@ static inline void dbs_timer_init(void) { INIT_WORK(&dbs_work, do_dbs_timer, NULL); schedule_delayed_work(&dbs_work, - sampling_rate_in_HZ(dbs_tuners_ins.sampling_rate)); + usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); return; } From 6f4095af6df7aa365ecf18473c8b05c5f6c38a78 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:44 -0700 Subject: [PATCH 126/155] [CPUFREQ] speedstep-smi: it works on at least one P4M The speedstep-smi driver actually works on >=1 notebook with a Pentium 4-M CPU where all other cpufreq drivers fail. Therefore, allow speedstep-smi on P4Ms again, but warn users of likely failure Signed-off-by: Dominik Brodowski Signed-off-by: Dave Jones --- arch/i386/kernel/cpu/cpufreq/speedstep-smi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c index 79440b3f087e..b25fb6b635ae 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-smi.c @@ -357,6 +357,9 @@ static int __init speedstep_init(void) case SPEEDSTEP_PROCESSOR_PIII_C: case SPEEDSTEP_PROCESSOR_PIII_C_EARLY: break; + case SPEEDSTEP_PROCESSOR_P4M: + printk(KERN_INFO "speedstep-smi: you're trying to use this cpufreq driver on a Pentium 4-based CPU. Most likely it will not work.\n"); + break; default: speedstep_processor = 0; } From 3310010818aa12145905faf97ffe3742acc842e2 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:44 -0700 Subject: [PATCH 127/155] [CPUFREQ] Add warning comment about default governors. This comes up time and time again. Until its fixed, place this comment in the Kconfig which should stem the flow of resubmissions. Signed-off-by: Rob Weryk Signed-off-by: Dave Jones --- drivers/cpufreq/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 95882bb1950e..3617e15567cb 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -46,6 +46,10 @@ config CPU_FREQ_STAT_DETAILS This will show detail CPU frequency translation table in sysfs file system +# Note that it is not currently possible to set the other governors (such as ondemand) +# as the default, since if they fail to initialise, cpufreq will be +# left in an undefined state. + choice prompt "Default CPUFreq governor" default CPU_FREQ_DEFAULT_GOV_USERSPACE if CPU_FREQ_SA1100 || CPU_FREQ_SA1110 From bf6fc9fd2d848d06b8f6c4caccef1dba9ef8c4c6 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:45 -0700 Subject: [PATCH 128/155] [CPUFREQ] AMD Elan SC520 cpufreq driver. From: Sean Young Signed-off-by: Dave Jones --- arch/i386/kernel/cpu/cpufreq/Kconfig | 14 +- arch/i386/kernel/cpu/cpufreq/Makefile | 1 + arch/i386/kernel/cpu/cpufreq/sc520_freq.c | 186 ++++++++++++++++++++++ 3 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 arch/i386/kernel/cpu/cpufreq/sc520_freq.c diff --git a/arch/i386/kernel/cpu/cpufreq/Kconfig b/arch/i386/kernel/cpu/cpufreq/Kconfig index f25ffd74235c..0f1eb507233b 100644 --- a/arch/i386/kernel/cpu/cpufreq/Kconfig +++ b/arch/i386/kernel/cpu/cpufreq/Kconfig @@ -23,7 +23,7 @@ config X86_ACPI_CPUFREQ If in doubt, say N. config ELAN_CPUFREQ - tristate "AMD Elan" + tristate "AMD Elan SC400 and SC410" select CPU_FREQ_TABLE depends on X86_ELAN ---help--- @@ -38,6 +38,18 @@ config ELAN_CPUFREQ If in doubt, say N. +config SC520_CPUFREQ + tristate "AMD Elan SC520" + select CPU_FREQ_TABLE + depends on X86_ELAN + ---help--- + This adds the CPUFreq driver for AMD Elan SC520 processor. + + For details, take a look at . + + If in doubt, say N. + + config X86_POWERNOW_K6 tristate "AMD Mobile K6-2/K6-3 PowerNow!" select CPU_FREQ_TABLE diff --git a/arch/i386/kernel/cpu/cpufreq/Makefile b/arch/i386/kernel/cpu/cpufreq/Makefile index a922e97aeedd..2e894f1c8910 100644 --- a/arch/i386/kernel/cpu/cpufreq/Makefile +++ b/arch/i386/kernel/cpu/cpufreq/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_X86_POWERNOW_K7) += powernow-k7.o obj-$(CONFIG_X86_POWERNOW_K8) += powernow-k8.o obj-$(CONFIG_X86_LONGHAUL) += longhaul.o obj-$(CONFIG_ELAN_CPUFREQ) += elanfreq.o +obj-$(CONFIG_SC520_CPUFREQ) += sc520_freq.o obj-$(CONFIG_X86_LONGRUN) += longrun.o obj-$(CONFIG_X86_GX_SUSPMOD) += gx-suspmod.o obj-$(CONFIG_X86_SPEEDSTEP_ICH) += speedstep-ich.o diff --git a/arch/i386/kernel/cpu/cpufreq/sc520_freq.c b/arch/i386/kernel/cpu/cpufreq/sc520_freq.c new file mode 100644 index 000000000000..ef457d50f4ac --- /dev/null +++ b/arch/i386/kernel/cpu/cpufreq/sc520_freq.c @@ -0,0 +1,186 @@ +/* + * sc520_freq.c: cpufreq driver for the AMD Elan sc520 + * + * Copyright (C) 2005 Sean Young + * + * 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. + * + * Based on elanfreq.c + * + * 2005-03-30: - initial revision + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#define MMCR_BASE 0xfffef000 /* The default base address */ +#define OFFS_CPUCTL 0x2 /* CPU Control Register */ + +static __u8 __iomem *cpuctl; + +#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "sc520_freq", msg) + +static struct cpufreq_frequency_table sc520_freq_table[] = { + {0x01, 100000}, + {0x02, 133000}, + {0, CPUFREQ_TABLE_END}, +}; + +static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu) +{ + u8 clockspeed_reg = *cpuctl; + + switch (clockspeed_reg & 0x03) { + default: + printk(KERN_ERR "sc520_freq: error: cpuctl register has unexpected value %02x\n", clockspeed_reg); + case 0x01: + return 100000; + case 0x02: + return 133000; + } +} + +static void sc520_freq_set_cpu_state (unsigned int state) +{ + + struct cpufreq_freqs freqs; + u8 clockspeed_reg; + + freqs.old = sc520_freq_get_cpu_frequency(0); + freqs.new = sc520_freq_table[state].frequency; + freqs.cpu = 0; /* AMD Elan is UP */ + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + + dprintk("attempting to set frequency to %i kHz\n", + sc520_freq_table[state].frequency); + + local_irq_disable(); + + clockspeed_reg = *cpuctl & ~0x03; + *cpuctl = clockspeed_reg | sc520_freq_table[state].index; + + local_irq_enable(); + + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); +}; + +static int sc520_freq_verify (struct cpufreq_policy *policy) +{ + return cpufreq_frequency_table_verify(policy, &sc520_freq_table[0]); +} + +static int sc520_freq_target (struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + unsigned int newstate = 0; + + if (cpufreq_frequency_table_target(policy, sc520_freq_table, target_freq, relation, &newstate)) + return -EINVAL; + + sc520_freq_set_cpu_state(newstate); + + return 0; +} + + +/* + * Module init and exit code + */ + +static int sc520_freq_cpu_init(struct cpufreq_policy *policy) +{ + struct cpuinfo_x86 *c = cpu_data; + int result; + + /* capability check */ + if (c->x86_vendor != X86_VENDOR_AMD || + c->x86 != 4 || c->x86_model != 9) + return -ENODEV; + + /* cpuinfo and default policy values */ + policy->governor = CPUFREQ_DEFAULT_GOVERNOR; + policy->cpuinfo.transition_latency = 1000000; /* 1ms */ + policy->cur = sc520_freq_get_cpu_frequency(0); + + result = cpufreq_frequency_table_cpuinfo(policy, sc520_freq_table); + if (result) + return (result); + + cpufreq_frequency_table_get_attr(sc520_freq_table, policy->cpu); + + return 0; +} + + +static int sc520_freq_cpu_exit(struct cpufreq_policy *policy) +{ + cpufreq_frequency_table_put_attr(policy->cpu); + return 0; +} + + +static struct freq_attr* sc520_freq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + + +static struct cpufreq_driver sc520_freq_driver = { + .get = sc520_freq_get_cpu_frequency, + .verify = sc520_freq_verify, + .target = sc520_freq_target, + .init = sc520_freq_cpu_init, + .exit = sc520_freq_cpu_exit, + .name = "sc520_freq", + .owner = THIS_MODULE, + .attr = sc520_freq_attr, +}; + + +static int __init sc520_freq_init(void) +{ + struct cpuinfo_x86 *c = cpu_data; + + /* Test if we have the right hardware */ + if(c->x86_vendor != X86_VENDOR_AMD || + c->x86 != 4 || c->x86_model != 9) { + dprintk("no Elan SC520 processor found!\n"); + return -ENODEV; + } + cpuctl = ioremap((unsigned long)(MMCR_BASE + OFFS_CPUCTL), 1); + if(!cpuctl) { + printk(KERN_ERR "sc520_freq: error: failed to remap memory\n"); + return -ENOMEM; + } + + return cpufreq_register_driver(&sc520_freq_driver); +} + + +static void __exit sc520_freq_exit(void) +{ + cpufreq_unregister_driver(&sc520_freq_driver); + iounmap(cpuctl); +} + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sean Young "); +MODULE_DESCRIPTION("cpufreq driver for AMD's Elan sc520 CPU"); + +module_init(sc520_freq_init); +module_exit(sc520_freq_exit); + From 91350ed49bf3613e243c2e216228cd4ae8f32516 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:45 -0700 Subject: [PATCH 129/155] [CPUFREQ] Recalibrate cpu_khz [1/2] We have to recalibrate cpu_khz in order to use the current FID instead the max FID since some BIOS do not put the processor at maximum frequency at POST. Also, some BIOS will change the processor frequency at our back after cpu_khz was calibrate. Finally, this will fix a long standing bug when we do something like this: # rmmod powernow-k7 # modprobe powernow-k7 Signed-off-by: Bruno Ducrot Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- arch/i386/kernel/cpu/cpufreq/powernow-k7.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c index 80f01b00bada..5c530064eb74 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -586,8 +587,12 @@ static int __init powernow_cpu_init (struct cpufreq_policy *policy) rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); - /* A K7 with powernow technology is set to max frequency by BIOS */ - fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.MFID]; + /* recalibrate cpu_khz */ + result = recalibrate_cpu_khz(); + if (result) + return result; + + fsb = (10 * cpu_khz) / fid_codes[fidvidstatus.bits.CFID]; if (!fsb) { printk(KERN_WARNING PFX "can not determine bus frequency\n"); return -EINVAL; From c5d28fb297efaa97c4b90e36f9dff3066e7f2778 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:46 -0700 Subject: [PATCH 130/155] [CPUFREQ] Recalibrate cpu_khz [2/2] Some cpufreq drivers (at that time, only powernow-k7) need to recalibrate the cpu_khz at runtime. Signed-off-by: Bruno Ducrot Signed-off-by: Andrew Morton Signed-off-by: Dave Jones --- arch/i386/kernel/timers/common.c | 6 ++++-- arch/i386/kernel/timers/timer_tsc.c | 20 ++++++++++++++++++++ include/asm-i386/timer.h | 1 + 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/arch/i386/kernel/timers/common.c b/arch/i386/kernel/timers/common.c index f7f90005e22e..8e201219f525 100644 --- a/arch/i386/kernel/timers/common.c +++ b/arch/i386/kernel/timers/common.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -24,7 +25,7 @@ #define CALIBRATE_TIME (5 * 1000020/HZ) -unsigned long __init calibrate_tsc(void) +unsigned long calibrate_tsc(void) { mach_prepare_counter(); @@ -139,7 +140,7 @@ bad_calibration: #endif /* calculate cpu_khz */ -void __init init_cpu_khz(void) +void init_cpu_khz(void) { if (cpu_has_tsc) { unsigned long tsc_quotient = calibrate_tsc(); @@ -158,3 +159,4 @@ void __init init_cpu_khz(void) } } } + diff --git a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c index 7926d967be00..180444d87824 100644 --- a/arch/i386/kernel/timers/timer_tsc.c +++ b/arch/i386/kernel/timers/timer_tsc.c @@ -320,6 +320,26 @@ core_initcall(cpufreq_tsc); static inline void cpufreq_delayed_get(void) { return; } #endif +int recalibrate_cpu_khz(void) +{ +#ifndef CONFIG_SMP + unsigned long cpu_khz_old = cpu_khz; + + if (cpu_has_tsc) { + init_cpu_khz(); + cpu_data[0].loops_per_jiffy = + cpufreq_scale(cpu_data[0].loops_per_jiffy, + cpu_khz_old, + cpu_khz); + return 0; + } else + return -ENODEV; +#else + return -ENODEV; +#endif +} +EXPORT_SYMBOL(recalibrate_cpu_khz); + static void mark_offset_tsc(void) { unsigned long lost,delay; diff --git a/include/asm-i386/timer.h b/include/asm-i386/timer.h index 40c54f69780e..c34709849839 100644 --- a/include/asm-i386/timer.h +++ b/include/asm-i386/timer.h @@ -53,6 +53,7 @@ extern struct init_timer_opts timer_cyclone_init; extern unsigned long calibrate_tsc(void); extern void init_cpu_khz(void); +extern int recalibrate_cpu_khz(void); #ifdef CONFIG_HPET_TIMER extern struct init_timer_opts timer_hpet_init; extern unsigned long calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr); From 7f335d4ef2d50a693fad70b8fa053d0382f4a45c Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:46 -0700 Subject: [PATCH 131/155] [CPUFREQ] make cpufreq_gov_dbs static This patch makes a needlessly global and EXPORT_SYMBOL'ed struct static. Signed-off-by: Adrian Bunk Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq_ondemand.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 0bc0bff55d26..84c658822a10 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -459,12 +459,11 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, return 0; } -struct cpufreq_governor cpufreq_gov_dbs = { +static struct cpufreq_governor cpufreq_gov_dbs = { .name = "ondemand", .governor = cpufreq_governor_dbs, .owner = THIS_MODULE, }; -EXPORT_SYMBOL(cpufreq_gov_dbs); static int __init cpufreq_gov_dbs_init(void) { From 065b807ca1f5bdbeb081e3cf75ac8de9be8ac212 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:46 -0700 Subject: [PATCH 132/155] [CPUFREQ] dual-core powernow-k8 With the release of the dual-core AMD Opterons last week, it's high time that cpufreq supported them. The attached patch applies cleanly to 2.6.12-rc3 and updates powernow-k8 to support the latest Athlon 64 and Opteron processors. Update the driver to version 1.40.0 and provide support for dual-core processors. Signed-off-by: Mark Langsdorf Signed-off-by: Dave Jones --- arch/i386/kernel/cpu/cpufreq/powernow-k8.c | 113 ++++++++++++++------- arch/i386/kernel/cpu/cpufreq/powernow-k8.h | 15 +++ 2 files changed, 91 insertions(+), 37 deletions(-) diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index a65ff7e32e5d..10cc096c0ade 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -4,7 +4,7 @@ * GNU general public license version 2. See "COPYING" or * http://www.gnu.org/licenses/gpl.html * - * Support : paul.devriendt@amd.com + * Support : mark.langsdorf@amd.com * * Based on the powernow-k7.c module written by Dave Jones. * (C) 2003 Dave Jones on behalf of SuSE Labs @@ -15,12 +15,13 @@ * * Valuable input gratefully received from Dave Jones, Pavel Machek, * Dominik Brodowski, and others. + * Originally developed by Paul Devriendt. * Processor information obtained from Chapter 9 (Power and Thermal Management) * of the "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD * Opteron Processors" available for download from www.amd.com * * Tables for specific CPUs can be infrerred from - * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/30430.pdf + * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/30430.pdf */ #include @@ -30,6 +31,7 @@ #include #include #include +#include #include #include @@ -42,7 +44,7 @@ #define PFX "powernow-k8: " #define BFX PFX "BIOS error: " -#define VERSION "version 1.00.09e" +#define VERSION "version 1.40.2" #include "powernow-k8.h" /* serialize freq changes */ @@ -50,6 +52,10 @@ static DECLARE_MUTEX(fidvid_sem); static struct powernow_k8_data *powernow_data[NR_CPUS]; +#ifndef CONFIG_SMP +static cpumask_t cpu_core_map[1]; +#endif + /* Return a frequency in MHz, given an input fid */ static u32 find_freq_from_fid(u32 fid) { @@ -274,11 +280,18 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid { u32 rvosteps = data->rvo; u32 savefid = data->currfid; + u32 maxvid, lo; dprintk("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x\n", smp_processor_id(), data->currfid, data->currvid, reqvid, data->rvo); + rdmsr(MSR_FIDVID_STATUS, lo, maxvid); + maxvid = 0x1f & (maxvid >> 16); + dprintk("ph1 maxvid=0x%x\n", maxvid); + if (reqvid < maxvid) /* lower numbers are higher voltages */ + reqvid = maxvid; + while (data->currvid > reqvid) { dprintk("ph1: curr 0x%x, req vid 0x%x\n", data->currvid, reqvid); @@ -286,8 +299,8 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data, u32 reqvid return 1; } - while ((rvosteps > 0) && ((data->rvo + data->currvid) > reqvid)) { - if (data->currvid == 0) { + while ((rvosteps > 0) && ((data->rvo + data->currvid) > reqvid)) { + if (data->currvid == maxvid) { rvosteps = 0; } else { dprintk("ph1: changing vid for rvo, req 0x%x\n", @@ -671,7 +684,7 @@ static int find_psb_table(struct powernow_k8_data *data) * BIOS and Kernel Developer's Guide, which is available on * www.amd.com */ - printk(KERN_ERR PFX "BIOS error - no PSB\n"); + printk(KERN_INFO PFX "BIOS error - no PSB or ACPI _PSS objects\n"); return -ENODEV; } @@ -695,7 +708,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) struct cpufreq_frequency_table *powernow_table; if (acpi_processor_register_performance(&data->acpi_data, data->cpu)) { - dprintk("register performance failed\n"); + dprintk("register performance failed: bad ACPI data\n"); return -EIO; } @@ -746,22 +759,23 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) continue; } - if (fid < HI_FID_TABLE_BOTTOM) { - if (cntlofreq) { - /* if both entries are the same, ignore this - * one... - */ - if ((powernow_table[i].frequency != powernow_table[cntlofreq].frequency) || - (powernow_table[i].index != powernow_table[cntlofreq].index)) { - printk(KERN_ERR PFX "Too many lo freq table entries\n"); - goto err_out_mem; - } - - dprintk("double low frequency table entry, ignoring it.\n"); - powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; - continue; - } else - cntlofreq = i; + /* verify only 1 entry from the lo frequency table */ + if (fid < HI_FID_TABLE_BOTTOM) { + if (cntlofreq) { + /* if both entries are the same, ignore this + * one... + */ + if ((powernow_table[i].frequency != powernow_table[cntlofreq].frequency) || + (powernow_table[i].index != powernow_table[cntlofreq].index)) { + printk(KERN_ERR PFX "Too many lo freq table entries\n"); + goto err_out_mem; + } + + dprintk("double low frequency table entry, ignoring it.\n"); + powernow_table[i].frequency = CPUFREQ_ENTRY_INVALID; + continue; + } else + cntlofreq = i; } if (powernow_table[i].frequency != (data->acpi_data.states[i].core_frequency * 1000)) { @@ -816,7 +830,7 @@ static int transition_frequency(struct powernow_k8_data *data, unsigned int inde { u32 fid; u32 vid; - int res; + int res, i; struct cpufreq_freqs freqs; dprintk("cpu %d transition to index %u\n", smp_processor_id(), index); @@ -841,7 +855,8 @@ static int transition_frequency(struct powernow_k8_data *data, unsigned int inde } if ((fid < HI_FID_TABLE_BOTTOM) && (data->currfid < HI_FID_TABLE_BOTTOM)) { - printk("ignoring illegal change in lo freq table-%x to 0x%x\n", + printk(KERN_ERR PFX + "ignoring illegal change in lo freq table-%x to 0x%x\n", data->currfid, fid); return 1; } @@ -850,18 +865,20 @@ static int transition_frequency(struct powernow_k8_data *data, unsigned int inde smp_processor_id(), fid, vid); freqs.cpu = data->cpu; - freqs.old = find_khz_freq_from_fid(data->currfid); freqs.new = find_khz_freq_from_fid(fid); - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + for_each_cpu_mask(i, cpu_core_map[data->cpu]) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } - down(&fidvid_sem); res = transition_fid_vid(data, fid, vid); - up(&fidvid_sem); freqs.new = find_khz_freq_from_fid(data->currfid); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - + for_each_cpu_mask(i, cpu_core_map[data->cpu]) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } return res; } @@ -874,6 +891,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi u32 checkvid = data->currvid; unsigned int newstate; int ret = -EIO; + int i; /* only run on specific CPU from here on */ oldmask = current->cpus_allowed; @@ -902,22 +920,41 @@ static int powernowk8_target(struct cpufreq_policy *pol, unsigned targfreq, unsi data->currfid, data->currvid); if ((checkvid != data->currvid) || (checkfid != data->currfid)) { - printk(KERN_ERR PFX - "error - out of sync, fid 0x%x 0x%x, vid 0x%x 0x%x\n", - checkfid, data->currfid, checkvid, data->currvid); + printk(KERN_INFO PFX + "error - out of sync, fix 0x%x 0x%x, vid 0x%x 0x%x\n", + checkfid, data->currfid, checkvid, data->currvid); } if (cpufreq_frequency_table_target(pol, data->powernow_table, targfreq, relation, &newstate)) goto err_out; + down(&fidvid_sem); + + for_each_cpu_mask(i, cpu_core_map[pol->cpu]) { + /* make sure the sibling is initialized */ + if (!powernow_data[i]) { + ret = 0; + up(&fidvid_sem); + goto err_out; + } + } + powernow_k8_acpi_pst_values(data, newstate); if (transition_frequency(data, newstate)) { printk(KERN_ERR PFX "transition frequency failed\n"); ret = 1; + up(&fidvid_sem); goto err_out; } + /* Update all the fid/vids of our siblings */ + for_each_cpu_mask(i, cpu_core_map[pol->cpu]) { + powernow_data[i]->currvid = data->currvid; + powernow_data[i]->currfid = data->currfid; + } + up(&fidvid_sem); + pol->cur = find_khz_freq_from_fid(data->currfid); ret = 0; @@ -962,7 +999,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) */ if ((num_online_cpus() != 1) || (num_possible_cpus() != 1)) { - printk(KERN_INFO PFX "MP systems not supported by PSB BIOS structure\n"); + printk(KERN_ERR PFX "MP systems not supported by PSB BIOS structure\n"); kfree(data); return -ENODEV; } @@ -1003,6 +1040,7 @@ static int __init powernowk8_cpu_init(struct cpufreq_policy *pol) schedule(); pol->governor = CPUFREQ_DEFAULT_GOVERNOR; + pol->cpus = cpu_core_map[pol->cpu]; /* Take a crude guess here. * That guess was in microseconds, so multiply with 1000 */ @@ -1069,7 +1107,7 @@ static unsigned int powernowk8_get (unsigned int cpu) return 0; } preempt_disable(); - + if (query_current_values_with_pending_wait(data)) goto out; @@ -1127,9 +1165,10 @@ static void __exit powernowk8_exit(void) cpufreq_unregister_driver(&cpufreq_amd64_driver); } -MODULE_AUTHOR("Paul Devriendt "); +MODULE_AUTHOR("Paul Devriendt and Mark Langsdorf Date: Tue, 31 May 2005 19:03:47 -0700 Subject: [PATCH 133/155] [CPUFREQ] fix up comment in cpufreq.h Fix up comment in cpufreq.h stating transition latency should be passed in microseconds -- it was decided long ago to switch to nanoseconds. Signed-off-by: Dominik Brodowski Signed-off-by: Dave Jones --- include/linux/cpufreq.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index f21af067d015..927daa86c9b3 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -49,7 +49,7 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list); /* Frequency values here are CPU kHz so that hardware which doesn't run * with some frequencies can complain without having to guess what per * cent / per mille means. - * Maximum transition latency is in microseconds - if it's unknown, + * Maximum transition latency is in nanoseconds - if it's unknown, * CPUFREQ_ETERNAL shall be used. */ From b9170836d1aa4ded7cc1ac1cb8fbc7867061c98c Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:47 -0700 Subject: [PATCH 134/155] [CPUFREQ] Conservative cpufreq governer A new cpufreq module, based on the ondemand one with my additional patches just posted. This one is more suitable for battery environments where its probably more appealing to have the cpu freq gracefully increase and decrease rather than flip between the min and max freq's. N.B. Bruno Ducrot pointed out that the amd64's "do have unacceptable latency between min and max freq transition, due to the step-by-step requirements (200MHz IIRC)"; so AMD64 users would probably benefit from this too. Signed-off-by: Alexander Clouter Signed-off-by: Dave Jones --- drivers/cpufreq/Kconfig | 20 + drivers/cpufreq/Makefile | 1 + drivers/cpufreq/cpufreq_conservative.c | 613 +++++++++++++++++++++++++ 3 files changed, 634 insertions(+) create mode 100644 drivers/cpufreq/cpufreq_conservative.c diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 3617e15567cb..60c9be99c6d9 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -119,4 +119,24 @@ config CPU_FREQ_GOV_ONDEMAND If in doubt, say N. +config CPU_FREQ_GOV_CONSERVATIVE + tristate "'conservative' cpufreq governor" + depends on CPU_FREQ + help + 'conservative' - this driver is rather similar to the 'ondemand' + governor both in its source code and its purpose, the difference is + its optimisation for better suitability in a battery powered + environment. The frequency is gracefully increased and decreased + rather than jumping to 100% when speed is required. + + If you have a desktop machine then you should really be considering + the 'ondemand' governor instead, however if you are using a laptop, + PDA or even an AMD64 based computer (due to the unacceptable + step-by-step latency issues between the minimum and maximum frequency + transitions in the CPU) you will probably want to use this governor. + + For details, take a look at linux/Documentation/cpu-freq. + + If in doubt, say N. + endif # CPU_FREQ diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 67b16e5a41a7..71fc3b4173f1 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o +obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o # CPUfreq cross-arch helpers obj-$(CONFIG_CPU_FREQ_TABLE) += freq_table.o diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c new file mode 100644 index 000000000000..dd2f5b272a4d --- /dev/null +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -0,0 +1,613 @@ +/* + * drivers/cpufreq/cpufreq_conservative.c + * + * Copyright (C) 2001 Russell King + * (C) 2003 Venkatesh Pallipadi . + * Jun Nakajima + * (C) 2004 Alexander Clouter + * + * 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 + +/* + * dbs is used in this file as a shortform for demandbased switching + * It helps to keep variable names smaller, simpler + */ + +#define DEF_FREQUENCY_UP_THRESHOLD (80) +#define MIN_FREQUENCY_UP_THRESHOLD (0) +#define MAX_FREQUENCY_UP_THRESHOLD (100) + +#define DEF_FREQUENCY_DOWN_THRESHOLD (20) +#define MIN_FREQUENCY_DOWN_THRESHOLD (0) +#define MAX_FREQUENCY_DOWN_THRESHOLD (100) + +/* + * The polling frequency of this governor depends on the capability of + * the processor. Default polling frequency is 1000 times the transition + * latency of the processor. The governor will work on any processor with + * transition latency <= 10mS, using appropriate sampling + * rate. + * For CPUs with transition latency > 10mS (mostly drivers with CPUFREQ_ETERNAL) + * this governor will not work. + * All times here are in uS. + */ +static unsigned int def_sampling_rate; +#define MIN_SAMPLING_RATE (def_sampling_rate / 2) +#define MAX_SAMPLING_RATE (500 * def_sampling_rate) +#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (100000) +#define DEF_SAMPLING_DOWN_FACTOR (5) +#define TRANSITION_LATENCY_LIMIT (10 * 1000) + +static void do_dbs_timer(void *data); + +struct cpu_dbs_info_s { + struct cpufreq_policy *cur_policy; + unsigned int prev_cpu_idle_up; + unsigned int prev_cpu_idle_down; + unsigned int enable; +}; +static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info); + +static unsigned int dbs_enable; /* number of CPUs using this policy */ + +static DECLARE_MUTEX (dbs_sem); +static DECLARE_WORK (dbs_work, do_dbs_timer, NULL); + +struct dbs_tuners { + unsigned int sampling_rate; + unsigned int sampling_down_factor; + unsigned int up_threshold; + unsigned int down_threshold; + unsigned int ignore_nice; + unsigned int freq_step; +}; + +static struct dbs_tuners dbs_tuners_ins = { + .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, + .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD, + .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, +}; + +/************************** sysfs interface ************************/ +static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf) +{ + return sprintf (buf, "%u\n", MAX_SAMPLING_RATE); +} + +static ssize_t show_sampling_rate_min(struct cpufreq_policy *policy, char *buf) +{ + return sprintf (buf, "%u\n", MIN_SAMPLING_RATE); +} + +#define define_one_ro(_name) \ +static struct freq_attr _name = \ +__ATTR(_name, 0444, show_##_name, NULL) + +define_one_ro(sampling_rate_max); +define_one_ro(sampling_rate_min); + +/* cpufreq_conservative Governor Tunables */ +#define show_one(file_name, object) \ +static ssize_t show_##file_name \ +(struct cpufreq_policy *unused, char *buf) \ +{ \ + return sprintf(buf, "%u\n", dbs_tuners_ins.object); \ +} +show_one(sampling_rate, sampling_rate); +show_one(sampling_down_factor, sampling_down_factor); +show_one(up_threshold, up_threshold); +show_one(down_threshold, down_threshold); +show_one(ignore_nice, ignore_nice); +show_one(freq_step, freq_step); + +static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf (buf, "%u", &input); + if (ret != 1 ) + return -EINVAL; + + down(&dbs_sem); + dbs_tuners_ins.sampling_down_factor = input; + up(&dbs_sem); + + return count; +} + +static ssize_t store_sampling_rate(struct cpufreq_policy *unused, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf (buf, "%u", &input); + + down(&dbs_sem); + if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE) { + up(&dbs_sem); + return -EINVAL; + } + + dbs_tuners_ins.sampling_rate = input; + up(&dbs_sem); + + return count; +} + +static ssize_t store_up_threshold(struct cpufreq_policy *unused, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf (buf, "%u", &input); + + down(&dbs_sem); + if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || + input < MIN_FREQUENCY_UP_THRESHOLD || + input <= dbs_tuners_ins.down_threshold) { + up(&dbs_sem); + return -EINVAL; + } + + dbs_tuners_ins.up_threshold = input; + up(&dbs_sem); + + return count; +} + +static ssize_t store_down_threshold(struct cpufreq_policy *unused, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf (buf, "%u", &input); + + down(&dbs_sem); + if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD || + input < MIN_FREQUENCY_DOWN_THRESHOLD || + input >= dbs_tuners_ins.up_threshold) { + up(&dbs_sem); + return -EINVAL; + } + + dbs_tuners_ins.down_threshold = input; + up(&dbs_sem); + + return count; +} + +static ssize_t store_ignore_nice(struct cpufreq_policy *policy, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + unsigned int j; + + ret = sscanf (buf, "%u", &input); + if ( ret != 1 ) + return -EINVAL; + + if ( input > 1 ) + input = 1; + + down(&dbs_sem); + if ( input == dbs_tuners_ins.ignore_nice ) { /* nothing to do */ + up(&dbs_sem); + return count; + } + dbs_tuners_ins.ignore_nice = input; + + /* we need to re-evaluate prev_cpu_idle_up and prev_cpu_idle_down */ + for_each_cpu_mask(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + j_dbs_info = &per_cpu(cpu_dbs_info, j); + j_dbs_info->cur_policy = policy; + + j_dbs_info->prev_cpu_idle_up = + kstat_cpu(j).cpustat.idle + + kstat_cpu(j).cpustat.iowait + + ( !dbs_tuners_ins.ignore_nice + ? kstat_cpu(j).cpustat.nice : 0 ); + j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up; + } + up(&dbs_sem); + + return count; +} + +static ssize_t store_freq_step(struct cpufreq_policy *policy, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf (buf, "%u", &input); + + if ( ret != 1 ) + return -EINVAL; + + if ( input > 100 ) + input = 100; + + /* no need to test here if freq_step is zero as the user might actually + * want this, they would be crazy though :) */ + down(&dbs_sem); + dbs_tuners_ins.freq_step = input; + up(&dbs_sem); + + return count; +} + +#define define_one_rw(_name) \ +static struct freq_attr _name = \ +__ATTR(_name, 0644, show_##_name, store_##_name) + +define_one_rw(sampling_rate); +define_one_rw(sampling_down_factor); +define_one_rw(up_threshold); +define_one_rw(down_threshold); +define_one_rw(ignore_nice); +define_one_rw(freq_step); + +static struct attribute * dbs_attributes[] = { + &sampling_rate_max.attr, + &sampling_rate_min.attr, + &sampling_rate.attr, + &sampling_down_factor.attr, + &up_threshold.attr, + &down_threshold.attr, + &ignore_nice.attr, + &freq_step.attr, + NULL +}; + +static struct attribute_group dbs_attr_group = { + .attrs = dbs_attributes, + .name = "conservative", +}; + +/************************** sysfs end ************************/ + +static void dbs_check_cpu(int cpu) +{ + unsigned int idle_ticks, up_idle_ticks, down_idle_ticks; + unsigned int total_idle_ticks; + unsigned int freq_step; + unsigned int freq_down_sampling_rate; + static int down_skip[NR_CPUS]; + static int requested_freq[NR_CPUS]; + static unsigned short init_flag = 0; + struct cpu_dbs_info_s *this_dbs_info; + struct cpu_dbs_info_s *dbs_info; + + struct cpufreq_policy *policy; + unsigned int j; + + this_dbs_info = &per_cpu(cpu_dbs_info, cpu); + if (!this_dbs_info->enable) + return; + + policy = this_dbs_info->cur_policy; + + if ( init_flag == 0 ) { + for ( /* NULL */; init_flag < NR_CPUS; init_flag++ ) { + dbs_info = &per_cpu(cpu_dbs_info, init_flag); + requested_freq[cpu] = dbs_info->cur_policy->cur; + } + init_flag = 1; + } + + /* + * The default safe range is 20% to 80% + * Every sampling_rate, we check + * - If current idle time is less than 20%, then we try to + * increase frequency + * Every sampling_rate*sampling_down_factor, we check + * - If current idle time is more than 80%, then we try to + * decrease frequency + * + * Any frequency increase takes it to the maximum frequency. + * Frequency reduction happens at minimum steps of + * 5% (default) of max_frequency + */ + + /* Check for frequency increase */ + total_idle_ticks = kstat_cpu(cpu).cpustat.idle + + kstat_cpu(cpu).cpustat.iowait; + /* consider 'nice' tasks as 'idle' time too if required */ + if (dbs_tuners_ins.ignore_nice == 0) + total_idle_ticks += kstat_cpu(cpu).cpustat.nice; + idle_ticks = total_idle_ticks - + this_dbs_info->prev_cpu_idle_up; + this_dbs_info->prev_cpu_idle_up = total_idle_ticks; + + + for_each_cpu_mask(j, policy->cpus) { + unsigned int tmp_idle_ticks; + struct cpu_dbs_info_s *j_dbs_info; + + if (j == cpu) + continue; + + j_dbs_info = &per_cpu(cpu_dbs_info, j); + /* Check for frequency increase */ + total_idle_ticks = kstat_cpu(j).cpustat.idle + + kstat_cpu(j).cpustat.iowait; + /* consider 'nice' too? */ + if (dbs_tuners_ins.ignore_nice == 0) + total_idle_ticks += kstat_cpu(j).cpustat.nice; + tmp_idle_ticks = total_idle_ticks - + j_dbs_info->prev_cpu_idle_up; + j_dbs_info->prev_cpu_idle_up = total_idle_ticks; + + if (tmp_idle_ticks < idle_ticks) + idle_ticks = tmp_idle_ticks; + } + + /* Scale idle ticks by 100 and compare with up and down ticks */ + idle_ticks *= 100; + up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) * + usecs_to_jiffies(dbs_tuners_ins.sampling_rate); + + if (idle_ticks < up_idle_ticks) { + /* if we are already at full speed then break out early */ + if (requested_freq[cpu] == policy->max) + return; + + freq_step = (dbs_tuners_ins.freq_step * policy->max) / 100; + + /* max freq cannot be less than 100. But who knows.... */ + if (unlikely(freq_step == 0)) + freq_step = 5; + + requested_freq[cpu] += freq_step; + if (requested_freq[cpu] > policy->max) + requested_freq[cpu] = policy->max; + + __cpufreq_driver_target(policy, requested_freq[cpu], + CPUFREQ_RELATION_H); + down_skip[cpu] = 0; + this_dbs_info->prev_cpu_idle_down = total_idle_ticks; + return; + } + + /* Check for frequency decrease */ + down_skip[cpu]++; + if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor) + return; + + total_idle_ticks = kstat_cpu(cpu).cpustat.idle + + kstat_cpu(cpu).cpustat.iowait; + /* consider 'nice' too? */ + if (dbs_tuners_ins.ignore_nice == 0) + total_idle_ticks += kstat_cpu(cpu).cpustat.nice; + idle_ticks = total_idle_ticks - + this_dbs_info->prev_cpu_idle_down; + this_dbs_info->prev_cpu_idle_down = total_idle_ticks; + + for_each_cpu_mask(j, policy->cpus) { + unsigned int tmp_idle_ticks; + struct cpu_dbs_info_s *j_dbs_info; + + if (j == cpu) + continue; + + j_dbs_info = &per_cpu(cpu_dbs_info, j); + /* Check for frequency increase */ + total_idle_ticks = kstat_cpu(j).cpustat.idle + + kstat_cpu(j).cpustat.iowait; + /* consider 'nice' too? */ + if (dbs_tuners_ins.ignore_nice == 0) + total_idle_ticks += kstat_cpu(j).cpustat.nice; + tmp_idle_ticks = total_idle_ticks - + j_dbs_info->prev_cpu_idle_down; + j_dbs_info->prev_cpu_idle_down = total_idle_ticks; + + if (tmp_idle_ticks < idle_ticks) + idle_ticks = tmp_idle_ticks; + } + + /* Scale idle ticks by 100 and compare with up and down ticks */ + idle_ticks *= 100; + down_skip[cpu] = 0; + + freq_down_sampling_rate = dbs_tuners_ins.sampling_rate * + dbs_tuners_ins.sampling_down_factor; + down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) * + usecs_to_jiffies(freq_down_sampling_rate); + + if (idle_ticks > down_idle_ticks ) { + /* if we are already at the lowest speed then break out early + * or if we 'cannot' reduce the speed as the user might want + * freq_step to be zero */ + if (requested_freq[cpu] == policy->min + || dbs_tuners_ins.freq_step == 0) + return; + + freq_step = (dbs_tuners_ins.freq_step * policy->max) / 100; + + /* max freq cannot be less than 100. But who knows.... */ + if (unlikely(freq_step == 0)) + freq_step = 5; + + requested_freq[cpu] -= freq_step; + if (requested_freq[cpu] < policy->min) + requested_freq[cpu] = policy->min; + + __cpufreq_driver_target(policy, + requested_freq[cpu], + CPUFREQ_RELATION_H); + return; + } +} + +static void do_dbs_timer(void *data) +{ + int i; + down(&dbs_sem); + for_each_online_cpu(i) + dbs_check_cpu(i); + schedule_delayed_work(&dbs_work, + usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); + up(&dbs_sem); +} + +static inline void dbs_timer_init(void) +{ + INIT_WORK(&dbs_work, do_dbs_timer, NULL); + schedule_delayed_work(&dbs_work, + usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); + return; +} + +static inline void dbs_timer_exit(void) +{ + cancel_delayed_work(&dbs_work); + return; +} + +static int cpufreq_governor_dbs(struct cpufreq_policy *policy, + unsigned int event) +{ + unsigned int cpu = policy->cpu; + struct cpu_dbs_info_s *this_dbs_info; + unsigned int j; + + this_dbs_info = &per_cpu(cpu_dbs_info, cpu); + + switch (event) { + case CPUFREQ_GOV_START: + if ((!cpu_online(cpu)) || + (!policy->cur)) + return -EINVAL; + + if (policy->cpuinfo.transition_latency > + (TRANSITION_LATENCY_LIMIT * 1000)) + return -EINVAL; + if (this_dbs_info->enable) /* Already enabled */ + break; + + down(&dbs_sem); + for_each_cpu_mask(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + j_dbs_info = &per_cpu(cpu_dbs_info, j); + j_dbs_info->cur_policy = policy; + + j_dbs_info->prev_cpu_idle_up = + kstat_cpu(j).cpustat.idle + + kstat_cpu(j).cpustat.iowait + + ( !dbs_tuners_ins.ignore_nice + ? kstat_cpu(j).cpustat.nice : 0 ); + j_dbs_info->prev_cpu_idle_down + = j_dbs_info->prev_cpu_idle_up; + } + this_dbs_info->enable = 1; + sysfs_create_group(&policy->kobj, &dbs_attr_group); + dbs_enable++; + /* + * Start the timerschedule work, when this governor + * is used for first time + */ + if (dbs_enable == 1) { + unsigned int latency; + /* policy latency is in nS. Convert it to uS first */ + + latency = policy->cpuinfo.transition_latency; + if (latency < 1000) + latency = 1000; + + def_sampling_rate = (latency / 1000) * + DEF_SAMPLING_RATE_LATENCY_MULTIPLIER; + dbs_tuners_ins.sampling_rate = def_sampling_rate; + dbs_tuners_ins.ignore_nice = 0; + dbs_tuners_ins.freq_step = 5; + + dbs_timer_init(); + } + + up(&dbs_sem); + break; + + case CPUFREQ_GOV_STOP: + down(&dbs_sem); + this_dbs_info->enable = 0; + sysfs_remove_group(&policy->kobj, &dbs_attr_group); + dbs_enable--; + /* + * Stop the timerschedule work, when this governor + * is used for first time + */ + if (dbs_enable == 0) + dbs_timer_exit(); + + up(&dbs_sem); + + break; + + case CPUFREQ_GOV_LIMITS: + down(&dbs_sem); + if (policy->max < this_dbs_info->cur_policy->cur) + __cpufreq_driver_target( + this_dbs_info->cur_policy, + policy->max, CPUFREQ_RELATION_H); + else if (policy->min > this_dbs_info->cur_policy->cur) + __cpufreq_driver_target( + this_dbs_info->cur_policy, + policy->min, CPUFREQ_RELATION_L); + up(&dbs_sem); + break; + } + return 0; +} + +static struct cpufreq_governor cpufreq_gov_dbs = { + .name = "conservative", + .governor = cpufreq_governor_dbs, + .owner = THIS_MODULE, +}; + +static int __init cpufreq_gov_dbs_init(void) +{ + return cpufreq_register_governor(&cpufreq_gov_dbs); +} + +static void __exit cpufreq_gov_dbs_exit(void) +{ + /* Make sure that the scheduled work is indeed not running */ + flush_scheduled_work(); + + cpufreq_unregister_governor(&cpufreq_gov_dbs); +} + + +MODULE_AUTHOR ("Alexander Clouter "); +MODULE_DESCRIPTION ("'cpufreq_conservative' - A dynamic cpufreq governor for " + "Low Latency Frequency Transition capable processors " + "optimised for use in a battery environment"); +MODULE_LICENSE ("GPL"); + +module_init(cpufreq_gov_dbs_init); +module_exit(cpufreq_gov_dbs_exit); From 3d5ee9e55d13de28d2fa58d6e13f2e4d3a5f8b1a Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:47 -0700 Subject: [PATCH 135/155] [CPUFREQ] Add support to cpufreq_ondemand to ignore 'nice' cpu time Signed-off-by: Alexander Clouter Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq_ondemand.c | 66 ++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 84c658822a10..7d7244314ac9 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -78,6 +78,7 @@ struct dbs_tuners { unsigned int sampling_down_factor; unsigned int up_threshold; unsigned int down_threshold; + unsigned int ignore_nice; }; static struct dbs_tuners dbs_tuners_ins = { @@ -115,6 +116,7 @@ show_one(sampling_rate, sampling_rate); show_one(sampling_down_factor, sampling_down_factor); show_one(up_threshold, up_threshold); show_one(down_threshold, down_threshold); +show_one(ignore_nice, ignore_nice); static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused, const char *buf, size_t count) @@ -193,6 +195,46 @@ static ssize_t store_down_threshold(struct cpufreq_policy *unused, return count; } +static ssize_t store_ignore_nice(struct cpufreq_policy *policy, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + unsigned int j; + + ret = sscanf (buf, "%u", &input); + if ( ret != 1 ) + return -EINVAL; + + if ( input > 1 ) + input = 1; + + down(&dbs_sem); + if ( input == dbs_tuners_ins.ignore_nice ) { /* nothing to do */ + up(&dbs_sem); + return count; + } + dbs_tuners_ins.ignore_nice = input; + + /* we need to re-evaluate prev_cpu_idle_up and prev_cpu_idle_down */ + for_each_cpu_mask(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + j_dbs_info = &per_cpu(cpu_dbs_info, j); + j_dbs_info->cur_policy = policy; + + j_dbs_info->prev_cpu_idle_up = + kstat_cpu(j).cpustat.idle + + kstat_cpu(j).cpustat.iowait + + ( !dbs_tuners_ins.ignore_nice + ? kstat_cpu(j).cpustat.nice : 0 ); + j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up; + } + up(&dbs_sem); + + return count; +} + #define define_one_rw(_name) \ static struct freq_attr _name = \ __ATTR(_name, 0644, show_##_name, store_##_name) @@ -201,6 +243,7 @@ define_one_rw(sampling_rate); define_one_rw(sampling_down_factor); define_one_rw(up_threshold); define_one_rw(down_threshold); +define_one_rw(ignore_nice); static struct attribute * dbs_attributes[] = { &sampling_rate_max.attr, @@ -209,6 +252,7 @@ static struct attribute * dbs_attributes[] = { &sampling_down_factor.attr, &up_threshold.attr, &down_threshold.attr, + &ignore_nice.attr, NULL }; @@ -253,6 +297,9 @@ static void dbs_check_cpu(int cpu) /* Check for frequency increase */ total_idle_ticks = kstat_cpu(cpu).cpustat.idle + kstat_cpu(cpu).cpustat.iowait; + /* consider 'nice' tasks as 'idle' time too if required */ + if (dbs_tuners_ins.ignore_nice == 0) + total_idle_ticks += kstat_cpu(cpu).cpustat.nice; idle_ticks = total_idle_ticks - this_dbs_info->prev_cpu_idle_up; this_dbs_info->prev_cpu_idle_up = total_idle_ticks; @@ -269,6 +316,9 @@ static void dbs_check_cpu(int cpu) /* Check for frequency increase */ total_idle_ticks = kstat_cpu(j).cpustat.idle + kstat_cpu(j).cpustat.iowait; + /* consider 'nice' too? */ + if (dbs_tuners_ins.ignore_nice == 0) + total_idle_ticks += kstat_cpu(j).cpustat.nice; tmp_idle_ticks = total_idle_ticks - j_dbs_info->prev_cpu_idle_up; j_dbs_info->prev_cpu_idle_up = total_idle_ticks; @@ -297,6 +347,9 @@ static void dbs_check_cpu(int cpu) total_idle_ticks = kstat_cpu(cpu).cpustat.idle + kstat_cpu(cpu).cpustat.iowait; + /* consider 'nice' too? */ + if (dbs_tuners_ins.ignore_nice == 0) + total_idle_ticks += kstat_cpu(cpu).cpustat.nice; idle_ticks = total_idle_ticks - this_dbs_info->prev_cpu_idle_down; this_dbs_info->prev_cpu_idle_down = total_idle_ticks; @@ -312,6 +365,9 @@ static void dbs_check_cpu(int cpu) /* Check for frequency increase */ total_idle_ticks = kstat_cpu(j).cpustat.idle + kstat_cpu(j).cpustat.iowait; + /* consider 'nice' too? */ + if (dbs_tuners_ins.ignore_nice == 0) + total_idle_ticks += kstat_cpu(j).cpustat.nice; tmp_idle_ticks = total_idle_ticks - j_dbs_info->prev_cpu_idle_down; j_dbs_info->prev_cpu_idle_down = total_idle_ticks; @@ -397,10 +453,11 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, j_dbs_info->prev_cpu_idle_up = kstat_cpu(j).cpustat.idle + - kstat_cpu(j).cpustat.iowait; - j_dbs_info->prev_cpu_idle_down = - kstat_cpu(j).cpustat.idle + - kstat_cpu(j).cpustat.iowait; + kstat_cpu(j).cpustat.iowait + + ( !dbs_tuners_ins.ignore_nice + ? kstat_cpu(j).cpustat.nice : 0 ); + j_dbs_info->prev_cpu_idle_down + = j_dbs_info->prev_cpu_idle_up; } this_dbs_info->enable = 1; sysfs_create_group(&policy->kobj, &dbs_attr_group); @@ -420,6 +477,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, def_sampling_rate = (latency / 1000) * DEF_SAMPLING_RATE_LATENCY_MULTIPLIER; dbs_tuners_ins.sampling_rate = def_sampling_rate; + dbs_tuners_ins.ignore_nice = 0; dbs_timer_init(); } From c11420a616039e2181e4ecbffb4d125d39e6877d Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:48 -0700 Subject: [PATCH 136/155] [CPUFREQ] Prevents un-necessary cpufreq changes if we are already at min/max Signed-off-by: Alexander Clouter Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq_ondemand.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 7d7244314ac9..6dc83808e590 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -333,6 +333,10 @@ static void dbs_check_cpu(int cpu) usecs_to_jiffies(dbs_tuners_ins.sampling_rate); if (idle_ticks < up_idle_ticks) { + /* if we are already at full speed then break out early */ + if (policy->cur == policy->max) + return; + __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); down_skip[cpu] = 0; @@ -386,6 +390,10 @@ static void dbs_check_cpu(int cpu) usecs_to_jiffies(freq_down_sampling_rate); if (idle_ticks > down_idle_ticks ) { + /* if we are already at the lowest speed then break out early */ + if (policy->cur == policy->min) + return; + freq_down_step = (5 * policy->max) / 100; /* max freq cannot be less than 100. But who knows.... */ From 1206aaac285904e3e3995eecbf4129b6555a8973 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:48 -0700 Subject: [PATCH 137/155] [CPUFREQ] Allow ondemand stepping to be changed by user. Adds support so that the cpufreq change stepping is no longer fixed at 5% and can be changed dynamically by the user Signed-off-by: Alexander Clouter Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq_ondemand.c | 42 +++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 6dc83808e590..056591612467 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -79,6 +79,7 @@ struct dbs_tuners { unsigned int up_threshold; unsigned int down_threshold; unsigned int ignore_nice; + unsigned int freq_step; }; static struct dbs_tuners dbs_tuners_ins = { @@ -117,6 +118,7 @@ show_one(sampling_down_factor, sampling_down_factor); show_one(up_threshold, up_threshold); show_one(down_threshold, down_threshold); show_one(ignore_nice, ignore_nice); +show_one(freq_step, freq_step); static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused, const char *buf, size_t count) @@ -235,6 +237,29 @@ static ssize_t store_ignore_nice(struct cpufreq_policy *policy, return count; } +static ssize_t store_freq_step(struct cpufreq_policy *policy, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + + ret = sscanf (buf, "%u", &input); + + if ( ret != 1 ) + return -EINVAL; + + if ( input > 100 ) + input = 100; + + /* no need to test here if freq_step is zero as the user might actually + * want this, they would be crazy though :) */ + down(&dbs_sem); + dbs_tuners_ins.freq_step = input; + up(&dbs_sem); + + return count; +} + #define define_one_rw(_name) \ static struct freq_attr _name = \ __ATTR(_name, 0644, show_##_name, store_##_name) @@ -244,6 +269,7 @@ define_one_rw(sampling_down_factor); define_one_rw(up_threshold); define_one_rw(down_threshold); define_one_rw(ignore_nice); +define_one_rw(freq_step); static struct attribute * dbs_attributes[] = { &sampling_rate_max.attr, @@ -253,6 +279,7 @@ static struct attribute * dbs_attributes[] = { &up_threshold.attr, &down_threshold.attr, &ignore_nice.attr, + &freq_step.attr, NULL }; @@ -291,7 +318,7 @@ static void dbs_check_cpu(int cpu) * * Any frequency increase takes it to the maximum frequency. * Frequency reduction happens at minimum steps of - * 5% of max_frequency + * 5% (default) of max_frequency */ /* Check for frequency increase */ @@ -390,18 +417,20 @@ static void dbs_check_cpu(int cpu) usecs_to_jiffies(freq_down_sampling_rate); if (idle_ticks > down_idle_ticks ) { - /* if we are already at the lowest speed then break out early */ - if (policy->cur == policy->min) + /* if we are already at the lowest speed then break out early + * or if we 'cannot' reduce the speed as the user might want + * freq_step to be zero */ + if (policy->cur == policy->min || dbs_tuners_ins.freq_step == 0) return; - - freq_down_step = (5 * policy->max) / 100; + + freq_down_step = (dbs_tuners_ins.freq_step * policy->max) / 100; /* max freq cannot be less than 100. But who knows.... */ if (unlikely(freq_down_step == 0)) freq_down_step = 5; __cpufreq_driver_target(policy, - policy->cur - freq_down_step, + policy->cur - freq_down_step, CPUFREQ_RELATION_H); return; } @@ -486,6 +515,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, DEF_SAMPLING_RATE_LATENCY_MULTIPLIER; dbs_tuners_ins.sampling_rate = def_sampling_rate; dbs_tuners_ins.ignore_nice = 0; + dbs_tuners_ins.freq_step = 5; dbs_timer_init(); } From dac1c1a56279b4545a822ec7bc770003c233e546 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:49 -0700 Subject: [PATCH 138/155] [CPUFREQ] ondemand,conservative minor bug-fix and cleanup [PATCH] [1/5] ondemand,conservative minor bug-fix and cleanup Attached patch fixes some minor issues with Alexander's patch and related cleanup in both ondemand and conservative governor. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq_conservative.c | 53 ++++++++--------------- drivers/cpufreq/cpufreq_ondemand.c | 58 +++++++++----------------- 2 files changed, 38 insertions(+), 73 deletions(-) diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index dd2f5b272a4d..3082a3fa5ec4 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -89,6 +89,15 @@ static struct dbs_tuners dbs_tuners_ins = { .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, }; +static inline unsigned int get_cpu_idle_time(unsigned int cpu) +{ + return kstat_cpu(cpu).cpustat.idle + + kstat_cpu(cpu).cpustat.iowait + + ( !dbs_tuners_ins.ignore_nice ? + kstat_cpu(cpu).cpustat.nice : + 0); +} + /************************** sysfs interface ************************/ static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf) { @@ -221,16 +230,10 @@ static ssize_t store_ignore_nice(struct cpufreq_policy *policy, dbs_tuners_ins.ignore_nice = input; /* we need to re-evaluate prev_cpu_idle_up and prev_cpu_idle_down */ - for_each_cpu_mask(j, policy->cpus) { + for_each_online_cpu(j) { struct cpu_dbs_info_s *j_dbs_info; j_dbs_info = &per_cpu(cpu_dbs_info, j); - j_dbs_info->cur_policy = policy; - - j_dbs_info->prev_cpu_idle_up = - kstat_cpu(j).cpustat.idle + - kstat_cpu(j).cpustat.iowait + - ( !dbs_tuners_ins.ignore_nice - ? kstat_cpu(j).cpustat.nice : 0 ); + j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j); j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up; } up(&dbs_sem); @@ -335,11 +338,7 @@ static void dbs_check_cpu(int cpu) */ /* Check for frequency increase */ - total_idle_ticks = kstat_cpu(cpu).cpustat.idle + - kstat_cpu(cpu).cpustat.iowait; - /* consider 'nice' tasks as 'idle' time too if required */ - if (dbs_tuners_ins.ignore_nice == 0) - total_idle_ticks += kstat_cpu(cpu).cpustat.nice; + total_idle_ticks = get_cpu_idle_time(cpu); idle_ticks = total_idle_ticks - this_dbs_info->prev_cpu_idle_up; this_dbs_info->prev_cpu_idle_up = total_idle_ticks; @@ -354,11 +353,7 @@ static void dbs_check_cpu(int cpu) j_dbs_info = &per_cpu(cpu_dbs_info, j); /* Check for frequency increase */ - total_idle_ticks = kstat_cpu(j).cpustat.idle + - kstat_cpu(j).cpustat.iowait; - /* consider 'nice' too? */ - if (dbs_tuners_ins.ignore_nice == 0) - total_idle_ticks += kstat_cpu(j).cpustat.nice; + total_idle_ticks = get_cpu_idle_time(j); tmp_idle_ticks = total_idle_ticks - j_dbs_info->prev_cpu_idle_up; j_dbs_info->prev_cpu_idle_up = total_idle_ticks; @@ -373,6 +368,8 @@ static void dbs_check_cpu(int cpu) usecs_to_jiffies(dbs_tuners_ins.sampling_rate); if (idle_ticks < up_idle_ticks) { + down_skip[cpu] = 0; + this_dbs_info->prev_cpu_idle_down = total_idle_ticks; /* if we are already at full speed then break out early */ if (requested_freq[cpu] == policy->max) return; @@ -389,8 +386,6 @@ static void dbs_check_cpu(int cpu) __cpufreq_driver_target(policy, requested_freq[cpu], CPUFREQ_RELATION_H); - down_skip[cpu] = 0; - this_dbs_info->prev_cpu_idle_down = total_idle_ticks; return; } @@ -399,11 +394,7 @@ static void dbs_check_cpu(int cpu) if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor) return; - total_idle_ticks = kstat_cpu(cpu).cpustat.idle + - kstat_cpu(cpu).cpustat.iowait; - /* consider 'nice' too? */ - if (dbs_tuners_ins.ignore_nice == 0) - total_idle_ticks += kstat_cpu(cpu).cpustat.nice; + total_idle_ticks = this_dbs_info->prev_cpu_idle_up; idle_ticks = total_idle_ticks - this_dbs_info->prev_cpu_idle_down; this_dbs_info->prev_cpu_idle_down = total_idle_ticks; @@ -417,11 +408,7 @@ static void dbs_check_cpu(int cpu) j_dbs_info = &per_cpu(cpu_dbs_info, j); /* Check for frequency increase */ - total_idle_ticks = kstat_cpu(j).cpustat.idle + - kstat_cpu(j).cpustat.iowait; - /* consider 'nice' too? */ - if (dbs_tuners_ins.ignore_nice == 0) - total_idle_ticks += kstat_cpu(j).cpustat.nice; + total_idle_ticks = j_dbs_info->prev_cpu_idle_up; tmp_idle_ticks = total_idle_ticks - j_dbs_info->prev_cpu_idle_down; j_dbs_info->prev_cpu_idle_down = total_idle_ticks; @@ -516,11 +503,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, j_dbs_info = &per_cpu(cpu_dbs_info, j); j_dbs_info->cur_policy = policy; - j_dbs_info->prev_cpu_idle_up = - kstat_cpu(j).cpustat.idle + - kstat_cpu(j).cpustat.iowait + - ( !dbs_tuners_ins.ignore_nice - ? kstat_cpu(j).cpustat.nice : 0 ); + j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j); j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up; } diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 056591612467..26cf54b11ba6 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -88,6 +88,15 @@ static struct dbs_tuners dbs_tuners_ins = { .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, }; +static inline unsigned int get_cpu_idle_time(unsigned int cpu) +{ + return kstat_cpu(cpu).cpustat.idle + + kstat_cpu(cpu).cpustat.iowait + + ( !dbs_tuners_ins.ignore_nice ? + kstat_cpu(cpu).cpustat.nice : + 0); +} + /************************** sysfs interface ************************/ static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf) { @@ -220,16 +229,10 @@ static ssize_t store_ignore_nice(struct cpufreq_policy *policy, dbs_tuners_ins.ignore_nice = input; /* we need to re-evaluate prev_cpu_idle_up and prev_cpu_idle_down */ - for_each_cpu_mask(j, policy->cpus) { + for_each_online_cpu(j) { struct cpu_dbs_info_s *j_dbs_info; j_dbs_info = &per_cpu(cpu_dbs_info, j); - j_dbs_info->cur_policy = policy; - - j_dbs_info->prev_cpu_idle_up = - kstat_cpu(j).cpustat.idle + - kstat_cpu(j).cpustat.iowait + - ( !dbs_tuners_ins.ignore_nice - ? kstat_cpu(j).cpustat.nice : 0 ); + j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j); j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up; } up(&dbs_sem); @@ -322,15 +325,10 @@ static void dbs_check_cpu(int cpu) */ /* Check for frequency increase */ - total_idle_ticks = kstat_cpu(cpu).cpustat.idle + - kstat_cpu(cpu).cpustat.iowait; - /* consider 'nice' tasks as 'idle' time too if required */ - if (dbs_tuners_ins.ignore_nice == 0) - total_idle_ticks += kstat_cpu(cpu).cpustat.nice; + total_idle_ticks = get_cpu_idle_time(cpu); idle_ticks = total_idle_ticks - this_dbs_info->prev_cpu_idle_up; this_dbs_info->prev_cpu_idle_up = total_idle_ticks; - for_each_cpu_mask(j, policy->cpus) { unsigned int tmp_idle_ticks; @@ -341,11 +339,7 @@ static void dbs_check_cpu(int cpu) j_dbs_info = &per_cpu(cpu_dbs_info, j); /* Check for frequency increase */ - total_idle_ticks = kstat_cpu(j).cpustat.idle + - kstat_cpu(j).cpustat.iowait; - /* consider 'nice' too? */ - if (dbs_tuners_ins.ignore_nice == 0) - total_idle_ticks += kstat_cpu(j).cpustat.nice; + total_idle_ticks = get_cpu_idle_time(j); tmp_idle_ticks = total_idle_ticks - j_dbs_info->prev_cpu_idle_up; j_dbs_info->prev_cpu_idle_up = total_idle_ticks; @@ -360,14 +354,14 @@ static void dbs_check_cpu(int cpu) usecs_to_jiffies(dbs_tuners_ins.sampling_rate); if (idle_ticks < up_idle_ticks) { + down_skip[cpu] = 0; + this_dbs_info->prev_cpu_idle_down = total_idle_ticks; /* if we are already at full speed then break out early */ if (policy->cur == policy->max) return; __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); - down_skip[cpu] = 0; - this_dbs_info->prev_cpu_idle_down = total_idle_ticks; return; } @@ -376,11 +370,7 @@ static void dbs_check_cpu(int cpu) if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor) return; - total_idle_ticks = kstat_cpu(cpu).cpustat.idle + - kstat_cpu(cpu).cpustat.iowait; - /* consider 'nice' too? */ - if (dbs_tuners_ins.ignore_nice == 0) - total_idle_ticks += kstat_cpu(cpu).cpustat.nice; + total_idle_ticks = this_dbs_info->prev_cpu_idle_up; idle_ticks = total_idle_ticks - this_dbs_info->prev_cpu_idle_down; this_dbs_info->prev_cpu_idle_down = total_idle_ticks; @@ -393,12 +383,8 @@ static void dbs_check_cpu(int cpu) continue; j_dbs_info = &per_cpu(cpu_dbs_info, j); - /* Check for frequency increase */ - total_idle_ticks = kstat_cpu(j).cpustat.idle + - kstat_cpu(j).cpustat.iowait; - /* consider 'nice' too? */ - if (dbs_tuners_ins.ignore_nice == 0) - total_idle_ticks += kstat_cpu(j).cpustat.nice; + /* Check for frequency decrease */ + total_idle_ticks = j_dbs_info->prev_cpu_idle_up; tmp_idle_ticks = total_idle_ticks - j_dbs_info->prev_cpu_idle_down; j_dbs_info->prev_cpu_idle_down = total_idle_ticks; @@ -414,7 +400,7 @@ static void dbs_check_cpu(int cpu) freq_down_sampling_rate = dbs_tuners_ins.sampling_rate * dbs_tuners_ins.sampling_down_factor; down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) * - usecs_to_jiffies(freq_down_sampling_rate); + usecs_to_jiffies(freq_down_sampling_rate); if (idle_ticks > down_idle_ticks ) { /* if we are already at the lowest speed then break out early @@ -488,11 +474,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, j_dbs_info = &per_cpu(cpu_dbs_info, j); j_dbs_info->cur_policy = policy; - j_dbs_info->prev_cpu_idle_up = - kstat_cpu(j).cpustat.idle + - kstat_cpu(j).cpustat.iowait + - ( !dbs_tuners_ins.ignore_nice - ? kstat_cpu(j).cpustat.nice : 0 ); + j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j); j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up; } From 790d76fa979f55bfc49a6901bb911778949b582d Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:49 -0700 Subject: [PATCH 139/155] [CPUFREQ] ondemand,conservative governor store the idle ticks for all cpus [PATCH] [2/5] ondemand,conservative governor store the idle ticks for all cpus Ondemand, conservative governor did not store prev_cpu_idle_up into prev_cpu_idle_down for other CPUs than the current CPU. Signed-off-by: Eric Piel Signed-off-by: Venkatesh Pallipadi Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq_conservative.c | 8 +++++++- drivers/cpufreq/cpufreq_ondemand.c | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 3082a3fa5ec4..c503ec14765f 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -369,7 +369,13 @@ static void dbs_check_cpu(int cpu) if (idle_ticks < up_idle_ticks) { down_skip[cpu] = 0; - this_dbs_info->prev_cpu_idle_down = total_idle_ticks; + for_each_cpu_mask(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + + j_dbs_info = &per_cpu(cpu_dbs_info, j); + j_dbs_info->prev_cpu_idle_down = + j_dbs_info->prev_cpu_idle_up; + } /* if we are already at full speed then break out early */ if (requested_freq[cpu] == policy->max) return; diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 26cf54b11ba6..f239545ac1b8 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -355,7 +355,13 @@ static void dbs_check_cpu(int cpu) if (idle_ticks < up_idle_ticks) { down_skip[cpu] = 0; - this_dbs_info->prev_cpu_idle_down = total_idle_ticks; + for_each_cpu_mask(j, policy->cpus) { + struct cpu_dbs_info_s *j_dbs_info; + + j_dbs_info = &per_cpu(cpu_dbs_info, j); + j_dbs_info->prev_cpu_idle_down = + j_dbs_info->prev_cpu_idle_up; + } /* if we are already at full speed then break out early */ if (policy->cur == policy->max) return; From 9c7d269b9b05440dd0fe92d96f4e5d7e73dd7238 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:49 -0700 Subject: [PATCH 140/155] [CPUFREQ] ondemand,conservative governor idle_tick clean-up [PATCH] [3/5] ondemand,conservative governor idle_tick clean-up Ondemand and conservative governor clean-up, it factorises the idle ticks measurement. Signed-off-by: Eric Piel Signed-off-by: Venkatesh Pallipadi Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq_conservative.c | 26 +++++--------------------- drivers/cpufreq/cpufreq_ondemand.c | 26 +++++--------------------- 2 files changed, 10 insertions(+), 42 deletions(-) diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index c503ec14765f..e1df376e709e 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -297,7 +297,6 @@ static struct attribute_group dbs_attr_group = { static void dbs_check_cpu(int cpu) { unsigned int idle_ticks, up_idle_ticks, down_idle_ticks; - unsigned int total_idle_ticks; unsigned int freq_step; unsigned int freq_down_sampling_rate; static int down_skip[NR_CPUS]; @@ -338,19 +337,12 @@ static void dbs_check_cpu(int cpu) */ /* Check for frequency increase */ - total_idle_ticks = get_cpu_idle_time(cpu); - idle_ticks = total_idle_ticks - - this_dbs_info->prev_cpu_idle_up; - this_dbs_info->prev_cpu_idle_up = total_idle_ticks; - + idle_ticks = UINT_MAX; for_each_cpu_mask(j, policy->cpus) { - unsigned int tmp_idle_ticks; + unsigned int tmp_idle_ticks, total_idle_ticks; struct cpu_dbs_info_s *j_dbs_info; - if (j == cpu) - continue; - j_dbs_info = &per_cpu(cpu_dbs_info, j); /* Check for frequency increase */ total_idle_ticks = get_cpu_idle_time(j); @@ -400,20 +392,12 @@ static void dbs_check_cpu(int cpu) if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor) return; - total_idle_ticks = this_dbs_info->prev_cpu_idle_up; - idle_ticks = total_idle_ticks - - this_dbs_info->prev_cpu_idle_down; - this_dbs_info->prev_cpu_idle_down = total_idle_ticks; - + idle_ticks = UINT_MAX; for_each_cpu_mask(j, policy->cpus) { - unsigned int tmp_idle_ticks; + unsigned int tmp_idle_ticks, total_idle_ticks; struct cpu_dbs_info_s *j_dbs_info; - if (j == cpu) - continue; - j_dbs_info = &per_cpu(cpu_dbs_info, j); - /* Check for frequency increase */ total_idle_ticks = j_dbs_info->prev_cpu_idle_up; tmp_idle_ticks = total_idle_ticks - j_dbs_info->prev_cpu_idle_down; @@ -432,7 +416,7 @@ static void dbs_check_cpu(int cpu) down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) * usecs_to_jiffies(freq_down_sampling_rate); - if (idle_ticks > down_idle_ticks ) { + if (idle_ticks > down_idle_ticks) { /* if we are already at the lowest speed then break out early * or if we 'cannot' reduce the speed as the user might want * freq_step to be zero */ diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index f239545ac1b8..0482bd49aba8 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -296,7 +296,6 @@ static struct attribute_group dbs_attr_group = { static void dbs_check_cpu(int cpu) { unsigned int idle_ticks, up_idle_ticks, down_idle_ticks; - unsigned int total_idle_ticks; unsigned int freq_down_step; unsigned int freq_down_sampling_rate; static int down_skip[NR_CPUS]; @@ -325,20 +324,12 @@ static void dbs_check_cpu(int cpu) */ /* Check for frequency increase */ - total_idle_ticks = get_cpu_idle_time(cpu); - idle_ticks = total_idle_ticks - - this_dbs_info->prev_cpu_idle_up; - this_dbs_info->prev_cpu_idle_up = total_idle_ticks; - + idle_ticks = UINT_MAX; for_each_cpu_mask(j, policy->cpus) { - unsigned int tmp_idle_ticks; + unsigned int tmp_idle_ticks, total_idle_ticks; struct cpu_dbs_info_s *j_dbs_info; - if (j == cpu) - continue; - j_dbs_info = &per_cpu(cpu_dbs_info, j); - /* Check for frequency increase */ total_idle_ticks = get_cpu_idle_time(j); tmp_idle_ticks = total_idle_ticks - j_dbs_info->prev_cpu_idle_up; @@ -376,18 +367,11 @@ static void dbs_check_cpu(int cpu) if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor) return; - total_idle_ticks = this_dbs_info->prev_cpu_idle_up; - idle_ticks = total_idle_ticks - - this_dbs_info->prev_cpu_idle_down; - this_dbs_info->prev_cpu_idle_down = total_idle_ticks; - + idle_ticks = UINT_MAX; for_each_cpu_mask(j, policy->cpus) { - unsigned int tmp_idle_ticks; + unsigned int tmp_idle_ticks, total_idle_ticks; struct cpu_dbs_info_s *j_dbs_info; - if (j == cpu) - continue; - j_dbs_info = &per_cpu(cpu_dbs_info, j); /* Check for frequency decrease */ total_idle_ticks = j_dbs_info->prev_cpu_idle_up; @@ -408,7 +392,7 @@ static void dbs_check_cpu(int cpu) down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) * usecs_to_jiffies(freq_down_sampling_rate); - if (idle_ticks > down_idle_ticks ) { + if (idle_ticks > down_idle_ticks) { /* if we are already at the lowest speed then break out early * or if we 'cannot' reduce the speed as the user might want * freq_step to be zero */ From c29f1403098135bdef75b190a5037db514701031 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:50 -0700 Subject: [PATCH 141/155] [CPUFREQ] ondemand governor automatic downscaling [PATCH] [4/5] ondemand governor automatic downscaling Here is a change of policy for the ondemand governor. The modification concerns the frequency downscaling. Instead of decreasing to a lower frequency when the CPU usage is under 20%, this new policy automatically scales to the optimal frequency. The optimal frequency being the lowest frequency which provides enough power to not trigger the upscaling policy. Signed-off-by: Eric Piel Signed-off-by: Venkatesh Pallipadi Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq_ondemand.c | 117 ++++++----------------------- 1 file changed, 25 insertions(+), 92 deletions(-) diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 0482bd49aba8..8bc38ab96400 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -34,13 +34,9 @@ */ #define DEF_FREQUENCY_UP_THRESHOLD (80) -#define MIN_FREQUENCY_UP_THRESHOLD (0) +#define MIN_FREQUENCY_UP_THRESHOLD (11) #define MAX_FREQUENCY_UP_THRESHOLD (100) -#define DEF_FREQUENCY_DOWN_THRESHOLD (20) -#define MIN_FREQUENCY_DOWN_THRESHOLD (0) -#define MAX_FREQUENCY_DOWN_THRESHOLD (100) - /* * The polling frequency of this governor depends on the capability of * the processor. Default polling frequency is 1000 times the transition @@ -77,14 +73,11 @@ struct dbs_tuners { unsigned int sampling_rate; unsigned int sampling_down_factor; unsigned int up_threshold; - unsigned int down_threshold; unsigned int ignore_nice; - unsigned int freq_step; }; static struct dbs_tuners dbs_tuners_ins = { .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, - .down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD, .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR, }; @@ -125,9 +118,7 @@ static ssize_t show_##file_name \ show_one(sampling_rate, sampling_rate); show_one(sampling_down_factor, sampling_down_factor); show_one(up_threshold, up_threshold); -show_one(down_threshold, down_threshold); show_one(ignore_nice, ignore_nice); -show_one(freq_step, freq_step); static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused, const char *buf, size_t count) @@ -173,8 +164,7 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused, down(&dbs_sem); if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD || - input < MIN_FREQUENCY_UP_THRESHOLD || - input <= dbs_tuners_ins.down_threshold) { + input < MIN_FREQUENCY_UP_THRESHOLD) { up(&dbs_sem); return -EINVAL; } @@ -185,27 +175,6 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused, return count; } -static ssize_t store_down_threshold(struct cpufreq_policy *unused, - const char *buf, size_t count) -{ - unsigned int input; - int ret; - ret = sscanf (buf, "%u", &input); - - down(&dbs_sem); - if (ret != 1 || input > MAX_FREQUENCY_DOWN_THRESHOLD || - input < MIN_FREQUENCY_DOWN_THRESHOLD || - input >= dbs_tuners_ins.up_threshold) { - up(&dbs_sem); - return -EINVAL; - } - - dbs_tuners_ins.down_threshold = input; - up(&dbs_sem); - - return count; -} - static ssize_t store_ignore_nice(struct cpufreq_policy *policy, const char *buf, size_t count) { @@ -240,29 +209,6 @@ static ssize_t store_ignore_nice(struct cpufreq_policy *policy, return count; } -static ssize_t store_freq_step(struct cpufreq_policy *policy, - const char *buf, size_t count) -{ - unsigned int input; - int ret; - - ret = sscanf (buf, "%u", &input); - - if ( ret != 1 ) - return -EINVAL; - - if ( input > 100 ) - input = 100; - - /* no need to test here if freq_step is zero as the user might actually - * want this, they would be crazy though :) */ - down(&dbs_sem); - dbs_tuners_ins.freq_step = input; - up(&dbs_sem); - - return count; -} - #define define_one_rw(_name) \ static struct freq_attr _name = \ __ATTR(_name, 0644, show_##_name, store_##_name) @@ -270,9 +216,7 @@ __ATTR(_name, 0644, show_##_name, store_##_name) define_one_rw(sampling_rate); define_one_rw(sampling_down_factor); define_one_rw(up_threshold); -define_one_rw(down_threshold); define_one_rw(ignore_nice); -define_one_rw(freq_step); static struct attribute * dbs_attributes[] = { &sampling_rate_max.attr, @@ -280,9 +224,7 @@ static struct attribute * dbs_attributes[] = { &sampling_rate.attr, &sampling_down_factor.attr, &up_threshold.attr, - &down_threshold.attr, &ignore_nice.attr, - &freq_step.attr, NULL }; @@ -295,8 +237,8 @@ static struct attribute_group dbs_attr_group = { static void dbs_check_cpu(int cpu) { - unsigned int idle_ticks, up_idle_ticks, down_idle_ticks; - unsigned int freq_down_step; + unsigned int idle_ticks, up_idle_ticks, total_ticks; + unsigned int freq_next; unsigned int freq_down_sampling_rate; static int down_skip[NR_CPUS]; struct cpu_dbs_info_s *this_dbs_info; @@ -310,17 +252,15 @@ static void dbs_check_cpu(int cpu) policy = this_dbs_info->cur_policy; /* - * The default safe range is 20% to 80% - * Every sampling_rate, we check - * - If current idle time is less than 20%, then we try to - * increase frequency - * Every sampling_rate*sampling_down_factor, we check - * - If current idle time is more than 80%, then we try to - * decrease frequency + * Every sampling_rate, we check, if current idle time is less + * than 20% (default), then we try to increase frequency + * Every sampling_rate*sampling_down_factor, we look for a the lowest + * frequency which can sustain the load while keeping idle time over + * 30%. If such a frequency exist, we try to decrease to this frequency. * * Any frequency increase takes it to the maximum frequency. * Frequency reduction happens at minimum steps of - * 5% (default) of max_frequency + * 5% (default) of current frequency */ /* Check for frequency increase */ @@ -383,33 +323,27 @@ static void dbs_check_cpu(int cpu) idle_ticks = tmp_idle_ticks; } - /* Scale idle ticks by 100 and compare with up and down ticks */ - idle_ticks *= 100; down_skip[cpu] = 0; + /* if we cannot reduce the frequency anymore, break out early */ + if (policy->cur == policy->min) + return; + /* Compute how many ticks there are between two measurements */ freq_down_sampling_rate = dbs_tuners_ins.sampling_rate * dbs_tuners_ins.sampling_down_factor; - down_idle_ticks = (100 - dbs_tuners_ins.down_threshold) * - usecs_to_jiffies(freq_down_sampling_rate); + total_ticks = usecs_to_jiffies(freq_down_sampling_rate); - if (idle_ticks > down_idle_ticks) { - /* if we are already at the lowest speed then break out early - * or if we 'cannot' reduce the speed as the user might want - * freq_step to be zero */ - if (policy->cur == policy->min || dbs_tuners_ins.freq_step == 0) - return; + /* + * The optimal frequency is the frequency that is the lowest that + * can support the current CPU usage without triggering the up + * policy. To be safe, we focus 10 points under the threshold. + */ + freq_next = ((total_ticks - idle_ticks) * 100) / total_ticks; + freq_next = (freq_next * policy->cur) / + (dbs_tuners_ins.up_threshold - 10); - freq_down_step = (dbs_tuners_ins.freq_step * policy->max) / 100; - - /* max freq cannot be less than 100. But who knows.... */ - if (unlikely(freq_down_step == 0)) - freq_down_step = 5; - - __cpufreq_driver_target(policy, - policy->cur - freq_down_step, - CPUFREQ_RELATION_H); - return; - } + if (freq_next <= ((policy->cur * 95) / 100)) + __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L); } static void do_dbs_timer(void *data) @@ -487,7 +421,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, DEF_SAMPLING_RATE_LATENCY_MULTIPLIER; dbs_tuners_ins.sampling_rate = def_sampling_rate; dbs_tuners_ins.ignore_nice = 0; - dbs_tuners_ins.freq_step = 5; dbs_timer_init(); } From e131832ca7d3a3e5f9c7624bb310a7747dc2b57c Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:50 -0700 Subject: [PATCH 142/155] [CPUFREQ] ondemand governor default sampling downfactor as 1 [PATCH] [5/5] ondemand governor default sampling downfactor as 1 Make default sampling downfactor 1. This works better with earlier auto downscaling change in ondemand governor. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq_ondemand.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 8bc38ab96400..c1fc9c62bb51 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -51,7 +51,8 @@ static unsigned int def_sampling_rate; #define MIN_SAMPLING_RATE (def_sampling_rate / 2) #define MAX_SAMPLING_RATE (500 * def_sampling_rate) #define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000) -#define DEF_SAMPLING_DOWN_FACTOR (10) +#define DEF_SAMPLING_DOWN_FACTOR (1) +#define MAX_SAMPLING_DOWN_FACTOR (10) #define TRANSITION_LATENCY_LIMIT (10 * 1000) static void do_dbs_timer(void *data); @@ -129,6 +130,9 @@ static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused, if (ret != 1 ) return -EINVAL; + if (input > MAX_SAMPLING_DOWN_FACTOR || input < 1) + return -EINVAL; + down(&dbs_sem); dbs_tuners_ins.sampling_down_factor = input; up(&dbs_sem); From 3be6a48f3c8df1b2fbbe57face95a03d167bda1b Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:51 -0700 Subject: [PATCH 143/155] [CPUFREQ] longhaul - disable PCI mastering around transition. The spec states that we have to do this, which is *horrid*. Based on code from: Ken Staton Signed-off-by: Dave Jones --- arch/i386/kernel/cpu/cpufreq/longhaul.c | 49 +++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index ab0f9f5aac11..8ea545e35b3a 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -120,6 +121,11 @@ static void do_powersaver(union msr_longhaul *longhaul, unsigned int clock_ratio_index) { int version; + unsigned long flags; + struct pci_dev *dev; + int i; + u16 pci_cmd; + u16 cmd_state[64]; switch (cpu_model) { case CPU_EZRA_T: @@ -137,17 +143,52 @@ static void do_powersaver(union msr_longhaul *longhaul, longhaul->bits.SoftBusRatio4 = (clock_ratio_index & 0x10) >> 4; longhaul->bits.EnableSoftBusRatio = 1; longhaul->bits.RevisionKey = 0; - local_irq_disable(); - wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); + + preempt_disable(); + local_irq_save(flags); + + /* + * get current pci bus master state for all devices + * and clear bus master bit + */ + dev = NULL; + i = 0; + do { + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); + if (dev != NULL) { + pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); + cmd_state[i++] = pci_cmd; + pci_cmd &= ~PCI_COMMAND_MASTER; + pci_write_config_word(dev, PCI_COMMAND, pci_cmd); + } + } while (dev != NULL); + local_irq_enable(); + + __hlt(); + wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); __hlt(); + local_irq_disable(); + + /* restore pci bus master state for all devices */ + dev = NULL; + i = 0; + do { + dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); + if (dev != NULL) { + pci_cmd = cmd_state[i++]; + pci_write_config_byte(dev, PCI_COMMAND, pci_cmd); + } + } while (dev != NULL); + local_irq_restore(flags); + preempt_enable(); + + /* disable bus ratio bit */ rdmsrl(MSR_VIA_LONGHAUL, longhaul->val); longhaul->bits.EnableSoftBusRatio = 0; longhaul->bits.RevisionKey = version; - local_irq_disable(); wrmsrl(MSR_VIA_LONGHAUL, longhaul->val); - local_irq_enable(); } /** From 1174631418fbb2c0c6946081b0b7d391f5d92861 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:51 -0700 Subject: [PATCH 144/155] [CPUFREQ] Longhaul: Magic timer frobbing. As mandated by the spec, disable timer around transitions. From code by : Ken Staton --- arch/i386/kernel/cpu/cpufreq/longhaul.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index 8ea545e35b3a..48899f0956f7 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c @@ -120,9 +120,10 @@ static int longhaul_get_cpu_mult(void) static void do_powersaver(union msr_longhaul *longhaul, unsigned int clock_ratio_index) { - int version; - unsigned long flags; struct pci_dev *dev; + unsigned long flags; + unsigned int tmp_mask; + int version; int i; u16 pci_cmd; u16 cmd_state[64]; @@ -163,6 +164,10 @@ static void do_powersaver(union msr_longhaul *longhaul, } } while (dev != NULL); + tmp_mask=inb(0x21); /* works on C3. save mask. */ + outb(0xFE,0x21); /* TMR0 only */ + outb(0xFF,0x80); /* delay */ + local_irq_enable(); __hlt(); @@ -171,6 +176,8 @@ static void do_powersaver(union msr_longhaul *longhaul, local_irq_disable(); + outb(tmp_mask,0x21); /* restore mask */ + /* restore pci bus master state for all devices */ dev = NULL; i = 0; From 6778bae0f2f1d4af1b8bb876c992ea094ee958b4 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:51 -0700 Subject: [PATCH 145/155] [CPUFREQ] longhaul - adjust transition latency. From patch by: Ken Staton Signed-off-by: Dave Jones --- arch/i386/kernel/cpu/cpufreq/longhaul.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index 48899f0956f7..04e3563da4fe 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c @@ -626,7 +626,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) longhaul_setup_voltagescaling(); policy->governor = CPUFREQ_DEFAULT_GOVERNOR; - policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + policy->cpuinfo.transition_latency = 200000; /* nsec */ policy->cur = calc_speed(longhaul_get_cpu_mult()); ret = cpufreq_frequency_table_cpuinfo(policy, longhaul_table); From f94ea640a28230f82a4395c34e1290748a9f6586 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 31 May 2005 19:03:52 -0700 Subject: [PATCH 146/155] [CPUFREQ] Typos. cpfureq developers cant spel. Signed-off-by: Dave Jones --- arch/i386/kernel/cpu/cpufreq/speedstep-lib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c index 8ba430a9c3a2..d368b3f5fce8 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-lib.c @@ -336,7 +336,7 @@ unsigned int speedstep_get_freqs(unsigned int processor, if (!prev_speed) return -EIO; - dprintk("previous seped is %u\n", prev_speed); + dprintk("previous speed is %u\n", prev_speed); local_irq_save(flags); @@ -348,7 +348,7 @@ unsigned int speedstep_get_freqs(unsigned int processor, goto out; } - dprintk("low seped is %u\n", *low_speed); + dprintk("low speed is %u\n", *low_speed); /* switch to high state */ set_state(SPEEDSTEP_HIGH); @@ -358,7 +358,7 @@ unsigned int speedstep_get_freqs(unsigned int processor, goto out; } - dprintk("high seped is %u\n", *high_speed); + dprintk("high speed is %u\n", *high_speed); if (*low_speed == *high_speed) { ret = -ENODEV; From 58f1df25403988b73d7129fcd2c4d4c24017f1af Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Wed, 25 May 2005 14:46:50 -0700 Subject: [PATCH 147/155] [PATCH] cpufreq-stats driver updates Changes to the cpufreq stats driver: * Changes the way P-state transition table looks in /sysfs providing more clear output * Changes the time unit in the output from HZ to clock_t Signed-off-by: Venkatesh Pallipadi Signed-off-by: Dave Jones --- drivers/cpufreq/cpufreq_stats.c | 47 +++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 2084593937c6..741b6b191e6a 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -19,6 +19,7 @@ #include #include #include +#include static spinlock_t cpufreq_stats_lock; @@ -29,20 +30,14 @@ static struct freq_attr _attr_##_name = {\ .show = _show,\ }; -static unsigned long -delta_time(unsigned long old, unsigned long new) -{ - return (old > new) ? (old - new): (new + ~old + 1); -} - struct cpufreq_stats { unsigned int cpu; unsigned int total_trans; - unsigned long long last_time; + unsigned long long last_time; unsigned int max_state; unsigned int state_num; unsigned int last_index; - unsigned long long *time_in_state; + cputime64_t *time_in_state; unsigned int *freq_table; #ifdef CONFIG_CPU_FREQ_STAT_DETAILS unsigned int *trans_table; @@ -60,12 +55,16 @@ static int cpufreq_stats_update (unsigned int cpu) { struct cpufreq_stats *stat; + unsigned long long cur_time; + + cur_time = get_jiffies_64(); spin_lock(&cpufreq_stats_lock); stat = cpufreq_stats_table[cpu]; if (stat->time_in_state) - stat->time_in_state[stat->last_index] += - delta_time(stat->last_time, jiffies); - stat->last_time = jiffies; + stat->time_in_state[stat->last_index] = + cputime64_add(stat->time_in_state[stat->last_index], + cputime_sub(cur_time, stat->last_time)); + stat->last_time = cur_time; spin_unlock(&cpufreq_stats_lock); return 0; } @@ -90,8 +89,8 @@ show_time_in_state(struct cpufreq_policy *policy, char *buf) return 0; cpufreq_stats_update(stat->cpu); for (i = 0; i < stat->state_num; i++) { - len += sprintf(buf + len, "%u %llu\n", - stat->freq_table[i], stat->time_in_state[i]); + len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i], + (unsigned long long)cputime64_to_clock_t(stat->time_in_state[i])); } return len; } @@ -107,16 +106,30 @@ show_trans_table(struct cpufreq_policy *policy, char *buf) if(!stat) return 0; cpufreq_stats_update(stat->cpu); + len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); + len += snprintf(buf + len, PAGE_SIZE - len, " : "); for (i = 0; i < stat->state_num; i++) { if (len >= PAGE_SIZE) break; - len += snprintf(buf + len, PAGE_SIZE - len, "%9u:\t", + len += snprintf(buf + len, PAGE_SIZE - len, "%9u ", + stat->freq_table[i]); + } + if (len >= PAGE_SIZE) + return len; + + len += snprintf(buf + len, PAGE_SIZE - len, "\n"); + + for (i = 0; i < stat->state_num; i++) { + if (len >= PAGE_SIZE) + break; + + len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ", stat->freq_table[i]); for (j = 0; j < stat->state_num; j++) { if (len >= PAGE_SIZE) break; - len += snprintf(buf + len, PAGE_SIZE - len, "%u\t", + len += snprintf(buf + len, PAGE_SIZE - len, "%9u ", stat->trans_table[i*stat->max_state+j]); } len += snprintf(buf + len, PAGE_SIZE - len, "\n"); @@ -197,7 +210,7 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy, count++; } - alloc_size = count * sizeof(int) + count * sizeof(long long); + alloc_size = count * sizeof(int) + count * sizeof(cputime64_t); #ifdef CONFIG_CPU_FREQ_STAT_DETAILS alloc_size += count * count * sizeof(int); @@ -224,7 +237,7 @@ cpufreq_stats_create_table (struct cpufreq_policy *policy, } stat->state_num = j; spin_lock(&cpufreq_stats_lock); - stat->last_time = jiffies; + stat->last_time = get_jiffies_64(); stat->last_index = freq_table_get_index(stat, policy->cur); spin_unlock(&cpufreq_stats_lock); cpufreq_cpu_put(data); From 21e3024cbddb712f6a078bf4132d7682d3c4e35e Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Wed, 25 May 2005 14:43:56 -0700 Subject: [PATCH 148/155] [PATCH] cpufreq-stats driver documentation Documentation for cpufreq stats. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Dave Jones --- Documentation/cpu-freq/cpufreq-stats.txt | 128 +++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 Documentation/cpu-freq/cpufreq-stats.txt diff --git a/Documentation/cpu-freq/cpufreq-stats.txt b/Documentation/cpu-freq/cpufreq-stats.txt new file mode 100644 index 000000000000..e2d1e760b4ba --- /dev/null +++ b/Documentation/cpu-freq/cpufreq-stats.txt @@ -0,0 +1,128 @@ + + CPU frequency and voltage scaling statictics in the Linux(TM) kernel + + + L i n u x c p u f r e q - s t a t s d r i v e r + + - information for users - + + + Venkatesh Pallipadi + +Contents +1. Introduction +2. Statistics Provided (with example) +3. Configuring cpufreq-stats + + +1. Introduction + +cpufreq-stats is a driver that provices CPU frequency statistics for each CPU. +This statistics is provided in /sysfs as a bunch of read_only interfaces. This +interface (when configured) will appear in a seperate directory under cpufreq +in /sysfs (/devices/system/cpu/cpuX/cpufreq/stats/) for each CPU. +Various statistics will form read_only files under this directory. + +This driver is designed to be independent of any particular cpufreq_driver +that may be running on your CPU. So, it will work with any cpufreq_driver. + + +2. Statistics Provided (with example) + +cpufreq stats provides following statistics (explained in detail below). +- time_in_state +- total_trans +- trans_table + +All the statistics will be from the time the stats driver has been inserted +to the time when a read of a particular statistic is done. Obviously, stats +driver will not have any information about the the frequcny transitions before +the stats driver insertion. + +-------------------------------------------------------------------------------- +:/sys/devices/system/cpu/cpu0/cpufreq/stats # ls -l +total 0 +drwxr-xr-x 2 root root 0 May 14 16:06 . +drwxr-xr-x 3 root root 0 May 14 15:58 .. +-r--r--r-- 1 root root 4096 May 14 16:06 time_in_state +-r--r--r-- 1 root root 4096 May 14 16:06 total_trans +-r--r--r-- 1 root root 4096 May 14 16:06 trans_table +-------------------------------------------------------------------------------- + +- time_in_state +This gives the amount of time spent in each of the frequencies supported by +this CPU. The cat output will have "