From a1676072558854b95336c8f7db76b0504e909a0a Mon Sep 17 00:00:00 2001 From: Tony Camuso Date: Thu, 15 May 2008 14:40:14 -0400 Subject: PCI: Correct last two HP entries in the bfsort whitelist Greetings. There is a code flaw in the bfsort whitelist, where there are redundant entries for the same two HP systems, DL385 G2 and DL585 G2. This patch replaces those redundant entries with the correct ones. The correct entries are for large-volume systems, the DL360 and DL380. ----------------------------------------------------------------------- commit ec69f0374c3b0ad7ea991b0e9ac00377acfe5b1a Author: Tony Camuso Date: Wed May 14 07:09:28 2008 -0400 Replace Redundant Whitelist Entries with the Correct Ones The ProLiant DL585 G2 and the DL585 G2 are entered reundantly in the dmi_system_id table. What should have been there are the DL360 and DL380. This patch simply replaces the redundant entries with the correct entries. arch/x86/pci/common.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) Signed-off-by: Tony Camuso Signed-off-by: Pat Schoeller Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/pci/common.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 6e64aaf00d1d..940185ecaeda 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c @@ -328,18 +328,18 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = { #endif { .callback = set_bf_sort, - .ident = "HP ProLiant DL385 G2", + .ident = "HP ProLiant DL360", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL385 G2"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL360"), }, }, { .callback = set_bf_sort, - .ident = "HP ProLiant DL585 G2", + .ident = "HP ProLiant DL380", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "HP"), - DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL585 G2"), + DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL380"), }, }, {} -- cgit v1.2.3 From aaa9bbe039febf1d3a0f3a374deea0680d9f5758 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 23 May 2008 17:38:32 +0000 Subject: [CIFS] remove unused variables CC: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 3 +-- fs/cifs/cifssmb.c | 6 ++---- fs/cifs/file.c | 7 ------- fs/cifs/misc.c | 3 +-- fs/cifs/readdir.c | 6 +----- 5 files changed, 5 insertions(+), 20 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 08914053242b..9cfcf326ead3 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -333,7 +333,6 @@ struct cifsFileInfo { bool messageMode:1; /* for pipes: message vs byte mode */ atomic_t wrtPending; /* handle in use - defer close */ struct semaphore fh_sem; /* prevents reopen race after dead ses*/ - char *search_resume_name; /* BB removeme BB */ struct cifs_search_info srch_inf; }; @@ -626,7 +625,7 @@ GLOBAL_EXTERN atomic_t tcpSesAllocCount; GLOBAL_EXTERN atomic_t tcpSesReconnectCount; GLOBAL_EXTERN atomic_t tconInfoReconnectCount; -/* Various Debug counters to remove someday (BB) */ +/* Various Debug counters */ GLOBAL_EXTERN atomic_t bufAllocCount; /* current number allocated */ #ifdef CONFIG_CIFS_STATS2 GLOBAL_EXTERN atomic_t totBufAllocCount; /* total allocated over all time */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 9b8b4cfdf993..174bf8aca237 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1728,7 +1728,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, { int rc = 0; LOCK_REQ *pSMB = NULL; - LOCK_RSP *pSMBr = NULL; +/* LOCK_RSP *pSMBr = NULL; */ /* No response data other than rc to parse */ int bytes_returned; int timeout = 0; __u16 count; @@ -1739,8 +1739,6 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, if (rc) return rc; - pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */ - if (lockType == LOCKING_ANDX_OPLOCK_RELEASE) { timeout = CIFS_ASYNC_OP; /* no response expected */ pSMB->Timeout = 0; @@ -1774,7 +1772,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, if (waitFlag) { rc = SendReceiveBlockingLock(xid, tcon, (struct smb_hdr *) pSMB, - (struct smb_hdr *) pSMBr, &bytes_returned); + (struct smb_hdr *) pSMB, &bytes_returned); cifs_small_buf_release(pSMB); } else { rc = SendReceiveNoRsp(xid, tcon->ses, (struct smb_hdr *)pSMB, diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 8636cec2642c..0aac824371a5 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -546,7 +546,6 @@ int cifs_close(struct inode *inode, struct file *file) msleep(timeout); timeout *= 8; } - kfree(pSMBFile->search_resume_name); kfree(file->private_data); file->private_data = NULL; } else @@ -605,12 +604,6 @@ int cifs_closedir(struct inode *inode, struct file *file) else cifs_buf_release(ptmp); } - ptmp = pCFileStruct->search_resume_name; - if (ptmp) { - cFYI(1, ("closedir free resume name")); - pCFileStruct->search_resume_name = NULL; - kfree(ptmp); - } kfree(file->private_data); file->private_data = NULL; } diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 1d69b8014e0b..4b17f8fe3157 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -519,8 +519,7 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) pnotify = (struct file_notify_information *) ((char *)&pSMBr->hdr.Protocol + data_offset); cFYI(1, ("dnotify on %s Action: 0x%x", - pnotify->FileName, - pnotify->Action)); /* BB removeme BB */ + pnotify->FileName, pnotify->Action)); /* cifs_dump_mem("Rcvd notify Data: ",buf, sizeof(struct smb_hdr)+60); */ return true; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 713c25110197..df2c3c466ee1 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -675,8 +675,6 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, cifsFile->invalidHandle = true; CIFSFindClose(xid, pTcon, cifsFile->netfid); } - kfree(cifsFile->search_resume_name); - cifsFile->search_resume_name = NULL; if (cifsFile->srch_inf.ntwrk_buf_start) { cFYI(1, ("freeing SMB ff cache buf on search rewind")); if (cifsFile->srch_inf.smallBuf) @@ -1043,9 +1041,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) } /* else { cifsFile->invalidHandle = true; CIFSFindClose(xid, pTcon, cifsFile->netfid); - } - kfree(cifsFile->search_resume_name); - cifsFile->search_resume_name = NULL; */ + } */ rc = find_cifs_entry(xid, pTcon, file, ¤t_entry, &num_to_fill); -- cgit v1.2.3 From 4468eb3fd102cad559e51594a01cbc65b994d264 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 22 May 2008 09:31:40 -0400 Subject: on non-posix shares, clear write bits in mode when ATTR_READONLY is set When mounting a share with posix extensions disabled, cifs_get_inode_info turns off all the write bits in the mode for regular files if ATTR_READONLY is set. Directories and other inode types, however, can also have ATTR_READONLY set, but the mode gives no indication of this. This patch makes this apply to other inode types besides regular files. It also cleans up how modes are set in cifs_get_inode_info for both the "normal" and "dynperm" cases. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/inode.c | 76 ++++++++++++++++++++++++++----------------------------- fs/cifs/readdir.c | 71 ++++++++++++++++++++++++++++----------------------- 2 files changed, 75 insertions(+), 72 deletions(-) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 129dbfe4dca7..ae5bcaf2031c 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -418,6 +418,7 @@ int cifs_get_inode_info(struct inode **pinode, char *buf = NULL; bool adjustTZ = false; bool is_dfs_referral = false; + umode_t default_mode; pTcon = cifs_sb->tcon; cFYI(1, ("Getting info on %s", full_path)); @@ -530,47 +531,42 @@ int cifs_get_inode_info(struct inode **pinode, inode->i_mtime.tv_sec += pTcon->ses->server->timeAdj; } - /* set default mode. will override for dirs below */ - if (atomic_read(&cifsInfo->inUse) == 0) - /* new inode, can safely set these fields */ - inode->i_mode = cifs_sb->mnt_file_mode; - else /* since we set the inode type below we need to mask off - to avoid strange results if type changes and both - get orred in */ - inode->i_mode &= ~S_IFMT; -/* if (attr & ATTR_REPARSE) */ - /* We no longer handle these as symlinks because we could not - follow them due to the absolute path with drive letter */ - if (attr & ATTR_DIRECTORY) { - /* override default perms since we do not do byte range locking - on dirs */ - inode->i_mode = cifs_sb->mnt_dir_mode; - inode->i_mode |= S_IFDIR; - } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (cifsInfo->cifsAttrs & ATTR_SYSTEM) && - /* No need to le64 convert size of zero */ - (pfindData->EndOfFile == 0)) { - inode->i_mode = cifs_sb->mnt_file_mode; - inode->i_mode |= S_IFIFO; -/* BB Finish for SFU style symlinks and devices */ - } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { - if (decode_sfu_inode(inode, le64_to_cpu(pfindData->EndOfFile), - full_path, cifs_sb, xid)) - cFYI(1, ("Unrecognized sfu inode type")); - - cFYI(1, ("sfu mode 0%o", inode->i_mode)); + /* get default inode mode */ + if (attr & ATTR_DIRECTORY) + default_mode = cifs_sb->mnt_dir_mode; + else + default_mode = cifs_sb->mnt_file_mode; + + /* set permission bits */ + if (atomic_read(&cifsInfo->inUse) == 0 || + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) + inode->i_mode = default_mode; + else { + /* just reenable write bits if !ATTR_READONLY */ + if ((inode->i_mode & S_IWUGO) == 0 && + (attr & ATTR_READONLY) == 0) + inode->i_mode |= (S_IWUGO & default_mode); + inode->i_mode &= ~S_IFMT; + } + /* clear write bits if ATTR_READONLY is set */ + if (attr & ATTR_READONLY) + inode->i_mode &= ~S_IWUGO; + + /* set inode type */ + if ((attr & ATTR_SYSTEM) && + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { + /* no need to fix endianness on 0 */ + if (pfindData->EndOfFile == 0) + inode->i_mode |= S_IFIFO; + else if (decode_sfu_inode(inode, + le64_to_cpu(pfindData->EndOfFile), + full_path, cifs_sb, xid)) + cFYI(1, ("unknown SFU file type\n")); } else { - inode->i_mode |= S_IFREG; - /* treat dos attribute of read-only as read-only mode eg 555 */ - if (cifsInfo->cifsAttrs & ATTR_READONLY) - inode->i_mode &= ~(S_IWUGO); - else if ((inode->i_mode & S_IWUGO) == 0) - /* the ATTR_READONLY flag may have been */ - /* changed on server -- set any w bits */ - /* allowed by mnt_file_mode */ - inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode); - /* BB add code to validate if device or weird share or device type? */ + if (attr & ATTR_DIRECTORY) + inode->i_mode |= S_IFDIR; + else + inode->i_mode |= S_IFREG; } spin_lock(&inode->i_lock); diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index df2c3c466ee1..83f306954883 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -132,6 +132,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, __u32 attr; __u64 allocation_size; __u64 end_of_file; + umode_t default_mode; /* save mtime and size */ local_mtime = tmp_inode->i_mtime; @@ -187,48 +188,54 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, if (atomic_read(&cifsInfo->inUse) == 0) { tmp_inode->i_uid = cifs_sb->mnt_uid; tmp_inode->i_gid = cifs_sb->mnt_gid; - /* set default mode. will override for dirs below */ - tmp_inode->i_mode = cifs_sb->mnt_file_mode; - } else { - /* mask off the type bits since it gets set - below and we do not want to get two type - bits set */ + } + + if (attr & ATTR_DIRECTORY) + default_mode = cifs_sb->mnt_dir_mode; + else + default_mode = cifs_sb->mnt_file_mode; + + /* set initial permissions */ + if ((atomic_read(&cifsInfo->inUse) == 0) || + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) + tmp_inode->i_mode = default_mode; + else { + /* just reenable write bits if !ATTR_READONLY */ + if ((tmp_inode->i_mode & S_IWUGO) == 0 && + (attr & ATTR_READONLY) == 0) + tmp_inode->i_mode |= (S_IWUGO & default_mode); + tmp_inode->i_mode &= ~S_IFMT; } - if (attr & ATTR_DIRECTORY) { - *pobject_type = DT_DIR; - /* override default perms since we do not lock dirs */ - if (atomic_read(&cifsInfo->inUse) == 0) - tmp_inode->i_mode = cifs_sb->mnt_dir_mode; - tmp_inode->i_mode |= S_IFDIR; - } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (attr & ATTR_SYSTEM)) { + /* clear write bits if ATTR_READONLY is set */ + if (attr & ATTR_READONLY) + tmp_inode->i_mode &= ~S_IWUGO; + + /* set inode type */ + if ((attr & ATTR_SYSTEM) && + (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL)) { if (end_of_file == 0) { - *pobject_type = DT_FIFO; tmp_inode->i_mode |= S_IFIFO; + *pobject_type = DT_FIFO; } else { - /* rather than get the type here, we mark the - inode as needing revalidate and get the real type - (blk vs chr vs. symlink) later ie in lookup */ - *pobject_type = DT_REG; + /* + * trying to get the type can be slow, so just call + * this a regular file for now, and mark for reval + */ tmp_inode->i_mode |= S_IFREG; + *pobject_type = DT_REG; cifsInfo->time = 0; } -/* we no longer mark these because we could not follow them */ -/* } else if (attr & ATTR_REPARSE) { - *pobject_type = DT_LNK; - tmp_inode->i_mode |= S_IFLNK; */ } else { - *pobject_type = DT_REG; - tmp_inode->i_mode |= S_IFREG; - if (attr & ATTR_READONLY) - tmp_inode->i_mode &= ~(S_IWUGO); - else if ((tmp_inode->i_mode & S_IWUGO) == 0) - /* the ATTR_READONLY flag may have been changed on */ - /* server -- set any w bits allowed by mnt_file_mode */ - tmp_inode->i_mode |= (S_IWUGO & cifs_sb->mnt_file_mode); - } /* could add code here - to validate if device or weird share type? */ + if (attr & ATTR_DIRECTORY) { + tmp_inode->i_mode |= S_IFDIR; + *pobject_type = DT_DIR; + } else { + tmp_inode->i_mode |= S_IFREG; + *pobject_type = DT_REG; + } + } /* can not fill in nlink here as in qpathinfo version and Unx search */ if (atomic_read(&cifsInfo->inUse) == 0) -- cgit v1.2.3 From b0fd30d3e7e768aad5e398caaea6ae5a5c814eab Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 22 May 2008 09:33:34 -0400 Subject: when creating new inodes, use file_mode/dir_mode exclusively on mount without unix extensions When CIFS creates a new inode on a mount without unix extensions, it temporarily assigns the mode that was passed to it in the create/mkdir call. Eventually, when the inode is revalidated, it changes to have the file_mode or dir_mode for the mount. This is confusing to users who expect that the mode shouldn't change this way. It's also problematic since only the mode is treated this way, not the uid or gid. Suppose you have a CIFS mount that's mounted with: uid=0,gid=0,file_mode=0666,dir_mode=0777 ...if an unprivileged user comes along and does this on the mount: mkdir -m 0700 foo touch foo/bar ...there is a period of time where the touch will fail, since the dir will initially be owned by root and have mode 0700. If the user waits long enough, then "foo" will be revalidated and will get the correct dir_mode permissions. This patch changes cifs_mkdir and cifs_create to not overwrite the mode found by the initial cifs_get_inode_info call after the inode is created on the server. Legacy behavior can be reenabled with the new "dynperm" mount option. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/dir.c | 4 +++- fs/cifs/inode.c | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index f0b5b5f3dd2e..fb69c1fa85c9 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -260,7 +260,9 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, buf, inode->i_sb, xid, &fileHandle); if (newinode) { - newinode->i_mode = mode; + if (cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_DYNPERM) + newinode->i_mode = mode; if ((oplock & CIFS_CREATE_ACTION) && (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ae5bcaf2031c..12667d6bf305 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1015,8 +1015,11 @@ mkdir_get_info: CIFS_MOUNT_MAP_SPECIAL_CHR); } if (direntry->d_inode) { - direntry->d_inode->i_mode = mode; - direntry->d_inode->i_mode |= S_IFDIR; + if (cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_DYNPERM) + direntry->d_inode->i_mode = + (mode | S_IFDIR); + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { direntry->d_inode->i_uid = -- cgit v1.2.3 From 4e94a105ed0df78e25b20ff8ed6761f5937662b1 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 23 May 2008 18:22:46 +0000 Subject: [CIFS] remove trailing whitespace Signed-off-by: Steve French --- fs/cifs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 12667d6bf305..ae6b725b3665 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1019,7 +1019,7 @@ mkdir_get_info: CIFS_MOUNT_DYNPERM) direntry->d_inode->i_mode = (mode | S_IFDIR); - + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { direntry->d_inode->i_uid = -- cgit v1.2.3 From 4ca691a892e8ab4f79583de1394f17a7dcfa2b57 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 22 May 2008 09:33:34 -0400 Subject: silently ignore ownership changes unless unix extensions are enabled or we're faking uid changes CIFS currently allows you to change the ownership of a file, but unless unix extensions are enabled this change is not passed off to the server. Have CIFS silently ignore ownership changes that can't be persistently stored on the server unless the "setuids" option is explicitly specified. We could return an error here (-EOPNOTSUPP or something), but this is how most disk-based windows filesystems on behave on Linux (e.g. VFAT, NTFS, etc). With cifsacl support and proper Windows to Unix idmapping support, we may be able to do this more properly in the future. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/inode.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ae6b725b3665..fe752fdb26c3 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1546,13 +1546,26 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) } else goto cifs_setattr_exit; } - if (attrs->ia_valid & ATTR_UID) { - cFYI(1, ("UID changed to %d", attrs->ia_uid)); - uid = attrs->ia_uid; - } - if (attrs->ia_valid & ATTR_GID) { - cFYI(1, ("GID changed to %d", attrs->ia_gid)); - gid = attrs->ia_gid; + + /* + * Without unix extensions we can't send ownership changes to the + * server, so silently ignore them. This is consistent with how + * local DOS/Windows filesystems behave (VFAT, NTFS, etc). With + * CIFSACL support + proper Windows to Unix idmapping, we may be + * able to support this in the future. + */ + if (!pTcon->unix_ext && + !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) { + attrs->ia_valid &= ~(ATTR_UID | ATTR_GID); + } else { + if (attrs->ia_valid & ATTR_UID) { + cFYI(1, ("UID changed to %d", attrs->ia_uid)); + uid = attrs->ia_uid; + } + if (attrs->ia_valid & ATTR_GID) { + cFYI(1, ("GID changed to %d", attrs->ia_gid)); + gid = attrs->ia_gid; + } } time_buf.Attributes = 0; -- cgit v1.2.3 From 27adb44c4f671d15932eb0702a09d27244a8a7c1 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 23 May 2008 19:43:29 +0000 Subject: [CIFS] warn if both dynperm and cifsacl mount options specified Signed-off-by: Steve French --- fs/cifs/connect.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 023434f72c15..d49e274f8eba 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2120,6 +2120,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; } + if ((volume_info.cifs_acl) && (volume_info.dynperm)) + cERROR(1, ("mount option dynperm ignored if cifsacl " + "mount option supported")); + tcon = find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, volume_info.username); -- cgit v1.2.3 From b7206153f61bb63ee2cffa63905b57ec01d20e6e Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 23 May 2008 20:35:07 +0000 Subject: [CIFS] Correct incorrect obscure open flag Also add defines for pipe subcommand codes Signed-off-by: Steve French --- fs/cifs/cifspdu.h | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 65d58b4e6a61..0f327c224da3 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -79,6 +79,19 @@ #define TRANS2_GET_DFS_REFERRAL 0x10 #define TRANS2_REPORT_DFS_INCOSISTENCY 0x11 +/* SMB Transact (Named Pipe) subcommand codes */ +#define TRANS_SET_NMPIPE_STATE 0x0001 +#define TRANS_RAW_READ_NMPIPE 0x0011 +#define TRANS_QUERY_NMPIPE_STATE 0x0021 +#define TRANS_QUERY_NMPIPE_INFO 0x0022 +#define TRANS_PEEK_NMPIPE 0x0023 +#define TRANS_TRANSACT_NMPIPE 0x0026 +#define TRANS_RAW_WRITE_NMPIPE 0x0031 +#define TRANS_READ_NMPIPE 0x0036 +#define TRANS_WRITE_NMPIPE 0x0037 +#define TRANS_WAIT_NMPIPE 0x0053 +#define TRANS_CALL_NMPIPE 0x0054 + /* NT Transact subcommand codes */ #define NT_TRANSACT_CREATE 0x01 #define NT_TRANSACT_IOCTL 0x02 @@ -328,12 +341,13 @@ #define CREATE_COMPLETE_IF_OPLK 0x00000100 /* should be zero */ #define CREATE_NO_EA_KNOWLEDGE 0x00000200 #define CREATE_EIGHT_DOT_THREE 0x00000400 /* doc says this is obsolete - open for recovery flag - should - be zero */ + "open for recovery" flag - should + be zero in any case */ +#define CREATE_OPEN_FOR_RECOVERY 0x00000400 #define CREATE_RANDOM_ACCESS 0x00000800 #define CREATE_DELETE_ON_CLOSE 0x00001000 #define CREATE_OPEN_BY_ID 0x00002000 -#define CREATE_OPEN_BACKUP_INTN 0x00004000 +#define CREATE_OPEN_BACKUP_INTENT 0x00004000 #define CREATE_NO_COMPRESSION 0x00008000 #define CREATE_RESERVE_OPFILTER 0x00100000 /* should be zero */ #define OPEN_REPARSE_POINT 0x00200000 @@ -722,7 +736,6 @@ typedef struct smb_com_tconx_rsp_ext { #define SMB_CSC_CACHE_AUTO_REINT 0x0004 #define SMB_CSC_CACHE_VDO 0x0008 #define SMB_CSC_NO_CACHING 0x000C - #define SMB_UNIQUE_FILE_NAME 0x0010 #define SMB_EXTENDED_SIGNATURES 0x0020 @@ -806,7 +819,7 @@ typedef struct smb_com_findclose_req { #define ICOUNT_MASK 0x00FF #define PIPE_READ_MODE 0x0100 #define NAMED_PIPE_TYPE 0x0400 -#define PIPE_END_POINT 0x0800 +#define PIPE_END_POINT 0x4000 #define BLOCKING_NAMED_PIPE 0x8000 typedef struct smb_com_open_req { /* also handles create */ -- cgit v1.2.3 From 4efeb4dd3c0bf534e431a8e7c72d0afbd4cd24aa Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 12 May 2008 21:21:05 +0200 Subject: PCI: use dev_to_node in pci_call_probe to make sure get one online node. Signed-off-by: Yinghai Lu Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- drivers/pci/pci-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 72cf61ed8f96..e1637bd82b8e 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -181,7 +181,7 @@ static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev, any need to change it. */ struct mempolicy *oldpol; cpumask_t oldmask = current->cpus_allowed; - int node = pcibus_to_node(dev->bus); + int node = dev_to_node(&dev->dev); if (node >= 0) { node_to_cpumask_ptr(nodecpumask, node); -- cgit v1.2.3 From 5132861a7a44498ebb18357473f8b8d4cdc70e9f Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 22 May 2008 09:33:34 -0400 Subject: disable most mode changes on non-unix/non-cifsacl mounts CIFS currently allows you to change the mode of an inode on a share that doesn't have unix extensions enabled, and isn't using cifsacl. The inode in this case *only* has its mode changed in memory on the client. This is problematic since it can change any time the inode is purged from the cache. This patch makes cifs_setattr silently ignore most mode changes when unix extensions and cifsacl support are not enabled, and when the share is not mounted with the "dynperm" option. The exceptions are: When a mode change would remove all write access to an inode we turn on the ATTR_READONLY bit on the server and remove all write bits from the inode's mode in memory. When a mode change would add a write bit to an inode that previously had them all turned off, it turns off the ATTR_READONLY bit on the server, and resets the mode back to what it would normally be (generally, the file_mode or dir_mode of the share). Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/inode.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index fe752fdb26c3..722be543ceec 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1575,7 +1575,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) attrs->ia_valid &= ~ATTR_MODE; if (attrs->ia_valid & ATTR_MODE) { - cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode)); + cFYI(1, ("Mode changed to 0%o", attrs->ia_mode)); mode = attrs->ia_mode; } @@ -1590,18 +1590,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) #ifdef CONFIG_CIFS_EXPERIMENTAL if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) rc = mode_to_acl(inode, full_path, mode); - else if ((mode & S_IWUGO) == 0) { -#else - if ((mode & S_IWUGO) == 0) { + else #endif - /* not writeable */ - if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) { - set_dosattr = true; - time_buf.Attributes = - cpu_to_le32(cifsInode->cifsAttrs | - ATTR_READONLY); - } - } else if (cifsInode->cifsAttrs & ATTR_READONLY) { + if (((mode & S_IWUGO) == 0) && + (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { + set_dosattr = true; + time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs | + ATTR_READONLY); + /* fix up mode if we're not using dynperm */ + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0) + attrs->ia_mode = inode->i_mode & ~S_IWUGO; + } else if ((mode & S_IWUGO) && + (cifsInode->cifsAttrs & ATTR_READONLY)) { /* If file is readonly on server, we would not be able to write to it - so if any write bit is enabled for user or group or other we @@ -1612,6 +1612,20 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) /* Windows ignores set to zero */ if (time_buf.Attributes == 0) time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL); + + /* reset local inode permissions to normal */ + if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { + attrs->ia_mode &= ~(S_IALLUGO); + if (S_ISDIR(inode->i_mode)) + attrs->ia_mode |= + cifs_sb->mnt_dir_mode; + else + attrs->ia_mode |= + cifs_sb->mnt_file_mode; + } + } else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) { + /* ignore mode change - ATTR_READONLY hasn't changed */ + attrs->ia_valid &= ~ATTR_MODE; } } -- cgit v1.2.3 From 75b19b790bec3ebffbf513405b27500e22270cbc Mon Sep 17 00:00:00 2001 From: Bertram Felgenhauer Date: Fri, 30 May 2008 03:20:05 +0200 Subject: pci, x86: add workaround for bug in ASUS A7V600 BIOS (rev 1005) This BIOS claims the VIA 8237 south bridge to be compatible with VIA 586, which it is not. Without this patch, I get the following warning while booting, among others, | PCI: Using IRQ router VIA [1106/3227] at 0000:00:11.0 | ------------[ cut here ]------------ | WARNING: at arch/x86/pci/irq.c:265 pirq_via586_get+0x4a/0x60() | Modules linked in: | Pid: 1, comm: swapper Not tainted 2.6.26-rc4-00015-g1ec7d99 #1 | [] warn_on_slowpath+0x54/0x70 | [] ? vt_console_print+0x210/0x2b0 | [] ? vt_console_print+0x0/0x2b0 | [] ? __call_console_drivers+0x43/0x60 | [] ? _call_console_drivers+0x52/0x80 | [] ? release_console_sem+0x1c9/0x200 | [] ? raw_pci_read+0x41/0x70 | [] ? pci_read+0x2f/0x40 | [] pirq_via586_get+0x4a/0x60 | [] ? pirq_via586_get+0x0/0x60 | [] pcibios_lookup_irq+0x15d/0x430 | [] pcibios_irq_init+0x17a/0x3e0 | [] ? kernel_init+0x0/0x250 | [] kernel_init+0x73/0x250 | [] ? pcibios_irq_init+0x0/0x3e0 | [] ? schedule_tail+0x10/0x40 | [] ? ret_from_fork+0x6/0x1c | [] ? kernel_init+0x0/0x250 | [] ? kernel_init+0x0/0x250 | [] kernel_thread_helper+0x7/0x1c | ======================= | ---[ end trace 4eaa2a86a8e2da22 ]--- and IRQ trouble later, | irq 10: nobody cared (try booting with the "irqpoll" option) Now that's an VIA 8237 chip, so pirq_via586_get shouldn't be called at all; adding this workaround to via_router_probe() fixes the problem for me. Amazingly I have a 2.6.23.8 kernel that somehow works fine ... I'll never understand why. Signed-off-by: Bertram Felgenhauer Acked-by: Alan Cox Signed-off-by: Ingo Molnar --- arch/x86/pci/irq.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index 0908fca901bf..ca8df9c260bc 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c @@ -621,6 +621,13 @@ static __init int via_router_probe(struct irq_router *r, */ device = PCI_DEVICE_ID_VIA_8235; break; + case PCI_DEVICE_ID_VIA_8237: + /** + * Asus a7v600 bios wrongly reports 8237 + * as 586-compatible + */ + device = PCI_DEVICE_ID_VIA_8237; + break; } } -- cgit v1.2.3 From db9f600b96c16bb3c7f094e294fbdd370226ad86 Mon Sep 17 00:00:00 2001 From: Miquel van Smoorenburg Date: Wed, 28 May 2008 10:31:25 +0200 Subject: x86: pci-dma.c: use __GFP_NO_OOM instead of __GFP_NORETRY On Wed, 2008-05-28 at 04:47 +0200, Andi Kleen wrote: > > So... why not just remove the setting of __GFP_NORETRY? Why is it > > wrong to oom-kill things in this case? > > When the 16MB zone overflows (which can be common in some workloads) > calling the OOM killer is pretty useless because it has barely any > real user data [only exception would be the "only 16MB" case Alan > mentioned]. Killing random processes in this case is bad. > > I think for 16MB __GFP_NORETRY is ok because there should be > nothing freeable in there so looping is useless. Only exception would be the > "only 16MB total" case again but I'm not sure 2.6 supports that at all > on x86. > > On the other hand d_a_c() does more allocations than just 16MB, especially > on 64bit and the other zones need different strategies. Okay, so how about this then ? Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-dma.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index c5ef1af8e79d..069e843f0b93 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -397,9 +397,6 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, if (dev->dma_mask == NULL) return NULL; - /* Don't invoke OOM killer */ - gfp |= __GFP_NORETRY; - #ifdef CONFIG_X86_64 /* Why <=? Even when the mask is smaller than 4GB it is often larger than 16MB and in this case we have a chance of @@ -410,7 +407,9 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, #endif again: - page = dma_alloc_pages(dev, gfp, get_order(size)); + /* Don't invoke OOM killer or retry in lower 16MB DMA zone */ + page = dma_alloc_pages(dev, + (gfp & GFP_DMA) ? gfp | __GFP_NORETRY : gfp, get_order(size)); if (page == NULL) return NULL; -- cgit v1.2.3 From f529626a86d61897862aa1bbbb4537773209238e Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Thu, 29 May 2008 00:30:21 -0700 Subject: suspend-vs-iommu: prevent suspend if we could not resume iommu/gart support misses suspend/resume code, which can do bad stuff, including memory corruption on resume. Prevent system suspend in case we would be unable to resume. Signed-off-by: Pavel Machek Tested-by: Patrick Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-gart_64.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index c07455d1695f..aa8ec928caa8 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -548,6 +549,28 @@ static __init unsigned read_aperture(struct pci_dev *dev, u32 *size) return aper_base; } +static int gart_resume(struct sys_device *dev) +{ + return 0; +} + +static int gart_suspend(struct sys_device *dev, pm_message_t state) +{ + return -EINVAL; +} + +static struct sysdev_class gart_sysdev_class = { + .name = "gart", + .suspend = gart_suspend, + .resume = gart_resume, + +}; + +static struct sys_device device_gart = { + .id = 0, + .cls = &gart_sysdev_class, +}; + /* * Private Northbridge GATT initialization in case we cannot use the * AGP driver for some reason. @@ -558,7 +581,7 @@ static __init int init_k8_gatt(struct agp_kern_info *info) unsigned aper_base, new_aper_base; struct pci_dev *dev; void *gatt; - int i; + int i, error; printk(KERN_INFO "PCI-DMA: Disabling AGP.\n"); aper_size = aper_base = info->aper_size = 0; @@ -606,6 +629,12 @@ static __init int init_k8_gatt(struct agp_kern_info *info) pci_write_config_dword(dev, 0x90, ctl); } + + error = sysdev_class_register(&gart_sysdev_class); + if (!error) + error = sysdev_register(&device_gart); + if (error) + panic("Could not register gart_sysdev -- would corrupt data on next suspend"); flush_gart(); printk(KERN_INFO "PCI-DMA: aperture base @ %x size %u KB\n", -- cgit v1.2.3 From f20d2752980c144c82649eb18746ef0c29f508dd Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Tue, 20 May 2008 13:13:50 +0200 Subject: KVM: ia64: fix zero extending for mmio ld1/2/4 emulation in KVM Only copy in the data actually requested by the instruction emulation and zero pad the destination register first. This avoids the problem where emulated mmio access got garbled data from ld2.acq instructions in the vga console driver. Signed-off-by: Jes Sorensen Acked-by: Xiantao Zhang Signed-off-by: Avi Kivity --- arch/ia64/kvm/mmio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/ia64/kvm/mmio.c b/arch/ia64/kvm/mmio.c index 351bf70da463..7f1a858bc69f 100644 --- a/arch/ia64/kvm/mmio.c +++ b/arch/ia64/kvm/mmio.c @@ -159,7 +159,8 @@ static void mmio_access(struct kvm_vcpu *vcpu, u64 src_pa, u64 *dest, if (p->u.ioreq.state == STATE_IORESP_READY) { if (dir == IOREQ_READ) - *dest = p->u.ioreq.data; + /* it's necessary to ensure zero extending */ + *dest = p->u.ioreq.data & (~0UL >> (64-(s*8))); } else panic_vm(vcpu); out: -- cgit v1.2.3 From 33e3885de25148e00595c4dd808d6eb15db2edcf Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 21 May 2008 15:34:25 +0300 Subject: KVM: x86 emulator: fix hypercall return value on AMD The hypercall instructions on Intel and AMD are different. KVM allows the guest to choose one or the other (the default is Intel), and if the guest chooses incorrectly, KVM will patch it at runtime to select the correct instruction. This allows live migration between Intel and AMD machines. This patching occurs in the x86 emulator. The current code also executes the hypercall. Unfortunately, the tail end of the x86 emulator code also executes, overwriting the return value of the hypercall with the original contents of rax (which happens to be the hypercall number). Fix not by executing the hypercall in the emulator context; instead let the guest reissue the patched instruction and execute the hypercall via the normal path. Signed-off-by: Avi Kivity --- arch/x86/kvm/x86_emulate.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86_emulate.c b/arch/x86/kvm/x86_emulate.c index 8a96320ab071..932f216d890c 100644 --- a/arch/x86/kvm/x86_emulate.c +++ b/arch/x86/kvm/x86_emulate.c @@ -1727,7 +1727,8 @@ twobyte_insn: if (rc) goto done; - kvm_emulate_hypercall(ctxt->vcpu); + /* Let the processor re-execute the fixed hypercall */ + c->eip = ctxt->vcpu->arch.rip; /* Disable writeback. */ c->dst.type = OP_NONE; break; -- cgit v1.2.3 From b8cee18cc75d7b9dbe6c6526dfae9ab49e84fa95 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 21 May 2008 13:37:16 +0200 Subject: KVM: s390: use yield instead of schedule to implement diag 0x44 diag 0x44 is the common way on s390 to yield the cpu to the hypervisor. It is called by the guest in cpu_relax and in the spinlock code to yield to other guest cpus. This semantic is similar to yield. Lets replace the call to schedule with yield to make sure that current is really yielding. Signed-off-by: Christian Borntraeger Signed-off-by: Carsten Otte Signed-off-by: Avi Kivity --- arch/s390/kvm/diag.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c index f639a152869f..a0775e1f08df 100644 --- a/arch/s390/kvm/diag.c +++ b/arch/s390/kvm/diag.c @@ -20,7 +20,7 @@ static int __diag_time_slice_end(struct kvm_vcpu *vcpu) VCPU_EVENT(vcpu, 5, "%s", "diag time slice end"); vcpu->stat.diagnose_44++; vcpu_put(vcpu); - schedule(); + yield(); vcpu_load(vcpu); return 0; } -- cgit v1.2.3 From 74b6b522ec83f9c44fc7743f2adcb24664aa8f45 Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 21 May 2008 13:37:29 +0200 Subject: KVM: s390: fix locking order problem in enable_sie There are potential locking problem in enable_sie. We take the task_lock and the mmap_sem. As exit_mm uses the same locks vice versa, this triggers a lockdep warning. The second problem is that dup_mm and mmput might sleep, so we must not hold the task_lock at that moment. The solution is to dup the mm unconditional and use the task_lock before and afterwards to check if we can use the new mm. dup_mm and mmput are called outside the task_lock, but we run update_mm while holding the task_lock, protection us against ptrace. Signed-off-by: Christian Borntraeger Signed-off-by: Carsten Otte Acked-by: Martin Schwidefsky Signed-off-by: Avi Kivity --- arch/s390/mm/pgtable.c | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 5c1aea97cd12..3d98ba82ea67 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -254,36 +254,46 @@ void disable_noexec(struct mm_struct *mm, struct task_struct *tsk) int s390_enable_sie(void) { struct task_struct *tsk = current; - struct mm_struct *mm; - int rc; + struct mm_struct *mm, *old_mm; - task_lock(tsk); - - rc = 0; + /* Do we have pgstes? if yes, we are done */ if (tsk->mm->context.pgstes) - goto unlock; + return 0; - rc = -EINVAL; + /* lets check if we are allowed to replace the mm */ + task_lock(tsk); if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 || - tsk->mm != tsk->active_mm || tsk->mm->ioctx_list) - goto unlock; + tsk->mm != tsk->active_mm || tsk->mm->ioctx_list) { + task_unlock(tsk); + return -EINVAL; + } + task_unlock(tsk); - tsk->mm->context.pgstes = 1; /* dirty little tricks .. */ + /* we copy the mm with pgstes enabled */ + tsk->mm->context.pgstes = 1; mm = dup_mm(tsk); tsk->mm->context.pgstes = 0; - - rc = -ENOMEM; if (!mm) - goto unlock; - mmput(tsk->mm); + return -ENOMEM; + + /* Now lets check again if somebody attached ptrace etc */ + task_lock(tsk); + if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 || + tsk->mm != tsk->active_mm || tsk->mm->ioctx_list) { + mmput(mm); + task_unlock(tsk); + return -EINVAL; + } + + /* ok, we are alone. No ptrace, no threads, etc. */ + old_mm = tsk->mm; tsk->mm = tsk->active_mm = mm; preempt_disable(); update_mm(mm, tsk); cpu_set(smp_processor_id(), mm->cpu_vm_mask); preempt_enable(); - rc = 0; -unlock: task_unlock(tsk); - return rc; + mmput(old_mm); + return 0; } EXPORT_SYMBOL_GPL(s390_enable_sie); -- cgit v1.2.3 From 71cde5879f10b639506bc0b9f29a89f58b42a17e Mon Sep 17 00:00:00 2001 From: Christian Borntraeger Date: Wed, 21 May 2008 13:37:34 +0200 Subject: KVM: s390: handle machine checks when guest is running The low-level interrupt handler on s390 checks for _TIF_WORK_INT and exits the guest context, if work is pending. TIF_WORK_INT is defined as_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING. Currently the sie loop checks for signals and reschedule, but it does not check for machine checks. That means that we exit the guest context if a machine check is pending, but we do not handle the machine check. Signed-off-by: Christian Borntraeger CC: Heiko Carstens Signed-off-by: Carsten Otte Signed-off-by: Avi Kivity --- arch/s390/kvm/kvm-s390.c | 5 +++++ drivers/s390/s390mach.c | 1 + 2 files changed, 6 insertions(+) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 0ac36a649eba..40e4f2de7320 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -423,6 +423,8 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, return -EINVAL; /* not implemented yet */ } +extern void s390_handle_mcck(void); + static void __vcpu_run(struct kvm_vcpu *vcpu) { memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16); @@ -430,6 +432,9 @@ static void __vcpu_run(struct kvm_vcpu *vcpu) if (need_resched()) schedule(); + if (test_thread_flag(TIF_MCCK_PENDING)) + s390_handle_mcck(); + vcpu->arch.sie_block->icptcode = 0; local_irq_disable(); kvm_guest_enter(); diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 5080f343ad74..5bfbe7659830 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -207,6 +207,7 @@ s390_handle_mcck(void) do_exit(SIGSEGV); } } +EXPORT_SYMBOL_GPL(s390_handle_mcck); /* * returns 0 if all registers could be validated -- cgit v1.2.3 From 0ff318674503ce3787ef62d84f4d948db204b268 Mon Sep 17 00:00:00 2001 From: Carsten Otte Date: Wed, 21 May 2008 13:37:37 +0200 Subject: KVM: s390: fix interrupt delivery The current code delivers pending interrupts before it checks for need_resched. On a busy host, this can lead to a longer interrupt latency if the interrupt is injected while the process is scheduled away. This patch moves delivering the interrupt _after_ schedule(), which makes more sense. Signed-off-by: Carsten Otte Signed-off-by: Avi Kivity --- arch/s390/kvm/kvm-s390.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 40e4f2de7320..ded27c7777cc 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -435,6 +435,8 @@ static void __vcpu_run(struct kvm_vcpu *vcpu) if (test_thread_flag(TIF_MCCK_PENDING)) s390_handle_mcck(); + kvm_s390_deliver_pending_interrupts(vcpu); + vcpu->arch.sie_block->icptcode = 0; local_irq_disable(); kvm_guest_enter(); @@ -480,7 +482,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) might_sleep(); do { - kvm_s390_deliver_pending_interrupts(vcpu); __vcpu_run(vcpu); rc = kvm_handle_sie_intercept(vcpu); } while (!signal_pending(current) && !rc); -- cgit v1.2.3 From 1f0d0f094df9a570dfc26d5eb825986b7e165e1d Mon Sep 17 00:00:00 2001 From: Carsten Otte Date: Wed, 21 May 2008 13:37:40 +0200 Subject: KVM: s390: Send program check on access error If the guest accesses non-existing memory, the sie64a function returns -EFAULT. We must check the return value and send a program check to the guest if the sie instruction faulted, otherwise the guest will loop at the faulting code. Signed-off-by: Christian Borntraeger Signed-off-by: Carsten Otte Signed-off-by: Avi Kivity --- arch/s390/kvm/kvm-s390.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index ded27c7777cc..6558b09ff579 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -443,7 +443,10 @@ static void __vcpu_run(struct kvm_vcpu *vcpu) local_irq_enable(); VCPU_EVENT(vcpu, 6, "entering sie flags %x", atomic_read(&vcpu->arch.sie_block->cpuflags)); - sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs); + if (sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs)) { + VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction"); + kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); + } VCPU_EVENT(vcpu, 6, "exit sie icptcode %d", vcpu->arch.sie_block->icptcode); local_irq_disable(); -- cgit v1.2.3 From e52b2af541bcb299212a63cfa3e3231618a415be Mon Sep 17 00:00:00 2001 From: Carsten Otte Date: Wed, 21 May 2008 13:37:44 +0200 Subject: KVM: s390: Fix race condition in kvm_s390_handle_wait The call to add_timer was issued before local_int.lock was taken and before timer_due was set to 0. If the timer expires before the lock is being taken, the timer function will set timer_due to 1 and exit before the vcpu falls asleep. Depending on other external events, the vcpu might sleep forever. This fix pulls setting timer_due to the beginning of the function before add_timer, which ensures correct behavior. Signed-off-by: Carsten Otte Signed-off-by: Avi Kivity --- arch/s390/kvm/interrupt.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index fcd1ed8015c1..84a7fed4cd4e 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -339,6 +339,11 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) if (kvm_cpu_has_interrupt(vcpu)) return 0; + __set_cpu_idle(vcpu); + spin_lock_bh(&vcpu->arch.local_int.lock); + vcpu->arch.local_int.timer_due = 0; + spin_unlock_bh(&vcpu->arch.local_int.lock); + if (psw_interrupts_disabled(vcpu)) { VCPU_EVENT(vcpu, 3, "%s", "disabled wait"); __unset_cpu_idle(vcpu); @@ -366,8 +371,6 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu) no_timer: spin_lock_bh(&vcpu->arch.local_int.float_int->lock); spin_lock_bh(&vcpu->arch.local_int.lock); - __set_cpu_idle(vcpu); - vcpu->arch.local_int.timer_due = 0; add_wait_queue(&vcpu->arch.local_int.wq, &wait); while (list_empty(&vcpu->arch.local_int.list) && list_empty(&vcpu->arch.local_int.float_int->list) && -- cgit v1.2.3 From ce263d70e509287ee761f9bba519342f57b121ca Mon Sep 17 00:00:00 2001 From: Hollis Blanchard Date: Wed, 21 May 2008 18:22:51 -0500 Subject: KVM: ppc: Remove duplicate function This was left behind from some code movement. Signed-off-by: Hollis Blanchard Signed-off-by: Avi Kivity --- arch/powerpc/kvm/booke_guest.c | 33 --------------------------------- include/asm-powerpc/kvm_ppc.h | 1 + 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/arch/powerpc/kvm/booke_guest.c b/arch/powerpc/kvm/booke_guest.c index 712d89a28c46..9c8ad850c6e3 100644 --- a/arch/powerpc/kvm/booke_guest.c +++ b/arch/powerpc/kvm/booke_guest.c @@ -227,39 +227,6 @@ void kvmppc_check_and_deliver_interrupts(struct kvm_vcpu *vcpu) } } -static int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu) -{ - enum emulation_result er; - int r; - - er = kvmppc_emulate_instruction(run, vcpu); - switch (er) { - case EMULATE_DONE: - /* Future optimization: only reload non-volatiles if they were - * actually modified. */ - r = RESUME_GUEST_NV; - break; - case EMULATE_DO_MMIO: - run->exit_reason = KVM_EXIT_MMIO; - /* We must reload nonvolatiles because "update" load/store - * instructions modify register state. */ - /* Future optimization: only reload non-volatiles if they were - * actually modified. */ - r = RESUME_HOST_NV; - break; - case EMULATE_FAIL: - /* XXX Deliver Program interrupt to guest. */ - printk(KERN_EMERG "%s: emulation failed (%08x)\n", __func__, - vcpu->arch.last_inst); - r = RESUME_HOST; - break; - default: - BUG(); - } - - return r; -} - /** * kvmppc_handle_exit * diff --git a/include/asm-powerpc/kvm_ppc.h b/include/asm-powerpc/kvm_ppc.h index b35a7e3ef978..5a21115228af 100644 --- a/include/asm-powerpc/kvm_ppc.h +++ b/include/asm-powerpc/kvm_ppc.h @@ -57,6 +57,7 @@ extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu, extern int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu); +extern int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu); extern void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn, u64 asid, u32 flags); -- cgit v1.2.3 From ac3cd34e4eb9e3dccaec8e586c073ba2660b322f Mon Sep 17 00:00:00 2001 From: Hollis Blanchard Date: Wed, 21 May 2008 18:22:52 -0500 Subject: KVM: ppc: add lwzx/stwz emulation Somehow these load/store instructions got missed before, but weren't used by the guest so didn't break anything. Signed-off-by: Hollis Blanchard Signed-off-by: Christian Ehrhardt Signed-off-by: Avi Kivity --- arch/powerpc/kvm/emulate.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c index a03fe0c80698..000097461283 100644 --- a/arch/powerpc/kvm/emulate.c +++ b/arch/powerpc/kvm/emulate.c @@ -246,6 +246,11 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) case 31: switch (get_xop(inst)) { + case 23: /* lwzx */ + rt = get_rt(inst); + emulated = kvmppc_handle_load(run, vcpu, rt, 4, 1); + break; + case 83: /* mfmsr */ rt = get_rt(inst); vcpu->arch.gpr[rt] = vcpu->arch.msr; @@ -267,6 +272,13 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) kvmppc_set_msr(vcpu, vcpu->arch.gpr[rs]); break; + case 151: /* stwx */ + rs = get_rs(inst); + emulated = kvmppc_handle_store(run, vcpu, + vcpu->arch.gpr[rs], + 4, 1); + break; + case 163: /* wrteei */ vcpu->arch.msr = (vcpu->arch.msr & ~MSR_EE) | (inst & MSR_EE); -- cgit v1.2.3 From 52435b7c7a29f7dd7947c8c204494d7f52f14813 Mon Sep 17 00:00:00 2001 From: Hollis Blanchard Date: Wed, 21 May 2008 18:22:53 -0500 Subject: KVM: ppc: Remove unmatched kunmap() call We're not calling kmap() now, so we shouldn't call kunmap() either. This has no practical effect in the non-highmem case, which is why it hasn't caused more obvious problems. Pointed out by Anthony Liguori. Signed-off-by: Hollis Blanchard Signed-off-by: Avi Kivity --- arch/powerpc/kvm/44x_tlb.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c index f5d7a5eab96e..aa649c7db99b 100644 --- a/arch/powerpc/kvm/44x_tlb.c +++ b/arch/powerpc/kvm/44x_tlb.c @@ -116,8 +116,6 @@ static void kvmppc_44x_shadow_release(struct kvm_vcpu *vcpu, struct tlbe *stlbe = &vcpu->arch.shadow_tlb[index]; struct page *page = vcpu->arch.shadow_pages[index]; - kunmap(vcpu->arch.shadow_pages[index]); - if (get_tlb_v(stlbe)) { if (kvmppc_44x_tlbe_is_writable(stlbe)) kvm_release_page_dirty(page); -- cgit v1.2.3 From 905fa4b9d6e2c9fd1c9ad84e3abe83021f498f53 Mon Sep 17 00:00:00 2001 From: Hollis Blanchard Date: Wed, 21 May 2008 18:22:54 -0500 Subject: KVM: ppc: Use a read lock around MMU operations, and release it on error gfn_to_page() and kvm_release_page_clean() are called from other contexts with mmap_sem locked only for reading. Signed-off-by: Hollis Blanchard Signed-off-by: Avi Kivity --- arch/powerpc/kvm/44x_tlb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c index aa649c7db99b..1c48d6164bd5 100644 --- a/arch/powerpc/kvm/44x_tlb.c +++ b/arch/powerpc/kvm/44x_tlb.c @@ -142,18 +142,19 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn, u64 asid, stlbe = &vcpu->arch.shadow_tlb[victim]; /* Get reference to new page. */ - down_write(¤t->mm->mmap_sem); + down_read(¤t->mm->mmap_sem); new_page = gfn_to_page(vcpu->kvm, gfn); if (is_error_page(new_page)) { printk(KERN_ERR "Couldn't get guest page!\n"); kvm_release_page_clean(new_page); + up_read(¤t->mm->mmap_sem); return; } hpaddr = page_to_phys(new_page); /* Drop reference to old page. */ kvmppc_44x_shadow_release(vcpu, victim); - up_write(¤t->mm->mmap_sem); + up_read(¤t->mm->mmap_sem); vcpu->arch.shadow_pages[victim] = new_page; -- cgit v1.2.3 From 9dcb40e1aa5bfe7d6ffc729f3c2b6c8f1392d2d3 Mon Sep 17 00:00:00 2001 From: Hollis Blanchard Date: Wed, 21 May 2008 18:22:55 -0500 Subject: KVM: ppc: Report bad GFNs This code shouldn't be hit anyways, but when it is, it's useful to have a little more information about the failure. Signed-off-by: Hollis Blanchard Signed-off-by: Avi Kivity --- arch/powerpc/kvm/44x_tlb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kvm/44x_tlb.c b/arch/powerpc/kvm/44x_tlb.c index 1c48d6164bd5..75dff7cfa814 100644 --- a/arch/powerpc/kvm/44x_tlb.c +++ b/arch/powerpc/kvm/44x_tlb.c @@ -145,7 +145,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gfn_t gfn, u64 asid, down_read(¤t->mm->mmap_sem); new_page = gfn_to_page(vcpu->kvm, gfn); if (is_error_page(new_page)) { - printk(KERN_ERR "Couldn't get guest page!\n"); + printk(KERN_ERR "Couldn't get guest page for gfn %lx!\n", gfn); kvm_release_page_clean(new_page); up_read(¤t->mm->mmap_sem); return; -- cgit v1.2.3 From 2f5997140f22f68f6390c49941150d3fa8a95cb7 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Tue, 27 May 2008 12:10:20 -0300 Subject: KVM: migrate PIT timer Migrate the PIT timer to the physical CPU which vcpu0 is scheduled on, similarly to what is done for the LAPIC timers, otherwise PIT interrupts will be delayed until an unrelated event causes an exit. Signed-off-by: Marcelo Tosatti Signed-off-by: Avi Kivity --- arch/x86/kvm/i8254.c | 14 +++++++++++++- arch/x86/kvm/irq.c | 6 ++++++ arch/x86/kvm/irq.h | 2 ++ arch/x86/kvm/svm.c | 2 +- arch/x86/kvm/vmx.c | 2 +- arch/x86/kvm/x86.c | 2 +- include/linux/kvm_host.h | 2 +- 7 files changed, 25 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 7c077a9d9777..f2f5d260874e 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c @@ -200,7 +200,6 @@ int __pit_timer_fn(struct kvm_kpit_state *ps) atomic_inc(&pt->pending); smp_mb__after_atomic_inc(); - /* FIXME: handle case where the guest is in guest mode */ if (vcpu0 && waitqueue_active(&vcpu0->wq)) { vcpu0->arch.mp_state = KVM_MP_STATE_RUNNABLE; wake_up_interruptible(&vcpu0->wq); @@ -237,6 +236,19 @@ static enum hrtimer_restart pit_timer_fn(struct hrtimer *data) return HRTIMER_NORESTART; } +void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu) +{ + struct kvm_pit *pit = vcpu->kvm->arch.vpit; + struct hrtimer *timer; + + if (vcpu->vcpu_id != 0 || !pit) + return; + + timer = &pit->pit_state.pit_timer.timer; + if (hrtimer_cancel(timer)) + hrtimer_start(timer, timer->expires, HRTIMER_MODE_ABS); +} + static void destroy_pit_timer(struct kvm_kpit_timer *pt) { pr_debug("pit: execute del timer!\n"); diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c index ce1f583459b1..76d736b5f664 100644 --- a/arch/x86/kvm/irq.c +++ b/arch/x86/kvm/irq.c @@ -94,3 +94,9 @@ void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec) /* TODO: PIT, RTC etc. */ } EXPORT_SYMBOL_GPL(kvm_timer_intr_post); + +void __kvm_migrate_timers(struct kvm_vcpu *vcpu) +{ + __kvm_migrate_apic_timer(vcpu); + __kvm_migrate_pit_timer(vcpu); +} diff --git a/arch/x86/kvm/irq.h b/arch/x86/kvm/irq.h index 1802134b836f..2a15be2275c0 100644 --- a/arch/x86/kvm/irq.h +++ b/arch/x86/kvm/irq.h @@ -84,6 +84,8 @@ void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec); void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); +void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu); +void __kvm_migrate_timers(struct kvm_vcpu *vcpu); int pit_has_pending_timer(struct kvm_vcpu *vcpu); int apic_has_pending_timer(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index ab22615eee89..6b0d5fa5bab3 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -688,7 +688,7 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu) delta = vcpu->arch.host_tsc - tsc_this; svm->vmcb->control.tsc_offset += delta; vcpu->cpu = cpu; - kvm_migrate_apic_timer(vcpu); + kvm_migrate_timers(vcpu); } for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index bfe4db11989c..96445f341519 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -608,7 +608,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) if (vcpu->cpu != cpu) { vcpu_clear(vmx); - kvm_migrate_apic_timer(vcpu); + kvm_migrate_timers(vcpu); vpid_sync_vcpu_all(vmx); } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 21338bdb28ff..00acf1301a15 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2758,7 +2758,7 @@ again: if (vcpu->requests) { if (test_and_clear_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests)) - __kvm_migrate_apic_timer(vcpu); + __kvm_migrate_timers(vcpu); if (test_and_clear_bit(KVM_REQ_REPORT_TPR_ACCESS, &vcpu->requests)) { kvm_run->exit_reason = KVM_EXIT_TPR_ACCESS; diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 398978972b7a..092b1b25291d 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -297,7 +297,7 @@ static inline gpa_t gfn_to_gpa(gfn_t gfn) return (gpa_t)gfn << PAGE_SHIFT; } -static inline void kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) +static inline void kvm_migrate_timers(struct kvm_vcpu *vcpu) { set_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests); } -- cgit v1.2.3 From e693d71b46e64536581bf4884434fc1b8797e96f Mon Sep 17 00:00:00 2001 From: Eli Collins Date: Sun, 1 Jun 2008 20:24:40 -0700 Subject: KVM: VMX: Clear CR4.VMXE in hardware_disable Clear CR4.VMXE in hardware_disable. There's no reason to leave it set after doing a VMXOFF. VMware Workstation 6.5 checks CR4.VMXE as a proxy for whether the CPU is in VMX mode, so leaving VMXE set means we'll refuse to power on. With this change the user can power on after unloading the kvm-intel module. I tested on kvm-67 and kvm-69. Signed-off-by: Eli Collins Signed-off-by: Avi Kivity --- arch/x86/kvm/vmx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 96445f341519..02efbe75f317 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1036,6 +1036,7 @@ static void hardware_enable(void *garbage) static void hardware_disable(void *garbage) { asm volatile (ASM_VMX_VMXOFF : : : "cc"); + write_cr4(read_cr4() & ~X86_CR4_VMXE); } static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, -- cgit v1.2.3 From 8d2d73b9a5c35f2c6abf427afba7888cfc4cc65d Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Wed, 4 Jun 2008 18:42:24 +0300 Subject: KVM: MMU: reschedule during shadow teardown Shadows for large guests can take a long time to tear down, so reschedule occasionally to avoid softlockup warnings. Signed-off-by: Avi Kivity --- arch/x86/kvm/mmu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index 7246b60afb96..c2fd6a4a58c3 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -1858,6 +1858,7 @@ static void free_mmu_pages(struct kvm_vcpu *vcpu) sp = container_of(vcpu->kvm->arch.active_mmu_pages.next, struct kvm_mmu_page, link); kvm_mmu_zap_page(vcpu->kvm, sp); + cond_resched(); } free_page((unsigned long)vcpu->arch.mmu.pae_root); } -- cgit v1.2.3 From ff4b9df877b30b8a371d706d3552999dee450738 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Thu, 5 Jun 2008 00:08:11 -0300 Subject: KVM: IOAPIC: only set remote_irr if interrupt was injected There's a bug in the IOAPIC code for level-triggered interrupts. Its relatively easy to trigger by sharing (virtio-blk + usbtablet was the testcase, initially reported by Gerd von Egidy). The "remote_irr" variable is used to indicate accepted but not yet acked interrupts. Its cleared from the EOI handler. Problem is that the EOI handler clears remote_irr unconditionally, even if it reinjected another pending interrupt. In that case, kvm_ioapic_set_irq() proceeds to ioapic_service() which sets remote_irr even if it failed to inject (since the IRR was high due to EOI reinjection). Since the TMR bit has been cleared by the first EOI, the second one fails to clear remote_irr. End result is interrupt line dead. Fix it by setting remote_irr only if a new pending interrupt has been generated (and the TMR bit for vector in question set). Signed-off-by: Marcelo Tosatti Signed-off-by: Avi Kivity --- virt/kvm/ioapic.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 4232fd75dd20..98778cb69c6e 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c @@ -45,7 +45,7 @@ #else #define ioapic_debug(fmt, arg...) #endif -static void ioapic_deliver(struct kvm_ioapic *vioapic, int irq); +static int ioapic_deliver(struct kvm_ioapic *vioapic, int irq); static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic, unsigned long addr, @@ -89,8 +89,8 @@ static void ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx) pent = &ioapic->redirtbl[idx]; if (!pent->fields.mask) { - ioapic_deliver(ioapic, idx); - if (pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) + int injected = ioapic_deliver(ioapic, idx); + if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) pent->fields.remote_irr = 1; } if (!pent->fields.trig_mode) @@ -133,7 +133,7 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) } } -static void ioapic_inj_irq(struct kvm_ioapic *ioapic, +static int ioapic_inj_irq(struct kvm_ioapic *ioapic, struct kvm_vcpu *vcpu, u8 vector, u8 trig_mode, u8 delivery_mode) { @@ -143,7 +143,7 @@ static void ioapic_inj_irq(struct kvm_ioapic *ioapic, ASSERT((delivery_mode == IOAPIC_FIXED) || (delivery_mode == IOAPIC_LOWEST_PRIORITY)); - kvm_apic_set_irq(vcpu, vector, trig_mode); + return kvm_apic_set_irq(vcpu, vector, trig_mode); } static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest, @@ -186,7 +186,7 @@ static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest, return mask; } -static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq) +static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) { u8 dest = ioapic->redirtbl[irq].fields.dest_id; u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode; @@ -195,7 +195,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq) u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode; u32 deliver_bitmask; struct kvm_vcpu *vcpu; - int vcpu_id; + int vcpu_id, r = 0; ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " "vector=%x trig_mode=%x\n", @@ -204,7 +204,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq) deliver_bitmask = ioapic_get_delivery_bitmask(ioapic, dest, dest_mode); if (!deliver_bitmask) { ioapic_debug("no target on destination\n"); - return; + return 0; } switch (delivery_mode) { @@ -216,7 +216,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq) vcpu = ioapic->kvm->vcpus[0]; #endif if (vcpu != NULL) - ioapic_inj_irq(ioapic, vcpu, vector, + r = ioapic_inj_irq(ioapic, vcpu, vector, trig_mode, delivery_mode); else ioapic_debug("null lowest prio vcpu: " @@ -234,7 +234,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq) deliver_bitmask &= ~(1 << vcpu_id); vcpu = ioapic->kvm->vcpus[vcpu_id]; if (vcpu) { - ioapic_inj_irq(ioapic, vcpu, vector, + r = ioapic_inj_irq(ioapic, vcpu, vector, trig_mode, delivery_mode); } } @@ -246,6 +246,7 @@ static void ioapic_deliver(struct kvm_ioapic *ioapic, int irq) delivery_mode); break; } + return r; } void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) -- cgit v1.2.3 From ebb0e6264c7a65c51feb3575e9edb58eab0cf469 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 20 May 2008 16:21:58 +0300 Subject: KVM: MMU: Fix printk() format string Signed-off-by: Avi Kivity --- arch/x86/kvm/paging_tmpl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 156fe10288ae..934c7b619396 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -418,7 +418,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, /* mmio */ if (is_error_pfn(pfn)) { - pgprintk("gfn %x is mmio\n", walker.gfn); + pgprintk("gfn %lx is mmio\n", walker.gfn); kvm_release_pfn_clean(pfn); return 1; } -- cgit v1.2.3 From 3c9155106d589584f67b026ec444e69c4a68d7dc Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 20 May 2008 16:21:13 +0300 Subject: KVM: MMU: Fix is_empty_shadow_page() check The check is only looking at one of two possible empty ptes. Signed-off-by: Avi Kivity --- arch/x86/kvm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index c2fd6a4a58c3..ee3f53098f0c 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -658,7 +658,7 @@ static int is_empty_shadow_page(u64 *spt) u64 *end; for (pos = spt, end = pos + PAGE_SIZE / sizeof(u64); pos != end; pos++) - if (*pos != shadow_trap_nonpresent_pte) { + if (is_shadow_present_pte(*pos)) { printk(KERN_ERR "%s: %p %llx\n", __func__, pos, *pos); return 0; -- cgit v1.2.3 From ea177305b321a4127e448b88de20d5792682ace1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 2 Jun 2008 17:51:23 -0400 Subject: ipw2200: queue direct scans When another scan is in progress, a direct scan gets dropped on the floor. However, that direct scan is usually the scan that's really needed by userspace, and gets stomped on by all the broadcast scans the ipw2200 driver issues internally. Make sure the direct scan happens eventually, and as a bonus ensure that the passive scan worker is cleaned up when appropriate. The change of request_passive_scan form a struct work to struct delayed_work is only to make the set_wx_scan() code a bit simpler, it's still only used with a delay of 0 to match previous behavior. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 176 +++++++++++++++++++---------------------- drivers/net/wireless/ipw2200.h | 6 +- 2 files changed, 87 insertions(+), 95 deletions(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 729336774828..6e704608947c 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1753,6 +1753,8 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) if (priv->workqueue) { cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); cancel_delayed_work(&priv->scan_event); } queue_work(priv->workqueue, &priv->down); @@ -2005,6 +2007,8 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) wake_up_interruptible(&priv->wait_command_queue); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); cancel_delayed_work(&priv->scan_event); schedule_work(&priv->link_down); queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); @@ -4712,6 +4716,12 @@ static void ipw_rx_notification(struct ipw_priv *priv, priv->status &= ~STATUS_SCAN_FORCED; #endif /* CONFIG_IPW2200_MONITOR */ + /* Do queued direct scans first */ + if (priv->status & STATUS_DIRECT_SCAN_PENDING) { + queue_delayed_work(priv->workqueue, + &priv->request_direct_scan, 0); + } + if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING | STATUS_ROAMING | @@ -6267,7 +6277,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, } } -static int ipw_request_scan_helper(struct ipw_priv *priv, int type) +static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) { struct ipw_scan_request_ext scan; int err = 0, scan_type; @@ -6278,22 +6288,31 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type) mutex_lock(&priv->mutex); + if (direct && (priv->direct_scan_ssid_len == 0)) { + IPW_DEBUG_HC("Direct scan requested but no SSID to scan for\n"); + priv->status &= ~STATUS_DIRECT_SCAN_PENDING; + goto done; + } + if (priv->status & STATUS_SCANNING) { - IPW_DEBUG_HC("Concurrent scan requested. Ignoring.\n"); - priv->status |= STATUS_SCAN_PENDING; + IPW_DEBUG_HC("Concurrent scan requested. Queuing.\n"); + priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING : + STATUS_SCAN_PENDING; goto done; } if (!(priv->status & STATUS_SCAN_FORCED) && priv->status & STATUS_SCAN_ABORTING) { IPW_DEBUG_HC("Scan request while abort pending. Queuing.\n"); - priv->status |= STATUS_SCAN_PENDING; + priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING : + STATUS_SCAN_PENDING; goto done; } if (priv->status & STATUS_RF_KILL_MASK) { - IPW_DEBUG_HC("Aborting scan due to RF Kill activation\n"); - priv->status |= STATUS_SCAN_PENDING; + IPW_DEBUG_HC("Queuing scan due to RF Kill activation\n"); + priv->status |= direct ? STATUS_DIRECT_SCAN_PENDING : + STATUS_SCAN_PENDING; goto done; } @@ -6321,6 +6340,7 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type) cpu_to_le16(20); scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120); + scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20); #ifdef CONFIG_IPW2200_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { @@ -6360,13 +6380,23 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type) cpu_to_le16(2000); } else { #endif /* CONFIG_IPW2200_MONITOR */ - /* If we are roaming, then make this a directed scan for the - * current network. Otherwise, ensure that every other scan - * is a fast channel hop scan */ - if ((priv->status & STATUS_ROAMING) - || (!(priv->status & STATUS_ASSOCIATED) - && (priv->config & CFG_STATIC_ESSID) - && (le32_to_cpu(scan.full_scan_index) % 2))) { + /* Honor direct scans first, otherwise if we are roaming make + * this a direct scan for the current network. Finally, + * ensure that every other scan is a fast channel hop scan */ + if (direct) { + err = ipw_send_ssid(priv, priv->direct_scan_ssid, + priv->direct_scan_ssid_len); + if (err) { + IPW_DEBUG_HC("Attempt to send SSID command " + "failed\n"); + goto done; + } + + scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; + } else if ((priv->status & STATUS_ROAMING) + || (!(priv->status & STATUS_ASSOCIATED) + && (priv->config & CFG_STATIC_ESSID) + && (le32_to_cpu(scan.full_scan_index) % 2))) { err = ipw_send_ssid(priv, priv->essid, priv->essid_len); if (err) { IPW_DEBUG_HC("Attempt to send SSID command " @@ -6391,7 +6421,12 @@ send_request: } priv->status |= STATUS_SCANNING; - priv->status &= ~STATUS_SCAN_PENDING; + if (direct) { + priv->status &= ~STATUS_DIRECT_SCAN_PENDING; + priv->direct_scan_ssid_len = 0; + } else + priv->status &= ~STATUS_SCAN_PENDING; + queue_delayed_work(priv->workqueue, &priv->scan_check, IPW_SCAN_CHECK_WATCHDOG); done: @@ -6402,15 +6437,22 @@ done: static void ipw_request_passive_scan(struct work_struct *work) { struct ipw_priv *priv = - container_of(work, struct ipw_priv, request_passive_scan); - ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE); + container_of(work, struct ipw_priv, request_passive_scan.work); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE, 0); } static void ipw_request_scan(struct work_struct *work) { struct ipw_priv *priv = container_of(work, struct ipw_priv, request_scan.work); - ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 0); +} + +static void ipw_request_direct_scan(struct work_struct *work) +{ + struct ipw_priv *priv = + container_of(work, struct ipw_priv, request_direct_scan.work); + ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE, 1); } static void ipw_bg_abort_scan(struct work_struct *work) @@ -9477,99 +9519,38 @@ static int ipw_wx_get_retry(struct net_device *dev, return 0; } -static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid, - int essid_len) -{ - struct ipw_scan_request_ext scan; - int err = 0, scan_type; - - if (!(priv->status & STATUS_INIT) || - (priv->status & STATUS_EXIT_PENDING)) - return 0; - - mutex_lock(&priv->mutex); - - if (priv->status & STATUS_RF_KILL_MASK) { - IPW_DEBUG_HC("Aborting scan due to RF kill activation\n"); - priv->status |= STATUS_SCAN_PENDING; - goto done; - } - - IPW_DEBUG_HC("starting request direct scan!\n"); - - if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) { - /* We should not sleep here; otherwise we will block most - * of the system (for instance, we hold rtnl_lock when we - * get here). - */ - err = -EAGAIN; - goto done; - } - memset(&scan, 0, sizeof(scan)); - - if (priv->config & CFG_SPEED_SCAN) - scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = - cpu_to_le16(30); - else - scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = - cpu_to_le16(20); - - scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = - cpu_to_le16(20); - scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120); - scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20); - - scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); - - err = ipw_send_ssid(priv, essid, essid_len); - if (err) { - IPW_DEBUG_HC("Attempt to send SSID command failed\n"); - goto done; - } - scan_type = IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN; - - ipw_add_scan_channels(priv, &scan, scan_type); - - err = ipw_send_scan_request_ext(priv, &scan); - if (err) { - IPW_DEBUG_HC("Sending scan command failed: %08X\n", err); - goto done; - } - - priv->status |= STATUS_SCANNING; - - done: - mutex_unlock(&priv->mutex); - return err; -} - static int ipw_wx_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); struct iw_scan_req *req = (struct iw_scan_req *)extra; + struct delayed_work *work = NULL; mutex_lock(&priv->mutex); + priv->user_requested_scan = 1; - mutex_unlock(&priv->mutex); if (wrqu->data.length == sizeof(struct iw_scan_req)) { if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { - ipw_request_direct_scan(priv, req->essid, - req->essid_len); - return 0; - } - if (req->scan_type == IW_SCAN_TYPE_PASSIVE) { - queue_work(priv->workqueue, - &priv->request_passive_scan); - return 0; + int len = min((int)req->essid_len, + (int)sizeof(priv->direct_scan_ssid)); + memcpy(priv->direct_scan_ssid, req->essid, len); + priv->direct_scan_ssid_len = len; + work = &priv->request_direct_scan; + } else if (req->scan_type == IW_SCAN_TYPE_PASSIVE) { + work = &priv->request_passive_scan; } + } else { + /* Normal active broadcast scan */ + work = &priv->request_scan; } + mutex_unlock(&priv->mutex); + IPW_DEBUG_WX("Start scan\n"); - queue_delayed_work(priv->workqueue, &priv->request_scan, 0); + queue_delayed_work(priv->workqueue, work, 0); return 0; } @@ -10731,6 +10712,8 @@ static void ipw_link_up(struct ipw_priv *priv) } cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); cancel_delayed_work(&priv->scan_event); ipw_reset_stats(priv); /* Ensure the rate is updated immediately */ @@ -10761,6 +10744,8 @@ static void ipw_link_down(struct ipw_priv *priv) /* Cancel any queued work ... */ cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); cancel_delayed_work(&priv->adhoc_check); cancel_delayed_work(&priv->gather_stats); @@ -10800,8 +10785,9 @@ static int __devinit ipw_setup_deferred_work(struct ipw_priv *priv) INIT_WORK(&priv->up, ipw_bg_up); INIT_WORK(&priv->down, ipw_bg_down); INIT_DELAYED_WORK(&priv->request_scan, ipw_request_scan); + INIT_DELAYED_WORK(&priv->request_direct_scan, ipw_request_direct_scan); + INIT_DELAYED_WORK(&priv->request_passive_scan, ipw_request_passive_scan); INIT_DELAYED_WORK(&priv->scan_event, ipw_scan_event); - INIT_WORK(&priv->request_passive_scan, ipw_request_passive_scan); INIT_DELAYED_WORK(&priv->gather_stats, ipw_bg_gather_stats); INIT_WORK(&priv->abort_scan, ipw_bg_abort_scan); INIT_WORK(&priv->roam, ipw_bg_roam); @@ -11835,6 +11821,8 @@ static void __devexit ipw_pci_remove(struct pci_dev *pdev) cancel_delayed_work(&priv->adhoc_check); cancel_delayed_work(&priv->gather_stats); cancel_delayed_work(&priv->request_scan); + cancel_delayed_work(&priv->request_direct_scan); + cancel_delayed_work(&priv->request_passive_scan); cancel_delayed_work(&priv->scan_event); cancel_delayed_work(&priv->rf_kill); cancel_delayed_work(&priv->scan_check); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index cd3295b66dd6..d4ab28b73b32 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1037,6 +1037,7 @@ struct ipw_cmd { /* XXX */ #define STATUS_DISASSOC_PENDING (1<<12) #define STATUS_STATE_PENDING (1<<13) +#define STATUS_DIRECT_SCAN_PENDING (1<<19) #define STATUS_SCAN_PENDING (1<<20) #define STATUS_SCANNING (1<<21) #define STATUS_SCAN_ABORTING (1<<22) @@ -1292,6 +1293,8 @@ struct ipw_priv { struct iw_public_data wireless_data; int user_requested_scan; + u8 direct_scan_ssid[IW_ESSID_MAX_SIZE]; + u8 direct_scan_ssid_len; struct workqueue_struct *workqueue; @@ -1301,8 +1304,9 @@ struct ipw_priv { struct work_struct system_config; struct work_struct rx_replenish; struct delayed_work request_scan; + struct delayed_work request_direct_scan; + struct delayed_work request_passive_scan; struct delayed_work scan_event; - struct work_struct request_passive_scan; struct work_struct adapter_restart; struct delayed_work rf_kill; struct work_struct up; -- cgit v1.2.3 From 507b06d0622480f8026d49a94f86068bb0fd6ed6 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 3 Jun 2008 23:39:55 -0400 Subject: mac80211: send association event on IBSS create Otherwise userspace has no idea the IBSS creation succeeded. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 841278f1df8e..af375da9df21 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2336,6 +2336,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, u8 *pos; struct ieee80211_sub_if_data *sdata; struct ieee80211_supported_band *sband; + union iwreq_data wrqu; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; @@ -2479,6 +2480,10 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, ifsta->state = IEEE80211_IBSS_JOINED; mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); + memset(&wrqu, 0, sizeof(wrqu)); + memcpy(wrqu.ap_addr.sa_data, bss->bssid, ETH_ALEN); + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); + return res; } -- cgit v1.2.3 From a01f5450401f081f07a866612121e780e0730cfd Mon Sep 17 00:00:00 2001 From: Holger Schurig Date: Wed, 4 Jun 2008 11:10:40 +0200 Subject: libertas: fix sleep confirmation This fixes an issus that made "iwconfig eth1 power on" non-working. When we get a "PS sleep" event, we have to confirm this to the firmware. The confirm happens with a command, but this command is special: the firmware won't send us a response. if_cs_host_to_card() is setting priv->dnld_sent anyway, so this variable stayed at DNLD_DATA_SENT and was never cleared back. Now I put the special knowledge that the CMD_802_11_PS_MODE with CMD_SUBCMD_SLEEP_CONFIRMED doesn't need to need a response by directly clearing the dnld_sent state in lbs_send_confirmsleep(). Signed-off-by: Holger Schurig Acked-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/cmd.c | 5 ++++- drivers/net/wireless/libertas/main.c | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 6328b9593877..8124fd9b1353 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -1842,6 +1842,9 @@ static void lbs_send_confirmsleep(struct lbs_private *priv) spin_lock_irqsave(&priv->driver_lock, flags); + /* We don't get a response on the sleep-confirmation */ + priv->dnld_sent = DNLD_RES_RECEIVED; + /* If nothing to do, go back to sleep (?) */ if (!__kfifo_len(priv->event_fifo) && !priv->resp_len[priv->resp_idx]) priv->psstate = PS_STATE_SLEEP; @@ -1904,12 +1907,12 @@ void lbs_ps_confirm_sleep(struct lbs_private *priv) lbs_deb_enter(LBS_DEB_HOST); + spin_lock_irqsave(&priv->driver_lock, flags); if (priv->dnld_sent) { allowed = 0; lbs_deb_host("dnld_sent was set\n"); } - spin_lock_irqsave(&priv->driver_lock, flags); /* In-progress command? */ if (priv->cur_cmd) { allowed = 0; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e1f066068590..acfc4bfcc262 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -732,8 +732,8 @@ static int lbs_thread(void *data) lbs_deb_thread("4: currenttxskb %p, dnld_sent %d\n", priv->currenttxskb, priv->dnld_sent); - spin_lock_irq(&priv->driver_lock); /* Process any pending command response */ + spin_lock_irq(&priv->driver_lock); resp_idx = priv->resp_idx; if (priv->resp_len[resp_idx]) { spin_unlock_irq(&priv->driver_lock); -- cgit v1.2.3 From ad81b2f97d42e13ef78bb3798e046cd5f0492980 Mon Sep 17 00:00:00 2001 From: Assaf Krauss Date: Wed, 4 Jun 2008 20:27:59 +0300 Subject: mac80211: Fixing slow IBSS rejoin This patch fixes the issue of slow reconnection to an IBSS cell after disconnection from it. Now the interface's bssid is reset upon ifdown. ieee80211_sta_find_ibss: if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 && (bss = ieee80211_rx_bss_get(dev, bssid, local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len))) Note: In general disconnection is still not handled properly in mac80211 Signed-off-by: Assaf Krauss Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- net/mac80211/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 5c876450b14c..98c0b5e56ecc 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -511,6 +511,7 @@ static int ieee80211_stop(struct net_device *dev) case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: sdata->u.sta.state = IEEE80211_DISABLED; + memset(sdata->u.sta.bssid, 0, ETH_ALEN); del_timer_sync(&sdata->u.sta.timer); /* * When we get here, the interface is marked down. -- cgit v1.2.3 From d005b1d042a1d5dcd8d898f26d8d9bb03f865284 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 5 Jun 2008 16:55:10 +0200 Subject: zd1211rw: Fix data padding for QoS This patch fixes a data alignment issue in the zd1211rw driver. The IEEE80211_STYPE_QOS_DATA bit should be used as a bitwise test to test for the presence of the 2 byte QoS control field. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/zd1211rw/zd_mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 6424e5a2c83d..418606ac1c3b 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -719,7 +719,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) fc = le16_to_cpu(*((__le16 *) buffer)); is_qos = ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_QOS_DATA); + (fc & IEEE80211_STYPE_QOS_DATA); is_4addr = (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS); need_padding = is_qos ^ is_4addr; -- cgit v1.2.3 From 872ba53395b2a8be08c3ea2d39e225e5b4a8cb40 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 4 Jun 2008 13:59:34 -0400 Subject: mac80211: decrease IBSS creation latency Sufficient scans (at least 2 or 3) should have been done within 7 seconds to find an existing IBSS to join. This should improve IBSS creation latency; and since IBSS merging is still in effect, shouldn't have detrimental effects on eventual IBSS convergence. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index af375da9df21..affe42f8484c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -44,7 +44,7 @@ #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) #define IEEE80211_SCAN_INTERVAL (2 * HZ) #define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ) -#define IEEE80211_IBSS_JOIN_TIMEOUT (20 * HZ) +#define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ) #define IEEE80211_PROBE_DELAY (HZ / 33) #define IEEE80211_CHANNEL_TIME (HZ / 33) -- cgit v1.2.3 From be038b376465953c358d675cb38a611898a49dc2 Mon Sep 17 00:00:00 2001 From: Assaf Krauss Date: Thu, 5 Jun 2008 19:55:21 +0300 Subject: mac80211: Checking IBSS support while changing channel in ad-hoc mode This patch adds a check to the set_channel flow. When attempting to change the channel while in IBSS mode, and the new channel does not support IBSS mode, the flow return with an error value with no consequences on the mac80211 and driver state. Signed-off-by: Assaf Krauss Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/mlme.c | 11 ++++------- net/mac80211/wext.c | 15 +++++++++++---- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c7314bf4bec2..006486b26726 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -899,7 +899,7 @@ extern const struct iw_handler_def ieee80211_iw_handler_def; /* ieee80211_ioctl.c */ -int ieee80211_set_freq(struct ieee80211_local *local, int freq); +int ieee80211_set_freq(struct net_device *dev, int freq); /* ieee80211_sta.c */ void ieee80211_sta_timer(unsigned long data); void ieee80211_sta_work(struct work_struct *work); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index affe42f8484c..4d2b582dd055 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2359,13 +2359,10 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, sdata->drop_unencrypted = bss->capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; - res = ieee80211_set_freq(local, bss->freq); + res = ieee80211_set_freq(dev, bss->freq); - if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) { - printk(KERN_DEBUG "%s: IBSS not allowed on frequency " - "%d MHz\n", dev->name, local->oper_channel->center_freq); - return -1; - } + if (res) + return res; /* Set beacon template */ skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); @@ -3491,7 +3488,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, spin_unlock_bh(&local->sta_bss_lock); if (selected) { - ieee80211_set_freq(local, selected->freq); + ieee80211_set_freq(dev, selected->freq); if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) ieee80211_sta_set_ssid(dev, selected->ssid, selected->ssid_len); diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 8311bb24f9f3..a8bb8e31b1ec 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -290,14 +290,22 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev, return 0; } -int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz) +int ieee80211_set_freq(struct net_device *dev, int freqMHz) { int ret = -EINVAL; struct ieee80211_channel *chan; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); chan = ieee80211_get_channel(local->hw.wiphy, freqMHz); if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && + chan->flags & IEEE80211_CHAN_NO_IBSS) { + printk(KERN_DEBUG "%s: IBSS not allowed on frequency " + "%d MHz\n", dev->name, chan->center_freq); + return ret; + } local->oper_channel = chan; if (local->sta_sw_scanning || local->sta_hw_scanning) @@ -315,7 +323,6 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->vif.type == IEEE80211_IF_TYPE_STA) @@ -329,14 +336,14 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, IEEE80211_STA_AUTO_CHANNEL_SEL; return 0; } else - return ieee80211_set_freq(local, + return ieee80211_set_freq(dev, ieee80211_channel_to_frequency(freq->m)); } else { int i, div = 1000000; for (i = 0; i < freq->e; i++) div /= 10; if (div > 0) - return ieee80211_set_freq(local, freq->m / div); + return ieee80211_set_freq(dev, freq->m / div); else return -EINVAL; } -- cgit v1.2.3 From 585c5434f0e02ff0ffc567ec223af61e2d8e2e88 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 5 Jun 2008 21:29:49 +0300 Subject: include/linux/ssb/ssb_driver_gige.h typo fix This patch fixes a typo in the name of a config variable. Reported-by: Robert P. J. Day Signed-off-by: Adrian Bunk Reviewed-by: Michael Buesch Signed-off-by: John W. Linville --- include/linux/ssb/ssb_driver_gige.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/ssb/ssb_driver_gige.h b/include/linux/ssb/ssb_driver_gige.h index 01fbdf5fef22..942e38736901 100644 --- a/include/linux/ssb/ssb_driver_gige.h +++ b/include/linux/ssb/ssb_driver_gige.h @@ -100,7 +100,7 @@ extern char * nvram_get(const char *name); /* Get the device MAC address */ static inline void ssb_gige_get_macaddr(struct pci_dev *pdev, u8 *macaddr) { -#ifdef CONFIG_BCM947XX +#ifdef CONFIG_BCM47XX char *res = nvram_get("et0macaddr"); if (res) memcpy(macaddr, res, 6); -- cgit v1.2.3 From b6b16196b064bbff83e8161359f8b73465d4aa36 Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Sun, 8 Jun 2008 13:13:06 +0200 Subject: iwlwifi: fix oops in iwl3945_led_brightness_set fix race between: ieee80211_open->ieee80211_led_radio->led_trigger_event->led_set_brightness->iwl3945_led_brightness_set (which assumes that "led->priv" is not NULL) and iwl3945_pci_probe->iwl3945_setup_deferred_work->(...)->iwl3945_bg_alive_start->iwl3945_alive_start->iwl3945_led_register->iwl3945_led_register_led which sets priv field in struct iwl3945_led after led->led_dev.brightness_set = iwl3945_led_brightness_set; (...) led_classdev_register(device, &led->led_dev); http://kerneloops.org/guilty.php?guilty=iwl3945_led_brightness_set&version=2.6.25-release&start=1671168&end=1703935&class=oops Signed-off-by: Marcin Slusarz Cc: Zhu Yi Cc: Reinette Chatre Cc: Tomas Winkler Cc: linux-wireless@vger.kernel.org Cc: ipw3945-devel@lists.sourceforge.net Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-led.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index d200d08fb086..8b1528e52d43 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -229,14 +229,15 @@ static int iwl3945_led_register_led(struct iwl3945_priv *priv, led->led_dev.brightness_set = iwl3945_led_brightness_set; led->led_dev.default_trigger = trigger; + led->priv = priv; + led->type = type; + ret = led_classdev_register(device, &led->led_dev); if (ret) { IWL_ERROR("Error: failed to register led handler.\n"); return ret; } - led->priv = priv; - led->type = type; led->registered = 1; if (set_led && led->led_on) -- cgit v1.2.3 From 2bd3ed0479c35f7c8dadecf72b725ca0c20ea015 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 9 Jun 2008 15:39:55 -0700 Subject: tg3: Fix 5714S / 5715S / 5780S link failures The git commit ef167e27039eeaea6d3cdd5c547b082e89840bdd entitled "Fix supporting flowctrl code" introduced a bug that prevents 5714S, 5715S and 5780S devices from falling back to a forced link mode. The problem is that the added flow control check will always fail if flow control is set to autoneg and either RX or TX (or both) flow control is enabled. The driver defaults to setting flow control to autoneg and advertises both RX and TX flow control. The fix is to remove the errant check. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 07b3f77e7626..4c248d79ee44 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3168,8 +3168,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) err |= tg3_readphy(tp, MII_BMCR, &bmcr); if ((tp->link_config.autoneg == AUTONEG_ENABLE) && !force_reset && - (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) && - tp->link_config.flowctrl == tp->link_config.active_flowctrl) { + (tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT)) { /* do nothing, just check for link up at the end */ } else if (tp->link_config.autoneg == AUTONEG_ENABLE) { u32 adv, new_adv; -- cgit v1.2.3 From 0ba11fb307a4f18c11df6f5f255158ce055a2a16 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 9 Jun 2008 15:40:26 -0700 Subject: tg3: Fix a flags typo This patch fixes a problem where the TG3_FLAG_10_100_ONLY flag was testing against the wrong flags variable. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 4c248d79ee44..c12931829439 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8598,7 +8598,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) (cmd->speed == SPEED_1000)) return -EINVAL; else if ((cmd->speed == SPEED_1000) && - (tp->tg3_flags2 & TG3_FLAG_10_100_ONLY)) + (tp->tg3_flags & TG3_FLAG_10_100_ONLY)) return -EINVAL; tg3_full_lock(tp, 0); -- cgit v1.2.3 From 5f0c4a3cb6fda7c505f8c916b54ea90205feed68 Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 9 Jun 2008 15:41:12 -0700 Subject: tg3: Fix 5761 WOL On 5761 non-e devices, two problems prevent the administrator from overriding the WOL settings in the device's NVRAM. The first problem is that GPIO 0 and GPIO 2 have been swapped. This change prevented the administrator from turning on WOL when it is disabled in NVRAM. The fix is to add a new path for the 5761 that swaps the two GPIOs in the code as well. The second problem is that GPIO 1 could not be toggled by the driver because the GPIO is shared with the debug UART GPIO. This will prevent the administrator from being able to turn WOL off if it was enabled in NVRAM. The fix is to always disable the debug UART after a GRC reset. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index c12931829439..f8ce87344b27 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1295,6 +1295,21 @@ static void tg3_frob_aux_power(struct tg3 *tp) GRC_LCLCTRL_GPIO_OUTPUT0 | GRC_LCLCTRL_GPIO_OUTPUT1), 100); + } else if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) { + /* The 5761 non-e device swaps GPIO 0 and GPIO 2. */ + u32 grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 | + GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OE2 | + GRC_LCLCTRL_GPIO_OUTPUT0 | + GRC_LCLCTRL_GPIO_OUTPUT1 | + tp->grc_local_ctrl; + tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100); + + grc_local_ctrl |= GRC_LCLCTRL_GPIO_OUTPUT2; + tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100); + + grc_local_ctrl &= ~GRC_LCLCTRL_GPIO_OUTPUT0; + tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100); } else { u32 no_gpio2; u32 grc_local_ctrl = 0; @@ -11767,6 +11782,15 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL; + if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) { + /* Turn off the debug UART. */ + tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL; + if (tp->tg3_flags2 & TG3_FLG2_IS_NIC) + /* Keep VMain power. */ + tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE0 | + GRC_LCLCTRL_GPIO_OUTPUT0; + } + /* Force the chip into D0. */ err = tg3_set_power_state(tp, PCI_D0); if (err) { -- cgit v1.2.3 From 1b84d9462a93ccfa99f725aad744ab4d1af8402b Mon Sep 17 00:00:00 2001 From: Matt Carlson Date: Mon, 9 Jun 2008 15:41:33 -0700 Subject: tg3: Update version to 3.92.1 This patch increments the version to 3.92.1. Signed-off-by: Matt Carlson Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f8ce87344b27..cc4bde852542 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -64,8 +64,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.92" -#define DRV_MODULE_RELDATE "May 2, 2008" +#define DRV_MODULE_VERSION "3.92.1" +#define DRV_MODULE_RELDATE "June 9, 2008" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v1.2.3 From 1420a4faee7086b6811b4a1f0672e32b5a6df80e Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 9 Jun 2008 15:47:38 -0700 Subject: irda: net/irda build fix: mcs7780 -tip testing found the following build error: drivers/built-in.o: In function `mcs_receive_irq': mcs7780.c:(.text+0x4e429): undefined reference to `crc32_le' drivers/built-in.o: In function `mcs_hard_xmit': mcs7780.c:(.text+0x4e9af): undefined reference to `crc32_le' with: http://redhat.com/~mingo/misc/config-Sun_Jun__8_22_56_14_CEST_2008.bad the reason is a missing enablement of the CRC32 library in the Kconfig. Signed-off-by: Ingo Molnar Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index ce816ba9c40d..e6317557a531 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -329,6 +329,7 @@ config PXA_FICP config MCS_FIR tristate "MosChip MCS7780 IrDA-USB dongle" depends on IRDA && USB && EXPERIMENTAL + select CRC32 help Say Y or M here if you want to build support for the MosChip MCS7780 IrDA-USB bridge device driver. -- cgit v1.2.3 From 2e761e0532a784816e7e822dbaaece8c5d4be14d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 9 Jun 2008 15:53:30 -0700 Subject: ipv6 netns: init net is used to set bindv6only for new sock The bindv6only is tuned via sysctl. It is already on a struct net and per-net sysctls allow for its modification (ipv6_sysctl_net_init). Despite this the value configured in the init net is used for the rest of them. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/af_inet6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 3c6aafb02183..e84b3fd17fb4 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -191,7 +191,7 @@ lookup_protocol: np->mcast_hops = -1; np->mc_loop = 1; np->pmtudisc = IPV6_PMTUDISC_WANT; - np->ipv6only = init_net.ipv6.sysctl.bindv6only; + np->ipv6only = net->ipv6.sysctl.bindv6only; /* Init the ipv4 part of the socket since we can have sockets * using v6 API for ipv4. -- cgit v1.2.3 From 148f1678f0ba7a5e79e44ff23064d4326fa145a4 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 10 Jun 2008 10:03:18 +0200 Subject: [S390] sparsemem: use SPARSEMEM_STATIC if !64BIT. In case of !64BIT kernel we end up with a zero sized mem_section array. This happens because NR_MEM_SECTIONS is smaller than SECTIONS_PER_ROOT but we have: #define NR_SECTION_ROOTS (NR_MEM_SECTIONS / SECTIONS_PER_ROOT) and struct mem_section *mem_section[NR_SECTION_ROOTS]; So fix this by selecting SPARSEMEM_STATIC which makes sure that SECTIONS_PER_ROOT is 1. Cc: Gerald Schaefer Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 93acb3c1859d..107e492cb47e 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -304,6 +304,7 @@ config ARCH_SPARSEMEM_ENABLE def_bool y select SPARSEMEM_VMEMMAP_ENABLE select SPARSEMEM_VMEMMAP + select SPARSEMEM_STATIC if !64BIT config ARCH_SPARSEMEM_DEFAULT def_bool y -- cgit v1.2.3 From 12829126aa47758608578cc5be3a5adffc3d4b09 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 10 Jun 2008 10:03:19 +0200 Subject: [S390] cio: Fix sparse warnings in blacklist.c. sparse complains about signedness: drivers/s390/cio/blacklist.c:132:28: warning: incorrect type in argument 2 (different signedness) drivers/s390/cio/blacklist.c:132:28: expected unsigned int *val drivers/s390/cio/blacklist.c:132:28: got int *cssid drivers/s390/cio/blacklist.c:136:28: warning: incorrect type in argument 2 (different signedness) drivers/s390/cio/blacklist.c:136:28: expected unsigned int *val drivers/s390/cio/blacklist.c:136:28: got int *ssid drivers/s390/cio/blacklist.c:140:28: warning: incorrect type in argument 2 (different signedness) drivers/s390/cio/blacklist.c:140:28: expected unsigned int *val drivers/s390/cio/blacklist.c:140:28: got int *devno cssid, ssid and devno are of course unsigned, so let's make the variables unsigned as well. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/blacklist.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index a4a5f2efea48..0bfcbbe375c4 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -97,8 +97,8 @@ static int pure_hex(char **cp, unsigned int *val, int min_digit, return 0; } -static int parse_busid(char *str, int *cssid, int *ssid, int *devno, - int msgtrigger) +static int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid, + unsigned int *devno, int msgtrigger) { char *str_work; int val, rc, ret; @@ -148,7 +148,7 @@ out: static int blacklist_parse_parameters(char *str, range_action action, int msgtrigger) { - int from_cssid, to_cssid, from_ssid, to_ssid, from, to; + unsigned int from_cssid, to_cssid, from_ssid, to_ssid, from, to; int rc, totalrc; char *parm; range_action ra; -- cgit v1.2.3 From ee0ddadd086e25503f81be551c43f66472300acd Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 10 Jun 2008 10:03:20 +0200 Subject: [S390] vmemmap: fix off-by-one bug. If a memory range is supposed to be added to the 1:1 mapping and it ends just below the maximum supported physical address it won't succeed. This is because a test doesn't consider that the end address is 1 smaller than start + size. Fix the comparison. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/mm/vmem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c index f591188fa2c0..e4868bfc672f 100644 --- a/arch/s390/mm/vmem.c +++ b/arch/s390/mm/vmem.c @@ -236,7 +236,7 @@ static int insert_memory_segment(struct memory_segment *seg) { struct memory_segment *tmp; - if (seg->start + seg->size >= VMEM_MAX_PHYS || + if (seg->start + seg->size > VMEM_MAX_PHYS || seg->start + seg->size < seg->start) return -ERANGE; -- cgit v1.2.3 From 85b0d7c0ad92c47887bf6aeb424a14e7af14bd87 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 10 Jun 2008 10:03:21 +0200 Subject: [S390] cio: Fix inverted isc priorities. Priorities for I/O interruption subclasses range from 0 (highest) to 7 (lowest). Unfortunately, the console has been using isc 7 instead of an isc with a higher priority than regular I/O subchannels (which use 3). Fix this by making the console use isc 1. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/cio.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 82c6a2d45128..b32d7eb3d81a 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -576,12 +576,14 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) err = -ENODEV; goto out; } - if (cio_is_console(sch->schid)) + if (cio_is_console(sch->schid)) { sch->opm = 0xff; - else + sch->isc = 1; + } else { sch->opm = chp_get_sch_opm(sch); + sch->isc = 3; + } sch->lpm = sch->schib.pmcw.pam & sch->opm; - sch->isc = 3; CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X " "- PIM = %02X, PAM = %02X, POM = %02X\n", @@ -704,9 +706,9 @@ void wait_cons_dev(void) if (!console_subchannel_in_use) return; - /* disable all but isc 7 (console device) */ + /* disable all but isc 1 (console device) */ __ctl_store (save_cr6, 6, 6); - cr6 = 0x01000000; + cr6 = 0x40000000; __ctl_load (cr6, 6, 6); do { @@ -788,11 +790,11 @@ cio_probe_console(void) } /* - * enable console I/O-interrupt subclass 7 + * enable console I/O-interrupt subclass 1 */ - ctl_set_bit(6, 24); - console_subchannel.isc = 7; - console_subchannel.schib.pmcw.isc = 7; + ctl_set_bit(6, 30); + console_subchannel.isc = 1; + console_subchannel.schib.pmcw.isc = 1; console_subchannel.schib.pmcw.intparm = (u32)(addr_t)&console_subchannel; ret = cio_modify(&console_subchannel); -- cgit v1.2.3 From 7b439d25300dc59bba76b53eb344bb9e5a1133f2 Mon Sep 17 00:00:00 2001 From: Carsten Otte Date: Tue, 10 Jun 2008 10:03:22 +0200 Subject: [S390] vt220 console, initialize list head before use This patch fixes a null pointer dereference during initialisation when no sclp event facility is available: sclp vt220 tty driver: could not register vt220 - sclp_register returned -5 Unable to handle kernel paging request at virtual user address 0000000000000000 Oops: 0004 [#1] PREEMPT SMP Modules linked in: CPU: 0 Not tainted 2.6.26-rc3-kvm-bigiron-00968-gd939e93-dirty #30 Process swapper (pid: 0, task: 0000000000600be0, ksp: 000000000064a000) Krnl PSW : 0400000180000000 0000000000320d8c (sclp_unregister+0x48/0x8c) R:0 T:1 IO:0 EX:0 Key:0 M:0 W:0 P:0 AS:0 CC:0 PM:0 EA:3 Krnl GPRS: 0000000000000000 0000000000000000 0000000000630478 0700000000649c20 0000000000000000 0000000000433060 000000000064a660 0000000002e26000 00000000006db000 0000000000000000 0000000000a78578 0000000000649b80 0000000000630dc0 000000000044fa20 0000000000320d76 0000000000649b80 Krnl Code: 0000000000320d7c: e310c0080004 lg %r1,8(%r12) 0000000000320d82: b9040032 lgr %r3,%r2 0000000000320d86: c02000187b79 larl %r2,630478 >0000000000320d8c: e34010000024 stg %r4,0(%r1) 0000000000320d92: e31040080024 stg %r1,8(%r4) 0000000000320d98: c01100200200 lgfi %r1,2097664 0000000000320d9e: e310c0080024 stg %r1,8(%r12) 0000000000320da4: c01100100100 lgfi %r1,1048832 Call Trace: ([<0000000000320d76>] sclp_unregister+0x32/0x8c) [<00000000006657b4>] __sclp_vt220_cleanup+0xc4/0xe0 [<000000000066595c>] __sclp_vt220_init+0x18c/0x1a0 [<0000000000665aba>] sclp_vt220_con_init+0x42/0x68 [<00000000006601ca>] console_init+0x4e/0x68 [<000000000064acae>] start_kernel+0x3a2/0x4dc [<0000000000100020>] _stext+0x20/0x80 INFO: lockdep is turned off. Last Breaking-Event-Address: [<000000000041f964>] _spin_lock_irqsave+0xb0/0xb4 <4>---[ end trace 31fd0ba7d8756001 ]--- The issue is caused by a list_empty() check in __sclp_vt220_cleanup, which usually fails on non-initialized list heads that contain {NULL,NULL} instead. Signed-off-by: Carsten Otte Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp_vt220.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 62576af36f47..3e577f655b18 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -773,6 +773,7 @@ sclp_vt220_con_init(void) { int rc; + INIT_LIST_HEAD(&sclp_vt220_register.list); if (!CONSOLE_IS_SCLP) return 0; rc = __sclp_vt220_init(); -- cgit v1.2.3 From 24d3e210c18bfedafe986ec489575cf91ac39d22 Mon Sep 17 00:00:00 2001 From: Segher Boessenkool Date: Tue, 10 Jun 2008 10:03:23 +0200 Subject: [S390] Fix build failure in __cpu_up() The first argument to __ctl_store() should be the array to store stuff in, not just the first element of that array. With the current code in __cpu_up(), mainline GCC dies with an internal compiler error. I didn't diagnose that further, but just fixed the kernel bug. Signed-off-by: Segher Boessenkool Signed-off-by: Martin Schwidefsky Cc: Heiko Carstens --- arch/s390/kernel/smp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 42b1d12ebb10..5d4fa4b1c74c 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -711,7 +711,7 @@ int __cpuinit __cpu_up(unsigned int cpu) memset(sf, 0, sizeof(struct stack_frame)); sf->gprs[9] = (unsigned long) sf; cpu_lowcore->save_area[15] = (unsigned long) sf; - __ctl_store(cpu_lowcore->cregs_save_area[0], 0, 15); + __ctl_store(cpu_lowcore->cregs_save_area, 0, 15); asm volatile( " stam 0,15,0(%0)" : : "a" (&cpu_lowcore->access_regs_save_area) : "memory"); -- cgit v1.2.3 From b57838ea3f860c97e4726ab93abdf83a3d079a66 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Tue, 10 Jun 2008 10:03:24 +0200 Subject: [S390] Fix __ctl_load/__ctl_store inline assembly constraints __ctl_load/__ctl_store are called with either an array of unsigned long or a single unsigned long value. Add an address operator to the "m"/"=m" contraints to make them work for unsigned long arguments as well. Signed-off-by: Martin Schwidefsky --- include/asm-s390/system.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index e0d4500d5f95..819e7d99ca0c 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h @@ -315,14 +315,14 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) asm volatile( \ " lctlg %1,%2,0(%0)\n" \ : : "a" (&array), "i" (low), "i" (high), \ - "m" (*(addrtype *)(array))); \ + "m" (*(addrtype *)(&array))); \ }) #define __ctl_store(array, low, high) ({ \ typedef struct { char _[sizeof(array)]; } addrtype; \ asm volatile( \ " stctg %2,%3,0(%1)\n" \ - : "=m" (*(addrtype *)(array)) \ + : "=m" (*(addrtype *)(&array)) \ : "a" (&array), "i" (low), "i" (high)); \ }) @@ -333,14 +333,14 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) asm volatile( \ " lctl %1,%2,0(%0)\n" \ : : "a" (&array), "i" (low), "i" (high), \ - "m" (*(addrtype *)(array))); \ + "m" (*(addrtype *)(&array))); \ }) #define __ctl_store(array, low, high) ({ \ typedef struct { char _[sizeof(array)]; } addrtype; \ asm volatile( \ " stctl %2,%3,0(%1)\n" \ - : "=m" (*(addrtype *)(array)) \ + : "=m" (*(addrtype *)(&array)) \ : "a" (&array), "i" (low), "i" (high)); \ }) -- cgit v1.2.3 From 1783e60ff207805a3e75cf522b17ec9bb1604a62 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 10 Jun 2008 10:03:25 +0200 Subject: [S390] tape_3590.c: introduce missing kfree The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) @r exists@ expression E,E1; statement S; position p1,p2,p3; @@ E =@p1 \(kmalloc\|kcalloc\|kzalloc\)(...) ... when != E = E1 if (E == NULL || ...) S ... when != E = E1 if@p2 (...) { ... when != kfree(E) } ... when != E = E1 kfree@p3(E); @forall@ position r.p2; expression r.E; int E1 != 0; @@ * if@p2 (...) { ... when != kfree(E) when strict return E1; } Signed-off-by: Julia Lawall Signed-off-by: Martin Schwidefsky --- drivers/s390/char/tape_3590.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 8246ef3ab095..42ce7915fc5d 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -1598,7 +1598,7 @@ tape_3590_setup_device(struct tape_device *device) rc = tape_3590_read_dev_chars(device, rdc_data); if (rc) { DBF_LH(3, "Read device characteristics failed!\n"); - goto fail_kmalloc; + goto fail_rdc_data; } rc = tape_std_assign(device); if (rc) -- cgit v1.2.3 From 16882c1e962b4be5122fc05aaf2afc10fd9e2d15 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 8 Jun 2008 21:20:41 +0400 Subject: sched: fix TASK_WAKEKILL vs SIGKILL race schedule() has the special "TASK_INTERRUPTIBLE && signal_pending()" case, this allows us to do current->state = TASK_INTERRUPTIBLE; schedule(); without fear to sleep with pending signal. However, the code like current->state = TASK_KILLABLE; schedule(); is not right, schedule() doesn't take TASK_WAKEKILL into account. This means that mutex_lock_killable(), wait_for_completion_killable(), down_killable(), schedule_timeout_killable() can miss SIGKILL (and btw the second SIGKILL has no effect). Introduce the new helper, signal_pending_state(), and change schedule() to use it. Hopefully it will have more users, that is why the task's state is passed separately. Note this "__TASK_STOPPED | __TASK_TRACED" check in signal_pending_state(). This is needed to preserve the current behaviour (ptrace_notify). I hope this check will be removed soon, but this (afaics good) change needs the separate discussion. The fast path is "(state & (INTERRUPTIBLE | WAKEKILL)) + signal_pending(p)", basically the same that schedule() does now. However, this patch of course bloats schedule(). Signed-off-by: Oleg Nesterov Signed-off-by: Ingo Molnar --- include/linux/sched.h | 13 +++++++++++++ kernel/sched.c | 6 ++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index ae0be3c62375..c5d3f847ca8d 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2026,6 +2026,19 @@ static inline int fatal_signal_pending(struct task_struct *p) return signal_pending(p) && __fatal_signal_pending(p); } +static inline int signal_pending_state(long state, struct task_struct *p) +{ + if (!(state & (TASK_INTERRUPTIBLE | TASK_WAKEKILL))) + return 0; + if (!signal_pending(p)) + return 0; + + if (state & (__TASK_STOPPED | __TASK_TRACED)) + return 0; + + return (state & TASK_INTERRUPTIBLE) || __fatal_signal_pending(p); +} + static inline int need_resched(void) { return unlikely(test_thread_flag(TIF_NEED_RESCHED)); diff --git a/kernel/sched.c b/kernel/sched.c index bfb8ad8ed171..2c65bf29d133 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -4159,12 +4159,10 @@ need_resched_nonpreemptible: clear_tsk_need_resched(prev); if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) { - if (unlikely((prev->state & TASK_INTERRUPTIBLE) && - signal_pending(prev))) { + if (unlikely(signal_pending_state(prev->state, prev))) prev->state = TASK_RUNNING; - } else { + else deactivate_task(rq, prev, 1); - } switch_count = &prev->nvcsw; } -- cgit v1.2.3 From b7f09ae583c49d28b2796d2fa5893dcf822e3a10 Mon Sep 17 00:00:00 2001 From: Miquel van Smoorenburg Date: Thu, 5 Jun 2008 18:14:44 +0200 Subject: x86, pci-dma.c: don't always add __GFP_NORETRY to gfp Currently arch/x86/kernel/pci-dma.c always adds __GFP_NORETRY to the allocation flags, because it wants to be reasonably sure not to deadlock when calling alloc_pages(). But really that should only be done in two cases: - when allocating memory in the lower 16 MB DMA zone. If there's no free memory there, waiting or OOM killing is of no use - when optimistically trying an allocation in the DMA32 zone when dma_mask < DMA_32BIT_MASK hoping that the allocation happens to fall within the limits of the dma_mask Also blindly adding __GFP_NORETRY to the the gfp variable might not be a good idea since we then also use it when calling dma_ops->alloc_coherent(). Clearing it might also not be a good idea, dma_alloc_coherent()'s caller might have set it on purpose. The gfp variable should not be clobbered. [ mingo@elte.hu: converted to delta patch ontop of previous version. ] Signed-off-by: Miquel van Smoorenburg Signed-off-by: Ingo Molnar --- arch/x86/kernel/pci-dma.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 069e843f0b93..dc00a1331ace 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -378,6 +378,7 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, struct page *page; unsigned long dma_mask = 0; dma_addr_t bus; + int noretry = 0; /* ignore region specifiers */ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); @@ -397,19 +398,25 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, if (dev->dma_mask == NULL) return NULL; + /* Don't invoke OOM killer or retry in lower 16MB DMA zone */ + if (gfp & __GFP_DMA) + noretry = 1; + #ifdef CONFIG_X86_64 /* Why <=? Even when the mask is smaller than 4GB it is often larger than 16MB and in this case we have a chance of finding fitting memory in the next higher zone first. If not retry with true GFP_DMA. -AK */ - if (dma_mask <= DMA_32BIT_MASK && !(gfp & GFP_DMA)) + if (dma_mask <= DMA_32BIT_MASK && !(gfp & GFP_DMA)) { gfp |= GFP_DMA32; + if (dma_mask < DMA_32BIT_MASK) + noretry = 1; + } #endif again: - /* Don't invoke OOM killer or retry in lower 16MB DMA zone */ page = dma_alloc_pages(dev, - (gfp & GFP_DMA) ? gfp | __GFP_NORETRY : gfp, get_order(size)); + noretry ? gfp | __GFP_NORETRY : gfp, get_order(size)); if (page == NULL) return NULL; -- cgit v1.2.3 From c592713b3e124ce0719e6af4bc2520424c49cbae Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Tue, 10 Jun 2008 08:53:39 -0400 Subject: shm: Remove silly double assignment Found a silly double assignment of err is do_shmat. Silly, but good to clean up the useless code. Signed-off-by: Neil Horman Signed-off-by: Linus Torvalds --- ipc/shm.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ipc/shm.c b/ipc/shm.c index 554429ade079..d05f6b564998 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -894,8 +894,6 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr) if (!sfd) goto out_put_dentry; - err = -ENOMEM; - file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations); if (!file) goto out_free; -- cgit v1.2.3 From b76916462d990751882eaeadc75ac8c487d6de1d Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 10 Jun 2008 20:56:36 +0200 Subject: ide: remove the ide_etrax100 chipset type I forgot to remove the ide_etrax100 chipset type when removing the ETRAX_IDE driver. Reported-by: Bartlomiej Zolnierkiewicz Signed-off-by: Adrian Bunk Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-probe.c | 5 ++--- drivers/ide/ide-proc.c | 1 - include/linux/ide.h | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 655ec7ef568a..0bccb63d10a1 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1333,8 +1333,7 @@ static void ide_port_init_devices(ide_hwif_t *hwif) static void ide_init_port(ide_hwif_t *hwif, unsigned int port, const struct ide_port_info *d) { - if (d->chipset != ide_etrax100) - hwif->channel = port; + hwif->channel = port; if (d->chipset) hwif->chipset = d->chipset; @@ -1519,7 +1518,7 @@ int ide_device_add_all(u8 *idx, const struct ide_port_info *d) continue; } - if (d->chipset != ide_etrax100 && (i & 1) && mate) { + if ((i & 1) && mate) { hwif->mate = mate; mate->mate = hwif; } diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 8d6ad812a014..55ec7f798772 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -63,7 +63,6 @@ static int proc_ide_read_imodel case ide_pmac: name = "mac-io"; break; case ide_au1xxx: name = "au1xxx"; break; case ide_palm3710: name = "palm3710"; break; - case ide_etrax100: name = "etrax100"; break; case ide_acorn: name = "acorn"; break; default: name = "(unknown)"; break; } diff --git a/include/linux/ide.h b/include/linux/ide.h index f8f195c20da2..9918772bf274 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -153,7 +153,7 @@ enum { ide_unknown, ide_generic, ide_pci, ide_qd65xx, ide_umc8672, ide_ht6560b, ide_rz1000, ide_trm290, ide_cmd646, ide_cy82c693, ide_4drives, - ide_pmac, ide_etrax100, ide_acorn, + ide_pmac, ide_acorn, ide_au1xxx, ide_palm3710 }; -- cgit v1.2.3 From 34e6e88f025ebe0613f53af2703d4d902e39273a Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 10 Jun 2008 20:56:36 +0200 Subject: MAINTAINERS: remove SIS 5513 IDE entry - maintainer has not been active for years - URLs no longer exist - covered by the IDE SUBSYSTEM entry - maintainer email bounces Signed-off-by: Adrian Bunk Cc: Lionel.Bouton@inet6.fr Signed-off-by: Bartlomiej Zolnierkiewicz --- MAINTAINERS | 7 ------- 1 file changed, 7 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index cb71eb47c331..e3560df4608e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3658,13 +3658,6 @@ M: romieu@fr.zoreil.com L: netdev@vger.kernel.org S: Maintained -SIS 5513 IDE CONTROLLER DRIVER -P: Lionel Bouton -M: Lionel.Bouton@inet6.fr -W: http://inet6.dyn.dhs.org/sponsoring/sis5513/index.html -W: http://gyver.homeip.net/sis5513/index.html -S: Maintained - SIS 900/7016 FAST ETHERNET DRIVER P: Daniele Venzano M: venza@brownhat.org -- cgit v1.2.3 From cd18f69f845dc8c769f0ef65046b7a113b8aba87 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 10 Jun 2008 20:56:36 +0200 Subject: sis5513: add missing pci_enable_device() call Cc: Riccardo Gori Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/sis5513.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c index 4b0b85d8faf5..e127eb25ab63 100644 --- a/drivers/ide/pci/sis5513.c +++ b/drivers/ide/pci/sis5513.c @@ -569,6 +569,11 @@ static int __devinit sis5513_init_one(struct pci_dev *dev, const struct pci_devi { struct ide_port_info d = sis5513_chipset; u8 udma_rates[] = { 0x00, 0x00, 0x07, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f }; + int rc; + + rc = pci_enable_device(dev); + if (rc) + return rc; if (sis_find_family(dev) == 0) return -ENOTSUPP; -- cgit v1.2.3 From 343a3451e20314d5959b59b992e33fbaadfe52bf Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 10 Jun 2008 20:56:36 +0200 Subject: ide-generic: add missing hwif->chipset setup hwif->chipset need to be set properly or ide-generic driver will break once we make a final step in fixing host drivers' dependence on ide_hwifs[]. Problem was catched early thanks to IDE tree exposure in -mm / -next trees and reported by people listed people (thank you guys!). Reported-by: "John Keller" Reported-by: Dmitri Vorobiev Reported-by: Mel Gorman Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-generic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c index a6073e248f45..9134488ac043 100644 --- a/drivers/ide/ide-generic.c +++ b/drivers/ide/ide-generic.c @@ -125,6 +125,7 @@ static int __init ide_generic_init(void) memset(&hw, 0, sizeof(hw)); ide_std_init_ports(&hw, io_addr, io_addr + 0x206); hw.irq = ide_default_irq(io_addr); + hw.chipset = ide_generic; ide_init_port_hw(hwif, &hw); idx[i] = i; -- cgit v1.2.3 From d427e836d1d9b58e8f1e648c09b5fbe36e01013b Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 10 Jun 2008 20:56:37 +0200 Subject: ide: fix host drivers missing hwif->chipset initialization ide_find_port() now depends on ->chipset being set for occupied ide_hwifs[] slots so all host drivers have to initialize hwif->chipset properly. This patch fixes a regression on hosts with > 1 port or with a single port but no devices attached to it for an affected host drivers. Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/arm/bast-ide.c | 1 + drivers/ide/arm/ide_arm.c | 1 + drivers/ide/ide-pnp.c | 1 + drivers/ide/ide-probe.c | 1 + drivers/ide/legacy/buddha.c | 2 ++ drivers/ide/legacy/falconide.c | 2 ++ drivers/ide/legacy/gayle.c | 2 ++ drivers/ide/legacy/macide.c | 2 ++ drivers/ide/legacy/q40ide.c | 2 ++ drivers/ide/pci/cmd640.c | 2 ++ drivers/ide/ppc/mpc8xx.c | 4 ++++ 11 files changed, 20 insertions(+) diff --git a/drivers/ide/arm/bast-ide.c b/drivers/ide/arm/bast-ide.c index 713cef20622e..8e8c28104b45 100644 --- a/drivers/ide/arm/bast-ide.c +++ b/drivers/ide/arm/bast-ide.c @@ -42,6 +42,7 @@ static int __init bastide_register(unsigned int base, unsigned int aux, int irq) hw.io_ports.ctl_addr = aux + (6 * 0x20); hw.irq = irq; + hw.chipset = ide_generic; hwif = ide_find_port(); if (hwif == NULL) diff --git a/drivers/ide/arm/ide_arm.c b/drivers/ide/arm/ide_arm.c index 4263ffd4ab20..2f311da4c963 100644 --- a/drivers/ide/arm/ide_arm.c +++ b/drivers/ide/arm/ide_arm.c @@ -49,6 +49,7 @@ static int __init ide_arm_init(void) memset(&hw, 0, sizeof(hw)); ide_std_init_ports(&hw, base, ctl); hw.irq = IDE_ARM_IRQ; + hw.chipset = ide_generic; hwif = ide_find_port(); if (hwif) { diff --git a/drivers/ide/ide-pnp.c b/drivers/ide/ide-pnp.c index 6a8953f68e9f..adbd01784162 100644 --- a/drivers/ide/ide-pnp.c +++ b/drivers/ide/ide-pnp.c @@ -55,6 +55,7 @@ static int idepnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) memset(&hw, 0, sizeof(hw)); ide_std_init_ports(&hw, base, ctl); hw.irq = pnp_irq(dev, 0); + hw.chipset = ide_generic; hwif = ide_find_port(); if (hwif) { diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 0bccb63d10a1..380fa0c8cc84 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1664,6 +1664,7 @@ static void ide_legacy_init_one(u8 *idx, hw_regs_t *hw, u8 port_no, ide_std_init_ports(hw, base, ctl); hw->irq = irq; + hw->chipset = d->chipset; hwif = ide_find_port_slot(d); if (hwif) { diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c index 5c730e4dd735..9a1d27ef3f8a 100644 --- a/drivers/ide/legacy/buddha.c +++ b/drivers/ide/legacy/buddha.c @@ -138,6 +138,8 @@ static void __init buddha_setup_ports(hw_regs_t *hw, unsigned long base, hw->irq = IRQ_AMIGA_PORTS; hw->ack_intr = ack_intr; + + hw->chipset = ide_generic; } /* diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c index 9e449a0c623f..af11028b4794 100644 --- a/drivers/ide/legacy/falconide.c +++ b/drivers/ide/legacy/falconide.c @@ -81,6 +81,8 @@ static void __init falconide_setup_ports(hw_regs_t *hw) hw->irq = IRQ_MFP_IDE; hw->ack_intr = NULL; + + hw->chipset = ide_generic; } /* diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c index a9c2593a898c..eb15ca619700 100644 --- a/drivers/ide/legacy/gayle.c +++ b/drivers/ide/legacy/gayle.c @@ -112,6 +112,8 @@ static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base, hw->irq = IRQ_AMIGA_PORTS; hw->ack_intr = ack_intr; + + hw->chipset = ide_generic; } /* diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c index caa2632dd08e..2e84290d0bcc 100644 --- a/drivers/ide/legacy/macide.c +++ b/drivers/ide/legacy/macide.c @@ -78,6 +78,8 @@ static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base, hw->irq = irq; hw->ack_intr = ack_intr; + + hw->chipset = ide_generic; } static const char *mac_ide_name[] = diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c index 6f535d00e638..8ff6e2d20834 100644 --- a/drivers/ide/legacy/q40ide.c +++ b/drivers/ide/legacy/q40ide.c @@ -70,6 +70,8 @@ static void q40_ide_setup_ports(hw_regs_t *hw, unsigned long base, hw->irq = irq; hw->ack_intr = ack_intr; + + hw->chipset = ide_generic; } static void q40ide_input_data(ide_drive_t *drive, struct request *rq, diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c index aaf38109eaec..b38a1980dcd5 100644 --- a/drivers/ide/pci/cmd640.c +++ b/drivers/ide/pci/cmd640.c @@ -747,9 +747,11 @@ static int __init cmd640x_init(void) ide_std_init_ports(&hw[0], 0x1f0, 0x3f6); hw[0].irq = 14; + hw[0].chipset = ide_cmd640; ide_std_init_ports(&hw[1], 0x170, 0x376); hw[1].irq = 15; + hw[1].chipset = ide_cmd640; printk(KERN_INFO "cmd640: buggy cmd640%c interface on %s, config=0x%02x" "\n", 'a' + cmd640_chip_version - 1, bus_type, cfr); diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c index f0e638dcc3ab..236f9c38e519 100644 --- a/drivers/ide/ppc/mpc8xx.c +++ b/drivers/ide/ppc/mpc8xx.c @@ -303,6 +303,8 @@ static int __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port) pcmp->pcmc_per = 0x100000 >> (16 * _slot_); #endif /* CONFIG_IDE_8xx_PCCARD */ + hw->chipset = ide_generic; + return 0; } #endif /* CONFIG_IDE_8xx_PCCARD || CONFIG_IDE_8xx_DIRECT */ @@ -377,6 +379,8 @@ static int __init m8xx_ide_init_ports(hw_regs_t *hw, unsigned long data_port) ((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |= (0x80000000 >> ioport_dsc[data_port].irq); + hw->chipset = ide_generic; + return 0; } #endif /* CONFIG_IDE_8xx_DIRECT */ -- cgit v1.2.3 From 8a7dbb9761d59996e4a037c969eabd8e93f3be1c Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 10 Jun 2008 20:56:37 +0200 Subject: delkin_cb: set proper hwif->gendev.parent value hwif->dev was set too late (after ide_device_add() call) so hwif->gendev.parent was not initialized properly. Fix it by setting hw.dev and letting ide_init_port_hw() do the rest. Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/delkin_cb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c index b9e457996d0e..5cf59333ef33 100644 --- a/drivers/ide/pci/delkin_cb.c +++ b/drivers/ide/pci/delkin_cb.c @@ -79,6 +79,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) memset(&hw, 0, sizeof(hw)); ide_std_init_ports(&hw, base + 0x10, base + 0x1e); hw.irq = dev->irq; + hw.dev = &dev->dev; hw.chipset = ide_pci; /* this enables IRQ sharing */ hwif = ide_find_port(); @@ -99,7 +100,7 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) goto out_disable; pci_set_drvdata(dev, hwif); - hwif->dev = &dev->dev; + drive = &hwif->drives[0]; if (drive->present) { drive->io_32bit = 1; -- cgit v1.2.3 From 1c4d4ad50ac5cc74c605c4a467db42c961ec7a69 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 10 Jun 2008 20:56:37 +0200 Subject: delkin_cb: use struct ide_port_info Convert the driver to use struct ide_port_info - as a nice side-effect this fixes racy setup of ->io_32bit/unmask settings (after ide_device_add() call device can be already in use). Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/delkin_cb.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c index 5cf59333ef33..1b69e4dd5522 100644 --- a/drivers/ide/pci/delkin_cb.c +++ b/drivers/ide/pci/delkin_cb.c @@ -47,13 +47,18 @@ static const struct ide_port_ops delkin_cb_port_ops = { .quirkproc = ide_undecoded_slave, }; +static const struct ide_port_info delkin_cb_port_info = { + .port_ops = &delkin_cb_port_ops, + .host_flags = IDE_HFLAG_IO_32BIT | IDE_HFLAG_UNMASK_IRQS | + IDE_HFLAG_NO_DMA, +}; + static int __devinit delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) { unsigned long base; hw_regs_t hw; ide_hwif_t *hwif = NULL; - ide_drive_t *drive; int i, rc; u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; @@ -90,22 +95,16 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) ide_init_port_data(hwif, i); ide_init_port_hw(hwif, &hw); - hwif->port_ops = &delkin_cb_port_ops; idx[0] = i; - ide_device_add(idx, NULL); + ide_device_add(idx, &delkin_cb_port_info); if (!hwif->present) goto out_disable; pci_set_drvdata(dev, hwif); - drive = &hwif->drives[0]; - if (drive->present) { - drive->io_32bit = 1; - drive->unmask = 1; - } return 0; out_disable: -- cgit v1.2.3 From 96fe439ec9ca25b09e1458d86bd739757ae11ea1 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 10 Jun 2008 20:56:38 +0200 Subject: delkin_cb: add warm-plug support Don't fail the probe if there are no devices attached to the controller. Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/delkin_cb.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c index 1b69e4dd5522..538f8045d416 100644 --- a/drivers/ide/pci/delkin_cb.c +++ b/drivers/ide/pci/delkin_cb.c @@ -100,15 +100,11 @@ delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) ide_device_add(idx, &delkin_cb_port_info); - if (!hwif->present) - goto out_disable; - pci_set_drvdata(dev, hwif); return 0; out_disable: - printk(KERN_ERR "delkin_cb: no IDE devices found\n"); pci_release_regions(dev); pci_disable_device(dev); return -ENODEV; -- cgit v1.2.3 From f4084a1d18d618bb360bc72713a3bc2b8375e12f Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 10 Jun 2008 20:56:38 +0200 Subject: delkin_cb: add missing __init/__exit tags Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/delkin_cb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c index 538f8045d416..af0f30051d5a 100644 --- a/drivers/ide/pci/delkin_cb.c +++ b/drivers/ide/pci/delkin_cb.c @@ -135,14 +135,12 @@ static struct pci_driver driver = { .remove = delkin_cb_remove, }; -static int -delkin_cb_init (void) +static int __init delkin_cb_init(void) { return pci_register_driver(&driver); } -static void -delkin_cb_exit (void) +static void __exit delkin_cb_exit(void) { pci_unregister_driver(&driver); } -- cgit v1.2.3 From fb374966ba13ccac341499eaefecd58a96bafb59 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 10 Jun 2008 20:56:38 +0200 Subject: palm_bk3710: add warm-plug support Don't fail the probe if there are no devices attached to the controller. Cc: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/arm/palm_bk3710.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c index 96378ebfb31f..d024ac8fad14 100644 --- a/drivers/ide/arm/palm_bk3710.c +++ b/drivers/ide/arm/palm_bk3710.c @@ -409,9 +409,6 @@ static int __devinit palm_bk3710_probe(struct platform_device *pdev) ide_device_add(idx, &palm_bk3710_port_info); - if (!hwif->present) - goto out; - return 0; out: printk(KERN_WARNING "Palm Chip BK3710 IDE Register Fail\n"); -- cgit v1.2.3 From 513f3c10ddb24b0a261ae96de6f7911ba28713f9 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 10 Jun 2008 20:56:38 +0200 Subject: ide: export ide_doubler This patch fixes the following build error: <-- snip --> ... Building modules, stage 2. MODPOST 1204 modules ERROR: "ide_doubler" [drivers/ide/ide-core.ko] undefined! ... make[2]: *** [__modpost] Error 1 <-- snip --> Reported-by: Adrian Bunk Signed-off-by: Adrian Bunk Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/legacy/gayle.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c index eb15ca619700..fed7d812761c 100644 --- a/drivers/ide/legacy/gayle.c +++ b/drivers/ide/legacy/gayle.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -62,7 +63,10 @@ GAYLE_NUM_HWIFS-1) #define GAYLE_HAS_CONTROL_REG (!ide_doubler) #define GAYLE_IDEREG_SIZE (ide_doubler ? 0x1000 : 0x2000) + int ide_doubler = 0; /* support IDE doublers? */ +EXPORT_SYMBOL_GPL(ide_doubler); + module_param_named(doubler, ide_doubler, bool, 0); MODULE_PARM_DESC(doubler, "enable support for IDE doublers"); #endif /* CONFIG_BLK_DEV_IDEDOUBLER */ -- cgit v1.2.3 From efc0fc1c2f37c8c0e43c7616394a979a042b9331 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 10 Jun 2008 20:56:38 +0200 Subject: fix BLK_DEV_HD_ONLY on ARM dependencies This patch limits BLK_DEV_HD_ONLY to the ARM platforms offering IRQ_HARDDISK, fixing the following compile error on others: <-- snip --> ... CC drivers/ide/legacy/hd.o ... /home/bunk/linux/kernel-2.6/git/linux-2.6/drivers/ide/legacy/hd.c: In function 'hd_times_out': /home/bunk/linux/kernel-2.6/git/linux-2.6/drivers/ide/legacy/hd.c:542: error: 'IRQ_HARDDISK' undeclared (first use in this function) /home/bunk/linux/kernel-2.6/git/linux-2.6/drivers/ide/legacy/hd.c:542: error: (Each undeclared identifier is reported only once /home/bunk/linux/kernel-2.6/git/linux-2.6/drivers/ide/legacy/hd.c:542: error: for each function it appears in.) /home/bunk/linux/kernel-2.6/git/linux-2.6/drivers/ide/legacy/hd.c: In function 'do_hd_request': /home/bunk/linux/kernel-2.6/git/linux-2.6/drivers/ide/legacy/hd.c:661: error: 'IRQ_HARDDISK' undeclared (first use in this function) /home/bunk/linux/kernel-2.6/git/linux-2.6/drivers/ide/legacy/hd.c: In function 'hd_init': /home/bunk/linux/kernel-2.6/git/linux-2.6/drivers/ide/legacy/hd.c:765: error: 'IRQ_HARDDISK' undeclared (first use in this function) make[3]: *** [drivers/ide/legacy/hd.o] Error 1 <-- snip --> Reported-by: Adrian Bunk Cc: Russell King Signed-off-by: Adrian Bunk Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index b4f3aefa12b6..1607536ff5fb 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -1028,6 +1028,7 @@ endif config BLK_DEV_HD_ONLY bool "Old hard disk (MFM/RLL/IDE) driver" + depends on !ARM || ARCH_RPC || ARCH_SHARK || BROKEN help There are two drivers for MFM/RLL/IDE hard disks. Most people use the newer enhanced driver, but this old one is still around for two -- cgit v1.2.3 From 6b6707a50c7598a83820077393f8823ab791abf8 Mon Sep 17 00:00:00 2001 From: James Chapman Date: Tue, 10 Jun 2008 12:35:00 -0700 Subject: l2tp: Fix potential memory corruption in pppol2tp_recvmsg() This patch fixes a potential memory corruption in pppol2tp_recvmsg(). If skb->len is bigger than the caller's buffer length, memcpy_toiovec() will go into unintialized data on the kernel heap, interpret it as an iovec and start modifying memory. The fix is to change the memcpy_toiovec() call to skb_copy_datagram_iovec() so that paged packets (rare for PPPOL2TP) are handled properly. Also check that the caller's buffer is big enough for the data and set the MSG_TRUNC flag if it is not so. Reported-by: Ilja Signed-off-by: James Chapman Signed-off-by: David S. Miller --- drivers/net/pppol2tp.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 70cfdb46aa27..f9298827a76c 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -783,14 +783,18 @@ static int pppol2tp_recvmsg(struct kiocb *iocb, struct socket *sock, err = 0; skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &err); - if (skb) { - err = memcpy_toiovec(msg->msg_iov, (unsigned char *) skb->data, - skb->len); - if (err < 0) - goto do_skb_free; - err = skb->len; - } -do_skb_free: + if (!skb) + goto end; + + if (len > skb->len) + len = skb->len; + else if (len < skb->len) + msg->msg_flags |= MSG_TRUNC; + + err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, len); + if (likely(err == 0)) + err = len; + kfree_skb(skb); end: return err; -- cgit v1.2.3 From 45d465bc237ab1e1ebb4c65b9b318830dafb7509 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Tue, 10 Jun 2008 12:37:42 -0700 Subject: ipv4: Remove unused declaration from include/net/tcp.h. - The tcp_unhash() method in /include/net/tcp.h is no more needed, as the unhash method in tcp_prot structure is now inet_unhash (instead of tcp_unhash in the past); see tcp_prot structure in net/ipv4/tcp_ipv4.c. - So, this patch removes tcp_unhash() declaration from include/net/tcp.h Signed-off-by: Rami Rosen Signed-off-by: David S. Miller --- include/net/tcp.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 633147cb6bbc..d448310c82c1 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -433,7 +433,6 @@ extern struct sk_buff * tcp_make_synack(struct sock *sk, extern int tcp_disconnect(struct sock *sk, int flags); -extern void tcp_unhash(struct sock *sk); /* From syncookies.c */ extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS]; -- cgit v1.2.3 From ce4a7d0d48bbaed78ccbb0bafb9229651a40303a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 10 Jun 2008 12:39:35 -0700 Subject: inet{6}_request_sock: Init ->opt and ->pktopts in the constructor Wei Yongjun noticed that we may call reqsk_free on request sock objects where the opt fields may not be initialized, fix it by introducing inet_reqsk_alloc where we initialize ->opt to NULL and set ->pktopts to NULL in inet6_reqsk_alloc. Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- include/linux/ipv6.h | 4 +++- include/net/inet_sock.h | 10 ++++++++++ net/dccp/ipv4.c | 3 +-- net/dccp/ipv6.c | 1 - net/ipv4/syncookies.c | 3 +-- net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/syncookies.c | 1 - net/ipv6/tcp_ipv6.c | 1 - 8 files changed, 16 insertions(+), 9 deletions(-) diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 10b666b61add..cde056e08181 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -396,8 +396,10 @@ static inline struct request_sock *inet6_reqsk_alloc(struct request_sock_ops *op { struct request_sock *req = reqsk_alloc(ops); - if (req != NULL) + if (req != NULL) { inet_rsk(req)->inet6_rsk_offset = inet6_rsk_offset(req); + inet6_rsk(req)->pktopts = NULL; + } return req; } diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index a42cd63d241a..9fabe5b38912 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -197,4 +197,14 @@ static inline int inet_iif(const struct sk_buff *skb) return skb->rtable->rt_iif; } +static inline struct request_sock *inet_reqsk_alloc(struct request_sock_ops *ops) +{ + struct request_sock *req = reqsk_alloc(ops); + + if (req != NULL) + inet_rsk(req)->opt = NULL; + + return req; +} + #endif /* _INET_SOCK_H */ diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index c22a3780c14e..37d27bcb361f 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -589,7 +589,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) goto drop; - req = reqsk_alloc(&dccp_request_sock_ops); + req = inet_reqsk_alloc(&dccp_request_sock_ops); if (req == NULL) goto drop; @@ -605,7 +605,6 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) ireq = inet_rsk(req); ireq->loc_addr = ip_hdr(skb)->daddr; ireq->rmt_addr = ip_hdr(skb)->saddr; - ireq->opt = NULL; /* * Step 3: Process LISTEN state diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 9b1129bb7ece..f7fe2a572d7b 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -421,7 +421,6 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) ireq6 = inet6_rsk(req); ipv6_addr_copy(&ireq6->rmt_addr, &ipv6_hdr(skb)->saddr); ipv6_addr_copy(&ireq6->loc_addr, &ipv6_hdr(skb)->daddr); - ireq6->pktopts = NULL; if (ipv6_opt_accepted(sk, skb) || np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 73ba98921d64..d182a2a26291 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -285,7 +285,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, cookie_check_timestamp(&tcp_opt); ret = NULL; - req = reqsk_alloc(&tcp_request_sock_ops); /* for safety */ + req = inet_reqsk_alloc(&tcp_request_sock_ops); /* for safety */ if (!req) goto out; @@ -301,7 +301,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, ireq->rmt_port = th->source; ireq->loc_addr = ip_hdr(skb)->daddr; ireq->rmt_addr = ip_hdr(skb)->saddr; - ireq->opt = NULL; ireq->snd_wscale = tcp_opt.snd_wscale; ireq->rcv_wscale = tcp_opt.rcv_wscale; ireq->sack_ok = tcp_opt.sack_ok; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index cd601a866c2f..4f8485c67d1a 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1285,7 +1285,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) goto drop; - req = reqsk_alloc(&tcp_request_sock_ops); + req = inet_reqsk_alloc(&tcp_request_sock_ops); if (!req) goto drop; diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 938ce4ecde55..3ecc1157994e 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -198,7 +198,6 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ireq = inet_rsk(req); ireq6 = inet6_rsk(req); treq = tcp_rsk(req); - ireq6->pktopts = NULL; if (security_inet_conn_request(sk, skb, req)) { reqsk_free(req); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 715965f0fac0..cb46749d4c32 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1299,7 +1299,6 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) treq = inet6_rsk(req); ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr); ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr); - treq->pktopts = NULL; if (!want_cookie) TCP_ECN_create_request(req, tcp_hdr(skb)); -- cgit v1.2.3 From b36ffc47a17ab5ce6d9589a99ac5d135c9173a9a Mon Sep 17 00:00:00 2001 From: Pradeep Singh Rautela Date: Tue, 10 Jun 2008 12:46:52 -0700 Subject: drivers/atm/eni.h: remove unused macro KERNEL_OFFSET KERNEL_OFFSET macro in eni.h is not required as it is not used anywhere. Remove the unused macro from eni.h header file. Signed-off-by: Pradeep Singh Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/atm/eni.h | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/atm/eni.h b/drivers/atm/eni.h index d04fefb0841f..e4c9525e60b3 100644 --- a/drivers/atm/eni.h +++ b/drivers/atm/eni.h @@ -18,7 +18,6 @@ #include "midway.h" -#define KERNEL_OFFSET 0xC0000000 /* kernel 0x0 is at phys 0xC0000000 */ #define DEV_LABEL "eni" #define UBR_BUFFER (128*1024) /* UBR buffer size */ -- cgit v1.2.3 From 495b36b15e17fb08434e3800959434f06a1a6fbc Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 10 Jun 2008 12:49:31 -0700 Subject: isdn divas: fix proc creation 1. creating proc entry and not saving pointer to PDE and checking it is not going to work. 2. if proc entry wasn't created, no reason to remove it on error path. Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/isdn/hardware/eicon/divasmain.c | 1 - drivers/isdn/hardware/eicon/divasproc.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index 5fcbdccd7a53..16a874bb1561 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -806,7 +806,6 @@ static int DIVA_INIT_FUNCTION divas_init(void) if (!create_divas_proc()) { #ifdef MODULE - remove_divas_proc(); divas_unregister_chrdev(); divasfunc_exit(); #endif diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c index fae895828a17..040827288ec9 100644 --- a/drivers/isdn/hardware/eicon/divasproc.c +++ b/drivers/isdn/hardware/eicon/divasproc.c @@ -125,8 +125,8 @@ static const struct file_operations divas_fops = { int create_divas_proc(void) { - proc_create(divas_proc_name, S_IFREG | S_IRUGO, proc_net_eicon, - &divas_fops); + divas_proc_entry = proc_create(divas_proc_name, S_IFREG | S_IRUGO, + proc_net_eicon, &divas_fops); if (!divas_proc_entry) return (0); -- cgit v1.2.3 From ea23ec26727b4df97b4965715f0519b6ddc0aa4b Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Tue, 10 Jun 2008 12:50:14 -0700 Subject: isdn: use simple_read_from_buffer() Signed-off-by: Akinobu Mita Acked-by: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/isdn/hysdn/hysdn_procconf.c | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index 15906d005b05..484299b031f8 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -207,30 +207,17 @@ hysdn_conf_write(struct file *file, const char __user *buf, size_t count, loff_t /* read conf file -> output card info data */ /*******************************************/ static ssize_t -hysdn_conf_read(struct file *file, char __user *buf, size_t count, loff_t * off) +hysdn_conf_read(struct file *file, char __user *buf, size_t count, loff_t *off) { char *cp; - int i; - if (file->f_mode & FMODE_READ) { - if (!(cp = file->private_data)) - return (-EFAULT); /* should never happen */ - i = strlen(cp); /* get total string length */ - if (*off < i) { - /* still bytes to transfer */ - cp += *off; /* point to desired data offset */ - i -= *off; /* remaining length */ - if (i > count) - i = count; /* limit length to transfer */ - if (copy_to_user(buf, cp, i)) - return (-EFAULT); /* copy error */ - *off += i; /* adjust offset */ - } else - return (0); - } else - return (-EPERM); /* no permission to read */ - - return (i); + if (!(file->f_mode & FMODE_READ)) + return -EPERM; /* no permission to read */ + + if (!(cp = file->private_data)) + return -EFAULT; /* should never happen */ + + return simple_read_from_buffer(buf, count, off, cp, strlen(cp)); } /* hysdn_conf_read */ /******************/ -- cgit v1.2.3 From 392fdb0e35055b96faa9c1cd6ab537805337cdce Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 10 Jun 2008 14:07:25 -0700 Subject: net pppoe: Check packet length on all receive paths The length field in the PPPOE header wasn't checked completely. This patch causes all packets shorter than the declared length to be dropped. It also changes the memcpy_toiovec call to skb_copy_datagram_iovec so that paged packets (rare for PPPOE) are handled properly. Thanks to Ilja of the Netric Security Team for discovering and reporting this bug, and Chris Wright for the total_len check. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/pppoe.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 58a26a47af29..d89ccfd6650c 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -341,12 +341,6 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) struct pppox_sock *relay_po; if (sk->sk_state & PPPOX_BOUND) { - struct pppoe_hdr *ph = pppoe_hdr(skb); - int len = ntohs(ph->length); - skb_pull_rcsum(skb, sizeof(struct pppoe_hdr)); - if (pskb_trim_rcsum(skb, len)) - goto abort_kfree; - ppp_input(&po->chan, skb); } else if (sk->sk_state & PPPOX_RELAY) { relay_po = get_item_by_addr(&po->pppoe_relay); @@ -357,7 +351,6 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) if ((sk_pppox(relay_po)->sk_state & PPPOX_CONNECTED) == 0) goto abort_put; - skb_pull(skb, sizeof(struct pppoe_hdr)); if (!__pppoe_xmit(sk_pppox(relay_po), skb)) goto abort_put; } else { @@ -388,6 +381,7 @@ static int pppoe_rcv(struct sk_buff *skb, { struct pppoe_hdr *ph; struct pppox_sock *po; + int len; if (!(skb = skb_share_check(skb, GFP_ATOMIC))) goto out; @@ -399,10 +393,21 @@ static int pppoe_rcv(struct sk_buff *skb, goto drop; ph = pppoe_hdr(skb); + len = ntohs(ph->length); + + skb_pull_rcsum(skb, sizeof(*ph)); + if (skb->len < len) + goto drop; po = get_item(ph->sid, eth_hdr(skb)->h_source, dev->ifindex); - if (po != NULL) - return sk_receive_skb(sk_pppox(po), skb, 0); + if (!po) + goto drop; + + if (pskb_trim_rcsum(skb, len)) + goto drop; + + return sk_receive_skb(sk_pppox(po), skb, 0); + drop: kfree_skb(skb); out: @@ -937,12 +942,10 @@ static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock, m->msg_namelen = 0; if (skb) { - struct pppoe_hdr *ph = pppoe_hdr(skb); - const int len = ntohs(ph->length); - - error = memcpy_toiovec(m->msg_iov, (unsigned char *) &ph->tag[0], len); + total_len = min(total_len, skb->len); + error = skb_copy_datagram_iovec(skb, 0, m->msg_iov, total_len); if (error == 0) - error = len; + error = total_len; } kfree_skb(skb); -- cgit v1.2.3 From bc6cffd177f9266af38dba96a2cea06c1e7ff932 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 10 Jun 2008 14:08:25 -0700 Subject: pppoe: Unshare skb before anything else We need to unshare the skb first as otherwise pskb_may_pull may write to a shared skb which could be bad. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/pppoe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index d89ccfd6650c..bafb69b6f7cb 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -432,12 +432,12 @@ static int pppoe_disc_rcv(struct sk_buff *skb, if (dev_net(dev) != &init_net) goto abort; - if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) - goto abort; - if (!(skb = skb_share_check(skb, GFP_ATOMIC))) goto out; + if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) + goto abort; + ph = pppoe_hdr(skb); if (ph->code != PADT_CODE) goto abort; -- cgit v1.2.3 From 738eca74d1bd3e51180de179b7b74d4e34c4e5a3 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Tue, 10 Jun 2008 14:13:09 -0700 Subject: sparc: get leo framebuffer working This patch fixes several issues: Use the right openprom device name so the driver is actually loaded. Fix a crash due to unitialized info->pseudo_palette. Put the framebuffer in the proper mode for software rendering. checkpatch cleanups. Hardware acceleration was removed when the driver was rewritten for the new framebuffer API in 2003. Software rendering requires a different framebuffer access mode but that wasn't changed. The driver now works again but is slow. The proper fix is to reintroduce hardware acceleration. Signed-off-by: Robert Reif Signed-off-by: David S. Miller --- drivers/video/leo.c | 58 ++++++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 8bc46e930340..13fea61d6ae4 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -17,8 +17,8 @@ #include #include #include +#include -#include #include #include "sbuslib.h" @@ -33,7 +33,6 @@ static int leo_blank(int, struct fb_info *); static int leo_mmap(struct fb_info *, struct vm_area_struct *); static int leo_ioctl(struct fb_info *, unsigned int, unsigned long); -static int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *); /* * Frame buffer operations @@ -43,7 +42,6 @@ static struct fb_ops leo_ops = { .owner = THIS_MODULE, .fb_setcolreg = leo_setcolreg, .fb_blank = leo_blank, - .fb_pan_display = leo_pan_display, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, @@ -78,7 +76,7 @@ static struct fb_ops leo_ops = { #define LEO_CUR_TYPE_CMAP 0x00000050 struct leo_cursor { - u8 xxx0[16]; + u8 xxx0[16]; u32 cur_type; u32 cur_misc; u32 cur_cursxy; @@ -105,7 +103,7 @@ struct leo_lx_krn { struct leo_lc_ss0_krn { u32 misc; - u8 xxx0[0x800-4]; + u8 xxx0[0x800-4]; u32 rev; }; @@ -116,7 +114,7 @@ struct leo_lc_ss0_usr { u32 fontt; u32 extent; u32 src; - u32 dst; + u32 dst; u32 copy; u32 fill; }; @@ -129,8 +127,8 @@ struct leo_lc_ss1_usr { u8 unknown; }; -struct leo_ld { - u8 xxx0[0xe00]; +struct leo_ld_ss0 { + u8 xxx0[0xe00]; u32 csr; u32 wid; u32 wmask; @@ -144,13 +142,13 @@ struct leo_ld { u32 src; /* Copy/Scroll (SS0 only) */ u32 dst; /* Copy/Scroll/Fill (SS0 only) */ u32 extent; /* Copy/Scroll/Fill size (SS0 only) */ - u32 xxx1[3]; + u32 xxx1[3]; u32 setsem; /* SS1 only */ u32 clrsem; /* SS1 only */ u32 clrpick; /* SS1 only */ u32 clrdat; /* SS1 only */ u32 alpha; /* SS1 only */ - u8 xxx2[0x2c]; + u8 xxx2[0x2c]; u32 winbg; u32 planemask; u32 rop; @@ -199,11 +197,12 @@ struct leo_par { static void leo_wait(struct leo_lx_krn __iomem *lx_krn) { int i; - + for (i = 0; - (sbus_readl(&lx_krn->krn_csr) & LEO_KRN_CSR_PROGRESS) && i < 300000; + (sbus_readl(&lx_krn->krn_csr) & LEO_KRN_CSR_PROGRESS) && + i < 300000; i++) - udelay (1); /* Busy wait at most 0.3 sec */ + udelay(1); /* Busy wait at most 0.3 sec */ return; } @@ -221,7 +220,7 @@ static int leo_setcolreg(unsigned regno, unsigned transp, struct fb_info *info) { struct leo_par *par = (struct leo_par *) info->par; - struct leo_lx_krn __iomem *lx_krn = par->lx_krn; + struct leo_lx_krn __iomem *lx_krn = par->lx_krn; unsigned long flags; u32 val; int i; @@ -408,7 +407,7 @@ static void leo_wid_put(struct fb_info *info, struct fb_wid_list *wl) leo_wait(lx_krn); for (i = 0, wi = wl->wl_list; i < wl->wl_count; i++, wi++) { - switch(wi->wi_type) { + switch (wi->wi_type) { case FB_WID_DBL_8: j = (wi->wi_index & 0xf) + 0x40; break; @@ -453,13 +452,12 @@ static void leo_init_wids(struct fb_info *info) wi.wi_index = 1; wi.wi_values [0] = 0x30; leo_wid_put(info, &wl); - } static void leo_switch_from_graph(struct fb_info *info) { struct leo_par *par = (struct leo_par *) info->par; - struct leo_ld __iomem *ss = (struct leo_ld __iomem *) par->ld_ss0; + struct leo_ld_ss0 __iomem *ss = par->ld_ss0; unsigned long flags; u32 val; @@ -485,19 +483,13 @@ static void leo_switch_from_graph(struct fb_info *info) val = sbus_readl(&par->lc_ss0_usr->csr); } while (val & 0x20000000); - spin_unlock_irqrestore(&par->lock, flags); -} - -static int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) -{ - /* We just use this to catch switches out of - * graphics mode. - */ - leo_switch_from_graph(info); + /* setup screen buffer for cfb_* functions */ + sbus_writel(1, &ss->wid); + sbus_writel(0x00ffffff, &ss->planemask); + sbus_writel(0x310b90, &ss->rop); + sbus_writel(0, &par->lc_ss0_usr->addrspace); - if (var->xoffset || var->yoffset || var->vmode) - return -EINVAL; - return 0; + spin_unlock_irqrestore(&par->lock, flags); } static void leo_init_hw(struct fb_info *info) @@ -542,7 +534,8 @@ static void leo_unmap_regs(struct of_device *op, struct fb_info *info, of_iounmap(&op->resource[0], info->screen_base, 0x800000); } -static int __devinit leo_probe(struct of_device *op, const struct of_device_id *match) +static int __devinit leo_probe(struct of_device *op, + const struct of_device_id *match) { struct device_node *dp = op->node; struct fb_info *info; @@ -594,8 +587,9 @@ static int __devinit leo_probe(struct of_device *op, const struct of_device_id * !info->screen_base) goto out_unmap_regs; - info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + info->flags = FBINFO_DEFAULT; info->fbops = &leo_ops; + info->pseudo_palette = par->clut_data; leo_init_wids(info); leo_init_hw(info); @@ -649,7 +643,7 @@ static int __devexit leo_remove(struct of_device *op) static struct of_device_id leo_match[] = { { - .name = "leo", + .name = "SUNW,leo", }, {}, }; -- cgit v1.2.3 From dbdbb87636e882042cbe53d5d4eac94206f8db83 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 10 Jun 2008 21:21:56 +0000 Subject: [CIFS] Fix hang in mount when negprot causes server to kill tcp session Acked-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/CHANGES | 5 +++++ fs/cifs/connect.c | 1 + 2 files changed, 6 insertions(+) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 28e3d5c5fcac..1f3465201fdf 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -2,6 +2,11 @@ Version 1.53 ------------ DFS support added (Microsoft Distributed File System client support needed for referrals which enable a hierarchical name space among servers). +Disable temporary caching of mode bits to servers which do not support +storing of mode (e.g. Windows servers, when client mounts without cifsacl +mount option) and add new "dynperm" mount option to enable temporary caching +of mode (enable old behavior). Fix hang on mount caused when server crashes +tcp session during negotiate protocol. Version 1.52 ------------ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d49e274f8eba..e8fa46c7cff2 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -653,6 +653,7 @@ multi_t2_fnd: spin_lock(&GlobalMid_Lock); server->tcpStatus = CifsExiting; spin_unlock(&GlobalMid_Lock); + wake_up_all(&server->response_q); /* don't exit until kthread_stop is called */ set_current_state(TASK_UNINTERRUPTIBLE); -- cgit v1.2.3 From 99c6f60e72f112b57ddb07abb2e5f771ee211f43 Mon Sep 17 00:00:00 2001 From: Jamal Hadi Salim Date: Tue, 10 Jun 2008 14:25:34 -0700 Subject: ipsec: pfkey should ignore events when no listeners When pfkey has no km listeners, it still does a lot of work before finding out there aint nobody out there. If a tree falls in a forest and no one is around to hear it, does it make a sound? In this case it makes a lot of noise: With this short-circuit adding 10s of thousands of SAs using netlink improves performance by ~10%. Signed-off-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- net/key/af_key.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/key/af_key.c b/net/key/af_key.c index 9bba7ac5fee0..7470e367272b 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3030,6 +3030,9 @@ static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c) static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c) { + if (atomic_read(&pfkey_socks_nr) == 0) + return 0; + switch (c->event) { case XFRM_MSG_EXPIRE: return key_notify_sa_expire(x, c); -- cgit v1.2.3 From 79ee9a8b2d328243488fee8b55bfacc822049a2a Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 10 Jun 2008 21:37:02 +0000 Subject: [CIFS] cifs: fix oops on mount when CONFIG_CIFS_DFS_UPCALL is enabled simple "mount -t cifs //xxx /mnt" oopsed on strlen of options http://kerneloops.org/guilty.php?guilty=cifs_get_sb&version=2.6.25-release&start=16711 \ 68&end=1703935&class=oops Signed-off-by: Marcin Slusarz Acked-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 5df93fd6303f..86b4d5f405ae 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -97,9 +97,6 @@ cifs_read_super(struct super_block *sb, void *data, { struct inode *inode; struct cifs_sb_info *cifs_sb; -#ifdef CONFIG_CIFS_DFS_UPCALL - int len; -#endif int rc = 0; /* BB should we make this contingent on mount parm? */ @@ -117,15 +114,17 @@ cifs_read_super(struct super_block *sb, void *data, * complex operation (mount), and in case of fail * just exit instead of doing mount and attempting * undo it if this copy fails?*/ - len = strlen(data); - cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL); - if (cifs_sb->mountdata == NULL) { - kfree(sb->s_fs_info); - sb->s_fs_info = NULL; - return -ENOMEM; + if (data) { + int len = strlen(data); + cifs_sb->mountdata = kzalloc(len + 1, GFP_KERNEL); + if (cifs_sb->mountdata == NULL) { + kfree(sb->s_fs_info); + sb->s_fs_info = NULL; + return -ENOMEM; + } + strncpy(cifs_sb->mountdata, data, len + 1); + cifs_sb->mountdata[len] = '\0'; } - strncpy(cifs_sb->mountdata, data, len + 1); - cifs_sb->mountdata[len] = '\0'; #endif rc = cifs_mount(sb, cifs_sb, data, devname); -- cgit v1.2.3 From 4db0ee176e256444695ee2d7b004552e82fec987 Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Mon, 9 Jun 2008 16:51:06 -0700 Subject: forcedeth: msi interrupts Add a workaround for lost MSI interrupts. There is a race condition in the HW in which future interrupts could be missed. The workaround is to toggle the MSI irq mask. Added cleanup based on comments from Andrew Morton. Signed-off-by: Ayaz Abdulla Cc: Manfred Spraul Cc: Jeff Garzik Cc: Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 9eca97fb0a54..2cb244763292 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -3273,6 +3273,20 @@ static void nv_link_irq(struct net_device *dev) dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name); } +static void nv_msi_workaround(struct fe_priv *np) +{ + + /* Need to toggle the msi irq mask within the ethernet device, + * otherwise, future interrupts will not be detected. + */ + if (np->msi_flags & NV_MSI_ENABLED) { + u8 __iomem *base = np->base; + + writel(0, base + NvRegMSIIrqMask); + writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask); + } +} + static irqreturn_t nv_nic_irq(int foo, void *data) { struct net_device *dev = (struct net_device *) data; @@ -3295,6 +3309,8 @@ static irqreturn_t nv_nic_irq(int foo, void *data) if (!(events & np->irqmask)) break; + nv_msi_workaround(np); + spin_lock(&np->lock); nv_tx_done(dev); spin_unlock(&np->lock); @@ -3410,6 +3426,8 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) if (!(events & np->irqmask)) break; + nv_msi_workaround(np); + spin_lock(&np->lock); nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); spin_unlock(&np->lock); @@ -3750,6 +3768,8 @@ static irqreturn_t nv_nic_irq_test(int foo, void *data) if (!(events & NVREG_IRQ_TIMER)) return IRQ_RETVAL(0); + nv_msi_workaround(np); + spin_lock(&np->lock); np->intr_test = 1; spin_unlock(&np->lock); -- cgit v1.2.3 From ff68cdbf86f09e602eb2b04e1a7d448a3c3a3b28 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Mon, 9 Jun 2008 15:57:17 -0700 Subject: ixgbe: fix typo Define names were accidently transposed. Signed-off-by: Jeff Kirsher Signed-off-by: Jeff Garzik --- drivers/net/ixgbe/ixgbe_82598.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 6321b059ce13..2f38e847e2cd 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -58,8 +58,8 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw); static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) { - hw->mac.num_rx_queues = IXGBE_82598_MAX_TX_QUEUES; - hw->mac.num_tx_queues = IXGBE_82598_MAX_RX_QUEUES; + hw->mac.num_rx_queues = IXGBE_82598_MAX_RX_QUEUES; + hw->mac.num_tx_queues = IXGBE_82598_MAX_TX_QUEUES; hw->mac.num_rx_addrs = IXGBE_82598_RAR_ENTRIES; /* PHY ops are filled in by default properly for Fiber only */ -- cgit v1.2.3 From bf4d593479e0a3f349118f9b8c40a6bc37bf1e2e Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 10 Jun 2008 01:22:16 +0300 Subject: add missing lance_* exports This patch fixes the following build error: <-- snip --> ... Building modules, stage 2. MODPOST 1203 modules ERROR: "lance_open" [drivers/net/mvme147.ko] undefined! ERROR: "lance_close" [drivers/net/mvme147.ko] undefined! ERROR: "lance_tx_timeout" [drivers/net/mvme147.ko] undefined! ERROR: "lance_set_multicast" [drivers/net/mvme147.ko] undefined! ERROR: "lance_start_xmit" [drivers/net/mvme147.ko] undefined! ... make[2]: *** [__modpost] Error 1 <-- snip --> Reported-by: Adrian Bunk Signed-off-by: Adrian Bunk Signed-off-by: Jeff Garzik --- drivers/net/7990.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/7990.c b/drivers/net/7990.c index 750a46f4bc58..ad6b8a5b6574 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -506,6 +506,7 @@ int lance_open (struct net_device *dev) return res; } +EXPORT_SYMBOL_GPL(lance_open); int lance_close (struct net_device *dev) { @@ -521,6 +522,7 @@ int lance_close (struct net_device *dev) return 0; } +EXPORT_SYMBOL_GPL(lance_close); void lance_tx_timeout(struct net_device *dev) { @@ -529,7 +531,7 @@ void lance_tx_timeout(struct net_device *dev) dev->trans_start = jiffies; netif_wake_queue (dev); } - +EXPORT_SYMBOL_GPL(lance_tx_timeout); int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) { @@ -586,6 +588,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) return 0; } +EXPORT_SYMBOL_GPL(lance_start_xmit); /* taken from the depca driver via a2065.c */ static void lance_load_multicast (struct net_device *dev) @@ -654,6 +657,7 @@ void lance_set_multicast (struct net_device *dev) if (!stopped) netif_start_queue (dev); } +EXPORT_SYMBOL_GPL(lance_set_multicast); #ifdef CONFIG_NET_POLL_CONTROLLER void lance_poll(struct net_device *dev) -- cgit v1.2.3 From 23bdfdd388723b8213f597743b1d4aba0d62de9c Mon Sep 17 00:00:00 2001 From: Steve Hodgson Date: Mon, 9 Jun 2008 19:34:32 +0100 Subject: sfc: Recover from RX queue flush failure RX queue flush can fail if traffic continues to arrive. Recover by performing an invisible reset. Signed-off-by: Ben Hutchings Signed-off-by: Jeff Garzik --- drivers/net/sfc/falcon.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index d3f749c72d41..790db89db345 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -733,8 +733,10 @@ void falcon_fini_rx(struct efx_rx_queue *rx_queue) continue; break; } - if (rc) + if (rc) { EFX_ERR(efx, "failed to flush rx queue %d\n", rx_queue->queue); + efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); + } /* Remove RX descriptor ring from card */ EFX_ZERO_OWORD(rx_desc_ptr); -- cgit v1.2.3 From 00aaea2f95d73d4e2b5e45cf77c3cbb16c59e87f Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Mon, 9 Jun 2008 15:17:37 +0100 Subject: ehea: set mac address fix eHEA has to call firmware functions in order to change the mac address of a logical port. This patch checks if the logical port is up when calling the register / deregister mac address calls. If the port is down these firmware calls would fail and are therefore not executed. Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea_main.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 287a61918739..faae01dc1c4b 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -1766,16 +1766,20 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa) mutex_lock(&ehea_bcmc_regs.lock); /* Deregister old MAC in pHYP */ - ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC); - if (ret) - goto out_upregs; + if (port->state == EHEA_PORT_UP) { + ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC); + if (ret) + goto out_upregs; + } port->mac_addr = cb0->port_mac_addr << 16; /* Register new MAC in pHYP */ - ret = ehea_broadcast_reg_helper(port, H_REG_BCMC); - if (ret) - goto out_upregs; + if (port->state == EHEA_PORT_UP) { + ret = ehea_broadcast_reg_helper(port, H_REG_BCMC); + if (ret) + goto out_upregs; + } ret = 0; -- cgit v1.2.3 From 23cde76d801246a702e7a84c3fe3d655b35c89a1 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Sun, 8 Jun 2008 20:49:00 +1000 Subject: virtio_net: Fix skb->csum_start computation hdr->csum_start is the offset from the start of the ethernet header to the transport layer checksum field. skb->csum_start is the offset from skb->head. skb_partial_csum_set() assumes that skb->data points to the ethernet header - i.e. it computes skb->csum_start by adding the headroom to hdr->csum_start. Since eth_type_trans() skb_pull()s the ethernet header, skb_partial_csum_set() should be called before eth_type_trans(). (Without this patch, GSO packets from a guest to the world outside the host are corrupted). Signed-off-by: Mark McLoughlin Acked-by: Herbert Xu Signed-off-by: Rusty Russell Signed-off-by: Jeff Garzik --- drivers/net/virtio_net.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 5450eac9e263..9a3b85e55ccc 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -94,9 +94,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, BUG_ON(len > MAX_PACKET_LEN); skb_trim(skb, len); - skb->protocol = eth_type_trans(skb, dev); - pr_debug("Receiving skb proto 0x%04x len %i type %i\n", - ntohs(skb->protocol), skb->len, skb->pkt_type); + dev->stats.rx_bytes += skb->len; dev->stats.rx_packets++; @@ -106,6 +104,10 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, goto frame_err; } + skb->protocol = eth_type_trans(skb, dev); + pr_debug("Receiving skb proto 0x%04x len %i type %i\n", + ntohs(skb->protocol), skb->len, skb->pkt_type); + if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { pr_debug("GSO!\n"); switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { -- cgit v1.2.3 From 2506ece0c0bbd2fc19a4827b96dc52ea47e2ce4a Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Sun, 8 Jun 2008 20:49:59 +1000 Subject: virtio: Fix typo in virtio_net_hdr comments Signed-off-by: Mark McLoughlin Signed-off-by: Rusty Russell Signed-off-by: Jeff Garzik --- include/linux/virtio_net.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h index 9405aa6cdf26..38c0571820fb 100644 --- a/include/linux/virtio_net.h +++ b/include/linux/virtio_net.h @@ -38,7 +38,7 @@ struct virtio_net_hdr #define VIRTIO_NET_HDR_GSO_ECN 0x80 // TCP has ECN set __u8 gso_type; __u16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */ - __u16 gso_size; /* Bytes to append to gso_hdr_len per frame */ + __u16 gso_size; /* Bytes to append to hdr_len per frame */ __u16 csum_start; /* Position to start checksumming from */ __u16 csum_offset; /* Offset after that to place checksum */ }; -- cgit v1.2.3 From 14c998f034bdc9a5bfa53bca18fbd0738cbc65e8 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Sun, 8 Jun 2008 20:50:56 +1000 Subject: virtio: virtio_net free transmit skbs in a timer virtio_net currently only frees old transmit skbs just before queueing new ones. If the queue is full, it then enables interrupts and waits for notification that more work has been performed. However, a side-effect of this scheme is that there are always xmit skbs left dangling when no new packets are sent, against the Documentation/networking/driver.txt guideline: "... it is not allowed for your TX mitigation scheme to let TX packets "hang out" in the TX ring unreclaimed forever if no new TX packets are sent." Add a timer to ensure that any time we queue new TX skbs, we will shortly free them again. This fixes an easily reproduced hang at shutdown where iptables attempts to unload nf_conntrack and nf_conntrack waits for an skb it is tracking to be freed, but virtio_net never frees it. Signed-off-by: Mark McLoughlin Signed-off-by: Rusty Russell Signed-off-by: Jeff Garzik --- drivers/net/virtio_net.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 9a3b85e55ccc..156d76fee164 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -44,6 +44,8 @@ struct virtnet_info /* The skb we couldn't send because buffers were full. */ struct sk_buff *last_xmit_skb; + struct timer_list xmit_free_timer; + /* Number of input buffers, and max we've ever had. */ unsigned int num, max; @@ -240,9 +242,23 @@ static void free_old_xmit_skbs(struct virtnet_info *vi) } } +static void xmit_free(unsigned long data) +{ + struct virtnet_info *vi = (void *)data; + + netif_tx_lock(vi->dev); + + free_old_xmit_skbs(vi); + + if (!skb_queue_empty(&vi->send)) + mod_timer(&vi->xmit_free_timer, jiffies + (HZ/10)); + + netif_tx_unlock(vi->dev); +} + static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) { - int num; + int num, err; struct scatterlist sg[2+MAX_SKB_FRAGS]; struct virtio_net_hdr *hdr; const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; @@ -285,7 +301,11 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) vnet_hdr_to_sg(sg, skb); num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; - return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); + err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); + if (!err) + mod_timer(&vi->xmit_free_timer, jiffies + (HZ/10)); + + return err; } static void xmit_tasklet(unsigned long data) @@ -456,6 +476,8 @@ static int virtnet_probe(struct virtio_device *vdev) tasklet_init(&vi->tasklet, xmit_tasklet, (unsigned long)vi); + setup_timer(&vi->xmit_free_timer, xmit_free, (unsigned long)vi); + err = register_netdev(dev); if (err) { pr_debug("virtio_net: registering device failed\n"); @@ -493,6 +515,8 @@ static void virtnet_remove(struct virtio_device *vdev) /* Stop all the virtqueues. */ vdev->config->reset(vdev); + del_timer_sync(&vi->xmit_free_timer); + /* Free our skbs in send and recv queues, if any. */ while ((skb = __skb_dequeue(&vi->recv)) != NULL) { kfree_skb(skb); -- cgit v1.2.3 From 363f15149cfba67d29f1e6a6103dda079f27f3fa Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 8 Jun 2008 20:51:55 +1000 Subject: virtio: use callback on empty in virtio_net virtio_net uses a timer to free old transmitted packets, rather than leaving callbacks enabled all the time. If the host promises to always notify us when the transmit ring is empty, we can free packets at that point and avoid the timer. Signed-off-by: Rusty Russell Signed-off-by: Jeff Garzik --- drivers/net/virtio_net.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 156d76fee164..4452306d5328 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -44,6 +44,7 @@ struct virtnet_info /* The skb we couldn't send because buffers were full. */ struct sk_buff *last_xmit_skb; + /* If we need to free in a timer, this is it. */ struct timer_list xmit_free_timer; /* Number of input buffers, and max we've ever had. */ @@ -51,6 +52,7 @@ struct virtnet_info /* For cleaning up after transmission. */ struct tasklet_struct tasklet; + bool free_in_tasklet; /* Receive & send queues. */ struct sk_buff_head recv; @@ -74,7 +76,7 @@ static void skb_xmit_done(struct virtqueue *svq) /* Suppress further interrupts. */ svq->vq_ops->disable_cb(svq); - /* We were waiting for more output buffers. */ + /* We were probably waiting for more output buffers. */ netif_wake_queue(vi->dev); /* Make sure we re-xmit last_xmit_skb: if there are no more packets @@ -242,6 +244,8 @@ static void free_old_xmit_skbs(struct virtnet_info *vi) } } +/* If the virtio transport doesn't always notify us when all in-flight packets + * are consumed, we fall back to using this function on a timer to free them. */ static void xmit_free(unsigned long data) { struct virtnet_info *vi = (void *)data; @@ -302,7 +306,7 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); - if (!err) + if (!err && !vi->free_in_tasklet) mod_timer(&vi->xmit_free_timer, jiffies + (HZ/10)); return err; @@ -317,6 +321,8 @@ static void xmit_tasklet(unsigned long data) vi->svq->vq_ops->kick(vi->svq); vi->last_xmit_skb = NULL; } + if (vi->free_in_tasklet) + free_old_xmit_skbs(vi); netif_tx_unlock_bh(vi->dev); } @@ -457,6 +463,10 @@ static int virtnet_probe(struct virtio_device *vdev) vi->vdev = vdev; vdev->priv = vi; + /* If they give us a callback when all buffers are done, we don't need + * the timer. */ + vi->free_in_tasklet = virtio_has_feature(vdev,VIRTIO_F_NOTIFY_ON_EMPTY); + /* We expect two virtqueues, receive then send. */ vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done); if (IS_ERR(vi->rvq)) { @@ -476,7 +486,8 @@ static int virtnet_probe(struct virtio_device *vdev) tasklet_init(&vi->tasklet, xmit_tasklet, (unsigned long)vi); - setup_timer(&vi->xmit_free_timer, xmit_free, (unsigned long)vi); + if (!vi->free_in_tasklet) + setup_timer(&vi->xmit_free_timer, xmit_free, (unsigned long)vi); err = register_netdev(dev); if (err) { @@ -515,7 +526,8 @@ static void virtnet_remove(struct virtio_device *vdev) /* Stop all the virtqueues. */ vdev->config->reset(vdev); - del_timer_sync(&vi->xmit_free_timer); + if (!vi->free_in_tasklet) + del_timer_sync(&vi->xmit_free_timer); /* Free our skbs in send and recv queues, if any. */ while ((skb = __skb_dequeue(&vi->recv)) != NULL) { @@ -540,7 +552,7 @@ static struct virtio_device_id id_table[] = { static unsigned int features[] = { VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC, VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, - VIRTIO_NET_F_HOST_ECN, + VIRTIO_NET_F_HOST_ECN, VIRTIO_F_NOTIFY_ON_EMPTY, }; static struct virtio_driver virtio_net = { -- cgit v1.2.3 From e5bd7be56787f8c5042081157fff983bcf0c8a42 Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Fri, 6 Jun 2008 12:37:44 +0200 Subject: qeth: layer 3 Oops in ip event handler The ip event handler may present us non qeth network interfaces. Add qeth card pointer check. Signed-off-by: Frank Blaschka Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth_l3_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 94a8ead64ed4..b041ea8c9577 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2070,7 +2070,7 @@ static struct qeth_card *qeth_l3_get_card_from_dev(struct net_device *dev) card = netdev_priv(dev); else if (rc == QETH_VLAN_CARD) card = netdev_priv(vlan_dev_info(dev)->real_dev); - if (card->options.layer2) + if (card && card->options.layer2) card = NULL; QETH_DBF_TEXT_(TRACE, 4, "%d", rc); return card ; -- cgit v1.2.3 From f06f6f3224afdd7e58207d1f5950f4666c5f095f Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Fri, 6 Jun 2008 12:37:45 +0200 Subject: qeth: Use ccw_device_get_id(). Get the devno from the ccw device via ccw_device_get_id() instead of parsing the bus_id. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky Signed-off-by: Frank Blaschka Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth_core_main.c | 11 +++-------- drivers/s390/net/qeth_l2_main.c | 11 ++++------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 436bf1f6d4a6..5a71ae909366 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1407,12 +1407,6 @@ static void qeth_init_func_level(struct qeth_card *card) } } -static inline __u16 qeth_raw_devno_from_bus_id(char *id) -{ - id += (strlen(id) - 4); - return (__u16) simple_strtoul(id, &id, 16); -} - static int qeth_idx_activate_get_answer(struct qeth_channel *channel, void (*idx_reply_cb)(struct qeth_channel *, struct qeth_cmd_buffer *)) @@ -1468,6 +1462,7 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel, __u16 temp; __u8 tmp; int rc; + struct ccw_dev_id temp_devid; card = CARD_FROM_CDEV(channel->ccwdev); @@ -1494,8 +1489,8 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel, &card->token.issuer_rm_w, QETH_MPC_TOKEN_LENGTH); memcpy(QETH_IDX_ACT_FUNC_LEVEL(iob->data), &card->info.func_level, sizeof(__u16)); - temp = qeth_raw_devno_from_bus_id(CARD_DDEV_ID(card)); - memcpy(QETH_IDX_ACT_QDIO_DEV_CUA(iob->data), &temp, 2); + ccw_device_get_id(CARD_DDEV(card), &temp_devid); + memcpy(QETH_IDX_ACT_QDIO_DEV_CUA(iob->data), &temp_devid.devno, 2); temp = (card->info.cula << 8) + card->info.unit_addr2; memcpy(QETH_IDX_ACT_QDIO_DEV_REALADDR(iob->data), &temp, 2); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 86ec50ddae13..d35a74c3b475 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -101,19 +101,16 @@ static struct net_device *qeth_l2_netdev_by_devno(unsigned char *read_dev_no) { struct qeth_card *card; struct net_device *ndev; - unsigned char *readno; - __u16 temp_dev_no, card_dev_no; - char *endp; + __u16 temp_dev_no; unsigned long flags; + struct ccw_dev_id read_devid; ndev = NULL; memcpy(&temp_dev_no, read_dev_no, 2); read_lock_irqsave(&qeth_core_card_list.rwlock, flags); list_for_each_entry(card, &qeth_core_card_list.list, list) { - readno = CARD_RDEV_ID(card); - readno += (strlen(readno) - 4); - card_dev_no = simple_strtoul(readno, &endp, 16); - if (card_dev_no == temp_dev_no) { + ccw_device_get_id(CARD_RDEV(card), &read_devid); + if (read_devid.devno == temp_dev_no) { ndev = card->dev; break; } -- cgit v1.2.3 From 14cc21b6770972e5d1487dbf3a2caaf63cae909a Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Fri, 6 Jun 2008 12:37:46 +0200 Subject: qeth: reduce number of kernel messages Remove unnecessary messages. Write important debug information to s390dbf. Signed-off-by: Frank Blaschka Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth_core_main.c | 30 ++++------------ drivers/s390/net/qeth_core_offl.c | 6 ++-- drivers/s390/net/qeth_core_sys.c | 12 ------- drivers/s390/net/qeth_l2_main.c | 29 ++++++---------- drivers/s390/net/qeth_l3_main.c | 72 ++++++++++++--------------------------- drivers/s390/net/qeth_l3_sys.c | 24 ------------- 6 files changed, 42 insertions(+), 131 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 5a71ae909366..f428d757e888 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -290,9 +290,6 @@ int qeth_set_large_send(struct qeth_card *card, card->dev->features |= NETIF_F_TSO | NETIF_F_SG | NETIF_F_HW_CSUM; } else { - PRINT_WARN("TSO not supported on %s. " - "large_send set to 'no'.\n", - card->dev->name); card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | NETIF_F_HW_CSUM); card->options.large_send = QETH_LARGE_SEND_NO; @@ -1433,7 +1430,7 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel, spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); if (rc) { - PRINT_ERR("Error2 in activating channel rc=%d\n", rc); + QETH_DBF_MESSAGE(2, "Error2 in activating channel rc=%d\n", rc); QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); atomic_set(&channel->irq_pending, 0); wake_up(&card->wait_q); @@ -1503,7 +1500,8 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel, spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); if (rc) { - PRINT_ERR("Error1 in activating channel. rc=%d\n", rc); + QETH_DBF_MESSAGE(2, "Error1 in activating channel. rc=%d\n", + rc); QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); atomic_set(&channel->irq_pending, 0); wake_up(&card->wait_q); @@ -1653,7 +1651,6 @@ int qeth_send_control_data(struct qeth_card *card, int len, reply = qeth_alloc_reply(card); if (!reply) { - PRINT_WARN("Could not alloc qeth_reply!\n"); return -ENOMEM; } reply->callback = reply_cb; @@ -2607,15 +2604,9 @@ void qeth_queue_input_buffer(struct qeth_card *card, int index) if (newcount < count) { /* we are in memory shortage so we switch back to traditional skb allocation and drop packages */ - if (!atomic_read(&card->force_alloc_skb) && - net_ratelimit()) - PRINT_WARN("Switch to alloc skb\n"); atomic_set(&card->force_alloc_skb, 3); count = newcount; } else { - if ((atomic_read(&card->force_alloc_skb) == 1) && - net_ratelimit()) - PRINT_WARN("Switch to sg\n"); atomic_add_unless(&card->force_alloc_skb, -1, 0); } @@ -3029,7 +3020,7 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr, elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) + skb->len) >> PAGE_SHIFT); if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { - PRINT_ERR("Invalid size of IP packet " + QETH_DBF_MESSAGE(2, "Invalid size of IP packet " "(Number=%d / Length=%d). Discarded.\n", (elements_needed+elems), skb->len); return 0; @@ -3242,8 +3233,6 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, * free buffers) to handle eddp context */ if (qeth_eddp_check_buffers_for_context(queue, ctx) < 0) { - if (net_ratelimit()) - PRINT_WARN("eddp tx_dropped 1\n"); rc = -EBUSY; goto out; } @@ -3255,7 +3244,6 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, tmp = qeth_eddp_fill_buffer(queue, ctx, queue->next_buf_to_fill); if (tmp < 0) { - PRINT_ERR("eddp tx_dropped 2\n"); rc = -EBUSY; goto out; } @@ -3597,8 +3585,6 @@ int qeth_snmp_command(struct qeth_card *card, char __user *udata) if ((!qeth_adp_supported(card, IPA_SETADP_SET_SNMP_CONTROL)) && (!card->options.layer2)) { - PRINT_WARN("SNMP Query MIBS not supported " - "on %s!\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } /* skip 4 bytes (data_len struct member) to get req_len */ @@ -3629,7 +3615,7 @@ int qeth_snmp_command(struct qeth_card *card, char __user *udata) rc = qeth_send_ipa_snmp_cmd(card, iob, QETH_SETADP_BASE_LEN + req_len, qeth_snmp_command_cb, (void *)&qinfo); if (rc) - PRINT_WARN("SNMP command failed on %s: (0x%x)\n", + QETH_DBF_MESSAGE(2, "SNMP command failed on %s: (0x%x)\n", QETH_CARD_IFNAME(card), rc); else { if (copy_to_user(udata, qinfo.udata, qinfo.udata_len)) @@ -3802,8 +3788,8 @@ retry: if (mpno) mpno = min(mpno - 1, QETH_MAX_PORTNO); if (card->info.portno > mpno) { - PRINT_ERR("Device %s does not offer port number %d \n.", - CARD_BUS_ID(card), card->info.portno); + QETH_DBF_MESSAGE(2, "Device %s does not offer port number %d" + "\n.", CARD_BUS_ID(card), card->info.portno); rc = -ENODEV; goto out; } @@ -3980,8 +3966,6 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, return skb; no_mem: if (net_ratelimit()) { - PRINT_WARN("No memory for packet received on %s.\n", - QETH_CARD_IFNAME(card)); QETH_DBF_TEXT(TRACE, 2, "noskbmem"); QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_BUS_ID(card)); } diff --git a/drivers/s390/net/qeth_core_offl.c b/drivers/s390/net/qeth_core_offl.c index 822df8362856..452874e89740 100644 --- a/drivers/s390/net/qeth_core_offl.c +++ b/drivers/s390/net/qeth_core_offl.c @@ -122,8 +122,8 @@ int qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue, if (element == 0) return -EBUSY; else { - PRINT_WARN("could only partially fill eddp " - "buffer!\n"); + QETH_DBF_MESSAGE(2, "could only partially fill" + "eddp buffer!\n"); goto out; } } @@ -143,8 +143,6 @@ int qeth_eddp_fill_buffer(struct qeth_qdio_out_q *queue, if (must_refcnt) { must_refcnt = 0; if (qeth_eddp_buf_ref_context(buf, ctx)) { - PRINT_WARN("no memory to create eddp context " - "reference\n"); goto out_check; } } diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c index 08a50f057284..c26e842ad905 100644 --- a/drivers/s390/net/qeth_core_sys.c +++ b/drivers/s390/net/qeth_core_sys.c @@ -129,7 +129,6 @@ static ssize_t qeth_dev_portno_store(struct device *dev, portno = simple_strtoul(buf, &tmp, 16); if (portno > QETH_MAX_PORTNO) { - PRINT_WARN("portno 0x%X is out of range\n", portno); return -EINVAL; } @@ -223,8 +222,6 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev, * if though we have to permit priority queueing */ if (card->qdio.no_out_queues == 1) { - PRINT_WARN("Priority queueing disabled due " - "to hardware limitations!\n"); card->qdio.do_prio_queueing = QETH_PRIOQ_DEFAULT; return -EPERM; } @@ -250,7 +247,6 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev, card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING; card->qdio.default_out_queue = QETH_DEFAULT_QUEUE; } else { - PRINT_WARN("Unknown queueing type '%s'\n", tmp); return -EINVAL; } return count; @@ -291,9 +287,6 @@ static ssize_t qeth_dev_bufcnt_store(struct device *dev, ((cnt > QETH_IN_BUF_COUNT_MAX) ? QETH_IN_BUF_COUNT_MAX : cnt); if (old_cnt != cnt) { rc = qeth_realloc_buffer_pool(card, cnt); - if (rc) - PRINT_WARN("Error (%d) while setting " - "buffer count.\n", rc); } return count; } @@ -355,7 +348,6 @@ static ssize_t qeth_dev_performance_stats_store(struct device *dev, card->perf_stats.initial_rx_packets = card->stats.rx_packets; card->perf_stats.initial_tx_packets = card->stats.tx_packets; } else { - PRINT_WARN("performance_stats: write 0 or 1 to this file!\n"); return -EINVAL; } return count; @@ -399,7 +391,6 @@ static ssize_t qeth_dev_layer2_store(struct device *dev, newdis = QETH_DISCIPLINE_LAYER2; break; default: - PRINT_WARN("layer2: write 0 or 1 to this file!\n"); return -EINVAL; } @@ -463,7 +454,6 @@ static ssize_t qeth_dev_large_send_store(struct device *dev, } else if (!strcmp(tmp, "TSO")) { type = QETH_LARGE_SEND_TSO; } else { - PRINT_WARN("large_send: invalid mode %s!\n", tmp); return -EINVAL; } if (card->options.large_send == type) @@ -503,8 +493,6 @@ static ssize_t qeth_dev_blkt_store(struct qeth_card *card, if (i <= max_value) { *value = i; } else { - PRINT_WARN("blkt total time: write values between" - " 0 and %d to this file!\n", max_value); return -EINVAL; } return count; diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index d35a74c3b475..dd7659c8de16 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -131,14 +131,14 @@ static int qeth_l2_send_setgroupmac_cb(struct qeth_card *card, mac = &cmd->data.setdelmac.mac[0]; /* MAC already registered, needed in couple/uncouple case */ if (cmd->hdr.return_code == 0x2005) { - PRINT_WARN("Group MAC %02x:%02x:%02x:%02x:%02x:%02x " \ + QETH_DBF_MESSAGE(2, "Group MAC %02x:%02x:%02x:%02x:%02x:%02x " "already existing on %s \n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], QETH_CARD_IFNAME(card)); cmd->hdr.return_code = 0; } if (cmd->hdr.return_code) - PRINT_ERR("Could not set group MAC " \ + QETH_DBF_MESSAGE(2, "Could not set group MAC " "%02x:%02x:%02x:%02x:%02x:%02x on %s: %x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], QETH_CARD_IFNAME(card), cmd->hdr.return_code); @@ -163,7 +163,7 @@ static int qeth_l2_send_delgroupmac_cb(struct qeth_card *card, cmd = (struct qeth_ipa_cmd *) data; mac = &cmd->data.setdelmac.mac[0]; if (cmd->hdr.return_code) - PRINT_ERR("Could not delete group MAC " \ + QETH_DBF_MESSAGE(2, "Could not delete group MAC " "%02x:%02x:%02x:%02x:%02x:%02x on %s: %x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], QETH_CARD_IFNAME(card), cmd->hdr.return_code); @@ -183,10 +183,8 @@ static void qeth_l2_add_mc(struct qeth_card *card, __u8 *mac) mc = kmalloc(sizeof(struct qeth_mc_mac), GFP_ATOMIC); - if (!mc) { - PRINT_ERR("no mem vor mc mac address\n"); + if (!mc) return; - } memcpy(mc->mc_addr, mac, OSA_ADDR_LEN); mc->mc_addrlen = OSA_ADDR_LEN; @@ -277,7 +275,7 @@ static int qeth_l2_send_setdelvlan_cb(struct qeth_card *card, QETH_DBF_TEXT(TRACE, 2, "L2sdvcb"); cmd = (struct qeth_ipa_cmd *) data; if (cmd->hdr.return_code) { - PRINT_ERR("Error in processing VLAN %i on %s: 0x%x. " + QETH_DBF_MESSAGE(2, "Error in processing VLAN %i on %s: 0x%x. " "Continuing\n", cmd->data.setdelvlan.vlan_id, QETH_CARD_IFNAME(card), cmd->hdr.return_code); QETH_DBF_TEXT_(TRACE, 2, "L2VL%4x", cmd->hdr.command); @@ -330,8 +328,6 @@ static void qeth_l2_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) spin_lock_bh(&card->vlanlock); list_add_tail(&id->list, &card->vid_list); spin_unlock_bh(&card->vlanlock); - } else { - PRINT_ERR("no memory for vid\n"); } } @@ -547,16 +543,15 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card) rc = qeth_query_setadapterparms(card); if (rc) { - PRINT_WARN("could not query adapter parameters on device %s: " - "x%x\n", CARD_BUS_ID(card), rc); + QETH_DBF_MESSAGE(2, "could not query adapter parameters on " + "device %s: x%x\n", CARD_BUS_ID(card), rc); } if (card->info.guestlan) { rc = qeth_setadpparms_change_macaddr(card); if (rc) { - PRINT_WARN("couldn't get MAC address on " - "device %s: x%x\n", - CARD_BUS_ID(card), rc); + QETH_DBF_MESSAGE(2, "couldn't get MAC address on " + "device %s: x%x\n", CARD_BUS_ID(card), rc); QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); return rc; } @@ -582,8 +577,6 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p) } if (card->info.type == QETH_CARD_TYPE_OSN) { - PRINT_WARN("Setting MAC address on %s is not supported.\n", - dev->name); QETH_DBF_TEXT(TRACE, 3, "setmcOSN"); return -EOPNOTSUPP; } @@ -663,7 +656,7 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ctx = qeth_eddp_create_context(card, new_skb, hdr, skb->sk->sk_protocol); if (ctx == NULL) { - PRINT_WARN("could not create eddp context\n"); + QETH_DBF_MESSAGE(2, "could not create eddp context\n"); goto tx_drop; } } else { @@ -1152,7 +1145,7 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len, (addr_t) iob, 0, 0); spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags); if (rc) { - PRINT_WARN("qeth_osn_send_control_data: " + QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: " "ccw_device_start rc = %i\n", rc); QETH_DBF_TEXT_(TRACE, 2, " err%d", rc); qeth_release_buffer(iob->channel, iob); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index b041ea8c9577..de256e48bfe9 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -311,7 +311,6 @@ static struct qeth_ipaddr *qeth_l3_get_addr_buffer( addr = kzalloc(sizeof(struct qeth_ipaddr), GFP_ATOMIC); if (addr == NULL) { - PRINT_WARN("Not enough memory to add address\n"); return NULL; } addr->type = QETH_IP_TYPE_NORMAL; @@ -649,15 +648,6 @@ static void qeth_l3_correct_routing_type(struct qeth_card *card, } } out_inval: - PRINT_WARN("Routing type '%s' not supported for interface %s.\n" - "Router status set to 'no router'.\n", - ((*type == PRIMARY_ROUTER)? "primary router" : - (*type == SECONDARY_ROUTER)? "secondary router" : - (*type == PRIMARY_CONNECTOR)? "primary connector" : - (*type == SECONDARY_CONNECTOR)? "secondary connector" : - (*type == MULTICAST_ROUTER)? "multicast router" : - "unknown"), - card->dev->name); *type = NO_ROUTER; } @@ -674,9 +664,9 @@ int qeth_l3_setrouting_v4(struct qeth_card *card) QETH_PROT_IPV4); if (rc) { card->options.route4.type = NO_ROUTER; - PRINT_WARN("Error (0x%04x) while setting routing type on %s. " - "Type set to 'no router'.\n", - rc, QETH_CARD_IFNAME(card)); + QETH_DBF_MESSAGE(2, "Error (0x%04x) while setting routing type" + " on %s. Type set to 'no router'.\n", rc, + QETH_CARD_IFNAME(card)); } return rc; } @@ -697,9 +687,9 @@ int qeth_l3_setrouting_v6(struct qeth_card *card) QETH_PROT_IPV6); if (rc) { card->options.route6.type = NO_ROUTER; - PRINT_WARN("Error (0x%04x) while setting routing type on %s. " - "Type set to 'no router'.\n", - rc, QETH_CARD_IFNAME(card)); + QETH_DBF_MESSAGE(2, "Error (0x%04x) while setting routing type" + " on %s. Type set to 'no router'.\n", rc, + QETH_CARD_IFNAME(card)); } #endif return rc; @@ -737,7 +727,6 @@ int qeth_l3_add_ipato_entry(struct qeth_card *card, if (!memcmp(ipatoe->addr, new->addr, (ipatoe->proto == QETH_PROT_IPV4)? 4:16) && (ipatoe->mask_bits == new->mask_bits)) { - PRINT_WARN("ipato entry already exists!\n"); rc = -EEXIST; break; } @@ -802,7 +791,6 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto, rc = -EEXIST; spin_unlock_irqrestore(&card->ip_lock, flags); if (rc) { - PRINT_WARN("Cannot add VIPA. Address already exists!\n"); return rc; } if (!qeth_l3_add_ip(card, ipaddr)) @@ -867,7 +855,6 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto, rc = -EEXIST; spin_unlock_irqrestore(&card->ip_lock, flags); if (rc) { - PRINT_WARN("Cannot add RXIP. Address already exists!\n"); return rc; } if (!qeth_l3_add_ip(card, ipaddr)) @@ -1020,23 +1007,23 @@ static int qeth_l3_setadapter_hstr(struct qeth_card *card) IPA_SETADP_SET_BROADCAST_MODE, card->options.broadcast_mode); if (rc) - PRINT_WARN("couldn't set broadcast mode on " + QETH_DBF_MESSAGE(2, "couldn't set broadcast mode on " "device %s: x%x\n", CARD_BUS_ID(card), rc); rc = qeth_l3_send_setadp_mode(card, IPA_SETADP_ALTER_MAC_ADDRESS, card->options.macaddr_mode); if (rc) - PRINT_WARN("couldn't set macaddr mode on " + QETH_DBF_MESSAGE(2, "couldn't set macaddr mode on " "device %s: x%x\n", CARD_BUS_ID(card), rc); return rc; } if (card->options.broadcast_mode == QETH_TR_BROADCAST_LOCAL) - PRINT_WARN("set adapter parameters not available " + QETH_DBF_MESSAGE(2, "set adapter parameters not available " "to set broadcast mode, using ALLRINGS " "on device %s:\n", CARD_BUS_ID(card)); if (card->options.macaddr_mode == QETH_TR_MACADDR_CANONICAL) - PRINT_WARN("set adapter parameters not available " + QETH_DBF_MESSAGE(2, "set adapter parameters not available " "to set macaddr mode, using NONCANONICAL " "on device %s:\n", CARD_BUS_ID(card)); return 0; @@ -2182,8 +2169,6 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries) if (card->info.guestlan) return -EOPNOTSUPP; if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) { - PRINT_WARN("ARP processing not supported " - "on %s!\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } rc = qeth_l3_send_simple_setassparms(card, IPA_ARP_PROCESSING, @@ -2191,8 +2176,8 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries) no_entries); if (rc) { tmp = rc; - PRINT_WARN("Could not set number of ARP entries on %s: " - "%s (0x%x/%d)\n", QETH_CARD_IFNAME(card), + QETH_DBF_MESSAGE(2, "Could not set number of ARP entries on " + "%s: %s (0x%x/%d)\n", QETH_CARD_IFNAME(card), qeth_l3_arp_get_error_cause(&rc), tmp, tmp); } return rc; @@ -2260,9 +2245,6 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card, qdata->no_entries * uentry_size){ QETH_DBF_TEXT_(TRACE, 4, "qaer3%i", -ENOMEM); cmd->hdr.return_code = -ENOMEM; - PRINT_WARN("query ARP user space buffer is too small for " - "the returned number of ARP entries. " - "Aborting query!\n"); goto out_error; } QETH_DBF_TEXT_(TRACE, 4, "anore%i", @@ -2324,8 +2306,6 @@ static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata) if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/ IPA_ARP_PROCESSING)) { - PRINT_WARN("ARP processing not supported " - "on %s!\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } /* get size of userspace buffer and mask_bits -> 6 bytes */ @@ -2344,7 +2324,7 @@ static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata) qeth_l3_arp_query_cb, (void *)&qinfo); if (rc) { tmp = rc; - PRINT_WARN("Error while querying ARP cache on %s: %s " + QETH_DBF_MESSAGE(2, "Error while querying ARP cache on %s: %s " "(0x%x/%d)\n", QETH_CARD_IFNAME(card), qeth_l3_arp_get_error_cause(&rc), tmp, tmp); if (copy_to_user(udata, qinfo.udata, 4)) @@ -2375,8 +2355,6 @@ static int qeth_l3_arp_add_entry(struct qeth_card *card, if (card->info.guestlan) return -EOPNOTSUPP; if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) { - PRINT_WARN("ARP processing not supported " - "on %s!\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } @@ -2391,10 +2369,9 @@ static int qeth_l3_arp_add_entry(struct qeth_card *card, if (rc) { tmp = rc; qeth_l3_ipaddr4_to_string((u8 *)entry->ipaddr, buf); - PRINT_WARN("Could not add ARP entry for address %s on %s: " - "%s (0x%x/%d)\n", - buf, QETH_CARD_IFNAME(card), - qeth_l3_arp_get_error_cause(&rc), tmp, tmp); + QETH_DBF_MESSAGE(2, "Could not add ARP entry for address %s " + "on %s: %s (0x%x/%d)\n", buf, QETH_CARD_IFNAME(card), + qeth_l3_arp_get_error_cause(&rc), tmp, tmp); } return rc; } @@ -2417,8 +2394,6 @@ static int qeth_l3_arp_remove_entry(struct qeth_card *card, if (card->info.guestlan) return -EOPNOTSUPP; if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) { - PRINT_WARN("ARP processing not supported " - "on %s!\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } memcpy(buf, entry, 12); @@ -2433,10 +2408,9 @@ static int qeth_l3_arp_remove_entry(struct qeth_card *card, tmp = rc; memset(buf, 0, 16); qeth_l3_ipaddr4_to_string((u8 *)entry->ipaddr, buf); - PRINT_WARN("Could not delete ARP entry for address %s on %s: " - "%s (0x%x/%d)\n", - buf, QETH_CARD_IFNAME(card), - qeth_l3_arp_get_error_cause(&rc), tmp, tmp); + QETH_DBF_MESSAGE(2, "Could not delete ARP entry for address %s" + " on %s: %s (0x%x/%d)\n", buf, QETH_CARD_IFNAME(card), + qeth_l3_arp_get_error_cause(&rc), tmp, tmp); } return rc; } @@ -2456,16 +2430,14 @@ static int qeth_l3_arp_flush_cache(struct qeth_card *card) if (card->info.guestlan || (card->info.type == QETH_CARD_TYPE_IQD)) return -EOPNOTSUPP; if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) { - PRINT_WARN("ARP processing not supported " - "on %s!\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } rc = qeth_l3_send_simple_setassparms(card, IPA_ARP_PROCESSING, IPA_CMD_ASS_ARP_FLUSH_CACHE, 0); if (rc) { tmp = rc; - PRINT_WARN("Could not flush ARP cache on %s: %s (0x%x/%d)\n", - QETH_CARD_IFNAME(card), + QETH_DBF_MESSAGE(2, "Could not flush ARP cache on %s: %s " + "(0x%x/%d)\n", QETH_CARD_IFNAME(card), qeth_l3_arp_get_error_cause(&rc), tmp, tmp); } return rc; @@ -2724,7 +2696,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ctx = qeth_eddp_create_context(card, new_skb, hdr, skb->sk->sk_protocol); if (ctx == NULL) { - PRINT_WARN("could not create eddp context\n"); + QETH_DBF_MESSAGE(2, "could not create eddp context\n"); goto tx_drop; } } else { diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index 08f51fd902c4..ac1993708ae9 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -85,7 +85,6 @@ static ssize_t qeth_l3_dev_route_store(struct qeth_card *card, } else if (!strcmp(tmp, "multicast_router")) { route->type = MULTICAST_ROUTER; } else { - PRINT_WARN("Invalid routing type '%s'.\n", tmp); return -EINVAL; } if (((card->state == CARD_STATE_SOFTSETUP) || @@ -137,9 +136,6 @@ static ssize_t qeth_l3_dev_route6_store(struct device *dev, return -EINVAL; if (!qeth_is_supported(card, IPA_IPV6)) { - PRINT_WARN("IPv6 not supported for interface %s.\n" - "Routing status no changed.\n", - QETH_CARD_IFNAME(card)); return -ENOTSUPP; } @@ -179,7 +175,6 @@ static ssize_t qeth_l3_dev_fake_broadcast_store(struct device *dev, if ((i == 0) || (i == 1)) card->options.fake_broadcast = i; else { - PRINT_WARN("fake_broadcast: write 0 or 1 to this file!\n"); return -EINVAL; } return count; @@ -220,7 +215,6 @@ static ssize_t qeth_l3_dev_broadcast_mode_store(struct device *dev, if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) || (card->info.link_type == QETH_LINK_TYPE_LANE_TR))) { - PRINT_WARN("Device is not a tokenring device!\n"); return -EINVAL; } @@ -233,8 +227,6 @@ static ssize_t qeth_l3_dev_broadcast_mode_store(struct device *dev, card->options.broadcast_mode = QETH_TR_BROADCAST_ALLRINGS; return count; } else { - PRINT_WARN("broadcast_mode: invalid mode %s!\n", - tmp); return -EINVAL; } return count; @@ -275,7 +267,6 @@ static ssize_t qeth_l3_dev_canonical_macaddr_store(struct device *dev, if (!((card->info.link_type == QETH_LINK_TYPE_HSTR) || (card->info.link_type == QETH_LINK_TYPE_LANE_TR))) { - PRINT_WARN("Device is not a tokenring device!\n"); return -EINVAL; } @@ -285,7 +276,6 @@ static ssize_t qeth_l3_dev_canonical_macaddr_store(struct device *dev, QETH_TR_MACADDR_CANONICAL : QETH_TR_MACADDR_NONCANONICAL; else { - PRINT_WARN("canonical_macaddr: write 0 or 1 to this file!\n"); return -EINVAL; } return count; @@ -327,7 +317,6 @@ static ssize_t qeth_l3_dev_checksum_store(struct device *dev, else if (!strcmp(tmp, "no_checksumming")) card->options.checksum_type = NO_CHECKSUMMING; else { - PRINT_WARN("Unknown checksumming type '%s'\n", tmp); return -EINVAL; } return count; @@ -382,8 +371,6 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev, } else if (!strcmp(tmp, "0")) { card->ipato.enabled = 0; } else { - PRINT_WARN("ipato_enable: write 0, 1 or 'toggle' to " - "this file\n"); return -EINVAL; } return count; @@ -422,8 +409,6 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev, } else if (!strcmp(tmp, "0")) { card->ipato.invert4 = 0; } else { - PRINT_WARN("ipato_invert4: write 0, 1 or 'toggle' to " - "this file\n"); return -EINVAL; } return count; @@ -486,13 +471,10 @@ static int qeth_l3_parse_ipatoe(const char *buf, enum qeth_prot_versions proto, /* get address string */ end = strchr(start, '/'); if (!end || (end - start >= 40)) { - PRINT_WARN("Invalid format for ipato_addx/delx. " - "Use /\n"); return -EINVAL; } strncpy(buffer, start, end - start); if (qeth_l3_string_to_ipaddr(buffer, proto, addr)) { - PRINT_WARN("Invalid IP address format!\n"); return -EINVAL; } start = end + 1; @@ -500,7 +482,6 @@ static int qeth_l3_parse_ipatoe(const char *buf, enum qeth_prot_versions proto, if (!strlen(start) || (tmp == start) || (*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128))) { - PRINT_WARN("Invalid mask bits for ipato_addx/delx !\n"); return -EINVAL; } return 0; @@ -520,7 +501,6 @@ static ssize_t qeth_l3_dev_ipato_add_store(const char *buf, size_t count, ipatoe = kzalloc(sizeof(struct qeth_ipato_entry), GFP_KERNEL); if (!ipatoe) { - PRINT_WARN("No memory to allocate ipato entry\n"); return -ENOMEM; } ipatoe->proto = proto; @@ -609,8 +589,6 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev, } else if (!strcmp(tmp, "0")) { card->ipato.invert6 = 0; } else { - PRINT_WARN("ipato_invert6: write 0, 1 or 'toggle' to " - "this file\n"); return -EINVAL; } return count; @@ -724,7 +702,6 @@ static int qeth_l3_parse_vipae(const char *buf, enum qeth_prot_versions proto, u8 *addr) { if (qeth_l3_string_to_ipaddr(buf, proto, addr)) { - PRINT_WARN("Invalid IP address format!\n"); return -EINVAL; } return 0; @@ -891,7 +868,6 @@ static int qeth_l3_parse_rxipe(const char *buf, enum qeth_prot_versions proto, u8 *addr) { if (qeth_l3_string_to_ipaddr(buf, proto, addr)) { - PRINT_WARN("Invalid IP address format!\n"); return -EINVAL; } return 0; -- cgit v1.2.3 From 345aa66e97e61dccafaaa835e4b20d9b241e187f Mon Sep 17 00:00:00 2001 From: Peter Tiedemann Date: Fri, 6 Jun 2008 12:37:47 +0200 Subject: qeth: Prepare-function to call s390dbf was wrong Prepare-function to call s390dbf was wrong handling variable arguments. This worked as macro but not as function any more. Now using va_list processing. Signed-off-by: Peter Tiedemann Signed-off-by: Frank Blaschka Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth_core_main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index f428d757e888..9a71dae223e8 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3983,15 +3983,17 @@ static void qeth_unregister_dbf_views(void) } } -void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...) +void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *fmt, ...) { char dbf_txt_buf[32]; + va_list args; if (level > (qeth_dbf[dbf_nix].id)->level) return; - snprintf(dbf_txt_buf, sizeof(dbf_txt_buf), text); + va_start(args, fmt); + vsnprintf(dbf_txt_buf, sizeof(dbf_txt_buf), fmt, args); + va_end(args); debug_text_event(qeth_dbf[dbf_nix].id, level, dbf_txt_buf); - } EXPORT_SYMBOL_GPL(qeth_dbf_longtext); -- cgit v1.2.3 From d0ec0f549705b7ecfb787f02512606b08fe5b291 Mon Sep 17 00:00:00 2001 From: Frank Blaschka Date: Fri, 6 Jun 2008 12:37:48 +0200 Subject: qeth: start dev queue after tx drop error In case the xmit function drop out with an error, we have to wake the netdevice queue to start another xmit. Signed-off-by: Frank Blaschka Signed-off-by: Martin Schwidefsky Signed-off-by: Jeff Garzik --- drivers/s390/net/qeth_l2_main.c | 1 + drivers/s390/net/qeth_l3_main.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index dd7659c8de16..f682f7b14480 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -721,6 +721,7 @@ tx_drop: if ((new_skb != skb) && new_skb) dev_kfree_skb_any(new_skb); dev_kfree_skb_any(skb); + netif_wake_queue(dev); return NETDEV_TX_OK; } diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index de256e48bfe9..999552c83bbe 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2764,6 +2764,7 @@ tx_drop: if ((new_skb != skb) && new_skb) dev_kfree_skb_any(new_skb); dev_kfree_skb_any(skb); + netif_wake_queue(dev); return NETDEV_TX_OK; } -- cgit v1.2.3 From ae6b4d9ab6129467415801f30e487bc141a3f471 Mon Sep 17 00:00:00 2001 From: Jay Cliburn Date: Sun, 1 Jun 2008 16:57:11 -0500 Subject: atl1: fix suspend regression Using vendor magic to force the PHY into power save mode breaks suspend. It isn't needed anyway, so remove it. Tested-by: Avuton Olrich Signed-off-by: Jay Cliburn Signed-off-by: Jeff Garzik --- drivers/net/atlx/atl1.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index 6ddc911e7d15..99e0b4cdc56f 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -636,22 +636,6 @@ static s32 atl1_phy_leave_power_saving(struct atl1_hw *hw) return atl1_write_phy_reg(hw, 30, 0); } -/* - * Force the PHY into power saving mode using vendor magic. - */ -#ifdef CONFIG_PM -static void atl1_phy_enter_power_saving(struct atl1_hw *hw) -{ - atl1_write_phy_reg(hw, MII_DBG_ADDR, 0); - atl1_write_phy_reg(hw, MII_DBG_DATA, 0x124E); - atl1_write_phy_reg(hw, MII_DBG_ADDR, 2); - atl1_write_phy_reg(hw, MII_DBG_DATA, 0x3000); - atl1_write_phy_reg(hw, MII_DBG_ADDR, 3); - atl1_write_phy_reg(hw, MII_DBG_DATA, 0); - -} -#endif - /* * Resets the PHY and make all config validate * hw - Struct containing variables accessed by shared code @@ -2860,7 +2844,6 @@ disable_wol: ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; iowrite32(ctrl, hw->hw_addr + REG_PCIE_PHYMISC); ioread32(hw->hw_addr + REG_PCIE_PHYMISC); - atl1_phy_enter_power_saving(hw); hw->phy_configured = false; pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); exit: -- cgit v1.2.3 From 69de8d23d10694bdd63fe715b98e1a61c56ed288 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 2 Jun 2008 10:59:02 +0100 Subject: s2io iomem annotations Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index a20693e09ae8..b5c1e663417d 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -2861,7 +2861,8 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) struct config_param *config; struct mac_info *mac_control; int pkts_processed = 0; - u8 *addr = NULL, val8 = 0; + u8 __iomem *addr = NULL; + u8 val8 = 0; struct s2io_nic *nic = dev->priv; struct XENA_dev_config __iomem *bar0 = nic->bar0; int budget_org = budget; @@ -2878,7 +2879,7 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) if (pkts_processed < budget_org) { netif_rx_complete(dev, napi); /*Re Enable MSI-Rx Vector*/ - addr = (u8 *)&bar0->xmsi_mask_reg; + addr = (u8 __iomem *)&bar0->xmsi_mask_reg; addr += 7 - ring->ring_no; val8 = (ring->ring_no == 0) ? 0x3f : 0xbf; writeb(val8, addr); @@ -4364,9 +4365,10 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) return IRQ_HANDLED; if (sp->config.napi) { - u8 *addr = NULL, val8 = 0; + u8 __iomem *addr = NULL; + u8 val8 = 0; - addr = (u8 *)&bar0->xmsi_mask_reg; + addr = (u8 __iomem *)&bar0->xmsi_mask_reg; addr += (7 - ring->ring_no); val8 = (ring->ring_no == 0) ? 0x7f : 0xff; writeb(val8, addr); -- cgit v1.2.3 From 68c2889834602f6efed195f44439ef5d526683a8 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 31 May 2008 16:52:52 +0100 Subject: sky2: Hold RTNL while calling dev_close() dev_close() must be called holding the RTNL. Signed-off-by: Ben Hutchings Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 3bb60530d4d7..62436b3a18c6 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -4404,7 +4404,9 @@ static int sky2_resume(struct pci_dev *pdev) if (err) { printk(KERN_ERR PFX "%s: could not up: %d\n", dev->name, err); + rtnl_lock(); dev_close(dev); + rtnl_unlock(); goto out; } } -- cgit v1.2.3 From 709772e6e06564ed94ba740de70185ac3d792773 Mon Sep 17 00:00:00 2001 From: Krzysztof Piotr Oledzki Date: Tue, 10 Jun 2008 15:44:49 -0700 Subject: net: Fix routing tables with id > 255 for legacy software Most legacy software do not like tables > 255 as rtm_table is u8 so tb_id is sent &0xff and it is possible to mismatch for example table 510 with table 254 (main). This patch introduces RT_TABLE_COMPAT=252 so the code uses it if tb_id > 255. It makes such old applications happy, new ones are still able to use RTA_TABLE to get a proper table id. Signed-off-by: Krzysztof Piotr Oledzki Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/rtnetlink.h | 1 + net/ipv4/fib_semantics.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index a2aec2c0cfb5..b358c704d102 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -246,6 +246,7 @@ enum rt_class_t { RT_TABLE_UNSPEC=0, /* User defined values */ + RT_TABLE_COMPAT=252, RT_TABLE_DEFAULT=253, RT_TABLE_MAIN=254, RT_TABLE_LOCAL=255, diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 3b83c34019fc..0d4d72827e4b 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -960,7 +960,10 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, rtm->rtm_dst_len = dst_len; rtm->rtm_src_len = 0; rtm->rtm_tos = tos; - rtm->rtm_table = tb_id; + if (tb_id < 256) + rtm->rtm_table = tb_id; + else + rtm->rtm_table = RT_TABLE_COMPAT; NLA_PUT_U32(skb, RTA_TABLE, tb_id); rtm->rtm_type = type; rtm->rtm_flags = fi->fib_flags; -- cgit v1.2.3 From 3294f202dc1acd82223e83ef59f272bd87bb06b2 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 11 Jun 2008 11:19:09 +0100 Subject: dccp ccid-3: Bug-Fix - Zero RTT is possible In commit $(825de27d9e40b3117b29a79d412b7a4b78c5d815) (from 27th May, commit message `dccp ccid-3: Fix "t_ipi explosion" bug'), the CCID-3 window counter computation was fixed to cope with RTTs < 4 microseconds. Such RTTs can be found e.g. when running CCID-3 over loopback. The fix removed a check against RTT < 4, but introduced a divide-by-zero bug. All steady-state RTTs in DCCP are filtered using dccp_sample_rtt(), which ensures non-zero samples. However, a zero RTT is possible on initialisation, when there is no RTT sample from the Request/Response exchange. The fix is to use the fallback-RTT from RFC 4340, 3.4. This is also better than just fixing update_win_count() since it allows other parts of the code to always assume that the RTT is non-zero during the time that the CCID is used. Signed-off-by: Gerrit Renker --- net/dccp/ccids/ccid3.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index f813077234b7..0474f4c5707a 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -329,8 +329,14 @@ static int ccid3_hc_tx_send_packet(struct sock *sk, struct sk_buff *skb) hctx->ccid3hctx_x = rfc3390_initial_rate(sk); hctx->ccid3hctx_t_ld = now; } else { - /* Sender does not have RTT sample: X_pps = 1 pkt/sec */ - hctx->ccid3hctx_x = hctx->ccid3hctx_s; + /* + * Sender does not have RTT sample: + * - set fallback RTT (RFC 4340, 3.4) since a RTT value + * is needed in several parts (e.g. window counter); + * - set sending rate X_pps = 1pps as per RFC 3448, 4.2. + */ + hctx->ccid3hctx_rtt = DCCP_FALLBACK_RTT; + hctx->ccid3hctx_x = hctx->ccid3hctx_s; hctx->ccid3hctx_x <<= 6; } ccid3_update_send_interval(hctx); -- cgit v1.2.3 From 1e2f0e5e8376f2a0ada8760fc9d3104e1a81382b Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 11 Jun 2008 11:19:09 +0100 Subject: dccp: Fix sparse warnings This patch fixes the following sparse warnings: * nested min(max()) expression: net/dccp/ccids/ccid3.c:91:21: warning: symbol '__x' shadows an earlier one net/dccp/ccids/ccid3.c:91:21: warning: symbol '__y' shadows an earlier one * Declaration of function prototypes in .c instead of .h file, resulting in "should it be static?" warnings. * Declared "struct dccpw" static (local to dccp_probe). * Disabled dccp_delayed_ack() - not fully removed due to RFC 4340, 11.3 ("Receivers SHOULD implement delayed acknowledgement timers ..."). * Used a different local variable name to avoid net/dccp/ackvec.c:293:13: warning: symbol 'state' shadows an earlier one net/dccp/ackvec.c:238:33: originally declared here * Removed unused functions `dccp_ackvector_print' and `dccp_ackvec_print'. Signed-off-by: Gerrit Renker --- net/dccp/ackvec.c | 29 ++--------------------------- net/dccp/ccids/ccid3.c | 4 ++-- net/dccp/ccids/lib/tfrc.c | 8 -------- net/dccp/ccids/lib/tfrc.h | 11 +++++++++-- net/dccp/output.c | 2 ++ net/dccp/probe.c | 2 +- 6 files changed, 16 insertions(+), 40 deletions(-) diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 6de4bd195d28..1e8be246ad15 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c @@ -290,12 +290,12 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, while (1) { const u8 len = dccp_ackvec_len(av, index); - const u8 state = dccp_ackvec_state(av, index); + const u8 av_state = dccp_ackvec_state(av, index); /* * valid packets not yet in av_buf have a reserved * entry, with a len equal to 0. */ - if (state == DCCP_ACKVEC_STATE_NOT_RECEIVED && + if (av_state == DCCP_ACKVEC_STATE_NOT_RECEIVED && len == 0 && delta == 0) { /* Found our reserved seat! */ dccp_pr_debug("Found %llu reserved seat!\n", @@ -325,31 +325,6 @@ out_duplicate: return -EILSEQ; } -#ifdef CONFIG_IP_DCCP_DEBUG -void dccp_ackvector_print(const u64 ackno, const unsigned char *vector, int len) -{ - dccp_pr_debug_cat("ACK vector len=%d, ackno=%llu |", len, - (unsigned long long)ackno); - - while (len--) { - const u8 state = (*vector & DCCP_ACKVEC_STATE_MASK) >> 6; - const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK; - - dccp_pr_debug_cat("%d,%d|", state, rl); - ++vector; - } - - dccp_pr_debug_cat("\n"); -} - -void dccp_ackvec_print(const struct dccp_ackvec *av) -{ - dccp_ackvector_print(av->av_buf_ackno, - av->av_buf + av->av_buf_head, - av->av_vec_len); -} -#endif - static void dccp_ackvec_throw_record(struct dccp_ackvec *av, struct dccp_ackvec_record *avr) { diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 0474f4c5707a..a1929f33d703 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -159,8 +159,8 @@ static void ccid3_hc_tx_update_x(struct sock *sk, ktime_t *stamp) } else if (ktime_us_delta(now, hctx->ccid3hctx_t_ld) - (s64)hctx->ccid3hctx_rtt >= 0) { - hctx->ccid3hctx_x = - max(min(2 * hctx->ccid3hctx_x, min_rate), + hctx->ccid3hctx_x = min(2 * hctx->ccid3hctx_x, min_rate); + hctx->ccid3hctx_x = max(hctx->ccid3hctx_x, scaled_div(((__u64)hctx->ccid3hctx_s) << 6, hctx->ccid3hctx_rtt)); hctx->ccid3hctx_t_ld = now; diff --git a/net/dccp/ccids/lib/tfrc.c b/net/dccp/ccids/lib/tfrc.c index d1dfbb8de64c..97ecec0a8e76 100644 --- a/net/dccp/ccids/lib/tfrc.c +++ b/net/dccp/ccids/lib/tfrc.c @@ -14,14 +14,6 @@ module_param(tfrc_debug, bool, 0444); MODULE_PARM_DESC(tfrc_debug, "Enable debug messages"); #endif -extern int tfrc_tx_packet_history_init(void); -extern void tfrc_tx_packet_history_exit(void); -extern int tfrc_rx_packet_history_init(void); -extern void tfrc_rx_packet_history_exit(void); - -extern int tfrc_li_init(void); -extern void tfrc_li_exit(void); - static int __init tfrc_module_init(void) { int rc = tfrc_li_init(); diff --git a/net/dccp/ccids/lib/tfrc.h b/net/dccp/ccids/lib/tfrc.h index 1fb1187bbf1c..ddd8107b927f 100644 --- a/net/dccp/ccids/lib/tfrc.h +++ b/net/dccp/ccids/lib/tfrc.h @@ -58,7 +58,14 @@ static inline u32 tfrc_ewma(const u32 avg, const u32 newval, const u8 weight) return avg ? (weight * avg + (10 - weight) * newval) / 10 : newval; } -extern u32 tfrc_calc_x(u16 s, u32 R, u32 p); -extern u32 tfrc_calc_x_reverse_lookup(u32 fvalue); +extern u32 tfrc_calc_x(u16 s, u32 R, u32 p); +extern u32 tfrc_calc_x_reverse_lookup(u32 fvalue); +extern int tfrc_tx_packet_history_init(void); +extern void tfrc_tx_packet_history_exit(void); +extern int tfrc_rx_packet_history_init(void); +extern void tfrc_rx_packet_history_exit(void); + +extern int tfrc_li_init(void); +extern void tfrc_li_exit(void); #endif /* _TFRC_H_ */ diff --git a/net/dccp/output.c b/net/dccp/output.c index 1f8a9b64c083..fe20068c5d8e 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -508,6 +508,7 @@ void dccp_send_ack(struct sock *sk) EXPORT_SYMBOL_GPL(dccp_send_ack); +#if 0 /* FIXME: Is this still necessary (11.3) - currently nowhere used by DCCP. */ void dccp_send_delayed_ack(struct sock *sk) { @@ -538,6 +539,7 @@ void dccp_send_delayed_ack(struct sock *sk) icsk->icsk_ack.timeout = timeout; sk_reset_timer(sk, &icsk->icsk_delack_timer, timeout); } +#endif void dccp_send_sync(struct sock *sk, const u64 ackno, const enum dccp_pkt_type pkt_type) diff --git a/net/dccp/probe.c b/net/dccp/probe.c index 0bcdc9250279..81368a7f5379 100644 --- a/net/dccp/probe.c +++ b/net/dccp/probe.c @@ -42,7 +42,7 @@ static int bufsize = 64 * 1024; static const char procname[] = "dccpprobe"; -struct { +static struct { struct kfifo *fifo; spinlock_t lock; wait_queue_head_t wait; -- cgit v1.2.3 From 65907a433ac0ca450c4408080f24c6e4743386b2 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 11 Jun 2008 11:19:09 +0100 Subject: dccp ccid-2: Bug-Fix - Ack Vectors need to be ignored on request sockets This fixes an oversight from an earlier patch, ensuring that Ack Vectors are not processed on request sockets. The issue is that Ack Vectors must not be parsed on request sockets, since the Ack Vector feature depends on the selection of the (TX) CCID. During the initial handshake the CCIDs are undefined, and so RFC 4340, 10.3 applies: "Using CCID-specific options and feature options during a negotiation for the corresponding CCID feature is NOT RECOMMENDED [...]" And it is not even possible: when the server receives the Request from the client, the CCID and Ack vector features are undefined; when the Ack finalising the 3-way hanshake arrives, the request socket has not been cloned yet into a full socket. (This order is necessary, since otherwise the newly created socket would have to be destroyed whenever an option error occurred - a malicious hacker could simply send garbage options and exploit this.) Signed-off-by: Gerrit Renker --- net/dccp/options.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/dccp/options.c b/net/dccp/options.c index d2a84a2fecee..43bc24e761d0 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -107,9 +107,11 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, * * CCID-specific options are ignored during connection setup, as * negotiation may still be in progress (see RFC 4340, 10.3). + * The same applies to Ack Vectors, as these depend on the CCID. * */ - if (dreq != NULL && opt >= 128) + if (dreq != NULL && (opt >= 128 || + opt == DCCPO_ACK_VECTOR_0 || opt == DCCPO_ACK_VECTOR_1)) goto ignore_option; switch (opt) { -- cgit v1.2.3 From 1e8a287c79f64226541f5c44aa52d4698bb84cf5 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 11 Jun 2008 11:19:10 +0100 Subject: dccp ccid-3: TFRC reverse-lookup Bug-Fix This fixes a bug in the reverse lookup of p: given a value f(p), instead of p, the function returned the smallest tabulated value f(p). The smallest tabulated value of 10^6 * f(p) = sqrt(2*p/3) + 12 * sqrt(3*p/8) * (32 * p^3 + p) for p=0.0001 is 8172. Since this value is scaled by 10^6, the outcome of this bug is that a loss of 8172/10^6 = 0.8172% was reported whenever the input was below the table resolution of 0.01%. This means that the value was over 80 times too high, resulting in large spikes of the initial loss interval, thus unnecessarily reducing the throughput. Also corrected the printk format (%u for u32). Signed-off-by: Gerrit Renker --- net/dccp/ccids/lib/tfrc_equation.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/dccp/ccids/lib/tfrc_equation.c b/net/dccp/ccids/lib/tfrc_equation.c index e4e64b76c10c..2f20a29cffe4 100644 --- a/net/dccp/ccids/lib/tfrc_equation.c +++ b/net/dccp/ccids/lib/tfrc_equation.c @@ -661,7 +661,7 @@ u32 tfrc_calc_x(u16 s, u32 R, u32 p) EXPORT_SYMBOL_GPL(tfrc_calc_x); -/* +/** * tfrc_calc_x_reverse_lookup - try to find p given f(p) * * @fvalue: function value to match, scaled by 1000000 @@ -676,11 +676,11 @@ u32 tfrc_calc_x_reverse_lookup(u32 fvalue) /* Error cases. */ if (fvalue < tfrc_calc_x_lookup[0][1]) { - DCCP_WARN("fvalue %d smaller than resolution\n", fvalue); - return tfrc_calc_x_lookup[0][1]; + DCCP_WARN("fvalue %u smaller than resolution\n", fvalue); + return TFRC_SMALLEST_P; } if (fvalue > tfrc_calc_x_lookup[TFRC_CALC_X_ARRSIZE - 1][0]) { - DCCP_WARN("fvalue %d exceeds bounds!\n", fvalue); + DCCP_WARN("fvalue %u exceeds bounds!\n", fvalue); return 1000000; } -- cgit v1.2.3 From 7deb0f851003287d7e259bf6b33548b144c0f2d5 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 11 Jun 2008 11:19:10 +0100 Subject: dccp ccid-3: X truncated due to type conversion This fixes a bug in computing the inter-packet-interval t_ipi = s/X: scaled_div32(a, b) uses u32 for b, but in "scaled_div32(s, X)" the type of the sending rate `X' is u64. Since X is scaled by 2^6, this truncates rates greater than 2^26 Bps (~537 Mbps). Using full 64-bit division now. Signed-off-by: Gerrit Renker --- net/dccp/ccids/lib/tfrc.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/net/dccp/ccids/lib/tfrc.h b/net/dccp/ccids/lib/tfrc.h index ddd8107b927f..ed9857527acf 100644 --- a/net/dccp/ccids/lib/tfrc.h +++ b/net/dccp/ccids/lib/tfrc.h @@ -15,7 +15,7 @@ * (at your option) any later version. */ #include -#include +#include #include "../../dccp.h" /* internal includes that this module exports: */ #include "loss_interval.h" @@ -29,21 +29,19 @@ extern int tfrc_debug; #endif /* integer-arithmetic divisions of type (a * 1000000)/b */ -static inline u64 scaled_div(u64 a, u32 b) +static inline u64 scaled_div(u64 a, u64 b) { BUG_ON(b==0); - a *= 1000000; - do_div(a, b); - return a; + return div64_u64(a * 1000000, b); } -static inline u32 scaled_div32(u64 a, u32 b) +static inline u32 scaled_div32(u64 a, u64 b) { u64 result = scaled_div(a, b); if (result > UINT_MAX) { - DCCP_CRIT("Overflow: a(%llu)/b(%u) > ~0U", - (unsigned long long)a, b); + DCCP_CRIT("Overflow: %llu/%llu > UINT_MAX", + (unsigned long long)a, (unsigned long long)b); return UINT_MAX; } return result; -- cgit v1.2.3 From be4c798a41bf626cdaacf96c382f116ed2f7dbe9 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Wed, 11 Jun 2008 11:19:10 +0100 Subject: dccp: Bug in initial acknowledgment number assignment Step 8.5 in RFC 4340 says for the newly cloned socket Initialize S.GAR := S.ISS, but what in fact the code (minisocks.c) does is Initialize S.GAR := S.ISR, which is wrong (typo?) -- fixed by the patch. Signed-off-by: Gerrit Renker --- net/dccp/minisocks.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 33ad48321b08..66dca5bba858 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -165,12 +165,12 @@ out_free: /* See dccp_v4_conn_request */ newdmsk->dccpms_sequence_window = req->rcv_wnd; - newdp->dccps_gar = newdp->dccps_isr = dreq->dreq_isr; - dccp_update_gsr(newsk, dreq->dreq_isr); - - newdp->dccps_iss = dreq->dreq_iss; + newdp->dccps_gar = newdp->dccps_iss = dreq->dreq_iss; dccp_update_gss(newsk, dreq->dreq_iss); + newdp->dccps_isr = dreq->dreq_isr; + dccp_update_gsr(newsk, dreq->dreq_isr); + /* * SWL and AWL are initially adjusted so that they are not less than * the initial Sequence Numbers received and sent, respectively: -- cgit v1.2.3 From 7427d8b815c7fc0b005a17cf3952b7ebef0481d2 Mon Sep 17 00:00:00 2001 From: Bryan Wu Date: Wed, 11 Jun 2008 12:08:39 +0800 Subject: smc91x: fix build error from the SMC_GET_MAC_ADDR API change Cc: Jeff Garzik Cc: Andrew Morton Signed-off-by: Bryan Wu Signed-off-by: Linus Torvalds --- drivers/net/smc91x.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 69e97a1cb1c4..8606818653f8 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -93,14 +93,14 @@ #define SMC_insw(a, r, p, l) insw ((unsigned long *)((a) + (r)), p, l) # endif /* check if the mac in reg is valid */ -#define SMC_GET_MAC_ADDR(addr) \ +#define SMC_GET_MAC_ADDR(lp, addr) \ do { \ unsigned int __v; \ - __v = SMC_inw(ioaddr, ADDR0_REG); \ + __v = SMC_inw(ioaddr, ADDR0_REG(lp)); \ addr[0] = __v; addr[1] = __v >> 8; \ - __v = SMC_inw(ioaddr, ADDR1_REG); \ + __v = SMC_inw(ioaddr, ADDR1_REG(lp)); \ addr[2] = __v; addr[3] = __v >> 8; \ - __v = SMC_inw(ioaddr, ADDR2_REG); \ + __v = SMC_inw(ioaddr, ADDR2_REG(lp)); \ addr[4] = __v; addr[5] = __v >> 8; \ if (*(u32 *)(&addr[0]) == 0xFFFFFFFF) { \ random_ether_addr(addr); \ -- cgit v1.2.3 From a4aff2233786640c10b178ad78d4dd7e375f1955 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 5 Jun 2008 10:43:14 +0100 Subject: [ARM] 5077/1: spi: fix list scan success verification in PXA ssp driver The list search success check in arch/arm/mach-pxa/ssp.c is wrong: for example, it didn't recognise failure for me when I requested port 0. Signed-off-by: Guennadi Liakhovetski Acked-by: Eric Miao Signed-off-by: Russell King --- arch/arm/mach-pxa/ssp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c index 00af7f2fed66..0bb31982fb6f 100644 --- a/arch/arm/mach-pxa/ssp.c +++ b/arch/arm/mach-pxa/ssp.c @@ -330,7 +330,7 @@ struct ssp_device *ssp_request(int port, const char *label) mutex_unlock(&ssp_lock); - if (ssp->port_id != port) + if (&ssp->node == &ssp_list) return NULL; return ssp; -- cgit v1.2.3 From 62cfcf4f467733a8dc218691c791804a148da887 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Schindele?= Date: Wed, 11 Jun 2008 19:56:06 +0100 Subject: [ARM] 5090/1: Correct pxafb palette typo error This patch correct a typo error in pxafb vhich is relevant for 8-bit palette framebuffer configuration. Signed-off-by: Jrgen Schindele Acked-by: Eric Miao Signed-off-by: Russell King --- drivers/video/pxafb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 274bc93ab7d8..7dcda187d9ba 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -573,8 +573,8 @@ static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal, dma_desc->fdadr = fbi->dma_buff_phys + dma_desc_off; fbi->fdadr[dma] = fbi->dma_buff_phys + dma_desc_off; } else { - pal_desc = &fbi->dma_buff->pal_desc[dma]; - pal_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[pal]); + pal_desc = &fbi->dma_buff->pal_desc[pal]; + pal_desc_off = offsetof(struct pxafb_dma_buff, pal_desc[pal]); pal_desc->fsadr = fbi->dma_buff_phys + pal * PALETTE_SIZE; pal_desc->fidr = 0; @@ -1276,6 +1276,8 @@ static int __init pxafb_map_video_memory(struct pxafb_info *fbi) fbi->dma_buff_phys = fbi->map_dma; fbi->palette_cpu = (u16 *) fbi->dma_buff->palette; + pr_debug("pxafb: palette_mem_size = 0x%08lx\n", fbi->palette_size*sizeof(u16)); + #ifdef CONFIG_FB_PXA_SMARTPANEL fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff; fbi->n_smart_cmds = 0; -- cgit v1.2.3 From e1094bfa26e5e94af2fea79e004614dbce42b008 Mon Sep 17 00:00:00 2001 From: Zhao Yakui Date: Wed, 14 May 2008 11:32:59 +0800 Subject: ACPI: Disable Fixed_RTC event when installing RTC handler The Fixed_RTC event should be disabled when installing RTC handler. Only when RTC alarm is set will it be enabled again. If it is not disabled, maybe some machines will be powered on automatically after the system is shutdown even when the RTC alarm is not set. http://bugzilla.kernel.org/show_bug.cgi?id=10010 Signed-off-by: Zhao Yakui Signed-off-by: Zhang Rui Signed-off-by: Len Brown --- drivers/acpi/glue.c | 6 ++++++ drivers/acpi/sleep/proc.c | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 06f8634fe58b..2808dc60fd67 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -272,6 +272,12 @@ static u32 rtc_handler(void *context) static inline void rtc_wake_setup(void) { acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); + /* + * After the RTC handler is installed, the Fixed_RTC event should + * be disabled. Only when the RTC alarm is set will it be enabled. + */ + acpi_clear_event(ACPI_EVENT_RTC); + acpi_disable_event(ACPI_EVENT_RTC, 0); } static void rtc_wake_on(struct device *dev) diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index 8a5fe8710513..224c57c03381 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -495,6 +495,12 @@ static int __init acpi_sleep_proc_init(void) acpi_root_dir, &acpi_system_alarm_fops); acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); + /* + * Disable the RTC event after installing RTC handler. + * Only when RTC alarm is set will it be enabled. + */ + acpi_clear_event(ACPI_EVENT_RTC); + acpi_disable_event(ACPI_EVENT_RTC, 0); #endif /* HAVE_ACPI_LEGACY_ALARM */ /* 'wakeup device' [R/W] */ -- cgit v1.2.3 From dcb84f335bee9c9a7781cfc5d74492dccaf066d2 Mon Sep 17 00:00:00 2001 From: Venkatesh Pallipadi Date: Mon, 19 May 2008 19:09:27 -0400 Subject: cpuidle acpi driver: fix oops on AC<->DC cpuidle and acpi driver interaction bug with the way cpuidle_register_driver() is called. Due to this bug, there will be oops on AC<->DC on some systems, where they support C-states in one DC and not in AC. The current code does ON BOOT: Look at CST and other C-state info to see whether more than C1 is supported. If it is, then acpi processor_idle does a cpuidle_register_driver() call, which internally enables the device. ON CST change notification (AC<->DC) and on suspend-resume: acpi driver temporarily disables device, updates the device with any new C-states, and reenables the device. The problem is is on boot, there are no C2, C3 states supported and we skip the register. Later on AC<->DC, we may get a CST notification and we try to reevaluate CST and enabled the device, without actually registering it. This causes breakage as we try to create /sys fs sub directory, without the parent directory which is created at register time. Thanks to Sanjeev for reporting the problem here. http://bugzilla.kernel.org/show_bug.cgi?id=10394 Signed-off-by: Venkatesh Pallipadi Signed-off-by: Len Brown --- drivers/acpi/processor_idle.c | 13 +++++++------ drivers/cpuidle/cpuidle.c | 40 +++++++++++++++++++++++++++++++++++----- include/linux/cpuidle.h | 1 + 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 2dd2c1f3a01c..556ee1585192 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1669,6 +1669,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) return -EINVAL; } + dev->cpu = pr->id; for (i = 0; i < CPUIDLE_STATE_MAX; i++) { dev->states[i].name[0] = '\0'; dev->states[i].desc[0] = '\0'; @@ -1738,7 +1739,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) int acpi_processor_cst_has_changed(struct acpi_processor *pr) { - int ret; + int ret = 0; if (boot_option_idle_override) return 0; @@ -1756,8 +1757,10 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) cpuidle_pause_and_lock(); cpuidle_disable_device(&pr->power.dev); acpi_processor_get_power_info(pr); - acpi_processor_setup_cpuidle(pr); - ret = cpuidle_enable_device(&pr->power.dev); + if (pr->flags.power) { + acpi_processor_setup_cpuidle(pr); + ret = cpuidle_enable_device(&pr->power.dev); + } cpuidle_resume_and_unlock(); return ret; @@ -1813,7 +1816,6 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, if (pr->flags.power) { #ifdef CONFIG_CPU_IDLE acpi_processor_setup_cpuidle(pr); - pr->power.dev.cpu = pr->id; if (cpuidle_register_device(&pr->power.dev)) return -EIO; #endif @@ -1850,8 +1852,7 @@ int acpi_processor_power_exit(struct acpi_processor *pr, return 0; #ifdef CONFIG_CPU_IDLE - if (pr->flags.power) - cpuidle_unregister_device(&pr->power.dev); + cpuidle_unregister_device(&pr->power.dev); #endif pr->flags.power_setup_done = 0; diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index fc555a90bb21..23554b676d6e 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -38,6 +38,8 @@ static void cpuidle_kick_cpus(void) static void cpuidle_kick_cpus(void) {} #endif +static int __cpuidle_register_device(struct cpuidle_device *dev); + /** * cpuidle_idle_call - the main idle loop * @@ -138,6 +140,12 @@ int cpuidle_enable_device(struct cpuidle_device *dev) if (!dev->state_count) return -EINVAL; + if (dev->registered == 0) { + ret = __cpuidle_register_device(dev); + if (ret) + return ret; + } + if ((ret = cpuidle_add_state_sysfs(dev))) return ret; @@ -232,10 +240,13 @@ static void poll_idle_init(struct cpuidle_device *dev) {} #endif /* CONFIG_ARCH_HAS_CPU_RELAX */ /** - * cpuidle_register_device - registers a CPU's idle PM feature + * __cpuidle_register_device - internal register function called before register + * and enable routines * @dev: the cpu + * + * cpuidle_lock mutex must be held before this is called */ -int cpuidle_register_device(struct cpuidle_device *dev) +static int __cpuidle_register_device(struct cpuidle_device *dev) { int ret; struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu); @@ -247,18 +258,34 @@ int cpuidle_register_device(struct cpuidle_device *dev) init_completion(&dev->kobj_unregister); - mutex_lock(&cpuidle_lock); - poll_idle_init(dev); per_cpu(cpuidle_devices, dev->cpu) = dev; list_add(&dev->device_list, &cpuidle_detected_devices); if ((ret = cpuidle_add_sysfs(sys_dev))) { - mutex_unlock(&cpuidle_lock); module_put(cpuidle_curr_driver->owner); return ret; } + dev->registered = 1; + return 0; +} + +/** + * cpuidle_register_device - registers a CPU's idle PM feature + * @dev: the cpu + */ +int cpuidle_register_device(struct cpuidle_device *dev) +{ + int ret; + + mutex_lock(&cpuidle_lock); + + if ((ret = __cpuidle_register_device(dev))) { + mutex_unlock(&cpuidle_lock); + return ret; + } + cpuidle_enable_device(dev); cpuidle_install_idle_handler(); @@ -278,6 +305,9 @@ void cpuidle_unregister_device(struct cpuidle_device *dev) { struct sys_device *sys_dev = get_cpu_sysdev((unsigned long)dev->cpu); + if (dev->registered == 0) + return; + cpuidle_pause_and_lock(); cpuidle_disable_device(dev); diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 51e6b1e520e6..dcf77fa826b5 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -82,6 +82,7 @@ struct cpuidle_state_kobj { }; struct cpuidle_device { + unsigned int registered:1; unsigned int enabled:1; unsigned int cpu; -- cgit v1.2.3 From 197a2cd907e3a5278a1cfd48c86402133f38a9ba Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 3 Jun 2008 23:36:09 -0300 Subject: thinkpad-acpi: SW_RADIO to SW_RFKILL_ALL rename Rename SW_RADIO to SW_RFKILL_ALL in thinkpad-acpi code and docs, following 5adad0133907790c50283bf03271d920d6897043 "Input: rename SW_RADIO to SW_RFKILL_ALL". Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- Documentation/laptops/thinkpad-acpi.txt | 2 +- drivers/misc/thinkpad_acpi.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 01c6c3d8a7e3..64b3f146e4b0 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -503,7 +503,7 @@ generate input device EV_KEY events. In addition to the EV_KEY events, thinkpad-acpi may also issue EV_SW events for switches: -SW_RADIO T60 and later hardare rfkill rocker switch +SW_RFKILL_ALL T60 and later hardare rfkill rocker switch SW_TABLET_MODE Tablet ThinkPads HKEY events 0x5009 and 0x500A Non hot-key ACPI HKEY event map: diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index a0ce0b2fa03e..f81e048c9872 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1293,7 +1293,7 @@ static void tpacpi_input_send_radiosw(void) mutex_lock(&tpacpi_inputdev_send_mutex); input_report_switch(tpacpi_inputdev, - SW_RADIO, !!wlsw); + SW_RFKILL_ALL, !!wlsw); input_sync(tpacpi_inputdev); mutex_unlock(&tpacpi_inputdev_send_mutex); @@ -2199,7 +2199,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) if (tp_features.hotkey_wlsw) { set_bit(EV_SW, tpacpi_inputdev->evbit); - set_bit(SW_RADIO, tpacpi_inputdev->swbit); + set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit); } if (tp_features.hotkey_tablet) { set_bit(EV_SW, tpacpi_inputdev->evbit); -- cgit v1.2.3 From 9c0a76e16ee6648f4bd19563e9fe12a4f4fabba1 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 3 Jun 2008 23:36:10 -0300 Subject: thinkpad-acpi: fix initialization error paths Rework some subdriver init and exit handlers, in order to fix some initialization error paths that were missing, or broken. Hitting those bugs should be extremely rare in the real world, but should that happen, thinkpad-acpi would fail to dealocate some resources and a reboot might well be needed to be able to load the driver again. Signed-off-by: Henrique de Moraes Holschuh Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 437 +++++++++++++++++++++++-------------------- 1 file changed, 230 insertions(+), 207 deletions(-) diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index f81e048c9872..58973da1e6d1 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1921,6 +1921,29 @@ static struct attribute *hotkey_mask_attributes[] __initdata = { &dev_attr_hotkey_wakeup_hotunplug_complete.attr, }; +static void hotkey_exit(void) +{ +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL + hotkey_poll_stop_sync(); +#endif + + if (hotkey_dev_attributes) + delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); + + kfree(hotkey_keycode_map); + + if (tp_features.hotkey) { + dbg_printk(TPACPI_DBG_EXIT, + "restoring original hot key mask\n"); + /* no short-circuit boolean operator below! */ + if ((hotkey_mask_set(hotkey_orig_mask) | + hotkey_status_set(hotkey_orig_status)) != 0) + printk(TPACPI_ERR + "failed to restore hot key mask " + "to BIOS defaults\n"); + } +} + static int __init hotkey_init(struct ibm_init_struct *iibm) { /* Requirements for changing the default keymaps: @@ -2060,226 +2083,220 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n", str_supported(tp_features.hotkey)); - if (tp_features.hotkey) { - hotkey_dev_attributes = create_attr_set(13, NULL); - if (!hotkey_dev_attributes) - return -ENOMEM; - res = add_many_to_attr_set(hotkey_dev_attributes, - hotkey_attributes, - ARRAY_SIZE(hotkey_attributes)); - if (res) - return res; + if (!tp_features.hotkey) + return 1; - /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, - A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking - for HKEY interface version 0x100 */ - if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { - if ((hkeyv >> 8) != 1) { - printk(TPACPI_ERR "unknown version of the " - "HKEY interface: 0x%x\n", hkeyv); - printk(TPACPI_ERR "please report this to %s\n", - TPACPI_MAIL); - } else { - /* - * MHKV 0x100 in A31, R40, R40e, - * T4x, X31, and later - */ - tp_features.hotkey_mask = 1; - } + hotkey_dev_attributes = create_attr_set(13, NULL); + if (!hotkey_dev_attributes) + return -ENOMEM; + res = add_many_to_attr_set(hotkey_dev_attributes, + hotkey_attributes, + ARRAY_SIZE(hotkey_attributes)); + if (res) + goto err_exit; + + /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, + A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking + for HKEY interface version 0x100 */ + if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { + if ((hkeyv >> 8) != 1) { + printk(TPACPI_ERR "unknown version of the " + "HKEY interface: 0x%x\n", hkeyv); + printk(TPACPI_ERR "please report this to %s\n", + TPACPI_MAIL); + } else { + /* + * MHKV 0x100 in A31, R40, R40e, + * T4x, X31, and later + */ + tp_features.hotkey_mask = 1; } + } - vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", - str_supported(tp_features.hotkey_mask)); + vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", + str_supported(tp_features.hotkey_mask)); - if (tp_features.hotkey_mask) { - if (!acpi_evalf(hkey_handle, &hotkey_all_mask, - "MHKA", "qd")) { - printk(TPACPI_ERR - "missing MHKA handler, " - "please report this to %s\n", - TPACPI_MAIL); - /* FN+F12, FN+F4, FN+F3 */ - hotkey_all_mask = 0x080cU; - } + if (tp_features.hotkey_mask) { + if (!acpi_evalf(hkey_handle, &hotkey_all_mask, + "MHKA", "qd")) { + printk(TPACPI_ERR + "missing MHKA handler, " + "please report this to %s\n", + TPACPI_MAIL); + /* FN+F12, FN+F4, FN+F3 */ + hotkey_all_mask = 0x080cU; } + } - /* hotkey_source_mask *must* be zero for - * the first hotkey_mask_get */ - res = hotkey_status_get(&hotkey_orig_status); - if (!res && tp_features.hotkey_mask) { - res = hotkey_mask_get(); - hotkey_orig_mask = hotkey_mask; - if (!res) { - res = add_many_to_attr_set( - hotkey_dev_attributes, - hotkey_mask_attributes, - ARRAY_SIZE(hotkey_mask_attributes)); - } - } + /* hotkey_source_mask *must* be zero for + * the first hotkey_mask_get */ + res = hotkey_status_get(&hotkey_orig_status); + if (res) + goto err_exit; + + if (tp_features.hotkey_mask) { + res = hotkey_mask_get(); + if (res) + goto err_exit; + + hotkey_orig_mask = hotkey_mask; + res = add_many_to_attr_set( + hotkey_dev_attributes, + hotkey_mask_attributes, + ARRAY_SIZE(hotkey_mask_attributes)); + if (res) + goto err_exit; + } #ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL - if (tp_features.hotkey_mask) { - hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK - & ~hotkey_all_mask; - } else { - hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; - } + if (tp_features.hotkey_mask) { + hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK + & ~hotkey_all_mask; + } else { + hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; + } - vdbg_printk(TPACPI_DBG_INIT, - "hotkey source mask 0x%08x, polling freq %d\n", - hotkey_source_mask, hotkey_poll_freq); + vdbg_printk(TPACPI_DBG_INIT, + "hotkey source mask 0x%08x, polling freq %d\n", + hotkey_source_mask, hotkey_poll_freq); #endif - /* Not all thinkpads have a hardware radio switch */ - if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { - tp_features.hotkey_wlsw = 1; - printk(TPACPI_INFO - "radio switch found; radios are %s\n", - enabled(status, 0)); - res = add_to_attr_set(hotkey_dev_attributes, - &dev_attr_hotkey_radio_sw.attr); - } + /* Not all thinkpads have a hardware radio switch */ + if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { + tp_features.hotkey_wlsw = 1; + printk(TPACPI_INFO + "radio switch found; radios are %s\n", + enabled(status, 0)); + res = add_to_attr_set(hotkey_dev_attributes, + &dev_attr_hotkey_radio_sw.attr); + } - /* For X41t, X60t, X61t Tablets... */ - if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { - tp_features.hotkey_tablet = 1; - printk(TPACPI_INFO - "possible tablet mode switch found; " - "ThinkPad in %s mode\n", - (status & TP_HOTKEY_TABLET_MASK)? - "tablet" : "laptop"); - res = add_to_attr_set(hotkey_dev_attributes, - &dev_attr_hotkey_tablet_mode.attr); - } + /* For X41t, X60t, X61t Tablets... */ + if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { + tp_features.hotkey_tablet = 1; + printk(TPACPI_INFO + "possible tablet mode switch found; " + "ThinkPad in %s mode\n", + (status & TP_HOTKEY_TABLET_MASK)? + "tablet" : "laptop"); + res = add_to_attr_set(hotkey_dev_attributes, + &dev_attr_hotkey_tablet_mode.attr); + } - if (!res) - res = register_attr_set_with_sysfs( - hotkey_dev_attributes, - &tpacpi_pdev->dev.kobj); - if (res) - return res; + if (!res) + res = register_attr_set_with_sysfs( + hotkey_dev_attributes, + &tpacpi_pdev->dev.kobj); + if (res) + goto err_exit; - /* Set up key map */ + /* Set up key map */ - hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, - GFP_KERNEL); - if (!hotkey_keycode_map) { - printk(TPACPI_ERR - "failed to allocate memory for key map\n"); - return -ENOMEM; - } + hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, + GFP_KERNEL); + if (!hotkey_keycode_map) { + printk(TPACPI_ERR + "failed to allocate memory for key map\n"); + res = -ENOMEM; + goto err_exit; + } - if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { - dbg_printk(TPACPI_DBG_INIT, - "using Lenovo default hot key map\n"); - memcpy(hotkey_keycode_map, &lenovo_keycode_map, - TPACPI_HOTKEY_MAP_SIZE); + if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { + dbg_printk(TPACPI_DBG_INIT, + "using Lenovo default hot key map\n"); + memcpy(hotkey_keycode_map, &lenovo_keycode_map, + TPACPI_HOTKEY_MAP_SIZE); + } else { + dbg_printk(TPACPI_DBG_INIT, + "using IBM default hot key map\n"); + memcpy(hotkey_keycode_map, &ibm_keycode_map, + TPACPI_HOTKEY_MAP_SIZE); + } + + set_bit(EV_KEY, tpacpi_inputdev->evbit); + set_bit(EV_MSC, tpacpi_inputdev->evbit); + set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); + tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; + tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; + tpacpi_inputdev->keycode = hotkey_keycode_map; + for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { + if (hotkey_keycode_map[i] != KEY_RESERVED) { + set_bit(hotkey_keycode_map[i], + tpacpi_inputdev->keybit); } else { - dbg_printk(TPACPI_DBG_INIT, - "using IBM default hot key map\n"); - memcpy(hotkey_keycode_map, &ibm_keycode_map, - TPACPI_HOTKEY_MAP_SIZE); - } - - set_bit(EV_KEY, tpacpi_inputdev->evbit); - set_bit(EV_MSC, tpacpi_inputdev->evbit); - set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); - tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; - tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; - tpacpi_inputdev->keycode = hotkey_keycode_map; - for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { - if (hotkey_keycode_map[i] != KEY_RESERVED) { - set_bit(hotkey_keycode_map[i], - tpacpi_inputdev->keybit); - } else { - if (i < sizeof(hotkey_reserved_mask)*8) - hotkey_reserved_mask |= 1 << i; - } - } - - if (tp_features.hotkey_wlsw) { - set_bit(EV_SW, tpacpi_inputdev->evbit); - set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit); - } - if (tp_features.hotkey_tablet) { - set_bit(EV_SW, tpacpi_inputdev->evbit); - set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); + if (i < sizeof(hotkey_reserved_mask)*8) + hotkey_reserved_mask |= 1 << i; } + } - /* Do not issue duplicate brightness change events to - * userspace */ - if (!tp_features.bright_acpimode) - /* update bright_acpimode... */ - tpacpi_check_std_acpi_brightness_support(); - - if (tp_features.bright_acpimode) { - printk(TPACPI_INFO - "This ThinkPad has standard ACPI backlight " - "brightness control, supported by the ACPI " - "video driver\n"); - printk(TPACPI_NOTICE - "Disabling thinkpad-acpi brightness events " - "by default...\n"); - - /* The hotkey_reserved_mask change below is not - * necessary while the keys are at KEY_RESERVED in the - * default map, but better safe than sorry, leave it - * here as a marker of what we have to do, especially - * when we finally become able to set this at runtime - * on response to X.org requests */ - hotkey_reserved_mask |= - (1 << TP_ACPI_HOTKEYSCAN_FNHOME) - | (1 << TP_ACPI_HOTKEYSCAN_FNEND); - } + if (tp_features.hotkey_wlsw) { + set_bit(EV_SW, tpacpi_inputdev->evbit); + set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit); + } + if (tp_features.hotkey_tablet) { + set_bit(EV_SW, tpacpi_inputdev->evbit); + set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); + } - dbg_printk(TPACPI_DBG_INIT, - "enabling hot key handling\n"); - res = hotkey_status_set(1); - if (res) - return res; - res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask) - & ~hotkey_reserved_mask) - | hotkey_orig_mask); - if (res < 0 && res != -ENXIO) - return res; + /* Do not issue duplicate brightness change events to + * userspace */ + if (!tp_features.bright_acpimode) + /* update bright_acpimode... */ + tpacpi_check_std_acpi_brightness_support(); - dbg_printk(TPACPI_DBG_INIT, - "legacy hot key reporting over procfs %s\n", - (hotkey_report_mode < 2) ? - "enabled" : "disabled"); + if (tp_features.bright_acpimode) { + printk(TPACPI_INFO + "This ThinkPad has standard ACPI backlight " + "brightness control, supported by the ACPI " + "video driver\n"); + printk(TPACPI_NOTICE + "Disabling thinkpad-acpi brightness events " + "by default...\n"); + + /* The hotkey_reserved_mask change below is not + * necessary while the keys are at KEY_RESERVED in the + * default map, but better safe than sorry, leave it + * here as a marker of what we have to do, especially + * when we finally become able to set this at runtime + * on response to X.org requests */ + hotkey_reserved_mask |= + (1 << TP_ACPI_HOTKEYSCAN_FNHOME) + | (1 << TP_ACPI_HOTKEYSCAN_FNEND); + } + + dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n"); + res = hotkey_status_set(1); + if (res) { + hotkey_exit(); + return res; + } + res = hotkey_mask_set(((hotkey_all_mask | hotkey_source_mask) + & ~hotkey_reserved_mask) + | hotkey_orig_mask); + if (res < 0 && res != -ENXIO) { + hotkey_exit(); + return res; + } - tpacpi_inputdev->open = &hotkey_inputdev_open; - tpacpi_inputdev->close = &hotkey_inputdev_close; + dbg_printk(TPACPI_DBG_INIT, + "legacy hot key reporting over procfs %s\n", + (hotkey_report_mode < 2) ? + "enabled" : "disabled"); - hotkey_poll_setup_safe(1); - tpacpi_input_send_radiosw(); - tpacpi_input_send_tabletsw(); - } + tpacpi_inputdev->open = &hotkey_inputdev_open; + tpacpi_inputdev->close = &hotkey_inputdev_close; - return (tp_features.hotkey)? 0 : 1; -} + hotkey_poll_setup_safe(1); + tpacpi_input_send_radiosw(); + tpacpi_input_send_tabletsw(); -static void hotkey_exit(void) -{ -#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL - hotkey_poll_stop_sync(); -#endif + return 0; - if (tp_features.hotkey) { - dbg_printk(TPACPI_DBG_EXIT, - "restoring original hot key mask\n"); - /* no short-circuit boolean operator below! */ - if ((hotkey_mask_set(hotkey_orig_mask) | - hotkey_status_set(hotkey_orig_status)) != 0) - printk(TPACPI_ERR - "failed to restore hot key mask " - "to BIOS defaults\n"); - } +err_exit: + delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); + hotkey_dev_attributes = NULL; - if (hotkey_dev_attributes) { - delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); - hotkey_dev_attributes = NULL; - } + return (res < 0)? res : 1; } static void hotkey_notify(struct ibm_struct *ibm, u32 event) @@ -3319,7 +3336,7 @@ static struct tpacpi_led_classdev tpacpi_led_thinklight = { static int __init light_init(struct ibm_init_struct *iibm) { - int rc = 0; + int rc; vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n"); @@ -3337,20 +3354,23 @@ static int __init light_init(struct ibm_init_struct *iibm) tp_features.light_status = acpi_evalf(ec_handle, NULL, "KBLT", "qv"); - vdbg_printk(TPACPI_DBG_INIT, "light is %s\n", - str_supported(tp_features.light)); + vdbg_printk(TPACPI_DBG_INIT, "light is %s, light status is %s\n", + str_supported(tp_features.light), + str_supported(tp_features.light_status)); - if (tp_features.light) { - rc = led_classdev_register(&tpacpi_pdev->dev, - &tpacpi_led_thinklight.led_classdev); - } + if (!tp_features.light) + return 1; + + rc = led_classdev_register(&tpacpi_pdev->dev, + &tpacpi_led_thinklight.led_classdev); if (rc < 0) { tp_features.light = 0; tp_features.light_status = 0; - } else { - rc = (tp_features.light)? 0 : 1; + } else { + rc = 0; } + return rc; } @@ -3978,7 +3998,6 @@ static void led_exit(void) } kfree(tpacpi_leds); - tpacpi_leds = NULL; } static int __init led_init(struct ibm_init_struct *iibm) @@ -4802,7 +4821,6 @@ static void brightness_exit(void) vdbg_printk(TPACPI_DBG_EXIT, "calling backlight_device_unregister()\n"); backlight_device_unregister(ibm_backlight_device); - ibm_backlight_device = NULL; } } @@ -5764,11 +5782,16 @@ static int __init fan_init(struct ibm_init_struct *iibm) fan_control_access_mode != TPACPI_FAN_WR_NONE) { rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); - if (!(rc < 0)) - rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, - &driver_attr_fan_watchdog); if (rc < 0) return rc; + + rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, + &driver_attr_fan_watchdog); + if (rc < 0) { + sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, + &fan_attr_group); + return rc; + } return 0; } else return 1; -- cgit v1.2.3 From 24e45bbe695719dca8c20e03d386eb6ea86526b5 Mon Sep 17 00:00:00 2001 From: Henrique de Moraes Holschuh Date: Tue, 3 Jun 2008 23:36:11 -0300 Subject: thinkpad-acpi: fix LED handling on older ThinkPads The less tested codepaths for LED handling, used on ThinkPads 570, 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 and maybe a few others, would write data to kernel memory it had no business touching, for leds number 3 and above. If one is lucky, that illegal write would cause an OOPS, but chances are it would silently corrupt a byte. The problem was introduced in commit af116101, "ACPI: thinkpad-acpi: add sysfs led class support to thinkpad leds (v3.2)". Fix the bug by refactoring the entire code to be far more obvious on what it wants to do. Also do some defensive "constification". Issue reported by Karol Lewandowski (he's an lucky guy and got an OOPS instead of silent corruption :-) ). Root cause of the OOPS identified by Adrian Bunk . Thanks, Adrian! Signed-off-by: Henrique de Moraes Holschuh Tested-by: Karol Lewandowski Signed-off-by: Len Brown --- drivers/misc/thinkpad_acpi.c | 55 ++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 58973da1e6d1..b5969298f3d3 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -3853,7 +3853,7 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { "tpacpi::standby", }; -static int led_get_status(unsigned int led) +static int led_get_status(const unsigned int led) { int status; enum led_status_t led_s; @@ -3877,41 +3877,42 @@ static int led_get_status(unsigned int led) /* not reached */ } -static int led_set_status(unsigned int led, enum led_status_t ledstatus) +static int led_set_status(const unsigned int led, + const enum led_status_t ledstatus) { /* off, on, blink. Index is led_status_t */ - static const int led_sled_arg1[] = { 0, 1, 3 }; - static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */ - static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */ - static const int led_led_arg1[] = { 0, 0x80, 0xc0 }; + static const unsigned int led_sled_arg1[] = { 0, 1, 3 }; + static const unsigned int led_led_arg1[] = { 0, 0x80, 0xc0 }; int rc = 0; switch (led_supported) { case TPACPI_LED_570: - /* 570 */ - led = 1 << led; - if (!acpi_evalf(led_handle, NULL, NULL, "vdd", - led, led_sled_arg1[ledstatus])) - rc = -EIO; - break; + /* 570 */ + if (led > 7) + return -EINVAL; + if (!acpi_evalf(led_handle, NULL, NULL, "vdd", + (1 << led), led_sled_arg1[ledstatus])) + rc = -EIO; + break; case TPACPI_LED_OLD: - /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ - led = 1 << led; - rc = ec_write(TPACPI_LED_EC_HLMS, led); - if (rc >= 0) - rc = ec_write(TPACPI_LED_EC_HLBL, - led * led_exp_hlbl[ledstatus]); - if (rc >= 0) - rc = ec_write(TPACPI_LED_EC_HLCL, - led * led_exp_hlcl[ledstatus]); - break; + /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ + if (led > 7) + return -EINVAL; + rc = ec_write(TPACPI_LED_EC_HLMS, (1 << led)); + if (rc >= 0) + rc = ec_write(TPACPI_LED_EC_HLBL, + (ledstatus == TPACPI_LED_BLINK) << led); + if (rc >= 0) + rc = ec_write(TPACPI_LED_EC_HLCL, + (ledstatus != TPACPI_LED_OFF) << led); + break; case TPACPI_LED_NEW: - /* all others */ - if (!acpi_evalf(led_handle, NULL, NULL, "vdd", - led, led_led_arg1[ledstatus])) - rc = -EIO; - break; + /* all others */ + if (!acpi_evalf(led_handle, NULL, NULL, "vdd", + led, led_led_arg1[ledstatus])) + rc = -EIO; + break; default: rc = -ENXIO; } -- cgit v1.2.3 From 1b7fc5aae8867046f8d3d45808309d5b7f2e036a Mon Sep 17 00:00:00 2001 From: Alexey Starikovskiy Date: Fri, 6 Jun 2008 11:49:33 -0400 Subject: ACPI: EC: Use msleep instead of udelay while waiting for event. http://bugzilla.kernel.org/show_bug.cgi?id=10724 Signed-off-by: Alexey Starikovskiy Signed-off-by: Len Brown --- drivers/acpi/ec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 0924992187e8..5622aee996b2 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -194,7 +194,7 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) while (time_before(jiffies, delay)) { if (acpi_ec_check_status(ec, event)) return 0; - udelay(ACPI_EC_UDELAY); + msleep(1); } } pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n", -- cgit v1.2.3 From c21d1e7f53ffd9c0f162c42e7fde07d1c45fa127 Mon Sep 17 00:00:00 2001 From: Alistair John Strachan Date: Mon, 12 May 2008 19:13:09 +0100 Subject: ACPI 2.6.26-rc2: Add missing newline to DSDT/SSDT warning message As of recently (probably 2.6.26-rc1) I've been getting the following mangling in the kernel log: [4294014.568167] ACPI: DSDT override uses original SSDTs unless "acpi_no_auto_ssdt"<6>CPU0: Intel(R) Pentium(R) Dual CPU E2160 @ 1.80GHz stepping 0d This is due to a missing newline character in the first message. The following patch against 2.6.26-rc2 fixes it. Please apply. Signed-off-by: Alistair John Strachan Signed-off-by: Len Brown --- drivers/acpi/tables/tbxface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index fb57b93c2495..0e319604d3e7 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -540,7 +540,7 @@ static acpi_status acpi_tb_load_namespace(void) acpi_tb_print_table_header(0, table); if (no_auto_ssdt == 0) { - printk(KERN_WARNING "ACPI: DSDT override uses original SSDTs unless \"acpi_no_auto_ssdt\""); + printk(KERN_WARNING "ACPI: DSDT override uses original SSDTs unless \"acpi_no_auto_ssdt\"\n"); } } -- cgit v1.2.3 From 0638bc8dc037d844efe1d4abf44488c037705905 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 20 May 2008 01:08:23 +0300 Subject: MAINTAINERS: update ACPI homepage This patch updates the location of the ACPI homepage in MAINTAINERS. Signed-off-by: Adrian Bunk Signed-off-by: Len Brown --- MAINTAINERS | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index e3560df4608e..9d4304266043 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -228,21 +228,21 @@ ACPI BATTERY DRIVERS P: Alexey Starikovskiy M: astarikovskiy@suse.de L: linux-acpi@vger.kernel.org -W: http://acpi.sourceforge.net/ +W: http://www.lesswatts.org/projects/acpi/ S: Supported ACPI EC DRIVER P: Alexey Starikovskiy M: astarikovskiy@suse.de L: linux-acpi@vger.kernel.org -W: http://acpi.sourceforge.net/ +W: http://www.lesswatts.org/projects/acpi/ S: Supported ACPI FAN DRIVER P: Len Brown M: len.brown@intel.com L: linux-acpi@vger.kernel.org -W: http://acpi.sourceforge.net/ +W: http://www.lesswatts.org/projects/acpi/ S: Supported ACPI PCI HOTPLUG DRIVER @@ -255,14 +255,14 @@ ACPI THERMAL DRIVER P: Len Brown M: len.brown@intel.com L: linux-acpi@vger.kernel.org -W: http://acpi.sourceforge.net/ +W: http://www.lesswatts.org/projects/acpi/ S: Supported ACPI VIDEO DRIVER P: Rui Zhang M: rui.zhang@intel.com L: linux-acpi@vger.kernel.org -W: http://acpi.sourceforge.net/ +W: http://www.lesswatts.org/projects/acpi/ S: Supported ACPI WMI DRIVER -- cgit v1.2.3 From e9fe9e188118a0a34c6200d9b10ea6247f53592d Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 9 Jun 2008 16:52:04 -0700 Subject: pnpacpi: fix IRQ flag decoding When decoding IRQ trigger mode and polarity, it is not enough to mask by IORESOURCE_BITS because there are now additional bits defined. For example, if IORESOURCE_IRQ_SHAREABLE was set, we failed to set *triggering and *polarity at all. I can't point to a failure that this patch fixes, but bugs in this area have caused problems when resuming after suspend, for example: http://bugzilla.kernel.org/show_bug.cgi?id=6316 http://bugzilla.kernel.org/show_bug.cgi?id=9487 https://bugs.launchpad.net/ubuntu/+source/linux-source-2.6.22/+bug/152187 This is based on a patch by Tom Jaeger: http://bugzilla.kernel.org/show_bug.cgi?id=9487#c32 [rene.herman@keyaccess.nl: fix comment] Signed-off-by: Bjorn Helgaas Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/pnp/pnpacpi/rsparser.c | 16 ++++++++++++---- include/linux/ioport.h | 6 +++--- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 0201c8adfda7..ab09fe6fe1e4 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -56,9 +56,11 @@ static int irq_flags(int triggering, int polarity, int shareable) return flags; } -static void decode_irq_flags(int flag, int *triggering, int *polarity) +static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, + int *polarity) { - switch (flag) { + switch (flags & (IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL | + IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE)) { case IORESOURCE_IRQ_LOWLEVEL: *triggering = ACPI_LEVEL_SENSITIVE; *polarity = ACPI_ACTIVE_LOW; @@ -75,6 +77,12 @@ static void decode_irq_flags(int flag, int *triggering, int *polarity) *triggering = ACPI_EDGE_SENSITIVE; *polarity = ACPI_ACTIVE_HIGH; break; + default: + dev_err(&dev->dev, "can't encode invalid IRQ mode %#x\n", + flags); + *triggering = ACPI_EDGE_SENSITIVE; + *polarity = ACPI_ACTIVE_HIGH; + break; } } @@ -790,7 +798,7 @@ static void pnpacpi_encode_irq(struct pnp_dev *dev, struct acpi_resource_irq *irq = &resource->data.irq; int triggering, polarity; - decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity); + decode_irq_flags(dev, p->flags, &triggering, &polarity); irq->triggering = triggering; irq->polarity = polarity; if (triggering == ACPI_EDGE_SENSITIVE) @@ -813,7 +821,7 @@ static void pnpacpi_encode_ext_irq(struct pnp_dev *dev, struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq; int triggering, polarity; - decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity); + decode_irq_flags(dev, p->flags, &triggering, &polarity); extended_irq->producer_consumer = ACPI_CONSUMER; extended_irq->triggering = triggering; extended_irq->polarity = polarity; diff --git a/include/linux/ioport.h b/include/linux/ioport.h index d5d40a9f7929..c6801bffe76d 100644 --- a/include/linux/ioport.h +++ b/include/linux/ioport.h @@ -53,14 +53,14 @@ struct resource_list { #define IORESOURCE_AUTO 0x40000000 #define IORESOURCE_BUSY 0x80000000 /* Driver has marked this resource busy */ -/* ISA PnP IRQ specific bits (IORESOURCE_BITS) */ +/* PnP IRQ specific bits (IORESOURCE_BITS) */ #define IORESOURCE_IRQ_HIGHEDGE (1<<0) #define IORESOURCE_IRQ_LOWEDGE (1<<1) #define IORESOURCE_IRQ_HIGHLEVEL (1<<2) #define IORESOURCE_IRQ_LOWLEVEL (1<<3) #define IORESOURCE_IRQ_SHAREABLE (1<<4) -/* ISA PnP DMA specific bits (IORESOURCE_BITS) */ +/* PnP DMA specific bits (IORESOURCE_BITS) */ #define IORESOURCE_DMA_TYPE_MASK (3<<0) #define IORESOURCE_DMA_8BIT (0<<0) #define IORESOURCE_DMA_8AND16BIT (1<<0) @@ -76,7 +76,7 @@ struct resource_list { #define IORESOURCE_DMA_TYPEB (2<<6) #define IORESOURCE_DMA_TYPEF (3<<6) -/* ISA PnP memory I/O specific bits (IORESOURCE_BITS) */ +/* PnP memory I/O specific bits (IORESOURCE_BITS) */ #define IORESOURCE_MEM_WRITEABLE (1<<0) /* dup: IORESOURCE_READONLY */ #define IORESOURCE_MEM_CACHEABLE (1<<1) /* dup: IORESOURCE_CACHEABLE */ #define IORESOURCE_MEM_RANGELENGTH (1<<2) /* dup: IORESOURCE_RANGELENGTH */ -- cgit v1.2.3 From a993273beae8022390e48fe9205480565ad470ab Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 9 Jun 2008 16:52:05 -0700 Subject: pnpacpi: fix shareable IRQ encode/decode When we encode IRQ resources, we should use the "shareable" flag we got from _PRS rather than guessing based on the IRQ trigger mode. This is based on a patch by Tom Jaeger: http://bugzilla.kernel.org/show_bug.cgi?id=9487#c32 Signed-off-by: Bjorn Helgaas Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/pnp/pnpacpi/rsparser.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index ab09fe6fe1e4..8681ff647201 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -50,14 +50,14 @@ static int irq_flags(int triggering, int polarity, int shareable) flags = IORESOURCE_IRQ_HIGHEDGE; } - if (shareable) + if (shareable == ACPI_SHARED) flags |= IORESOURCE_IRQ_SHAREABLE; return flags; } static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, - int *polarity) + int *polarity, int *shareable) { switch (flags & (IORESOURCE_IRQ_LOWLEVEL | IORESOURCE_IRQ_HIGHLEVEL | IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE)) { @@ -84,6 +84,11 @@ static void decode_irq_flags(struct pnp_dev *dev, int flags, int *triggering, *polarity = ACPI_ACTIVE_HIGH; break; } + + if (flags & IORESOURCE_IRQ_SHAREABLE) + *shareable = ACPI_SHARED; + else + *shareable = ACPI_EXCLUSIVE; } static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev, @@ -796,15 +801,12 @@ static void pnpacpi_encode_irq(struct pnp_dev *dev, struct resource *p) { struct acpi_resource_irq *irq = &resource->data.irq; - int triggering, polarity; + int triggering, polarity, shareable; - decode_irq_flags(dev, p->flags, &triggering, &polarity); + decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable); irq->triggering = triggering; irq->polarity = polarity; - if (triggering == ACPI_EDGE_SENSITIVE) - irq->sharable = ACPI_EXCLUSIVE; - else - irq->sharable = ACPI_SHARED; + irq->sharable = shareable; irq->interrupt_count = 1; irq->interrupts[0] = p->start; @@ -819,16 +821,13 @@ static void pnpacpi_encode_ext_irq(struct pnp_dev *dev, struct resource *p) { struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq; - int triggering, polarity; + int triggering, polarity, shareable; - decode_irq_flags(dev, p->flags, &triggering, &polarity); + decode_irq_flags(dev, p->flags, &triggering, &polarity, &shareable); extended_irq->producer_consumer = ACPI_CONSUMER; extended_irq->triggering = triggering; extended_irq->polarity = polarity; - if (triggering == ACPI_EDGE_SENSITIVE) - extended_irq->sharable = ACPI_EXCLUSIVE; - else - extended_irq->sharable = ACPI_SHARED; + extended_irq->sharable = shareable; extended_irq->interrupt_count = 1; extended_irq->interrupts[0] = p->start; -- cgit v1.2.3 From 36d872a370d3d10e5a7faa9dcacce744260fb13b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 9 Jun 2008 16:52:06 -0700 Subject: PNPACPI: use _CRS IRQ descriptor length for _SRS When configuring the resources of an ACPI device, we first evaluate _CRS to get a template of resource descriptors, then fill in the specific resource values we want, and finally evaluate _SRS to actually configure the device. Some resources have optional fields, so the size of encoded descriptors varies depending on the specific values. For example, IRQ descriptors can be either two or three bytes long. The third byte contains triggering information and can be omitted if the IRQ is edge-triggered and active high. The BIOS often assumes that IRQ descriptors in the _SRS buffer use the same format as those in the _CRS buffer, so this patch enforces that constraint. The "Start Dependent Function" descriptor also has an optional byte, but we don't currently encode those descriptors, so I didn't do anything for those. I have tested this patch on a Toshiba Portege 4000. Without the patch, parport_pc claims the parallel port only if I use "pnpacpi=off". This patch makes it work with PNPACPI. This is an extension of a patch by Tom Jaeger: http://bugzilla.kernel.org/show_bug.cgi?id=9487#c42 References: http://bugzilla.kernel.org/show_bug.cgi?id=5832 Enabling ACPI Plug and Play in kernels >2.6.9 kills Parallel support http://bugzilla.kernel.org/show_bug.cgi?id=9487 buggy firmware expects four-byte IRQ resource descriptor (was: Serial port disappears after Suspend on Toshiba R25) http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=1d5b285da1893b90507b081664ac27f1a8a3dc5b related ACPICA fix Signed-off-by: Bjorn Helgaas Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/pnp/pnpacpi/rsparser.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 8681ff647201..46c791adb894 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -755,6 +755,9 @@ static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data) if (pnpacpi_supported_resource(res)) { (*resource)->type = res->type; (*resource)->length = sizeof(struct acpi_resource); + if (res->type == ACPI_RESOURCE_TYPE_IRQ) + (*resource)->data.irq.descriptor_length = + res->data.irq.descriptor_length; (*resource)++; } @@ -810,10 +813,12 @@ static void pnpacpi_encode_irq(struct pnp_dev *dev, irq->interrupt_count = 1; irq->interrupts[0] = p->start; - dev_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start, + dev_dbg(&dev->dev, " encode irq %d %s %s %s (%d-byte descriptor)\n", + (int) p->start, triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge", polarity == ACPI_ACTIVE_LOW ? "low" : "high", - irq->sharable == ACPI_SHARED ? "shared" : "exclusive"); + irq->sharable == ACPI_SHARED ? "shared" : "exclusive", + irq->descriptor_length); } static void pnpacpi_encode_ext_irq(struct pnp_dev *dev, -- cgit v1.2.3 From 39b8931b5cad9a7cbcd2394a40a088311e783a82 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Mon, 9 Jun 2008 16:48:18 -0700 Subject: ACPI: handle invalid ACPI SLIT table This is a SLIT sanity checking patch. It moves slit_valid() function to generic ACPI code and does sanity checking for both x86 and ia64. It sets up node_distance with LOCAL_DISTANCE and REMOTE_DISTANCE when hitting invalid SLIT table on ia64. It also cleans up unused variable localities in acpi_parse_slit() on x86. Signed-off-by: Fenghua Yu Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- arch/ia64/kernel/acpi.c | 9 +++++++-- arch/x86/mm/srat_64.c | 27 --------------------------- drivers/acpi/numa.c | 31 +++++++++++++++++++++++++++---- 3 files changed, 34 insertions(+), 33 deletions(-) diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 853d1f11be00..43687cc60dfb 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -465,7 +465,6 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit) printk(KERN_ERR "ACPI 2.0 SLIT: size mismatch: %d expected, %d actual\n", len, slit->header.length); - memset(numa_slit, 10, sizeof(numa_slit)); return; } slit_table = slit; @@ -574,8 +573,14 @@ void __init acpi_numa_arch_fixup(void) printk(KERN_INFO "Number of memory chunks in system = %d\n", num_node_memblks); - if (!slit_table) + if (!slit_table) { + for (i = 0; i < MAX_NUMNODES; i++) + for (j = 0; j < MAX_NUMNODES; j++) + node_distance(i, j) = i == j ? LOCAL_DISTANCE : + REMOTE_DISTANCE; return; + } + memset(numa_slit, -1, sizeof(numa_slit)); for (i = 0; i < slit_table->locality_count; i++) { if (!pxm_bit_test(i)) diff --git a/arch/x86/mm/srat_64.c b/arch/x86/mm/srat_64.c index 3890234e5b26..99649dccad28 100644 --- a/arch/x86/mm/srat_64.c +++ b/arch/x86/mm/srat_64.c @@ -97,36 +97,9 @@ static __init inline int srat_disabled(void) return numa_off || acpi_numa < 0; } -/* - * A lot of BIOS fill in 10 (= no distance) everywhere. This messes - * up the NUMA heuristics which wants the local node to have a smaller - * distance than the others. - * Do some quick checks here and only use the SLIT if it passes. - */ -static __init int slit_valid(struct acpi_table_slit *slit) -{ - int i, j; - int d = slit->locality_count; - for (i = 0; i < d; i++) { - for (j = 0; j < d; j++) { - u8 val = slit->entry[d*i + j]; - if (i == j) { - if (val != LOCAL_DISTANCE) - return 0; - } else if (val <= LOCAL_DISTANCE) - return 0; - } - } - return 1; -} - /* Callback for SLIT parsing */ void __init acpi_numa_slit_init(struct acpi_table_slit *slit) { - if (!slit_valid(slit)) { - printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n"); - return; - } acpi_slit = slit; } diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 5d59cb33b1a5..658e5f3abae0 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -140,19 +140,42 @@ acpi_table_print_srat_entry(struct acpi_subtable_header *header) } } +/* + * A lot of BIOS fill in 10 (= no distance) everywhere. This messes + * up the NUMA heuristics which wants the local node to have a smaller + * distance than the others. + * Do some quick checks here and only use the SLIT if it passes. + */ +static __init int slit_valid(struct acpi_table_slit *slit) +{ + int i, j; + int d = slit->locality_count; + for (i = 0; i < d; i++) { + for (j = 0; j < d; j++) { + u8 val = slit->entry[d*i + j]; + if (i == j) { + if (val != LOCAL_DISTANCE) + return 0; + } else if (val <= LOCAL_DISTANCE) + return 0; + } + } + return 1; +} + static int __init acpi_parse_slit(struct acpi_table_header *table) { struct acpi_table_slit *slit; - u32 localities; if (!table) return -EINVAL; slit = (struct acpi_table_slit *)table; - /* downcast just for %llu vs %lu for i386/ia64 */ - localities = (u32) slit->locality_count; - + if (!slit_valid(slit)) { + printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n"); + return -EINVAL; + } acpi_numa_slit_init(slit); return 0; -- cgit v1.2.3 From a66b34b26fe1b0983c6d91b6381df806cd98886e Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 9 Jun 2008 16:22:24 -0700 Subject: proper prototype for acpi_processor_tstate_has_changed() This patch adds a proper prototype for acpi_processor_tstate_has_changed() in include/acpi/processor.h Signed-off-by: Adrian Bunk Cc: Len Brown Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/processor_core.c | 1 - include/acpi/processor.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 386e5aa48834..9dd0fa93b9e1 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -86,7 +86,6 @@ static int acpi_processor_info_open_fs(struct inode *inode, struct file *file); static void acpi_processor_notify(acpi_handle handle, u32 event, void *data); static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu); static int acpi_processor_handle_eject(struct acpi_processor *pr); -extern int acpi_processor_tstate_has_changed(struct acpi_processor *pr); static const struct acpi_device_id processor_device_ids[] = { diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 06480bcabfdc..06ebb6ef72aa 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -319,6 +319,7 @@ static inline int acpi_processor_ppc_has_changed(struct acpi_processor *pr) #endif /* CONFIG_CPU_FREQ */ /* in processor_throttling.c */ +int acpi_processor_tstate_has_changed(struct acpi_processor *pr); int acpi_processor_get_throttling_info(struct acpi_processor *pr); extern int acpi_processor_set_throttling(struct acpi_processor *pr, int state); extern struct file_operations acpi_processor_throttling_fops; -- cgit v1.2.3 From 1fdd68608614cd1e951fd93873fe5597374e8c54 Mon Sep 17 00:00:00 2001 From: Tim Pepper Date: Mon, 9 Jun 2008 16:22:25 -0700 Subject: dock.c remove trailing printk whitespace Signed-off-by: Tim Pepper Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/dock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index fa44fb96fc34..96c542f7fded 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -834,7 +834,7 @@ static int dock_add(acpi_handle handle) goto dock_add_err; } - printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_DESCRIPTION); + printk(KERN_INFO PREFIX "%s\n", ACPI_DOCK_DRIVER_DESCRIPTION); return 0; -- cgit v1.2.3 From 7efd52a407bed6a2b02015b8ebbff7beba155392 Mon Sep 17 00:00:00 2001 From: Holger Macht Date: Mon, 9 Jun 2008 16:22:24 -0700 Subject: bay: exit if notify handler cannot be installed If acpi_install_notify_handler() for a bay device fails, the bay driver is superfluous. Most likely, another driver (like libata) is already caring about this device anyway. Furthermore, register_hotplug_dock_device(acpi_handle) from the dock driver must not be called twice with the same handler. This would result in an endless loop consuming 100% of CPU. So clean up and exit. Signed-off-by: Holger Macht Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/bay.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c index d2fc94161848..26038c2a2a71 100644 --- a/drivers/acpi/bay.c +++ b/drivers/acpi/bay.c @@ -301,16 +301,20 @@ static int bay_add(acpi_handle handle, int id) */ pdev->dev.uevent_suppress = 0; - if (acpi_bay_add_fs(new_bay)) { - platform_device_unregister(new_bay->pdev); - goto bay_add_err; - } - /* register for events on this device */ status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, bay_notify, new_bay); if (ACPI_FAILURE(status)) { - printk(KERN_ERR PREFIX "Error installing bay notify handler\n"); + printk(KERN_INFO PREFIX "Error installing bay notify handler\n"); + platform_device_unregister(new_bay->pdev); + goto bay_add_err; + } + + if (acpi_bay_add_fs(new_bay)) { + acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + bay_notify); + platform_device_unregister(new_bay->pdev); + goto bay_add_err; } /* if we are on a dock station, we should register for dock -- cgit v1.2.3 From 46a21e465e506bcd4dba759a39e7ef79978a705d Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 9 Jun 2008 16:22:26 -0700 Subject: ACPI: use memory_read_from_buffer() Signed-off-by: Akinobu Mita Acked-by: Zhang Rui Signed-off-by: Andrew Morton Signed-off-by: Len Brown --- drivers/acpi/system.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 769f24855eb6..5bd2dec9a7ac 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -77,7 +77,6 @@ static ssize_t acpi_table_show(struct kobject *kobj, container_of(bin_attr, struct acpi_table_attr, attr); struct acpi_table_header *table_header = NULL; acpi_status status; - ssize_t ret_count = count; status = acpi_get_table(table_attr->name, table_attr->instance, @@ -85,18 +84,8 @@ static ssize_t acpi_table_show(struct kobject *kobj, if (ACPI_FAILURE(status)) return -ENODEV; - if (offset >= table_header->length) { - ret_count = 0; - goto end; - } - - if (offset + ret_count > table_header->length) - ret_count = table_header->length - offset; - - memcpy(buf, ((char *)table_header) + offset, ret_count); - - end: - return ret_count; + return memory_read_from_buffer(buf, count, &offset, + table_header, table_header->length); } static void acpi_table_attr_init(struct acpi_table_attr *table_attr, -- cgit v1.2.3 From 7aa7d4336df34e32195557a1ad422627bd69ef0b Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 10 Jun 2008 13:00:32 +0800 Subject: ACPICA: Fix to allow zero-length ASL field declarations Allows null field list in Field(), BankField(), and IndexField(). 2.6.26-rc1 regression: ACPI fails to load SDT. - Dell M1530 http://bugzilla.kernel.org/show_bug.cgi?id=10606 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/dispatcher/dsfield.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c index c78078315be9..f988a5e7d2b4 100644 --- a/drivers/acpi/dispatcher/dsfield.c +++ b/drivers/acpi/dispatcher/dsfield.c @@ -450,10 +450,6 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, return_ACPI_STATUS(AE_BAD_PARAMETER); } - if (!arg) { - return_ACPI_STATUS(AE_AML_NO_OPERAND); - } - /* Creating new namespace node(s), should not already exist */ flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | @@ -467,6 +463,7 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, /* * Walk the list of entries in the field_list + * Note: field_list can be of zero length. In this case, Arg will be NULL. */ while (arg) { /* -- cgit v1.2.3 From bc45b1d39a925b56796bebf8a397a0491489d85c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 10 Jun 2008 14:12:50 +0800 Subject: ACPICA: Ignore ACPI table signature for Load() operator Only "SSDT" is acceptable to the ACPI spec, but tables are seen with OEMx and null sigs. Therefore, signature validation is worthless. Apparently MS ACPI accepts such signatures, ACPICA must be compatible. http://bugzilla.kernel.org/show_bug.cgi?id=10454 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/tables/tbinstal.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c index 402f93e1ff20..5336ce88f89f 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/tables/tbinstal.c @@ -123,24 +123,13 @@ acpi_tb_add_table(struct acpi_table_desc *table_desc, } } - /* The table must be either an SSDT or a PSDT or an OEMx */ - - if (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT)&& - !ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)&& - strncmp(table_desc->pointer->signature, "OEM", 3)) { - /* Check for a printable name */ - if (acpi_ut_valid_acpi_name( - *(u32 *) table_desc->pointer->signature)) { - ACPI_ERROR((AE_INFO, "Table has invalid signature " - "[%4.4s], must be SSDT or PSDT", - table_desc->pointer->signature)); - } else { - ACPI_ERROR((AE_INFO, "Table has invalid signature " - "(0x%8.8X), must be SSDT or PSDT", - *(u32 *) table_desc->pointer->signature)); - } - return_ACPI_STATUS(AE_BAD_SIGNATURE); - } + /* + * Originally, we checked the table signature for "SSDT" or "PSDT" here. + * Next, we added support for OEMx tables, signature "OEM". + * Valid tables were encountered with a null signature, so we've just + * given up on validating the signature, since it seems to be a waste + * of code. The original code was removed (05/2008). + */ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); -- cgit v1.2.3 From 0bda3f2f86e233b00b46d91b07db25dd23ec15bc Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 10 Jun 2008 14:14:17 +0800 Subject: ACPICA: Fix for Load operator, load table at the namespace root This reverts a change introduced in version 20071019. The table is now loaded at the namespace root even though this goes against the ACPI specification. This provides compatibility with other ACPI implementations. Signed-off-by: Lin Ming Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/executer/exconfig.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index 24da921d13e3..39d742190584 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -375,9 +375,15 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, goto cleanup; } + /* + * Add the table to the namespace. + * + * Note: We load the table objects relative to the root of the namespace. + * This appears to go against the ACPI specification, but we do it for + * compatibility with other ACPI implementations. + */ status = - acpi_ex_add_table(table_index, walk_state->scope_info->scope.node, - &ddb_handle); + acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle); if (ACPI_FAILURE(status)) { /* On error, table_ptr was deallocated above */ -- cgit v1.2.3 From d52c79ace60a2e2b22455fd195ff4bc8e7afa177 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 10 Jun 2008 14:26:57 +0800 Subject: ACPICA: Fix to make _SST method optional Fixes a problem introduced in 20080514 where the status of execution of _SST is incorrectly returned to the caller. _SST is optional, and if it is AE_NOT_FOUND, the exception should be ignored. http://www.acpica.org/bugzilla/show_bug.cgi?id=716 Signed-off-by: Bob Moore Signed-off-by: Lin Ming Signed-off-by: Len Brown --- drivers/acpi/hardware/hwsleep.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index d9937e05ec6a..dba3cfbe8cba 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -223,15 +223,17 @@ acpi_status acpi_enter_sleep_state_prep(u8 sleep_state) break; } - /* Set the system indicators to show the desired sleep state. */ - + /* + * Set the system indicators to show the desired sleep state. + * _SST is an optional method (return no error if not found) + */ status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { ACPI_EXCEPTION((AE_INFO, status, "While executing method _SST")); } - return_ACPI_STATUS(status); + return_ACPI_STATUS(AE_OK); } ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep) -- cgit v1.2.3 From 8410565f540db87ca938f56f92780d251e4f157d Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 10 Jun 2008 14:29:26 +0800 Subject: ACPICA: Fix for access to deleted object Fixes problem introduced in 20080123, with fix for Unload operator. Parse tree object can be already deleted; must use the opcode within the WalkState. ACPI: kmemcheck: Caught 16-bit read from freed memory http://bugzilla.kernel.org/show_bug.cgi?id=10669 Signed-off-by: Lin Ming Signed-off-by: Bob Moore Signed-off-by: Len Brown --- drivers/acpi/parser/psargs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c index f1e8bf65e24e..e94463778845 100644 --- a/drivers/acpi/parser/psargs.c +++ b/drivers/acpi/parser/psargs.c @@ -268,7 +268,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, */ if (ACPI_SUCCESS(status) && possible_method_call && (node->type == ACPI_TYPE_METHOD)) { - if (walk_state->op->common.aml_opcode == AML_UNLOAD_OP) { + if (walk_state->opcode == AML_UNLOAD_OP) { /* * acpi_ps_get_next_namestring has increased the AML pointer, * so we need to restore the saved AML pointer for method call. @@ -691,7 +691,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, /* To support super_name arg of Unload */ - if (walk_state->op->common.aml_opcode == AML_UNLOAD_OP) { + if (walk_state->opcode == AML_UNLOAD_OP) { status = acpi_ps_get_next_namepath(walk_state, parser_state, arg, -- cgit v1.2.3 From a39a2d7c72b358c6253a2ec28e17b023b7f6f41c Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Mon, 19 May 2008 15:55:15 -0700 Subject: ACPI: Reject below-freezing temperatures as invalid critical temperatures My laptop thinks that it's a good idea to give -73C as the critical CPU temperature.... which isn't the best thing since it causes a shutdown right at bootup. Temperatures below freezing are clearly invalid critical thresholds so just reject these as such. Signed-off-by: Arjan van de Ven Acked-by: Zhang Rui Signed-off-by: Len Brown --- drivers/acpi/thermal.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 504385b1f211..84c795fb9b1e 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -364,10 +364,17 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) if (flag & ACPI_TRIPS_CRITICAL) { status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, &tz->trips.critical.temperature); - if (ACPI_FAILURE(status)) { + /* + * Treat freezing temperatures as invalid as well; some + * BIOSes return really low values and cause reboots at startup. + * Below zero (Celcius) values clearly aren't right for sure.. + * ... so lets discard those as invalid. + */ + if (ACPI_FAILURE(status) || + tz->trips.critical.temperature <= 2732) { tz->trips.critical.flags.valid = 0; ACPI_EXCEPTION((AE_INFO, status, - "No critical threshold")); + "No or invalid critical threshold")); return -ENODEV; } else { tz->trips.critical.flags.valid = 1; -- cgit v1.2.3 From 3549dba2c334e82df90f5e00ff85d2a7a2cdd1af Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 6 Jun 2008 15:32:39 -0400 Subject: ACPICA: fix stray va_end() caused by mis-merge Signed-off-by: Len Brown --- drivers/acpi/utilities/utmisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c index e4ba7192cd15..1f057b71db1a 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/utilities/utmisc.c @@ -1048,6 +1048,7 @@ acpi_ut_exception(char *module_name, va_start(args, format); acpi_os_vprintf(format, args); acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); + va_end(args); } EXPORT_SYMBOL(acpi_ut_exception); @@ -1063,7 +1064,6 @@ acpi_ut_warning(char *module_name, u32 line_number, char *format, ...) acpi_os_vprintf(format, args); acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); va_end(args); - va_end(args); } void ACPI_INTERNAL_VAR_XFACE -- cgit v1.2.3 From 4623236619ff5ce233136d13ee2747c194a63591 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 4 Jun 2008 21:40:43 -0700 Subject: dev_set_name: fix missing kernel-doc Fix kernel-doc for new dev_set_name() function: Warning(lin2626-rc5//drivers/base/core.c:767): No description found for parameter 'fmt' Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/base/core.c b/drivers/base/core.c index 422cfcad486d..ee0a51a3a41d 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -762,6 +762,7 @@ static void device_remove_class_symlinks(struct device *dev) /** * dev_set_name - set a device name * @dev: device + * @fmt: format string for the device's name */ int dev_set_name(struct device *dev, const char *fmt, ...) { -- cgit v1.2.3 From acccafe9ca63eac3a202d8805d286ada6ab8cced Mon Sep 17 00:00:00 2001 From: David Brigada Date: Wed, 11 Jun 2008 13:27:32 -0400 Subject: kobject: Documentation Spelling Patch Signed-off-by: David Brigada Signed-off-by: Greg Kroah-Hartman --- Documentation/kobject.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt index bf3256e04027..51a8021ee532 100644 --- a/Documentation/kobject.txt +++ b/Documentation/kobject.txt @@ -305,7 +305,7 @@ should not be manipulated by any other user. A kset keeps its children in a standard kernel linked list. Kobjects point back to their containing kset via their kset field. In almost all cases, -the kobjects belonging to a ket have that kset (or, strictly, its embedded +the kobjects belonging to a kset have that kset (or, strictly, its embedded kobject) in their parent. As a kset contains a kobject within it, it should always be dynamically -- cgit v1.2.3 From 6460a261b5893e769a314c246faec31bbc4aad9c Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 2 Jun 2008 21:21:03 +0200 Subject: USB: fix build bug in USB_ISIGHTFW USB: fix build bug in USB_ISIGHTFW -tip tree testing found this build bug: drivers/built-in.o: In function `isight_firmware_load': isight_firmware.c:(.text+0x1ade08): undefined reference to `request_firmware' isight_firmware.c:(.text+0x1adf9c): undefined reference to `release_firmware' select FW_LOADER in USB_ISIGHTFW. From: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index eb6c06979f3b..001789c9a11a 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -272,6 +272,7 @@ config USB_TEST config USB_ISIGHTFW tristate "iSight firmware loading support" depends on USB + select FW_LOADER help This driver loads firmware for USB Apple iSight cameras, allowing them to be driven by the USB video class driver available at -- cgit v1.2.3 From 62b5884875fcd4babf6c0c377046f226abbfe491 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 6 Jun 2008 12:35:15 -0700 Subject: isight_firmware: Avoid crash on loading invalid firmware Different tools generate slightly different formats of the isight firmware. Ensure that the firmware buffer is not overrun, while still ensuring that the correct amount of data is written if trailing data is present. Signed-off-by: Matthew Garrett Report-by: Justin Mattock Tested-by: Justin Mattock Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/isight_firmware.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/usb/misc/isight_firmware.c b/drivers/usb/misc/isight_firmware.c index 390e04885536..9f30aa1f8a5d 100644 --- a/drivers/usb/misc/isight_firmware.c +++ b/drivers/usb/misc/isight_firmware.c @@ -39,9 +39,12 @@ static int isight_firmware_load(struct usb_interface *intf, struct usb_device *dev = interface_to_usbdev(intf); int llen, len, req, ret = 0; const struct firmware *firmware; - unsigned char *buf; + unsigned char *buf = kmalloc(50, GFP_KERNEL); unsigned char data[4]; - char *ptr; + u8 *ptr; + + if (!buf) + return -ENOMEM; if (request_firmware(&firmware, "isight.fw", &dev->dev) != 0) { printk(KERN_ERR "Unable to load isight firmware\n"); @@ -59,7 +62,7 @@ static int isight_firmware_load(struct usb_interface *intf, goto out; } - while (1) { + while (ptr+4 <= firmware->data+firmware->size) { memcpy(data, ptr, 4); len = (data[0] << 8 | data[1]); req = (data[2] << 8 | data[3]); @@ -71,10 +74,14 @@ static int isight_firmware_load(struct usb_interface *intf, continue; for (; len > 0; req += 50) { - llen = len > 50 ? 50 : len; + llen = min(len, 50); len -= llen; - - buf = kmalloc(llen, GFP_KERNEL); + if (ptr+llen > firmware->data+firmware->size) { + printk(KERN_ERR + "Malformed isight firmware"); + ret = -ENODEV; + goto out; + } memcpy(buf, ptr, llen); ptr += llen; @@ -89,16 +96,18 @@ static int isight_firmware_load(struct usb_interface *intf, goto out; } - kfree(buf); } } + if (usb_control_msg (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\0", 1, 300) != 1) { printk(KERN_ERR "isight firmware loading completion failed\n"); ret = -ENODEV; } + out: + kfree(buf); release_firmware(firmware); return ret; } -- cgit v1.2.3 From e6942d633be61f1638e08c56ab8244fc9f1c61e3 Mon Sep 17 00:00:00 2001 From: Nate Case Date: Wed, 21 May 2008 16:28:20 -0500 Subject: USB: isp1760: Assign resource fields before adding hcd This fixes the bogus "io mem 0x00000000" message printed during driver init due to hcd->rsrc_start being assigned after the call to usb_add_hcd(). Signed-off-by: Nate Case Acked-by: Sebastian Siewior Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp1760-hcd.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index c9cec8738261..65aa5ecf569a 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -2207,14 +2207,14 @@ struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq, goto err_put; } - ret = usb_add_hcd(hcd, irq, irqflags); - if (ret) - goto err_unmap; - hcd->irq = irq; hcd->rsrc_start = res_start; hcd->rsrc_len = res_len; + ret = usb_add_hcd(hcd, irq, irqflags); + if (ret) + goto err_unmap; + return hcd; err_unmap: -- cgit v1.2.3 From 5340ba827b6269ccd2dcfd3d966626d9dd75d5d4 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 10 Jun 2008 14:59:43 -0400 Subject: USB: don't use reset-resume if drivers don't support it This patch tries to identify which devices are able to accept reset-resume handling, by checking that there is at least one interface driver bound and that all of the drivers have a reset_resume method defined. If these conditions don't hold then during resume processing, the device is logicall disconnected. This is only a temporary fix. Later on we will explicitly unbind drivers that can't handle reset-resumes. Signed-off-by: Linus Torvalds Signed-off-by: Alan Stern Cc: Oliver Neukum Cc: Pavel Machek Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 8eb4da332f56..94789be54ca3 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -644,6 +644,48 @@ static void hub_stop(struct usb_hub *hub) #ifdef CONFIG_PM +/* Try to identify which devices need USB-PERSIST handling */ +static int persistent_device(struct usb_device *udev) +{ + int i; + int retval; + struct usb_host_config *actconfig; + + /* Explicitly not marked persistent? */ + if (!udev->persist_enabled) + return 0; + + /* No active config? */ + actconfig = udev->actconfig; + if (!actconfig) + return 0; + + /* FIXME! We should check whether it's open here or not! */ + + /* + * Check that all the interface drivers have a + * 'reset_resume' entrypoint + */ + retval = 0; + for (i = 0; i < actconfig->desc.bNumInterfaces; i++) { + struct usb_interface *intf; + struct usb_driver *driver; + + intf = actconfig->interface[i]; + if (!intf->dev.driver) + continue; + driver = to_usb_driver(intf->dev.driver); + if (!driver->reset_resume) + return 0; + /* + * We have at least one driver, and that one + * has a reset_resume method. + */ + retval = 1; + } + return retval; +} + static void hub_restart(struct usb_hub *hub, int type) { struct usb_device *hdev = hub->hdev; @@ -689,8 +731,8 @@ static void hub_restart(struct usb_hub *hub, int type) * turn off the various status changes to prevent * khubd from disconnecting it later. */ - if (udev->persist_enabled && status == 0 && - !(portstatus & USB_PORT_STAT_ENABLE)) { + if (status == 0 && !(portstatus & USB_PORT_STAT_ENABLE) && + persistent_device(udev)) { if (portchange & USB_PORT_STAT_C_ENABLE) clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_ENABLE); -- cgit v1.2.3 From 20c61fbd8deb2ada0ac3acecf6156a986dbfff2d Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Mon, 28 Apr 2008 14:40:55 +0900 Subject: ipv6 mcast: Check address family of gf_group in getsockopt(MS_FILTER). Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/ipv6_sockglue.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 26b83e512a09..ce794d6acb70 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -874,6 +874,8 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, return -EINVAL; if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) return -EFAULT; + if (gsf.gf_group.ss_family != AF_INET6) + return -EADDRNOTAVAIL; lock_sock(sk); err = ip6_mc_msfget(sk, &gsf, (struct group_filter __user *)optval, optlen); -- cgit v1.2.3 From 36e3deae8ba84865fd9eb3f2f21bbc00d49b7544 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 13 May 2008 02:52:55 +0900 Subject: ipv6 route: Fix route lifetime in netlink message. 1) We may have route lifetime larger than INT_MAX. In that case we had wired value in lifetime. Use INT_MAX if lifetime does not fit in s32. 2) Lifetime is valid iif RTF_EXPIRES is set. Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/route.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 220cffe9e63b..d1f3e19b06c7 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2196,8 +2196,12 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, NLA_PUT_U32(skb, RTA_PRIORITY, rt->rt6i_metric); - expires = (rt->rt6i_flags & RTF_EXPIRES) ? - rt->rt6i_expires - jiffies : 0; + if (!(rt->rt6i_flags & RTF_EXPIRES)) + expires = 0; + else if (rt->rt6i_expires - jiffies < INT_MAX) + expires = rt->rt6i_expires - jiffies; + else + expires = INT_MAX; if (rtnl_put_cacheinfo(skb, &rt->u.dst, 0, 0, 0, expires, rt->u.dst.error) < 0) -- cgit v1.2.3 From e8766fc86b34d44a8c55a2f9d71da69e091b1ca4 Mon Sep 17 00:00:00 2001 From: Shan Wei Date: Tue, 10 Jun 2008 15:50:55 +0800 Subject: ipv6: Check the hop limit setting in ancillary data. When specifing the outgoing hop limit as ancillary data for sendmsg(), the kernel doesn't check the integer hop limit value as specified in [RFC-3542] section 6.3. Signed-off-by: Shan Wei Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/datagram.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index b9c2de84a8a2..0f0f94a40335 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -705,6 +705,11 @@ int datagram_send_ctl(struct net *net, } *hlimit = *(int *)CMSG_DATA(cmsg); + if (*hlimit < -1 || *hlimit > 0xff) { + err = -EINVAL; + goto exit_f; + } + break; case IPV6_TCLASS: -- cgit v1.2.3 From 28d4488216645cd71402925cffde9528b0cfdb7e Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 12 Jun 2008 03:14:51 +0900 Subject: ipv6: Check IPV6_MULTICAST_LOOP option value. Only 0 and 1 are valid for IPV6_MULTICAST_LOOP socket option, and we should return an error of EINVAL otherwise, per RFC3493. Based on patch from Shan Wei . Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/ipv6_sockglue.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index ce794d6acb70..9a3697172d5e 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -458,6 +458,8 @@ done: case IPV6_MULTICAST_LOOP: if (optlen < sizeof(int)) goto e_inval; + if (val != valbool) + goto e_inval; np->mc_loop = valbool; retv = 0; break; -- cgit v1.2.3 From 1717699cd5130009b7cd6756e883d8582c1fe706 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 12 Jun 2008 03:27:26 +0900 Subject: ipv6: Fail with appropriate error code when setting not-applicable sockopt. IPV6_MULTICAST_HOPS, for example, is not valid for stream sockets. Since they are virtually unavailable for stream sockets, we should return ENOPROTOOPT instead of EINVAL. Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/ipv6_sockglue.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 9a3697172d5e..c042ce19bd14 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -67,7 +67,7 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *)) /* RA packet may be delivered ONLY to IPPROTO_RAW socket */ if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num != IPPROTO_RAW) - return -EINVAL; + return -ENOPROTOOPT; new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; @@ -446,7 +446,7 @@ done: case IPV6_MULTICAST_HOPS: if (sk->sk_type == SOCK_STREAM) - goto e_inval; + break; if (optlen < sizeof(int)) goto e_inval; if (val > 255 || val < -1) @@ -466,7 +466,7 @@ done: case IPV6_MULTICAST_IF: if (sk->sk_type == SOCK_STREAM) - goto e_inval; + break; if (optlen < sizeof(int)) goto e_inval; @@ -862,7 +862,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, if (sk->sk_protocol != IPPROTO_UDP && sk->sk_protocol != IPPROTO_UDPLITE && sk->sk_protocol != IPPROTO_TCP) - return -EINVAL; + return -ENOPROTOOPT; if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; val = sk->sk_family; -- cgit v1.2.3 From b66985b11b8b00e1ec65b89a3112510ac9a9ec6e Mon Sep 17 00:00:00 2001 From: Eric Leblond Date: Wed, 11 Jun 2008 17:50:27 -0700 Subject: netfilter: Make nflog quiet when no one listen in userspace. The message "nf_log_packet: can't log since no backend logging module loaded in! Please either load one, or disable logging explicitly" was displayed for each logged packet when no userspace application is listening to nflog events. The message seems to warn for a problem with a kernel module missing but as said before this is not the case. I thus propose to suppress the message (I don't see any reason to flood the log because a user application has crashed.) Signed-off-by: Eric Leblond Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nf_log.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index bc11d7092032..9fda6ee95a31 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -92,10 +92,6 @@ void nf_log_packet(int pf, vsnprintf(prefix, sizeof(prefix), fmt, args); va_end(args); logger->logfn(pf, hooknum, skb, in, out, loginfo, prefix); - } else if (net_ratelimit()) { - printk(KERN_WARNING "nf_log_packet: can\'t log since " - "no backend logging module loaded in! Please either " - "load one, or disable logging explicitly\n"); } rcu_read_unlock(); } -- cgit v1.2.3 From ceeff7541e5a4ba8e8d97ffbae32b3f283cb7a3f Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Wed, 11 Jun 2008 17:51:10 -0700 Subject: netfilter: nf_conntrack: fix ctnetlink related crash in nf_nat_setup_info() When creation of a new conntrack entry in ctnetlink fails after having set up the NAT mappings, the conntrack has an extension area allocated that is not getting properly destroyed when freeing the conntrack again. This means the NAT extension is still in the bysource hash, causing a crash when walking over the hash chain the next time: BUG: unable to handle kernel paging request at 00120fbd IP: [] nf_nat_setup_info+0x221/0x58a *pde = 00000000 Oops: 0000 [#1] PREEMPT SMP Pid: 2795, comm: conntrackd Not tainted (2.6.26-rc5 #1) EIP: 0060:[] EFLAGS: 00010206 CPU: 1 EIP is at nf_nat_setup_info+0x221/0x58a EAX: 00120fbd EBX: 00120fbd ECX: 00000001 EDX: 00000000 ESI: 0000019e EDI: e853bbb4 EBP: e853bbc8 ESP: e853bb78 DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 Process conntrackd (pid: 2795, ti=e853a000 task=f7de10f0 task.ti=e853a000) Stack: 00000000 e853bc2c e85672ec 00000008 c0561084 63c1db4a 00000000 00000000 00000000 0002e109 61d2b1c3 00000000 00000000 00000000 01114e22 61d2b1c3 00000000 00000000 f7444674 e853bc04 00000008 c038e728 0000000a f7444674 Call Trace: [] nla_parse+0x5c/0xb0 [] ctnetlink_change_status+0x190/0x1c6 [] ctnetlink_new_conntrack+0x189/0x61f [] update_curr+0x3d/0x52 [] nfnetlink_rcv_msg+0xc1/0xd8 [] nfnetlink_rcv_msg+0x18/0xd8 [] nfnetlink_rcv_msg+0x0/0xd8 [] netlink_rcv_skb+0x2d/0x71 [] nfnetlink_rcv+0x19/0x24 [] netlink_unicast+0x1b3/0x216 ... Move invocation of the extension destructors to nf_conntrack_free() to fix this problem. Fixes http://bugzilla.kernel.org/show_bug.cgi?id=10875 Reported-and-Tested-by: Krzysztof Piotr Oledzki Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index c4b1799da5d7..662c1ccfee26 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -196,8 +196,6 @@ destroy_conntrack(struct nf_conntrack *nfct) if (l4proto && l4proto->destroy) l4proto->destroy(ct); - nf_ct_ext_destroy(ct); - rcu_read_unlock(); spin_lock_bh(&nf_conntrack_lock); @@ -520,6 +518,7 @@ static void nf_conntrack_free_rcu(struct rcu_head *head) void nf_conntrack_free(struct nf_conn *ct) { + nf_ct_ext_destroy(ct); call_rcu(&ct->rcu, nf_conntrack_free_rcu); } EXPORT_SYMBOL_GPL(nf_conntrack_free); -- cgit v1.2.3 From 0761248f08ccd94ddceb5454eb1ad96626b10611 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 9 Jun 2008 16:33:50 -0700 Subject: ipg: fix receivemode IPG_RM_RECEIVEMULTICAST{,HASH} in ipg_nic_set_multicast_list() The branches are dead code. even when dev->flag IFF_MULTICAST (defined 0x1000) is set, dev->flags & IFF_MULTICAST & [boolean] always evaluates to 0. Signed-off-by: Roel Kluin Cc: Francois Romieu Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/ipg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 9b358f61ed7f..679a0826780e 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -577,12 +577,12 @@ static void ipg_nic_set_multicast_list(struct net_device *dev) /* NIC to be configured in promiscuous mode. */ receivemode = IPG_RM_RECEIVEALLFRAMES; } else if ((dev->flags & IFF_ALLMULTI) || - (dev->flags & IFF_MULTICAST & + ((dev->flags & IFF_MULTICAST) && (dev->mc_count > IPG_MULTICAST_HASHTABLE_SIZE))) { /* NIC to be configured to receive all multicast * frames. */ receivemode |= IPG_RM_RECEIVEMULTICAST; - } else if (dev->flags & IFF_MULTICAST & (dev->mc_count > 0)) { + } else if ((dev->flags & IFF_MULTICAST) && (dev->mc_count > 0)) { /* NIC to be configured to receive selected * multicast addresses. */ receivemode |= IPG_RM_RECEIVEMULTICASTHASH; -- cgit v1.2.3 From 8b9835108f68938a5f7e74fd2c0fc65da2abad92 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 9 Jun 2008 16:33:51 -0700 Subject: fec_mpc52xx: MPC52xx_MESSAGES_DEFAULT: 2nd NETIF_MSG_IFDOWN => IFUP Duplicate NETIF_MSG_IFDOWN, 2nd should be NETIF_MSG_IFUP Signed-off-by: Roel Kluin Acked-by: Sylvain Munaut Cc: Grant Likely Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/fec_mpc52xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index 5f9c42e7a7f1..329edd9c08fc 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -78,7 +78,7 @@ module_param_array_named(mac, mpc52xx_fec_mac_addr, byte, NULL, 0); MODULE_PARM_DESC(mac, "six hex digits, ie. 0x1,0x2,0xc0,0x01,0xba,0xbe"); #define MPC52xx_MESSAGES_DEFAULT ( NETIF_MSG_DRV | NETIF_MSG_PROBE | \ - NETIF_MSG_LINK | NETIF_MSG_IFDOWN | NETIF_MSG_IFDOWN ) + NETIF_MSG_LINK | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP) static int debug = -1; /* the above default */ module_param(debug, int, 0); MODULE_PARM_DESC(debug, "debugging messages level"); -- cgit v1.2.3 From 208aefa2451cc1f4d87622cb9b2ca4333afa8337 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Thu, 15 May 2008 23:26:22 +0200 Subject: drivers/net/r6040.c: correct bad use of round_jiffies() Compared to other places in the kernel, I think that this driver misuses the function round_jiffies. Signed-off-by: Christophe Jaillet Signed-off-by: Jeff Garzik --- drivers/net/r6040.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 169edc154928..858b191517b3 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -733,7 +733,7 @@ static void r6040_timer(unsigned long data) } /* Timer active again */ - mod_timer(&lp->timer, jiffies + round_jiffies(HZ)); + mod_timer(&lp->timer, round_jiffies(jiffies + HZ)); } /* Read/set MAC address routines */ -- cgit v1.2.3 From 45aec1ae72fc592f231e9e73ed9ed4d10cfbc0b5 Mon Sep 17 00:00:00 2001 From: "venkatesh.pallipadi@intel.com" Date: Tue, 18 Mar 2008 17:00:22 -0700 Subject: x86: PAT export resource_wc in pci sysfs For the ranges with IORESOURCE_PREFETCH, export a new resource_wc interface in pci /sysfs along with resource (which is uncached). Signed-off-by: Venkatesh Pallipadi Signed-off-by: Suresh Siddha Acked-by: Jesse Barnes Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- Documentation/filesystems/sysfs-pci.txt | 1 + drivers/pci/pci-sysfs.c | 84 ++++++++++++++++++++++++--------- include/linux/pci.h | 1 + 3 files changed, 64 insertions(+), 22 deletions(-) diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt index 5daa2aaec2c5..68ef48839c04 100644 --- a/Documentation/filesystems/sysfs-pci.txt +++ b/Documentation/filesystems/sysfs-pci.txt @@ -36,6 +36,7 @@ files, each with their own function. local_cpus nearby CPU mask (cpumask, ro) resource PCI resource host addresses (ascii, ro) resource0..N PCI resource N, if present (binary, mmap) + resource0_wc..N_wc PCI WC map resource N, if prefetchable (binary, mmap) rom PCI ROM resource, if present (binary, ro) subsystem_device PCI subsystem device (ascii, ro) subsystem_vendor PCI subsystem vendor (ascii, ro) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 271d41cc05ab..9ec7d3977a82 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -489,13 +489,14 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr, * @kobj: kobject for mapping * @attr: struct bin_attribute for the file being mapped * @vma: struct vm_area_struct passed into the mmap + * @write_combine: 1 for write_combine mapping * * Use the regular PCI mapping routines to map a PCI resource into userspace. * FIXME: write combining? maybe automatic for prefetchable regions? */ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, - struct vm_area_struct *vma) + struct vm_area_struct *vma, int write_combine) { struct pci_dev *pdev = to_pci_dev(container_of(kobj, struct device, kobj)); @@ -518,7 +519,21 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, vma->vm_pgoff += start >> PAGE_SHIFT; mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io; - return pci_mmap_page_range(pdev, vma, mmap_type, 0); + return pci_mmap_page_range(pdev, vma, mmap_type, write_combine); +} + +static int +pci_mmap_resource_uc(struct kobject *kobj, struct bin_attribute *attr, + struct vm_area_struct *vma) +{ + return pci_mmap_resource(kobj, attr, vma, 0); +} + +static int +pci_mmap_resource_wc(struct kobject *kobj, struct bin_attribute *attr, + struct vm_area_struct *vma) +{ + return pci_mmap_resource(kobj, attr, vma, 1); } /** @@ -541,9 +556,46 @@ pci_remove_resource_files(struct pci_dev *pdev) sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); kfree(res_attr); } + + res_attr = pdev->res_attr_wc[i]; + if (res_attr) { + sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); + kfree(res_attr); + } } } +static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine) +{ + /* allocate attribute structure, piggyback attribute name */ + int name_len = write_combine ? 13 : 10; + struct bin_attribute *res_attr; + int retval; + + res_attr = kzalloc(sizeof(*res_attr) + name_len, GFP_ATOMIC); + if (res_attr) { + char *res_attr_name = (char *)(res_attr + 1); + + if (write_combine) { + pdev->res_attr_wc[num] = res_attr; + sprintf(res_attr_name, "resource%d_wc", num); + res_attr->mmap = pci_mmap_resource_wc; + } else { + pdev->res_attr[num] = res_attr; + sprintf(res_attr_name, "resource%d", num); + res_attr->mmap = pci_mmap_resource_uc; + } + res_attr->attr.name = res_attr_name; + res_attr->attr.mode = S_IRUSR | S_IWUSR; + res_attr->size = pci_resource_len(pdev, num); + res_attr->private = &pdev->resource[num]; + retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); + } else + retval = -ENOMEM; + + return retval; +} + /** * pci_create_resource_files - create resource files in sysfs for @dev * @dev: dev in question @@ -557,31 +609,19 @@ static int pci_create_resource_files(struct pci_dev *pdev) /* Expose the PCI resources from this device as files */ for (i = 0; i < PCI_ROM_RESOURCE; i++) { - struct bin_attribute *res_attr; /* skip empty resources */ if (!pci_resource_len(pdev, i)) continue; - /* allocate attribute structure, piggyback attribute name */ - res_attr = kzalloc(sizeof(*res_attr) + 10, GFP_ATOMIC); - if (res_attr) { - char *res_attr_name = (char *)(res_attr + 1); - - pdev->res_attr[i] = res_attr; - sprintf(res_attr_name, "resource%d", i); - res_attr->attr.name = res_attr_name; - res_attr->attr.mode = S_IRUSR | S_IWUSR; - res_attr->size = pci_resource_len(pdev, i); - res_attr->mmap = pci_mmap_resource; - res_attr->private = &pdev->resource[i]; - retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); - if (retval) { - pci_remove_resource_files(pdev); - return retval; - } - } else { - return -ENOMEM; + retval = pci_create_attr(pdev, i, 0); + /* for prefetchable resources, create a WC mappable file */ + if (!retval && pdev->resource[i].flags & IORESOURCE_PREFETCH) + retval = pci_create_attr(pdev, i, 1); + + if (retval) { + pci_remove_resource_files(pdev); + return retval; } } return 0; diff --git a/include/linux/pci.h b/include/linux/pci.h index 509159bcd4e7..d18b1dd49fab 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -206,6 +206,7 @@ struct pci_dev { struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */ int rom_attr_enabled; /* has display of the rom attribute been enabled? */ struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ + struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */ #ifdef CONFIG_PCI_MSI struct list_head msi_list; #endif -- cgit v1.2.3 From f595ec964daf7f99668039d7303ddedd09a75142 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 12 Jun 2008 10:47:56 +0200 Subject: common implementation of iterative div/mod We have a few instances of the open-coded iterative div/mod loop, used when we don't expcet the dividend to be much bigger than the divisor. Unfortunately modern gcc's have the tendency to strength "reduce" this into a full mod operation, which isn't necessarily any faster, and even if it were, doesn't exist if gcc implements it in libgcc. The workaround is to put a dummy asm statement in the loop to prevent gcc from performing the transformation. This patch creates a single implementation of this loop, and uses it to replace the open-coded versions I know about. Signed-off-by: Jeremy Fitzhardinge Cc: Andrew Morton Cc: john stultz Cc: Segher Boessenkool Cc: Christian Kujau Cc: Robert Hancock Signed-off-by: Ingo Molnar --- arch/x86/xen/time.c | 13 +++---------- include/linux/math64.h | 2 ++ include/linux/time.h | 11 ++--------- lib/div64.c | 23 +++++++++++++++++++++++ 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index c39e1a5aa241..52b2e3856980 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -150,11 +151,7 @@ static void do_stolen_accounting(void) if (stolen < 0) stolen = 0; - ticks = 0; - while (stolen >= NS_PER_TICK) { - ticks++; - stolen -= NS_PER_TICK; - } + ticks = iter_div_u64_rem(stolen, NS_PER_TICK, &stolen); __get_cpu_var(residual_stolen) = stolen; account_steal_time(NULL, ticks); @@ -166,11 +163,7 @@ static void do_stolen_accounting(void) if (blocked < 0) blocked = 0; - ticks = 0; - while (blocked >= NS_PER_TICK) { - ticks++; - blocked -= NS_PER_TICK; - } + ticks = iter_div_u64_rem(blocked, NS_PER_TICK, &blocked); __get_cpu_var(residual_blocked) = blocked; account_steal_time(idle_task(smp_processor_id()), ticks); } diff --git a/include/linux/math64.h b/include/linux/math64.h index c1a5f81501ff..177785e1e4a3 100644 --- a/include/linux/math64.h +++ b/include/linux/math64.h @@ -81,4 +81,6 @@ static inline s64 div_s64(s64 dividend, s32 divisor) } #endif +u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder); + #endif /* _LINUX_MATH64_H */ diff --git a/include/linux/time.h b/include/linux/time.h index d32ef0ad4c0a..05f9517a8ed1 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -6,6 +6,7 @@ #ifdef __KERNEL__ # include # include +# include #endif #ifndef _STRUCT_TIMESPEC @@ -172,15 +173,7 @@ extern struct timeval ns_to_timeval(const s64 nsec); */ static inline void timespec_add_ns(struct timespec *a, u64 ns) { - ns += a->tv_nsec; - while(unlikely(ns >= NSEC_PER_SEC)) { - /* The following asm() prevents the compiler from - * optimising this loop into a modulo operation. */ - asm("" : "+r"(ns)); - - ns -= NSEC_PER_SEC; - a->tv_sec++; - } + a->tv_sec += iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns); a->tv_nsec = ns; } #endif /* __KERNEL__ */ diff --git a/lib/div64.c b/lib/div64.c index bb5bd0c0f030..76c01542d3e1 100644 --- a/lib/div64.c +++ b/lib/div64.c @@ -98,3 +98,26 @@ EXPORT_SYMBOL(div64_u64); #endif #endif /* BITS_PER_LONG == 32 */ + +/* + * Iterative div/mod for use when dividend is not expected to be much + * bigger than divisor. + */ +u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder) +{ + u32 ret = 0; + + while (dividend >= divisor) { + /* The following asm() prevents the compiler from + optimising this loop into a modulo operation. */ + asm("" : "+rm"(dividend)); + + dividend -= divisor; + ret++; + } + + *remainder = dividend; + + return ret; +} +EXPORT_SYMBOL(iter_div_u64_rem); -- cgit v1.2.3 From d5e181f78ac753893eb930868a52a4488cd3de0a Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 12 Jun 2008 10:47:58 +0200 Subject: add an inlined version of iter_div_u64_rem iter_div_u64_rem is used in the x86-64 vdso, which cannot call other kernel code. For this case, provide the always_inlined version, __iter_div_u64_rem. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Ingo Molnar --- include/linux/math64.h | 19 +++++++++++++++++++ lib/div64.c | 15 +-------------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/include/linux/math64.h b/include/linux/math64.h index 177785e1e4a3..c87f1528703a 100644 --- a/include/linux/math64.h +++ b/include/linux/math64.h @@ -83,4 +83,23 @@ static inline s64 div_s64(s64 dividend, s32 divisor) u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder); +static __always_inline u32 +__iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder) +{ + u32 ret = 0; + + while (dividend >= divisor) { + /* The following asm() prevents the compiler from + optimising this loop into a modulo operation. */ + asm("" : "+rm"(dividend)); + + dividend -= divisor; + ret++; + } + + *remainder = dividend; + + return ret; +} + #endif /* _LINUX_MATH64_H */ diff --git a/lib/div64.c b/lib/div64.c index 76c01542d3e1..a111eb8de9cf 100644 --- a/lib/div64.c +++ b/lib/div64.c @@ -105,19 +105,6 @@ EXPORT_SYMBOL(div64_u64); */ u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder) { - u32 ret = 0; - - while (dividend >= divisor) { - /* The following asm() prevents the compiler from - optimising this loop into a modulo operation. */ - asm("" : "+rm"(dividend)); - - dividend -= divisor; - ret++; - } - - *remainder = dividend; - - return ret; + return __iter_div_u64_rem(dividend, divisor, remainder); } EXPORT_SYMBOL(iter_div_u64_rem); -- cgit v1.2.3 From 9412e28649d0272df5e4af57bb378926fd4df580 Mon Sep 17 00:00:00 2001 From: Jeremy Fitzhardinge Date: Thu, 12 Jun 2008 10:48:00 +0200 Subject: always_inline timespec_add_ns timespec_add_ns is used from the x86-64 vdso, which cannot call out to other kernel code. Make sure that timespec_add_ns is always inlined (and only uses always_inlined functions) to make sure there are no unexpected calls. Signed-off-by: Jeremy Fitzhardinge Signed-off-by: Ingo Molnar --- include/linux/time.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/linux/time.h b/include/linux/time.h index 05f9517a8ed1..e15206a7e82e 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -170,10 +170,13 @@ extern struct timeval ns_to_timeval(const s64 nsec); * timespec_add_ns - Adds nanoseconds to a timespec * @a: pointer to timespec to be incremented * @ns: unsigned nanoseconds value to be added + * + * This must always be inlined because its used from the x86-64 vdso, + * which cannot call other kernel functions. */ -static inline void timespec_add_ns(struct timespec *a, u64 ns) +static __always_inline void timespec_add_ns(struct timespec *a, u64 ns) { - a->tv_sec += iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns); + a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns); a->tv_nsec = ns; } #endif /* __KERNEL__ */ -- cgit v1.2.3 From 4bb073c0e32a0862bdb5215d11af19f6c0180c98 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 12 Jun 2008 02:22:02 -0700 Subject: net: Eliminate flush_scheduled_work() calls while RTNL is held. If the RTNL is held when we invoke flush_scheduled_work() we could deadlock. One such case is linkwatch, it is a work struct which tries to grab the RTNL semaphore. The most common case are net driver ->stop() methods. The simplest conversion is to instead use cancel_{delayed_}work_sync() explicitly on the various work struct the driver uses. This is an OK transformation because these work structs are doing things like resetting the chip, restarting link negotiation, and so forth. And if we're bringing down the device, we're about to turn the chip off and reset it anways. So if we cancel a pending work event, that's fine here. Some drivers were working around this deadlock by using a msleep() polling loop of some sort, and those cases are converted to instead use cancel_{delayed_}work_sync() as well. Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 9 +-------- drivers/net/bnx2.h | 1 - drivers/net/ehea/ehea_main.c | 3 ++- drivers/net/hamradio/baycom_epp.c | 2 +- drivers/net/smc911x.c | 24 +++++------------------- drivers/net/smc91x.c | 17 +++-------------- drivers/net/tulip/tulip_core.c | 2 +- drivers/net/usb/kaweth.c | 2 +- drivers/net/wireless/hostap/hostap_main.c | 8 +++++++- 9 files changed, 21 insertions(+), 47 deletions(-) diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 4b46e68183e0..367b6d462708 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -5724,14 +5724,12 @@ bnx2_reset_task(struct work_struct *work) if (!netif_running(bp->dev)) return; - bp->in_reset_task = 1; bnx2_netif_stop(bp); bnx2_init_nic(bp); atomic_set(&bp->intr_sem, 1); bnx2_netif_start(bp); - bp->in_reset_task = 0; } static void @@ -5907,12 +5905,7 @@ bnx2_close(struct net_device *dev) struct bnx2 *bp = netdev_priv(dev); u32 reset_code; - /* Calling flush_scheduled_work() may deadlock because - * linkwatch_event() may be on the workqueue and it will try to get - * the rtnl_lock which we are holding. - */ - while (bp->in_reset_task) - msleep(1); + cancel_work_sync(&bp->reset_task); bnx2_disable_int_sync(bp); bnx2_napi_disable(bp); diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 1eaf5bb3d9c2..2377cc13bf61 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -6656,7 +6656,6 @@ struct bnx2 { int current_interval; struct timer_list timer; struct work_struct reset_task; - int in_reset_task; /* Used to synchronize phy accesses. */ spinlock_t phy_lock; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index faae01dc1c4b..075fd547421e 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -2605,7 +2605,8 @@ static int ehea_stop(struct net_device *dev) if (netif_msg_ifdown(port)) ehea_info("disabling port %s", dev->name); - flush_scheduled_work(); + cancel_work_sync(&port->reset_task); + mutex_lock(&port->port_lock); netif_stop_queue(dev); port_napi_disable(port); diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index dde9c7e6408a..00bc7fbb6b37 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -959,7 +959,7 @@ static int epp_close(struct net_device *dev) unsigned char tmp[1]; bc->work_running = 0; - flush_scheduled_work(); + cancel_delayed_work_sync(&bc->run_work); bc->stat = EPP_DCDBIT; tmp[0] = 0; pp->ops->epp_write_addr(pp, tmp, 1, 0); diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 4e2800205189..e2ee91a6ae7e 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -136,7 +136,6 @@ struct smc911x_local { /* work queue */ struct work_struct phy_configure; - int work_pending; int tx_throttle; spinlock_t lock; @@ -960,11 +959,11 @@ static void smc911x_phy_configure(struct work_struct *work) * We should not be called if phy_type is zero. */ if (lp->phy_type == 0) - goto smc911x_phy_configure_exit_nolock; + return; if (smc911x_phy_reset(dev, phyaddr)) { printk("%s: PHY reset timed out\n", dev->name); - goto smc911x_phy_configure_exit_nolock; + return; } spin_lock_irqsave(&lp->lock, flags); @@ -1033,8 +1032,6 @@ static void smc911x_phy_configure(struct work_struct *work) smc911x_phy_configure_exit: spin_unlock_irqrestore(&lp->lock, flags); -smc911x_phy_configure_exit_nolock: - lp->work_pending = 0; } /* @@ -1356,11 +1353,8 @@ static void smc911x_timeout(struct net_device *dev) * smc911x_phy_configure() calls msleep() which calls schedule_timeout() * which calls schedule(). Hence we use a work queue. */ - if (lp->phy_type != 0) { - if (schedule_work(&lp->phy_configure)) { - lp->work_pending = 1; - } - } + if (lp->phy_type != 0) + schedule_work(&lp->phy_configure); /* We can accept TX packets again */ dev->trans_start = jiffies; @@ -1531,16 +1525,8 @@ static int smc911x_close(struct net_device *dev) if (lp->phy_type != 0) { /* We need to ensure that no calls to * smc911x_phy_configure are pending. - - * flush_scheduled_work() cannot be called because we - * are running with the netlink semaphore held (from - * devinet_ioctl()) and the pending work queue - * contains linkwatch_event() (scheduled by - * netif_carrier_off() above). linkwatch_event() also - * wants the netlink semaphore. */ - while (lp->work_pending) - schedule(); + cancel_work_sync(&lp->phy_configure); smc911x_phy_powerdown(dev, lp->mii.phy_id); } diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index a188e33484e6..f2051b209da2 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1016,15 +1016,8 @@ static void smc_phy_powerdown(struct net_device *dev) /* We need to ensure that no calls to smc_phy_configure are pending. - - flush_scheduled_work() cannot be called because we are - running with the netlink semaphore held (from - devinet_ioctl()) and the pending work queue contains - linkwatch_event() (scheduled by netif_carrier_off() - above). linkwatch_event() also wants the netlink semaphore. */ - while(lp->work_pending) - yield(); + cancel_work_sync(&lp->phy_configure); bmcr = smc_phy_read(dev, phy, MII_BMCR); smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN); @@ -1161,7 +1154,6 @@ static void smc_phy_configure(struct work_struct *work) smc_phy_configure_exit: SMC_SELECT_BANK(lp, 2); spin_unlock_irq(&lp->lock); - lp->work_pending = 0; } /* @@ -1389,11 +1381,8 @@ static void smc_timeout(struct net_device *dev) * smc_phy_configure() calls msleep() which calls schedule_timeout() * which calls schedule(). Hence we use a work queue. */ - if (lp->phy_type != 0) { - if (schedule_work(&lp->phy_configure)) { - lp->work_pending = 1; - } - } + if (lp->phy_type != 0) + schedule_work(&lp->phy_configure); /* We can accept TX packets again */ dev->trans_start = jiffies; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 55670b5eb611..af8d2c436efd 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -731,7 +731,7 @@ static void tulip_down (struct net_device *dev) void __iomem *ioaddr = tp->base_addr; unsigned long flags; - flush_scheduled_work(); + cancel_work_sync(&tp->media_work); #ifdef CONFIG_TULIP_NAPI napi_disable(&tp->napi); diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 0dcfc0310264..7c66b052f55a 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -706,7 +706,7 @@ static void kaweth_kill_urbs(struct kaweth_device *kaweth) usb_kill_urb(kaweth->rx_urb); usb_kill_urb(kaweth->tx_urb); - flush_scheduled_work(); + cancel_delayed_work_sync(&kaweth->lowmem_work); /* a scheduled work may have resubmitted, we hit them again */ diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 20d387f6658c..f7aec9309d04 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -682,7 +682,13 @@ static int prism2_close(struct net_device *dev) netif_device_detach(dev); } - flush_scheduled_work(); + cancel_work_sync(&local->reset_queue); + cancel_work_sync(&local->set_multicast_list_queue); + cancel_work_sync(&local->set_tim_queue); +#ifndef PRISM2_NO_STATION_MODES + cancel_work_sync(&local->info_queue); +#endif + cancel_work_sync(&local->comms_qual_update); module_put(local->hw_module); -- cgit v1.2.3 From 2e084786f6fe052274f1dfa7c675fe4a02cacd6e Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Thu, 12 Jun 2008 16:42:58 +0800 Subject: sched: fair group: fix overflow(was: fix divide by zero) I found a bug which can be reproduced by this way:(linux-2.6.26-rc5, x86-64) (use 2^32, 2^33, ...., 2^63 as shares value) # mkdir /dev/cpuctl # mount -t cgroup -o cpu cpuctl /dev/cpuctl # cd /dev/cpuctl # mkdir sub # echo 0x8000000000000000 > sub/cpu.shares # echo $$ > sub/tasks oops here! divide by zero. This is because do_div() expects the 2th parameter to be 32 bits, but unsigned long is 64 bits in x86_64. Peter Zijstra pointed it out that the sane thing to do is limit the shares value to something smaller instead of using an even more expensive divide. Also, I found another bug about "the shares value is too large": pid1 and pid2 are set affinity to cpu#0 pid1 is attached to cg1 and pid2 is attached to cg2 if cg1/cpu.shares = 1024 cg2/cpu.shares = 2000000000 then pid2 got 100% usage of cpu, and pid1 0% if cg1/cpu.shares = 1024 cg2/cpu.shares = 20000000000 then pid2 got 0% usage of cpu, and pid1 100% And a weight of a cfs_rq is the sum of weights of which entities are queued on this cfs_rq, so the shares value should be limited to a smaller value. I think that (1UL << 18) is a good limited value: 1) it's not too large, we can create a lot of group before overflow 2) it's several times the weight value for nice=-19 (not too small) Signed-off-by: Lai Jiangshan Acked-by: Peter Zijlstra Signed-off-by: Ingo Molnar --- kernel/sched.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index 2c65bf29d133..6c1ecbdc0db9 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -312,12 +312,15 @@ static DEFINE_SPINLOCK(task_group_lock); #endif /* - * A weight of 0, 1 or ULONG_MAX can cause arithmetics problems. + * A weight of 0 or 1 can cause arithmetics problems. + * A weight of a cfs_rq is the sum of weights of which entities + * are queued on this cfs_rq, so a weight of a entity should not be + * too large, so as the shares value of a task group. * (The default weight is 1024 - so there's no practical * limitation from this.) */ #define MIN_SHARES 2 -#define MAX_SHARES (ULONG_MAX - 1) +#define MAX_SHARES (1UL << 18) static int init_task_group_load = INIT_TASK_GROUP_LOAD; #endif -- cgit v1.2.3 From 7a232e0350940d2664f4de5cc3f0f443bae5062d Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Thu, 12 Jun 2008 16:43:07 +0800 Subject: sched: 64-bit: fix arithmetics overflow (overflow means weight >= 2^32 here, because inv_weigh = 2^32/weight) A weight of a cfs_rq is the sum of weights of which entities are queued on this cfs_rq, so it will overflow when there are too many entities. Although, overflow occurs very rarely, but it break fairness when it occurs. 64-bits systems have more memory than 32-bit systems and 64-bit systems can create more process usually, so overflow may occur more frequently. This patch guarantees fairness when overflow happens on 64-bit systems. Thanks to the optimization of compiler, it changes nothing on 32-bit. Signed-off-by: Lai Jiangshan Acked-by: Peter Zijlstra Signed-off-by: Ingo Molnar --- kernel/sched.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/sched.c b/kernel/sched.c index 6c1ecbdc0db9..eaf6751e7612 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1340,8 +1340,13 @@ calc_delta_mine(unsigned long delta_exec, unsigned long weight, { u64 tmp; - if (!lw->inv_weight) - lw->inv_weight = 1 + (WMULT_CONST-lw->weight/2)/(lw->weight+1); + if (!lw->inv_weight) { + if (BITS_PER_LONG > 32 && unlikely(lw->weight >= WMULT_CONST)) + lw->inv_weight = 1; + else + lw->inv_weight = 1 + (WMULT_CONST-lw->weight/2) + / (lw->weight+1); + } tmp = (u64)delta_exec * weight; /* -- cgit v1.2.3 From 4d7365d664e79710ac0e782a23443471ddf05bdd Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Thu, 12 Jun 2008 15:02:55 +0200 Subject: kbuild: ignore powerpc specific symbols in modpost Kumar Gala wrote: We have a case in powerpc in which we want to link some library routines with all module objects. The routines are intended for handling out-of-line function call register save/restore so having them as EXPORT_SYMBOL() is counter productive (we do also need to link the same "library" code into the kernel). Without this patch a powerpc build would error out and fail to build modules with the added register save/restore module. There were two obvious solutions: 1) To link the .o file before the modpost stage 2) To ignore the symbols in modpost Option 1) was ruled out because we do not have any separate linking stage for single file modules. This patch implements option 2 - and do so only for powerpc. The symbols we ignore are all undefined symbols named: _restgpr_*, _savegpr_*, _rest32gpr_*, _save32gpr_* Signed-off-by: Sam Ravnborg Cc: Kumar Gala Cc: Paul Mackerras --- scripts/mod/modpost.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 508c5895c680..a07f91aac920 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -467,6 +467,25 @@ static void parse_elf_finish(struct elf_info *info) release_file(info->hdr, info->size); } +static int ignore_undef_symbol(struct elf_info *info, const char *symname) +{ + /* ignore __this_module, it will be resolved shortly */ + if (strcmp(symname, MODULE_SYMBOL_PREFIX "__this_module") == 0) + return 1; + /* ignore global offset table */ + if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) + return 1; + if (info->hdr->e_machine == EM_PPC) + /* Special register function linked on all modules during final link of .ko */ + if (strncmp(symname, "_restgpr_", sizeof("_restgpr_") - 1) == 0 || + strncmp(symname, "_savegpr_", sizeof("_savegpr_") - 1) == 0 || + strncmp(symname, "_rest32gpr_", sizeof("_rest32gpr_") - 1) == 0 || + strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0) + return 1; + /* Do not ignore this symbol */ + return 0; +} + #define CRC_PFX MODULE_SYMBOL_PREFIX "__crc_" #define KSYMTAB_PFX MODULE_SYMBOL_PREFIX "__ksymtab_" @@ -493,11 +512,7 @@ static void handle_modversions(struct module *mod, struct elf_info *info, if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL && ELF_ST_BIND(sym->st_info) != STB_WEAK) break; - /* ignore global offset table */ - if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) - break; - /* ignore __this_module, it will be resolved shortly */ - if (strcmp(symname, MODULE_SYMBOL_PREFIX "__this_module") == 0) + if (ignore_undef_symbol(info, symname)) break; /* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */ #if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER) -- cgit v1.2.3 From f969c5672b16b857e5231ad3c78f08d8ef3305aa Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Thu, 12 Jun 2008 02:05:26 -0400 Subject: fsl-diu-db: compile fix This patch fixes a compile failure in 2.6.26-rc5-git5. The variable is expected to be called ofdev. Signed-off-by: Jeff Mahoney Signed-off-by: Linus Torvalds --- drivers/video/fsl-diu-fb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index b50bb03cb5ab..0a2785361ca3 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -1320,7 +1320,7 @@ static void free_irq_local(int irq) * Power management hooks. Note that we won't be called from IRQ context, * unlike the blank functions above, so we may sleep. */ -static int fsl_diu_suspend(struct of_device *dev, pm_message_t state) +static int fsl_diu_suspend(struct of_device *ofdev, pm_message_t state) { struct fsl_diu_data *machine_data; @@ -1330,7 +1330,7 @@ static int fsl_diu_suspend(struct of_device *dev, pm_message_t state) return 0; } -static int fsl_diu_resume(struct of_device *dev) +static int fsl_diu_resume(struct of_device *ofdev) { struct fsl_diu_data *machine_data; -- cgit v1.2.3 From 5a1603be58f11edb1b30cb1e40cfbdd4439289d0 Mon Sep 17 00:00:00 2001 From: Paul Mundt Date: Thu, 12 Jun 2008 16:29:55 +0900 Subject: nommu: Correct kobjsize() page validity checks. This implements a few changes on top of the recent kobjsize() refactoring introduced by commit 6cfd53fc03670c7a544a56d441eb1a6cc800d72b. As Christoph points out: virt_to_head_page cannot return NULL. virt_to_page also does not return NULL. pfn_valid() needs to be used to figure out if a page is valid. Otherwise the page struct reference that was returned may have PageReserved() set to indicate that it is not a valid page. As discussed further in the thread, virt_addr_valid() is the preferable way to validate the object pointer in this case. In addition to fixing up the reserved page case, it also has the benefit of encapsulating the hack introduced by commit 4016a1390d07f15b267eecb20e76a48fd5c524ef on the impacted platforms, allowing us to get rid of the extra checking in kobjsize() for the platforms that don't perform this type of bizarre memory_end abuse (every nommu platform that isn't blackfin). If blackfin decides to get in line with every other platform and use PageReserved for the DMA pages in question, kobjsize() will also continue to work fine. It also turns out that compound_order() will give us back 0-order for non-head pages, so we can get rid of the PageCompound check and just use compound_order() directly. Clean that up while we're at it. Signed-off-by: Paul Mundt Reviewed-by: Christoph Lameter Acked-by: David Howells Signed-off-by: Linus Torvalds --- mm/nommu.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/mm/nommu.c b/mm/nommu.c index 3abd0845bda4..4462b6a3fcb9 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -104,21 +104,15 @@ EXPORT_SYMBOL(vmtruncate); unsigned int kobjsize(const void *objp) { struct page *page; - int order = 0; /* * If the object we have should not have ksize performed on it, * return size of 0 */ - if (!objp) - return 0; - - if ((unsigned long)objp >= memory_end) + if (!objp || !virt_addr_valid(objp)) return 0; page = virt_to_head_page(objp); - if (!page) - return 0; /* * If the allocator sets PageSlab, we know the pointer came from @@ -129,18 +123,9 @@ unsigned int kobjsize(const void *objp) /* * The ksize() function is only guaranteed to work for pointers - * returned by kmalloc(). So handle arbitrary pointers, that we expect - * always to be compound pages, here. - */ - if (PageCompound(page)) - order = compound_order(page); - - /* - * Finally, handle arbitrary pointers that don't set PageSlab. - * Default to 0-order in the case when we're unable to ksize() - * the object. + * returned by kmalloc(). So handle arbitrary pointers here. */ - return PAGE_SIZE << order; + return PAGE_SIZE << compound_order(page); } /* -- cgit v1.2.3 From 14a73f54798f39854e521fb596da7d50b7566bbd Mon Sep 17 00:00:00 2001 From: Carl Henrik Lunde Date: Thu, 12 Jun 2008 20:13:58 +0200 Subject: block: disable IRQs until data is written to relay channel As we may run relay_reserve from interrupt context we must always disable IRQs. This is because a call to relay_reserve may expose previously written data to use space. Updated new message code and an old but related comment. Signed-off-by: Carl Henrik Lunde Signed-off-by: Jens Axboe Signed-off-by: Linus Torvalds --- block/blktrace.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/block/blktrace.c b/block/blktrace.c index 7ae87cc4a163..8d3a27780260 100644 --- a/block/blktrace.c +++ b/block/blktrace.c @@ -79,16 +79,17 @@ void __trace_note_message(struct blk_trace *bt, const char *fmt, ...) { int n; va_list args; + unsigned long flags; char *buf; - preempt_disable(); + local_irq_save(flags); buf = per_cpu_ptr(bt->msg_data, smp_processor_id()); va_start(args, fmt); n = vscnprintf(buf, BLK_TN_MAX_MSG, fmt, args); va_end(args); trace_note(bt, 0, BLK_TN_MESSAGE, buf, n); - preempt_enable(); + local_irq_restore(flags); } EXPORT_SYMBOL_GPL(__trace_note_message); @@ -158,10 +159,7 @@ void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes, /* * A word about the locking here - we disable interrupts to reserve * some space in the relay per-cpu buffer, to prevent an irq - * from coming in and stepping on our toes. Once reserved, it's - * enough to get preemption disabled to prevent read of this data - * before we are through filling it. get_cpu()/put_cpu() does this - * for us + * from coming in and stepping on our toes. */ local_irq_save(flags); -- cgit v1.2.3 From 3703f39965a197ebd91743fc38d0f640606b8da3 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 4 Jun 2008 18:13:37 +0200 Subject: geode: fix modular build -tip testing found this build bug: MODPOST 331 modules ERROR: "geode_mfgpt_toggle_event" [drivers/watchdog/geodewdt.ko] undefined! ERROR: "geode_mfgpt_alloc_timer" [drivers/watchdog/geodewdt.ko] undefined! make[1]: *** [__modpost] Error 1 make: *** [modules] Error 2 with this config: http://redhat.com/~mingo/misc/config-Wed_Jun__4_18_01_59_CEST_2008.bad export those symbols. Signed-off-by: Ingo Molnar --- arch/x86/kernel/mfgpt_32.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c index 3cad17fe026b..07c0f828f488 100644 --- a/arch/x86/kernel/mfgpt_32.c +++ b/arch/x86/kernel/mfgpt_32.c @@ -155,6 +155,7 @@ int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable) wrmsr(msr, value, dummy); return 0; } +EXPORT_SYMBOL_GPL(geode_mfgpt_toggle_event); int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable) { @@ -222,6 +223,7 @@ int geode_mfgpt_alloc_timer(int timer, int domain) /* No timers available - too bad */ return -1; } +EXPORT_SYMBOL_GPL(geode_mfgpt_alloc_timer); #ifdef CONFIG_GEODE_MFGPT_TIMER -- cgit v1.2.3 From b29c701deacd5d24453127c37ed77ef851c53b8b Mon Sep 17 00:00:00 2001 From: Henry Nestler Date: Mon, 12 May 2008 15:44:39 +0200 Subject: x86: fix endless page faults in mount_block_root for Linux 2.6 Page faults in kernel address space between PAGE_OFFSET up to VMALLOC_START should not try to map as vmalloc. Fix rarely endless page faults inside mount_block_root for root filesystem at boot time. All 32bit kernels up to 2.6.25 can fail into this hole. I can not present this under native linux kernel. I see, that the 64bit has fixed the problem. I copied the same lines into 32bit part. Recorded debugs are from coLinux kernel 2.6.22.18 (virtualisation): http://www.henrynestler.com/colinux/testing/pfn-check-0.7.3/20080410-antinx/bug16-recursive-page-fault-endless.txt The physicaly memory was trimmed down to 192MB to better catch the bug. More memory gets the bug more rarely. Details, how every x86 32bit system can fail: Start from "mount_block_root", http://lxr.linux.no/linux/init/do_mounts.c#L297 There the variable "fs_names" got one memory page with 4096 bytes. Variable "p" walks through the existing file system types. The first string is no problem. But, with the second loop in mount_block_root the offset of "p" is not at beginning of page, the offset is for example +9, if "reiserfs" is the first in list. Than calls do_mount_root, and lands in sys_mount. Remember: Variable "type_page" contains now "fs_type+9" and not contains a full page. The sys_mount copies 4096 bytes with function "exact_copy_from_user()": http://lxr.linux.no/linux/fs/namespace.c#L1540 Mostly exist pages after the buffer "fs_names+4096+9" and the page fault handler was not called. No problem. In the case, if the page after "fs_names+4096" is not mapped, the page fault handler was called from http://lxr.linux.no/linux/fs/namespace.c#L1320 The do_page_fault gots an address 0xc03b4000. It's kernel address, address >= TASK_SIZE, but not from vmalloc! It's from "__getname()" alias "kmem_cache_alloc". The "error_code" is 0. "vmalloc_fault" will be call: http://lxr.linux.no/linux/arch/i386/mm/fault.c#L332 "vmalloc_fault" tryed to find the physical page for a non existing virtual memory area. The macro "pte_present" in vmalloc_fault() got a next page fault for 0xc0000ed0 at: http://lxr.linux.no/linux/arch/i386/mm/fault.c#L282 No PTE exist for such virtual address. The page fault handler was trying to sync the physical page for the PTE lockup. This called vmalloc_fault() again for address 0xc000000, and that also was not existing. The endless began... In normal case the cpu would still loop with disabled interrrupts. Under coLinux this was catched by a stack overflow inside printk debugs. Signed-off-by: Henry Nestler Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/mm/fault.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index fd7e1798c75a..8bcb6f40ccb6 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -497,6 +497,11 @@ static int vmalloc_fault(unsigned long address) unsigned long pgd_paddr; pmd_t *pmd_k; pte_t *pte_k; + + /* Make sure we are in vmalloc area */ + if (!(address >= VMALLOC_START && address < VMALLOC_END)) + return -1; + /* * Synchronize this task's top level page-table * with the 'reference' page table. -- cgit v1.2.3 From 86b2b70e156203149c3861455feec54bc4906e6d Mon Sep 17 00:00:00 2001 From: Joe Korty Date: Mon, 2 Jun 2008 17:21:06 -0400 Subject: x86: fix asm warning in head_32.S On Mon, May 19, 2008 at 04:10:02PM -0700, Linus Torvalds wrote: > It also causes these warnings on 32-bit PAE: > > AS arch/x86/kernel/head_32.o > arch/x86/kernel/head_32.S: Assembler messages: > arch/x86/kernel/head_32.S:225: Warning: left operand is a bignum; integer 0 assumed > arch/x86/kernel/head_32.S:609: Warning: left operand is a bignum; integer 0 assumed > > and I do not see why (the end result seems to be identical). Fix head_32.S gcc bignum warnings when CONFIG_PAE=y. arch/x86/kernel/head_32.S: Assembler messages: arch/x86/kernel/head_32.S:225: Warning: left operand is a bignum; integer 0 assumed arch/x86/kernel/head_32.S:609: Warning: left operand is a bignum; integer 0 assumed The assembler was stumbling over the 64-bit constant 0x100000000 in the KPMDS #define. Testing: a cmp(1) on head_32.o before and after shows the binary is unchanged. Signed-off-by: Joe Korty Cc: Theodore Tso Cc: Gabriel C Cc: Keith Packard Cc: "Pallipadi Venkatesh" Cc: Eric Anholt Cc: "Siddha Suresh B" Cc: bugme-daemon@bugzilla.kernel.org Cc: airlied@linux.ie Cc: "Barnes Jesse" Cc: Jeremy Fitzhardinge Cc: Andrew Morton Cc: "Rafael J. Wysocki" Cc: Linus Torvalds Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar --- arch/x86/kernel/head_32.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S index b2cc73768a9d..f7357cc0162c 100644 --- a/arch/x86/kernel/head_32.S +++ b/arch/x86/kernel/head_32.S @@ -189,7 +189,7 @@ default_entry: * this stage. */ -#define KPMDS ((0x100000000-__PAGE_OFFSET) >> 30) /* Number of kernel PMDs */ +#define KPMDS (((-__PAGE_OFFSET) >> 30) & 3) /* Number of kernel PMDs */ xorl %ebx,%ebx /* %ebx is kept at zero */ -- cgit v1.2.3 From 0b6a39f7ebcb1c82587ce35b401c513eed41ac5c Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 9 Jun 2008 13:29:43 +0200 Subject: Revert "x86: fix ioapic bug again" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 6e908947b4995bc0e551a8257c586d5c3e428201. Németh Márton reported: | there is a problem in 2.6.26-rc3 which was not there in case of | 2.6.25: the CPU wakes up ~90,000 times per sec instead of ~60 per sec. | | I also "git bisected" the problem, the result is: | | 6e908947b4995bc0e551a8257c586d5c3e428201 is first bad commit | commit 6e908947b4995bc0e551a8257c586d5c3e428201 | Author: Ingo Molnar | Date: Fri Mar 21 14:32:36 2008 +0100 | | x86: fix ioapic bug again the original problem is fixed by Maciej W. Rozycki in the tip/x86/apic branch (confirmed by Márton), but those changes are too intrusive for v2.6.26 so we'll go for the less intrusive (repeated) revert now. Reported-and-bisected-by: Németh Márton Signed-off-by: Ingo Molnar --- arch/x86/kernel/io_apic_32.c | 12 ++---------- arch/x86/kernel/nmi_32.c | 9 ++------- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/arch/x86/kernel/io_apic_32.c b/arch/x86/kernel/io_apic_32.c index a40d54fc1fdd..4dc8600d9d20 100644 --- a/arch/x86/kernel/io_apic_32.c +++ b/arch/x86/kernel/io_apic_32.c @@ -2130,14 +2130,10 @@ static inline void __init check_timer(void) { int apic1, pin1, apic2, pin2; int vector; - unsigned int ver; unsigned long flags; local_irq_save(flags); - ver = apic_read(APIC_LVR); - ver = GET_APIC_VERSION(ver); - /* * get/set the timer IRQ vector: */ @@ -2150,15 +2146,11 @@ static inline void __init check_timer(void) * mode for the 8259A whenever interrupts are routed * through I/O APICs. Also IRQ0 has to be enabled in * the 8259A which implies the virtual wire has to be - * disabled in the local APIC. Finally timer interrupts - * need to be acknowledged manually in the 8259A for - * timer_interrupt() and for the i82489DX when using - * the NMI watchdog. + * disabled in the local APIC. */ apic_write_around(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); init_8259A(1); - timer_ack = !cpu_has_tsc; - timer_ack |= (nmi_watchdog == NMI_IO_APIC && !APIC_INTEGRATED(ver)); + timer_ack = 1; if (timer_over_8254 > 0) enable_8259A_irq(0); diff --git a/arch/x86/kernel/nmi_32.c b/arch/x86/kernel/nmi_32.c index 11b14bbaa61e..84160f74eeb0 100644 --- a/arch/x86/kernel/nmi_32.c +++ b/arch/x86/kernel/nmi_32.c @@ -26,7 +26,6 @@ #include #include -#include #include "mach_traps.h" @@ -82,7 +81,7 @@ int __init check_nmi_watchdog(void) prev_nmi_count = kmalloc(NR_CPUS * sizeof(int), GFP_KERNEL); if (!prev_nmi_count) - goto error; + return -1; printk(KERN_INFO "Testing NMI watchdog ... "); @@ -119,7 +118,7 @@ int __init check_nmi_watchdog(void) if (!atomic_read(&nmi_active)) { kfree(prev_nmi_count); atomic_set(&nmi_active, -1); - goto error; + return -1; } printk("OK.\n"); @@ -130,10 +129,6 @@ int __init check_nmi_watchdog(void) kfree(prev_nmi_count); return 0; -error: - timer_ack = !cpu_has_tsc; - - return -1; } static int __init setup_nmi_watchdog(char *str) -- cgit v1.2.3 From 52aaa12fbe786c90396f1b11ec39c924ccdd8fd5 Mon Sep 17 00:00:00 2001 From: Manish Katiyar Date: Thu, 5 Jun 2008 19:14:15 +0530 Subject: x86: fix unused variable 'loops' warning in arch/x86/boot/a20.c Following patch fixes the below warning message : arch/x86/boot/a20.c:118: warning: unused variable 'loops' Signed-off-by : Manish Katiyar Signed-off-by: Ingo Molnar --- arch/x86/boot/a20.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/boot/a20.c b/arch/x86/boot/a20.c index 90943f83e84d..e01aafd03bde 100644 --- a/arch/x86/boot/a20.c +++ b/arch/x86/boot/a20.c @@ -115,8 +115,6 @@ static void enable_a20_fast(void) int enable_a20(void) { - int loops = A20_ENABLE_LOOPS; - #if defined(CONFIG_X86_ELAN) /* Elan croaks if we try to touch the KBC */ enable_a20_fast(); @@ -128,6 +126,7 @@ int enable_a20(void) enable_a20_kbc(); return 0; #else + int loops = A20_ENABLE_LOOPS; while (loops--) { /* First, check to see if A20 is already enabled (legacy free, etc.) */ -- cgit v1.2.3 From e32e58a96de4ac35a03349db2ab69f263ded958f Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 6 Jun 2008 10:14:08 +0200 Subject: x86: fix lockdep warning during suspend-to-ram Andrew Morton wrote: > I've been seeing the below for a long time during suspend-to-ram on the Vaio. > > > PM: Syncing filesystems ... done. > PM: Preparing system for mem sleep > Freezing user space processes ... <4>------------[ cut here ]------------ > WARNING: at kernel/lockdep.c:2658 check_flags+0x4c/0x127() > Modules linked in: i915 drm ipw2200 sonypi ipv6 autofs4 hidp l2cap bluetooth sunrpc nf_conntrack_netbios_ns ipt_REJECT nf_conntrack_ipv4 xt_state nf_conntrack xt_tcpudp iptable_filter ip_tables x_tables acpi_cpufreq nvram ohci1394 ieee1394 ehci_hcd uhci_hcd sg joydev snd_hda_intel snd_seq_dummy sr_mod snd_seq_oss cdrom snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss ieee80211 pcspkr ieee80211_crypt snd_pcm i2c_i801 snd_timer i2c_core ide_pci_generic piix snd soundcore snd_page_alloc button ext3 jbd ide_disk ide_core [last unloaded: ipw2200] > Pid: 3250, comm: zsh Not tainted 2.6.26-rc5 #1 > [] warn_on_slowpath+0x41/0x6d > [] ? native_sched_clock+0x82/0x96 > [] ? mark_held_locks+0x41/0x5c > [] ? _spin_unlock_irqrestore+0x36/0x58 > [] ? trace_hardirqs_on+0xe6/0x10d > [] ? __lock_acquire+0xae3/0xb2b > [] ? schedule+0x39b/0x3b4 > [] check_flags+0x4c/0x127 > [] lock_acquire+0x3a/0x86 > [] _spin_lock+0x26/0x53 > [] ? refrigerator+0x13/0xc3 > [] refrigerator+0x13/0xc3 > [] get_signal_to_deliver+0x3c/0x31e > [] do_notify_resume+0x91/0x6ee > [] ? lock_release_holdtime+0x50/0x56 > [] ? _spin_unlock_irqrestore+0x36/0x58 > [] ? read_chan+0x0/0x58c > [] ? trace_hardirqs_on+0xe6/0x10d > [] ? _spin_unlock_irqrestore+0x42/0x58 > [] ? tty_ldisc_deref+0x5c/0x63 > [] ? tty_read+0x66/0x98 > [] ? audit_syscall_exit+0x2aa/0x2c5 > [] ? do_syscall_trace+0x6b/0x16f > [] work_notifysig+0x13/0x1b > ======================= > ---[ end trace 25b49fe59a25afa5 ]--- > possible reason: unannotated irqs-off. > irq event stamp: 58919 > hardirqs last enabled at (58919): [] syscall_exit_work+0x11/0x26 Joy - I so love entry.S Best I can make of it: syscall_exit_work resume_userspace DISABLE_INTERRUPTS (no TRACE_IRQS_OFF) work_pending work_notifysig do_notify_resume() do_signal() get_signal_to_deliver() try_to_freeze() refrigerator() task_lock() -> check_flags() -> BANG The normal path is: syscall_exit_work resume_userspace DISABLE_INTERRUPTS restore_all TRACE_IRQS_IRET iret No idea why that would not warn.. Signed-off-by: Peter Zijlstra Signed-off-by: Ingo Molnar --- arch/x86/kernel/entry_32.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S index 2a609dc3271c..c778e4fa55a2 100644 --- a/arch/x86/kernel/entry_32.S +++ b/arch/x86/kernel/entry_32.S @@ -248,6 +248,7 @@ ENTRY(resume_userspace) DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt # setting need_resched or sigpending # between sampling and the iret + TRACE_IRQS_OFF movl TI_flags(%ebp), %ecx andl $_TIF_WORK_MASK, %ecx # is there any work to be done on # int/exception return? -- cgit v1.2.3 From eb53e9f3ea859a6d59c37b500593b970aa8562e6 Mon Sep 17 00:00:00 2001 From: David Howells Date: Sat, 7 Jun 2008 17:18:40 +0100 Subject: x86: fix an incompatible pointer type warning on 64-bit compilations Fix an incompatible pointer type warning on x86_64 compilations. early_memtest() is passing a u64* to find_e820_area_size() which is expecting an unsigned long. Change t_start and t_size to unsigned long as those are also 64-bit types on x88_64. Signed-off-by: David Howells Signed-off-by: Ingo Molnar --- arch/x86/mm/init_64.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 156e6d7b0e32..998a06ea5f7d 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -506,7 +506,7 @@ early_param("memtest", parse_memtest); static void __init early_memtest(unsigned long start, unsigned long end) { - u64 t_start, t_size; + unsigned long t_start, t_size; unsigned pattern; if (!memtest_pattern) @@ -525,7 +525,7 @@ static void __init early_memtest(unsigned long start, unsigned long end) if (t_start + t_size > end) t_size = end - t_start; - printk(KERN_CONT "\n %016llx - %016llx pattern %d", + printk(KERN_CONT "\n %016lx - %016lx pattern %d", t_start, t_start + t_size, pattern); memtest(t_start, t_size, pattern); -- cgit v1.2.3 From 4461145ef1be92851c230f858f6b6f457c99670f Mon Sep 17 00:00:00 2001 From: Vegard Nossum Date: Thu, 12 Jun 2008 08:55:59 +0200 Subject: x86, lockdep: fix "WARNING: at kernel/lockdep.c:2658 check_flags+0x4c/0x128()" Alessandro Suardi reported: > Recently upgraded my FC6 desktop to Fedora 9; with the > latest nautilus RPM updates my VNC session went nuts > with nautilus pegging the CPU for everything that breathed. > > I now reverted to an earlier nautilus package, but during > the peak CPU period my kernel spat this: > > [314185.623294] ------------[ cut here ]------------ > [314185.623414] WARNING: at kernel/lockdep.c:2658 check_flags+0x4c/0x128() > [314185.623514] Modules linked in: iptable_filter ip_tables x_tables > sunrpc ipv6 fuse snd_via82xx snd_ac97_codec ac97_bus snd_mpu401_uart > snd_rawmidi via686a hwmon parport_pc sg parport uhci_hcd ehci_hcd > [314185.623924] Pid: 12314, comm: nautilus Not tainted 2.6.26-rc5-git2 #4 > [314185.624021] [] warn_on_slowpath+0x41/0x7b > [314185.624021] [] ? do_page_fault+0x2c1/0x5fd > [314185.624021] [] ? up_read+0x16/0x28 > [314185.624021] [] ? do_page_fault+0x2c1/0x5fd > [314185.624021] [] ? __lock_acquire+0xbb4/0xbc3 > [314185.624021] [] check_flags+0x4c/0x128 > [314185.624021] [] lock_acquire+0x31/0x7d > [314185.624021] [] __atomic_notifier_call_chain+0x30/0x80 > [314185.624021] [] ? __atomic_notifier_call_chain+0x0/0x80 > [314185.624021] [] atomic_notifier_call_chain+0xc/0xe > [314185.624021] [] notify_die+0x2d/0x2f > [314185.624021] [] do_int3+0x1f/0x4d > [314185.624021] [] int3+0x27/0x2c > [314185.624021] ======================= > [314185.624021] ---[ end trace 1923f65a2d7bb246 ]--- > [314185.624021] possible reason: unannotated irqs-off. > [314185.624021] irq event stamp: 488879 > [314185.624021] hardirqs last enabled at (488879): [] > restore_nocheck+0x12/0x15 > [314185.624021] hardirqs last disabled at (488878): [] > work_resched+0x19/0x30 > [314185.624021] softirqs last enabled at (488876): [] > __do_softirq+0xa6/0xac > [314185.624021] softirqs last disabled at (488865): [] > do_softirq+0x57/0xa6 > > I didn't seem to find it with some googling, so here it is. > > I was incidentally ltracing that process to try and find out > what was gulping down that much CPU (sorry, no idea > whether ltrace and the WARNING happened at the same > time or which came first) and: Yeah, this is extremely likely to be the source of the warning. The warning should be harmless, however. > Box is my trusty noname K7-800, 512MB RAM; if there's > anything else useful I might be able to provide, just ask. It would be interesting to see where the int3 comes from. Too bad, lockdep doesn't provide the register dump. The stacktrace also doesn't go further than the int3(), I wonder if this int3 came from userspace? The ltrace readme says "software breakpoints, like gdb", so I guess this is the case. Yep, seems like it. This looks relevant: | commit fb1dac909d94ff807cd833d340c6827c3a957159 | Author: Peter Zijlstra | Date: Wed Jan 16 09:51:59 2008 +0100 | | lockdep: more hardirq annotations for notify_die() I'm attaching a similarly-looking patch for this case (DO_VM86_ERROR), though I suspect it might be missing for the other cases (DO_ERROR/DO_ERROR_INFO) as well. Reported-by: Alessandro Suardi Signed-off-by: Vegard Nossum Acked-by: Peter Zijlstra Signed-off-by: Ingo Molnar --- arch/x86/kernel/traps_32.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index bde6f63e15d5..08d752de4eee 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c @@ -544,6 +544,7 @@ vm86_trap: #define DO_ERROR(trapnr, signr, str, name) \ void do_##name(struct pt_regs *regs, long error_code) \ { \ + trace_hardirqs_fixup(); \ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ == NOTIFY_STOP) \ return; \ -- cgit v1.2.3 From f8a45704f5bd5f037c8e4a75172cab1476fc0447 Mon Sep 17 00:00:00 2001 From: Kevin Winchester Date: Thu, 29 May 2008 21:14:35 -0300 Subject: x86: fix pointer type warning in arch/x86/mm/init_64.c:early_memtest Changed the call to find_e820_area_size to pass u64 instead of unsigned long. Signed-off-by: Kevin Winchester Signed-off-by: Ingo Molnar --- arch/x86/mm/init_64.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 998a06ea5f7d..156e6d7b0e32 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -506,7 +506,7 @@ early_param("memtest", parse_memtest); static void __init early_memtest(unsigned long start, unsigned long end) { - unsigned long t_start, t_size; + u64 t_start, t_size; unsigned pattern; if (!memtest_pattern) @@ -525,7 +525,7 @@ static void __init early_memtest(unsigned long start, unsigned long end) if (t_start + t_size > end) t_size = end - t_start; - printk(KERN_CONT "\n %016lx - %016lx pattern %d", + printk(KERN_CONT "\n %016llx - %016llx pattern %d", t_start, t_start + t_size, pattern); memtest(t_start, t_size, pattern); -- cgit v1.2.3 From 3692fd0aaef489b063518b5999c702bada5b6e22 Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Thu, 12 Jun 2008 07:07:22 +0100 Subject: [ARM] 5091/1: Add missing bitfield include to regs-lcd.h Macros like Fld() or FShft used in regs-lcd.h are defined in bitfield.h, but the latter is not included. Also fix one whitespace issue while being there. Signed-off-by: Antonio Ospite Signed-off-by: Stefan Schmidt Acked-by: Eric Miao Signed-off-by: Russell King --- include/asm-arm/arch-pxa/regs-lcd.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/asm-arm/arch-pxa/regs-lcd.h b/include/asm-arm/arch-pxa/regs-lcd.h index f762493f5141..3ba464c913a5 100644 --- a/include/asm-arm/arch-pxa/regs-lcd.h +++ b/include/asm-arm/arch-pxa/regs-lcd.h @@ -1,5 +1,8 @@ #ifndef __ASM_ARCH_REGS_LCD_H #define __ASM_ARCH_REGS_LCD_H + +#include + /* * LCD Controller Registers and Bits Definitions */ @@ -69,7 +72,7 @@ #define LCCR0_QDM (1 << 11) /* LCD Quick Disable mask */ #define LCCR0_PDD (0xff << 12) /* Palette DMA request delay */ #define LCCR0_PDD_S 12 -#define LCCR0_BM (1 << 20) /* Branch mask */ +#define LCCR0_BM (1 << 20) /* Branch mask */ #define LCCR0_OUM (1 << 21) /* Output FIFO underrun mask */ #define LCCR0_LCDT (1 << 22) /* LCD panel type */ #define LCCR0_RDSTM (1 << 23) /* Read status interrupt mask */ -- cgit v1.2.3 From 81d5575a48f49f494289a1299a32e4e5e41fbf40 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 12 Jun 2008 13:51:46 -0700 Subject: PCI: fixup write combine comment in pci_mmap_resource Now that we can actually do write combining properly, there's no need to have the FIXME. Signed-off-by: Jesse Barnes --- drivers/pci/pci-sysfs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 9ec7d3977a82..6f3c7446c329 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -492,7 +492,6 @@ pci_mmap_legacy_mem(struct kobject *kobj, struct bin_attribute *attr, * @write_combine: 1 for write_combine mapping * * Use the regular PCI mapping routines to map a PCI resource into userspace. - * FIXME: write combining? maybe automatic for prefetchable regions? */ static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr, -- cgit v1.2.3 From 5dd34572ad9a3be430632dd42e4af2ea370b397b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 12 Jun 2008 14:22:24 -0700 Subject: Linux 2.6.26-rc6 .. and a new name, courtesy of Alan. --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 2b951205317d..6923d669a4f6 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,8 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 26 -EXTRAVERSION = -rc5 -NAME = Funky Weasel is Jiggy wit it +EXTRAVERSION = -rc6 +NAME = Rotary Wombat # *DOCUMENTATION* # To see a list of typical targets execute "make help" -- cgit v1.2.3 From 24e3fcefb9cc61acce59ed54c00c4e4c32537de7 Mon Sep 17 00:00:00 2001 From: Eilon Greenstein Date: Thu, 12 Jun 2008 14:30:28 -0700 Subject: bnx2x: Updating the Maintainer I would like to thank Eliezer Tamir for writing and maintaining the driver for the past two years. I will take over maintaining the bnx2x driver from now on. Signed-off-by: Eilon Greenstein Signed-off-by: Eliezer Tamir Signed-off-by: David S. Miller --- MAINTAINERS | 4 ++-- drivers/net/bnx2x.c | 5 +++-- drivers/net/bnx2x.h | 3 ++- drivers/net/bnx2x_init.h | 3 ++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 46fa1797707a..7c8e561dbe19 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -995,8 +995,8 @@ L: netdev@vger.kernel.org S: Supported BROADCOM BNX2X 10 GIGABIT ETHERNET DRIVER -P: Eliezer Tamir -M: eliezert@broadcom.com +P: Eilon Greenstein +M: eilong@broadcom.com L: netdev@vger.kernel.org S: Supported diff --git a/drivers/net/bnx2x.c b/drivers/net/bnx2x.c index 7bdb5af35951..70cba64732ca 100644 --- a/drivers/net/bnx2x.c +++ b/drivers/net/bnx2x.c @@ -6,7 +6,8 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * - * Written by: Eliezer Tamir + * Maintained by: Eilon Greenstein + * Written by: Eliezer Tamir * Based on code from Michael Chan's bnx2 driver * UDP CSUM errata workaround by Arik Gendelman * Slowpath rework by Vladislav Zolotarov @@ -74,7 +75,7 @@ static char version[] __devinitdata = "Broadcom NetXtreme II 5771X 10Gigabit Ethernet Driver " DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; -MODULE_AUTHOR("Eliezer Tamir "); +MODULE_AUTHOR("Eliezer Tamir"); MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710 Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h index 4f0c0d31e7c1..8e68d06510a6 100644 --- a/drivers/net/bnx2x.h +++ b/drivers/net/bnx2x.h @@ -6,7 +6,8 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * - * Written by: Eliezer Tamir + * Maintained by: Eilon Greenstein + * Written by: Eliezer Tamir * Based on code from Michael Chan's bnx2 driver */ diff --git a/drivers/net/bnx2x_init.h b/drivers/net/bnx2x_init.h index dcaecc53bdb1..370686eef97c 100644 --- a/drivers/net/bnx2x_init.h +++ b/drivers/net/bnx2x_init.h @@ -6,7 +6,8 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation. * - * Written by: Eliezer Tamir + * Maintained by: Eilon Greenstein + * Written by: Eliezer Tamir */ #ifndef BNX2X_INIT_H -- cgit v1.2.3 From f23d60de719e639690b2dc5c2d0e4243ff614b7a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 12 Jun 2008 14:47:58 -0700 Subject: ipv6: Fix duplicate initialization of rawv6_prot.destroy In changeset 22dd485022f3d0b162ceb5e67d85de7c3806aa20 ("raw: Raw socket leak.") code was added so that we flush pending frames on raw sockets to avoid leaks. The ipv4 part was fine, but the ipv6 part was not done correctly. Unlike the ipv4 side, the ipv6 code already has a .destroy method for rawv6_prot. So now there were two assignments to this member, and what the compiler does is use the last one, effectively making the ipv6 parts of that changeset a NOP. Fix this by removing the: .destroy = inet6_destroy_sock, line, and adding an inet6_destroy_sock() call to the end of raw6_destroy(). Noticed by Al Viro. Signed-off-by: David S. Miller Acked-by: YOSHIFUJI Hideaki --- net/ipv6/raw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 8fee9a15b2d3..3aee12310d94 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1169,7 +1169,8 @@ static int raw6_destroy(struct sock *sk) lock_sock(sk); ip6_flush_pending_frames(sk); release_sock(sk); - return 0; + + return inet6_destroy_sock(sk); } static int rawv6_init_sk(struct sock *sk) @@ -1200,7 +1201,6 @@ struct proto rawv6_prot = { .disconnect = udp_disconnect, .ioctl = rawv6_ioctl, .init = rawv6_init_sk, - .destroy = inet6_destroy_sock, .setsockopt = rawv6_setsockopt, .getsockopt = rawv6_getsockopt, .sendmsg = rawv6_sendmsg, -- cgit v1.2.3 From ec0a196626bd12e0ba108d7daa6d95a4fb25c2c5 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 12 Jun 2008 16:31:35 -0700 Subject: tcp: Revert 'process defer accept as established' changes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts two changesets, ec3c0982a2dd1e671bad8e9d26c28dcba0039d87 ("[TCP]: TCP_DEFER_ACCEPT updates - process as established") and the follow-on bug fix 9ae27e0adbf471c7a6b80102e38e1d5a346b3b38 ("tcp: Fix slab corruption with ipv6 and tcp6fuzz"). This change causes several problems, first reported by Ingo Molnar as a distcc-over-loopback regression where connections were getting stuck. Ilpo Järvinen first spotted the locking problems. The new function added by this code, tcp_defer_accept_check(), only has the child socket locked, yet it is modifying state of the parent listening socket. Fixing that is non-trivial at best, because we can't simply just grab the parent listening socket lock at this point, because it would create an ABBA deadlock. The normal ordering is parent listening socket --> child socket, but this code path would require the reverse lock ordering. Next is a problem noticed by Vitaliy Gusev, he noted: ---------------------------------------- >--- a/net/ipv4/tcp_timer.c >+++ b/net/ipv4/tcp_timer.c >@@ -481,6 +481,11 @@ static void tcp_keepalive_timer (unsigned long data) > goto death; > } > >+ if (tp->defer_tcp_accept.request && sk->sk_state == TCP_ESTABLISHED) { >+ tcp_send_active_reset(sk, GFP_ATOMIC); >+ goto death; Here socket sk is not attached to listening socket's request queue. tcp_done() will not call inet_csk_destroy_sock() (and tcp_v4_destroy_sock() which should release this sk) as socket is not DEAD. Therefore socket sk will be lost for freeing. ---------------------------------------- Finally, Alexey Kuznetsov argues that there might not even be any real value or advantage to these new semantics even if we fix all of the bugs: ---------------------------------------- Hiding from accept() sockets with only out-of-order data only is the only thing which is impossible with old approach. Is this really so valuable? My opinion: no, this is nothing but a new loophole to consume memory without control. ---------------------------------------- So revert this thing for now. Signed-off-by: David S. Miller --- include/linux/tcp.h | 7 ------- include/net/request_sock.h | 4 ++-- include/net/tcp.h | 1 - net/ipv4/inet_connection_sock.c | 11 +++++++--- net/ipv4/tcp.c | 18 ++++++++++------- net/ipv4/tcp_input.c | 45 ----------------------------------------- net/ipv4/tcp_ipv4.c | 8 -------- net/ipv4/tcp_minisocks.c | 32 +++++++++++------------------ net/ipv4/tcp_timer.c | 5 ----- 9 files changed, 33 insertions(+), 98 deletions(-) diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 18e62e3d406f..b31b6b74aa28 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -239,11 +239,6 @@ static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) return (struct tcp_request_sock *)req; } -struct tcp_deferred_accept_info { - struct sock *listen_sk; - struct request_sock *request; -}; - struct tcp_sock { /* inet_connection_sock has to be the first member of tcp_sock */ struct inet_connection_sock inet_conn; @@ -379,8 +374,6 @@ struct tcp_sock { unsigned int keepalive_intvl; /* time interval between keep alive probes */ int linger2; - struct tcp_deferred_accept_info defer_tcp_accept; - unsigned long last_synq_overflow; u32 tso_deferred; diff --git a/include/net/request_sock.h b/include/net/request_sock.h index b220b5f624de..0c96e7bed5db 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -115,8 +115,8 @@ struct request_sock_queue { struct request_sock *rskq_accept_head; struct request_sock *rskq_accept_tail; rwlock_t syn_wait_lock; - u16 rskq_defer_accept; - /* 2 bytes hole, try to pack */ + u8 rskq_defer_accept; + /* 3 bytes hole, try to pack */ struct listen_sock *listen_opt; }; diff --git a/include/net/tcp.h b/include/net/tcp.h index d448310c82c1..cf54034019d9 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -139,7 +139,6 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); #define MAX_TCP_KEEPINTVL 32767 #define MAX_TCP_KEEPCNT 127 #define MAX_TCP_SYNCNT 127 -#define MAX_TCP_ACCEPT_DEFERRED 65535 #define TCP_SYNQ_INTERVAL (HZ/5) /* Period of SYNACK timer */ diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 828ea211ff21..045e799d3e1d 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -419,7 +419,8 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, struct inet_connection_sock *icsk = inet_csk(parent); struct request_sock_queue *queue = &icsk->icsk_accept_queue; struct listen_sock *lopt = queue->listen_opt; - int thresh = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries; + int max_retries = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries; + int thresh = max_retries; unsigned long now = jiffies; struct request_sock **reqp, *req; int i, budget; @@ -455,6 +456,9 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, } } + if (queue->rskq_defer_accept) + max_retries = queue->rskq_defer_accept; + budget = 2 * (lopt->nr_table_entries / (timeout / interval)); i = lopt->clock_hand; @@ -462,8 +466,9 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, reqp=&lopt->syn_table[i]; while ((req = *reqp) != NULL) { if (time_after_eq(now, req->expires)) { - if (req->retrans < thresh && - !req->rsk_ops->rtx_syn_ack(parent, req)) { + if ((req->retrans < (inet_rsk(req)->acked ? max_retries : thresh)) && + (inet_rsk(req)->acked || + !req->rsk_ops->rtx_syn_ack(parent, req))) { unsigned long timeo; if (req->retrans++ == 0) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index ab66683b8043..fc54a48fde1e 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2112,12 +2112,15 @@ static int do_tcp_setsockopt(struct sock *sk, int level, break; case TCP_DEFER_ACCEPT: - if (val < 0) { - err = -EINVAL; - } else { - if (val > MAX_TCP_ACCEPT_DEFERRED) - val = MAX_TCP_ACCEPT_DEFERRED; - icsk->icsk_accept_queue.rskq_defer_accept = val; + icsk->icsk_accept_queue.rskq_defer_accept = 0; + if (val > 0) { + /* Translate value in seconds to number of + * retransmits */ + while (icsk->icsk_accept_queue.rskq_defer_accept < 32 && + val > ((TCP_TIMEOUT_INIT / HZ) << + icsk->icsk_accept_queue.rskq_defer_accept)) + icsk->icsk_accept_queue.rskq_defer_accept++; + icsk->icsk_accept_queue.rskq_defer_accept++; } break; @@ -2299,7 +2302,8 @@ static int do_tcp_getsockopt(struct sock *sk, int level, val = (val ? : sysctl_tcp_fin_timeout) / HZ; break; case TCP_DEFER_ACCEPT: - val = icsk->icsk_accept_queue.rskq_defer_accept; + val = !icsk->icsk_accept_queue.rskq_defer_accept ? 0 : + ((TCP_TIMEOUT_INIT / HZ) << (icsk->icsk_accept_queue.rskq_defer_accept - 1)); break; case TCP_WINDOW_CLAMP: val = tp->window_clamp; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index eba873e9b560..cad73b7dfef0 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4541,49 +4541,6 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, struct tcphdr *th) } } -static int tcp_defer_accept_check(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (tp->defer_tcp_accept.request) { - int queued_data = tp->rcv_nxt - tp->copied_seq; - int hasfin = !skb_queue_empty(&sk->sk_receive_queue) ? - tcp_hdr((struct sk_buff *) - sk->sk_receive_queue.prev)->fin : 0; - - if (queued_data && hasfin) - queued_data--; - - if (queued_data && - tp->defer_tcp_accept.listen_sk->sk_state == TCP_LISTEN) { - if (sock_flag(sk, SOCK_KEEPOPEN)) { - inet_csk_reset_keepalive_timer(sk, - keepalive_time_when(tp)); - } else { - inet_csk_delete_keepalive_timer(sk); - } - - inet_csk_reqsk_queue_add( - tp->defer_tcp_accept.listen_sk, - tp->defer_tcp_accept.request, - sk); - - tp->defer_tcp_accept.listen_sk->sk_data_ready( - tp->defer_tcp_accept.listen_sk, 0); - - sock_put(tp->defer_tcp_accept.listen_sk); - sock_put(sk); - tp->defer_tcp_accept.listen_sk = NULL; - tp->defer_tcp_accept.request = NULL; - } else if (hasfin || - tp->defer_tcp_accept.listen_sk->sk_state != TCP_LISTEN) { - tcp_reset(sk); - return -1; - } - } - return 0; -} - static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen) { struct tcp_sock *tp = tcp_sk(sk); @@ -4944,8 +4901,6 @@ step5: tcp_data_snd_check(sk); tcp_ack_snd_check(sk); - - tcp_defer_accept_check(sk); return 0; csum_error: diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 4f8485c67d1a..97a230026e13 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1918,14 +1918,6 @@ int tcp_v4_destroy_sock(struct sock *sk) sk->sk_sndmsg_page = NULL; } - if (tp->defer_tcp_accept.request) { - reqsk_free(tp->defer_tcp_accept.request); - sock_put(tp->defer_tcp_accept.listen_sk); - sock_put(sk); - tp->defer_tcp_accept.listen_sk = NULL; - tp->defer_tcp_accept.request = NULL; - } - atomic_dec(&tcp_sockets_allocated); return 0; diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 019c8c16e5cc..8245247a6ceb 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -571,8 +571,10 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, does sequence test, SYN is truncated, and thus we consider it a bare ACK. - Both ends (listening sockets) accept the new incoming - connection and try to talk to each other. 8-) + If icsk->icsk_accept_queue.rskq_defer_accept, we silently drop this + bare ACK. Otherwise, we create an established connection. Both + ends (listening sockets) accept the new incoming connection and try + to talk to each other. 8-) Note: This case is both harmless, and rare. Possibility is about the same as us discovering intelligent life on another plant tomorrow. @@ -640,6 +642,13 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, if (!(flg & TCP_FLAG_ACK)) return NULL; + /* If TCP_DEFER_ACCEPT is set, drop bare ACK. */ + if (inet_csk(sk)->icsk_accept_queue.rskq_defer_accept && + TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) { + inet_rsk(req)->acked = 1; + return NULL; + } + /* OK, ACK is valid, create big socket and * feed this segment to it. It will repeat all * the tests. THIS SEGMENT MUST MOVE SOCKET TO @@ -678,24 +687,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, inet_csk_reqsk_queue_unlink(sk, req, prev); inet_csk_reqsk_queue_removed(sk, req); - if (inet_csk(sk)->icsk_accept_queue.rskq_defer_accept && - TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) { - - /* the accept queue handling is done is est recv slow - * path so lets make sure to start there - */ - tcp_sk(child)->pred_flags = 0; - sock_hold(sk); - sock_hold(child); - tcp_sk(child)->defer_tcp_accept.listen_sk = sk; - tcp_sk(child)->defer_tcp_accept.request = req; - - inet_csk_reset_keepalive_timer(child, - inet_csk(sk)->icsk_accept_queue.rskq_defer_accept * HZ); - } else { - inet_csk_reqsk_queue_add(sk, req, child); - } - + inet_csk_reqsk_queue_add(sk, req, child); return child; listen_overflow: diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 4de68cf5f2aa..63ed9d6830e7 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -489,11 +489,6 @@ static void tcp_keepalive_timer (unsigned long data) goto death; } - if (tp->defer_tcp_accept.request && sk->sk_state == TCP_ESTABLISHED) { - tcp_send_active_reset(sk, GFP_ATOMIC); - goto death; - } - if (!sock_flag(sk, SOCK_KEEPOPEN) || sk->sk_state == TCP_CLOSE) goto out; -- cgit v1.2.3 From df0bcab2c66ac876d5e80864fca5cce944a44540 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Thu, 12 Jun 2008 15:21:26 -0700 Subject: agp: add support for Radeon Mobility 9000 chipset Addresses https://bugs.edge.launchpad.net/ubuntu/+source/linux-source-2.6.22/+bug/178634 Signed-off-by: Amit Kucheria Signed-off-by: maximilian attems Acked-by: Dave Airlie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/agp/ati-agp.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 55c97f623242..07b4d8ff56e5 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -457,6 +457,10 @@ static struct agp_device_ids ati_agp_device_ids[] __devinitdata = .device_id = PCI_DEVICE_ID_ATI_RS300_200, .chipset_name = "IGP9100/M", }, + { + .device_id = PCI_DEVICE_ID_ATI_RS350_133, + .chipset_name = "IGP9000/M", + }, { .device_id = PCI_DEVICE_ID_ATI_RS350_200, .chipset_name = "IGP9100/M", -- cgit v1.2.3 From c700be3d1320d2be4f04c8a5330186b7df724438 Mon Sep 17 00:00:00 2001 From: "kosaki.motohiro@jp.fujitsu.com" Date: Thu, 12 Jun 2008 15:21:27 -0700 Subject: mm: fix incorrect variable type in do_try_to_free_pages() "Smarter retry of costly-order allocations" patch series change behaver of do_try_to_free_pages(). But unfortunately ret variable type was unchanged. Thus an overflow is possible. Signed-off-by: KOSAKI Motohiro Acked-by: Nishanth Aravamudan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/vmscan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 9a29901ad3b3..967d30ccd92b 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1307,7 +1307,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, struct scan_control *sc) { int priority; - int ret = 0; + unsigned long ret = 0; unsigned long total_scanned = 0; unsigned long nr_reclaimed = 0; struct reclaim_state *reclaim_state = current->reclaim_state; -- cgit v1.2.3 From 2d518f84e5ecd1d71df0e6ac5176d212f68c27ce Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Thu, 12 Jun 2008 15:21:28 -0700 Subject: fat: relax the permission check of fat_setattr() New chmod() allows only acceptable permission, and if not acceptable, it returns -EPERM. Old one allows even if it can't store permission to on disk inode. But it seems too strict for users. E.g. https://bugzilla.redhat.com/show_bug.cgi?id=449080: With new one, rsync couldn't create the temporary file. So, this patch allows like old one, but now it doesn't change the permission if it can't store, and it returns 0. Also, this patch fixes missing check. Signed-off-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/fat/file.c | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/fs/fat/file.c b/fs/fat/file.c index 27cc1164ec36..771326b8047e 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -257,26 +257,34 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) } EXPORT_SYMBOL_GPL(fat_getattr); -static int fat_check_mode(const struct msdos_sb_info *sbi, struct inode *inode, - mode_t mode) +static int fat_sanitize_mode(const struct msdos_sb_info *sbi, + struct inode *inode, umode_t *mode_ptr) { - mode_t mask, req = mode & ~S_IFMT; + mode_t mask, perm; - if (S_ISREG(mode)) + /* + * Note, the basic check is already done by a caller of + * (attr->ia_mode & ~MSDOS_VALID_MODE) + */ + + if (S_ISREG(inode->i_mode)) mask = sbi->options.fs_fmask; else mask = sbi->options.fs_dmask; + perm = *mode_ptr & ~(S_IFMT | mask); + /* * Of the r and x bits, all (subject to umask) must be present. Of the * w bits, either all (subject to umask) or none must be present. */ - req &= ~mask; - if ((req & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO))) + if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO))) return -EPERM; - if ((req & S_IWUGO) && ((req & S_IWUGO) != (S_IWUGO & ~mask))) + if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask))) return -EPERM; + *mode_ptr &= S_IFMT | perm; + return 0; } @@ -299,7 +307,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) { struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); struct inode *inode = dentry->d_inode; - int mask, error = 0; + int error = 0; unsigned int ia_valid; lock_kernel(); @@ -332,12 +340,13 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) error = 0; goto out; } + if (((attr->ia_valid & ATTR_UID) && (attr->ia_uid != sbi->options.fs_uid)) || ((attr->ia_valid & ATTR_GID) && (attr->ia_gid != sbi->options.fs_gid)) || ((attr->ia_valid & ATTR_MODE) && - fat_check_mode(sbi, inode, attr->ia_mode) < 0)) + (attr->ia_mode & ~MSDOS_VALID_MODE))) error = -EPERM; if (error) { @@ -346,15 +355,16 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) goto out; } - error = inode_setattr(inode, attr); - if (error) - goto out; + /* + * We don't return -EPERM here. Yes, strange, but this is too + * old behavior. + */ + if (attr->ia_valid & ATTR_MODE) { + if (fat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) + attr->ia_valid &= ~ATTR_MODE; + } - if (S_ISDIR(inode->i_mode)) - mask = sbi->options.fs_dmask; - else - mask = sbi->options.fs_fmask; - inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask); + error = inode_setattr(inode, attr); out: unlock_kernel(); return error; -- cgit v1.2.3 From 69c5ddf58a03da3686691ad2f293bc79fd977c10 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Thu, 12 Jun 2008 15:21:29 -0700 Subject: m68k: Add ext2_find_{first,next}_bit() for ext4 Add ext2_find_{first,next}_bit(), which are needed for ext4. They're derived out of the ext2_find_next_zero_bit found in the same file. Compile tested with crosstools [Reworked to preserve all symmetry with ext2_find_{first,next}_zero_bit()] This fixes http://bugzilla.kernel.org/show_bug.cgi?id=10393 [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-m68k/bitops.h | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/include/asm-m68k/bitops.h b/include/asm-m68k/bitops.h index 83d1f286230b..3e8106442d5a 100644 --- a/include/asm-m68k/bitops.h +++ b/include/asm-m68k/bitops.h @@ -410,8 +410,49 @@ static inline int ext2_find_next_zero_bit(const void *vaddr, unsigned size, res = ext2_find_first_zero_bit (p, size - 32 * (p - addr)); return (p - addr) * 32 + res; } -#define ext2_find_next_bit(addr, size, off) \ - generic_find_next_le_bit((unsigned long *)(addr), (size), (off)) + +static inline int ext2_find_first_bit(const void *vaddr, unsigned size) +{ + const unsigned long *p = vaddr, *addr = vaddr; + int res; + + if (!size) + return 0; + + size = (size >> 5) + ((size & 31) > 0); + while (*p++ == 0UL) { + if (--size == 0) + return (p - addr) << 5; + } + + --p; + for (res = 0; res < 32; res++) + if (ext2_test_bit(res, p)) + break; + return (p - addr) * 32 + res; +} + +static inline int ext2_find_next_bit(const void *vaddr, unsigned size, + unsigned offset) +{ + const unsigned long *addr = vaddr; + const unsigned long *p = addr + (offset >> 5); + int bit = offset & 31UL, res; + + if (offset >= size) + return size; + + if (bit) { + /* Look for one in first longword */ + for (res = bit; res < 32; res++) + if (ext2_test_bit(res, p)) + return (p - addr) * 32 + res; + p++; + } + /* No set bit yet, search remaining full bytes for a set bit */ + res = ext2_find_first_bit(p, size - 32 * (p - addr)); + return (p - addr) * 32 + res; +} #endif /* __KERNEL__ */ -- cgit v1.2.3 From 630c270183133ac25bef8c8d726ac448df9b169a Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Thu, 12 Jun 2008 15:21:29 -0700 Subject: hgafb: resource management fix Release ports which are requested during detection which are not freed if there is no hga card. Otherwise there is a crash during cat /proc/ioports command. Signed-off-by: Krzysztof Helt Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/hgafb.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c index fb9e67228543..c18880d9db1f 100644 --- a/drivers/video/hgafb.c +++ b/drivers/video/hgafb.c @@ -279,7 +279,7 @@ static void hga_blank(int blank_mode) static int __init hga_card_detect(void) { - int count=0; + int count = 0; void __iomem *p, *q; unsigned short p_save, q_save; @@ -303,20 +303,18 @@ static int __init hga_card_detect(void) writew(0x55aa, p); if (readw(p) == 0x55aa) count++; writew(p_save, p); - if (count != 2) { - return 0; - } + if (count != 2) + goto error; /* Ok, there is definitely a card registering at the correct * memory location, so now we do an I/O port test. */ - if (!test_hga_b(0x66, 0x0f)) { /* cursor low register */ - return 0; - } - if (!test_hga_b(0x99, 0x0f)) { /* cursor low register */ - return 0; - } + if (!test_hga_b(0x66, 0x0f)) /* cursor low register */ + goto error; + + if (!test_hga_b(0x99, 0x0f)) /* cursor low register */ + goto error; /* See if the card is a Hercules, by checking whether the vsync * bit of the status register is changing. This test lasts for @@ -331,7 +329,7 @@ static int __init hga_card_detect(void) } if (p_save == q_save) - return 0; + goto error; switch (inb_p(HGA_STATUS_PORT) & 0x70) { case 0x10: @@ -348,6 +346,12 @@ static int __init hga_card_detect(void) break; } return 1; +error: + if (release_io_ports) + release_region(0x3b0, 12); + if (release_io_port) + release_region(0x3bf, 1); + return 0; } /** -- cgit v1.2.3 From 551e172a20cf960f7caab4d31b252dc59538bfa4 Mon Sep 17 00:00:00 2001 From: Paul Jackson Date: Thu, 12 Jun 2008 15:21:31 -0700 Subject: cpusets: provide another web page URL in MAINTAINERS file Add URL for another CPUSETS web page to the MAINTAINERS file. This URL provides links to major LGPL user level C libraries supporting cpuset usage and user level cpu and node masks. Signed-off-by: Paul Jackson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 9d4304266043..9187bb014266 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1202,6 +1202,7 @@ M: pj@sgi.com M: menage@google.com L: linux-kernel@vger.kernel.org W: http://www.bullopensource.org/cpuset/ +W: http://oss.sgi.com/projects/cpusets/ S: Supported CRAMFS FILESYSTEM -- cgit v1.2.3 From 57d3c64fd8130ebdacd85a36c9656ba5e221f3a3 Mon Sep 17 00:00:00 2001 From: Ben Nizette Date: Thu, 12 Jun 2008 15:21:31 -0700 Subject: proc_fs.h: move struct mm_struct forward-declaration Move the forward-declaration of struct mm_struct a little way up proc_fs.h. This fixes a bunch of "'struct mm_struct' declared inside parameter list" warnings with CONFIG_PROC_FS=n Signed-off-by: Ben Nizette Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/proc_fs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 9883bc942262..fff1d27ddb4c 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -9,6 +9,8 @@ struct net; struct completion; +struct mm_struct; + /* * The proc filesystem constants/structures */ @@ -101,8 +103,6 @@ extern spinlock_t proc_subdir_lock; extern void proc_root_init(void); extern void proc_misc_init(void); -struct mm_struct; - void proc_flush_task(struct task_struct *task); struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *); int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir); -- cgit v1.2.3 From 8cdbc2b9826b3543fecff2f6d6400fa77b21ffdd Mon Sep 17 00:00:00 2001 From: "Andrew G. Morgan" Date: Thu, 12 Jun 2008 15:21:33 -0700 Subject: capabilities: add (back) dummy support for KEEPCAPS The dummy module is used by folk that run security conscious code(!?). A feature of such code (for example, dhclient) is that it tries to operate with minimum privilege (dropping unneeded capabilities). While the dummy module doesn't restrict code execution based on capability state, the user code expects the kernel to appear to support it. This patch adds back faked support for the PR_SET_KEEPCAPS etc., calls - making the kernel behave as before 2.6.26. For details see: http://bugzilla.kernel.org/show_bug.cgi?id=10748 Signed-off-by: Andrew G. Morgan Acked-by: Serge Hallyn Cc: James Morris Cc: Stephen Smalley Cc: Chris Wright Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- security/dummy.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/security/dummy.c b/security/dummy.c index f50c6c3c32c9..b8916883b77f 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include static int dummy_ptrace (struct task_struct *parent, struct task_struct *child) { @@ -607,7 +609,27 @@ static int dummy_task_kill (struct task_struct *p, struct siginfo *info, static int dummy_task_prctl (int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, long *rc_p) { - return 0; + switch (option) { + case PR_CAPBSET_READ: + *rc_p = (cap_valid(arg2) ? 1 : -EINVAL); + break; + case PR_GET_KEEPCAPS: + *rc_p = issecure(SECURE_KEEP_CAPS); + break; + case PR_SET_KEEPCAPS: + if (arg2 > 1) + *rc_p = -EINVAL; + else if (arg2) + current->securebits |= issecure_mask(SECURE_KEEP_CAPS); + else + current->securebits &= + ~issecure_mask(SECURE_KEEP_CAPS); + break; + default: + return 0; + } + + return 1; } static void dummy_task_reparent_to_init (struct task_struct *p) -- cgit v1.2.3 From 24aac480e76c6f5d1391ac05c5e9c0eb9b0cd302 Mon Sep 17 00:00:00 2001 From: Mike Miller Date: Thu, 12 Jun 2008 15:21:34 -0700 Subject: cciss: add new hardware support Add support for the next generation of HP Smart Array SAS/SATA controllers. Shipping date is late Fall 2008. Bump the driver version to 3.6.20 to reflect the new hardware support from patch 1 of this set. Signed-off-by: Mike Miller Cc: Jens Axboe Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/cciss.txt | 5 +++++ drivers/block/cciss.c | 21 ++++++++++++++++----- include/linux/pci_ids.h | 1 + 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt index e65736c6b8bc..63e59b8847c5 100644 --- a/Documentation/cciss.txt +++ b/Documentation/cciss.txt @@ -21,6 +21,11 @@ This driver is known to work with the following cards: * SA E200 * SA E200i * SA E500 + * SA P212 + * SA P410 + * SA P410i + * SA P411 + * SA P812 Detecting drive failures: ------------------------- diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index e336b05fe4a7..5f1e1cc6165a 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -53,15 +53,16 @@ #include #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "HP CISS Driver (v 3.6.14)" -#define DRIVER_VERSION CCISS_DRIVER_VERSION(3,6,14) +#define DRIVER_NAME "HP CISS Driver (v 3.6.20)" +#define DRIVER_VERSION CCISS_DRIVER_VERSION(3, 6, 20) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Hewlett-Packard Company"); -MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 3.6.14"); +MODULE_DESCRIPTION("Driver for HP Smart Array Controllers"); MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" - " SA6i P600 P800 P400 P400i E200 E200i E500"); -MODULE_VERSION("3.6.14"); + " SA6i P600 P800 P400 P400i E200 E200i E500 P700m" + " Smart Array G2 Series SAS/SATA Controllers"); +MODULE_VERSION("3.6.20"); MODULE_LICENSE("GPL"); #include "cciss_cmd.h" @@ -90,6 +91,11 @@ static const struct pci_device_id cciss_pci_device_id[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3215}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3237}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x323D}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3241}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3243}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3245}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3247}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249}, {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0}, {0,} @@ -123,6 +129,11 @@ static struct board_type products[] = { {0x3215103C, "Smart Array E200i", &SA5_access, 120}, {0x3237103C, "Smart Array E500", &SA5_access, 512}, {0x323D103C, "Smart Array P700m", &SA5_access, 512}, + {0x3241103C, "Smart Array P212", &SA5_access, 384}, + {0x3243103C, "Smart Array P410", &SA5_access, 384}, + {0x3245103C, "Smart Array P410i", &SA5_access, 384}, + {0x3247103C, "Smart Array P411", &SA5_access, 384}, + {0x3249103C, "Smart Array P812", &SA5_access, 384}, {0xFFFF103C, "Unknown Smart Array", &SA5_access, 120}, }; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 9b940e644179..eafc9d6d2b35 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -716,6 +716,7 @@ #define PCI_DEVICE_ID_HP_CISSA 0x3220 #define PCI_DEVICE_ID_HP_CISSC 0x3230 #define PCI_DEVICE_ID_HP_CISSD 0x3238 +#define PCI_DEVICE_ID_HP_CISSE 0x323a #define PCI_DEVICE_ID_HP_ZX2_IOC 0x4031 #define PCI_VENDOR_ID_PCTECH 0x1042 -- cgit v1.2.3 From 67dddaad5d8b8c5ee5b96a7e2f6cb0faad703865 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 12 Jun 2008 15:21:35 -0700 Subject: kprobes: fix error checking of batch registration Fix error checking routine to catch an error which occurs in first __register_*probe(). Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Jim Keniston Cc: David Miller Cc: Anil S Keshavamurthy Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/kprobes.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 1e0250cb9486..d4998f81e229 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -699,8 +699,9 @@ static int __register_kprobes(struct kprobe **kps, int num, return -EINVAL; for (i = 0; i < num; i++) { ret = __register_kprobe(kps[i], called_from); - if (ret < 0 && i > 0) { - unregister_kprobes(kps, i); + if (ret < 0) { + if (i > 0) + unregister_kprobes(kps, i); break; } } @@ -776,8 +777,9 @@ static int __register_jprobes(struct jprobe **jps, int num, jp->kp.break_handler = longjmp_break_handler; ret = __register_kprobe(&jp->kp, called_from); } - if (ret < 0 && i > 0) { - unregister_jprobes(jps, i); + if (ret < 0) { + if (i > 0) + unregister_jprobes(jps, i); break; } } @@ -920,8 +922,9 @@ static int __register_kretprobes(struct kretprobe **rps, int num, return -EINVAL; for (i = 0; i < num; i++) { ret = __register_kretprobe(rps[i], called_from); - if (ret < 0 && i > 0) { - unregister_kretprobes(rps, i); + if (ret < 0) { + if (i > 0) + unregister_kretprobes(rps, i); break; } } -- cgit v1.2.3 From 6c38d8578545482fe45d6e6ea37be02a2e1bb289 Mon Sep 17 00:00:00 2001 From: Philippe De Muyter Date: Thu, 12 Jun 2008 15:21:36 -0700 Subject: m68knommu: init coldfire timer TRR with n - 1, not n The coldfire timer must be initialised to n - 1 if we want it to count n cycles between each tick interrupt. This was already fixed, but has been lost with the conversion to GENERIC_TIMER. Signed-off-by: Philippe De Muyter Acked-by: Greg Ungerer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/m68knommu/platform/coldfire/timers.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/m68knommu/platform/coldfire/timers.c b/arch/m68knommu/platform/coldfire/timers.c index ba5a9f32ebd4..454f25493491 100644 --- a/arch/m68knommu/platform/coldfire/timers.c +++ b/arch/m68knommu/platform/coldfire/timers.c @@ -111,7 +111,13 @@ void hw_timer_init(void) __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR)); mcftmr_cycles_per_jiffy = FREQ / HZ; - __raw_writetrr(mcftmr_cycles_per_jiffy, TA(MCFTIMER_TRR)); + /* + * The coldfire timer runs from 0 to TRR included, then 0 + * again and so on. It counts thus actually TRR + 1 steps + * for 1 tick, not TRR. So if you want n cycles, + * initialize TRR with n - 1. + */ + __raw_writetrr(mcftmr_cycles_per_jiffy - 1, TA(MCFTIMER_TRR)); __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR)); -- cgit v1.2.3 From 529a4f4ec90ffd9394fdfc22bea7a858ae343171 Mon Sep 17 00:00:00 2001 From: Haavard Skinnemoen Date: Thu, 12 Jun 2008 15:21:38 -0700 Subject: rtc-at32ap700x: fix bug in at32_rtc_readalarm() alarm->pending indicates whether there's an alarm that has actually been triggered, not whether we're waiting for it. alarm->enabled indicates that. Also add missing locking around reading the RTC registers. Signed-off-by: Haavard Skinnemoen Signed-off-by: Alessandro Zummo Cc: Hans-Christian Egtvedt Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/rtc-at32ap700x.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c index 42244f14b41c..2ef8cdfda4a7 100644 --- a/drivers/rtc/rtc-at32ap700x.c +++ b/drivers/rtc/rtc-at32ap700x.c @@ -94,8 +94,11 @@ static int at32_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct rtc_at32ap700x *rtc = dev_get_drvdata(dev); + spin_lock_irq(&rtc->lock); rtc_time_to_tm(rtc->alarm_time, &alrm->time); - alrm->pending = rtc_readl(rtc, IMR) & RTC_BIT(IMR_TOPI) ? 1 : 0; + alrm->enabled = rtc_readl(rtc, IMR) & RTC_BIT(IMR_TOPI) ? 1 : 0; + alrm->pending = rtc_readl(rtc, ISR) & RTC_BIT(ISR_TOPI) ? 1 : 0; + spin_unlock_irq(&rtc->lock); return 0; } @@ -119,7 +122,7 @@ static int at32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) spin_lock_irq(&rtc->lock); rtc->alarm_time = alarm_unix_time; rtc_writel(rtc, TOP, rtc->alarm_time); - if (alrm->pending) + if (alrm->enabled) rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL) | RTC_BIT(CTRL_TOPEN)); else -- cgit v1.2.3 From 14c8a77e1bbd693446dad297d2ae2dd22f187e4f Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 12 Jun 2008 15:21:40 -0700 Subject: uml: remove include of asm/user.h I allowed an include of asm/user.h to sneak back in. This patch replaces it with sys/user.h. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/sys-i386/registers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c index b487cbead1bd..229f7a53d8da 100644 --- a/arch/um/os-Linux/sys-i386/registers.c +++ b/arch/um/os-Linux/sys-i386/registers.c @@ -6,7 +6,7 @@ #include #include -#include +#include #include "kern_constants.h" #include "longjmp.h" #include "user.h" @@ -76,7 +76,7 @@ int put_fp_registers(int pid, unsigned long *regs) void arch_init_registers(int pid) { - struct user_fxsr_struct fpx_regs; + struct user_fpxregs_struct fpx_regs; int err; err = ptrace(PTRACE_GETFPXREGS, pid, 0, &fpx_regs); -- cgit v1.2.3 From f1ef9167ca4494a8c6d71d0031c73e9c8841eadd Mon Sep 17 00:00:00 2001 From: Jeff Dike Date: Thu, 12 Jun 2008 15:21:41 -0700 Subject: uml: work around broken host PTRACE_SYSEMU Fedora broke PTRACE_SYSEMU again, and UML crashes as a result when it doesn't need to. This patch makes the PTRACE_SYSEMU check fail gracefully and makes UML fall back to PTRACE_SYSCALL. Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/os-Linux/start_up.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index b4b36e0f2e89..183db26d01bf 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -121,8 +121,10 @@ static int stop_ptraced_child(int pid, int exitcode, int mustexit) { int status, n, ret = 0; - if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) - fatal_perror("stop_ptraced_child : ptrace failed"); + if (ptrace(PTRACE_CONT, pid, 0, 0) < 0) { + perror("stop_ptraced_child : ptrace failed"); + return -1; + } CATCH_EINTR(n = waitpid(pid, &status, 0)); if (!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) { int exit_with = WEXITSTATUS(status); @@ -212,7 +214,7 @@ static void __init check_sysemu(void) if (n < 0) fatal_perror("check_sysemu : wait failed"); if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) - fatal("check_sysemu : expected SIGTRAP, got status = %d", + fatal("check_sysemu : expected SIGTRAP, got status = %d\n", status); if (ptrace(PTRACE_GETREGS, pid, 0, regs) < 0) @@ -254,9 +256,11 @@ static void __init check_sysemu(void) if (WIFSTOPPED(status) && (WSTOPSIG(status) == (SIGTRAP|0x80))) { - if (!count) - fatal("check_ptrace : SYSEMU_SINGLESTEP " - "doesn't singlestep"); + if (!count) { + non_fatal("check_ptrace : SYSEMU_SINGLESTEP " + "doesn't singlestep"); + goto fail; + } n = ptrace(PTRACE_POKEUSR, pid, PT_SYSCALL_RET_OFFSET, os_getpid()); if (n < 0) @@ -266,9 +270,12 @@ static void __init check_sysemu(void) } else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) count++; - else - fatal("check_ptrace : expected SIGTRAP or " - "(SIGTRAP | 0x80), got status = %d", status); + else { + non_fatal("check_ptrace : expected SIGTRAP or " + "(SIGTRAP | 0x80), got status = %d\n", + status); + goto fail; + } } if (stop_ptraced_child(pid, 0, 0) < 0) goto fail_stopped; -- cgit v1.2.3 From 30ec261e5f97986644c0982543bc1cee1b2782bf Mon Sep 17 00:00:00 2001 From: Eric Miao Date: Thu, 12 Jun 2008 15:21:41 -0700 Subject: MAINTAINERS: update maintainership of pxa2xx/pxa3xx Signed-off-by: Eric Miao Acked-by: Russell King Acked-by: Nicolas Pitre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 9187bb014266..88aac5f81e23 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3330,9 +3330,11 @@ L: video4linux-list@redhat.com W: http://www.isely.net/pvrusb2/ S: Maintained -PXA2xx SUPPORT -P: Nicolas Pitre -M: nico@cam.org +PXA2xx/PXA3xx SUPPORT +P: Eric Miao +M: eric.miao@marvell.com +P: Russell King +M: linux@arm.linux.org.uk L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) S: Maintained -- cgit v1.2.3 From cef33400d0349fb24b6f8b7dea79b66e3144fd8b Mon Sep 17 00:00:00 2001 From: Chuck Ebbert Date: Thu, 12 Jun 2008 15:21:42 -0700 Subject: mmc: wbsd: initialize tasklets before requesting interrupt With CONFIG_DEBUG_SHIRQ set we will get an interrupt as soon as we allocate one. Tasklets may be scheduled in the interrupt handler but they will be initialized after the handler returns, causing a BUG() in kernel/softirq.c when they run. Should fix this Fedora bug report: https://bugzilla.redhat.com/show_bug.cgi?id=449817 Signed-off-by: Chuck Ebbert Acked-by: Pierre Ossman Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/mmc/host/wbsd.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/mmc/host/wbsd.c b/drivers/mmc/host/wbsd.c index be624a049c67..c303e7f57ab4 100644 --- a/drivers/mmc/host/wbsd.c +++ b/drivers/mmc/host/wbsd.c @@ -1457,17 +1457,7 @@ static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq) int ret; /* - * Allocate interrupt. - */ - - ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host); - if (ret) - return ret; - - host->irq = irq; - - /* - * Set up tasklets. + * Set up tasklets. Must be done before requesting interrupt. */ tasklet_init(&host->card_tasklet, wbsd_tasklet_card, (unsigned long)host); @@ -1480,6 +1470,15 @@ static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq) tasklet_init(&host->finish_tasklet, wbsd_tasklet_finish, (unsigned long)host); + /* + * Allocate interrupt. + */ + ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host); + if (ret) + return ret; + + host->irq = irq; + return 0; } -- cgit v1.2.3 From 093a44e71aa29157fb1611b00507d67c954099d6 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 12 Jun 2008 15:21:43 -0700 Subject: drivers/isdn/sc/ioctl.c: add missing kfree spid has been allocated in this function and so should be freed before leaving it, as in the other error handling cases. The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) @r exists@ expression E,E1; statement S; position p1,p2,p3; @@ E =@p1 \(kmalloc\|kcalloc\|kzalloc\)(...) ... when != E = E1 if (E == NULL || ...) S ... when != E = E1 if@p2 (...) { ... when != kfree(E) } ... when != E = E1 kfree@p3(E); @forall@ position r.p2; expression r.E; int E1 != 0; @@ * if@p2 (...) { ... when != kfree(E) when strict return E1; } Signed-off-by: Julia Lawall Cc: Karsten Keil Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/isdn/sc/ioctl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c index 7817d2244921..1081091bbfaf 100644 --- a/drivers/isdn/sc/ioctl.c +++ b/drivers/isdn/sc/ioctl.c @@ -226,6 +226,7 @@ int sc_ioctl(int card, scs_ioctl *data) */ if (copy_from_user(spid, data->dataptr, SCIOC_SPIDSIZE)) { kfree(rcvmsg); + kfree(spid); return -EFAULT; } -- cgit v1.2.3 From c97aee9ba43d60ff20d955065d29b6d3d8c950d5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 12 Jun 2008 15:21:45 -0700 Subject: intel_rng: make device not found a warning Since many distros load this driver by default (throw it against the wall and see what sticks method). Change the error message severity level to avoid alarming users. Isn't it annoying when users actually read the error logs... Signed-off-by: Stephen Hemminger Cc: Michael Buesch Acked-by: Jan Beulich Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/hw_random/intel-rng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index 5cc651ef75eb..27fdc0866496 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c @@ -273,7 +273,7 @@ static int __init intel_rng_hw_init(void *_intel_rng_hw) if (mfc != INTEL_FWH_MANUFACTURER_CODE || (dvc != INTEL_FWH_DEVICE_CODE_8M && dvc != INTEL_FWH_DEVICE_CODE_4M)) { - printk(KERN_ERR PFX "FWH not detected\n"); + printk(KERN_NOTICE PFX "FWH not detected\n"); return -ENODEV; } -- cgit v1.2.3 From e59b6a5ab51f6192cbe20d4f031335fe6d0e73fd Mon Sep 17 00:00:00 2001 From: Philippe De Muyter Date: Thu, 12 Jun 2008 15:21:45 -0700 Subject: drivers/video/cirrusfb: fix RAM address printk In the cirrusfb driver, the RAM address printk has a superfluous 'x' that could be interpreted as "don't care", while it is actually a typo. Fix that. [akpm@linux-foundation.org: join the two printk strings to make it atomic] Signed-off-by: Philippe De Muyter Cc: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/cirrusfb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c index 35ac9d956b3d..c14b2435d23e 100644 --- a/drivers/video/cirrusfb.c +++ b/drivers/video/cirrusfb.c @@ -2432,9 +2432,9 @@ static int cirrusfb_pci_register(struct pci_dev *pdev, info->screen_size = board_size; cinfo->unmap = cirrusfb_pci_unmap; - printk(KERN_INFO " RAM (%lu kB) at 0xx%lx, ", - info->screen_size >> 10, board_addr); - printk(KERN_INFO "Cirrus Logic chipset on PCI bus\n"); + printk(KERN_INFO "RAM (%lu kB) at 0x%lx, Cirrus " + "Logic chipset on PCI bus\n", + info->screen_size >> 10, board_addr); pci_set_drvdata(pdev, info); ret = cirrusfb_register(info); -- cgit v1.2.3 From cfc53f65f56f9f33c0cf522124045ac5a64076b3 Mon Sep 17 00:00:00 2001 From: Philippe De Muyter Date: Thu, 12 Jun 2008 15:21:46 -0700 Subject: driver/char/generic_nvram: fix banner The generic nvram driver announces itself as 'Macintosh non-volatile memory driver' instead of 'Generic non-volatile memory driver'. Fix that. Signed-off-by: Philippe De Muyter Cc: Benjamin Herrenschmidt Cc: Arjan van de Ven Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/generic_nvram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c index 2398e864c28d..a00869c650d5 100644 --- a/drivers/char/generic_nvram.c +++ b/drivers/char/generic_nvram.c @@ -133,7 +133,7 @@ static struct miscdevice nvram_dev = { int __init nvram_init(void) { - printk(KERN_INFO "Macintosh non-volatile memory driver v%s\n", + printk(KERN_INFO "Generic non-volatile memory driver v%s\n", NVRAM_VERSION); return misc_register(&nvram_dev); } -- cgit v1.2.3 From 2165009bdf63f79716a36ad545df14c3cdf958b7 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 12 Jun 2008 15:21:47 -0700 Subject: pagemap: pass mm into pagewalkers We need this at least for huge page detection for now, because powerpc needs the vm_area_struct to be able to determine whether a virtual address is referring to a huge page (its pmd_huge() doesn't work). It might also come in handy for some of the other users. Signed-off-by: Dave Hansen Acked-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/task_mmu.c | 44 +++++++++++++++++++++++++------------------- include/linux/mm.h | 17 +++++++++-------- mm/pagewalk.c | 42 ++++++++++++++++++++++-------------------- 3 files changed, 56 insertions(+), 47 deletions(-) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 17403629e330..f0df3109343d 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -315,9 +315,9 @@ struct mem_size_stats { }; static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, - void *private) + struct mm_walk *walk) { - struct mem_size_stats *mss = private; + struct mem_size_stats *mss = walk->private; struct vm_area_struct *vma = mss->vma; pte_t *pte, ptent; spinlock_t *ptl; @@ -365,19 +365,21 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, return 0; } -static struct mm_walk smaps_walk = { .pmd_entry = smaps_pte_range }; - static int show_smap(struct seq_file *m, void *v) { struct vm_area_struct *vma = v; struct mem_size_stats mss; int ret; + struct mm_walk smaps_walk = { + .pmd_entry = smaps_pte_range, + .mm = vma->vm_mm, + .private = &mss, + }; memset(&mss, 0, sizeof mss); mss.vma = vma; if (vma->vm_mm && !is_vm_hugetlb_page(vma)) - walk_page_range(vma->vm_mm, vma->vm_start, vma->vm_end, - &smaps_walk, &mss); + walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); ret = show_map(m, v); if (ret) @@ -426,9 +428,9 @@ const struct file_operations proc_smaps_operations = { }; static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, - unsigned long end, void *private) + unsigned long end, struct mm_walk *walk) { - struct vm_area_struct *vma = private; + struct vm_area_struct *vma = walk->private; pte_t *pte, ptent; spinlock_t *ptl; struct page *page; @@ -452,8 +454,6 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, return 0; } -static struct mm_walk clear_refs_walk = { .pmd_entry = clear_refs_pte_range }; - static ssize_t clear_refs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { @@ -476,11 +476,17 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf, return -ESRCH; mm = get_task_mm(task); if (mm) { + static struct mm_walk clear_refs_walk; + memset(&clear_refs_walk, 0, sizeof(clear_refs_walk)); + clear_refs_walk.pmd_entry = clear_refs_pte_range; + clear_refs_walk.mm = mm; down_read(&mm->mmap_sem); - for (vma = mm->mmap; vma; vma = vma->vm_next) + for (vma = mm->mmap; vma; vma = vma->vm_next) { + clear_refs_walk.private = vma; if (!is_vm_hugetlb_page(vma)) - walk_page_range(mm, vma->vm_start, vma->vm_end, - &clear_refs_walk, vma); + walk_page_range(vma->vm_start, vma->vm_end, + &clear_refs_walk); + } flush_tlb_mm(mm); up_read(&mm->mmap_sem); mmput(mm); @@ -528,9 +534,9 @@ static int add_to_pagemap(unsigned long addr, u64 pfn, } static int pagemap_pte_hole(unsigned long start, unsigned long end, - void *private) + struct mm_walk *walk) { - struct pagemapread *pm = private; + struct pagemapread *pm = walk->private; unsigned long addr; int err = 0; for (addr = start; addr < end; addr += PAGE_SIZE) { @@ -548,9 +554,9 @@ static u64 swap_pte_to_pagemap_entry(pte_t pte) } static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, - void *private) + struct mm_walk *walk) { - struct pagemapread *pm = private; + struct pagemapread *pm = walk->private; pte_t *pte; int err = 0; @@ -675,8 +681,8 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, * user buffer is tracked in "pm", and the walk * will stop when we hit the end of the buffer. */ - ret = walk_page_range(mm, start_vaddr, end_vaddr, - &pagemap_walk, &pm); + ret = walk_page_range(start_vaddr, end_vaddr, + &pagemap_walk); if (ret == PM_END_OF_BUFFER) ret = 0; /* don't need mmap_sem for these, but this looks cleaner */ diff --git a/include/linux/mm.h b/include/linux/mm.h index c31a9cd2a30e..586a943cab01 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -760,16 +760,17 @@ unsigned long unmap_vmas(struct mmu_gather **tlb, * (see walk_page_range for more details) */ struct mm_walk { - int (*pgd_entry)(pgd_t *, unsigned long, unsigned long, void *); - int (*pud_entry)(pud_t *, unsigned long, unsigned long, void *); - int (*pmd_entry)(pmd_t *, unsigned long, unsigned long, void *); - int (*pte_entry)(pte_t *, unsigned long, unsigned long, void *); - int (*pte_hole)(unsigned long, unsigned long, void *); + int (*pgd_entry)(pgd_t *, unsigned long, unsigned long, struct mm_walk *); + int (*pud_entry)(pud_t *, unsigned long, unsigned long, struct mm_walk *); + int (*pmd_entry)(pmd_t *, unsigned long, unsigned long, struct mm_walk *); + int (*pte_entry)(pte_t *, unsigned long, unsigned long, struct mm_walk *); + int (*pte_hole)(unsigned long, unsigned long, struct mm_walk *); + struct mm_struct *mm; + void *private; }; -int walk_page_range(const struct mm_struct *, unsigned long addr, - unsigned long end, const struct mm_walk *walk, - void *private); +int walk_page_range(unsigned long addr, unsigned long end, + struct mm_walk *walk); void free_pgd_range(struct mmu_gather **tlb, unsigned long addr, unsigned long end, unsigned long floor, unsigned long ceiling); void free_pgtables(struct mmu_gather **tlb, struct vm_area_struct *start_vma, diff --git a/mm/pagewalk.c b/mm/pagewalk.c index 0afd2387e507..d5878bed7841 100644 --- a/mm/pagewalk.c +++ b/mm/pagewalk.c @@ -3,14 +3,14 @@ #include static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, - const struct mm_walk *walk, void *private) + struct mm_walk *walk) { pte_t *pte; int err = 0; pte = pte_offset_map(pmd, addr); for (;;) { - err = walk->pte_entry(pte, addr, addr + PAGE_SIZE, private); + err = walk->pte_entry(pte, addr, addr + PAGE_SIZE, walk); if (err) break; addr += PAGE_SIZE; @@ -24,7 +24,7 @@ static int walk_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, } static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end, - const struct mm_walk *walk, void *private) + struct mm_walk *walk) { pmd_t *pmd; unsigned long next; @@ -35,15 +35,15 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end, next = pmd_addr_end(addr, end); if (pmd_none_or_clear_bad(pmd)) { if (walk->pte_hole) - err = walk->pte_hole(addr, next, private); + err = walk->pte_hole(addr, next, walk); if (err) break; continue; } if (walk->pmd_entry) - err = walk->pmd_entry(pmd, addr, next, private); + err = walk->pmd_entry(pmd, addr, next, walk); if (!err && walk->pte_entry) - err = walk_pte_range(pmd, addr, next, walk, private); + err = walk_pte_range(pmd, addr, next, walk); if (err) break; } while (pmd++, addr = next, addr != end); @@ -52,7 +52,7 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end, } static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end, - const struct mm_walk *walk, void *private) + struct mm_walk *walk) { pud_t *pud; unsigned long next; @@ -63,15 +63,15 @@ static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end, next = pud_addr_end(addr, end); if (pud_none_or_clear_bad(pud)) { if (walk->pte_hole) - err = walk->pte_hole(addr, next, private); + err = walk->pte_hole(addr, next, walk); if (err) break; continue; } if (walk->pud_entry) - err = walk->pud_entry(pud, addr, next, private); + err = walk->pud_entry(pud, addr, next, walk); if (!err && (walk->pmd_entry || walk->pte_entry)) - err = walk_pmd_range(pud, addr, next, walk, private); + err = walk_pmd_range(pud, addr, next, walk); if (err) break; } while (pud++, addr = next, addr != end); @@ -85,15 +85,15 @@ static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end, * @addr: starting address * @end: ending address * @walk: set of callbacks to invoke for each level of the tree - * @private: private data passed to the callback function * * Recursively walk the page table for the memory area in a VMA, * calling supplied callbacks. Callbacks are called in-order (first * PGD, first PUD, first PMD, first PTE, second PTE... second PMD, * etc.). If lower-level callbacks are omitted, walking depth is reduced. * - * Each callback receives an entry pointer, the start and end of the - * associated range, and a caller-supplied private data pointer. + * Each callback receives an entry pointer and the start and end of the + * associated range, and a copy of the original mm_walk for access to + * the ->private or ->mm fields. * * No locks are taken, but the bottom level iterator will map PTE * directories from highmem if necessary. @@ -101,9 +101,8 @@ static int walk_pud_range(pgd_t *pgd, unsigned long addr, unsigned long end, * If any callback returns a non-zero value, the walk is aborted and * the return value is propagated back to the caller. Otherwise 0 is returned. */ -int walk_page_range(const struct mm_struct *mm, - unsigned long addr, unsigned long end, - const struct mm_walk *walk, void *private) +int walk_page_range(unsigned long addr, unsigned long end, + struct mm_walk *walk) { pgd_t *pgd; unsigned long next; @@ -112,21 +111,24 @@ int walk_page_range(const struct mm_struct *mm, if (addr >= end) return err; - pgd = pgd_offset(mm, addr); + if (!walk->mm) + return -EINVAL; + + pgd = pgd_offset(walk->mm, addr); do { next = pgd_addr_end(addr, end); if (pgd_none_or_clear_bad(pgd)) { if (walk->pte_hole) - err = walk->pte_hole(addr, next, private); + err = walk->pte_hole(addr, next, walk); if (err) break; continue; } if (walk->pgd_entry) - err = walk->pgd_entry(pgd, addr, next, private); + err = walk->pgd_entry(pgd, addr, next, walk); if (!err && (walk->pud_entry || walk->pmd_entry || walk->pte_entry)) - err = walk_pud_range(pgd, addr, next, walk, private); + err = walk_pud_range(pgd, addr, next, walk); if (err) break; } while (pgd++, addr = next, addr != end); -- cgit v1.2.3 From bcf8039ed45f56013c4afea5520bca7d909e5e61 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Thu, 12 Jun 2008 15:21:48 -0700 Subject: pagemap: fix large pages in pagemap We were walking right into huge page areas in the pagemap walker, and calling the pmds pmd_bad() and clearing them. That leaked huge pages. Bad. This patch at least works around that for now. It ignores huge pages in the pagemap walker for the time being, and won't leak those pages. Signed-off-by: Dave Hansen Acked-by: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/task_mmu.c | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index f0df3109343d..ab8ccc9d14ff 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -553,24 +553,45 @@ static u64 swap_pte_to_pagemap_entry(pte_t pte) return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT); } +static unsigned long pte_to_pagemap_entry(pte_t pte) +{ + unsigned long pme = 0; + if (is_swap_pte(pte)) + pme = PM_PFRAME(swap_pte_to_pagemap_entry(pte)) + | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP; + else if (pte_present(pte)) + pme = PM_PFRAME(pte_pfn(pte)) + | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT; + return pme; +} + static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, struct mm_walk *walk) { + struct vm_area_struct *vma; struct pagemapread *pm = walk->private; pte_t *pte; int err = 0; + /* find the first VMA at or above 'addr' */ + vma = find_vma(walk->mm, addr); for (; addr != end; addr += PAGE_SIZE) { u64 pfn = PM_NOT_PRESENT; - pte = pte_offset_map(pmd, addr); - if (is_swap_pte(*pte)) - pfn = PM_PFRAME(swap_pte_to_pagemap_entry(*pte)) - | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP; - else if (pte_present(*pte)) - pfn = PM_PFRAME(pte_pfn(*pte)) - | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT; - /* unmap so we're not in atomic when we copy to userspace */ - pte_unmap(pte); + + /* check to see if we've left 'vma' behind + * and need a new, higher one */ + if (vma && (addr >= vma->vm_end)) + vma = find_vma(walk->mm, addr); + + /* check that 'vma' actually covers this address, + * and that it isn't a huge page vma */ + if (vma && (vma->vm_start <= addr) && + !is_vm_hugetlb_page(vma)) { + pte = pte_offset_map(pmd, addr); + pfn = pte_to_pagemap_entry(*pte); + /* unmap before userspace copy */ + pte_unmap(pte); + } err = add_to_pagemap(addr, pfn, pm); if (err) return err; -- cgit v1.2.3 From 6c826818ff55eae7702b778b5f8bdf765af3b2af Mon Sep 17 00:00:00 2001 From: Paul Menage Date: Thu, 12 Jun 2008 15:21:49 -0700 Subject: /proc/sysvipc/shm: fix 32-bit truncation of segment sizes sysvipc_shm_proc_show() picks between format strings (based on the expected maximum length of a SHM segment) in a way that prevents gcc from performing format checks on the seq_printf() parameters. This hid two format errors - shp->shm_segsz and shp->shm_nattach are both unsigned long, but were being printed as unsigned int and signed int respectively. This leads to 32-bit truncation of SHM segment sizes reported in /proc/sysvipc/shm. (And for nattach, but that's less of a problem for most users). This patch makes the format string directly visible to gcc's format specifier checker, and fixes the two broken format specifiers. Signed-off-by: Paul Menage Cc: Nadia Derbey Cc: Manfred Spraul Cc: Pierre Peiffer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/shm.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ipc/shm.c b/ipc/shm.c index d05f6b564998..790240cd067f 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -1058,16 +1058,16 @@ asmlinkage long sys_shmdt(char __user *shmaddr) static int sysvipc_shm_proc_show(struct seq_file *s, void *it) { struct shmid_kernel *shp = it; - char *format; -#define SMALL_STRING "%10d %10d %4o %10u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n" -#define BIG_STRING "%10d %10d %4o %21u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n" +#if BITS_PER_LONG <= 32 +#define SIZE_SPEC "%10lu" +#else +#define SIZE_SPEC "%21lu" +#endif - if (sizeof(size_t) <= sizeof(int)) - format = SMALL_STRING; - else - format = BIG_STRING; - return seq_printf(s, format, + return seq_printf(s, + "%10d %10d %4o " SIZE_SPEC " %5u %5u " + "%5lu %5u %5u %5u %5u %10lu %10lu %10lu\n", shp->shm_perm.key, shp->shm_perm.id, shp->shm_perm.mode, -- cgit v1.2.3 From d2187ebd84c7dd13ef269e9600f4daebeb02816e Mon Sep 17 00:00:00 2001 From: Jiri Bohac Date: Thu, 12 Jun 2008 15:21:51 -0700 Subject: console keyboard mapping broken by 04c71976 Several console keyboard maps are broken since commit 04c71976500352d02f60616d2b960267d8c5fe24 Author: Samuel Thibault Date: Tue Oct 16 23:27:04 2007 -0700 unicode diacritics support because that changeset made k_self consider the value as a latin1 character when in Unicode mode, which is wrong; k_self should still take the console map into account. Signed-off-by: Samuel Thibault Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/keyboard.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 7f7e798c1384..d9a0a53c842d 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -677,12 +677,7 @@ static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag) static void k_self(struct vc_data *vc, unsigned char value, char up_flag) { - unsigned int uni; - if (kbd->kbdmode == VC_UNICODE) - uni = value; - else - uni = conv_8bit_to_uni(value); - k_unicode(vc, uni, up_flag); + k_unicode(vc, conv_8bit_to_uni(value), up_flag); } static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag) -- cgit v1.2.3 From 643b52b9c0b4e959436b4b551ebf4060d06d5ae8 Mon Sep 17 00:00:00 2001 From: Nick Piggin Date: Thu, 12 Jun 2008 15:21:52 -0700 Subject: radix-tree: fix small lockless radix-tree bug We shrink a radix tree when its root node has only one child, in the left most slot. The child becomes the new root node. To perform this operation in a manner compatible with concurrent lockless lookups, we atomically switch the root pointer from the parent to its child. However a concurrent lockless lookup may now have loaded a pointer to the parent (and is presently deciding what to do next). For this reason, we also have to keep the parent node in a valid state after shrinking the tree, until the next RCU grace period -- otherwise this lookup with the parent pointer may not do the right thing. Notably, we need to keep the child in the left most slot there in case that is requested by the lookup. This is all pretty standard RCU stuff. It is worth repeating because in my eagerness to obey the radix tree node constructor scheme, I had broken it by zeroing the radix tree node before the grace period. What could happen is that a lookup can load the parent pointer, then decide it wants to follow the left most child slot, only to find the slot contained NULL due to the concurrent shrinker having zeroed the parent node before waiting for a grace period. The lookup would return a false negative as a result. Fix it by doing that clearing in the RCU callback. I would normally want to rip out the constructor entirely, but radix tree nodes are one of those places where they make sense (only few cachelines will be touched soon after allocation). This was never actually found in any lockless pagecache testing or by the test harness, but by seeing the odd problem with my scalable vmap rewrite. I have not tickled the test harness into reproducing it yet, but I'll keep working at it. Fortunately, it is not a problem anywhere lockless pagecache is used in mainline kernels (pagecache probe is not a guarantee, and brd does not have concurrent lookups and deletes). Signed-off-by: Nick Piggin Acked-by: Peter Zijlstra Cc: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/radix-tree.c | 120 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 62 insertions(+), 58 deletions(-) diff --git a/lib/radix-tree.c b/lib/radix-tree.c index bd521716ab1a..169a2f8dabcc 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -88,6 +88,57 @@ static inline gfp_t root_gfp_mask(struct radix_tree_root *root) return root->gfp_mask & __GFP_BITS_MASK; } +static inline void tag_set(struct radix_tree_node *node, unsigned int tag, + int offset) +{ + __set_bit(offset, node->tags[tag]); +} + +static inline void tag_clear(struct radix_tree_node *node, unsigned int tag, + int offset) +{ + __clear_bit(offset, node->tags[tag]); +} + +static inline int tag_get(struct radix_tree_node *node, unsigned int tag, + int offset) +{ + return test_bit(offset, node->tags[tag]); +} + +static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag) +{ + root->gfp_mask |= (__force gfp_t)(1 << (tag + __GFP_BITS_SHIFT)); +} + +static inline void root_tag_clear(struct radix_tree_root *root, unsigned int tag) +{ + root->gfp_mask &= (__force gfp_t)~(1 << (tag + __GFP_BITS_SHIFT)); +} + +static inline void root_tag_clear_all(struct radix_tree_root *root) +{ + root->gfp_mask &= __GFP_BITS_MASK; +} + +static inline int root_tag_get(struct radix_tree_root *root, unsigned int tag) +{ + return (__force unsigned)root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT)); +} + +/* + * Returns 1 if any slot in the node has this tag set. + * Otherwise returns 0. + */ +static inline int any_tag_set(struct radix_tree_node *node, unsigned int tag) +{ + int idx; + for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { + if (node->tags[tag][idx]) + return 1; + } + return 0; +} /* * This assumes that the caller has performed appropriate preallocation, and * that the caller has pinned this thread of control to the current CPU. @@ -124,6 +175,17 @@ static void radix_tree_node_rcu_free(struct rcu_head *head) { struct radix_tree_node *node = container_of(head, struct radix_tree_node, rcu_head); + + /* + * must only free zeroed nodes into the slab. radix_tree_shrink + * can leave us with a non-NULL entry in the first slot, so clear + * that here to make sure. + */ + tag_clear(node, 0, 0); + tag_clear(node, 1, 0); + node->slots[0] = NULL; + node->count = 0; + kmem_cache_free(radix_tree_node_cachep, node); } @@ -165,59 +227,6 @@ out: } EXPORT_SYMBOL(radix_tree_preload); -static inline void tag_set(struct radix_tree_node *node, unsigned int tag, - int offset) -{ - __set_bit(offset, node->tags[tag]); -} - -static inline void tag_clear(struct radix_tree_node *node, unsigned int tag, - int offset) -{ - __clear_bit(offset, node->tags[tag]); -} - -static inline int tag_get(struct radix_tree_node *node, unsigned int tag, - int offset) -{ - return test_bit(offset, node->tags[tag]); -} - -static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag) -{ - root->gfp_mask |= (__force gfp_t)(1 << (tag + __GFP_BITS_SHIFT)); -} - - -static inline void root_tag_clear(struct radix_tree_root *root, unsigned int tag) -{ - root->gfp_mask &= (__force gfp_t)~(1 << (tag + __GFP_BITS_SHIFT)); -} - -static inline void root_tag_clear_all(struct radix_tree_root *root) -{ - root->gfp_mask &= __GFP_BITS_MASK; -} - -static inline int root_tag_get(struct radix_tree_root *root, unsigned int tag) -{ - return (__force unsigned)root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT)); -} - -/* - * Returns 1 if any slot in the node has this tag set. - * Otherwise returns 0. - */ -static inline int any_tag_set(struct radix_tree_node *node, unsigned int tag) -{ - int idx; - for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { - if (node->tags[tag][idx]) - return 1; - } - return 0; -} - /* * Return the maximum key which can be store into a * radix tree with height HEIGHT. @@ -930,11 +939,6 @@ static inline void radix_tree_shrink(struct radix_tree_root *root) newptr = radix_tree_ptr_to_indirect(newptr); root->rnode = newptr; root->height--; - /* must only free zeroed nodes into the slab */ - tag_clear(to_free, 0, 0); - tag_clear(to_free, 1, 0); - to_free->slots[0] = NULL; - to_free->count = 0; radix_tree_node_free(to_free); } } -- cgit v1.2.3 From 1da2e3d679a8ea2d9e82040359a706da0bd3bef6 Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Thu, 12 Jun 2008 15:21:54 -0700 Subject: provide rtc_cmos platform device Recently (around 2.6.25) I've noticed that RTC no longer works for me. It turned out this is because I use pnpacpi=off kernel option to work around the parport_pc bugs. I always did so, but RTC used to work fine in the past, and now it have regressed. The patch fixes the problem by creating the platform device for the RTC when PNP is disabled. This may also help running the PNP-enabled kernel on an older PCs. Signed-off-by: Stas Sergeev Cc: David Brownell Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Bjorn Helgaas Cc: Adam Belay Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/kernel/rtc.c | 34 ++++++++++++++++++++++++++++++++++ drivers/rtc/rtc-cmos.c | 31 ++++++++++++++++--------------- 2 files changed, 50 insertions(+), 15 deletions(-) diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c index 9615eee9b775..05191bbc68b8 100644 --- a/arch/x86/kernel/rtc.c +++ b/arch/x86/kernel/rtc.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include @@ -197,3 +199,35 @@ unsigned long long native_read_tsc(void) } EXPORT_SYMBOL(native_read_tsc); + +static struct resource rtc_resources[] = { + [0] = { + .start = RTC_PORT(0), + .end = RTC_PORT(1), + .flags = IORESOURCE_IO, + }, + [1] = { + .start = RTC_IRQ, + .end = RTC_IRQ, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device rtc_device = { + .name = "rtc_cmos", + .id = -1, + .resource = rtc_resources, + .num_resources = ARRAY_SIZE(rtc_resources), +}; + +static __init int add_rtc_cmos(void) +{ +#ifdef CONFIG_PNP + if (!pnp_platform_devices) + platform_device_register(&rtc_device); +#else + platform_device_register(&rtc_device); +#endif /* CONFIG_PNP */ + return 0; +} +device_initcall(add_rtc_cmos); diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index d060a06ce05b..d7bb9bac71df 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -905,19 +905,7 @@ static struct pnp_driver cmos_pnp_driver = { .resume = cmos_pnp_resume, }; -static int __init cmos_init(void) -{ - return pnp_register_driver(&cmos_pnp_driver); -} -module_init(cmos_init); - -static void __exit cmos_exit(void) -{ - pnp_unregister_driver(&cmos_pnp_driver); -} -module_exit(cmos_exit); - -#else /* no PNP */ +#endif /* CONFIG_PNP */ /*----------------------------------------------------------------*/ @@ -958,20 +946,33 @@ static struct platform_driver cmos_platform_driver = { static int __init cmos_init(void) { +#ifdef CONFIG_PNP + if (pnp_platform_devices) + return pnp_register_driver(&cmos_pnp_driver); + else + return platform_driver_probe(&cmos_platform_driver, + cmos_platform_probe); +#else return platform_driver_probe(&cmos_platform_driver, cmos_platform_probe); +#endif /* CONFIG_PNP */ } module_init(cmos_init); static void __exit cmos_exit(void) { +#ifdef CONFIG_PNP + if (pnp_platform_devices) + pnp_unregister_driver(&cmos_pnp_driver); + else + platform_driver_unregister(&cmos_platform_driver); +#else platform_driver_unregister(&cmos_platform_driver); +#endif /* CONFIG_PNP */ } module_exit(cmos_exit); -#endif /* !PNP */ - MODULE_AUTHOR("David Brownell"); MODULE_DESCRIPTION("Driver for PC-style 'CMOS' RTCs"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e6d2bb2bacb43ff03b0f458108d71981d58e775a Mon Sep 17 00:00:00 2001 From: David Brownell Date: Thu, 12 Jun 2008 15:21:55 -0700 Subject: rtc: make HPET_RTC_IRQ track HPET_EMULATE_RTC More Kconfig tweaks related to the legacy PC RTC code: - Describe the legacy PC RTC driver as such ... it's never quite been clear that this driver is for PC RTCs, and now it's fair to call this the "legacy" driver. - Force it to understand about HPET stealing its IRQs ... kernel code does this always when HPET is in use, there should be no option for users to goof up the config. This seems to fix kernel bugzilla #10729. Signed-off-by: David Brownell Cc: Maxim Levitsky Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index d307bf26af58..2d854bb9373e 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -749,7 +749,7 @@ config NVRAM if RTC_LIB=n config RTC - tristate "Enhanced Real Time Clock Support" + tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)" depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV \ && !ARM && !SUPERH && !S390 && !AVR32 ---help--- @@ -1036,9 +1036,9 @@ config HPET non-periodic and/or periodic. config HPET_RTC_IRQ - bool "HPET Control RTC IRQ" if !HPET_EMULATE_RTC - default n - depends on HPET + bool + default HPET_EMULATE_RTC + depends on RTC && HPET help If you say Y here, you will disable RTC_IRQ in drivers/char/rtc.c. It is assumed the platform called hpet_alloc with the RTC IRQ values for -- cgit v1.2.3 From c6d8f400cc7610f04177f81168c19b8407cb48c3 Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Thu, 12 Jun 2008 15:21:55 -0700 Subject: rtc: Ramtron FM3130 RTC support Ramtron FM3130 is a chip with two separate devices inside, RTC clock and FRAM. This driver provides only RTC functionality. This chip is met in lots of custom boards with AT91SAMXXXX CPU I work with, is cheap and in no way better or worse than any other RTC on market. While it is mostly met on much smaller devices, I think it is great to have it supported in Linux. Signed-off-by: Sergey Lapin Signed-off-by: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/rtc/Kconfig | 11 ++ drivers/rtc/Makefile | 3 +- drivers/rtc/rtc-fm3130.c | 501 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 514 insertions(+), 1 deletion(-) create mode 100644 drivers/rtc/rtc-fm3130.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 60f8afc7a56e..4949dc4859be 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -256,6 +256,17 @@ config RTC_DRV_S35390A This driver can also be built as a module. If so the module will be called rtc-s35390a. +config RTC_DRV_FM3130 + tristate "Ramtron FM3130" + help + If you say Y here you will get support for the + Ramtron FM3130 RTC chips. + Ramtron FM3130 is a chip with two separate devices inside, + RTC clock and FRAM. This driver provides only RTC functionality. + + This driver can also be built as a module. If so the module + will be called rtc-fm3130. + endif # I2C comment "SPI RTC drivers" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index ebe871cf16c1..b6e14d51670b 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o +obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o @@ -41,6 +42,7 @@ obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o +obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o @@ -54,4 +56,3 @@ obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o -obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c new file mode 100644 index 000000000000..11644c8fca82 --- /dev/null +++ b/drivers/rtc/rtc-fm3130.c @@ -0,0 +1,501 @@ +/* + * rtc-fm3130.c - RTC driver for Ramtron FM3130 I2C chip. + * + * Copyright (C) 2008 Sergey Lapin + * Based on ds1307 driver by James Chapman and David Brownell + * + * 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 + +#define FM3130_RTC_CONTROL (0x0) +#define FM3130_CAL_CONTROL (0x1) +#define FM3130_RTC_SECONDS (0x2) +#define FM3130_RTC_MINUTES (0x3) +#define FM3130_RTC_HOURS (0x4) +#define FM3130_RTC_DAY (0x5) +#define FM3130_RTC_DATE (0x6) +#define FM3130_RTC_MONTHS (0x7) +#define FM3130_RTC_YEARS (0x8) + +#define FM3130_ALARM_SECONDS (0x9) +#define FM3130_ALARM_MINUTES (0xa) +#define FM3130_ALARM_HOURS (0xb) +#define FM3130_ALARM_DATE (0xc) +#define FM3130_ALARM_MONTHS (0xd) +#define FM3130_ALARM_WP_CONTROL (0xe) + +#define FM3130_CAL_CONTROL_BIT_nOSCEN (1 << 7) /* Osciallator enabled */ +#define FM3130_RTC_CONTROL_BIT_LB (1 << 7) /* Low battery */ +#define FM3130_RTC_CONTROL_BIT_AF (1 << 6) /* Alarm flag */ +#define FM3130_RTC_CONTROL_BIT_CF (1 << 5) /* Century overflow */ +#define FM3130_RTC_CONTROL_BIT_POR (1 << 4) /* Power on reset */ +#define FM3130_RTC_CONTROL_BIT_AEN (1 << 3) /* Alarm enable */ +#define FM3130_RTC_CONTROL_BIT_CAL (1 << 2) /* Calibration mode */ +#define FM3130_RTC_CONTROL_BIT_WRITE (1 << 1) /* W=1 -> write mode W=0 normal */ +#define FM3130_RTC_CONTROL_BIT_READ (1 << 0) /* R=1 -> read mode R=0 normal */ + +#define FM3130_CLOCK_REGS 7 +#define FM3130_ALARM_REGS 5 + +struct fm3130 { + u8 reg_addr_time; + u8 reg_addr_alarm; + u8 regs[15]; + struct i2c_msg msg[4]; + struct i2c_client *client; + struct rtc_device *rtc; + int data_valid; + int alarm; +}; +static const struct i2c_device_id fm3130_id[] = { + { "fm3130-rtc", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, fm3130_id); + +#define FM3130_MODE_NORMAL 0 +#define FM3130_MODE_WRITE 1 +#define FM3130_MODE_READ 2 + +static void fm3130_rtc_mode(struct device *dev, int mode) +{ + struct fm3130 *fm3130 = dev_get_drvdata(dev); + + fm3130->regs[FM3130_RTC_CONTROL] = + i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL); + switch (mode) { + case FM3130_MODE_NORMAL: + fm3130->regs[FM3130_RTC_CONTROL] &= + ~(FM3130_RTC_CONTROL_BIT_WRITE | + FM3130_RTC_CONTROL_BIT_READ); + break; + case FM3130_MODE_WRITE: + fm3130->regs[FM3130_RTC_CONTROL] |= FM3130_RTC_CONTROL_BIT_WRITE; + break; + case FM3130_MODE_READ: + fm3130->regs[FM3130_RTC_CONTROL] |= FM3130_RTC_CONTROL_BIT_READ; + break; + default: + dev_dbg(dev, "invalid mode %d\n", mode); + break; + } + /* Checking for alarm */ + if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { + fm3130->alarm = 1; + fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; + } + i2c_smbus_write_byte_data(fm3130->client, + FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL]); +} + +static int fm3130_get_time(struct device *dev, struct rtc_time *t) +{ + struct fm3130 *fm3130 = dev_get_drvdata(dev); + int tmp; + + if (!fm3130->data_valid) { + /* We have invalid data in RTC, probably due + to battery faults or other problems. Return EIO + for now, it will allow us to set data later insted + of error during probing which disables device */ + return -EIO; + } + fm3130_rtc_mode(dev, FM3130_MODE_READ); + + /* read the RTC date and time registers all at once */ + tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent), + fm3130->msg, 2); + if (tmp != 2) { + dev_err(dev, "%s error %d\n", "read", tmp); + return -EIO; + } + + fm3130_rtc_mode(dev, FM3130_MODE_NORMAL); + + dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x" + "%02x %02x %02x %02x %02x %02x %02x\n", + "read", + fm3130->regs[0], fm3130->regs[1], + fm3130->regs[2], fm3130->regs[3], + fm3130->regs[4], fm3130->regs[5], + fm3130->regs[6], fm3130->regs[7], + fm3130->regs[8], fm3130->regs[9], + fm3130->regs[0xa], fm3130->regs[0xb], + fm3130->regs[0xc], fm3130->regs[0xd], + fm3130->regs[0xe]); + + t->tm_sec = BCD2BIN(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f); + t->tm_min = BCD2BIN(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); + tmp = fm3130->regs[FM3130_RTC_HOURS] & 0x3f; + t->tm_hour = BCD2BIN(tmp); + t->tm_wday = BCD2BIN(fm3130->regs[FM3130_RTC_DAY] & 0x07) - 1; + t->tm_mday = BCD2BIN(fm3130->regs[FM3130_RTC_DATE] & 0x3f); + tmp = fm3130->regs[FM3130_RTC_MONTHS] & 0x1f; + t->tm_mon = BCD2BIN(tmp) - 1; + + /* assume 20YY not 19YY, and ignore CF bit */ + t->tm_year = BCD2BIN(fm3130->regs[FM3130_RTC_YEARS]) + 100; + + dev_dbg(dev, "%s secs=%d, mins=%d, " + "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", + "read", t->tm_sec, t->tm_min, + t->tm_hour, t->tm_mday, + t->tm_mon, t->tm_year, t->tm_wday); + + /* initial clock setting can be undefined */ + return rtc_valid_tm(t); +} + + +static int fm3130_set_time(struct device *dev, struct rtc_time *t) +{ + struct fm3130 *fm3130 = dev_get_drvdata(dev); + int tmp, i; + u8 *buf = fm3130->regs; + + dev_dbg(dev, "%s secs=%d, mins=%d, " + "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", + "write", t->tm_sec, t->tm_min, + t->tm_hour, t->tm_mday, + t->tm_mon, t->tm_year, t->tm_wday); + + /* first register addr */ + buf[FM3130_RTC_SECONDS] = BIN2BCD(t->tm_sec); + buf[FM3130_RTC_MINUTES] = BIN2BCD(t->tm_min); + buf[FM3130_RTC_HOURS] = BIN2BCD(t->tm_hour); + buf[FM3130_RTC_DAY] = BIN2BCD(t->tm_wday + 1); + buf[FM3130_RTC_DATE] = BIN2BCD(t->tm_mday); + buf[FM3130_RTC_MONTHS] = BIN2BCD(t->tm_mon + 1); + + /* assume 20YY not 19YY */ + tmp = t->tm_year - 100; + buf[FM3130_RTC_YEARS] = BIN2BCD(tmp); + + dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x" + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + "write", buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7], + buf[8], buf[9], buf[0xa], buf[0xb], + buf[0xc], buf[0xd], buf[0xe]); + + fm3130_rtc_mode(dev, FM3130_MODE_WRITE); + + /* Writing time registers, we don't support multibyte transfers */ + for (i = 0; i < FM3130_CLOCK_REGS; i++) { + i2c_smbus_write_byte_data(fm3130->client, + FM3130_RTC_SECONDS + i, + fm3130->regs[FM3130_RTC_SECONDS + i]); + } + + fm3130_rtc_mode(dev, FM3130_MODE_NORMAL); + + /* We assume here that data are valid once written */ + if (!fm3130->data_valid) + fm3130->data_valid = 1; + return 0; +} + +static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct fm3130 *fm3130 = dev_get_drvdata(dev); + int tmp; + struct rtc_time *tm = &alrm->time; + /* read the RTC alarm registers all at once */ + tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent), + &fm3130->msg[2], 2); + if (tmp != 2) { + dev_err(dev, "%s error %d\n", "read", tmp); + return -EIO; + } + dev_dbg(dev, "alarm read %02x %02x %02x %02x %02x\n", + fm3130->regs[FM3130_ALARM_SECONDS], + fm3130->regs[FM3130_ALARM_MINUTES], + fm3130->regs[FM3130_ALARM_HOURS], + fm3130->regs[FM3130_ALARM_DATE], + fm3130->regs[FM3130_ALARM_MONTHS]); + + + tm->tm_sec = BCD2BIN(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F); + tm->tm_min = BCD2BIN(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F); + tm->tm_hour = BCD2BIN(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F); + tm->tm_mday = BCD2BIN(fm3130->regs[FM3130_ALARM_DATE] & 0x3F); + tm->tm_mon = BCD2BIN(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F); + if (tm->tm_mon > 0) + tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */ + dev_dbg(dev, "%s secs=%d, mins=%d, " + "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", + "read alarm", tm->tm_sec, tm->tm_min, + tm->tm_hour, tm->tm_mday, + tm->tm_mon, tm->tm_year, tm->tm_wday); + + return 0; +} + +static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct fm3130 *fm3130 = dev_get_drvdata(dev); + struct rtc_time *tm = &alrm->time; + int i; + + dev_dbg(dev, "%s secs=%d, mins=%d, " + "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", + "write alarm", tm->tm_sec, tm->tm_min, + tm->tm_hour, tm->tm_mday, + tm->tm_mon, tm->tm_year, tm->tm_wday); + + if (tm->tm_sec != -1) + fm3130->regs[FM3130_ALARM_SECONDS] = + BIN2BCD(tm->tm_sec) | 0x80; + + if (tm->tm_min != -1) + fm3130->regs[FM3130_ALARM_MINUTES] = + BIN2BCD(tm->tm_min) | 0x80; + + if (tm->tm_hour != -1) + fm3130->regs[FM3130_ALARM_HOURS] = + BIN2BCD(tm->tm_hour) | 0x80; + + if (tm->tm_mday != -1) + fm3130->regs[FM3130_ALARM_DATE] = + BIN2BCD(tm->tm_mday) | 0x80; + + if (tm->tm_mon != -1) + fm3130->regs[FM3130_ALARM_MONTHS] = + BIN2BCD(tm->tm_mon + 1) | 0x80; + + dev_dbg(dev, "alarm write %02x %02x %02x %02x %02x\n", + fm3130->regs[FM3130_ALARM_SECONDS], + fm3130->regs[FM3130_ALARM_MINUTES], + fm3130->regs[FM3130_ALARM_HOURS], + fm3130->regs[FM3130_ALARM_DATE], + fm3130->regs[FM3130_ALARM_MONTHS]); + /* Writing time registers, we don't support multibyte transfers */ + for (i = 0; i < FM3130_ALARM_REGS; i++) { + i2c_smbus_write_byte_data(fm3130->client, + FM3130_ALARM_SECONDS + i, + fm3130->regs[FM3130_ALARM_SECONDS + i]); + } + fm3130->regs[FM3130_RTC_CONTROL] = + i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL); + /* Checking for alarm */ + if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { + fm3130->alarm = 1; + fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; + } + if (alrm->enabled) { + i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, + (fm3130->regs[FM3130_RTC_CONTROL] & + ~(FM3130_RTC_CONTROL_BIT_CAL)) | + FM3130_RTC_CONTROL_BIT_AEN); + } else { + i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL, + fm3130->regs[FM3130_RTC_CONTROL] & + ~(FM3130_RTC_CONTROL_BIT_AEN)); + } + return 0; +} + +static const struct rtc_class_ops fm3130_rtc_ops = { + .read_time = fm3130_get_time, + .set_time = fm3130_set_time, + .read_alarm = fm3130_read_alarm, + .set_alarm = fm3130_set_alarm, +}; + +static struct i2c_driver fm3130_driver; + +static int __devinit fm3130_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct fm3130 *fm3130; + int err = -ENODEV; + int tmp; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + + if (!i2c_check_functionality(adapter, + I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) + return -EIO; + + fm3130 = kzalloc(sizeof(struct fm3130), GFP_KERNEL); + + if (!fm3130) + return -ENOMEM; + + fm3130->client = client; + i2c_set_clientdata(client, fm3130); + fm3130->reg_addr_time = FM3130_RTC_SECONDS; + fm3130->reg_addr_alarm = FM3130_ALARM_SECONDS; + + /* Messages to read time */ + fm3130->msg[0].addr = client->addr; + fm3130->msg[0].flags = 0; + fm3130->msg[0].len = 1; + fm3130->msg[0].buf = &fm3130->reg_addr_time; + + fm3130->msg[1].addr = client->addr; + fm3130->msg[1].flags = I2C_M_RD; + fm3130->msg[1].len = FM3130_CLOCK_REGS; + fm3130->msg[1].buf = &fm3130->regs[FM3130_RTC_SECONDS]; + + /* Messages to read alarm */ + fm3130->msg[2].addr = client->addr; + fm3130->msg[2].flags = 0; + fm3130->msg[2].len = 1; + fm3130->msg[2].buf = &fm3130->reg_addr_alarm; + + fm3130->msg[3].addr = client->addr; + fm3130->msg[3].flags = I2C_M_RD; + fm3130->msg[3].len = FM3130_ALARM_REGS; + fm3130->msg[3].buf = &fm3130->regs[FM3130_ALARM_SECONDS]; + + fm3130->data_valid = 0; + + tmp = i2c_transfer(adapter, fm3130->msg, 4); + if (tmp != 4) { + pr_debug("read error %d\n", tmp); + err = -EIO; + goto exit_free; + } + + fm3130->regs[FM3130_RTC_CONTROL] = + i2c_smbus_read_byte_data(client, FM3130_RTC_CONTROL); + fm3130->regs[FM3130_CAL_CONTROL] = + i2c_smbus_read_byte_data(client, FM3130_CAL_CONTROL); + + /* Checking for alarm */ + if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) { + fm3130->alarm = 1; + fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF; + } + + /* Disabling calibration mode */ + if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL) + i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, + fm3130->regs[FM3130_RTC_CONTROL] & + ~(FM3130_RTC_CONTROL_BIT_CAL)); + dev_warn(&client->dev, "Disabling calibration mode!\n"); + + /* Disabling read and write modes */ + if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_WRITE || + fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_READ) + i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, + fm3130->regs[FM3130_RTC_CONTROL] & + ~(FM3130_RTC_CONTROL_BIT_READ | + FM3130_RTC_CONTROL_BIT_WRITE)); + dev_warn(&client->dev, "Disabling READ or WRITE mode!\n"); + + /* oscillator off? turn it on, so clock can tick. */ + if (fm3130->regs[FM3130_CAL_CONTROL] & FM3130_CAL_CONTROL_BIT_nOSCEN) + i2c_smbus_write_byte_data(client, FM3130_CAL_CONTROL, + fm3130->regs[FM3130_CAL_CONTROL] & + ~(FM3130_CAL_CONTROL_BIT_nOSCEN)); + + /* oscillator fault? clear flag, and warn */ + if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_LB) + dev_warn(&client->dev, "Low battery!\n"); + + /* oscillator fault? clear flag, and warn */ + if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_POR) { + i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL, + fm3130->regs[FM3130_RTC_CONTROL] & + ~FM3130_RTC_CONTROL_BIT_POR); + dev_warn(&client->dev, "SET TIME!\n"); + } + /* ACS is controlled by alarm */ + i2c_smbus_write_byte_data(client, FM3130_ALARM_WP_CONTROL, 0x80); + + /* TODO */ + /* TODO need to sanity check alarm */ + tmp = fm3130->regs[FM3130_RTC_SECONDS]; + tmp = BCD2BIN(tmp & 0x7f); + if (tmp > 60) + goto exit_bad; + tmp = BCD2BIN(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f); + if (tmp > 60) + goto exit_bad; + + tmp = BCD2BIN(fm3130->regs[FM3130_RTC_DATE] & 0x3f); + if (tmp == 0 || tmp > 31) + goto exit_bad; + + tmp = BCD2BIN(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f); + if (tmp == 0 || tmp > 12) + goto exit_bad; + + tmp = fm3130->regs[FM3130_RTC_HOURS]; + + fm3130->data_valid = 1; + +exit_bad: + if (!fm3130->data_valid) + dev_dbg(&client->dev, + "%s: %02x %02x %02x %02x %02x %02x %02x %02x" + "%02x %02x %02x %02x %02x %02x %02x\n", + "bogus registers", + fm3130->regs[0], fm3130->regs[1], + fm3130->regs[2], fm3130->regs[3], + fm3130->regs[4], fm3130->regs[5], + fm3130->regs[6], fm3130->regs[7], + fm3130->regs[8], fm3130->regs[9], + fm3130->regs[0xa], fm3130->regs[0xb], + fm3130->regs[0xc], fm3130->regs[0xd], + fm3130->regs[0xe]); + + /* We won't bail out here because we just got invalid data. + Time setting from u-boot doesn't work anyway */ + fm3130->rtc = rtc_device_register(client->name, &client->dev, + &fm3130_rtc_ops, THIS_MODULE); + if (IS_ERR(fm3130->rtc)) { + err = PTR_ERR(fm3130->rtc); + dev_err(&client->dev, + "unable to register the class device\n"); + goto exit_free; + } + return 0; +exit_free: + kfree(fm3130); + return err; +} + +static int __devexit fm3130_remove(struct i2c_client *client) +{ + struct fm3130 *fm3130 = i2c_get_clientdata(client); + + rtc_device_unregister(fm3130->rtc); + kfree(fm3130); + return 0; +} + +static struct i2c_driver fm3130_driver = { + .driver = { + .name = "rtc-fm3130", + .owner = THIS_MODULE, + }, + .probe = fm3130_probe, + .remove = __devexit_p(fm3130_remove), + .id_table = fm3130_id, +}; + +static int __init fm3130_init(void) +{ + return i2c_add_driver(&fm3130_driver); +} +module_init(fm3130_init); + +static void __exit fm3130_exit(void) +{ + i2c_del_driver(&fm3130_driver); +} +module_exit(fm3130_exit); + +MODULE_DESCRIPTION("RTC driver for FM3130"); +MODULE_AUTHOR("Sergey Lapin "); +MODULE_LICENSE("GPL"); + -- cgit v1.2.3 From e297d99e103f951a71fcb1534f1ff3480dd3a851 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 10 Jun 2008 00:13:04 +0900 Subject: ahci: workarounds for mcp65 MCP65 ahci can do NCQ but doesn't set the CAP bit and rev A0 and A1 can't do MSI but have MSI capability. Implement AHCI_HFLAG_YES_NCQ and apply appropriate workarounds. Signed-off-by: Tejun Heo Cc: Peer Chen Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 544b7d6c617c..1c62b8e39645 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -89,6 +89,7 @@ enum { board_ahci_sb600 = 3, board_ahci_mv = 4, board_ahci_sb700 = 5, + board_ahci_mcp65 = 6, /* global controller registers */ HOST_CAP = 0x00, /* host capabilities */ @@ -190,6 +191,7 @@ enum { AHCI_HFLAG_NO_PMP = (1 << 6), /* no PMP */ AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */ AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */ + AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */ /* ap->flags bits */ @@ -384,6 +386,14 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, + /* board_ahci_mcp65 */ + { + AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ), + .flags = AHCI_FLAG_COMMON, + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, }; static const struct pci_device_id ahci_pci_tbl[] = { @@ -438,14 +448,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(VIA, 0x6287), board_ahci_vt8251 }, /* VIA VT8251 */ /* NVIDIA */ - { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci }, /* MCP65 */ - { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci_mcp65 }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci_mcp65 }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci_mcp65 }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci_mcp65 }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045c), board_ahci_mcp65 }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045d), board_ahci_mcp65 }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045e), board_ahci_mcp65 }, /* MCP65 */ + { PCI_VDEVICE(NVIDIA, 0x045f), board_ahci_mcp65 }, /* MCP65 */ { PCI_VDEVICE(NVIDIA, 0x0550), board_ahci }, /* MCP67 */ { PCI_VDEVICE(NVIDIA, 0x0551), board_ahci }, /* MCP67 */ { PCI_VDEVICE(NVIDIA, 0x0552), board_ahci }, /* MCP67 */ @@ -624,6 +634,12 @@ static void ahci_save_initial_config(struct pci_dev *pdev, cap &= ~HOST_CAP_NCQ; } + if (!(cap & HOST_CAP_NCQ) && (hpriv->flags & AHCI_HFLAG_YES_NCQ)) { + dev_printk(KERN_INFO, &pdev->dev, + "controller can do NCQ, turning on CAP_NCQ\n"); + cap |= HOST_CAP_NCQ; + } + if ((cap & HOST_CAP_PMP) && (hpriv->flags & AHCI_HFLAG_NO_PMP)) { dev_printk(KERN_INFO, &pdev->dev, "controller can't do PMP, turning off CAP_PMP\n"); @@ -2118,7 +2134,8 @@ static void ahci_p5wdh_workaround(struct ata_host *host) static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int printed_version; - struct ata_port_info pi = ahci_port_info[ent->driver_data]; + unsigned int board_id = ent->driver_data; + struct ata_port_info pi = ahci_port_info[board_id]; const struct ata_port_info *ppi[] = { &pi, NULL }; struct device *dev = &pdev->dev; struct ahci_host_priv *hpriv; @@ -2167,6 +2184,11 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return -ENOMEM; hpriv->flags |= (unsigned long)pi.private_data; + /* MCP65 revision A1 and A2 can't do MSI */ + if (board_id == board_ahci_mcp65 && + (pdev->revision == 0xa1 || pdev->revision == 0xa2)) + hpriv->flags |= AHCI_HFLAG_NO_MSI; + if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev)) pci_intx(pdev, 1); -- cgit v1.2.3 From bd17243a84632465f5403bc9eb8b4831bd67e582 Mon Sep 17 00:00:00 2001 From: Shane Huang Date: Tue, 10 Jun 2008 15:52:04 +0800 Subject: ahci: Workaround HW bug for SB600/700 SATA controller PMP support There is one bug in ATI SATA PMP of SB600 and SB700 old revision, which leads to soft reset failure. This patch can fix the bug. Signed-off-by: Shane Huang Acked-by: Tejun Heo Signed-off-by: Jeff Garzik --- drivers/ata/ahci.c | 99 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 82 insertions(+), 17 deletions(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 1c62b8e39645..966ab401e523 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -255,6 +255,8 @@ static void ahci_pmp_attach(struct ata_port *ap); static void ahci_pmp_detach(struct ata_port *ap); static int ahci_softreset(struct ata_link *link, unsigned int *class, unsigned long deadline); +static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline); static int ahci_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline); static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, @@ -331,6 +333,12 @@ static struct ata_port_operations ahci_p5wdh_ops = { .hardreset = ahci_p5wdh_hardreset, }; +static struct ata_port_operations ahci_sb600_ops = { + .inherits = &ahci_ops, + .softreset = ahci_sb600_softreset, + .pmp_softreset = ahci_sb600_softreset, +}; + #define AHCI_HFLAGS(flags) .private_data = (void *)(flags) static const struct ata_port_info ahci_port_info[] = { @@ -361,11 +369,11 @@ static const struct ata_port_info ahci_port_info[] = { { AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | - AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP), + AHCI_HFLAG_SECT255), .flags = AHCI_FLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, - .port_ops = &ahci_ops, + .port_ops = &ahci_sb600_ops, }, /* board_ahci_mv */ { @@ -379,12 +387,11 @@ static const struct ata_port_info ahci_port_info[] = { }, /* board_ahci_sb700 */ { - AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | - AHCI_HFLAG_NO_PMP), + AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL), .flags = AHCI_FLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = ATA_UDMA6, - .port_ops = &ahci_ops, + .port_ops = &ahci_sb600_ops, }, /* board_ahci_mcp65 */ { @@ -1278,19 +1285,11 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp, return 0; } -static int ahci_check_ready(struct ata_link *link) -{ - void __iomem *port_mmio = ahci_port_base(link->ap); - u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; - - return ata_check_ready(status); -} - -static int ahci_softreset(struct ata_link *link, unsigned int *class, - unsigned long deadline) +static int ahci_do_softreset(struct ata_link *link, unsigned int *class, + int pmp, unsigned long deadline, + int (*check_ready)(struct ata_link *link)) { struct ata_port *ap = link->ap; - int pmp = sata_srst_pmp(link); const char *reason = NULL; unsigned long now, msecs; struct ata_taskfile tf; @@ -1328,7 +1327,7 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class, ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0); /* wait for link to become ready */ - rc = ata_wait_after_reset(link, deadline, ahci_check_ready); + rc = ata_wait_after_reset(link, deadline, check_ready); /* link occupied, -ENODEV too is an error */ if (rc) { reason = "device not ready"; @@ -1344,6 +1343,72 @@ static int ahci_softreset(struct ata_link *link, unsigned int *class, return rc; } +static int ahci_check_ready(struct ata_link *link) +{ + void __iomem *port_mmio = ahci_port_base(link->ap); + u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; + + return ata_check_ready(status); +} + +static int ahci_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + int pmp = sata_srst_pmp(link); + + DPRINTK("ENTER\n"); + + return ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready); +} + +static int ahci_sb600_check_ready(struct ata_link *link) +{ + void __iomem *port_mmio = ahci_port_base(link->ap); + u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF; + u32 irq_status = readl(port_mmio + PORT_IRQ_STAT); + + /* + * There is no need to check TFDATA if BAD PMP is found due to HW bug, + * which can save timeout delay. + */ + if (irq_status & PORT_IRQ_BAD_PMP) + return -EIO; + + return ata_check_ready(status); +} + +static int ahci_sb600_softreset(struct ata_link *link, unsigned int *class, + unsigned long deadline) +{ + struct ata_port *ap = link->ap; + void __iomem *port_mmio = ahci_port_base(ap); + int pmp = sata_srst_pmp(link); + int rc; + u32 irq_sts; + + DPRINTK("ENTER\n"); + + rc = ahci_do_softreset(link, class, pmp, deadline, + ahci_sb600_check_ready); + + /* + * Soft reset fails on some ATI chips with IPMS set when PMP + * is enabled but SATA HDD/ODD is connected to SATA port, + * do soft reset again to port 0. + */ + if (rc == -EIO) { + irq_sts = readl(port_mmio + PORT_IRQ_STAT); + if (irq_sts & PORT_IRQ_BAD_PMP) { + ata_link_printk(link, KERN_WARNING, + "failed due to HW bug, retry pmp=0\n"); + rc = ahci_do_softreset(link, class, 0, deadline, + ahci_check_ready); + } + } + + return rc; +} + static int ahci_hardreset(struct ata_link *link, unsigned int *class, unsigned long deadline) { -- cgit v1.2.3 From dfcf753bd3fb09f336659d07b1c48db7e62772e0 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 22 May 2008 14:36:31 -0400 Subject: Revert "parisc: fix trivial section name warnings" This reverts commit bd3bb8c15b9a80dbddfb7905b237a4a11a4725b4. Signed-off-by: Kyle McMartin --- arch/parisc/hpux/gate.S | 3 +-- arch/parisc/hpux/wrappers.S | 3 +-- arch/parisc/kernel/entry.S | 3 +-- arch/parisc/kernel/head.S | 2 +- arch/parisc/kernel/hpmc.S | 3 +-- arch/parisc/kernel/pacache.S | 3 +-- arch/parisc/kernel/perf_asm.S | 2 +- arch/parisc/kernel/real2.S | 13 ++++++------- arch/parisc/kernel/syscall.S | 5 ++--- arch/parisc/lib/fixup.S | 3 +-- arch/parisc/lib/lusercopy.S | 5 ++--- 11 files changed, 18 insertions(+), 27 deletions(-) diff --git a/arch/parisc/hpux/gate.S b/arch/parisc/hpux/gate.S index f0b18ce89842..38a1c1b8d4e8 100644 --- a/arch/parisc/hpux/gate.S +++ b/arch/parisc/hpux/gate.S @@ -13,10 +13,9 @@ #include #include #include -#include .level LEVEL - __HEAD + .text .import hpux_call_table .import hpux_syscall_exit,code diff --git a/arch/parisc/hpux/wrappers.S b/arch/parisc/hpux/wrappers.S index ccd3a50c0995..58c53c879c02 100644 --- a/arch/parisc/hpux/wrappers.S +++ b/arch/parisc/hpux/wrappers.S @@ -28,10 +28,9 @@ #include #include #include -#include .level LEVEL - __HEAD + .text /* These should probably go in a header file somewhere. * They are duplicated in kernel/wrappers.S diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 5d0837458c19..d1fa4edd2d80 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -38,7 +38,6 @@ #include #include -#include #ifdef CONFIG_64BIT .level 2.0w @@ -622,7 +621,7 @@ * the static part of the kernel address space. */ - __HEAD + .text .align PAGE_SIZE diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S index 5680a2c3b13d..ec2482dc1beb 100644 --- a/arch/parisc/kernel/head.S +++ b/arch/parisc/kernel/head.S @@ -32,7 +32,7 @@ ENTRY(boot_args) .word 0 /* arg3 */ END(boot_args) - __HEAD + .section .text.head .align 4 .import init_thread_union,data .import fault_vector_20,code /* IVA parisc 2.0 32 bit */ diff --git a/arch/parisc/kernel/hpmc.S b/arch/parisc/kernel/hpmc.S index 068322eb8c9b..2cbf13b3ef11 100644 --- a/arch/parisc/kernel/hpmc.S +++ b/arch/parisc/kernel/hpmc.S @@ -47,7 +47,6 @@ #include #include -#include /* * stack for os_hpmc, the HPMC handler. @@ -77,7 +76,7 @@ ENTRY(hpmc_pim_data) .block HPMC_PIM_DATA_SIZE END(hpmc_pim_data) - __HEAD + .text .import intr_save, code ENTRY(os_hpmc) diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index e3246a5ca74f..09b77b2553c6 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -37,9 +37,8 @@ #include #include #include -#include - __HEAD + .text .align 128 ENTRY(flush_tlb_all_local) diff --git a/arch/parisc/kernel/perf_asm.S b/arch/parisc/kernel/perf_asm.S index d411dfb5b6d1..fa6ea99bb324 100644 --- a/arch/parisc/kernel/perf_asm.S +++ b/arch/parisc/kernel/perf_asm.S @@ -43,7 +43,7 @@ ; The coprocessor only needs to be enabled when ; starting/stopping the coprocessor with the pmenb/pmdis. ; - __HEAD + .text ENTRY(perf_intrigue_enable_perf_counters) .proc diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S index 47fbdae6efd5..7a92695d95a6 100644 --- a/arch/parisc/kernel/real2.S +++ b/arch/parisc/kernel/real2.S @@ -12,7 +12,6 @@ #include #include -#include .section .bss .export real_stack @@ -40,7 +39,7 @@ save_cr_end: /************************ 32-bit real-mode calls ***********************/ /* This can be called in both narrow and wide kernels */ - __HEAD + .text /* unsigned long real32_call_asm(unsigned int *sp, * unsigned int *arg0p, @@ -114,7 +113,7 @@ ENDPROC(real32_call_asm) # define PUSH_CR(r, where) mfctl r, %r1 ! STREG,ma %r1, REG_SZ(where) # define POP_CR(r, where) LDREG,mb -REG_SZ(where), %r1 ! mtctl %r1, r - __HEAD + .text save_control_regs: load32 PA(save_cr_space), %r28 PUSH_CR(%cr24, %r28) @@ -146,7 +145,7 @@ restore_control_regs: /* rfi_virt2real() and rfi_real2virt() could perhaps be adapted for * more general-purpose use by the several places which need RFIs */ - __HEAD + .text .align 128 rfi_virt2real: /* switch to real mode... */ @@ -181,7 +180,7 @@ rfi_v2r_1: bv 0(%r2) nop - __HEAD + .text .align 128 rfi_real2virt: rsm PSW_SM_I,%r0 @@ -219,7 +218,7 @@ rfi_r2v_1: /************************ 64-bit real-mode calls ***********************/ /* This is only usable in wide kernels right now and will probably stay so */ - __HEAD + .text /* unsigned long real64_call_asm(unsigned long *sp, * unsigned long *arg0p, * unsigned long fn) @@ -277,7 +276,7 @@ ENDPROC(real64_call_asm) #endif - __HEAD + .text /* http://lists.parisc-linux.org/hypermail/parisc-linux/10916.html ** GCC 3.3 and later has a new function in libgcc.a for ** comparing function pointers. diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index ae509d8cd03f..69b6eebc466e 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -17,7 +17,6 @@ #include #include -#include /* We fill the empty parts of the gateway page with * something that will kill the kernel or a @@ -27,7 +26,7 @@ .level LEVEL - __HEAD + .text .import syscall_exit,code .import syscall_exit_rfi,code @@ -637,7 +636,7 @@ END(sys_call_table64) All light-weight-syscall atomic operations will use this set of locks */ - .section .data, "aw" + .section .data .align PAGE_SIZE ENTRY(lws_lock_start) /* lws locks */ diff --git a/arch/parisc/lib/fixup.S b/arch/parisc/lib/fixup.S index 4821ad6d5269..d172d4245cdc 100644 --- a/arch/parisc/lib/fixup.S +++ b/arch/parisc/lib/fixup.S @@ -23,7 +23,6 @@ #include #include #include -#include #ifdef CONFIG_SMP .macro get_fault_ip t1 t2 @@ -56,7 +55,7 @@ .level LEVEL - __HEAD + .text .section .fixup, "ax" /* get_user() fixups, store -EFAULT in r8, and 0 in r9 */ diff --git a/arch/parisc/lib/lusercopy.S b/arch/parisc/lib/lusercopy.S index b0d885350846..1bd23ccec17b 100644 --- a/arch/parisc/lib/lusercopy.S +++ b/arch/parisc/lib/lusercopy.S @@ -33,12 +33,11 @@ */ + .text + #include #include #include -#include - - __HEAD /* * get_sr gets the appropriate space value into -- cgit v1.2.3 From 1138a72cd96857d1d5928c0c8c83d8b8995eeb38 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 22 May 2008 14:38:26 -0400 Subject: parisc: move head.S to head.text section And explicitly list it in vmlinux.lds... Signed-off-by: Kyle McMartin --- arch/parisc/kernel/head.S | 3 ++- arch/parisc/kernel/vmlinux.lds.S | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S index ec2482dc1beb..a84e31e82876 100644 --- a/arch/parisc/kernel/head.S +++ b/arch/parisc/kernel/head.S @@ -32,7 +32,8 @@ ENTRY(boot_args) .word 0 /* arg3 */ END(boot_args) - .section .text.head + __HEAD + .align 4 .import init_thread_union,data .import fault_vector_20,code /* IVA parisc 2.0 32 bit */ diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 50b4a3a25d0a..2e516b871752 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S @@ -50,6 +50,7 @@ SECTIONS _text = .; /* Text and read-only data */ .text ALIGN(16) : { + HEAD_TEXT TEXT_TEXT SCHED_TEXT LOCK_TEXT -- cgit v1.2.3 From db51d92b90193cf69b2bcc2874fd0b267fd3e710 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Mon, 26 May 2008 01:49:01 -0400 Subject: parisc: export copy_user_page_asm Needed by fuse (via copy_highpage). Signed-off-by: Kyle McMartin --- arch/parisc/kernel/parisc_ksyms.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c index 5b7fc4aa044d..0eecfbbc59cd 100644 --- a/arch/parisc/kernel/parisc_ksyms.c +++ b/arch/parisc/kernel/parisc_ksyms.c @@ -152,3 +152,6 @@ EXPORT_SYMBOL($$dyncall); EXPORT_SYMBOL(node_data); EXPORT_SYMBOL(pfnnid_map); #endif + +/* from pacache.S -- needed for copy_page */ +EXPORT_SYMBOL(copy_user_page_asm); -- cgit v1.2.3 From 22febf1f372496d74534be32b6b5edcee7fb7cc5 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Mon, 26 May 2008 01:54:35 -0400 Subject: parisc: export empty_zero_page Needed by ext4 when built as a module. Signed-off-by: Kyle McMartin --- arch/parisc/mm/init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index 78fe252b92c3..ce0da689a89d 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -547,6 +547,7 @@ void __init mem_init(void) } unsigned long *empty_zero_page __read_mostly; +EXPORT_SYMBOL(empty_zero_page); void show_mem(void) { -- cgit v1.2.3 From f4441b62d46e7033e907dfd6a8bb0b75b5519e88 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Tue, 27 May 2008 01:56:29 -0400 Subject: parisc: fix off by one in setup_sigcontext32 Thankfully, the values were irrelevant... Spotted by newer gcc. Signed-off-by: Kyle McMartin --- arch/parisc/kernel/signal32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index db94affe5c71..fb59852006de 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -289,7 +289,7 @@ setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __ &sc->sc_iaoq[0], compat_reg); /* Store upper half */ - compat_reg = (compat_uint_t)(regs->gr[32] >> 32); + compat_reg = (compat_uint_t)(regs->gr[31] >> 32); err |= __put_user(compat_reg, &rf->rf_iaoq[0]); DBG(2,"setup_sigcontext32: upper half iaoq[0] = %#x\n", compat_reg); @@ -299,7 +299,7 @@ setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __ DBG(2,"setup_sigcontext32: sc->sc_iaoq[1] = %p <= %#x\n", &sc->sc_iaoq[1], compat_reg); /* Store upper half */ - compat_reg = (compat_uint_t)((regs->gr[32]+4) >> 32); + compat_reg = (compat_uint_t)((regs->gr[31]+4) >> 32); err |= __put_user(compat_reg, &rf->rf_iaoq[1]); DBG(2,"setup_sigcontext32: upper half iaoq[1] = %#x\n", compat_reg); -- cgit v1.2.3 From e374d17cd74ec5967f81e2b0c67ec3219a2bbbcc Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sat, 31 May 2008 12:15:42 -0400 Subject: parisc: fix miscompilation of ip_fast_csum with gcc >= 4.3 ip_fast_csum needs an asm "memory" clobber, otherwise the aggressive optimizations in gcc-4.3 cause it to be miscompiled. Signed-off-by: Kyle McMartin --- include/asm-parisc/checksum.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/asm-parisc/checksum.h b/include/asm-parisc/checksum.h index cc3ec1bd8919..e9639ccc3fce 100644 --- a/include/asm-parisc/checksum.h +++ b/include/asm-parisc/checksum.h @@ -65,7 +65,7 @@ static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) "2:\n" : "=r" (sum), "=r" (iph), "=r" (ihl) : "1" (iph), "2" (ihl) - : "r19", "r20", "r21" ); + : "r19", "r20", "r21", "memory"); return (__force __sum16)sum; } -- cgit v1.2.3 From 42a5a8a60a093c359987fd884aec99b9d7f4c084 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 6 Jun 2008 17:16:17 -0400 Subject: parisc: update my email address Signed-off-by: Kyle McMartin --- MAINTAINERS | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 9d4304266043..01605a9b95e7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -274,7 +274,7 @@ S: Maintained AD1889 ALSA SOUND DRIVER P: Kyle McMartin -M: kyle@parisc-linux.org +M: kyle@mcmartin.ca P: Thibaut Varene M: T-Bone@parisc-linux.org W: http://wiki.parisc-linux.org/AD1889 @@ -1827,7 +1827,7 @@ S: Maintained HARMONY SOUND DRIVER P: Kyle McMartin -M: kyle@parisc-linux.org +M: kyle@mcmartin.ca L: linux-parisc@vger.kernel.org S: Maintained @@ -3120,7 +3120,7 @@ S: Maintained PARISC ARCHITECTURE P: Kyle McMartin -M: kyle@parisc-linux.org +M: kyle@mcmartin.ca P: Matthew Wilcox M: matthew@wil.cx P: Grant Grundler @@ -4023,7 +4023,7 @@ TULIP NETWORK DRIVERS P: Grant Grundler M: grundler@parisc-linux.org P: Kyle McMartin -M: kyle@parisc-linux.org +M: kyle@mcmartin.ca L: netdev@vger.kernel.org S: Maintained -- cgit v1.2.3 From 62128b2ca812c1266f4ff7bac068bf0b626c6179 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 15 Jun 2008 21:00:21 +0200 Subject: opti621: disable read prefetch This fixes 2.6.25 regression (kernel.org bugzilla bug #10723) caused by: commit 912fb29a36a7269ac1c4a4df45bc0ac1d2637972 Author: Bartlomiej Zolnierkiewicz Date: Fri Oct 19 00:30:11 2007 +0200 opti621: always tune PIO ... Based on a bugreport from Juergen Kosel & inspired by pata_opti.c code. Bisected-by: Juergen Kosel Tested-by: Juergen Kosel Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/opti621.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index 6e99080497bf..e31e0f970a2c 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -102,18 +102,6 @@ * address: 50 ns, data: 50 ns, recovery: 100 ns. */ -/* #define READ_PREFETCH 0 */ -/* Uncomment for disable read prefetch. - * There is some readprefetch capatibility in hdparm, - * but when I type hdparm -P 1 /dev/hda, I got errors - * and till reset drive is inaccessible. - * This (hw) read prefetch is safe on my drive. - */ - -#ifndef READ_PREFETCH -#define READ_PREFETCH 0x40 /* read prefetch is enabled */ -#endif /* else read prefetch is disabled */ - #define READ_REG 0 /* index of Read cycle timing register */ #define WRITE_REG 1 /* index of Write cycle timing register */ #define CNTRL_REG 3 /* index of Control register */ @@ -264,7 +252,8 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) cycle1 = ((first.data_time-1)<<4) | (first.recovery_time-2); cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2); - misc = READ_PREFETCH | ((ax-1)<<4) | ((drdy-2)<<1); + + misc = ((ax - 1) << 4) | ((drdy - 2) << 1); #ifdef OPTI621_DEBUG printk("%s: master: address: %d, data: %d, " -- cgit v1.2.3 From f361037631ba547ea88adf8d2359d810c1b2605a Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 15 Jun 2008 21:00:21 +0200 Subject: opti621: remove DMA support These controllers don't support DMA. Based on a bugreport from Juergen Kosel & inspired by pata_opti.c code. Tested-by: Juergen Kosel Acked-by: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/opti621.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index e31e0f970a2c..65f180738947 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -324,18 +324,14 @@ static const struct ide_port_info opti621_chipsets[] __devinitdata = { .name = "OPTI621", .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} }, .port_ops = &opti621_port_ops, - .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA, + .host_flags = IDE_HFLAG_NO_DMA, .pio_mask = ATA_PIO3, - .swdma_mask = ATA_SWDMA2, - .mwdma_mask = ATA_MWDMA2, }, { /* 1 */ .name = "OPTI621X", .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} }, .port_ops = &opti621_port_ops, - .host_flags = IDE_HFLAG_TRUST_BIOS_FOR_DMA, + .host_flags = IDE_HFLAG_NO_DMA, .pio_mask = ATA_PIO3, - .swdma_mask = ATA_SWDMA2, - .mwdma_mask = ATA_MWDMA2, } }; -- cgit v1.2.3 From 21bd33a656a60daadc475ce330272f4410ae27b7 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 15 Jun 2008 21:00:22 +0200 Subject: opti621: use PCI clock value provided by controller Use PCI clock value provided by controller instead of depending on a default (or user supplied) value. Based on a bugreport from Juergen Kosel & inspired by pata_opti.c code. Tested-by: Juergen Kosel Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/opti621.c | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index 65f180738947..7547fa2d83ac 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -193,11 +193,10 @@ typedef struct pio_clocks_s { int recovery_time; /* Recovery time (clocks) */ } pio_clocks_t; -static void compute_clocks(int pio, pio_clocks_t *clks) +static void compute_clocks(int pio, pio_clocks_t *clks, int bus_speed) { if (pio != PIO_NOT_EXIST) { int adr_setup, data_pls; - int bus_speed = ide_pci_clk ? ide_pci_clk : system_bus_clock(); adr_setup = ide_pio_timings[pio].setup_time; data_pls = ide_pio_timings[pio].active_time; @@ -234,7 +233,7 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) u8 pio1 = 0, pio2 = 0; pio_clocks_t first, second; int ax, drdy; - u8 cycle1, cycle2, misc; + u8 cycle1, cycle2, misc, clk; ide_hwif_t *hwif = HWIF(drive); /* sets drive->drive_data for both drives */ @@ -242,8 +241,26 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) pio1 = hwif->drives[0].drive_data; pio2 = hwif->drives[1].drive_data; - compute_clocks(pio1, &first); - compute_clocks(pio2, &second); + spin_lock_irqsave(&opti621_lock, flags); + + reg_base = hwif->io_ports.data_addr; + + /* allow Register-B */ + outb(0xc0, reg_base + CNTRL_REG); + /* hmm, setupvic.exe does this ;-) */ + outb(0xff, reg_base + 5); + /* if reads 0xff, adapter not exist? */ + (void)inb(reg_base + CNTRL_REG); + /* if reads 0xc0, no interface exist? */ + read_reg(CNTRL_REG); + + /* check CLK speed */ + clk = read_reg(STRAP_REG) & 1; + + printk(KERN_INFO "%s: CLK = %d MHz\n", hwif->name, clk ? 25 : 33); + + compute_clocks(pio1, &first, clk ? 25 : 33); + compute_clocks(pio2, &second, clk ? 25 : 33); /* ax = max(a1,a2) */ ax = (first.address_time < second.address_time) ? second.address_time : first.address_time; @@ -266,21 +283,6 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) second.recovery_time, drdy); #endif - spin_lock_irqsave(&opti621_lock, flags); - - reg_base = hwif->io_ports.data_addr; - - /* allow Register-B */ - outb(0xc0, reg_base + CNTRL_REG); - /* hmm, setupvic.exe does this ;-) */ - outb(0xff, reg_base + 5); - /* if reads 0xff, adapter not exist? */ - (void)inb(reg_base + CNTRL_REG); - /* if reads 0xc0, no interface exist? */ - read_reg(CNTRL_REG); - /* read version, probably 0 */ - read_reg(STRAP_REG); - /* program primary drive */ /* select Index-0 for Register-A */ write_reg(0, MISC_REG); -- cgit v1.2.3 From 6c987183fcc3c6cb9eb77fd0b3e8ca1ac98a4813 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 15 Jun 2008 21:00:22 +0200 Subject: opti621: program devices timings separately in ->set_pio_mode * Set drive->drive_data to 'pio + XFER_PIO_0' instead of 'pio', then simplify selecting maximum adress setup timing. * Remove no longer needed compute_pios() and opti621_port_init_devs(). * Program devices timings separately in ->set_pio_mode. Based on a bugreport from Juergen Kosel & inspired by pata_opti.c code. Tested-by: Juergen Kosel Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/opti621.c | 80 +++++++++-------------------------------------- 1 file changed, 15 insertions(+), 65 deletions(-) diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index 7547fa2d83ac..c746e6f06077 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -115,34 +115,6 @@ static int reg_base; static DEFINE_SPINLOCK(opti621_lock); -/* there are stored pio numbers from other calls of opti621_set_pio_mode */ -static void compute_pios(ide_drive_t *drive, const u8 pio) -/* Store values into drive->drive_data - * second_contr - 0 for primary controller, 1 for secondary - * slave_drive - 0 -> pio is for master, 1 -> pio is for slave - * pio - PIO mode for selected drive (for other we don't know) - */ -{ - int d; - ide_hwif_t *hwif = HWIF(drive); - - drive->drive_data = pio; - - for (d = 0; d < 2; ++d) { - drive = &hwif->drives[d]; - if (drive->present) { - if (drive->drive_data == PIO_DONT_KNOW) - drive->drive_data = ide_get_best_pio_mode(drive, 255, 3); -#ifdef OPTI621_DEBUG - printk("%s: Selected PIO mode %d\n", - drive->name, drive->drive_data); -#endif - } else { - drive->drive_data = PIO_NOT_EXIST; - } - } -} - static int cmpt_clk(int time, int bus_speed) /* Returns (rounded up) time in clocks for time in ns, * with bus_speed in MHz. @@ -226,20 +198,19 @@ static void compute_clocks(int pio, pio_clocks_t *clks, int bus_speed) static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) { - /* primary and secondary drives share some registers, - * so we have to program both drives - */ + ide_hwif_t *hwif = drive->hwif; + ide_drive_t *pair = ide_get_paired_drive(drive); unsigned long flags; - u8 pio1 = 0, pio2 = 0; pio_clocks_t first, second; int ax, drdy; - u8 cycle1, cycle2, misc, clk; - ide_hwif_t *hwif = HWIF(drive); + u8 cycle1, misc, clk, addr_pio = pio; - /* sets drive->drive_data for both drives */ - compute_pios(drive, pio); - pio1 = hwif->drives[0].drive_data; - pio2 = hwif->drives[1].drive_data; + drive->drive_data = XFER_PIO_0 + pio; + + if (pair->present) { + if (pair->drive_data && pair->drive_data < drive->drive_data) + addr_pio = pair->drive_data - XFER_PIO_0; + } spin_lock_irqsave(&opti621_lock, flags); @@ -259,8 +230,8 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) printk(KERN_INFO "%s: CLK = %d MHz\n", hwif->name, clk ? 25 : 33); - compute_clocks(pio1, &first, clk ? 25 : 33); - compute_clocks(pio2, &second, clk ? 25 : 33); + compute_clocks(pio, &first, clk ? 25 : 33); + compute_clocks(addr_pio, &second, clk ? 25 : 33); /* ax = max(a1,a2) */ ax = (first.address_time < second.address_time) ? second.address_time : first.address_time; @@ -268,37 +239,23 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) drdy = 2; /* DRDY is default 2 (by OPTi Databook) */ cycle1 = ((first.data_time-1)<<4) | (first.recovery_time-2); - cycle2 = ((second.data_time-1)<<4) | (second.recovery_time-2); misc = ((ax - 1) << 4) | ((drdy - 2) << 1); #ifdef OPTI621_DEBUG - printk("%s: master: address: %d, data: %d, " + printk("%s: address: %d, data: %d, " "recovery: %d, drdy: %d [clk]\n", - hwif->name, ax, first.data_time, + drive->name, ax, first.data_time, first.recovery_time, drdy); - printk("%s: slave: address: %d, data: %d, " - "recovery: %d, drdy: %d [clk]\n", - hwif->name, ax, second.data_time, - second.recovery_time, drdy); #endif - /* program primary drive */ - /* select Index-0 for Register-A */ - write_reg(0, MISC_REG); + /* select Index-0/1 for Register-A/B */ + write_reg(drive->select.b.unit, MISC_REG); /* set read cycle timings */ write_reg(cycle1, READ_REG); /* set write cycle timings */ write_reg(cycle1, WRITE_REG); - /* program secondary drive */ - /* select Index-1 for Register-B */ - write_reg(1, MISC_REG); - /* set read cycle timings */ - write_reg(cycle2, READ_REG); - /* set write cycle timings */ - write_reg(cycle2, WRITE_REG); - /* use Register-A for drive 0 */ /* use Register-B for drive 1 */ write_reg(0x85, CNTRL_REG); @@ -310,14 +267,7 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) spin_unlock_irqrestore(&opti621_lock, flags); } -static void __devinit opti621_port_init_devs(ide_hwif_t *hwif) -{ - hwif->drives[0].drive_data = PIO_DONT_KNOW; - hwif->drives[1].drive_data = PIO_DONT_KNOW; -} - static const struct ide_port_ops opti621_port_ops = { - .port_init_devs = opti621_port_init_devs, .set_pio_mode = opti621_set_pio_mode, }; -- cgit v1.2.3 From 810253d44bc92b44b66cd9944b579de54c0cd3ff Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 15 Jun 2008 21:00:22 +0200 Subject: opti621: use pre-calculated PIO timings * Use pre-calculated PIO timings in ->set_pio_mode. * Remove no longer needed compute_clocks(), cmpt_clk(), struct pio_clocks_s, PIO_* defines and OPTI621_DEBUG define. There should be no functional changes caused by this patch. Based on a bugreport from Juergen Kosel & inspired by pata_opti.c code. Tested-by: Juergen Kosel Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/opti621.c | 92 ++++++++--------------------------------------- 1 file changed, 15 insertions(+), 77 deletions(-) diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index c746e6f06077..8c715b7a85db 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -81,8 +81,6 @@ * 0.5 doesn't work. */ -#define OPTI621_DEBUG /* define for debug messages */ - #include #include #include @@ -110,23 +108,8 @@ static int reg_base; -#define PIO_NOT_EXIST 254 -#define PIO_DONT_KNOW 255 - static DEFINE_SPINLOCK(opti621_lock); -static int cmpt_clk(int time, int bus_speed) -/* Returns (rounded up) time in clocks for time in ns, - * with bus_speed in MHz. - * Example: bus_speed = 40 MHz, time = 80 ns - * 1000/40 = 25 ns (clk value), - * 80/25 = 3.2, rounded up to 4 (I hope ;-)). - * Use idebus=xx to select right frequency. - */ -{ - return ((time*bus_speed+999)/1000); -} - /* Write value to register reg, base of register * is at reg_base (0x1f0 primary, 0x170 secondary, * if not changed by PCI configuration). @@ -159,51 +142,22 @@ static u8 read_reg(int reg) return ret; } -typedef struct pio_clocks_s { - int address_time; /* Address setup (clocks) */ - int data_time; /* Active/data pulse (clocks) */ - int recovery_time; /* Recovery time (clocks) */ -} pio_clocks_t; - -static void compute_clocks(int pio, pio_clocks_t *clks, int bus_speed) -{ - if (pio != PIO_NOT_EXIST) { - int adr_setup, data_pls; - - adr_setup = ide_pio_timings[pio].setup_time; - data_pls = ide_pio_timings[pio].active_time; - clks->address_time = cmpt_clk(adr_setup, bus_speed); - clks->data_time = cmpt_clk(data_pls, bus_speed); - clks->recovery_time = cmpt_clk(ide_pio_timings[pio].cycle_time - - adr_setup-data_pls, bus_speed); - if (clks->address_time < 1) - clks->address_time = 1; - if (clks->address_time > 4) - clks->address_time = 4; - if (clks->data_time < 1) - clks->data_time = 1; - if (clks->data_time > 16) - clks->data_time = 16; - if (clks->recovery_time < 2) - clks->recovery_time = 2; - if (clks->recovery_time > 17) - clks->recovery_time = 17; - } else { - clks->address_time = 1; - clks->data_time = 1; - clks->recovery_time = 2; - /* minimal values */ - } -} - static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = drive->hwif; ide_drive_t *pair = ide_get_paired_drive(drive); unsigned long flags; - pio_clocks_t first, second; - int ax, drdy; - u8 cycle1, misc, clk, addr_pio = pio; + u8 tim, misc, addr_pio = pio, clk; + + /* DRDY is default 2 (by OPTi Databook) */ + static const u8 addr_timings[2][4] = { + { 0x20, 0x10, 0x00, 0x00 }, /* 33 MHz */ + { 0x10, 0x10, 0x00, 0x00 }, /* 25 MHz */ + }; + static const u8 data_rec_timings[2][4] = { + { 0x5b, 0x45, 0x32, 0x21 }, /* 33 MHz */ + { 0x48, 0x34, 0x21, 0x10 } /* 25 MHz */ + }; drive->drive_data = XFER_PIO_0 + pio; @@ -230,31 +184,15 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) printk(KERN_INFO "%s: CLK = %d MHz\n", hwif->name, clk ? 25 : 33); - compute_clocks(pio, &first, clk ? 25 : 33); - compute_clocks(addr_pio, &second, clk ? 25 : 33); - - /* ax = max(a1,a2) */ - ax = (first.address_time < second.address_time) ? second.address_time : first.address_time; - - drdy = 2; /* DRDY is default 2 (by OPTi Databook) */ - - cycle1 = ((first.data_time-1)<<4) | (first.recovery_time-2); - - misc = ((ax - 1) << 4) | ((drdy - 2) << 1); - -#ifdef OPTI621_DEBUG - printk("%s: address: %d, data: %d, " - "recovery: %d, drdy: %d [clk]\n", - drive->name, ax, first.data_time, - first.recovery_time, drdy); -#endif + tim = data_rec_timings[clk][pio]; + misc = addr_timings[clk][addr_pio]; /* select Index-0/1 for Register-A/B */ write_reg(drive->select.b.unit, MISC_REG); /* set read cycle timings */ - write_reg(cycle1, READ_REG); + write_reg(tim, READ_REG); /* set write cycle timings */ - write_reg(cycle1, WRITE_REG); + write_reg(tim, WRITE_REG); /* use Register-A for drive 0 */ /* use Register-B for drive 1 */ -- cgit v1.2.3 From 80a65fc5ee04497e6c28bdaefc44d375b19c4a79 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 15 Jun 2008 21:00:22 +0200 Subject: opti621: add PIO 4 support * Add PIO 4 support. While at it: * Use a single struct ide_port_info instance for OPTi621 and OPTi621X. Based on a bugreport from Juergen Kosel & inspired by pata_opti.c code. Tested-by: Juergen Kosel Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/pci/opti621.c | 46 ++++++++++++++-------------------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c index 8c715b7a85db..725c80508d90 100644 --- a/drivers/ide/pci/opti621.c +++ b/drivers/ide/pci/opti621.c @@ -90,16 +90,6 @@ #include -//#define OPTI621_MAX_PIO 3 -/* In fact, I do not have any PIO 4 drive - * (address: 25 ns, data: 70 ns, recovery: 35 ns), - * but OPTi 82C621 is programmable and it can do (minimal values): - * on 40MHz PCI bus (pulse 25 ns): - * address: 25 ns, data: 25 ns, recovery: 50 ns; - * on 20MHz PCI bus (pulse 50 ns): - * address: 50 ns, data: 50 ns, recovery: 100 ns. - */ - #define READ_REG 0 /* index of Read cycle timing register */ #define WRITE_REG 1 /* index of Write cycle timing register */ #define CNTRL_REG 3 /* index of Control register */ @@ -150,13 +140,13 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) u8 tim, misc, addr_pio = pio, clk; /* DRDY is default 2 (by OPTi Databook) */ - static const u8 addr_timings[2][4] = { - { 0x20, 0x10, 0x00, 0x00 }, /* 33 MHz */ - { 0x10, 0x10, 0x00, 0x00 }, /* 25 MHz */ + static const u8 addr_timings[2][5] = { + { 0x20, 0x10, 0x00, 0x00, 0x00 }, /* 33 MHz */ + { 0x10, 0x10, 0x00, 0x00, 0x00 }, /* 25 MHz */ }; - static const u8 data_rec_timings[2][4] = { - { 0x5b, 0x45, 0x32, 0x21 }, /* 33 MHz */ - { 0x48, 0x34, 0x21, 0x10 } /* 25 MHz */ + static const u8 data_rec_timings[2][5] = { + { 0x5b, 0x45, 0x32, 0x21, 0x20 }, /* 33 MHz */ + { 0x48, 0x34, 0x21, 0x10, 0x10 } /* 25 MHz */ }; drive->drive_data = XFER_PIO_0 + pio; @@ -209,30 +199,22 @@ static const struct ide_port_ops opti621_port_ops = { .set_pio_mode = opti621_set_pio_mode, }; -static const struct ide_port_info opti621_chipsets[] __devinitdata = { - { /* 0 */ - .name = "OPTI621", - .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} }, - .port_ops = &opti621_port_ops, - .host_flags = IDE_HFLAG_NO_DMA, - .pio_mask = ATA_PIO3, - }, { /* 1 */ - .name = "OPTI621X", - .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} }, - .port_ops = &opti621_port_ops, - .host_flags = IDE_HFLAG_NO_DMA, - .pio_mask = ATA_PIO3, - } +static const struct ide_port_info opti621_chipset __devinitdata = { + .name = "OPTI621/X", + .enablebits = { {0x45, 0x80, 0x00}, {0x40, 0x08, 0x00} }, + .port_ops = &opti621_port_ops, + .host_flags = IDE_HFLAG_NO_DMA, + .pio_mask = ATA_PIO4, }; static int __devinit opti621_init_one(struct pci_dev *dev, const struct pci_device_id *id) { - return ide_setup_pci_device(dev, &opti621_chipsets[id->driver_data]); + return ide_setup_pci_device(dev, &opti621_chipset); } static const struct pci_device_id opti621_pci_tbl[] = { { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 }, - { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 1 }, + { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 0 }, { 0, }, }; MODULE_DEVICE_TABLE(pci, opti621_pci_tbl); -- cgit v1.2.3 From c1a8e39819bd6797ee2b82b88517268d39921b03 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 15 Jun 2008 21:00:23 +0200 Subject: ide-pmac: bugfix for media-bay support rework Fix bug introduced by: commit 2dde7861afa23cd59db83515cb0b810b92b220aa Author: Bartlomiej Zolnierkiewicz Date: Fri Apr 18 00:46:23 2008 +0200 ide: rework PowerMac media-bay support (take 2) ... [ Yeah, I suck. ] bay->cd_index shouldn't be changed if IDE devices are not present or retry operations won't happen. Cc: Benjamin Herrenschmidt Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/macintosh/mediabay.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index 82add26cc665..c34bdf852e32 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -556,7 +556,8 @@ static void media_bay_step(int i) printk("mediabay %d, registering IDE...\n", i); pmu_suspend(); ide_port_scan(bay->cd_port); - bay->cd_index = bay->cd_port->index; + if (bay->cd_port->present) + bay->cd_index = bay->cd_port->index; pmu_resume(); } if (bay->cd_index == -1) { -- cgit v1.2.3 From 07a6c66da53f646a39103290bfbd85be18892895 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 15 Jun 2008 21:00:23 +0200 Subject: ide-pmac: add ->cable_detect method Add ->cable_detect method and remove no longer needed pmif->cable_80 flag (there is also no need to mask ->udma_mask now). This fixes: - forced ignoring of cable detection (needed for some CF devices & debug) - cable detection for warm-plug Cc: Benjamin Herrenschmidt Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ppc/pmac.c | 55 ++++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 48aa019127bc..7f669a997aa6 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -59,7 +59,6 @@ typedef struct pmac_ide_hwif { int irq; int kind; int aapl_bus_id; - unsigned cable_80 : 1; unsigned mediabay : 1; unsigned broken_dma : 1; unsigned broken_dma_warn : 1; @@ -918,10 +917,40 @@ pmac_ide_do_resume(ide_hwif_t *hwif) return 0; } +static u8 pmac_ide_cable_detect(ide_hwif_t *hwif) +{ + pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)ide_get_hwifdata(hwif); + struct device_node *np = pmif->node; + const char *cable = of_get_property(np, "cable-type", NULL); + + /* Get cable type from device-tree. */ + if (cable && !strncmp(cable, "80-", 3)) + return ATA_CBL_PATA80; + + /* + * G5's seem to have incorrect cable type in device-tree. + * Let's assume they have a 80 conductor cable, this seem + * to be always the case unless the user mucked around. + */ + if (of_device_is_compatible(np, "K2-UATA") || + of_device_is_compatible(np, "shasta-ata")) + return ATA_CBL_PATA80; + + return ATA_CBL_PATA40; +} + static const struct ide_port_ops pmac_ide_ata6_port_ops = { .set_pio_mode = pmac_ide_set_pio_mode, .set_dma_mode = pmac_ide_set_dma_mode, .selectproc = pmac_ide_kauai_selectproc, + .cable_detect = pmac_ide_cable_detect, +}; + +static const struct ide_port_ops pmac_ide_ata4_port_ops = { + .set_pio_mode = pmac_ide_set_pio_mode, + .set_dma_mode = pmac_ide_set_dma_mode, + .selectproc = pmac_ide_selectproc, + .cable_detect = pmac_ide_cable_detect, }; static const struct ide_port_ops pmac_ide_port_ops = { @@ -962,7 +991,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw) u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; struct ide_port_info d = pmac_port_info; - pmif->cable_80 = 0; pmif->broken_dma = pmif->broken_dma_warn = 0; if (of_device_is_compatible(np, "shasta-ata")) { pmif->kind = controller_sh_ata6; @@ -979,6 +1007,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw) } else if (of_device_is_compatible(np, "keylargo-ata")) { if (strcmp(np->name, "ata-4") == 0) { pmif->kind = controller_kl_ata4; + d.port_ops = &pmac_ide_ata4_port_ops; d.udma_mask = ATA_UDMA4; } else pmif->kind = controller_kl_ata3; @@ -992,22 +1021,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw) bidp = of_get_property(np, "AAPL,bus-id", NULL); pmif->aapl_bus_id = bidp ? *bidp : 0; - /* Get cable type from device-tree */ - if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6 - || pmif->kind == controller_k2_ata6 - || pmif->kind == controller_sh_ata6) { - const char* cable = of_get_property(np, "cable-type", NULL); - if (cable && !strncmp(cable, "80-", 3)) - pmif->cable_80 = 1; - } - /* G5's seem to have incorrect cable type in device-tree. Let's assume - * they have a 80 conductor cable, this seem to be always the case unless - * the user mucked around - */ - if (of_device_is_compatible(np, "K2-UATA") || - of_device_is_compatible(np, "shasta-ata")) - pmif->cable_80 = 1; - /* On Kauai-type controllers, we make sure the FCR is correct */ if (pmif->kauai_fcr) writel(KAUAI_FCR_UATA_MAGIC | @@ -1053,7 +1066,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw) hwif->hwif_data = pmif; ide_init_port_hw(hwif, hw); - hwif->cbl = pmif->cable_80 ? ATA_CBL_PATA80 : ATA_CBL_PATA40; printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n", hwif->index, model_name[pmif->kind], pmif->aapl_bus_id, @@ -1070,11 +1082,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw) } } -#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC - if (pmif->cable_80 == 0) - d.udma_mask &= ATA_UDMA2; -#endif - idx[0] = hwif->index; ide_device_add(idx, &d); -- cgit v1.2.3 From 5b16464ac32a92c2332030d11ec445bddeb141fa Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 15 Jun 2008 21:00:23 +0200 Subject: ide-pmac: remove bogus comment about pmac_ide_setup_device() Cc: Benjamin Herrenschmidt Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ppc/pmac.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index 7f669a997aa6..ba2d58727964 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c @@ -978,10 +978,7 @@ static const struct ide_port_info pmac_port_info = { /* * Setup, register & probe an IDE channel driven by this driver, this is - * called by one of the 2 probe functions (macio or PCI). Note that a channel - * that ends up beeing free of any device is not kept around by this driver - * (it is kept in 2.4). This introduce an interface numbering change on some - * rare machines unfortunately, but it's better this way. + * called by one of the 2 probe functions (macio or PCI). */ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif, hw_regs_t *hw) -- cgit v1.2.3 From 792a1a98560a2a1619491eed8b18fccb09b312a7 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 15 Jun 2008 21:00:23 +0200 Subject: ide-cs: fix probing and add warm-plug support * Fix probing by using ide_port_scan() and moving "retry loop" from ide_config() to idecs_register(). * Don't fail probe if there are no devices attached to a port. * Remove (now redundant) error message from ide_config(). Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/legacy/ide-cs.c | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index aa2ea3deac85..d08107db54d4 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -194,6 +194,16 @@ static ide_hwif_t *idecs_register(unsigned long io, unsigned long ctl, if (hwif->present) return hwif; + /* retry registration in case device is still spinning up */ + for (i = 0; i < 10; i++) { + msleep(100); + ide_port_scan(hwif); + if (hwif->present) + return hwif; + } + + return hwif; + out_release: release_region(ctl, 1); release_region(io, 8); @@ -222,7 +232,7 @@ static int ide_config(struct pcmcia_device *link) cistpl_cftable_entry_t dflt; } *stk = NULL; cistpl_cftable_entry_t *cfg; - int i, pass, last_ret = 0, last_fn = 0, is_kme = 0; + int pass, last_ret = 0, last_fn = 0, is_kme = 0; unsigned long io_base, ctl_base; ide_hwif_t *hwif; @@ -319,30 +329,15 @@ static int ide_config(struct pcmcia_device *link) if (is_kme) outb(0x81, ctl_base+1); - /* retry registration in case device is still spinning up */ - for (i = 0; i < 10; i++) { - hwif = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link); - if (hwif) - break; - if (link->io.NumPorts1 == 0x20) { + hwif = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link); + if (hwif == NULL && link->io.NumPorts1 == 0x20) { outb(0x02, ctl_base + 0x10); hwif = idecs_register(io_base + 0x10, ctl_base + 0x10, link->irq.AssignedIRQ, link); - if (hwif) { - io_base += 0x10; - ctl_base += 0x10; - break; - } - } - msleep(100); } - if (hwif == NULL) { - printk(KERN_NOTICE "ide-cs: ide_register() at 0x%3lx & 0x%3lx" - ", irq %u failed\n", io_base, ctl_base, - link->irq.AssignedIRQ); + if (hwif == NULL) goto failed; - } info->ndev = 1; sprintf(info->node.dev_name, "hd%c", 'a' + hwif->index * 2); -- cgit v1.2.3 From fbc69fd9b76158daaa83e5372e44fdd81df20f92 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 15 Jun 2008 21:00:23 +0200 Subject: ide-cs: fix releasing I/O resources hwif content is already freed after ide_release() call so cache hwif->io_ports.{data,ctl}_addr in local variables in ide_detach(). This fixes post-2.6.25 regression. Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/legacy/ide-cs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index d08107db54d4..f633b6b3c7f3 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c @@ -135,13 +135,17 @@ static void ide_detach(struct pcmcia_device *link) { ide_info_t *info = link->priv; ide_hwif_t *hwif = info->hwif; + unsigned long data_addr, ctl_addr; DEBUG(0, "ide_detach(0x%p)\n", link); + data_addr = hwif->io_ports.data_addr; + ctl_addr = hwif->io_ports.ctl_addr; + ide_release(link); - release_region(hwif->io_ports.ctl_addr, 1); - release_region(hwif->io_ports.data_addr, 8); + release_region(ctl_addr, 1); + release_region(data_addr, 8); kfree(info); } /* ide_detach */ -- cgit v1.2.3 From 0cbccbc30a60ff60dbeb203154f1f527c632de9b Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Sun, 15 Jun 2008 21:00:24 +0200 Subject: ide-generic: don't probe all legacy ISA IDE ports by default We can't probe all legacy ISA IDE ports by default as the resources may be occupied by other ISA devices. Add "probe_mask" module parameter and probe only first two ISA IDE ports by default leaving the decision about probing the rest to the user (systems with ISA ide2-6 should be very, very rare). This fixes a regression caused by: commit 343a3451e20314d5959b59b992e33fbaadfe52bf Author: Bartlomiej Zolnierkiewicz Date: Tue Jun 10 20:56:36 2008 +0200 ide-generic: add missing hwif->chipset setup ... Reported-by: Mikael Pettersson Bisected-by: Mikael Pettersson Tested-by: Mikael Pettersson Cc: Alan Cox Signed-off-by: Bartlomiej Zolnierkiewicz --- drivers/ide/ide-generic.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c index 9134488ac043..2d92214096ab 100644 --- a/drivers/ide/ide-generic.c +++ b/drivers/ide/ide-generic.c @@ -22,6 +22,10 @@ #define DRV_NAME "ide_generic" +static int probe_mask = 0x03; +module_param(probe_mask, int, 0); +MODULE_PARM_DESC(probe_mask, "probe mask for legacy ISA IDE ports"); + static ssize_t store_add(struct class *cls, const char *buf, size_t n) { ide_hwif_t *hwif; @@ -89,6 +93,9 @@ static int __init ide_generic_init(void) u8 idx[MAX_HWIFS]; int i; + printk(KERN_INFO DRV_NAME ": please use \"probe_mask=0x3f\" module " + "parameter for probing all legacy ISA IDE ports\n"); + for (i = 0; i < MAX_HWIFS; i++) { ide_hwif_t *hwif; unsigned long io_addr = ide_default_io_base(i); @@ -96,7 +103,7 @@ static int __init ide_generic_init(void) idx[i] = 0xff; - if (io_addr) { + if ((probe_mask & (1 << i)) && io_addr) { if (!request_region(io_addr, 8, DRV_NAME)) { printk(KERN_ERR "%s: I/O resource 0x%lX-0x%lX " "not free.\n", -- cgit v1.2.3 From b92dea67cc66970cda6b5b11895d08e35b4618e7 Mon Sep 17 00:00:00 2001 From: Mark McLoughlin Date: Sun, 15 Jun 2008 23:20:50 +1000 Subject: virtio: Complete feature negotation before updating status lguest (in rusty's use-tun-ringfd patch) assumes that the guest has updated its feature bits before setting its status to VIRTIO_CONFIG_S_DRIVER_OK. That's pretty reasonable, so let's make it so. Signed-off-by: Mark McLoughlin Signed-off-by: Rusty Russell Signed-off-by: Linus Torvalds --- drivers/virtio/virtio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 0f3c2bb7bf35..7084e7e146c0 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -124,9 +124,9 @@ static int virtio_dev_probe(struct device *_d) if (err) add_status(dev, VIRTIO_CONFIG_S_FAILED); else { - add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); /* They should never have set feature bits beyond 32 */ dev->config->set_features(dev, dev->features[0]); + add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); } return err; } -- cgit v1.2.3