From 2d925a5b8e7ea244bca1e988df4ce0c6db0c4d07 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Fri, 7 Oct 2011 18:57:45 +0400 Subject: [PATCH 0001/4025] CIFS: Fix incorrect max RFC1002 write size value commit 94443f43404239c2a6dc4252a7cb9e77f5b1eb6e upstream. ..the length field has only 17 bits. Acked-by: Jeff Layton Signed-off-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/connect.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2451627c015..cb85825c741 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2767,10 +2767,10 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info, /* * When the server doesn't allow large posix writes, only allow a wsize of - * 128k minus the size of the WRITE_AND_X header. That allows for a write up + * 2^17-1 minus the size of the WRITE_AND_X header. That allows for a write up * to the maximum size described by RFC1002. */ -#define CIFS_MAX_RFC1002_WSIZE (128 * 1024 - sizeof(WRITE_REQ) + 4) +#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4) /* * The default wsize is 1M. find_get_pages seems to return a maximum of 256 From e842a3e0d2bd01e0e32c0af4ef266f08b9b9ef75 Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Sat, 22 Oct 2011 14:37:50 +0400 Subject: [PATCH 0002/4025] CIFS: Fix DFS handling in cifs_get_file_info commit 42274bb22afc3e877ae5abed787b0b09d7dede52 upstream. We should call cifs_all_info_to_fattr in rc == 0 case only. Signed-off-by: Pavel Shilovsky Reviewed-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/inode.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index a7b2dcd4a53..745e5cdca8f 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -562,7 +562,16 @@ int cifs_get_file_info(struct file *filp) xid = GetXid(); rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data); - if (rc == -EOPNOTSUPP || rc == -EINVAL) { + switch (rc) { + case 0: + cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false); + break; + case -EREMOTE: + cifs_create_dfs_fattr(&fattr, inode->i_sb); + rc = 0; + break; + case -EOPNOTSUPP: + case -EINVAL: /* * FIXME: legacy server -- fall back to path-based call? * for now, just skip revalidating and mark inode for @@ -570,18 +579,14 @@ int cifs_get_file_info(struct file *filp) */ rc = 0; CIFS_I(inode)->time = 0; + default: goto cgfi_exit; - } else if (rc == -EREMOTE) { - cifs_create_dfs_fattr(&fattr, inode->i_sb); - rc = 0; - } else if (rc) - goto cgfi_exit; + } /* * don't bother with SFU junk here -- just mark inode as needing * revalidation. */ - cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false); fattr.cf_uniqueid = CIFS_I(inode)->uniqueid; fattr.cf_flags |= CIFS_FATTR_NEED_REVAL; cifs_fattr_to_inode(inode, &fattr); From 47bbdafa8ab90e3d4b7a4c6dd9bf54f7bc6df66d Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Thu, 1 Sep 2011 13:58:29 +0800 Subject: [PATCH 0003/4025] cris: fix a build error in drivers/tty/serial/crisv10.c commit 2f7861de111bb8e33e6ab9f9607583c6fbc00132 upstream. This patch fixes the following build error: drivers/tty/serial/crisv10.c:4453: error: 'if_ser0' undeclared (first use in this function): 2 errors in 2 logs v3.1-rc4/cris/cris-allmodconfig v3.1-rc4/cris/cris-allyesconfig drivers/tty/serial/crisv10.c:4453: error: (Each undeclared identifier is reported only once: 2 errors in 2 logs v3.1-rc4/cris/cris-allmodconfig v3.1-rc4/cris/cris-allyesconfig drivers/tty/serial/crisv10.c:4453: error: for each function it appears in.): 2 errors in 2 logs v3.1-rc4/cris/cris-allmodconfig v3.1-rc4/cris/cris-allyesconfig "if_ser0" is a typo, it should be "if_serial_0". Cc: Mikael Starvik Cc: Jesper Nilsson Signed-off-by: WANG Cong Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/crisv10.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index 225123b37f1..58be715913c 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -4450,7 +4450,7 @@ static int __init rs_init(void) #if defined(CONFIG_ETRAX_RS485) #if defined(CONFIG_ETRAX_RS485_ON_PA) - if (cris_io_interface_allocate_pins(if_ser0, 'a', rs485_pa_bit, + if (cris_io_interface_allocate_pins(if_serial_0, 'a', rs485_pa_bit, rs485_pa_bit)) { printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " "RS485 pin\n"); @@ -4459,7 +4459,7 @@ static int __init rs_init(void) } #endif #if defined(CONFIG_ETRAX_RS485_ON_PORT_G) - if (cris_io_interface_allocate_pins(if_ser0, 'g', rs485_pa_bit, + if (cris_io_interface_allocate_pins(if_serial_0, 'g', rs485_pa_bit, rs485_port_g_bit)) { printk(KERN_CRIT "ETRAX100LX serial: Could not allocate " "RS485 pin\n"); From 36174dd629350d0654982977d7795ca28475c16f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 12 Oct 2011 11:32:42 +0200 Subject: [PATCH 0004/4025] TTY: drop driver reference in tty_open fail path commit c290f8358acaeffd8e0c551ddcc24d1206143376 upstream. When tty_driver_lookup_tty fails in tty_open, we forget to drop a reference to the tty driver. This was added by commit 4a2b5fddd5 (Move tty lookup/reopen to caller). Fix that by adding tty_driver_kref_put to the fail path. I will refactor the code later. This is for the ease of backporting to stable. Introduced-in: v2.6.28-rc2 Signed-off-by: Jiri Slaby Cc: Alan Cox Acked-by: Sukadev Bhattiprolu Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index b6f92d3001a..e9495ed8ec0 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1872,6 +1872,7 @@ static int tty_open(struct inode *inode, struct file *filp) if (IS_ERR(tty)) { tty_unlock(); mutex_unlock(&tty_mutex); + tty_driver_kref_put(driver); return PTR_ERR(tty); } } From 0c1f111ae7fcea822fd1c078ef48e88d93afc57a Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 12 Oct 2011 11:32:43 +0200 Subject: [PATCH 0005/4025] TTY: make tty_add_file non-failing commit fa90e1c935472281de314e6d7c9a37db9cbc2e4e upstream. If tty_add_file fails at the point it is now, we have to revert all the changes we did to the tty. It means either decrease all refcounts if this was a tty reopen or delete the tty if it was newly allocated. There was a try to fix this in v3.0-rc2 using tty_release in 0259894c7 (TTY: fix fail path in tty_open). But instead it introduced a NULL dereference. It's because tty_release dereferences filp->private_data, but that one is set even in our tty_add_file. And when tty_add_file fails, it's still NULL/garbage. Hence tty_release cannot be called there. To circumvent the original leak (and the current NULL deref) we split tty_add_file into two functions, making the latter non-failing. In that case we may do the former early in open, where handling failures is easy. The latter stays as it is now. So there is no change in functionality. The original bug (leak) was introduced by f573bd176 (tty: Remove __GFP_NOFAIL from tty_add_file()). Thanks Dan for reporting this. Later, we may split tty_release into more functions and call only some of them in this fail path instead. (If at all possible.) Introduced-in: v2.6.37-rc2 Signed-off-by: Jiri Slaby Reported-by: Dan Carpenter Cc: Alan Cox Cc: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/tty/pty.c | 16 ++++++++++----- drivers/tty/tty_io.c | 47 +++++++++++++++++++++++++++++++++----------- include/linux/tty.h | 4 +++- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index e809e9d4683..696e8510a5f 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -670,12 +670,18 @@ static int ptmx_open(struct inode *inode, struct file *filp) nonseekable_open(inode, filp); + retval = tty_alloc_file(filp); + if (retval) + return retval; + /* find a device that is not in use. */ tty_lock(); index = devpts_new_index(inode); tty_unlock(); - if (index < 0) - return index; + if (index < 0) { + retval = index; + goto err_file; + } mutex_lock(&tty_mutex); tty_lock(); @@ -689,9 +695,7 @@ static int ptmx_open(struct inode *inode, struct file *filp) set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ - retval = tty_add_file(tty, filp); - if (retval) - goto out; + tty_add_file(tty, filp); retval = devpts_pty_new(inode, tty->link); if (retval) @@ -710,6 +714,8 @@ static int ptmx_open(struct inode *inode, struct file *filp) out: devpts_kill_index(inode, index); tty_unlock(); +err_file: + tty_free_file(filp); return retval; } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index e9495ed8ec0..b44aef078f1 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -193,8 +193,7 @@ static inline struct tty_struct *file_tty(struct file *file) return ((struct tty_file_private *)file->private_data)->tty; } -/* Associate a new file with the tty structure */ -int tty_add_file(struct tty_struct *tty, struct file *file) +int tty_alloc_file(struct file *file) { struct tty_file_private *priv; @@ -202,15 +201,36 @@ int tty_add_file(struct tty_struct *tty, struct file *file) if (!priv) return -ENOMEM; + file->private_data = priv; + + return 0; +} + +/* Associate a new file with the tty structure */ +void tty_add_file(struct tty_struct *tty, struct file *file) +{ + struct tty_file_private *priv = file->private_data; + priv->tty = tty; priv->file = file; - file->private_data = priv; spin_lock(&tty_files_lock); list_add(&priv->list, &tty->tty_files); spin_unlock(&tty_files_lock); +} - return 0; +/** + * tty_free_file - free file->private_data + * + * This shall be used only for fail path handling when tty_add_file was not + * called yet. + */ +void tty_free_file(struct file *file) +{ + struct tty_file_private *priv = file->private_data; + + file->private_data = NULL; + kfree(priv); } /* Delete file from its tty */ @@ -221,8 +241,7 @@ void tty_del_file(struct file *file) spin_lock(&tty_files_lock); list_del(&priv->list); spin_unlock(&tty_files_lock); - file->private_data = NULL; - kfree(priv); + tty_free_file(file); } @@ -1811,6 +1830,10 @@ static int tty_open(struct inode *inode, struct file *filp) nonseekable_open(inode, filp); retry_open: + retval = tty_alloc_file(filp); + if (retval) + return -ENOMEM; + noctty = filp->f_flags & O_NOCTTY; index = -1; retval = 0; @@ -1823,6 +1846,7 @@ static int tty_open(struct inode *inode, struct file *filp) if (!tty) { tty_unlock(); mutex_unlock(&tty_mutex); + tty_free_file(filp); return -ENXIO; } driver = tty_driver_kref_get(tty->driver); @@ -1855,6 +1879,7 @@ static int tty_open(struct inode *inode, struct file *filp) } tty_unlock(); mutex_unlock(&tty_mutex); + tty_free_file(filp); return -ENODEV; } @@ -1862,6 +1887,7 @@ static int tty_open(struct inode *inode, struct file *filp) if (!driver) { tty_unlock(); mutex_unlock(&tty_mutex); + tty_free_file(filp); return -ENODEV; } got_driver: @@ -1873,6 +1899,7 @@ static int tty_open(struct inode *inode, struct file *filp) tty_unlock(); mutex_unlock(&tty_mutex); tty_driver_kref_put(driver); + tty_free_file(filp); return PTR_ERR(tty); } } @@ -1888,15 +1915,11 @@ static int tty_open(struct inode *inode, struct file *filp) tty_driver_kref_put(driver); if (IS_ERR(tty)) { tty_unlock(); + tty_free_file(filp); return PTR_ERR(tty); } - retval = tty_add_file(tty, filp); - if (retval) { - tty_unlock(); - tty_release(inode, filp); - return retval; - } + tty_add_file(tty, filp); check_tty_count(tty, "tty_open"); if (tty->driver->type == TTY_DRIVER_TYPE_PTY && diff --git a/include/linux/tty.h b/include/linux/tty.h index 6660c41949b..1ff6b62fb69 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -472,7 +472,9 @@ extern void proc_clear_tty(struct task_struct *p); extern struct tty_struct *get_current_tty(void); extern void tty_default_fops(struct file_operations *fops); extern struct tty_struct *alloc_tty_struct(void); -extern int tty_add_file(struct tty_struct *tty, struct file *file); +extern int tty_alloc_file(struct file *file); +extern void tty_add_file(struct tty_struct *tty, struct file *file); +extern void tty_free_file(struct file *file); extern void free_tty_struct(struct tty_struct *tty); extern void initialize_tty_struct(struct tty_struct *tty, struct tty_driver *driver, int idx); From eece93cccb258072bf9a355faeca2ee2752b27e3 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 12 Oct 2011 11:32:44 +0200 Subject: [PATCH 0006/4025] TTY: pty, release tty in all ptmx_open fail paths commit 1177c0efc04d032644895b8d757f55b433912596 upstream. Mistakenly, commit 64ba3dc3143d (tty: never hold BTM while getting tty_mutex) switched one fail path in ptmx_open to not free the newly allocated tty. Fix that by jumping to the appropriate place. And rename the labels so that it's clear what is going on there. Introduced-in: v2.6.36-rc2 Signed-off-by: Jiri Slaby Cc: Arnd Bergmann Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/pty.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 696e8510a5f..e18604b3fc7 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -699,15 +699,15 @@ static int ptmx_open(struct inode *inode, struct file *filp) retval = devpts_pty_new(inode, tty->link); if (retval) - goto out1; + goto err_release; retval = ptm_driver->ops->open(tty, filp); if (retval) - goto out2; -out1: + goto err_release; + tty_unlock(); - return retval; -out2: + return 0; +err_release: tty_unlock(); tty_release(inode, filp); return retval; From e46389fa0026dd3bbaebf92a525dad3e80b7bce2 Mon Sep 17 00:00:00 2001 From: Jim Wylder Date: Tue, 6 Sep 2011 21:07:20 -0500 Subject: [PATCH 0007/4025] USB: for usb_autopm_get_interface_async -EINPROGRESS is not an error commit c5a48592d874ddef8c7880311581eccf0eb30c3b upstream. A return value of -EINPROGRESS from pm_runtime_get indicates that the device is already resuming due to a previous call. Internally, usb_autopm_get_interface_async doesn't treat this as an error and increments the usage count, but passes the error status along to the caller. The logical assumption of the caller is that any negative return value reflects the device not resuming and the pm_usage_cnt not being incremented. Since the usage count is being incremented and the device is resuming, return success (0) instead. Signed-off-by: James Wylder Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 34e3da5aa72..14b83f2a4e8 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1583,7 +1583,7 @@ int usb_autopm_get_interface_async(struct usb_interface *intf) dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n", __func__, atomic_read(&intf->dev.power.usage_count), status); - if (status > 0) + if (status > 0 || status == -EINPROGRESS) status = 0; return status; } From da7061614e7d11f0a0db96a5f507feca4ac9fa17 Mon Sep 17 00:00:00 2001 From: Bill Pemberton Date: Mon, 29 Aug 2011 13:48:54 -0400 Subject: [PATCH 0008/4025] staging: serqt_usb2: remove ssu100 from supported devices commit 7cbf3c7cd59288fb5e9f31815c74773549668d43 upstream. The serqt_usb2 driver will not work properly with the ssu100 device even though it claims to support it. The ssu100 is supported by the ssu100 driver in mainline so there is no need to have it claimed by serqt_usb2. Signed-off-by: Bill Pemberton Signed-off-by: Greg Kroah-Hartman --- drivers/staging/serqt_usb2/serqt_usb2.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c index 12f5eba0355..48aa61eb9c7 100644 --- a/drivers/staging/serqt_usb2/serqt_usb2.c +++ b/drivers/staging/serqt_usb2/serqt_usb2.c @@ -24,7 +24,6 @@ static int debug; #define DRIVER_DESC "Quatech USB to Serial Driver" #define USB_VENDOR_ID_QUATECH 0x061d /* Quatech VID */ -#define QUATECH_SSU100 0xC020 /* SSU100 */ #define QUATECH_SSU200 0xC030 /* SSU200 */ #define QUATECH_DSU100 0xC040 /* DSU100 */ #define QUATECH_DSU200 0xC050 /* DSU200 */ @@ -127,7 +126,6 @@ static int debug; #define RS232_MODE 0x00 static const struct usb_device_id serqt_id_table[] = { - {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100)}, {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU200)}, {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU100)}, {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU200)}, @@ -775,7 +773,6 @@ static int qt_startup(struct usb_serial *serial) } switch (serial->dev->descriptor.idProduct) { - case QUATECH_SSU100: case QUATECH_DSU100: case QUATECH_QSU100: case QUATECH_ESU100A: From 828ed1259f73a85d47b417edd84e02bbbb52bb87 Mon Sep 17 00:00:00 2001 From: Kautuk Consul Date: Wed, 14 Sep 2011 08:56:21 +0530 Subject: [PATCH 0009/4025] staging: quatech_usb2: Potential lost wakeup scenario in TIOCMIWAIT commit e8df1674d383d2ecc6efa8d7dba74c03aafdfdd7 upstream. If the usermode app does an ioctl over this serial device by using TIOCMIWAIT, then the code will wait by setting the current task state to TASK_INTERRUPTIBLE and then calling schedule(). This will be woken up by the qt2_process_modem_status on URB completion when the port_extra->shadowMSR is set to the new modem status. However, this could result in a lost wakeup scenario due to a race in the logic in the qt2_ioctl(TIOCMIWAIT) loop and the URB completion for new modem status in qt2_process_modem_status. Due to this, the usermode app's task will continue to sleep despite a change in the modem status. Signed-off-by: Kautuk Consul Signed-off-by: Greg Kroah-Hartman --- drivers/staging/quatech_usb2/quatech_usb2.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/staging/quatech_usb2/quatech_usb2.c b/drivers/staging/quatech_usb2/quatech_usb2.c index ca098cabc2b..02fafecd477 100644 --- a/drivers/staging/quatech_usb2/quatech_usb2.c +++ b/drivers/staging/quatech_usb2/quatech_usb2.c @@ -916,9 +916,10 @@ static int qt2_ioctl(struct tty_struct *tty, dbg("%s() port %d, cmd == TIOCMIWAIT enter", __func__, port->number); prev_msr_value = port_extra->shadowMSR & QT2_SERIAL_MSR_MASK; + barrier(); + __set_current_state(TASK_INTERRUPTIBLE); while (1) { add_wait_queue(&port_extra->wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); schedule(); dbg("%s(): port %d, cmd == TIOCMIWAIT here\n", __func__, port->number); @@ -926,9 +927,12 @@ static int qt2_ioctl(struct tty_struct *tty, /* see if a signal woke us up */ if (signal_pending(current)) return -ERESTARTSYS; + set_current_state(TASK_INTERRUPTIBLE); msr_value = port_extra->shadowMSR & QT2_SERIAL_MSR_MASK; - if (msr_value == prev_msr_value) + if (msr_value == prev_msr_value) { + __set_current_state(TASK_RUNNING); return -EIO; /* no change - error */ + } if ((arg & TIOCM_RNG && ((prev_msr_value & QT2_SERIAL_MSR_RI) == (msr_value & QT2_SERIAL_MSR_RI))) || @@ -941,6 +945,7 @@ static int qt2_ioctl(struct tty_struct *tty, (arg & TIOCM_CTS && ((prev_msr_value & QT2_SERIAL_MSR_CTS) == (msr_value & QT2_SERIAL_MSR_CTS)))) { + __set_current_state(TASK_RUNNING); return 0; } } /* end inifinite while */ From 70908d994241bb79e4f3c546f6ddd262567610c6 Mon Sep 17 00:00:00 2001 From: Mike Sterling Date: Tue, 6 Sep 2011 16:10:55 -0700 Subject: [PATCH 0010/4025] Staging: hv: Add support for >2 TB LUN in storage driver. commit cf55f4a8b6243b42fb91c56d1421db0d36d60f96 upstream. If a LUN larger than 2 TB is attached to a Linux VM on Hyper-V, we currently report a maximum size of 2 TB. This patch resolves the issue in hv_storvsc. Thanks to Robert Scheck for reporting the issue. Reported-by: Robert Scheck Signed-off-by: Mike Sterling Signed-off-by: K.Y. Srinivasan Signed-off-by: Haiyang Zhang Signed-off-by: Greg Kroah-Hartman --- drivers/staging/hv/hyperv_storage.h | 1 + drivers/staging/hv/storvsc_drv.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/staging/hv/hyperv_storage.h b/drivers/staging/hv/hyperv_storage.h index a01f9a07c98..5af82f4235b 100644 --- a/drivers/staging/hv/hyperv_storage.h +++ b/drivers/staging/hv/hyperv_storage.h @@ -218,6 +218,7 @@ struct vstor_packet { #define STORVSC_MAX_LUNS_PER_TARGET 64 #define STORVSC_MAX_TARGETS 1 #define STORVSC_MAX_CHANNELS 1 +#define STORVSC_MAX_CMD_LEN 16 struct hv_storvsc_request; diff --git a/drivers/staging/hv/storvsc_drv.c b/drivers/staging/hv/storvsc_drv.c index cb4a25b0831..734076b41bf 100644 --- a/drivers/staging/hv/storvsc_drv.c +++ b/drivers/staging/hv/storvsc_drv.c @@ -729,6 +729,8 @@ static int storvsc_probe(struct hv_device *device) host->max_id = STORVSC_MAX_TARGETS; /* max # of channels */ host->max_channel = STORVSC_MAX_CHANNELS - 1; + /* max cmd length */ + host->max_cmd_len = STORVSC_MAX_CMD_LEN; /* Register the HBA and start the scsi bus scan */ ret = scsi_add_host(host, &device->device); From 285c6b4b3be21529ec5dbdfb1a6d48a3aa31d0c7 Mon Sep 17 00:00:00 2001 From: Richard Hartmann Date: Tue, 20 Sep 2011 20:50:51 +0200 Subject: [PATCH 0011/4025] USB: qcserial: Add support for Sierra Wireless MC8355/Gobi 3000 commit 68c79e5756903229fa96826a2493c2265a3b395f upstream. Simple patch to make qcserial recognize the USB id of the Sierra Wireless MC8355 which is based on the Gobi 3000 chip. Both UMTS and GPS work fine. Signed-off-by: Richard Hartmann Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/qcserial.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 27f9ae4dffd..ca79bfa9668 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -83,6 +83,7 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ {USB_DEVICE(0x05c6, 0x9204)}, /* Gobi 2000 QDL device */ {USB_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ + {USB_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table); From ee5ad2bab31967d0d836e56c10e57e74145df151 Mon Sep 17 00:00:00 2001 From: Rigbert Hamisch Date: Tue, 27 Sep 2011 10:46:43 +0200 Subject: [PATCH 0012/4025] USB: qcserial: add device ID for "HP un2430 Mobile Broadband Module" commit 1bfac90d1b8e63a4d44158c3445d8fda3fb6d5eb upstream. add device ID for "HP un2430 Mobile Broadband Module" Signed-off-by: Rigbert Hamisch Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/qcserial.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index ca79bfa9668..7ec639860c5 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -28,6 +28,7 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ {USB_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ {USB_DEVICE(0x03f0, 0x201d)}, /* HP un2400 Gobi QDL Device */ + {USB_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */ {USB_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ {USB_DEVICE(0x04da, 0x250c)}, /* Panasonic Gobi QDL device */ {USB_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */ From d5fe5d1648b88aa16b5d97d088d9b743bc9ce0a8 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Tue, 30 Aug 2011 13:53:10 +0200 Subject: [PATCH 0013/4025] serial: pxa: work around for errata #20 commit e44aabd649c80e8be16ede3ed3cbff6fb2561ca9 upstream. Errata E20: UART: Character Timeout interrupt remains set under certain software conditions. Implication: The software servicing the UART can be trapped in an infinite loop. Signed-off-by: Marcus Folkesson Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pxa.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index 4302e6e3768..81243a62dd5 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -100,6 +100,16 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status) int max_count = 256; do { + /* work around Errata #20 according to + * Intel(R) PXA27x Processor Family + * Specification Update (May 2005) + * + * Step 2 + * Disable the Reciever Time Out Interrupt via IER[RTOEI] + */ + up->ier &= ~UART_IER_RTOIE; + serial_out(up, UART_IER, up->ier); + ch = serial_in(up, UART_RX); flag = TTY_NORMAL; up->port.icount.rx++; @@ -156,6 +166,16 @@ static inline void receive_chars(struct uart_pxa_port *up, int *status) *status = serial_in(up, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); tty_flip_buffer_push(tty); + + /* work around Errata #20 according to + * Intel(R) PXA27x Processor Family + * Specification Update (May 2005) + * + * Step 6: + * No more data in FIFO: Re-enable RTO interrupt via IER[RTOIE] + */ + up->ier |= UART_IER_RTOIE; + serial_out(up, UART_IER, up->ier); } static void transmit_chars(struct uart_pxa_port *up) From 3e9efdd45f78e0ad859b60906c6556e8efe2579b Mon Sep 17 00:00:00 2001 From: Ning Jiang Date: Mon, 5 Sep 2011 16:28:18 +0800 Subject: [PATCH 0014/4025] serial-core: power up uart port early before we do set_termios when resuming commit 94abc56f4d90f289ea32a0a11d3577fcd8cb28fb upstream. The following patch removed uart_change_pm() in uart_resume_port(): commit 5933a161abcb8d83a2c145177f48027c3c0a8995 Author: Yin Kangkai serial-core: reset the console speed on resume It will break the pxa serial driver when the system resumes from suspend mode as it will try to set baud rate divider register in set_termios but with clock off. The register value can not be set correctly on some platform if the clock is disabled. The pxa driver will check the value and report the following warning: ------------[ cut here ]------------ WARNING: at drivers/tty/serial/pxa.c:545 serial_pxa_set_termios+0x1dc/0x250() Modules linked in: [] (unwind_backtrace+0x0/0xf0) from [] (warn_slowpath_common+0x4c/0x64) [] (warn_slowpath_common+0x4c/0x64) from [] (warn_slowpath_null+0x18/0x1c) [] (warn_slowpath_null+0x18/0x1c) from [] (serial_pxa_set_termios+0x1dc/0x250) [] (serial_pxa_set_termios+0x1dc/0x250) from [] (uart_resume_port+0x128/0x2dc) [] (uart_resume_port+0x128/0x2dc) from [] (serial_pxa_resume+0x18/0x24) [] (serial_pxa_resume+0x18/0x24) from [] (platform_pm_resume+0x40/0x4c) [] (platform_pm_resume+0x40/0x4c) from [] (pm_op+0x68/0xb4) [] (pm_op+0x68/0xb4) from [] (device_resume+0xb0/0xec) [] (device_resume+0xb0/0xec) from [] (dpm_resume+0xe0/0x194) [] (dpm_resume+0xe0/0x194) from [] (dpm_resume_end+0xc/0x18) [] (dpm_resume_end+0xc/0x18) from [] (suspend_devices_and_enter+0x16c/0x1ac) [] (suspend_devices_and_enter+0x16c/0x1ac) from [] (enter_state+0xac/0xdc) [] (enter_state+0xac/0xdc) from [] (state_store+0xa0/0xbc) [] (state_store+0xa0/0xbc) from [] (kobj_attr_store+0x18/0x1c) [] (kobj_attr_store+0x18/0x1c) from [] (sysfs_write_file+0x108/0x140) [] (sysfs_write_file+0x108/0x140) from [] (vfs_write+0xac/0x134) [] (vfs_write+0xac/0x134) from [] (sys_write+0x3c/0x68) [] (sys_write+0x3c/0x68) from [] (ret_fast_syscall+0x0/0x2c) ---[ end trace 88289eceb4675b04 ]--- This patch fix the problem by adding the power on opertion back for uart console when console_suspend_enabled is true. Signed-off-by: Ning Jiang Tested-by: Mayank Rana Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index db7912cb7ae..6bc20d77395 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -2003,6 +2003,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) if (port->tty && port->tty->termios && termios.c_cflag == 0) termios = *(port->tty->termios); + if (console_suspend_enabled) + uart_change_pm(state, 0); uport->ops->set_termios(uport, &termios, NULL); if (console_suspend_enabled) console_start(uport->cons); From cd0712116761eed1500b2272a5492d2120c30f26 Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Sat, 2 Jul 2011 19:47:33 +0200 Subject: [PATCH 0015/4025] EHCI : introduce a common ehci_setup commit 2093c6b49c8f1dc581d8953aca71297d4cace55e upstream. This allow to clean duplicated code in most of SOC driver. Signed-off-by: Matthieu CASTET Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hcd.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 9ff9abc7e3a..c45a116f50f 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -761,6 +761,35 @@ static int ehci_run (struct usb_hcd *hcd) return 0; } +static int __maybe_unused ehci_setup (struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int retval; + + ehci->regs = (void __iomem *)ehci->caps + + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); + dbg_hcs_params(ehci, "reset"); + dbg_hcc_params(ehci, "reset"); + + /* cache this readonly data; minimize chip reads */ + ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); + + ehci->sbrn = HCD_USB2; + + retval = ehci_halt(ehci); + if (retval) + return retval; + + /* data structure init */ + retval = ehci_init(hcd); + if (retval) + return retval; + + ehci_reset(ehci); + + return 0; +} + /*-------------------------------------------------------------------------*/ static irqreturn_t ehci_irq (struct usb_hcd *hcd) From 7eede2cbc1066124a0a4fee4d9671e28f7c62277 Mon Sep 17 00:00:00 2001 From: Harro Haan Date: Mon, 10 Oct 2011 14:38:27 +0200 Subject: [PATCH 0016/4025] USB: fix ehci alignment error commit 276532ba9666b36974cbe16f303fc8be99c9da17 upstream. The Kirkwood gave an unaligned memory access error on line 742 of drivers/usb/host/echi-hcd.c: "ehci->last_periodic_enable = ktime_get_real();" Signed-off-by: Harro Haan Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/hcd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 0097136ba45..c0ecc5a2ef9 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -178,7 +178,7 @@ struct usb_hcd { * this structure. */ unsigned long hcd_priv[0] - __attribute__ ((aligned(sizeof(unsigned long)))); + __attribute__ ((aligned(sizeof(s64)))); }; /* 2.4 does this a bit differently ... */ From 21f25cdb9e476c64d504981133d0552f7d155805 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 12 Oct 2011 10:39:14 -0400 Subject: [PATCH 0017/4025] EHCI: workaround for MosChip controller bug commit 68aa95d5d4de31c9348c1628ffa85c805305ebc5 upstream. This patch (as1489) works around a hardware bug in MosChip EHCI controllers. Evidently when one of these controllers increments the frame-index register, it changes the three low-order bits (the microframe counter) before changing the higher order bits (the frame counter). If the register is read at just the wrong time, the value obtained is too low by 8. When the appropriate quirk flag is set, we work around this problem by reading the frame-index register a second time if the first value's three low-order bits are all 0. This gives the hardware a chance to finish updating the register, yielding the correct value. Signed-off-by: Alan Stern Tested-by: Jason N Pitt Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-dbg.c | 2 +- drivers/usb/host/ehci-hcd.c | 3 +-- drivers/usb/host/ehci-pci.c | 5 +++++ drivers/usb/host/ehci-sched.c | 30 +++++++++++++++++++++++++----- drivers/usb/host/ehci.h | 17 +++++++++++++++++ 5 files changed, 49 insertions(+), 8 deletions(-) diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 40a844c1dbb..3e2ccb0dd25 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -808,7 +808,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf) next += temp; temp = scnprintf (next, size, "uframe %04x\n", - ehci_readl(ehci, &ehci->regs->frame_index)); + ehci_read_frame_index(ehci)); size -= temp; next += temp; diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index c45a116f50f..b27ceab1774 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1188,8 +1188,7 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) static int ehci_get_frame (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); - return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) % - ehci->periodic_size; + return (ehci_read_frame_index(ehci) >> 3) % ehci->periodic_size; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 1102ce65a3a..1d1caa6a33f 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -224,6 +224,11 @@ static int ehci_pci_setup(struct usb_hcd *hcd) pci_dev_put(p_smbus); } break; + case PCI_VENDOR_ID_NETMOS: + /* MosChip frame-index-register bug */ + ehci_info(ehci, "applying MosChip frame-index workaround\n"); + ehci->frame_index_bug = 1; + break; } /* optional debug port, normally in the first BAR */ diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 6c9fbe352f7..063c630d246 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -36,6 +36,27 @@ static int ehci_get_frame (struct usb_hcd *hcd); +#ifdef CONFIG_PCI + +static unsigned ehci_read_frame_index(struct ehci_hcd *ehci) +{ + unsigned uf; + + /* + * The MosChip MCS9990 controller updates its microframe counter + * a little before the frame counter, and occasionally we will read + * the invalid intermediate value. Avoid problems by checking the + * microframe number (the low-order 3 bits); if they are 0 then + * re-read the register to get the correct value. + */ + uf = ehci_readl(ehci, &ehci->regs->frame_index); + if (unlikely(ehci->frame_index_bug && ((uf & 7) == 0))) + uf = ehci_readl(ehci, &ehci->regs->frame_index); + return uf; +} + +#endif + /*-------------------------------------------------------------------------*/ /* @@ -482,7 +503,7 @@ static int enable_periodic (struct ehci_hcd *ehci) ehci_to_hcd(ehci)->state = HC_STATE_RUNNING; /* make sure ehci_work scans these */ - ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index) + ehci->next_uframe = ehci_read_frame_index(ehci) % (ehci->periodic_size << 3); if (unlikely(ehci->broken_periodic)) ehci->last_periodic_enable = ktime_get_real(); @@ -1412,7 +1433,7 @@ iso_stream_schedule ( goto fail; } - now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1); + now = ehci_read_frame_index(ehci) & (mod - 1); /* Typical case: reuse current schedule, stream is still active. * Hopefully there are no gaps from the host falling behind @@ -2279,7 +2300,7 @@ scan_periodic (struct ehci_hcd *ehci) */ now_uframe = ehci->next_uframe; if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) { - clock = ehci_readl(ehci, &ehci->regs->frame_index); + clock = ehci_read_frame_index(ehci); clock_frame = (clock >> 3) & (ehci->periodic_size - 1); } else { clock = now_uframe + mod - 1; @@ -2458,8 +2479,7 @@ scan_periodic (struct ehci_hcd *ehci) || ehci->periodic_sched == 0) break; ehci->next_uframe = now_uframe; - now = ehci_readl(ehci, &ehci->regs->frame_index) & - (mod - 1); + now = ehci_read_frame_index(ehci) & (mod - 1); if (now_uframe == now) break; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 989e0a8e01f..3ffb27f472c 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -137,6 +137,7 @@ struct ehci_hcd { /* one per controller */ unsigned fs_i_thresh:1; /* Intel iso scheduling */ unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/ unsigned has_synopsys_hc_bug:1; /* Synopsys HC */ + unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ /* required for usb32 quirk */ #define OHCI_CTRL_HCFS (3 << 6) @@ -738,6 +739,22 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x) /*-------------------------------------------------------------------------*/ +#ifdef CONFIG_PCI + +/* For working around the MosChip frame-index-register bug */ +static unsigned ehci_read_frame_index(struct ehci_hcd *ehci); + +#else + +static inline unsigned ehci_read_frame_index(struct ehci_hcd *ehci) +{ + return ehci_readl(ehci, &ehci->regs->frame_index); +} + +#endif + +/*-------------------------------------------------------------------------*/ + #ifndef DEBUG #define STUB_DEBUG_FILES #endif /* DEBUG */ From fb71face21504aaf924e6084abee9512bb1f2f29 Mon Sep 17 00:00:00 2001 From: Kautuk Consul Date: Mon, 19 Sep 2011 16:53:12 -0700 Subject: [PATCH 0018/4025] xhci-mem.c: Check for ring->first_seg != NULL commit 0e6c7f746ea99089fb3263709075c20485a479ae upstream. There are 2 situations wherein the xhci_ring* might not get freed: - When xhci_ring_alloc() -> xhci_segment_alloc() returns NULL and we goto the fail: label in xhci_ring_alloc. In this case, the ring will not get kfreed. - When the num_segs argument to xhci_ring_alloc is passed as 0 and we try to free the rung after that. ( This doesn't really happen as of now in the code but we seem to be entertaining num_segs=0 in xhci_ring_alloc ) This should be backported to kernels as old as 2.6.31. Signed-off-by: Kautuk Consul Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index fcb7f7efc86..d1687046049 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -112,18 +112,20 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring) struct xhci_segment *seg; struct xhci_segment *first_seg; - if (!ring || !ring->first_seg) + if (!ring) return; - first_seg = ring->first_seg; - seg = first_seg->next; - xhci_dbg(xhci, "Freeing ring at %p\n", ring); - while (seg != first_seg) { - struct xhci_segment *next = seg->next; - xhci_segment_free(xhci, seg); - seg = next; + if (ring->first_seg) { + first_seg = ring->first_seg; + seg = first_seg->next; + xhci_dbg(xhci, "Freeing ring at %p\n", ring); + while (seg != first_seg) { + struct xhci_segment *next = seg->next; + xhci_segment_free(xhci, seg); + seg = next; + } + xhci_segment_free(xhci, first_seg); + ring->first_seg = NULL; } - xhci_segment_free(xhci, first_seg); - ring->first_seg = NULL; kfree(ring); } From 5c7a6982e976b381595c9d4ee8e8c94564a40aec Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Fri, 23 Sep 2011 14:19:54 -0700 Subject: [PATCH 0019/4025] xHCI: AMD isoc link TRB chain bit quirk commit 7e393a834b41001174a8fb3ae3bc23a749467760 upstream. Setting the chain (CH) bit in the link TRB of isochronous transfer rings is required by AMD 0.96 xHCI host controller to successfully transverse multi-TRB TD that span through different memory segments. When a Missed Service Error event occurs, if the chain bit is not set in the link TRB and the host skips TDs which just across a link TRB, the host may falsely recognize the link TRB as a normal TRB. You can see this may cause big trouble - the host does not jump to the right address which is pointed by the link TRB, but continue fetching the memory which is after the link TRB address, which may not even belong to the host, and the result cannot be predicted. This causes some big problems. Without the former patch I sent: "xHCI: prevent infinite loop when processing MSE event", the system may hang. With that patch applied, system does not hang, but the host still access wrong memory address and isoc transfer will fail. With this patch, isochronous transfer works as expected. This patch should be applied to kernels as old as 2.6.36, which was when the first isochronous support was added for the xHCI host controller. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 32 ++++++++++++---------- drivers/usb/host/xhci-pci.c | 3 ++ drivers/usb/host/xhci-ring.c | 53 ++++++++++++++++++++---------------- drivers/usb/host/xhci.h | 1 + 4 files changed, 51 insertions(+), 38 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d1687046049..104620b3764 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -81,7 +81,7 @@ static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg) * related flags, such as End TRB, Toggle Cycle, and no snoop. */ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev, - struct xhci_segment *next, bool link_trbs) + struct xhci_segment *next, bool link_trbs, bool isoc) { u32 val; @@ -97,7 +97,9 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev, val &= ~TRB_TYPE_BITMASK; val |= TRB_TYPE(TRB_LINK); /* Always set the chain bit with 0.95 hardware */ - if (xhci_link_trb_quirk(xhci)) + /* Set chain bit for isoc rings on AMD 0.96 host */ + if (xhci_link_trb_quirk(xhci) || + (isoc && (xhci->quirks & XHCI_AMD_0x96_HOST))) val |= TRB_CHAIN; prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val); } @@ -154,7 +156,7 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring) * See section 4.9.1 and figures 15 and 16. */ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, - unsigned int num_segs, bool link_trbs, gfp_t flags) + unsigned int num_segs, bool link_trbs, bool isoc, gfp_t flags) { struct xhci_ring *ring; struct xhci_segment *prev; @@ -180,12 +182,12 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci, next = xhci_segment_alloc(xhci, flags); if (!next) goto fail; - xhci_link_segments(xhci, prev, next, link_trbs); + xhci_link_segments(xhci, prev, next, link_trbs, isoc); prev = next; num_segs--; } - xhci_link_segments(xhci, prev, ring->first_seg, link_trbs); + xhci_link_segments(xhci, prev, ring->first_seg, link_trbs, isoc); if (link_trbs) { /* See section 4.9.2.1 and 6.4.4.1 */ @@ -231,14 +233,14 @@ void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci, * pointers to the beginning of the ring. */ static void xhci_reinit_cached_ring(struct xhci_hcd *xhci, - struct xhci_ring *ring) + struct xhci_ring *ring, bool isoc) { struct xhci_segment *seg = ring->first_seg; do { memset(seg->trbs, 0, sizeof(union xhci_trb)*TRBS_PER_SEGMENT); /* All endpoint rings have link TRBs */ - xhci_link_segments(xhci, seg, seg->next, 1); + xhci_link_segments(xhci, seg, seg->next, 1, isoc); seg = seg->next; } while (seg != ring->first_seg); xhci_initialize_ring_info(ring); @@ -542,7 +544,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, */ for (cur_stream = 1; cur_stream < num_streams; cur_stream++) { stream_info->stream_rings[cur_stream] = - xhci_ring_alloc(xhci, 1, true, mem_flags); + xhci_ring_alloc(xhci, 1, true, false, mem_flags); cur_ring = stream_info->stream_rings[cur_stream]; if (!cur_ring) goto cleanup_rings; @@ -767,7 +769,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, } /* Allocate endpoint 0 ring */ - dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, flags); + dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, false, flags); if (!dev->eps[0].ring) goto fail; @@ -1177,10 +1179,10 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, */ if (usb_endpoint_xfer_isoc(&ep->desc)) virt_dev->eps[ep_index].new_ring = - xhci_ring_alloc(xhci, 8, true, mem_flags); + xhci_ring_alloc(xhci, 8, true, true, mem_flags); else virt_dev->eps[ep_index].new_ring = - xhci_ring_alloc(xhci, 1, true, mem_flags); + xhci_ring_alloc(xhci, 1, true, false, mem_flags); if (!virt_dev->eps[ep_index].new_ring) { /* Attempt to use the ring cache */ if (virt_dev->num_rings_cached == 0) @@ -1189,7 +1191,8 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, virt_dev->ring_cache[virt_dev->num_rings_cached]; virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL; virt_dev->num_rings_cached--; - xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring); + xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring, + usb_endpoint_xfer_isoc(&ep->desc) ? true : false); } virt_dev->eps[ep_index].skip = false; ep_ring = virt_dev->eps[ep_index].new_ring; @@ -2003,7 +2006,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) goto fail; /* Set up the command ring to have one segments for now. */ - xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, flags); + xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, false, flags); if (!xhci->cmd_ring) goto fail; xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring); @@ -2034,7 +2037,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) * the event ring segment table (ERST). Section 4.9.3. */ xhci_dbg(xhci, "// Allocating event ring\n"); - xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, flags); + xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, false, + flags); if (!xhci->event_ring) goto fail; if (xhci_check_trb_in_td_math(xhci, flags) < 0) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index cb16de213f6..50e7156a7d8 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -128,6 +128,9 @@ static int xhci_pci_setup(struct usb_hcd *hcd) if (pdev->vendor == PCI_VENDOR_ID_NEC) xhci->quirks |= XHCI_NEC_HOST; + if (pdev->vendor == PCI_VENDOR_ID_AMD && xhci->hci_version == 0x96) + xhci->quirks |= XHCI_AMD_0x96_HOST; + /* AMD PLL quirk */ if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) xhci->quirks |= XHCI_AMD_PLL_FIX; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index d0871ea687d..e64bd6f9bfb 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -187,7 +187,7 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer * prepare_transfer()? */ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, - bool consumer, bool more_trbs_coming) + bool consumer, bool more_trbs_coming, bool isoc) { u32 chain; union xhci_trb *next; @@ -214,11 +214,13 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, if (!chain && !more_trbs_coming) break; - /* If we're not dealing with 0.95 hardware, + /* If we're not dealing with 0.95 hardware or + * isoc rings on AMD 0.96 host, * carry over the chain bit of the previous TRB * (which may mean the chain bit is cleared). */ - if (!xhci_link_trb_quirk(xhci)) { + if (!(isoc && (xhci->quirks & XHCI_AMD_0x96_HOST)) + && !xhci_link_trb_quirk(xhci)) { next->link.control &= cpu_to_le32(~TRB_CHAIN); next->link.control |= @@ -2398,7 +2400,7 @@ irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd) * prepare_transfer()? */ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, - bool consumer, bool more_trbs_coming, + bool consumer, bool more_trbs_coming, bool isoc, u32 field1, u32 field2, u32 field3, u32 field4) { struct xhci_generic_trb *trb; @@ -2408,7 +2410,7 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, trb->field[1] = cpu_to_le32(field2); trb->field[2] = cpu_to_le32(field3); trb->field[3] = cpu_to_le32(field4); - inc_enq(xhci, ring, consumer, more_trbs_coming); + inc_enq(xhci, ring, consumer, more_trbs_coming, isoc); } /* @@ -2416,7 +2418,7 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, * FIXME allocate segments if the ring is full. */ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, - u32 ep_state, unsigned int num_trbs, gfp_t mem_flags) + u32 ep_state, unsigned int num_trbs, bool isoc, gfp_t mem_flags) { /* Make sure the endpoint has been added to xHC schedule */ switch (ep_state) { @@ -2458,10 +2460,11 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, next = ring->enqueue; while (last_trb(xhci, ring, ring->enq_seg, next)) { - /* If we're not dealing with 0.95 hardware, - * clear the chain bit. + /* If we're not dealing with 0.95 hardware or isoc rings + * on AMD 0.96 host, clear the chain bit. */ - if (!xhci_link_trb_quirk(xhci)) + if (!xhci_link_trb_quirk(xhci) && !(isoc && + (xhci->quirks & XHCI_AMD_0x96_HOST))) next->link.control &= cpu_to_le32(~TRB_CHAIN); else next->link.control |= cpu_to_le32(TRB_CHAIN); @@ -2494,6 +2497,7 @@ static int prepare_transfer(struct xhci_hcd *xhci, unsigned int num_trbs, struct urb *urb, unsigned int td_index, + bool isoc, gfp_t mem_flags) { int ret; @@ -2511,7 +2515,7 @@ static int prepare_transfer(struct xhci_hcd *xhci, ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK, - num_trbs, mem_flags); + num_trbs, isoc, mem_flags); if (ret) return ret; @@ -2734,7 +2738,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, - num_trbs, urb, 0, mem_flags); + num_trbs, urb, 0, false, mem_flags); if (trb_buff_len < 0) return trb_buff_len; @@ -2829,7 +2833,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, more_trbs_coming = true; else more_trbs_coming = false; - queue_trb(xhci, ep_ring, false, more_trbs_coming, + queue_trb(xhci, ep_ring, false, more_trbs_coming, false, lower_32_bits(addr), upper_32_bits(addr), length_field, @@ -2920,7 +2924,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, - num_trbs, urb, 0, mem_flags); + num_trbs, urb, 0, false, mem_flags); if (ret < 0) return ret; @@ -2992,7 +2996,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, more_trbs_coming = true; else more_trbs_coming = false; - queue_trb(xhci, ep_ring, false, more_trbs_coming, + queue_trb(xhci, ep_ring, false, more_trbs_coming, false, lower_32_bits(addr), upper_32_bits(addr), length_field, @@ -3052,7 +3056,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, num_trbs++; ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, - num_trbs, urb, 0, mem_flags); + num_trbs, urb, 0, false, mem_flags); if (ret < 0) return ret; @@ -3085,7 +3089,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, } } - queue_trb(xhci, ep_ring, false, true, + queue_trb(xhci, ep_ring, false, true, false, setup->bRequestType | setup->bRequest << 8 | le16_to_cpu(setup->wValue) << 16, le16_to_cpu(setup->wIndex) | le16_to_cpu(setup->wLength) << 16, TRB_LEN(8) | TRB_INTR_TARGET(0), @@ -3105,7 +3109,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (urb->transfer_buffer_length > 0) { if (setup->bRequestType & USB_DIR_IN) field |= TRB_DIR_IN; - queue_trb(xhci, ep_ring, false, true, + queue_trb(xhci, ep_ring, false, true, false, lower_32_bits(urb->transfer_dma), upper_32_bits(urb->transfer_dma), length_field, @@ -3121,7 +3125,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, field = 0; else field = TRB_DIR_IN; - queue_trb(xhci, ep_ring, false, false, + queue_trb(xhci, ep_ring, false, false, false, 0, 0, TRB_INTR_TARGET(0), @@ -3270,7 +3274,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, trbs_per_td = count_isoc_trbs_needed(xhci, urb, i); ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, - urb->stream_id, trbs_per_td, urb, i, mem_flags); + urb->stream_id, trbs_per_td, urb, i, true, + mem_flags); if (ret < 0) { if (i == 0) return ret; @@ -3340,7 +3345,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, remainder | TRB_INTR_TARGET(0); - queue_trb(xhci, ep_ring, false, more_trbs_coming, + queue_trb(xhci, ep_ring, false, more_trbs_coming, true, lower_32_bits(addr), upper_32_bits(addr), length_field, @@ -3422,7 +3427,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, * Do not insert any td of the urb to the ring if the check failed. */ ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK, - num_trbs, mem_flags); + num_trbs, true, mem_flags); if (ret) return ret; @@ -3481,7 +3486,7 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, reserved_trbs++; ret = prepare_ring(xhci, xhci->cmd_ring, EP_STATE_RUNNING, - reserved_trbs, GFP_ATOMIC); + reserved_trbs, false, GFP_ATOMIC); if (ret < 0) { xhci_err(xhci, "ERR: No room for command on command ring\n"); if (command_must_succeed) @@ -3489,8 +3494,8 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, "unfailable commands failed.\n"); return ret; } - queue_trb(xhci, xhci->cmd_ring, false, false, field1, field2, field3, - field4 | xhci->cmd_ring->cycle_state); + queue_trb(xhci, xhci->cmd_ring, false, false, false, field1, field2, + field3, field4 | xhci->cmd_ring->cycle_state); return 0; } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index d8bbf5ccb10..8a98416e535 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1311,6 +1311,7 @@ struct xhci_hcd { #define XHCI_EP_LIMIT_QUIRK (1 << 5) #define XHCI_BROKEN_MSI (1 << 6) #define XHCI_RESET_ON_RESUME (1 << 7) +#define XHCI_AMD_0x96_HOST (1 << 9) unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ From b620fec43eeeadb25d96e537fc06dddf59ebfd78 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Wed, 28 Sep 2011 16:38:44 -0700 Subject: [PATCH 0020/4025] drm/i915: Wrap DP EDID fetch functions to enable eDP panel power commit 8c241fef3e6f69f3f675678ae03599ece3f562e2 upstream. Talking to the eDP DDC channel requires that the panel be powered up. Wrap both the EDID and modes fetch code with calls to turn the vdd power on and back off. Signed-off-by: Keith Packard Reviewed-by: Daniel Vetter Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_dp.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index e2aced6eec4..14264a8c03e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1658,6 +1658,31 @@ g4x_dp_detect(struct intel_dp *intel_dp) return status; } +static struct edid * +intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) +{ + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct edid *edid; + + ironlake_edp_panel_vdd_on(intel_dp); + edid = drm_get_edid(connector, adapter); + ironlake_edp_panel_vdd_off(intel_dp); + return edid; +} + +static int +intel_dp_get_edid_modes(struct drm_connector *connector, struct i2c_adapter *adapter) +{ + struct intel_dp *intel_dp = intel_attached_dp(connector); + int ret; + + ironlake_edp_panel_vdd_on(intel_dp); + ret = intel_ddc_get_modes(connector, adapter); + ironlake_edp_panel_vdd_off(intel_dp); + return ret; +} + + /** * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection. * @@ -1684,7 +1709,7 @@ intel_dp_detect(struct drm_connector *connector, bool force) if (intel_dp->force_audio) { intel_dp->has_audio = intel_dp->force_audio > 0; } else { - edid = drm_get_edid(connector, &intel_dp->adapter); + edid = intel_dp_get_edid(connector, &intel_dp->adapter); if (edid) { intel_dp->has_audio = drm_detect_monitor_audio(edid); connector->display_info.raw_edid = NULL; @@ -1705,7 +1730,7 @@ static int intel_dp_get_modes(struct drm_connector *connector) /* We should parse the EDID data and find out if it has an audio sink */ - ret = intel_ddc_get_modes(connector, &intel_dp->adapter); + ret = intel_dp_get_edid_modes(connector, &intel_dp->adapter); if (ret) { if (is_edp(intel_dp) && !dev_priv->panel_fixed_mode) { struct drm_display_mode *newmode; @@ -1741,7 +1766,7 @@ intel_dp_detect_audio(struct drm_connector *connector) struct edid *edid; bool has_audio = false; - edid = drm_get_edid(connector, &intel_dp->adapter); + edid = intel_dp_get_edid(connector, &intel_dp->adapter); if (edid) { has_audio = drm_detect_monitor_audio(edid); From 97e4a783f6e9b5d99123c93233b4592278439377 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 14 Oct 2011 11:45:40 +0200 Subject: [PATCH 0021/4025] drm/i915/panel: Always record the backlight level again (but cleverly) commit f52c619a590fa75276c07dfcaf380dee53e4ea4c upstream. The commit 47356eb67285014527a5ab87543ba1fae3d1e10a introduced a mechanism to record the backlight level only at disabling time, but it also introduced a regression. Since intel_lvds_enable() may be called without disabling (e.g. intel_lvds_commit() calls it unconditionally), the backlight gets back to the last recorded value. For example, this happens when you dim the backlight, close the lid and open the lid, then the backlight suddenly goes to the brightest. This patch fixes the bug by recording the backlight level always when changed via intel_panel_set_backlight(). And, intel_panel_{enable|disable}_backlight() call the internal function not to update the recorded level wrongly. Signed-off-by: Takashi Iwai Reviewed-by: Keith Packard Signed-off-by: Keith Packard Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_panel.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 05f500cd9c2..f8aa8211fed 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -226,7 +226,7 @@ static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level) I915_WRITE(BLC_PWM_CPU_CTL, val | level); } -void intel_panel_set_backlight(struct drm_device *dev, u32 level) +static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level) { struct drm_i915_private *dev_priv = dev->dev_private; u32 tmp; @@ -254,16 +254,21 @@ void intel_panel_set_backlight(struct drm_device *dev, u32 level) I915_WRITE(BLC_PWM_CTL, tmp | level); } -void intel_panel_disable_backlight(struct drm_device *dev) +void intel_panel_set_backlight(struct drm_device *dev, u32 level) { struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->backlight_enabled) { - dev_priv->backlight_level = intel_panel_get_backlight(dev); - dev_priv->backlight_enabled = false; - } + dev_priv->backlight_level = level; + if (dev_priv->backlight_enabled) + intel_panel_actually_set_backlight(dev, level); +} + +void intel_panel_disable_backlight(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; - intel_panel_set_backlight(dev, 0); + dev_priv->backlight_enabled = false; + intel_panel_actually_set_backlight(dev, 0); } void intel_panel_enable_backlight(struct drm_device *dev) @@ -273,8 +278,8 @@ void intel_panel_enable_backlight(struct drm_device *dev) if (dev_priv->backlight_level == 0) dev_priv->backlight_level = intel_panel_get_max_backlight(dev); - intel_panel_set_backlight(dev, dev_priv->backlight_level); dev_priv->backlight_enabled = true; + intel_panel_actually_set_backlight(dev, dev_priv->backlight_level); } void intel_panel_setup_backlight(struct drm_device *dev) From c271809eb4a52643cb5618678c81d682c20ad501 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 7 Oct 2011 14:23:47 -0400 Subject: [PATCH 0022/4025] drm/radeon/kms: bail early in dvi_detect for digital only connectors commit 5f0a26128d66ef81613fe923d5c288942844ccdc upstream. DVI-D and HDMI-A are digital only, so there's no need to attempt analog load detect. Also, skip bail before the !force check, or we fail to get a disconnect events. The next patches in the series attempt to fix disconnect events for connectors with analog support (DVI-I, HDMI-B, DVI-A). Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=41561 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_connectors.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 05b8b2cbd4f..c063da3dd86 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -950,6 +950,11 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) if ((ret == connector_status_connected) && (radeon_connector->use_digital == true)) goto out; + /* DVI-D and HDMI-A are digital only */ + if ((connector->connector_type == DRM_MODE_CONNECTOR_DVID) || + (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)) + goto out; + if (!force) { ret = connector->status; goto out; From 12bc1875cccdb601083183961533f64a0386370b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 7 Oct 2011 14:23:48 -0400 Subject: [PATCH 0023/4025] drm/radeon/kms: handle !force case in connector detect more gracefully commit d0d0a225e6ad43314c9aa7ea081f76adc5098ad4 upstream. When force == false, we don't do load detection in the connector detect functions. Unforunately, we also return the previous connector state so we never get disconnect events for DVI-I, DVI-A, or VGA. Save whether we detected the monitor via load detection previously and use that to determine whether we return the previous state or not. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=41561 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_connectors.c | 23 +++++++++++++++++++--- drivers/gpu/drm/radeon/radeon_mode.h | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index c063da3dd86..404a220a570 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -715,6 +715,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force) dret = radeon_ddc_probe(radeon_connector, radeon_connector->requires_extended_probe); if (dret) { + radeon_connector->detected_by_load = false; if (radeon_connector->edid) { kfree(radeon_connector->edid); radeon_connector->edid = NULL; @@ -741,12 +742,21 @@ radeon_vga_detect(struct drm_connector *connector, bool force) } else { /* if we aren't forcing don't do destructive polling */ - if (!force) - return connector->status; + if (!force) { + /* only return the previous status if we last + * detected a monitor via load. + */ + if (radeon_connector->detected_by_load) + return connector->status; + else + return ret; + } if (radeon_connector->dac_load_detect && encoder) { encoder_funcs = encoder->helper_private; ret = encoder_funcs->detect(encoder, connector); + if (ret == connector_status_connected) + radeon_connector->detected_by_load = true; } } @@ -888,6 +898,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) dret = radeon_ddc_probe(radeon_connector, radeon_connector->requires_extended_probe); if (dret) { + radeon_connector->detected_by_load = false; if (radeon_connector->edid) { kfree(radeon_connector->edid); radeon_connector->edid = NULL; @@ -955,8 +966,13 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) (connector->connector_type == DRM_MODE_CONNECTOR_HDMIA)) goto out; + /* if we aren't forcing don't do destructive polling */ if (!force) { - ret = connector->status; + /* only return the previous status if we last + * detected a monitor via load. + */ + if (radeon_connector->detected_by_load) + ret = connector->status; goto out; } @@ -980,6 +996,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) ret = encoder_funcs->detect(encoder, connector); if (ret == connector_status_connected) { radeon_connector->use_digital = false; + radeon_connector->detected_by_load = true; } } break; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 68820f5f630..ed0178f0323 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -447,6 +447,7 @@ struct radeon_connector { struct edid *edid; void *con_priv; bool dac_load_detect; + bool detected_by_load; /* if the connection status was determined by load */ uint16_t connector_object_id; struct radeon_hpd hpd; struct radeon_router router; From c86935898f7af4bbafa14c0f402a79925c53a33f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 6 Oct 2011 18:16:24 +0200 Subject: [PATCH 0024/4025] drm/radeon/kms: Fix I2C mask definitions commit 286e0c94f9c3f292cb38a977fbbde3433347a868 upstream. Commit 9b9fe724 accidentally used RADEON_GPIO_EN_* where RADEON_GPIO_MASK_* was intended. This caused improper initialization of I2C buses, mostly visible when setting i2c_algo_bit.bit_test=1. Using the right constants fixes the problem. Signed-off-by: Jean Delvare Reviewed-by: Alex Deucher Cc: Jerome Glisse Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_combios.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index cd3c86c845e..859df6b5bca 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -620,8 +620,8 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde i2c.y_data_mask = 0x80; } else { /* default masks for ddc pads */ - i2c.mask_clk_mask = RADEON_GPIO_EN_1; - i2c.mask_data_mask = RADEON_GPIO_EN_0; + i2c.mask_clk_mask = RADEON_GPIO_MASK_1; + i2c.mask_data_mask = RADEON_GPIO_MASK_0; i2c.a_clk_mask = RADEON_GPIO_A_1; i2c.a_data_mask = RADEON_GPIO_A_0; i2c.en_clk_mask = RADEON_GPIO_EN_1; From 311c3c10f6429f4405be6a0e98cb27c6995ca8b9 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 21 Sep 2011 14:08:13 -0400 Subject: [PATCH 0025/4025] mmc: core: Fix hangs related to insert/remove of cards commit 7f7e4129c23f0419257184dff6fec89d2d5a8964 upstream. During a rescan operation mmc_attach(sd|mmc|sdio) functions are called. The error handling in these function can trigger a detach of the bus, which also meant a power off. This is not notified by the rescan operation which then continues to the next attach function. If a power off has been done, the framework must never send any new commands to the host driver, without first doing a new power up. This will most likely trigger any host driver to hang. Moving power off out of detach and instead handle power off separately when it is actually needed, solves the issue. Signed-off-by: Ulf Hansson Acked-by: Linus Walleij Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/core.c | 10 +++++----- drivers/mmc/core/core.h | 1 + drivers/mmc/core/mmc.c | 1 + drivers/mmc/core/sd.c | 1 + drivers/mmc/core/sdio.c | 1 + 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 38089b25c57..75db30e6dcf 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1057,7 +1057,7 @@ static void mmc_power_up(struct mmc_host *host) mmc_host_clk_release(host); } -static void mmc_power_off(struct mmc_host *host) +void mmc_power_off(struct mmc_host *host) { mmc_host_clk_hold(host); @@ -1147,8 +1147,7 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops) } /* - * Remove the current bus handler from a host. Assumes that there are - * no interesting cards left, so the bus is powered down. + * Remove the current bus handler from a host. */ void mmc_detach_bus(struct mmc_host *host) { @@ -1165,8 +1164,6 @@ void mmc_detach_bus(struct mmc_host *host) spin_unlock_irqrestore(&host->lock, flags); - mmc_power_off(host); - mmc_bus_put(host); } @@ -1675,6 +1672,7 @@ void mmc_stop_host(struct mmc_host *host) mmc_claim_host(host); mmc_detach_bus(host); + mmc_power_off(host); mmc_release_host(host); mmc_bus_put(host); return; @@ -1796,6 +1794,7 @@ int mmc_suspend_host(struct mmc_host *host) host->bus_ops->remove(host); mmc_claim_host(host); mmc_detach_bus(host); + mmc_power_off(host); mmc_release_host(host); host->pm_flags = 0; err = 0; @@ -1883,6 +1882,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, host->bus_ops->remove(host); mmc_detach_bus(host); + mmc_power_off(host); mmc_release_host(host); host->pm_flags = 0; break; diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h index d9411ed2a39..14664f1fb16 100644 --- a/drivers/mmc/core/core.h +++ b/drivers/mmc/core/core.h @@ -43,6 +43,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11); void mmc_set_timing(struct mmc_host *host, unsigned int timing); void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); +void mmc_power_off(struct mmc_host *host); static inline void mmc_delay(unsigned int ms) { diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index aa7d1d79b8c..6f5ee84ec71 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -891,6 +891,7 @@ static void mmc_detect(struct mmc_host *host) mmc_claim_host(host); mmc_detach_bus(host); + mmc_power_off(host); mmc_release_host(host); } } diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index ff2774128aa..bd8805c9e8a 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -1008,6 +1008,7 @@ static void mmc_sd_detect(struct mmc_host *host) mmc_claim_host(host); mmc_detach_bus(host); + mmc_power_off(host); mmc_release_host(host); } } diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 262fff01917..ac492ac974e 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -597,6 +597,7 @@ static void mmc_sdio_detect(struct mmc_host *host) mmc_claim_host(host); mmc_detach_bus(host); + mmc_power_off(host); mmc_release_host(host); } } From c359836591a99d43c5e4c6792de75dcaddee805e Mon Sep 17 00:00:00 2001 From: Andrei Warkentin Date: Sat, 24 Sep 2011 12:12:30 -0400 Subject: [PATCH 0026/4025] mmc: core: ext_csd.raw_* used in comparison but never set commit 5238acbe36dd5100fb6b035a995ae5fc89dd0708 upstream. f39b2dd9d ("mmc: core: Bus width testing needs to handle suspend/resume") added code to only compare read-only ext_csd fields in bus width testing code, yet it's comparing some fields that are never set. The affected fields are ext_csd.raw_erased_mem_count and ext_csd.raw_partition_support. Signed-off-by: Andrei Warkentin Acked-by: Philip Rakity Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/mmc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 6f5ee84ec71..20b42c835ab 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -359,6 +359,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) * card has the Enhanced area enabled. If so, export enhanced * area offset and size to user by adding sysfs interface. */ + card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT]; if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) && (ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) { u8 hc_erase_grp_sz = @@ -405,6 +406,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd) if (card->ext_csd.rev >= 5) card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM]; + card->ext_csd.raw_erased_mem_count = ext_csd[EXT_CSD_ERASED_MEM_CONT]; if (ext_csd[EXT_CSD_ERASED_MEM_CONT]) card->erased_byte = 0xFF; else From 95bf50db41fbb1db306b3e636d46ce9014482a50 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Wed, 5 Oct 2011 11:44:50 -0400 Subject: [PATCH 0027/4025] PCI quirk: mmc: Always check for lower base frequency quirk for Ricoh 1180:e823 commit 3e309cdf07c930f29a4e0f233e47d399bea34c68 upstream. Commit 15bed0f2f added a quirk for the e823 Ricoh card reader to lower the base frequency. However, the quirk first checks to see if the proprietary MMC controller is disabled, and returns if so. On some devices, such as the Lenovo X220, the MMC controller is already disabled by firmware it seems, but the frequency change is still needed so sdhci-pci can talk to the cards. Since the MMC controller is disabled, the frequency fixup was never being run on these machines. This moves the e823 check above the MMC controller check so that it always gets run. This fixes https://bugzilla.redhat.com/show_bug.cgi?id=722509 Signed-off-by: Josh Boyer Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 1196f61a4ab..cec46292731 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2745,20 +2745,6 @@ static void ricoh_mmc_fixup_r5c832(struct pci_dev *dev) /* disable must be done via function #0 */ if (PCI_FUNC(dev->devfn)) return; - - pci_read_config_byte(dev, 0xCB, &disable); - - if (disable & 0x02) - return; - - pci_read_config_byte(dev, 0xCA, &write_enable); - pci_write_config_byte(dev, 0xCA, 0x57); - pci_write_config_byte(dev, 0xCB, disable | 0x02); - pci_write_config_byte(dev, 0xCA, write_enable); - - dev_notice(&dev->dev, "proprietary Ricoh MMC controller disabled (via firewire function)\n"); - dev_notice(&dev->dev, "MMC cards are now supported by standard SDHCI controller\n"); - /* * RICOH 0xe823 SD/MMC card reader fails to recognize * certain types of SD/MMC cards. Lowering the SD base @@ -2781,6 +2767,20 @@ static void ricoh_mmc_fixup_r5c832(struct pci_dev *dev) dev_notice(&dev->dev, "MMC controller base frequency changed to 50Mhz.\n"); } + + pci_read_config_byte(dev, 0xCB, &disable); + + if (disable & 0x02) + return; + + pci_read_config_byte(dev, 0xCA, &write_enable); + pci_write_config_byte(dev, 0xCA, 0x57); + pci_write_config_byte(dev, 0xCB, disable | 0x02); + pci_write_config_byte(dev, 0xCA, write_enable); + + dev_notice(&dev->dev, "proprietary Ricoh MMC controller disabled (via firewire function)\n"); + dev_notice(&dev->dev, "MMC cards are now supported by standard SDHCI controller\n"); + } DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832); DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832); From 20e801924287a2eebe00395f4cebc8eeb7d5aa62 Mon Sep 17 00:00:00 2001 From: adam radford Date: Thu, 13 Oct 2011 16:01:12 -0700 Subject: [PATCH 0028/4025] megaraid_sas: Fix instance access in megasas_reset_timer commit f575c5d3ebdca3b0482847d8fcba971767754a9e upstream. The following patch for megaraid_sas will fix a potential bad pointer access in megasas_reset_timer(), when a MegaRAID 9265/9285 or 9360/9380 gets a timeout. megasas_build_io_fusion() sets SCp.ptr to be a struct megasas_cmd_fusion *, but then megasas_reset_timer() was casting SCp.ptr to be a struct megasas_cmd *, then trying to access cmd->instance, which is invalid. Just loading instance from scmd->device->host->hostdata in megasas_reset_timer() fixes the issue. Signed-off-by: Adam Radford Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/megaraid/megaraid_sas_base.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 2d8cdce7b2f..e6e30f4da1f 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -1906,7 +1906,6 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd) static enum blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) { - struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr; struct megasas_instance *instance; unsigned long flags; @@ -1915,7 +1914,7 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) return BLK_EH_NOT_HANDLED; } - instance = cmd->instance; + instance = (struct megasas_instance *)scmd->device->host->hostdata; if (!(instance->flag & MEGASAS_FW_BUSY)) { /* FW is busy, throttle IO */ spin_lock_irqsave(instance->host->host_lock, flags); From fa11f5a1d9e8e199dfacb16a4288d4d4c5c549ff Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 1 Aug 2011 19:43:45 +1000 Subject: [PATCH 0029/4025] ipr: Always initiate hard reset in kdump kernel commit 5d7c20b7fa5c6ca19e871b4050e321c99d32bd43 upstream. During kdump testing I noticed timeouts when initialising each IPR adapter. While the driver has logic to detect an adapter in an indeterminate state, it wasn't triggering and each adapter went through a 5 minute timeout before finally going operational. Some analysis showed the needs_hard_reset flag wasn't getting set. We can check the reset_devices kernel parameter which is set by kdump and force a full reset. This fixes the problem. Signed-off-by: Anton Blanchard Acked-by: Brian King Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/ipr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 888086c4e70..c5c7c3abb4b 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -8812,7 +8812,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev, uproc = readl(ioa_cfg->regs.sense_uproc_interrupt_reg32); if ((mask & IPR_PCII_HRRQ_UPDATED) == 0 || (uproc & IPR_UPROCI_RESET_ALERT)) ioa_cfg->needs_hard_reset = 1; - if (interrupts & IPR_PCII_ERROR_INTERRUPTS) + if ((interrupts & IPR_PCII_ERROR_INTERRUPTS) || reset_devices) ioa_cfg->needs_hard_reset = 1; if (interrupts & IPR_PCII_IOA_UNIT_CHECKED) ioa_cfg->ioa_unit_checked = 1; From 31a471a2d7c27373b80677f65934b16adf4635d5 Mon Sep 17 00:00:00 2001 From: Jack Wang Date: Fri, 23 Sep 2011 14:32:32 +0800 Subject: [PATCH 0030/4025] libsas: set sas_address and device type of rphy commit bb041a0e9c31229071b6e56e1d0d8374af0d2038 upstream. Libsas forget to set the sas_address and device type of rphy lead to file under /sys/class/sas_x show wrong value, fix that. Signed-off-by: Jack Wang Tested-by: Crystal Yu Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/libsas/sas_expander.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 16ad97df5ba..37cbe4d3bb9 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -199,6 +199,8 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, phy->virtual = dr->virtual; phy->last_da_index = -1; + phy->phy->identify.sas_address = SAS_ADDR(phy->attached_sas_addr); + phy->phy->identify.device_type = phy->attached_dev_type; phy->phy->identify.initiator_port_protocols = phy->attached_iproto; phy->phy->identify.target_port_protocols = phy->attached_tproto; phy->phy->identify.phy_identifier = phy_id; From 5cbadb2ee60c10ada1a8bfd1f7ba67d8e30a4e39 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 28 Sep 2011 18:35:27 -0700 Subject: [PATCH 0031/4025] isci: fix support for large smp requests commit 54b5e3a4bfa3452bc10cd4da672099ccc46b8c09 upstream. Kill the local smp response buffer. Besides being unnecessary, it is too small (currently truncates responses to 60 bytes). The mid-layer will have already allocated a sufficiently sized buffer, just kmap and copy into it directly. Reported-by: Derick Marks Tested-by: Derick Marks Signed-off-by: Dan Williams Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/isci/isci.h | 2 +- drivers/scsi/isci/request.c | 49 +++++++++++++++---------------------- drivers/scsi/isci/request.h | 3 --- drivers/scsi/isci/sas.h | 2 -- 4 files changed, 21 insertions(+), 35 deletions(-) diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h index d1de63312e7..8efeb6b0832 100644 --- a/drivers/scsi/isci/isci.h +++ b/drivers/scsi/isci/isci.h @@ -97,7 +97,7 @@ #define SCU_MAX_COMPLETION_QUEUE_SHIFT (ilog2(SCU_MAX_COMPLETION_QUEUE_ENTRIES)) #define SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES (4096) -#define SCU_UNSOLICITED_FRAME_BUFFER_SIZE (1024) +#define SCU_UNSOLICITED_FRAME_BUFFER_SIZE (1024U) #define SCU_INVALID_FRAME_INDEX (0xFFFF) #define SCU_IO_REQUEST_MAX_SGE_SIZE (0x00FFFFFF) diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index b5d3a8c4d32..225b196800a 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -1490,29 +1490,30 @@ sci_io_request_frame_handler(struct isci_request *ireq, return SCI_SUCCESS; case SCI_REQ_SMP_WAIT_RESP: { - struct smp_resp *rsp_hdr = &ireq->smp.rsp; - void *frame_header; + struct sas_task *task = isci_request_access_task(ireq); + struct scatterlist *sg = &task->smp_task.smp_resp; + void *frame_header, *kaddr; + u8 *rsp; sci_unsolicited_frame_control_get_header(&ihost->uf_control, - frame_index, - &frame_header); - - /* byte swap the header. */ - word_cnt = SMP_RESP_HDR_SZ / sizeof(u32); - sci_swab32_cpy(rsp_hdr, frame_header, word_cnt); + frame_index, + &frame_header); + kaddr = kmap_atomic(sg_page(sg), KM_IRQ0); + rsp = kaddr + sg->offset; + sci_swab32_cpy(rsp, frame_header, 1); - if (rsp_hdr->frame_type == SMP_RESPONSE) { + if (rsp[0] == SMP_RESPONSE) { void *smp_resp; sci_unsolicited_frame_control_get_buffer(&ihost->uf_control, - frame_index, - &smp_resp); + frame_index, + &smp_resp); - word_cnt = (sizeof(struct smp_resp) - SMP_RESP_HDR_SZ) / - sizeof(u32); - - sci_swab32_cpy(((u8 *) rsp_hdr) + SMP_RESP_HDR_SZ, - smp_resp, word_cnt); + word_cnt = (sg->length/4)-1; + if (word_cnt > 0) + word_cnt = min_t(unsigned int, word_cnt, + SCU_UNSOLICITED_FRAME_BUFFER_SIZE/4); + sci_swab32_cpy(rsp + 4, smp_resp, word_cnt); ireq->scu_status = SCU_TASK_DONE_GOOD; ireq->sci_status = SCI_SUCCESS; @@ -1528,12 +1529,13 @@ sci_io_request_frame_handler(struct isci_request *ireq, __func__, ireq, frame_index, - rsp_hdr->frame_type); + rsp[0]); ireq->scu_status = SCU_TASK_DONE_SMP_FRM_TYPE_ERR; ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); } + kunmap_atomic(kaddr, KM_IRQ0); sci_controller_release_frame(ihost, frame_index); @@ -2603,18 +2605,7 @@ static void isci_request_io_request_complete(struct isci_host *ihost, status = SAM_STAT_GOOD; set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - if (task->task_proto == SAS_PROTOCOL_SMP) { - void *rsp = &request->smp.rsp; - - dev_dbg(&ihost->pdev->dev, - "%s: SMP protocol completion\n", - __func__); - - sg_copy_from_buffer( - &task->smp_task.smp_resp, 1, - rsp, sizeof(struct smp_resp)); - } else if (completion_status - == SCI_IO_SUCCESS_IO_DONE_EARLY) { + if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) { /* This was an SSP / STP / SATA transfer. * There is a possibility that less data than diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h index 7a1d5a9778e..58d70b6606e 100644 --- a/drivers/scsi/isci/request.h +++ b/drivers/scsi/isci/request.h @@ -173,9 +173,6 @@ struct isci_request { u8 rsp_buf[SSP_RESP_IU_MAX_SIZE]; }; } ssp; - struct { - struct smp_resp rsp; - } smp; struct { struct isci_stp_request req; struct host_to_dev_fis cmd; diff --git a/drivers/scsi/isci/sas.h b/drivers/scsi/isci/sas.h index 462b15174d3..dc26b4aea99 100644 --- a/drivers/scsi/isci/sas.h +++ b/drivers/scsi/isci/sas.h @@ -204,8 +204,6 @@ struct smp_req { u8 req_data[0]; } __packed; -#define SMP_RESP_HDR_SZ 4 - /* * struct sci_sas_address - This structure depicts how a SAS address is * represented by SCI. From cdab390353a92844107bf49bd4bb8b436e909b2f Mon Sep 17 00:00:00 2001 From: Jeff Skirvin Date: Wed, 28 Sep 2011 18:35:32 -0700 Subject: [PATCH 0032/4025] isci: fix missed unlock in apc_agent_timeout() commit 983d3fdd332742167d0482c06fd29cf4b8a687c0 upstream. Needed to jump to scic_lock unlock. Also spotted by coccicheck. Signed-off-by: Jeff Skirvin Signed-off-by: Dan Williams Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/isci/port_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c index 486b113c634..38a99d28114 100644 --- a/drivers/scsi/isci/port_config.c +++ b/drivers/scsi/isci/port_config.c @@ -678,7 +678,7 @@ static void apc_agent_timeout(unsigned long data) configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask; if (!configure_phy_mask) - return; + goto done; for (index = 0; index < SCI_MAX_PHYS; index++) { if ((configure_phy_mask & (1 << index)) == 0) From 6d8891c6a14141fad833f15745ae2f637d23dd8a Mon Sep 17 00:00:00 2001 From: Charles Chin Date: Thu, 13 Oct 2011 07:54:09 +0200 Subject: [PATCH 0033/4025] ALSA: hda - Remove bad code for IDT 92HD83 family patch commit 6c5c04e509b7000617b09d4301f0b9b6d171d1e6 upstream. The purpose of this patch is to remove a section of "bad" code that assigns the last DAC to ports E or F in order to support notebooks with docking in earlier days, around ALSA 1.0.19 - 21. This is not necessary now and actually breaks some configurations that use these ports as other devices. This have been tested on several different configurations to make sure that it is working for different combinations. Signed-off-by: Charles Chin Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_sigmatel.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 5c42f3e0b16..24a99e040f4 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5425,9 +5425,7 @@ static void stac92hd8x_fill_auto_spec(struct hda_codec *codec) static int patch_stac92hd83xxx(struct hda_codec *codec) { struct sigmatel_spec *spec; - hda_nid_t conn[STAC92HD83_DAC_COUNT + 1]; int err; - int num_dacs; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -5522,22 +5520,6 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) return err; } - /* docking output support */ - num_dacs = snd_hda_get_connections(codec, 0xF, - conn, STAC92HD83_DAC_COUNT + 1) - 1; - /* skip non-DAC connections */ - while (num_dacs >= 0 && - (get_wcaps_type(get_wcaps(codec, conn[num_dacs])) - != AC_WID_AUD_OUT)) - num_dacs--; - /* set port E and F to select the last DAC */ - if (num_dacs >= 0) { - snd_hda_codec_write_cache(codec, 0xE, 0, - AC_VERB_SET_CONNECT_SEL, num_dacs); - snd_hda_codec_write_cache(codec, 0xF, 0, - AC_VERB_SET_CONNECT_SEL, num_dacs); - } - codec->proc_widget_hook = stac92hd_proc_hook; return 0; From 133615a7e293f3628c6f7860a41b9d7964d15a60 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Tue, 18 Oct 2011 14:07:51 +0200 Subject: [PATCH 0034/4025] ALSA: HDA: Add new revision for ALC662 commit cc667a72d471e79fd8e5e291ea115923cf44dca0 upstream. The revision 0x100300 was found for ALC662. It seems to work well with patch_alc662. BugLink: http://bugs.launchpad.net/bugs/877373 Tested-by: Shengyao Xue Signed-off-by: David Henningsson Acked-by: Kailang Yang Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4c7cd6b58b2..62b13141876 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -20126,6 +20126,8 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { .patch = patch_alc882 }, { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", .patch = patch_alc662 }, + { .id = 0x10ec0662, .rev = 0x100300, .name = "ALC662 rev3", + .patch = patch_alc662 }, { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, From f2c1c3233aa7b1742c458b1eed929d675222e70c Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Tue, 18 Oct 2011 23:48:04 -0700 Subject: [PATCH 0035/4025] target: Fix REPORT TARGET PORT GROUPS handling with small allocation length commit 6b20fa9aaf0c2f69ee6f9648e20ab2be0206705e upstream. This patch fixes a bug with the handling of REPORT TARGET PORT GROUPS containing a smaller allocation length than the payload requires causing memory writes beyond the end of the buffer. This patch checks for the minimum 4 byte length for the response payload length, and also checks upon each loop of T10_ALUA(su_dev)->tg_pt_gps_list to ensure the Target port group and Target port descriptor list is able to fit into the remaining allocation length. If the response payload exceeds the allocation length length, then rd_len is still increments to indicate to the initiator that the payload has been truncated. Reported-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_alua.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 47abb42d9c3..86b36600acb 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -60,10 +60,30 @@ int core_emulate_report_target_port_groups(struct se_cmd *cmd) unsigned char *buf = (unsigned char *)T_TASK(cmd)->t_task_buf; u32 rd_len = 0, off = 4; /* Skip over RESERVED area to first Target port group descriptor */ + /* + * Need at least 4 bytes of response data or else we can't + * even fit the return data length. + */ + if (cmd->data_length < 4) { + pr_warn("REPORT TARGET PORT GROUPS allocation length %u" + " too small\n", cmd->data_length); + return -EINVAL; + } spin_lock(&T10_ALUA(su_dev)->tg_pt_gps_lock); list_for_each_entry(tg_pt_gp, &T10_ALUA(su_dev)->tg_pt_gps_list, tg_pt_gp_list) { + /* + * Check if the Target port group and Target port descriptor list + * based on tg_pt_gp_members count will fit into the response payload. + * Otherwise, bump rd_len to let the initiator know we have exceeded + * the allocation length and the response is truncated. + */ + if ((off + 8 + (tg_pt_gp->tg_pt_gp_members * 4)) > + cmd->data_length) { + rd_len += 8 + (tg_pt_gp->tg_pt_gp_members * 4); + continue; + } /* * PREF: Preferred target port bit, determine if this * bit should be set for port group. From 0989d31d57762309445fa1469907b2e6c2cd4ae5 Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Tue, 20 Sep 2011 13:55:04 -0700 Subject: [PATCH 0036/4025] x86: uv2: Workaround for UV2 Hub bug (system global address format) commit 6a469e4665bc158599de55d64388861d0a9f10f4 upstream. This is a workaround for a UV2 hub bug that affects the format of system global addresses. The GRU API for UV2 was inadvertently broken by a hardware change. The format of the physical address used for TLB dropins and for addresses used with instructions running in unmapped mode has changed. This change was not documented and became apparent only when diags failed running on system simulators. For UV1, TLB and GRU instruction physical addresses are identical to socket physical addresses (although high NASID bits must be OR'ed into the address). For UV2, socket physical addresses need to be converted. The NODE portion of the physical address needs to be shifted so that the low bit is in bit 39 or bit 40, depending on an MMR value. It is not yet clear if this bug will be fixed in a silicon respin. If it is fixed, the hub revision will be incremented & the workaround disabled. Signed-off-by: Jack Steiner Cc: Ingo Molnar Cc: "H. Peter Anvin" Signed-off-by: Andrew Morton Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/uv/uv_bau.h | 1 + arch/x86/include/asm/uv/uv_hub.h | 37 +++++++++++++++++++++++++++--- arch/x86/kernel/apic/x2apic_uv_x.c | 7 ++++-- arch/x86/platform/uv/tlb_uv.c | 17 +++++--------- 4 files changed, 46 insertions(+), 16 deletions(-) diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h index a291c40efd4..5d62d651a62 100644 --- a/arch/x86/include/asm/uv/uv_bau.h +++ b/arch/x86/include/asm/uv/uv_bau.h @@ -55,6 +55,7 @@ #define UV_BAU_TUNABLES_DIR "sgi_uv" #define UV_BAU_TUNABLES_FILE "bau_tunables" #define WHITESPACE " \t\n" +#define uv_mmask ((1UL << uv_hub_info->m_val) - 1) #define uv_physnodeaddr(x) ((__pa((unsigned long)(x)) & uv_mmask)) #define cpubit_isset(cpu, bau_local_cpumask) \ test_bit((cpu), (bau_local_cpumask).bits) diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index f26544a1521..54a13aaebc4 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -46,6 +46,13 @@ * PNODE - the low N bits of the GNODE. The PNODE is the most useful variant * of the nasid for socket usage. * + * GPA - (global physical address) a socket physical address converted + * so that it can be used by the GRU as a global address. Socket + * physical addresses 1) need additional NASID (node) bits added + * to the high end of the address, and 2) unaliased if the + * partition does not have a physical address 0. In addition, on + * UV2 rev 1, GPAs need the gnode left shifted to bits 39 or 40. + * * * NumaLink Global Physical Address Format: * +--------------------------------+---------------------+ @@ -141,6 +148,8 @@ struct uv_hub_info_s { unsigned int gnode_extra; unsigned char hub_revision; unsigned char apic_pnode_shift; + unsigned char m_shift; + unsigned char n_lshift; unsigned long gnode_upper; unsigned long lowmem_remap_top; unsigned long lowmem_remap_base; @@ -177,6 +186,16 @@ static inline int is_uv2_hub(void) return uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE; } +static inline int is_uv2_1_hub(void) +{ + return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE; +} + +static inline int is_uv2_2_hub(void) +{ + return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE + 1; +} + union uvh_apicid { unsigned long v; struct uvh_apicid_s { @@ -276,7 +295,10 @@ static inline unsigned long uv_soc_phys_ram_to_gpa(unsigned long paddr) { if (paddr < uv_hub_info->lowmem_remap_top) paddr |= uv_hub_info->lowmem_remap_base; - return paddr | uv_hub_info->gnode_upper; + paddr |= uv_hub_info->gnode_upper; + paddr = ((paddr << uv_hub_info->m_shift) >> uv_hub_info->m_shift) | + ((paddr >> uv_hub_info->m_val) << uv_hub_info->n_lshift); + return paddr; } @@ -300,16 +322,19 @@ static inline unsigned long uv_gpa_to_soc_phys_ram(unsigned long gpa) unsigned long remap_base = uv_hub_info->lowmem_remap_base; unsigned long remap_top = uv_hub_info->lowmem_remap_top; + gpa = ((gpa << uv_hub_info->m_shift) >> uv_hub_info->m_shift) | + ((gpa >> uv_hub_info->n_lshift) << uv_hub_info->m_val); + gpa = gpa & uv_hub_info->gpa_mask; if (paddr >= remap_base && paddr < remap_base + remap_top) paddr -= remap_base; return paddr; } -/* gnode -> pnode */ +/* gpa -> pnode */ static inline unsigned long uv_gpa_to_gnode(unsigned long gpa) { - return gpa >> uv_hub_info->m_val; + return gpa >> uv_hub_info->n_lshift; } /* gpa -> pnode */ @@ -320,6 +345,12 @@ static inline int uv_gpa_to_pnode(unsigned long gpa) return uv_gpa_to_gnode(gpa) & n_mask; } +/* gpa -> node offset*/ +static inline unsigned long uv_gpa_to_offset(unsigned long gpa) +{ + return (gpa << uv_hub_info->m_shift) >> uv_hub_info->m_shift; +} + /* pnode, offset --> socket virtual */ static inline void *uv_pnode_offset_to_vaddr(int pnode, unsigned long offset) { diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 34b18594e72..cfeb978f49f 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -832,6 +832,10 @@ void __init uv_system_init(void) uv_cpu_hub_info(cpu)->apic_pnode_shift = uvh_apicid.s.pnode_shift; uv_cpu_hub_info(cpu)->hub_revision = uv_hub_info->hub_revision; + uv_cpu_hub_info(cpu)->m_shift = 64 - m_val; + uv_cpu_hub_info(cpu)->n_lshift = is_uv2_1_hub() ? + (m_val == 40 ? 40 : 39) : m_val; + pnode = uv_apicid_to_pnode(apicid); blade = boot_pnode_to_blade(pnode); lcpu = uv_blade_info[blade].nr_possible_cpus; @@ -862,8 +866,7 @@ void __init uv_system_init(void) if (uv_node_to_blade[nid] >= 0) continue; paddr = node_start_pfn(nid) << PAGE_SHIFT; - paddr = uv_soc_phys_ram_to_gpa(paddr); - pnode = (paddr >> m_val) & pnode_mask; + pnode = uv_gpa_to_pnode(uv_soc_phys_ram_to_gpa(paddr)); blade = boot_pnode_to_blade(pnode); uv_node_to_blade[nid] = blade; } diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index 68e467f69fe..82cff4a25f4 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c @@ -115,9 +115,6 @@ early_param("nobau", setup_nobau); /* base pnode in this partition */ static int uv_base_pnode __read_mostly; -/* position of pnode (which is nasid>>1): */ -static int uv_nshift __read_mostly; -static unsigned long uv_mmask __read_mostly; static DEFINE_PER_CPU(struct ptc_stats, ptcstats); static DEFINE_PER_CPU(struct bau_control, bau_control); @@ -1426,7 +1423,7 @@ static void activation_descriptor_init(int node, int pnode, int base_pnode) { int i; int cpu; - unsigned long pa; + unsigned long gpa; unsigned long m; unsigned long n; size_t dsize; @@ -1442,9 +1439,9 @@ static void activation_descriptor_init(int node, int pnode, int base_pnode) bau_desc = kmalloc_node(dsize, GFP_KERNEL, node); BUG_ON(!bau_desc); - pa = uv_gpa(bau_desc); /* need the real nasid*/ - n = pa >> uv_nshift; - m = pa & uv_mmask; + gpa = uv_gpa(bau_desc); + n = uv_gpa_to_gnode(gpa); + m = uv_gpa_to_offset(gpa); /* the 14-bit pnode */ write_mmr_descriptor_base(pnode, (n << UV_DESC_PSHIFT | m)); @@ -1516,9 +1513,9 @@ static void pq_init(int node, int pnode) bcp->queue_last = pqp + (DEST_Q_SIZE - 1); } /* - * need the pnode of where the memory was really allocated + * need the gnode of where the memory was really allocated */ - pn = uv_gpa(pqp) >> uv_nshift; + pn = uv_gpa_to_gnode(uv_gpa(pqp)); first = uv_physnodeaddr(pqp); pn_first = ((unsigned long)pn << UV_PAYLOADQ_PNODE_SHIFT) | first; last = uv_physnodeaddr(pqp + (DEST_Q_SIZE - 1)); @@ -1812,8 +1809,6 @@ static int __init uv_bau_init(void) zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cur_cpu)); } - uv_nshift = uv_hub_info->m_val; - uv_mmask = (1UL << uv_hub_info->m_val) - 1; nuvhubs = uv_num_possible_blades(); spin_lock_init(&disable_lock); congested_cycles = usec_2_cycles(congested_respns_us); From 2f3f49d0afbeb318b096f09fccaf8747251afccf Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Mon, 24 Oct 2011 10:15:51 -0700 Subject: [PATCH 0037/4025] x86: Fix compilation bug in kprobes' twobyte_is_boostable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 315eb8a2a1b7f335d40ceeeb11b9e067475eb881 upstream. When compiling an i386_defconfig kernel with gcc-4.6.1-9.fc15.i686, I noticed a warning about the asm operand for test_bit in kprobes' can_boost. I discovered that this caused only the first long of twobyte_is_boostable[] to be output. Jakub filed and fixed gcc PR50571 to correct the warning and this output issue. But to solve it for less current gcc, we can make kprobes' twobyte_is_boostable[] non-const, and it won't be optimized out. Before: CC arch/x86/kernel/kprobes.o In file included from include/linux/bitops.h:22:0, from include/linux/kernel.h:17, from [...]/arch/x86/include/asm/percpu.h:44, from [...]/arch/x86/include/asm/current.h:5, from [...]/arch/x86/include/asm/processor.h:15, from [...]/arch/x86/include/asm/atomic.h:6, from include/linux/atomic.h:4, from include/linux/mutex.h:18, from include/linux/notifier.h:13, from include/linux/kprobes.h:34, from arch/x86/kernel/kprobes.c:43: [...]/arch/x86/include/asm/bitops.h: In function ‘can_boost.part.1’: [...]/arch/x86/include/asm/bitops.h:319:2: warning: use of memory input without lvalue in asm operand 1 is deprecated [enabled by default] $ objdump -rd arch/x86/kernel/kprobes.o | grep -A1 -w bt 551: 0f a3 05 00 00 00 00 bt %eax,0x0 554: R_386_32 .rodata.cst4 $ objdump -s -j .rodata.cst4 -j .data arch/x86/kernel/kprobes.o arch/x86/kernel/kprobes.o: file format elf32-i386 Contents of section .data: 0000 48000000 00000000 00000000 00000000 H............... Contents of section .rodata.cst4: 0000 4c030000 L... Only a single long of twobyte_is_boostable[] is in the object file. After, without the const on twobyte_is_boostable: $ objdump -rd arch/x86/kernel/kprobes.o | grep -A1 -w bt 551: 0f a3 05 20 00 00 00 bt %eax,0x20 554: R_386_32 .data $ objdump -s -j .rodata.cst4 -j .data arch/x86/kernel/kprobes.o arch/x86/kernel/kprobes.o: file format elf32-i386 Contents of section .data: 0000 48000000 00000000 00000000 00000000 H............... 0010 00000000 00000000 00000000 00000000 ................ 0020 4c030000 0f000200 ffff0000 ffcff0c0 L............... 0030 0000ffff 3bbbfff8 03ff2ebb 26bb2e77 ....;.......&..w Now all 32 bytes are output into .data instead. Signed-off-by: Josh Stone Cc: Masami Hiramatsu Cc: Jakub Jelinek Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/kprobes.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index f1a6244d7d9..794bc95134c 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c @@ -75,8 +75,10 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); /* * Undefined/reserved opcodes, conditional jump, Opcode Extension * Groups, and some special opcodes can not boost. + * This is non-const to keep gcc from statically optimizing it out, as + * variable_test_bit makes gcc think only *(unsigned long*) is used. */ -static const u32 twobyte_is_boostable[256 / 32] = { +static u32 twobyte_is_boostable[256 / 32] = { /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ /* ---------------------------------------------- */ W(0x00, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0) | /* 00 */ From 3dbbae24b399adc22957217d579d53ae363f090f Mon Sep 17 00:00:00 2001 From: Nelson Elhage Date: Mon, 31 Oct 2011 17:13:14 -0700 Subject: [PATCH 0038/4025] epoll: fix spurious lockdep warnings commit d8805e633e054c816c47cb6e727c81f156d9253d upstream. epoll can acquire recursively acquire ep->mtx on multiple "struct eventpoll"s at once in the case where one epoll fd is monitoring another epoll fd. This is perfectly OK, since we're careful about the lock ordering, but it causes spurious lockdep warnings. Annotate the recursion using mutex_lock_nested, and add a comment explaining the nesting rules for good measure. Recent versions of systemd are triggering this, and it can also be demonstrated with the following trivial test program: --------------------8<-------------------- int main(void) { int e1, e2; struct epoll_event evt = { .events = EPOLLIN }; e1 = epoll_create1(0); e2 = epoll_create1(0); epoll_ctl(e1, EPOLL_CTL_ADD, e2, &evt); return 0; } --------------------8<-------------------- Reported-by: Paul Bolle Tested-by: Paul Bolle Signed-off-by: Nelson Elhage Acked-by: Jason Baron Cc: Dave Jones Cc: Davide Libenzi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/eventpoll.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/fs/eventpoll.c b/fs/eventpoll.c index f9cfd168fbe..2acaf60f4e4 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -70,6 +70,15 @@ * simultaneous inserts (A into B and B into A) from racing and * constructing a cycle without either insert observing that it is * going to. + * It is necessary to acquire multiple "ep->mtx"es at once in the + * case when one epoll fd is added to another. In this case, we + * always acquire the locks in the order of nesting (i.e. after + * epoll_ctl(e1, EPOLL_CTL_ADD, e2), e1->mtx will always be acquired + * before e2->mtx). Since we disallow cycles of epoll file + * descriptors, this ensures that the mutexes are well-ordered. In + * order to communicate this nesting to lockdep, when walking a tree + * of epoll file descriptors, we use the current recursion depth as + * the lockdep subkey. * It is possible to drop the "ep->mtx" and to use the global * mutex "epmutex" (together with "ep->lock") to have it working, * but having "ep->mtx" will make the interface more scalable. @@ -464,13 +473,15 @@ static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi) * @ep: Pointer to the epoll private data structure. * @sproc: Pointer to the scan callback. * @priv: Private opaque data passed to the @sproc callback. + * @depth: The current depth of recursive f_op->poll calls. * * Returns: The same integer error code returned by the @sproc callback. */ static int ep_scan_ready_list(struct eventpoll *ep, int (*sproc)(struct eventpoll *, struct list_head *, void *), - void *priv) + void *priv, + int depth) { int error, pwake = 0; unsigned long flags; @@ -481,7 +492,7 @@ static int ep_scan_ready_list(struct eventpoll *ep, * We need to lock this because we could be hit by * eventpoll_release_file() and epoll_ctl(). */ - mutex_lock(&ep->mtx); + mutex_lock_nested(&ep->mtx, depth); /* * Steal the ready list, and re-init the original one to the @@ -670,7 +681,7 @@ static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head, static int ep_poll_readyevents_proc(void *priv, void *cookie, int call_nests) { - return ep_scan_ready_list(priv, ep_read_events_proc, NULL); + return ep_scan_ready_list(priv, ep_read_events_proc, NULL, call_nests + 1); } static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait) @@ -737,7 +748,7 @@ void eventpoll_release_file(struct file *file) ep = epi->ep; list_del_init(&epi->fllink); - mutex_lock(&ep->mtx); + mutex_lock_nested(&ep->mtx, 0); ep_remove(ep, epi); mutex_unlock(&ep->mtx); } @@ -1134,7 +1145,7 @@ static int ep_send_events(struct eventpoll *ep, esed.maxevents = maxevents; esed.events = events; - return ep_scan_ready_list(ep, ep_send_events_proc, &esed); + return ep_scan_ready_list(ep, ep_send_events_proc, &esed, 0); } static inline struct timespec ep_set_mstimeout(long ms) @@ -1267,7 +1278,7 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests) struct rb_node *rbp; struct epitem *epi; - mutex_lock(&ep->mtx); + mutex_lock_nested(&ep->mtx, call_nests + 1); for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) { epi = rb_entry(rbp, struct epitem, rbn); if (unlikely(is_file_epoll(epi->ffd.file))) { @@ -1409,7 +1420,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, } - mutex_lock(&ep->mtx); + mutex_lock_nested(&ep->mtx, 0); /* * Try to lookup the file inside our RB tree, Since we grabbed "mtx" From 52f91caed3c682bf032628eaa60a1faa0d577e78 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Mon, 31 Oct 2011 17:12:19 -0700 Subject: [PATCH 0039/4025] leds: save the delay values after a successful call to blink_set() commit 6123b0e274503a0d3588e84fbe07c9aa01bfaf5d upstream. When calling the hardware blinking function implemented by blink_set(), the delay_on and delay_off values are not preserved across calls. Fix that and make the "timer" trigger work as expected when hardware blinking is available. BEFORE the fix: $ cd /sys/class/leds/someled $ echo timer > trigger $ cat delay_on delay_off 0 0 $ echo 100 > delay_on $ cat delay_on delay_off 0 0 $ echo 100 > delay_off $ cat delay_on delay_off 0 0 AFTER the fix: $ cd /sys/class/leds/someled $ echo timer > trigger $ cat delay_on delay_off 0 0 $ echo 100 > delay_on $ cat delay_on delay_off 100 0 $ echo 100 > delay_off $ cat delay_on delay_off 100 100 Signed-off-by: Antonio Ospite Reviewed-by: Johannes Berg Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/leds/led-class.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index dc3d3d83191..5c270aecedc 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -268,8 +268,11 @@ void led_blink_set(struct led_classdev *led_cdev, unsigned long *delay_off) { if (led_cdev->blink_set && - !led_cdev->blink_set(led_cdev, delay_on, delay_off)) + !led_cdev->blink_set(led_cdev, delay_on, delay_off)) { + led_cdev->blink_delay_on = *delay_on; + led_cdev->blink_delay_off = *delay_off; return; + } /* blink with 1 Hz as default if nothing specified */ if (!*delay_on && !*delay_off) From 1470a499e1aaca5dd4bb6e0626211f91af33fb3b Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Mon, 31 Oct 2011 17:12:22 -0700 Subject: [PATCH 0040/4025] leds: turn the blink_timer off before starting to blink commit 488bc35bf40df89d37486c1826b178a2fba36ce7 upstream. Depending on the implementation of the hardware blinking function in blink_set(), the led can support hardware blinking for some values of delay_on and delay_off and fall-back to software blinking for some other values. Turning off the blink_timer unconditionally before starting to blink make sure that a sequence like: OFF hardware blinking software blinking hardware blinking does not leave the software blinking timer active. Signed-off-by: Antonio Ospite Reviewed-by: Johannes Berg Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/leds/led-class.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 5c270aecedc..661b692573e 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -267,6 +267,8 @@ void led_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off) { + del_timer_sync(&led_cdev->blink_timer); + if (led_cdev->blink_set && !led_cdev->blink_set(led_cdev, delay_on, delay_off)) { led_cdev->blink_delay_on = *delay_on; From cdf110e180a088826bfe31156276f186bf7e7e8e Mon Sep 17 00:00:00 2001 From: Johannes Stezenbach Date: Thu, 8 Sep 2011 15:39:15 +0200 Subject: [PATCH 0041/4025] usbmon vs. tcpdump: fix dropped packet count commit 236c448cb6e7f82096101e1ace4b77f8b38f82c8 upstream. Report the number of dropped packets instead of zero when using the binary usbmon interface with tcpdump. # tcpdump -i usbmon1 -w dump tcpdump: listening on usbmon1, link-type USB_LINUX_MMAPPED (USB with padded Linux header), capture size 65535 bytes ^C2155 packets captured 2155 packets received by filter 1019 packets dropped by kernel Signed-off-by: Johannes Stezenbach Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_bin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index a09dbd243eb..a04b2ff9dd8 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -1101,7 +1101,7 @@ static long mon_bin_ioctl(struct file *file, unsigned int cmd, unsigned long arg nevents = mon_bin_queued(rp); sp = (struct mon_bin_stats __user *)arg; - if (put_user(rp->cnt_lost, &sp->dropped)) + if (put_user(ndropped, &sp->dropped)) return -EFAULT; if (put_user(nevents, &sp->queued)) return -EFAULT; From ab6e8fabfbdbca5a7273347e224fe59efe869e76 Mon Sep 17 00:00:00 2001 From: Luben Tuikov Date: Thu, 11 Nov 2010 15:43:11 -0800 Subject: [PATCH 0042/4025] USB: storage: Use normalized sense when emulating autosense commit e16da02fcdf1c5e824432f88abf42623dafdf191 upstream. This patch solves two things: 1) Enables autosense emulation code to correctly interpret descriptor format sense data, and 2) Fixes a bug whereby the autosense emulation code would overwrite descriptor format sense data with SENSE KEY HARDWARE ERROR in fixed format, to incorrectly look like this: Oct 21 14:11:07 localhost kernel: sd 7:0:0:0: [sdc] Sense Key : Recovered Error [current] [descriptor] Oct 21 14:11:07 localhost kernel: Descriptor sense data with sense descriptors (in hex): Oct 21 14:11:07 localhost kernel: 72 01 04 1d 00 00 00 0e 09 0c 00 00 00 00 00 00 Oct 21 14:11:07 localhost kernel: 00 4f 00 c2 00 50 Oct 21 14:11:07 localhost kernel: sd 7:0:0:0: [sdc] ASC=0x4 ASCQ=0x1d Signed-off-by: Luben Tuikov Acked-by: Alan Stern Acked-by: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/transport.c | 34 ++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index e8ae21b2d38..ff32390d61e 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -691,6 +691,9 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) int temp_result; struct scsi_eh_save ses; int sense_size = US_SENSE_SIZE; + struct scsi_sense_hdr sshdr; + const u8 *scdd; + u8 fm_ili; /* device supports and needs bigger sense buffer */ if (us->fflags & US_FL_SANE_SENSE) @@ -774,32 +777,30 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) srb->sense_buffer[7] = (US_SENSE_SIZE - 8); } + scsi_normalize_sense(srb->sense_buffer, SCSI_SENSE_BUFFERSIZE, + &sshdr); + US_DEBUGP("-- Result from auto-sense is %d\n", temp_result); US_DEBUGP("-- code: 0x%x, key: 0x%x, ASC: 0x%x, ASCQ: 0x%x\n", - srb->sense_buffer[0], - srb->sense_buffer[2] & 0xf, - srb->sense_buffer[12], - srb->sense_buffer[13]); + sshdr.response_code, sshdr.sense_key, + sshdr.asc, sshdr.ascq); #ifdef CONFIG_USB_STORAGE_DEBUG - usb_stor_show_sense( - srb->sense_buffer[2] & 0xf, - srb->sense_buffer[12], - srb->sense_buffer[13]); + usb_stor_show_sense(sshdr.sense_key, sshdr.asc, sshdr.ascq); #endif /* set the result so the higher layers expect this data */ srb->result = SAM_STAT_CHECK_CONDITION; + scdd = scsi_sense_desc_find(srb->sense_buffer, + SCSI_SENSE_BUFFERSIZE, 4); + fm_ili = (scdd ? scdd[3] : srb->sense_buffer[2]) & 0xA0; + /* We often get empty sense data. This could indicate that * everything worked or that there was an unspecified * problem. We have to decide which. */ - if ( /* Filemark 0, ignore EOM, ILI 0, no sense */ - (srb->sense_buffer[2] & 0xaf) == 0 && - /* No ASC or ASCQ */ - srb->sense_buffer[12] == 0 && - srb->sense_buffer[13] == 0) { - + if (sshdr.sense_key == 0 && sshdr.asc == 0 && sshdr.ascq == 0 && + fm_ili == 0) { /* If things are really okay, then let's show that. * Zero out the sense buffer so the higher layers * won't realize we did an unsolicited auto-sense. @@ -814,7 +815,10 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) */ } else { srb->result = DID_ERROR << 16; - srb->sense_buffer[2] = HARDWARE_ERROR; + if ((sshdr.response_code & 0x72) == 0x72) + srb->sense_buffer[1] = HARDWARE_ERROR; + else + srb->sense_buffer[2] = HARDWARE_ERROR; } } } From f72d6f85aa5857d889a2b4a41f2bd6be4918703a Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 6 Oct 2011 15:35:43 -0400 Subject: [PATCH 0043/4025] USB: Fix runtime wakeup on OHCI commit a8b43c00ef06aec49b9fe0a5bad8a6a320e4d27b upstream. At least some OHCI hardware (such as the MCP89) fails to flag any change in the host status register or the port status registers when receiving a remote wakeup while in D3 state. This results in the controller being resumed but no device state change being noticed, at which point the controller is put back to sleep again. Since there doesn't seem to be any reliable way to identify the state change, just unconditionally resume the hub. It'll be put back to sleep in the near future anyway if there are no active devices attached to it. Signed-off-by: Matthew Garrett Cc: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hub.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 9154615292d..2f00040fc40 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -356,10 +356,7 @@ static void ohci_finish_controller_resume(struct usb_hcd *hcd) msleep(20); } - /* Does the root hub have a port wakeup pending? */ - if (ohci_readl(ohci, &ohci->regs->intrstatus) & - (OHCI_INTR_RD | OHCI_INTR_RHSC)) - usb_hcd_resume_root_hub(hcd); + usb_hcd_resume_root_hub(hcd); } /* Carry out polling-, autostop-, and autoresume-related state changes */ From 76fa3531d09c55ecf99ea62f13f8b1dd8be076e1 Mon Sep 17 00:00:00 2001 From: Fabian Godehardt Date: Thu, 1 Sep 2011 14:15:46 +0200 Subject: [PATCH 0044/4025] USB: g_printer: fix bug in unregistration commit 8582d86143c690c68cc42f996def466a035bee34 upstream. The allocated chardevice region range is only 1 device but on unregister it currently tries to deregister 2. Found this while doing a insmod/rmmod/insmod/rm... of the module which seemed to eat major numbers. Signed-off-by: Fabian Godehardt Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/printer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 271ef94668e..88a464cc96c 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -1602,7 +1602,7 @@ cleanup(void) if (status) ERROR(dev, "usb_gadget_unregister_driver %x\n", status); - unregister_chrdev_region(g_printer_devno, 2); + unregister_chrdev_region(g_printer_devno, 1); class_destroy(usb_gadget_class); mutex_unlock(&usb_printer_gadget.lock_printer_io); } From 1faec480bbcf3917205feef90ae1e1b38edceaf6 Mon Sep 17 00:00:00 2001 From: Matthias Dellweg <2500@gmx.de> Date: Sun, 25 Sep 2011 14:26:25 +0200 Subject: [PATCH 0045/4025] usb/core/devio.c: Check for printer class specific request commit 393cbb5151ecda9f9e14e3082d048dd27a1ff9f6 upstream. In the usb printer class specific request get_device_id the value of wIndex is (interface << 8 | altsetting) instead of just interface. This enables the detection of some printers with libusb. Acked-by: Alan Stern Signed-off-by: Matthias Dellweg <2500@gmx.de> Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 37518dfdeb9..1d73709c41b 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -607,9 +607,10 @@ static int findintfep(struct usb_device *dev, unsigned int ep) } static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, - unsigned int index) + unsigned int request, unsigned int index) { int ret = 0; + struct usb_host_interface *alt_setting; if (ps->dev->state != USB_STATE_UNAUTHENTICATED && ps->dev->state != USB_STATE_ADDRESS @@ -618,6 +619,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype)) return 0; + /* + * check for the special corner case 'get_device_id' in the printer + * class specification, where wIndex is (interface << 8 | altsetting) + * instead of just interface + */ + if (requesttype == 0xa1 && request == 0) { + alt_setting = usb_find_alt_setting(ps->dev->actconfig, + index >> 8, index & 0xff); + if (alt_setting + && alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER) + index >>= 8; + } + index &= 0xff; switch (requesttype & USB_RECIP_MASK) { case USB_RECIP_ENDPOINT: @@ -770,7 +784,8 @@ static int proc_control(struct dev_state *ps, void __user *arg) if (copy_from_user(&ctrl, arg, sizeof(ctrl))) return -EFAULT; - ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex); + ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.bRequest, + ctrl.wIndex); if (ret) return ret; wLength = ctrl.wLength; /* To suppress 64k PAGE_SIZE warning */ @@ -1100,7 +1115,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, kfree(dr); return -EINVAL; } - ret = check_ctrlrecip(ps, dr->bRequestType, + ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest, le16_to_cpup(&dr->wIndex)); if (ret) { kfree(dr); From 62a5ac8b5fa6381fca135325166fb71b5e413be6 Mon Sep 17 00:00:00 2001 From: Serge Hallyn Date: Mon, 26 Sep 2011 10:18:29 -0500 Subject: [PATCH 0046/4025] USB: pid_ns: ensure pid is not freed during kill_pid_info_as_uid commit aec01c5895051849ed842dc5b8794017a7751f28 upstream. Alan Stern points out that after spin_unlock(&ps->lock) there is no guarantee that ps->pid won't be freed. Since kill_pid_info_as_uid() is called after the spin_unlock(), the pid passed to it must be pinned. Reported-by: Alan Stern Signed-off-by: Serge Hallyn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/devio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 1d73709c41b..0ca54e22d31 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -407,7 +407,7 @@ static void async_completed(struct urb *urb) sinfo.si_errno = as->status; sinfo.si_code = SI_ASYNCIO; sinfo.si_addr = as->userurb; - pid = as->pid; + pid = get_pid(as->pid); uid = as->uid; euid = as->euid; secid = as->secid; @@ -422,9 +422,11 @@ static void async_completed(struct urb *urb) cancel_bulk_urbs(ps, as->bulk_addr); spin_unlock(&ps->lock); - if (signr) + if (signr) { kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid, euid, secid); + put_pid(pid); + } wake_up(&ps->wait); } From 2305a1169c91eee50fe91204692eebea8dce6b6c Mon Sep 17 00:00:00 2001 From: Denis Pershin Date: Sun, 4 Sep 2011 17:37:21 +0700 Subject: [PATCH 0047/4025] usb: cdc-acm: Owen SI-30 support commit 65e52f41fa944cef2e6d4222b8c54f46cc575214 upstream. here is the patch to support Owen SI-30 device. This is a pulse counter controller. http://www.owen.ru/en/catalog/93788515 usb-drivers output: T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=02(commc) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 P: Vendor=03eb ProdID=0030 Rev=01.01 C: #Ifs= 2 Cfg#= 1 Atr=c0 MxPwr=0mA I: If#= 0 Alt= 0 #EPs= 1 Cls=02(commc) Sub=02 Prot=00 Driver=cdc_acm I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=cdc_acm This patch is installed on my home system which receives data from this controller connected to cold water counter. Signed-off-by: Denis Pershin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index dac7676ce21..5112f572677 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1534,6 +1534,9 @@ static const struct usb_device_id acm_ids[] = { { NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */ { SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */ + /* Support for Owen devices */ + { USB_DEVICE(0x03eb, 0x0030), }, /* Owen SI30 */ + /* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */ /* Support Lego NXT using pbLua firmware */ From a8de96f08123ea80b04264e9faecfa34118ce4d8 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 13 Sep 2011 08:42:21 +0200 Subject: [PATCH 0048/4025] USB: add RESET_RESUME for webcams shown to be quirky commit 2394d67e446bf616a0885167d5f0d397bdacfdfc upstream. The new runtime PM code has shown that many webcams suffer from a race condition that may crash them upon resume. Runtime PM is especially prone to show the problem because it retains power to the cameras at all times. However system suspension may also crash the devices and retain power to the devices. The only way to solve this problem without races is in usbcore with the RESET_RESUME quirk. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 81ce6a8e1d9..38f0510e760 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -38,6 +38,24 @@ static const struct usb_device_id usb_quirk_list[] = { /* Creative SB Audigy 2 NX */ { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam C200 */ + { USB_DEVICE(0x046d, 0x0802), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C250 */ + { USB_DEVICE(0x046d, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam B/C500 */ + { USB_DEVICE(0x046d, 0x0807), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam Pro 9000 */ + { USB_DEVICE(0x046d, 0x0809), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C310 */ + { USB_DEVICE(0x046d, 0x081b), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C270 */ + { USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Harmony 700-series */ { USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT }, @@ -69,6 +87,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x06a3, 0x0006), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, + /* Guillemot Webcam Hercules Dualpix Exchange*/ + { USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME }, + /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, From 30dd5b9fd9ccc9cf661a72d54ef67511cdadbec1 Mon Sep 17 00:00:00 2001 From: Jon Levell Date: Thu, 29 Sep 2011 20:42:52 +0100 Subject: [PATCH 0049/4025] USB: add quirk for Logitech C300 web cam commit 5b253d88cc6c65a23cefc457a5a4ef139913c5fc upstream. My webcam is a Logitech C300 and I get "chipmunk"ed squeaky sound. The following trivial patch fixes it. Signed-off-by: Jon Levell Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 38f0510e760..d6a8d8269bf 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -44,6 +44,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Logitech Webcam C250 */ { USB_DEVICE(0x046d, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam C300 */ + { USB_DEVICE(0x046d, 0x0805), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam B/C500 */ { USB_DEVICE(0x046d, 0x0807), .driver_info = USB_QUIRK_RESET_RESUME }, From f06eb26fd629d39f3cfc729dc08668d89b137650 Mon Sep 17 00:00:00 2001 From: Eric Benoit Date: Sat, 24 Sep 2011 02:04:50 -0400 Subject: [PATCH 0050/4025] USB: pl2303: add id for SMART device commit 598f0b703506da841d3459dc0c48506be14d1778 upstream. Add vendor and product ID for the SMART USB to serial adapter. These were meant to be used with their SMART Board whiteboards, but can be re-purposed for other tasks. Tested and working (at at least 9600 bps). Signed-off-by: Eric Benoit Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/pl2303.c | 1 + drivers/usb/serial/pl2303.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 1d33260de01..614fabc6a15 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -92,6 +92,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, { USB_DEVICE(WINCHIPHEAD_VENDOR_ID, WINCHIPHEAD_USBSER_PRODUCT_ID) }, + { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index ca0d237683b..3d10d7f0207 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -148,3 +148,8 @@ /* WinChipHead USB->RS 232 adapter */ #define WINCHIPHEAD_VENDOR_ID 0x4348 #define WINCHIPHEAD_USBSER_PRODUCT_ID 0x5523 + +/* SMART USB Serial Adapter */ +#define SMART_VENDOR_ID 0x0b8c +#define SMART_PRODUCT_ID 0x2303 + From 9eacde321d0b3e1fed9478a8c02110392e96d039 Mon Sep 17 00:00:00 2001 From: Hakan Kvist Date: Mon, 3 Oct 2011 13:41:15 +0200 Subject: [PATCH 0051/4025] USB: ftdi_sio: add PID for Sony Ericsson Urban commit 74bdf22b5c3858b06af46f19d05c23e76c40a3bb upstream. Add PID 0xfc8a, 0xfc8b for device Sony Ericsson Urban Signed-off-by: Hakan Kvist Signed-off-by: Oskar Andero Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 ++ drivers/usb/serial/ftdi_sio_ids.h | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index f968a3debf1..1a2a2f5c46f 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -206,6 +206,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_XF_640_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_642_PID) }, { USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_URBAN_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_URBAN_1_PID) }, { USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) }, { USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) }, { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 19156d1049f..4519f9f86d7 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -420,9 +420,11 @@ #define PROTEGO_SPECIAL_4 0xFC73 /* special/unknown device */ /* - * DSS-20 Sync Station for Sony Ericsson P800 + * Sony Ericsson product ids */ -#define FTDI_DSS20_PID 0xFC82 +#define FTDI_DSS20_PID 0xFC82 /* DSS-20 Sync Station for Sony Ericsson P800 */ +#define FTDI_URBAN_0_PID 0xFC8A /* Sony Ericsson Urban, uart #0 */ +#define FTDI_URBAN_1_PID 0xFC8B /* Sony Ericsson Urban, uart #1 */ /* www.irtrans.de device */ #define FTDI_IRTRANS_PID 0xFC60 /* Product Id */ From 1d2c1def575aa7dec304f820fdf4c01726416042 Mon Sep 17 00:00:00 2001 From: Peter Stuge Date: Mon, 10 Oct 2011 03:34:54 +0200 Subject: [PATCH 0052/4025] USB: ftdi_sio: Support TI/Luminary Micro Stellaris BD-ICDI Board commit 3687f641307eeff6f7fe31a88dc39db88e89238b upstream. Some Stellaris evaluation kits have the JTAG/SWD FTDI chip onboard, and some, like EK-LM3S9B90, come with a separate In-Circuit Debugger Interface Board. The ICDI board can also be used stand-alone, for other boards and chips than the kit it came with. The ICDI has both old style 20-pin JTAG connector and new style JTAG/SWD 10-pin 1.27mm pitch connector. Tested with EK-LM3S9B90, where the BD-ICDI board is included. Signed-off-by: Peter Stuge Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 ++ drivers/usb/serial/ftdi_sio_ids.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 1a2a2f5c46f..1f7da48a0fb 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -746,6 +746,8 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, LMI_LM3S_EVAL_BOARD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, LMI_LM3S_ICDI_BOARD_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 4519f9f86d7..f35ee4d1245 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -54,6 +54,7 @@ /* FTDI 2332C Dual channel device, side A=245 FIFO (JTAG), Side B=RS232 UART */ #define LMI_LM3S_DEVEL_BOARD_PID 0xbcd8 #define LMI_LM3S_EVAL_BOARD_PID 0xbcd9 +#define LMI_LM3S_ICDI_BOARD_PID 0xbcda #define FTDI_TURTELIZER_PID 0xBDC8 /* JTAG/RS-232 adapter by egnite GmbH */ From 03c4fd7b657b3ea22c86a6b7e5b01aa0cfdb52bd Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 13 Sep 2011 13:49:41 -0500 Subject: [PATCH 0053/4025] USB: option: convert interface blacklisting to bitfields commit b4626c10928c13ee73b013dcbc23676333e79b59 upstream. It's cleaner than the array stuff, and we're about to add a bunch more blacklist entries. Second, there are devices that need both the sendsetup and the reserved interface blacklists, which the current code can't accommodate. Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 53 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index fe22e90bc87..d4fc3c38eee 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -475,31 +475,24 @@ enum option_blacklist_reason { OPTION_BLACKLIST_RESERVED_IF = 2 }; +#define MAX_BL_NUM 8 struct option_blacklist_info { - const u32 infolen; /* number of interface numbers on blacklist */ - const u8 *ifaceinfo; /* pointer to the array holding the numbers */ - enum option_blacklist_reason reason; + /* bitfield of interface numbers for OPTION_BLACKLIST_SENDSETUP */ + const unsigned long sendsetup; + /* bitfield of interface numbers for OPTION_BLACKLIST_RESERVED_IF */ + const unsigned long reserved; }; -static const u8 four_g_w14_no_sendsetup[] = { 0, 1 }; static const struct option_blacklist_info four_g_w14_blacklist = { - .infolen = ARRAY_SIZE(four_g_w14_no_sendsetup), - .ifaceinfo = four_g_w14_no_sendsetup, - .reason = OPTION_BLACKLIST_SENDSETUP + .sendsetup = BIT(0) | BIT(1), }; -static const u8 alcatel_x200_no_sendsetup[] = { 0, 1 }; static const struct option_blacklist_info alcatel_x200_blacklist = { - .infolen = ARRAY_SIZE(alcatel_x200_no_sendsetup), - .ifaceinfo = alcatel_x200_no_sendsetup, - .reason = OPTION_BLACKLIST_SENDSETUP + .sendsetup = BIT(0) | BIT(1), }; -static const u8 zte_k3765_z_no_sendsetup[] = { 0, 1, 2 }; static const struct option_blacklist_info zte_k3765_z_blacklist = { - .infolen = ARRAY_SIZE(zte_k3765_z_no_sendsetup), - .ifaceinfo = zte_k3765_z_no_sendsetup, - .reason = OPTION_BLACKLIST_SENDSETUP + .sendsetup = BIT(0) | BIT(1) | BIT(2), }; static const struct usb_device_id option_ids[] = { @@ -1255,21 +1248,28 @@ static int option_probe(struct usb_serial *serial, return 0; } -static enum option_blacklist_reason is_blacklisted(const u8 ifnum, - const struct option_blacklist_info *blacklist) +static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason, + const struct option_blacklist_info *blacklist) { - const u8 *info; - int i; + unsigned long num; + const unsigned long *intf_list; if (blacklist) { - info = blacklist->ifaceinfo; + if (reason == OPTION_BLACKLIST_SENDSETUP) + intf_list = &blacklist->sendsetup; + else if (reason == OPTION_BLACKLIST_RESERVED_IF) + intf_list = &blacklist->reserved; + else { + BUG_ON(reason); + return false; + } - for (i = 0; i < blacklist->infolen; i++) { - if (info[i] == ifnum) - return blacklist->reason; + for_each_set_bit(num, intf_list, MAX_BL_NUM + 1) { + if (num == ifnum) + return true; } } - return OPTION_BLACKLIST_NONE; + return false; } static void option_instat_callback(struct urb *urb) @@ -1343,9 +1343,8 @@ static int option_send_setup(struct usb_serial_port *port) int val = 0; dbg("%s", __func__); - if (is_blacklisted(ifNum, - (struct option_blacklist_info *) intfdata->private) - == OPTION_BLACKLIST_SENDSETUP) { + if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP, + (struct option_blacklist_info *) intfdata->private)) { dbg("No send_setup on blacklisted interface #%d\n", ifNum); return -EIO; } From af7b2c02829fedfcc02732e31f09bf5968bb0c52 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 13 Sep 2011 13:51:13 -0500 Subject: [PATCH 0054/4025] USB: option: convert Huawei K3765, K4505, K4605 reservered interface to blacklist commit 0d905fd5ece4ab65e8407c450077744e1c8f661b upstream. That's what the blacklist is for... Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 79 ++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index d4fc3c38eee..fc9e874a768 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -495,6 +495,10 @@ static const struct option_blacklist_info zte_k3765_z_blacklist = { .sendsetup = BIT(0) | BIT(1) | BIT(2), }; +static const struct option_blacklist_info huawei_cdc12_blacklist = { + .reserved = BIT(1) | BIT(2), +}; + static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -592,12 +596,15 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3806, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x31) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x32) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x31) }, @@ -1207,10 +1214,35 @@ static void __exit option_exit(void) module_init(option_init); module_exit(option_exit); +static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason, + const struct option_blacklist_info *blacklist) +{ + unsigned long num; + const unsigned long *intf_list; + + if (blacklist) { + if (reason == OPTION_BLACKLIST_SENDSETUP) + intf_list = &blacklist->sendsetup; + else if (reason == OPTION_BLACKLIST_RESERVED_IF) + intf_list = &blacklist->reserved; + else { + BUG_ON(reason); + return false; + } + + for_each_set_bit(num, intf_list, MAX_BL_NUM + 1) { + if (num == ifnum) + return true; + } + } + return false; +} + static int option_probe(struct usb_serial *serial, const struct usb_device_id *id) { struct usb_wwan_intf_private *data; + /* D-Link DWM 652 still exposes CD-Rom emulation interface in modem mode */ if (serial->dev->descriptor.idVendor == DLINK_VENDOR_ID && serial->dev->descriptor.idProduct == DLINK_PRODUCT_DWM_652 && @@ -1223,14 +1255,14 @@ static int option_probe(struct usb_serial *serial, serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff) return -ENODEV; - /* Don't bind network interfaces on Huawei K3765, K4505 & K4605 */ - if (serial->dev->descriptor.idVendor == HUAWEI_VENDOR_ID && - (serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K3765 || - serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K4505 || - serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K4605) && - (serial->interface->cur_altsetting->desc.bInterfaceNumber == 1 || - serial->interface->cur_altsetting->desc.bInterfaceNumber == 2)) - return -ENODEV; + /* Don't bind reserved interfaces (like network ones) which often have + * the same class/subclass/protocol as the serial interfaces. Look at + * the Windows driver .INF files for reserved interface numbers. + */ + if (is_blacklisted( + serial->interface->cur_altsetting->desc.bInterfaceNumber, + OPTION_BLACKLIST_RESERVED_IF, + (const struct option_blacklist_info *) id->driver_info)) /* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */ if (serial->dev->descriptor.idVendor == SAMSUNG_VENDOR_ID && @@ -1239,7 +1271,6 @@ static int option_probe(struct usb_serial *serial, return -ENODEV; data = serial->private = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); - if (!data) return -ENOMEM; data->send_setup = option_send_setup; @@ -1248,30 +1279,6 @@ static int option_probe(struct usb_serial *serial, return 0; } -static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason, - const struct option_blacklist_info *blacklist) -{ - unsigned long num; - const unsigned long *intf_list; - - if (blacklist) { - if (reason == OPTION_BLACKLIST_SENDSETUP) - intf_list = &blacklist->sendsetup; - else if (reason == OPTION_BLACKLIST_RESERVED_IF) - intf_list = &blacklist->reserved; - else { - BUG_ON(reason); - return false; - } - - for_each_set_bit(num, intf_list, MAX_BL_NUM + 1) { - if (num == ifnum) - return true; - } - } - return false; -} - static void option_instat_callback(struct urb *urb) { int err; From cf39988db6f0e4e15c6fa81100ab18ae63dcf3a1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 13 Sep 2011 13:51:45 -0500 Subject: [PATCH 0055/4025] USB: option: add ZTE product 0x0037 to sendsetup blacklist commit eb05ce567a81c592c58f4bdb96eb91ce96661c30 upstream. Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index fc9e874a768..7a336f7089a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -491,6 +491,10 @@ static const struct option_blacklist_info alcatel_x200_blacklist = { .sendsetup = BIT(0) | BIT(1), }; +static const struct option_blacklist_info zte_0037_blacklist = { + .sendsetup = BIT(0) | BIT(1), +}; + static const struct option_blacklist_info zte_k3765_z_blacklist = { .sendsetup = BIT(0) | BIT(1) | BIT(2), }; @@ -743,7 +747,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0032, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0033, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0034, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0037, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&zte_0037_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0038, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0039, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0040, 0xff, 0xff, 0xff) }, From 68401aa09eece84a291c98d3c2d39d09f7f7336f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 13 Sep 2011 13:52:52 -0500 Subject: [PATCH 0056/4025] USB: option: add various ZTE device network interfaces to the blacklist commit c58a76cdd7ab5a945a44fd2d64f6faf40323f95b upstream. IDs found in the Windows driver's ZTEusbnet.inf file from the ZTE MF100 drivers (O2 UK). Also fixes the ZTE MF626 device since it really is distinct from the 4G Systems stick and apparently needs the net interface blacklisted too, while there's no indication (yet) that the 4G Systems stick does. Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 63 ++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 14 deletions(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 7a336f7089a..89ae1f65e1b 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -497,12 +497,34 @@ static const struct option_blacklist_info zte_0037_blacklist = { static const struct option_blacklist_info zte_k3765_z_blacklist = { .sendsetup = BIT(0) | BIT(1) | BIT(2), + .reserved = BIT(4), }; static const struct option_blacklist_info huawei_cdc12_blacklist = { .reserved = BIT(1) | BIT(2), }; +static const struct option_blacklist_info net_intf1_blacklist = { + .reserved = BIT(1), +}; + +static const struct option_blacklist_info net_intf3_blacklist = { + .reserved = BIT(3), +}; + +static const struct option_blacklist_info net_intf4_blacklist = { + .reserved = BIT(4), +}; + +static const struct option_blacklist_info net_intf5_blacklist = { + .reserved = BIT(5), +}; + +static const struct option_blacklist_info zte_mf626_blacklist = { + .sendsetup = BIT(0) | BIT(1), + .reserved = BIT(4), +}; + static const struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) }, @@ -709,7 +731,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0003, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0004, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0005, 0xff, 0xff, 0xff) }, @@ -724,26 +747,30 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x000f, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0010, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0011, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0013, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0016, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0018, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0019, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0020, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0021, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0022, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0023, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0024, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, /* { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0026, 0xff, 0xff, 0xff) }, */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0028, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0029, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0030, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626, 0xff, - 0xff, 0xff), .driver_info = (kernel_ulong_t)&four_g_w14_blacklist }, + 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_mf626_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0032, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0033, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0034, 0xff, 0xff, 0xff) }, @@ -752,24 +779,30 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0038, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0039, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0040, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0042, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0043, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0044, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0048, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0049, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0050, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0051, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, /* { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0053, 0xff, 0xff, 0xff) }, */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0054, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0056, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0057, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0061, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0062, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0064, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0065, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0066, 0xff, 0xff, 0xff) }, @@ -784,11 +817,13 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0083, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0086, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0087, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0105, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0106, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0108, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0113, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0117, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0118, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0121, 0xff, 0xff, 0xff) }, From 0ada2d28df779a5368b9ca77e1a7088bbabf68d7 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 23 Aug 2011 15:07:31 -0700 Subject: [PATCH 0057/4025] MAINTANERS: update Qualcomm Atheros addresses commit fe8e084455f273b32cc57a5fbaf6c22ef984d657 upstream. Qualcomm ate up Atheros, all of the old e-mail addresses no longer work and e-mails sent to it will bounce. Update the addresses to the new shiny Qualcomm Atheros (QCA) ones. Cc: stable@kernel.org Cc: netdev@vger.kernel.org Cc: jouni@qca.qualcomm.com Cc: yangjie@qca.qualcomm.com Cc: vthiagar@qca.qualcomm.com Cc: senthilb@qca.qualcomm.com Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 187282da921..34e24186584 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1221,7 +1221,7 @@ F: Documentation/aoe/ F: drivers/block/aoe/ ATHEROS ATH GENERIC UTILITIES -M: "Luis R. Rodriguez" +M: "Luis R. Rodriguez" L: linux-wireless@vger.kernel.org S: Supported F: drivers/net/wireless/ath/* @@ -1229,7 +1229,7 @@ F: drivers/net/wireless/ath/* ATHEROS ATH5K WIRELESS DRIVER M: Jiri Slaby M: Nick Kossifidis -M: "Luis R. Rodriguez" +M: "Luis R. Rodriguez" M: Bob Copeland L: linux-wireless@vger.kernel.org L: ath5k-devel@lists.ath5k.org @@ -1238,10 +1238,10 @@ S: Maintained F: drivers/net/wireless/ath/ath5k/ ATHEROS ATH9K WIRELESS DRIVER -M: "Luis R. Rodriguez" -M: Jouni Malinen -M: Vasanthakumar Thiagarajan -M: Senthil Balasubramanian +M: "Luis R. Rodriguez" +M: Jouni Malinen +M: Vasanthakumar Thiagarajan +M: Senthil Balasubramanian L: linux-wireless@vger.kernel.org L: ath9k-devel@lists.ath9k.org W: http://wireless.kernel.org/en/users/Drivers/ath9k @@ -1269,7 +1269,7 @@ F: drivers/input/misc/ati_remote2.c ATLX ETHERNET DRIVERS M: Jay Cliburn M: Chris Snook -M: Jie Yang +M: Jie Yang L: netdev@vger.kernel.org W: http://sourceforge.net/projects/atl1 W: http://atl1.sourceforge.net From 1ad894adcc396cb74d1ee7173d013a803c457ad8 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Sat, 20 Aug 2011 17:22:09 +0530 Subject: [PATCH 0058/4025] ath9k_hw: Fix descriptor status of TxOpExceeded commit 2a15b394f8e46dd3e2ab365ab41cfa701d92fa77 upstream. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ar9003_mac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index 1f992497186..7880dca026c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -255,8 +255,6 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, return -EIO; } - if (status & AR_TxOpExceeded) - ts->ts_status |= ATH9K_TXERR_XTXOP; ts->ts_rateindex = MS(status, AR_FinalTxIdx); ts->ts_seqnum = MS(status, AR_SeqNum); ts->tid = MS(status, AR_TxTid); @@ -267,6 +265,8 @@ static int ar9003_hw_proc_txdesc(struct ath_hw *ah, void *ds, ts->ts_status = 0; ts->ts_flags = 0; + if (status & AR_TxOpExceeded) + ts->ts_status |= ATH9K_TXERR_XTXOP; status = ACCESS_ONCE(ads->status2); ts->ts_rssi_ctl0 = MS(status, AR_TxRSSIAnt00); ts->ts_rssi_ctl1 = MS(status, AR_TxRSSIAnt01); From 26155866748bad74d6b257ba891d794dad85f621 Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 15 Sep 2011 19:02:25 +0530 Subject: [PATCH 0059/4025] ath9k_hw: Fix magnitude/phase coeff correction commit e9c10469cf3c71bc1c6b0f01319161e277d6ac9b upstream. Do the magnitude/phase coeff correction only if the outlier is detected. Updating wrong magnitude/phase coeff factor impacts not only tx gain setting but also leads to poor performance in congested networks. In the clear environment the impact is very minimal because the outlier happens very rarely according to the past experiment. It occured less than once every 1000 calibrations. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ar9003_calib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index f48051c5009..7c2aaad24ed 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -643,8 +643,9 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement, outlier_idx = max_idx; else outlier_idx = min_idx; + + mp_coeff[outlier_idx] = mp_avg; } - mp_coeff[outlier_idx] = mp_avg; } static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah, From 7ff861f96140c2dc6411deafb281dbfe958324d9 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Thu, 29 Sep 2011 10:42:19 -0700 Subject: [PATCH 0060/4025] ath9k_htc: add AVM FRITZ!WLAN 11N v2 support commit 8c34559b4a6df32e4af1b073397fa4dc189a5485 upstream. This was reported and tested by Martin Walter over at AVM GmbH Berlin. This also applies to 3.0.1 so sendint to stable. Cc: s.kirste@avm.de Cc: d.friedel@avm.de Cc: Martin Walter Cc: Peter Grabienski Tested-by: Martin Walter Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/hif_usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index 260f1f37a60..5513c0aa4c1 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -37,6 +37,7 @@ static struct usb_device_id ath9k_hif_usb_ids[] = { { USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */ { USB_DEVICE(0x040D, 0x3801) }, /* VIA */ { USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */ + { USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */ { USB_DEVICE(0x0cf3, 0x7015), .driver_info = AR9287_USB }, /* Atheros */ From e4779966c769188b76ee699e0ab476030b2d2e6a Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Fri, 30 Sep 2011 11:31:27 +0530 Subject: [PATCH 0061/4025] ath9k_hw: Fix number of GPIO pins for AR9287/9300 commit 6321eb0977b011ac61dfca36e7c69b2c4325b104 upstream. this patch fixes the assumption of maximum number of GPIO pins present in AR9287/AR9300. this fix is essential as we might encounter some functionality issues involved in accessing the status of GPIO pins which are all incorrectly assumed to be not within the range of max_num_gpio of AR9300/AR9287 chipsets Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/hw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 03900ca7d99..7c2f06ed7a1 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1931,6 +1931,10 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) pCap->num_gpio_pins = AR9271_NUM_GPIO; else if (AR_DEVID_7010(ah)) pCap->num_gpio_pins = AR7010_NUM_GPIO; + else if (AR_SREV_9300_20_OR_LATER(ah)) + pCap->num_gpio_pins = AR9300_NUM_GPIO; + else if (AR_SREV_9287_11_OR_LATER(ah)) + pCap->num_gpio_pins = AR9287_NUM_GPIO; else if (AR_SREV_9285_12_OR_LATER(ah)) pCap->num_gpio_pins = AR9285_NUM_GPIO; else if (AR_SREV_9280_20_OR_LATER(ah)) From 07bb3623343d8060b6f68aa294e3ecb9391a82d4 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 8 Oct 2011 15:49:57 +0200 Subject: [PATCH 0062/4025] ath9k: disable unnecessary PHY error reporting commit ac06697c79bad09e44a8b1d52104014016fb90de upstream. PHY errors relevant for ANI are always tracked by hardware counters, the bits that allow them to pass through the rx filter are independent of that. Enabling PHY errors in the rx filter often creates lots of useless DMA traffic and might be responsible for some of the rx dma stop failure warnings. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ani.c | 5 ----- drivers/net/wireless/ath/ath9k/recv.c | 5 +---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index bfb6481f01f..4e4e7c3dcdd 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -502,9 +502,6 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, ATH9K_ANI_CCK_WEAK_SIG_THR); - ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | - ATH9K_RX_FILTER_PHYERR); - ath9k_ani_restart(ah); return; } @@ -525,8 +522,6 @@ static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, aniState->firstepLevel); - ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & - ~ATH9K_RX_FILTER_PHYERR); ath9k_ani_restart(ah); ENABLE_REGWRITE_BUFFER(ah); diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 07e35e59c9e..3b5f9d6e3cb 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -423,12 +423,9 @@ void ath_rx_cleanup(struct ath_softc *sc) u32 ath_calcrxfilter(struct ath_softc *sc) { -#define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) - u32 rfilt; - rfilt = (ath9k_hw_getrxfilter(sc->sc_ah) & RX_FILTER_PRESERVE) - | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST + rfilt = ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST | ATH9K_RX_FILTER_MCAST; if (sc->rx.rxfilter & FIF_PROBE_REQ) From 5b81a5e1aee86808849307d5e025185ee5bde276 Mon Sep 17 00:00:00 2001 From: Sergei Kolzun Date: Thu, 4 Aug 2011 00:25:56 -0700 Subject: [PATCH 0063/4025] HID: ACRUX - fix enabling force feedback support commit 364b936fc38dec7653c690d710e10657af235a36 upstream. The config option needs to be a 'bool' and not a tristate, otheriwse force feedback support never makes it into the module. Signed-off-by: Sergei Kolzun Signed-off-by: Dmitry Torokhov Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 36ca465c00c..a1f3c0ddd01 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -69,7 +69,7 @@ config HID_ACRUX Say Y here if you want to enable support for ACRUX game controllers. config HID_ACRUX_FF - tristate "ACRUX force feedback support" + bool "ACRUX force feedback support" depends on HID_ACRUX select INPUT_FF_MEMLESS ---help--- From d25b0f91d1f35a91b2eb49d139fa2803f55b6b47 Mon Sep 17 00:00:00 2001 From: Jerry Huang Date: Tue, 18 Oct 2011 13:09:48 +0800 Subject: [PATCH 0064/4025] QE/FHCI: fixed the CONTROL bug commit 273d23574f9dacd9c63c80e7d63639a669aad441 upstream. For USB CONTROL transaction, when the data length is zero, the IN package is needed to finish this transaction in status stage. Signed-off-by: Jerry Huang Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/fhci-sched.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c index a42ef380e91..2df851b4bc7 100644 --- a/drivers/usb/host/fhci-sched.c +++ b/drivers/usb/host/fhci-sched.c @@ -1,7 +1,7 @@ /* * Freescale QUICC Engine USB Host Controller Driver * - * Copyright (c) Freescale Semicondutor, Inc. 2006. + * Copyright (c) Freescale Semicondutor, Inc. 2006, 2011. * Shlomi Gridish * Jerry Huang * Copyright (c) Logic Product Development, Inc. 2007 @@ -810,9 +810,11 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) ed->dev_addr = usb_pipedevice(urb->pipe); ed->max_pkt_size = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); + /* setup stage */ td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_SETUP, USB_TD_TOGGLE_DATA0, urb->setup_packet, 8, 0, 0, true); + /* data stage */ if (data_len > 0) { td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, usb_pipeout(urb->pipe) ? FHCI_TA_OUT : @@ -820,9 +822,18 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) USB_TD_TOGGLE_DATA1, data, data_len, 0, 0, true); } - td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, - usb_pipeout(urb->pipe) ? FHCI_TA_IN : FHCI_TA_OUT, - USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true); + + /* status stage */ + if (data_len > 0) + td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, + (usb_pipeout(urb->pipe) ? FHCI_TA_IN : + FHCI_TA_OUT), + USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true); + else + td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, + FHCI_TA_IN, + USB_TD_TOGGLE_DATA1, data, 0, 0, 0, true); + urb_state = US_CTRL_SETUP; break; case FHCI_TF_ISO: From f9409cf55e878e48f3649522b06a3f7c74d48f8c Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 17 Oct 2011 21:16:39 -0400 Subject: [PATCH 0065/4025] Update email address for stable patch submission commit 5fa224295f0e0358c8bc0e5390702338df889def upstream. The stable@kernel.org email address has been replaced with the stable@vger.kernel.org mailing list. Change the stable kernel rules to reference the new list instead of the semi-defunct email alias. Signed-off-by: Josh Boyer Signed-off-by: Greg Kroah-Hartman --- Documentation/stable_kernel_rules.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt index e213f45cf9d..21fd05c28e7 100644 --- a/Documentation/stable_kernel_rules.txt +++ b/Documentation/stable_kernel_rules.txt @@ -24,10 +24,10 @@ Rules on what kind of patches are accepted, and which ones are not, into the Procedure for submitting patches to the -stable tree: - Send the patch, after verifying that it follows the above rules, to - stable@kernel.org. You must note the upstream commit ID in the changelog - of your submission. + stable@vger.kernel.org. You must note the upstream commit ID in the + changelog of your submission. - To have the patch automatically included in the stable tree, add the tag - Cc: stable@kernel.org + Cc: stable@vger.kernel.org in the sign-off area. Once the patch is merged it will be applied to the stable tree without anything else needing to be done by the author or subsystem maintainer. @@ -35,10 +35,10 @@ Procedure for submitting patches to the -stable tree: cherry-picked than this can be specified in the following format in the sign-off area: - Cc: # .32.x: a1f84a3: sched: Check for idle - Cc: # .32.x: 1b9508f: sched: Rate-limit newidle - Cc: # .32.x: fd21073: sched: Fix affinity logic - Cc: # .32.x + Cc: # .32.x: a1f84a3: sched: Check for idle + Cc: # .32.x: 1b9508f: sched: Rate-limit newidle + Cc: # .32.x: fd21073: sched: Fix affinity logic + Cc: # .32.x Signed-off-by: Ingo Molnar The tag sequence has the meaning of: From 50bac9ce730674d25f010b5a591e8376e001658f Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 22 Jul 2011 12:18:43 -0400 Subject: [PATCH 0066/4025] xen-pcifront: Update warning comment to use 'e820_host' option. commit 917e3e65c35459d52f0d0b890aa5df0cad07a051 upstream. With Xen changeset 23428 "libxl: Add 'e820_host' option to config file" the E820 as seen from the host can now be passed into the guest. This means that a PV guest can now: - Use the correct PCI I/O gap. Before these patches, Linux guest would boot up and would tell: [ 0.000000] Allocating PCI resources starting at 40000000 (gap: 40000000:c0000000) while in actuality the PCI I/O gap should have been: [ 0.000000] Allocating PCI resources starting at b0000000 (gap: b0000000:4c000000) - The PV domain with PCI devices was limited to 3GB. It now can be booted with 4GB, 8GB, or whatever number you want. The PCI devices will now _not_ conflict with System RAM. Meaning the drivers can load. CC: Jesse Barnes CC: linux-pci@vger.kernel.org [v2: Made the string less broken up. Suggested by Joe Perches] Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/pci/xen-pcifront.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 492b7d807fe..d4e7a105225 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -400,9 +400,8 @@ static int pcifront_claim_resource(struct pci_dev *dev, void *data) dev_info(&pdev->xdev->dev, "claiming resource %s/%d\n", pci_name(dev), i); if (pci_claim_resource(dev, i)) { - dev_err(&pdev->xdev->dev, "Could not claim " - "resource %s/%d! Device offline. Try " - "giving less than 4GB to domain.\n", + dev_err(&pdev->xdev->dev, "Could not claim resource %s/%d! " + "Device offline. Try using e820_host=1 in the guest config.\n", pci_name(dev), i); } } From a19d5a89a43fa64f2739bdadbc35d4723ab9bcdb Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 22 Jul 2011 12:51:48 -0400 Subject: [PATCH 0067/4025] xen-swiotlb: Fix wrong panic. commit ab2a47bd242d6cdcf6b2b64797f271c6f0a6d338 upstream. Propagate the baremetal git commit "swiotlb: fix wrong panic" (fba99fa38b023224680308a482e12a0eca87e4e1) in the Xen-SWIOTLB version. wherein swiotlb's map_page wrongly calls panic() when it can't find a buffer fit for device's dma mask. It should return an error instead. Devices with an odd dma mask (i.e. under 4G) like b44 network card hit this bug (the system crashes): http://marc.info/?l=linux-kernel&m=129648943830106&w=2 If xen-swiotlb returns an error, b44 driver can use the own bouncing mechanism. Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/xen/swiotlb-xen.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 6e8c15a2320..84f317e0cc2 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -278,9 +278,10 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, /* * Ensure that the address returned is DMA'ble */ - if (!dma_capable(dev, dev_addr, size)) - panic("map_single: bounce buffer is not DMA'ble"); - + if (!dma_capable(dev, dev_addr, size)) { + swiotlb_tbl_unmap_single(dev, map, size, dir); + dev_addr = 0; + } return dev_addr; } EXPORT_SYMBOL_GPL(xen_swiotlb_map_page); From 7b59e3e29e1a28ad40892dd2115175e2702f1153 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Mon, 22 Aug 2011 15:51:34 +0200 Subject: [PATCH 0068/4025] kobj_uevent: Ignore if some listeners cannot handle message commit ebf4127cd677e9781b450e44dfaaa1cc595efcaa upstream. kobject_uevent() uses a multicast socket and should ignore if one of listeners cannot handle messages or nobody is listening at all. Easily reproducible when a process in system is cloned with CLONE_NEWNET flag. (See also http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/5256) Signed-off-by: Milan Broz Acked-by: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- lib/kobject_uevent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index 70af0a7f97c..ad72a03ce5e 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -282,7 +282,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, kobj_bcast_filter, kobj); /* ENOBUFS should be handled in userspace */ - if (retval == -ENOBUFS) + if (retval == -ENOBUFS || retval == -ESRCH) retval = 0; } else retval = -ENOMEM; From 5c2433cdc72a03446184e2f898be3b05095b5ed0 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 24 Oct 2011 21:25:21 +0000 Subject: [PATCH 0069/4025] caif: Fix BUG() with network namespaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 08613e4626c06ca408fc55071f6aedee36986a87 upstream. The caif code will register its own pernet_operations, and then register a netdevice_notifier. Each time the netdevice_notifier is triggered, it'll do some stuff... including a lookup of its own pernet stuff with net_generic(). If the net_generic() call ever returns NULL, the caif code will BUG(). That doesn't seem *so* unreasonable, I suppose — it does seem like it should never happen. However, it *does* happen. When we clone a network namespace, setup_net() runs through all the pernet_operations one at a time. It gets to loopback before it gets to caif. And loopback_net_init() registers a netdevice... while caif hasn't been initialised. So the caif netdevice notifier triggers, and immediately goes BUG(). We could imagine a complex and overengineered solution to this generic class of problems, but this patch takes the simple approach. It just makes caif_device_notify() *not* go looking for its pernet data structures if the device it's being notified about isn't a caif device in the first place. Signed-off-by: David Woodhouse Acked-by: Sjur Brændeland Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/caif/caif_dev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index 682c0fedf36..dbdaa95b800 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -209,8 +209,7 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, enum cfcnfg_phy_preference pref; enum cfcnfg_phy_type phy_type; struct cfcnfg *cfg; - struct caif_device_entry_list *caifdevs = - caif_device_list(dev_net(dev)); + struct caif_device_entry_list *caifdevs; if (dev->type != ARPHRD_CAIF) return 0; @@ -219,6 +218,8 @@ static int caif_device_notify(struct notifier_block *me, unsigned long what, if (cfg == NULL) return 0; + caifdevs = caif_device_list(dev_net(dev)); + switch (what) { case NETDEV_REGISTER: caifd = caif_device_alloc(dev); From b78db0895fff3d3da005f8e03f700b9a559c1065 Mon Sep 17 00:00:00 2001 From: Stefan Beller Date: Tue, 20 Sep 2011 09:16:08 -0700 Subject: [PATCH 0070/4025] platform: samsung_laptop: add dmi information for Samsung R700 laptops commit f87d02996f05ec1789ceecce9ec839f629b7aa80 upstream. My DMI model is this: >dmesg |grep DMI [ 0.000000] DMI present. [ 0.000000] DMI: SAMSUNG ELECTRONICS CO., LTD. SR700/SR700, BIOS 04SR 02/20/2008 adding dmi information of Samsung R700 laptops This adds the dmi information of Samsungs R700 laptops. Signed-off-by: Stefan Beller Signed-off-by: Greg Kroah-Hartman Signed-off-by: Matthew Garrett --- drivers/platform/x86/samsung-laptop.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 16585756df8..35c781baf3b 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -630,6 +630,15 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { }, .callback = dmi_check_cb, }, + { + .ident = "R700", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "SR700"), + DMI_MATCH(DMI_BOARD_NAME, "SR700"), + }, + .callback = dmi_check_cb, + }, { .ident = "R530/R730", .matches = { From b0da5e7b1493c59b04604d6839565a6135773002 Mon Sep 17 00:00:00 2001 From: Tommaso Massimi Date: Tue, 20 Sep 2011 09:16:09 -0700 Subject: [PATCH 0071/4025] Platform: samsung_laptop: add support for X520 machines. commit 7500eeb08a179e61a4219288c21407d63d1e9c64 upstream. my samsung laptop would be very happy if you add these lines to the file drivers/platform/x86/samsung-laptop.c Signed-off-by: Greg Kroah-Hartman Signed-off-by: Matthew Garrett --- drivers/platform/x86/samsung-laptop.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 35c781baf3b..618cd4ec162 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -684,6 +684,15 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "P460"), }, .callback = dmi_check_cb, + }, + { + .ident = "X520", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "X520"), + DMI_MATCH(DMI_BOARD_NAME, "X520"), + }, + .callback = dmi_check_cb, }, { }, }; From 472806574215cfc649b3619b2047785fe2897b58 Mon Sep 17 00:00:00 2001 From: Smelov Andrey Date: Tue, 20 Sep 2011 09:16:10 -0700 Subject: [PATCH 0072/4025] Platform: samsung_laptop: samsung backlight for R528/R728 commit 093ed561648d43263c009ea88abab21a31cd4f1d upstream. patch works for me, but I need to add "acpi_backlight=vendor" to kernel params Signed-off-by: Smelov Andrey Signed-off-by: Greg Kroah-Hartman Signed-off-by: Matthew Garrett --- drivers/platform/x86/samsung-laptop.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 618cd4ec162..ffa7008d0c9 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -694,6 +694,15 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = { }, .callback = dmi_check_cb, }, + { + .ident = "R528/R728", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "R528/R728"), + DMI_MATCH(DMI_BOARD_NAME, "R528/R728"), + }, + .callback = dmi_check_cb, + }, { }, }; MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); From 08a84a609d1679c9aeb958c3bc7886118e682b77 Mon Sep 17 00:00:00 2001 From: Jason Stubbs Date: Tue, 20 Sep 2011 09:16:11 -0700 Subject: [PATCH 0073/4025] platform: samsung_laptop: fix samsung brightness min/max calculations commit bee460be8c691c544e84ed678280ace6153104c6 upstream. The min_brightness value of the sabi_config is incorrectly used in brightness calculations. For the config where min_brightness = 1 and max_brightness = 8, the user visible range should be 0 to 7 with hardware being set in the range of 1 to 8. What is actually happening is that the user visible range is 0 to 8 with hardware being set in the range of -1 to 7. This patch fixes the above issue as well as a miscalculation that would occur in the case of min_brightness > 1. Signed-off-by: Jason Stubbs Signed-off-by: Greg Kroah-Hartman Signed-off-by: Matthew Garrett --- drivers/platform/x86/samsung-laptop.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index ffa7008d0c9..33d3c3f3eb0 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -370,15 +370,17 @@ static u8 read_brightness(void) &sretval); if (!retval) { user_brightness = sretval.retval[0]; - if (user_brightness != 0) + if (user_brightness > sabi_config->min_brightness) user_brightness -= sabi_config->min_brightness; + else + user_brightness = 0; } return user_brightness; } static void set_brightness(u8 user_brightness) { - u8 user_level = user_brightness - sabi_config->min_brightness; + u8 user_level = user_brightness + sabi_config->min_brightness; sabi_set_command(sabi_config->commands.set_brightness, user_level); } @@ -819,7 +821,8 @@ static int __init samsung_init(void) /* create a backlight device to talk to this one */ memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_PLATFORM; - props.max_brightness = sabi_config->max_brightness; + props.max_brightness = sabi_config->max_brightness - + sabi_config->min_brightness; backlight_device = backlight_device_register("samsung", &sdev->dev, NULL, &backlight_ops, &props); From 50f621d8f5b6f9e8ed931df12c595fd0e882f8e3 Mon Sep 17 00:00:00 2001 From: David Herrmann Date: Tue, 20 Sep 2011 09:16:12 -0700 Subject: [PATCH 0074/4025] Platform: Fix error path in samsung-laptop init commit a7ea19926ffba86f373f6050a106cd162dbb9a78 upstream. samsung_init() should not return success if not all devices are initialized. Otherwise, samsung_exit() will dereference sdev NULL pointers and others. Signed-off-by: David Herrmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Matthew Garrett --- drivers/platform/x86/samsung-laptop.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c index 33d3c3f3eb0..ec85987b224 100644 --- a/drivers/platform/x86/samsung-laptop.c +++ b/drivers/platform/x86/samsung-laptop.c @@ -789,7 +789,7 @@ static int __init samsung_init(void) sabi_iface = ioremap_nocache(ifaceP, 16); if (!sabi_iface) { pr_err("Can't remap %x\n", ifaceP); - goto exit; + goto error_no_signature; } if (debug) { printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP); @@ -841,7 +841,6 @@ static int __init samsung_init(void) if (retval) goto error_file_create; -exit: return 0; error_file_create: From 3cdf240310b4f3d94981d727d3660c78a50a40c6 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 26 Oct 2011 13:10:39 +1030 Subject: [PATCH 0075/4025] kmod: prevent kmod_loop_msg overflow in __request_module() commit 37252db6aa576c34fd794a5a54fb32d7a8b3a07a upstream. Due to post-increment in condition of kmod_loop_msg in __request_module(), the system log can be spammed by much more than 5 instances of the 'runaway loop' message if the number of events triggering it makes the kmod_loop_msg to overflow. Fix that by making sure we never increment it past the threshold. Signed-off-by: Jiri Kosina Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman --- kernel/kmod.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/kmod.c b/kernel/kmod.c index 47613dfb7b2..fabfe541b1d 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -114,10 +114,12 @@ int __request_module(bool wait, const char *fmt, ...) atomic_inc(&kmod_concurrent); if (atomic_read(&kmod_concurrent) > max_modprobes) { /* We may be blaming an innocent here, but unlikely */ - if (kmod_loop_msg++ < 5) + if (kmod_loop_msg < 5) { printk(KERN_ERR "request_module: runaway loop modprobe %s\n", module_name); + kmod_loop_msg++; + } atomic_dec(&kmod_concurrent); return -ENOMEM; } From b04a57568d86586d704babc7584e5fff4343fc61 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 17 Oct 2011 18:22:55 -0700 Subject: [PATCH 0076/4025] Revert "NFS: Ensure that writeback_single_inode() calls write_inode() when syncing" commit 59b7c05fffba030e5d9e72324691e2f99aa69b79 upstream. This reverts commit b80c3cb628f0ebc241b02e38dd028969fb8026a2. The reverted commit was rendered obsolete by a VFS fix: commit 5547e8aac6f71505d621a612de2fca0dd988b439 (writeback: Update dirty flags in two steps). We now no longer need to worry about writeback_single_inode() missing our marking the inode for COMMIT in 'do_writepages()' call. Reverting this patch, fixes a performance regression in which the inode would continuously get queued to the dirty list, causing the writeback code to unnecessarily try to send a COMMIT. Signed-off-by: Trond Myklebust Tested-by: Simon Kirby Signed-off-by: Greg Kroah-Hartman --- fs/nfs/write.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 72716805968..07e9e79b8b4 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -428,7 +428,6 @@ static void nfs_mark_request_dirty(struct nfs_page *req) { __set_page_dirty_nobuffers(req->wb_page); - __mark_inode_dirty(req->wb_page->mapping->host, I_DIRTY_DATASYNC); } #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) @@ -762,6 +761,8 @@ int nfs_updatepage(struct file *file, struct page *page, status = nfs_writepage_setup(ctx, page, offset, count); if (status < 0) nfs_set_pageerror(page); + else + __set_page_dirty_nobuffers(page); dprintk("NFS: nfs_updatepage returns %d (isize %lld)\n", status, (long long)i_size_read(inode)); From 363d0372b331c8ac8ef54c0bd81aadea43cfd74c Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 11 Oct 2011 09:49:21 -0400 Subject: [PATCH 0077/4025] nfs: don't redirty inode when ncommit == 0 in nfs_commit_unstable_pages commit 3236c3e1adc0c7ec83eaff1de2d06746b7c5bb28 upstream. commit 420e3646 allowed the kernel to reduce the number of unnecessary commit calls by skipping the commit when there are a large number of outstanding pages. However, the current test in nfs_commit_unstable_pages does not handle the edge condition properly. When ncommit == 0, then that means that the kernel doesn't need to do anything more for the inode. The current test though in the WB_SYNC_NONE case will return true, and the inode will end up being marked dirty. Once that happens the inode will never be clean until there's a WB_SYNC_ALL flush. Fix this by immediately returning from nfs_commit_unstable_pages when ncommit == 0. Mike noticed this problem initially in RHEL5 (2.6.18-based kernel) which has a backported version of 420e3646. The inode cache there was growing very large. The inode cache was unable to be shrunk since the inodes were all marked dirty. Calling sync() would essentially "fix" the problem -- the WB_SYNC_ALL flush would result in the inodes all being marked clean. What I'm not clear on is how big a problem this is in mainline kernels as the writeback code there is very different. Either way, it seems incorrect to re-mark the inode dirty in this case. Reported-by: Mike McLean Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/write.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 07e9e79b8b4..6015c7a879b 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1526,6 +1526,10 @@ static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_contr int flags = FLUSH_SYNC; int ret = 0; + /* no commits means nothing needs to be done */ + if (!nfsi->ncommit) + return ret; + if (wbc->sync_mode == WB_SYNC_NONE) { /* Don't commit yet if this is a non-blocking flush and there * are a lot of outstanding writes for this mapping. From e277beeb68b1f1e9326d57913a41549744002449 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 7 Oct 2011 11:50:22 +0800 Subject: [PATCH 0078/4025] ata_piix: make DVD Drive recognisable on systems with Intel Sandybridge chipsets(v2) commit 5e5a4f5d5a08c9c504fe956391ac3dae2c66556d upstream. This quirk patch fixes one kind of bug inside some Intel Sandybridge chipsets, see reports from https://bugzilla.kernel.org/show_bug.cgi?id=40592. Many guys also have reported the problem before: https://bugs.launchpad.net/bugs/737388 https://bugs.launchpad.net/bugs/794642 https://bugs.launchpad.net/bugs/782389 ...... With help from Tejun, the problem is found to be caused by 32bit PIO mode, so introduce the quirk patch to disable 32bit PIO on SATA piix for some Sandybridge CPT chipsets. Seth also tested the patch on all five affected chipsets (pci device ID: 0x1c00, 0x1c01, 0x1d00, 0x1e00, 0x1e01), and found the patch does fix the problem. Tested-by: Heasley, Seth Cc: Alan Cox Signed-off-by: Ming Lei Acked-by: Tejun Heo Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- drivers/ata/ata_piix.c | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 6f6e7718b05..6da6debee35 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -113,6 +113,8 @@ enum { PIIX_PATA_FLAGS = ATA_FLAG_SLAVE_POSS, PIIX_SATA_FLAGS = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR, + PIIX_FLAG_PIO16 = (1 << 30), /*support 16bit PIO only*/ + PIIX_80C_PRI = (1 << 5) | (1 << 4), PIIX_80C_SEC = (1 << 7) | (1 << 6), @@ -147,6 +149,7 @@ enum piix_controller_ids { ich8m_apple_sata, /* locks up on second port enable */ tolapai_sata, piix_pata_vmw, /* PIIX4 for VMware, spurious DMA_ERR */ + ich8_sata_snb, }; struct piix_map_db { @@ -177,6 +180,7 @@ static int piix_sidpr_scr_write(struct ata_link *link, static int piix_sidpr_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, unsigned hints); static bool piix_irq_check(struct ata_port *ap); +static int piix_port_start(struct ata_port *ap); #ifdef CONFIG_PM static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg); static int piix_pci_device_resume(struct pci_dev *pdev); @@ -298,21 +302,21 @@ static const struct pci_device_id piix_pci_tbl[] = { /* SATA Controller IDE (PCH) */ { 0x8086, 0x3b2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, /* SATA Controller IDE (CPT) */ - { 0x8086, 0x1c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, + { 0x8086, 0x1c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, /* SATA Controller IDE (CPT) */ - { 0x8086, 0x1c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, + { 0x8086, 0x1c01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, /* SATA Controller IDE (CPT) */ { 0x8086, 0x1c08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, /* SATA Controller IDE (CPT) */ { 0x8086, 0x1c09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, /* SATA Controller IDE (PBG) */ - { 0x8086, 0x1d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, + { 0x8086, 0x1d00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, /* SATA Controller IDE (PBG) */ { 0x8086, 0x1d08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, /* SATA Controller IDE (Panther Point) */ - { 0x8086, 0x1e00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, + { 0x8086, 0x1e00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, /* SATA Controller IDE (Panther Point) */ - { 0x8086, 0x1e01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, + { 0x8086, 0x1e01, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_snb }, /* SATA Controller IDE (Panther Point) */ { 0x8086, 0x1e08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata }, /* SATA Controller IDE (Panther Point) */ @@ -338,6 +342,7 @@ static struct scsi_host_template piix_sht = { static struct ata_port_operations piix_sata_ops = { .inherits = &ata_bmdma32_port_ops, .sff_irq_check = piix_irq_check, + .port_start = piix_port_start, }; static struct ata_port_operations piix_pata_ops = { @@ -478,6 +483,7 @@ static const struct piix_map_db *piix_map_db_table[] = { [ich8_2port_sata] = &ich8_2port_map_db, [ich8m_apple_sata] = &ich8m_apple_map_db, [tolapai_sata] = &tolapai_map_db, + [ich8_sata_snb] = &ich8_map_db, }; static struct ata_port_info piix_port_info[] = { @@ -606,6 +612,19 @@ static struct ata_port_info piix_port_info[] = { .port_ops = &piix_vmw_ops, }, + /* + * some Sandybridge chipsets have broken 32 mode up to now, + * see https://bugzilla.kernel.org/show_bug.cgi?id=40592 + */ + [ich8_sata_snb] = + { + .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SIDPR | PIIX_FLAG_PIO16, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA6, + .port_ops = &piix_sata_ops, + }, + }; static struct pci_bits piix_enable_bits[] = { @@ -649,6 +668,14 @@ static const struct ich_laptop ich_laptop[] = { { 0, } }; +static int piix_port_start(struct ata_port *ap) +{ + if (!(ap->flags & PIIX_FLAG_PIO16)) + ap->pflags |= ATA_PFLAG_PIO32 | ATA_PFLAG_PIO32CHANGE; + + return ata_bmdma_port_start(ap); +} + /** * ich_pata_cable_detect - Probe host controller cable detect info * @ap: Port for which cable detect info is desired From 32779fa06584fdcab2228a36c3a846fa0a6f5cdb Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 21 Oct 2011 06:24:20 +0000 Subject: [PATCH 0079/4025] rtnetlink: Add missing manual netlink notification in dev_change_net_namespaces commit d2237d35748e7f448a9c2d9dc6a85ef637466e24 upstream. Renato Westphal noticed that since commit a2835763e130c343ace5320c20d33c281e7097b7 "rtnetlink: handle rtnl_link netlink notifications manually" was merged we no longer send a netlink message when a networking device is moved from one network namespace to another. Fix this by adding the missing manual notification in dev_change_net_namespaces. Since all network devices that are processed by dev_change_net_namspaces are in the initialized state the complicated tests that guard the manual rtmsg_ifinfo calls in rollback_registered and register_netdevice are unnecessary and we can just perform a plain notification. Tested-by: Renato Westphal Signed-off-by: Eric W. Biederman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/core/dev.c b/net/core/dev.c index 9c58c1ec41a..f14f6015a7a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6105,6 +6105,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char */ call_netdevice_notifiers(NETDEV_UNREGISTER, dev); call_netdevice_notifiers(NETDEV_UNREGISTER_BATCH, dev); + rtmsg_ifinfo(RTM_DELLINK, dev, ~0U); /* * Flush the unicast and multicast chains From 806aeb924e925e6f1584ff956c9b9695e4ec18f9 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 21 Oct 2011 00:49:17 +0000 Subject: [PATCH 0080/4025] dp83640: free packet queues on remove commit 8b3408f8ee994973869d8ba32c5bf482bc4ddca4 upstream. If the PHY should disappear (for example, on an USB Ethernet MAC), then the driver would leak any undelivered time stamp packets. This commit fixes the issue by calling the appropriate functions to free any packets left in the transmit and receive queues. The driver first appeared in v3.0. Signed-off-by: Richard Cochran Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/dp83640.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index cb6e0b486b1..db659c5f0fe 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -875,6 +875,7 @@ static void dp83640_remove(struct phy_device *phydev) struct dp83640_clock *clock; struct list_head *this, *next; struct dp83640_private *tmp, *dp83640 = phydev->priv; + struct sk_buff *skb; if (phydev->addr == BROADCAST_ADDR) return; @@ -882,6 +883,12 @@ static void dp83640_remove(struct phy_device *phydev) enable_status_frames(phydev, false); cancel_work_sync(&dp83640->ts_work); + while ((skb = skb_dequeue(&dp83640->rx_queue)) != NULL) + kfree_skb(skb); + + while ((skb = skb_dequeue(&dp83640->tx_queue)) != NULL) + skb_complete_tx_timestamp(skb, NULL); + clock = dp83640_clock_get(dp83640->clock); if (dp83640 == clock->chosen) { From 4641f8a010eb97303fbc9bd8a094139b52ffd629 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 4 Oct 2011 18:27:10 +0200 Subject: [PATCH 0081/4025] mac80211: fix offchannel TX cookie matching commit 28a1bcdb57d50f3038a255741ecc83e391e5282e upstream. When I introduced in-kernel off-channel TX I introduced a bug -- the work can't be canceled again because the code clear the skb pointer. Fix this by keeping track separately of whether TX status has already been reported. Reported-by: Jouni Malinen Tested-by: Jouni Malinen Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/cfg.c | 2 +- net/mac80211/ieee80211_i.h | 1 + net/mac80211/status.c | 2 +- net/mac80211/work.c | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index be70c70d3f5..143a0064348 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1798,7 +1798,7 @@ ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb) * so in that case userspace will have to deal with it. */ - if (wk->offchan_tx.wait && wk->offchan_tx.frame) + if (wk->offchan_tx.wait && !wk->offchan_tx.status) cfg80211_mgmt_tx_status(wk->sdata->dev, (unsigned long) wk->offchan_tx.frame, wk->ie, wk->ie_len, false, GFP_KERNEL); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 090b0ec1e05..0c5aed2257f 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -328,6 +328,7 @@ struct ieee80211_work { struct { struct sk_buff *frame; u32 wait; + bool status; } offchan_tx; }; diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 1658efaa2e8..04cdbaf160b 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -336,7 +336,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) continue; if (wk->offchan_tx.frame != skb) continue; - wk->offchan_tx.frame = NULL; + wk->offchan_tx.status = true; break; } rcu_read_unlock(); diff --git a/net/mac80211/work.c b/net/mac80211/work.c index d2e7f0e8667..dc8ec05a8fc 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -553,7 +553,7 @@ ieee80211_offchannel_tx(struct ieee80211_work *wk) /* * After this, offchan_tx.frame remains but now is no * longer a valid pointer -- we still need it as the - * cookie for canceling this work. + * cookie for canceling this work/status matching. */ ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame); From babba877daf7a7ee0cb03dfb5e63f23e2d32dddf Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 21 Oct 2011 00:49:15 +0000 Subject: [PATCH 0082/4025] net: hold sock reference while processing tx timestamps commit da92b194cc36b5dc1fbd85206aeeffd80bee0c39 upstream. The pair of functions, * skb_clone_tx_timestamp() * skb_complete_tx_timestamp() were designed to allow timestamping in PHY devices. The first function, called during the MAC driver's hard_xmit method, identifies PTP protocol packets, clones them, and gives them to the PHY device driver. The PHY driver may hold onto the packet and deliver it at a later time using the second function, which adds the packet to the socket's error queue. As pointed out by Johannes, nothing prevents the socket from disappearing while the cloned packet is sitting in the PHY driver awaiting a timestamp. This patch fixes the issue by taking a reference on the socket for each such packet. In addition, the comments regarding the usage of these function are expanded to highlight the rule that PHY drivers must use skb_complete_tx_timestamp() to release the packet, in order to release the socket reference, too. These functions first appeared in v2.6.36. Reported-by: Johannes Berg Signed-off-by: Richard Cochran Signed-off-by: Eric Dumazet Reviewed-by: Johannes Berg Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/phy.h | 2 +- include/linux/skbuff.h | 7 ++++++- net/core/timestamping.c | 12 ++++++++++-- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/include/linux/phy.h b/include/linux/phy.h index 7da5fa84595..4d3f63ac242 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -418,7 +418,7 @@ struct phy_driver { /* * Requests a Tx timestamp for 'skb'. The phy driver promises - * to deliver it to the socket's error queue as soon as a + * to deliver it using skb_complete_tx_timestamp() as soon as a * timestamp becomes available. One of the PTP_CLASS_ values * is passed in 'type'. */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index c0a4f3ab0cc..b920a72a7a9 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1996,8 +1996,13 @@ static inline bool skb_defer_rx_timestamp(struct sk_buff *skb) /** * skb_complete_tx_timestamp() - deliver cloned skb with tx timestamps * + * PHY drivers may accept clones of transmitted packets for + * timestamping via their phy_driver.txtstamp method. These drivers + * must call this function to return the skb back to the stack, with + * or without a timestamp. + * * @skb: clone of the the original outgoing packet - * @hwtstamps: hardware time stamps + * @hwtstamps: hardware time stamps, may be NULL if not available * */ void skb_complete_tx_timestamp(struct sk_buff *skb, diff --git a/net/core/timestamping.c b/net/core/timestamping.c index 7e7ca375d43..97d036a6b89 100644 --- a/net/core/timestamping.c +++ b/net/core/timestamping.c @@ -57,9 +57,13 @@ void skb_clone_tx_timestamp(struct sk_buff *skb) case PTP_CLASS_V2_VLAN: phydev = skb->dev->phydev; if (likely(phydev->drv->txtstamp)) { + if (!atomic_inc_not_zero(&sk->sk_refcnt)) + return; clone = skb_clone(skb, GFP_ATOMIC); - if (!clone) + if (!clone) { + sock_put(sk); return; + } clone->sk = sk; phydev->drv->txtstamp(phydev, clone, type); } @@ -76,8 +80,11 @@ void skb_complete_tx_timestamp(struct sk_buff *skb, struct sock_exterr_skb *serr; int err; - if (!hwtstamps) + if (!hwtstamps) { + sock_put(sk); + kfree_skb(skb); return; + } *skb_hwtstamps(skb) = *hwtstamps; serr = SKB_EXT_ERR(skb); @@ -86,6 +93,7 @@ void skb_complete_tx_timestamp(struct sk_buff *skb, serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; skb->sk = NULL; err = sock_queue_err_skb(sk, skb); + sock_put(sk); if (err) kfree_skb(skb); } From 40b3c4dc2c6c44972323be3a1ebd62c4fe35fac0 Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 22 Sep 2011 10:06:10 +0300 Subject: [PATCH 0083/4025] wl12xx: fix forced passive scans commit 6cd9d21a0c1e2648c07c32c66bb25795ad3208aa upstream. We were using incorrect max and min dwell times during forced passive scans because we were still using the active scan states to scan (passively) the channels that were not marked as passive. Instead of doing passive scans in active states, we now skip active states and scan for all channels in passive states. Signed-off-by: Luciano Coelho Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/wl12xx/scan.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 56f76abc754..9542e4662b6 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -83,14 +83,18 @@ static int wl1271_get_scan_channels(struct wl1271 *wl, for (i = 0, j = 0; i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS; i++) { - flags = req->channels[i]->flags; if (!test_bit(i, wl->scan.scanned_ch) && !(flags & IEEE80211_CHAN_DISABLED) && - ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) && - (req->channels[i]->band == band)) { - + (req->channels[i]->band == band) && + /* + * In passive scans, we scan all remaining + * channels, even if not marked as such. + * In active scans, we only scan channels not + * marked as passive. + */ + (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) { wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ", req->channels[i]->band, req->channels[i]->center_freq); @@ -142,6 +146,10 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, int ret; u16 scan_options = 0; + /* skip active scans if we don't have SSIDs */ + if (!passive && wl->scan.req->n_ssids == 0) + return WL1271_NOTHING_TO_SCAN; + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); if (!cmd || !trigger) { @@ -152,8 +160,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band, /* We always use high priority scans */ scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH; - /* No SSIDs means that we have a forced passive scan */ - if (passive || wl->scan.req->n_ssids == 0) + if (passive) scan_options |= WL1271_SCAN_OPT_PASSIVE; cmd->params.scan_options = cpu_to_le16(scan_options); From c7f65094f7e2b8463a7c002e967e78db8f30468a Mon Sep 17 00:00:00 2001 From: hank Date: Tue, 20 Sep 2011 13:53:39 -0700 Subject: [PATCH 0084/4025] time: Change jiffies_to_clock_t() argument type to unsigned long commit cbbc719fccdb8cbd87350a05c0d33167c9b79365 upstream. The parameter's origin type is long. On an i386 architecture, it can easily be larger than 0x80000000, causing this function to convert it to a sign-extended u64 type. Change the type to unsigned long so we get the correct result. Signed-off-by: hank Cc: John Stultz [ build fix ] Signed-off-by: Andrew Morton Signed-off-by: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- include/linux/jiffies.h | 2 +- kernel/time.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index f97672a36fa..265e2c3cbd1 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -303,7 +303,7 @@ extern void jiffies_to_timespec(const unsigned long jiffies, extern unsigned long timeval_to_jiffies(const struct timeval *value); extern void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value); -extern clock_t jiffies_to_clock_t(long x); +extern clock_t jiffies_to_clock_t(unsigned long x); extern unsigned long clock_t_to_jiffies(unsigned long x); extern u64 jiffies_64_to_clock_t(u64 x); extern u64 nsec_to_clock_t(u64 x); diff --git a/kernel/time.c b/kernel/time.c index 8e8dc6d705c..d7760621452 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -575,7 +575,7 @@ EXPORT_SYMBOL(jiffies_to_timeval); /* * Convert jiffies/jiffies_64 to clock_t and back. */ -clock_t jiffies_to_clock_t(long x) +clock_t jiffies_to_clock_t(unsigned long x) { #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 # if HZ < USER_HZ From e747500485ddef175ac6694dcff4fd8088e62071 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Wed, 28 Sep 2011 16:44:54 +0100 Subject: [PATCH 0085/4025] apic, i386/bigsmp: Fix false warnings regarding logical APIC ID mismatches commit 838312be46f3abfbdc175f81c3e54a857994476d upstream. These warnings (generally one per CPU) are a result of initializing x86_cpu_to_logical_apicid while apic_default is still in use, but the check in setup_local_APIC() being done when apic_bigsmp was already used as an override in default_setup_apic_routing(): Overriding APIC driver with bigsmp Enabling APIC mode: Physflat. Using 5 I/O APICs ------------[ cut here ]------------ WARNING: at .../arch/x86/kernel/apic/apic.c:1239 ... CPU 1 irqstacks, hard=f1c9a000 soft=f1c9c000 Booting Node 0, Processors #1 smpboot cpu 1: start_ip = 9e000 Initializing CPU#1 ------------[ cut here ]------------ WARNING: at .../arch/x86/kernel/apic/apic.c:1239 setup_local_APIC+0x137/0x46b() Hardware name: ... CPU1 logical APIC ID: 2 != 8 ... Fix this (for the time being, i.e. until x86_32_early_logical_apicid() will get removed again, as Tejun says ought to be possible) by overriding the previously stored values at the point where the APIC driver gets overridden. v2: Move this and the pre-existing override logic into arch/x86/kernel/apic/bigsmp_32.c. Signed-off-by: Jan Beulich Acked-by: Tejun Heo Link: http://lkml.kernel.org/r/4E835D16020000780005844C@nat28.tlf.novell.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/apic.h | 2 +- arch/x86/kernel/apic/bigsmp_32.c | 20 ++++++++++++++++---- arch/x86/kernel/apic/probe_32.c | 10 ++-------- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h index 4a0b7c7e2cc..244ac77eee8 100644 --- a/arch/x86/include/asm/apic.h +++ b/arch/x86/include/asm/apic.h @@ -495,7 +495,7 @@ static inline void default_wait_for_init_deassert(atomic_t *deassert) return; } -extern struct apic *generic_bigsmp_probe(void); +extern void generic_bigsmp_probe(void); #ifdef CONFIG_X86_LOCAL_APIC diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c index efd737e827f..521bead0113 100644 --- a/arch/x86/kernel/apic/bigsmp_32.c +++ b/arch/x86/kernel/apic/bigsmp_32.c @@ -255,12 +255,24 @@ static struct apic apic_bigsmp = { .x86_32_early_logical_apicid = bigsmp_early_logical_apicid, }; -struct apic * __init generic_bigsmp_probe(void) +void __init generic_bigsmp_probe(void) { - if (probe_bigsmp()) - return &apic_bigsmp; + unsigned int cpu; - return NULL; + if (!probe_bigsmp()) + return; + + apic = &apic_bigsmp; + + for_each_possible_cpu(cpu) { + if (early_per_cpu(x86_cpu_to_logical_apicid, + cpu) == BAD_APICID) + continue; + early_per_cpu(x86_cpu_to_logical_apicid, cpu) = + bigsmp_early_logical_apicid(cpu); + } + + pr_info("Overriding APIC driver with %s\n", apic_bigsmp.name); } apic_driver(apic_bigsmp); diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c index b5254ad044a..0787bb3412f 100644 --- a/arch/x86/kernel/apic/probe_32.c +++ b/arch/x86/kernel/apic/probe_32.c @@ -200,14 +200,8 @@ void __init default_setup_apic_routing(void) * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support */ - if (!cmdline_apic && apic == &apic_default) { - struct apic *bigsmp = generic_bigsmp_probe(); - if (bigsmp) { - apic = bigsmp; - printk(KERN_INFO "Overriding APIC driver with %s\n", - apic->name); - } - } + if (!cmdline_apic && apic == &apic_default) + generic_bigsmp_probe(); #endif if (apic->setup_apic_routing) From a847627709b3402163d99f7c6fda4a77bcd6b51b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 26 Oct 2011 10:31:04 +1100 Subject: [PATCH 0086/4025] md/raid5: fix bug that could result in reads from a failed device. commit 355840e7a7e56bb2834fd3b0da64da5465f8aeaa upstream. This bug was introduced in 415e72d034c50520ddb7ff79e7d1792c1306f0c9 which was in 2.6.36. There is a small window of time between when a device fails and when it is removed from the array. During this time we might still read from it, but we won't write to it - so it is possible that we could read stale data. We didn't need the test of 'Faulty' before because the test on In_sync is sufficient. Since we started allowing reads from the early part of non-In_sync devices we need a test on Faulty too. This is suitable for any kernel from 2.6.36 onwards, though the patch might need a bit of tweaking in 3.0 and earlier. Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 2581ba12735..e509147318e 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3369,7 +3369,7 @@ static void handle_stripe6(struct stripe_head *sh) /* Not in-sync */; else if (test_bit(In_sync, &rdev->flags)) set_bit(R5_Insync, &dev->flags); - else { + else if (!test_bit(Faulty, &rdev->flags)) { /* in sync if before recovery_offset */ if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset) set_bit(R5_Insync, &dev->flags); From d59892017c5f6de2fdee221f2a7788696e9f2cda Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Tue, 4 Oct 2011 19:45:04 +0900 Subject: [PATCH 0087/4025] perf probe: Fix to show correct error string commit 44a56040a0037a845d5fa218dffde464579f0cab upstream. Fix perf probe to show correct error string when it fails to delete an event. The write(2) returns -1 if failed, and errno stores real error number. Signed-off-by: Masami Hiramatsu Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Paul Mackerras Cc: Ingo Molnar Link: http://lkml.kernel.org/r/20111004104504.14591.41266.stgit@fedora15 Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/probe-event.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index f0223166e76..8c50da86885 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -1869,8 +1869,10 @@ static int __del_trace_probe_event(int fd, struct str_node *ent) pr_debug("Writing event: %s\n", buf); ret = write(fd, buf, strlen(buf)); - if (ret < 0) + if (ret < 0) { + ret = -errno; goto error; + } printf("Remove event: %s\n", ent->s); return 0; From 12cb3e734a5616ea0057aee938c553ff6ccbdfbd Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 14 Oct 2011 10:44:25 -0400 Subject: [PATCH 0088/4025] tracing: Fix returning of duplicate data after EOF in trace_pipe_raw commit 436fc280261dcfce5af38f08b89287750dc91cd2 upstream. The trace_pipe_raw handler holds a cached page from the time the file is opened to the time it is closed. The cached page is used to handle the case of the user space buffer being smaller than what was read from the ring buffer. The left over buffer is held in the cache so that the next read will continue where the data left off. After EOF is returned (no more data in the buffer), the index of the cached page is set to zero. If a user app reads the page again after EOF, the check in the buffer will see that the cached page is less than page size and will return the cached page again. This will cause reading the trace_pipe_raw again after EOF to return duplicate data, making the output look like the time went backwards but instead data is just repeated. The fix is to not reset the index right after all data is read from the cache, but to reset it after all data is read and more data exists in the ring buffer. Reported-by: Jeremy Eder Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index ee9c921d7f2..0731e81a5bb 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3704,8 +3704,6 @@ tracing_buffers_read(struct file *filp, char __user *ubuf, if (info->read < PAGE_SIZE) goto read; - info->read = 0; - trace_access_lock(info->cpu); ret = ring_buffer_read_page(info->tr->buffer, &info->spare, @@ -3715,6 +3713,8 @@ tracing_buffers_read(struct file *filp, char __user *ubuf, if (ret < 0) return 0; + info->read = 0; + read: size = PAGE_SIZE - info->read; if (size > count) From 09bb52774e0543390bdba59b67ade093d34e4906 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 3 Oct 2011 15:37:00 +0100 Subject: [PATCH 0089/4025] genirq: Add IRQF_RESUME_EARLY and resume such IRQs earlier commit 9bab0b7fbaceec47d32db51cd9e59c82fb071f5a upstream. This adds a mechanism to resume selected IRQs during syscore_resume instead of dpm_resume_noirq. Under Xen we need to resume IRQs associated with IPIs early enough that the resched IPI is unmasked and we can therefore schedule ourselves out of the stop_machine where the suspend/resume takes place. This issue was introduced by 676dc3cf5bc3 "xen: Use IRQF_FORCE_RESUME". Signed-off-by: Ian Campbell Cc: Rafael J. Wysocki Cc: Jeremy Fitzhardinge Cc: xen-devel Cc: Konrad Rzeszutek Wilk Link: http://lkml.kernel.org/r/1318713254.11016.52.camel@dagon.hellion.org.uk Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/xen/events.c | 2 +- include/linux/interrupt.h | 3 +++ kernel/irq/pm.c | 48 +++++++++++++++++++++++++++++++++------ 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 30df85d8fca..a5493f8acf9 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -1026,7 +1026,7 @@ int bind_ipi_to_irqhandler(enum ipi_vector ipi, if (irq < 0) return irq; - irqflags |= IRQF_NO_SUSPEND | IRQF_FORCE_RESUME; + irqflags |= IRQF_NO_SUSPEND | IRQF_FORCE_RESUME | IRQF_EARLY_RESUME; retval = request_irq(irq, handler, irqflags, devname, dev_id); if (retval != 0) { unbind_from_irq(irq); diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index f6efed0039e..b9490bf3939 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -59,6 +59,8 @@ * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set * IRQF_NO_THREAD - Interrupt cannot be threaded + * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device + * resume time. */ #define IRQF_DISABLED 0x00000020 #define IRQF_SAMPLE_RANDOM 0x00000040 @@ -72,6 +74,7 @@ #define IRQF_NO_SUSPEND 0x00004000 #define IRQF_FORCE_RESUME 0x00008000 #define IRQF_NO_THREAD 0x00010000 +#define IRQF_EARLY_RESUME 0x00020000 #define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD) diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c index f76fc00c987..15e53b1766a 100644 --- a/kernel/irq/pm.c +++ b/kernel/irq/pm.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "internals.h" @@ -39,25 +40,58 @@ void suspend_device_irqs(void) } EXPORT_SYMBOL_GPL(suspend_device_irqs); -/** - * resume_device_irqs - enable interrupt lines disabled by suspend_device_irqs() - * - * Enable all interrupt lines previously disabled by suspend_device_irqs() that - * have the IRQS_SUSPENDED flag set. - */ -void resume_device_irqs(void) +static void resume_irqs(bool want_early) { struct irq_desc *desc; int irq; for_each_irq_desc(irq, desc) { unsigned long flags; + bool is_early = desc->action && + desc->action->flags & IRQF_EARLY_RESUME; + + if (is_early != want_early) + continue; raw_spin_lock_irqsave(&desc->lock, flags); __enable_irq(desc, irq, true); raw_spin_unlock_irqrestore(&desc->lock, flags); } } + +/** + * irq_pm_syscore_ops - enable interrupt lines early + * + * Enable all interrupt lines with %IRQF_EARLY_RESUME set. + */ +static void irq_pm_syscore_resume(void) +{ + resume_irqs(true); +} + +static struct syscore_ops irq_pm_syscore_ops = { + .resume = irq_pm_syscore_resume, +}; + +static int __init irq_pm_init_ops(void) +{ + register_syscore_ops(&irq_pm_syscore_ops); + return 0; +} + +device_initcall(irq_pm_init_ops); + +/** + * resume_device_irqs - enable interrupt lines disabled by suspend_device_irqs() + * + * Enable all non-%IRQF_EARLY_RESUME interrupt lines previously + * disabled by suspend_device_irqs() that have the IRQS_SUSPENDED flag + * set as well as those with %IRQF_FORCE_RESUME. + */ +void resume_device_irqs(void) +{ + resume_irqs(false); +} EXPORT_SYMBOL_GPL(resume_device_irqs); /** From 60eb9e7d1a8aeec2d4371ec445e7fd4425d05017 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Wed, 12 Oct 2011 10:57:42 -0400 Subject: [PATCH 0090/4025] nfs: don't try to migrate pages with active requests commit 2da956523526e440ef4f4dd174e26f5ac06fe011 upstream. nfs_find_and_lock_request will take a reference to the nfs_page and will then put it if the req is already locked. It's possible though that the reference will be the last one. That put then can kick off a whole series of reference puts: nfs_page nfs_open_context dentry inode If the inode ends up being deleted, then the VFS will call truncate_inode_pages. That function will try to take the page lock, but it was already locked when migrate_page was called. The code deadlocks. Fix this by simply refusing the migration request if PagePrivate is already set, indicating that the page is already associated with an active read or write request. We've had a customer test a backported version of this patch and the preliminary results seem good. Cc: Andrea Arcangeli Reported-by: Harshula Jayasuriya Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/write.c | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 6015c7a879b..f2f80c005c0 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1664,34 +1664,20 @@ int nfs_wb_page(struct inode *inode, struct page *page) int nfs_migrate_page(struct address_space *mapping, struct page *newpage, struct page *page) { - struct nfs_page *req; - int ret; + /* + * If PagePrivate is set, then the page is currently associated with + * an in-progress read or write request. Don't try to migrate it. + * + * FIXME: we could do this in principle, but we'll need a way to ensure + * that we can safely release the inode reference while holding + * the page lock. + */ + if (PagePrivate(page)) + return -EBUSY; nfs_fscache_release_page(page, GFP_KERNEL); - req = nfs_find_and_lock_request(page, false); - ret = PTR_ERR(req); - if (IS_ERR(req)) - goto out; - - ret = migrate_page(mapping, newpage, page); - if (!req) - goto out; - if (ret) - goto out_unlock; - page_cache_get(newpage); - spin_lock(&mapping->host->i_lock); - req->wb_page = newpage; - SetPagePrivate(newpage); - set_page_private(newpage, (unsigned long)req); - ClearPagePrivate(page); - set_page_private(page, 0); - spin_unlock(&mapping->host->i_lock); - page_cache_release(page); -out_unlock: - nfs_clear_page_tag_locked(req); -out: - return ret; + return migrate_page(mapping, newpage, page); } #endif From 6176ebe5391aa20700f9348fa7f7aca1a559e78f Mon Sep 17 00:00:00 2001 From: Bernd Schubert Date: Mon, 8 Aug 2011 17:38:08 +0200 Subject: [PATCH 0091/4025] nfsd4: Remove check for a 32-bit cookie in nfsd4_readdir() commit 832023bffb4b493f230be901f681020caf3ed1f8 upstream. Fan Yong noticed setting FMODE_32bithash wouldn't work with nfsd v4, as nfsd4_readdir() checks for 32 bit cookies. However, according to RFC 3530 cookies have a 64 bit type and cookies are also defined as u64 in 'struct nfsd4_readdir'. So remove the test for >32-bit values. Signed-off-by: Bernd Schubert Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 3a6dbd70b34..f7799d370ab 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -682,7 +682,7 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion); readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion); - if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) || + if ((cookie == 1) || (cookie == 2) || (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE))) return nfserr_bad_cookie; From 80931f71f0e7c151aa260590c655d536c967af56 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 10 Aug 2011 19:07:33 -0400 Subject: [PATCH 0092/4025] nfsd4: stop using nfserr_resource for transitory errors commit 3e77246393c0a433247631a1f0e9ec98d3d78a1c upstream. The server is returning nfserr_resource for both permanent errors and for errors (like allocation failures) that might be resolved by retrying later. Save nfserr_resource for the former and use delay/jukebox for the latter. Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4proc.c | 2 +- fs/nfsd/nfs4recover.c | 2 +- fs/nfsd/nfs4state.c | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index f7799d370ab..61bdef3bae2 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -921,7 +921,7 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, count = 4 + (verify->ve_attrlen >> 2); buf = kmalloc(count << 2, GFP_KERNEL); if (!buf) - return nfserr_resource; + return nfserr_jukebox; status = nfsd4_encode_fattr(&cstate->current_fh, cstate->current_fh.fh_export, diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index ffb59ef6f82..be268148170 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -88,7 +88,7 @@ nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) struct xdr_netobj cksum; struct hash_desc desc; struct scatterlist sg; - __be32 status = nfserr_resource; + __be32 status = nfserr_jukebox; dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", clname->len, clname->data); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3b8ad35561b..bfe577c7676 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1903,7 +1903,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, * of 5 bullet points, labeled as CASE0 - CASE4 below. */ unconf = find_unconfirmed_client_by_str(dname, strhashval); - status = nfserr_resource; + status = nfserr_jukebox; if (!conf) { /* * RFC 3530 14.2.33 CASE 4: @@ -2440,7 +2440,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, if (open->op_stateowner == NULL) { sop = alloc_init_open_stateowner(strhashval, clp, open); if (sop == NULL) - return nfserr_resource; + return nfserr_jukebox; open->op_stateowner = sop; } list_del_init(&sop->so_close_lru); @@ -2576,7 +2576,7 @@ nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, stp = nfs4_alloc_stateid(); if (stp == NULL) - return nfserr_resource; + return nfserr_jukebox; status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); if (status) { @@ -2807,7 +2807,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf status = nfserr_bad_stateid; if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) goto out; - status = nfserr_resource; + status = nfserr_jukebox; fp = alloc_init_file(ino); if (fp == NULL) goto out; @@ -3840,7 +3840,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, /* XXX: Do we need to check for duplicate stateowners on * the same file, or should they just be allowed (and * create new stateids)? */ - status = nfserr_resource; + status = nfserr_jukebox; lock_sop = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock); if (lock_sop == NULL) @@ -3924,9 +3924,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, case (EDEADLK): status = nfserr_deadlock; break; - default: + default: dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err); - status = nfserr_resource; + status = nfserrno(err); break; } out: From e3d0b28c5ec3bf7628a9707a6392cdb4adebabba Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 10 Aug 2011 19:16:22 -0400 Subject: [PATCH 0093/4025] nfsd4: fix seqid_mutating_error commit 576163005de286bbd418fcb99cfd0971523a0c6d upstream. The set of errors here does *not* agree with the set of errors specified in the rfc! While we're there, turn this macros into a function, for the usual reasons, and move it to the one place where it's actually used. Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4xdr.c | 12 ++++++++++++ fs/nfsd/state.h | 6 ------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 99018110321..6c740974bfe 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1548,6 +1548,18 @@ static void write_cinfo(__be32 **p, struct nfsd4_change_info *c) \ save = resp->p; +static bool seqid_mutating_err(__be32 err) +{ + /* rfc 3530 section 8.1.5: */ + return err != nfserr_stale_clientid && + err != nfserr_stale_stateid && + err != nfserr_bad_stateid && + err != nfserr_bad_seqid && + err != nfserr_bad_xdr && + err != nfserr_resource && + err != nfserr_nofilehandle; +} + /* * Routine for encoding the result of a "seqid-mutating" NFSv4 operation. This * is where sequence id's are incremented, and the replay cache is filled. diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 6bd2f3c21f2..858c7baea2d 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -447,12 +447,6 @@ struct nfs4_stateid { #define WR_STATE 0x00000020 #define CLOSE_STATE 0x00000040 -#define seqid_mutating_err(err) \ - (((err) != nfserr_stale_clientid) && \ - ((err) != nfserr_bad_seqid) && \ - ((err) != nfserr_stale_stateid) && \ - ((err) != nfserr_bad_stateid)) - struct nfsd4_compound_state; extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, From 0a52cb1083a662d4c417638ccdaa81df0e67494b Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 25 Aug 2011 10:48:39 -0400 Subject: [PATCH 0094/4025] nfsd4: permit read opens of executable-only files commit a043226bc140a2c1dde162246d68a67e5043e6b2 upstream. A client that wants to execute a file must be able to read it. Read opens over nfs are therefore implicitly allowed for executable files even when those files are not readable. NFSv2/v3 get this right by using a passed-in NFSD_MAY_OWNER_OVERRIDE on read requests, but NFSv4 has gotten this wrong ever since dc730e173785e29b297aa605786c94adaffe2544 "nfsd4: fix owner-override on open", when we realized that the file owner shouldn't override permissions on non-reclaim NFSv4 opens. So we can't use NFSD_MAY_OWNER_OVERRIDE to tell nfsd_permission to allow reads of executable files. So, do the same thing we do whenever we encounter another weird NFS permission nit: define yet another NFSD_MAY_* flag. The industry's future standardization on 128-bit processors will be motivated primarily by the need for integers with enough bits for all the NFSD_MAY_* flags. Reported-by: Leonardo Borda Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4proc.c | 2 ++ fs/nfsd/vfs.c | 3 ++- fs/nfsd/vfs.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 61bdef3bae2..0b8830c9de7 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -156,6 +156,8 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) return nfserr_inval; + accmode |= NFSD_MAY_READ_IF_EXEC; + if (open->op_share_access & NFS4_SHARE_ACCESS_READ) accmode |= NFSD_MAY_READ; if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index fd0acca5370..acf88aea211 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -2114,7 +2114,8 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, /* Allow read access to binaries even when mode 111 */ if (err == -EACCES && S_ISREG(inode->i_mode) && - acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE)) + (acc == (NFSD_MAY_READ | NFSD_MAY_OWNER_OVERRIDE) || + acc == (NFSD_MAY_READ | NFSD_MAY_READ_IF_EXEC))) err = inode_permission(inode, MAY_EXEC); return err? nfserrno(err) : 0; diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index e0bbac04d1d..a22e40e2786 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -25,6 +25,7 @@ #define NFSD_MAY_BYPASS_GSS_ON_ROOT 256 #define NFSD_MAY_NOT_BREAK_LEASE 512 #define NFSD_MAY_BYPASS_GSS 1024 +#define NFSD_MAY_READ_IF_EXEC 2048 #define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE) #define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC) From 279b483174560147e9f56f79e9b1fd3bd4fc8f40 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 19 Sep 2011 15:07:41 -0400 Subject: [PATCH 0095/4025] nfsd4: fix open downgrade, again commit 3d02fa29dec920c597dd7b7db608a4bc71f088ce upstream. Yet another open-management regression: - nfs4_file_downgrade() doesn't remove the BOTH access bit on downgrade, so the server's idea of the stateid's access gets out of sync with the client's. If we want to keep an O_RDWR open in this case, we should do that in the file_put_access logic rather than here. - We forgot to convert v4 access to an open mode here. This logic has proven too hard to get right. In the future we may consider: - reexamining the lock/openowner relationship (locks probably don't really need to take their own references here). - adding open upgrade/downgrade support to the vfs. - removing the atomic operations. They're redundant as long as this is all under some other lock. Also, maybe some kind of additional static checking would help catch O_/NFS4_SHARE_ACCESS confusion. Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4state.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index bfe577c7676..3d893645cc6 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -188,8 +188,15 @@ static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag) static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) { if (atomic_dec_and_test(&fp->fi_access[oflag])) { - nfs4_file_put_fd(fp, O_RDWR); nfs4_file_put_fd(fp, oflag); + /* + * It's also safe to get rid of the RDWR open *if* + * we no longer have need of the other kind of access + * or if we already have the other kind of open: + */ + if (fp->fi_fds[1-oflag] + || atomic_read(&fp->fi_access[1 - oflag]) == 0) + nfs4_file_put_fd(fp, O_RDWR); } } @@ -3381,8 +3388,9 @@ static inline void nfs4_file_downgrade(struct nfs4_stateid *stp, unsigned int to int i; for (i = 1; i < 4; i++) { - if (test_bit(i, &stp->st_access_bmap) && !(i & to_access)) { - nfs4_file_put_access(stp->st_file, i); + if (test_bit(i, &stp->st_access_bmap) + && ((i & to_access) != i)) { + nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(i)); __clear_bit(i, &stp->st_access_bmap); } } From 0dc8985b7f2da02180135396871d396f33a39b43 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 10 Oct 2011 17:34:31 -0400 Subject: [PATCH 0096/4025] nfsd4: ignore WANT bits in open downgrade commit c30e92df30d7d5fe65262fbce5d1b7de675fe34e upstream. We don't use WANT bits yet--and sending them can probably trigger a BUG() further down. Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4state.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3d893645cc6..ecd8152965e 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3421,6 +3421,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, if (!access_valid(od->od_share_access, cstate->minorversion) || !deny_valid(od->od_share_deny)) return nfserr_inval; + /* We don't yet support WANT bits: */ + od->od_share_access &= NFS4_SHARE_ACCESS_MASK; nfs4_lock_state(); if ((status = nfs4_preprocess_seqid_op(cstate, From b2f0a734b06e2e257bb0565800ac222244d981dc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 27 Jul 2011 22:21:58 -0400 Subject: [PATCH 0097/4025] hppfs: missing include commit d6b722aa383a467a43d09ee38e866981abba08ab upstream. Signed-off-by: Al Viro Cc: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/hppfs/hppfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index 85c098a499f..9d71c95b193 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "os.h" From 2f8c09acae88d1bf0aeedffd3f788eb5c5b4db29 Mon Sep 17 00:00:00 2001 From: Bryan Schumaker Date: Fri, 7 Oct 2011 13:41:15 -0400 Subject: [PATCH 0098/4025] vfs: add "device" tag to /proc/self/mountstats commit a877ee03ac010ded434b77f7831f43cbb1fcc60f upstream. nfsiostat was failing to find mounted filesystems on kernels after 2.6.38 because of changes to show_vfsstat() by commit c7f404b40a3665d9f4e9a927cc5c1ee0479ed8f9. This patch adds back the "device" tag before the nfs server entry so scripts can parse the mountstats file correctly. Signed-off-by: Bryan Schumaker Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman --- fs/namespace.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/namespace.c b/fs/namespace.c index fe59bd145d2..304a55d0aa8 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1109,6 +1109,7 @@ static int show_vfsstat(struct seq_file *m, void *v) /* device */ if (mnt->mnt_sb->s_op->show_devname) { + seq_puts(m, "device "); err = mnt->mnt_sb->s_op->show_devname(m, mnt); } else { if (mnt->mnt_devname) { From 0198c89767e26f78e619eef2309be74186b4fdcd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 28 Sep 2011 11:57:23 +0200 Subject: [PATCH 0099/4025] io-mapping: ensure io_mapping_map_atomic _is_ atomic commit 24dd85ff723f142093f44244764b9b5c152235b8 upstream. For the !HAVE_ATOMIC_IOMAP case the stub functions did not call pagefault_disable/_enable. The i915 driver relies on the map actually being atomic, otherwise it can deadlock with it's own pagefault handler in the gtt pwrite fastpath. This is exercised by gem_mmap_gtt from the intel-gpu-toosl gem testsuite. v2: Chris Wilson noted the lack of an include. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=38115 Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Signed-off-by: Keith Packard Signed-off-by: Greg Kroah-Hartman --- include/linux/io-mapping.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/io-mapping.h b/include/linux/io-mapping.h index 8cdcc2a199a..1feeb526356 100644 --- a/include/linux/io-mapping.h +++ b/include/linux/io-mapping.h @@ -117,6 +117,8 @@ io_mapping_unmap(void __iomem *vaddr) #else +#include + /* this struct isn't actually defined anywhere */ struct io_mapping; @@ -138,12 +140,14 @@ static inline void __iomem * io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset) { + pagefault_disable(); return ((char __force __iomem *) mapping) + offset; } static inline void io_mapping_unmap_atomic(void __iomem *vaddr) { + pagefault_enable(); } /* Non-atomic map/unmap */ From dae187ec04a6f7752b140d789269730791a7388f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 26 Oct 2011 09:53:41 +0800 Subject: [PATCH 0100/4025] ASoC: wm8940: Properly set codec->dapm.bias_level commit 5927f94700e860ae27ff24e7f3bc9e4f7b9922eb upstream. Reported-by: Chris Paulson-Ellis Signed-off-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8940.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 25580e3ee7c..d4ecb3f2d8d 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -472,6 +472,8 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec, break; } + codec->dapm.bias_level = level; + return ret; } From 311afee68d5f06f9f0910231b17e9d5b25ec4491 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 17 Oct 2011 20:14:56 +0800 Subject: [PATCH 0101/4025] ASoC: wm8741: Fix setting interface format for DSP modes commit 3a340104fad6ecbea5ad6792a2ea855f0507a6e0 upstream. According to the datasheet: Format Control (05h) BITS[3:2] FMT[1:0] Audio data format selection 00 = right justified mode 01 = left justified mode 10 = I2S mode 11 = DSP mode BIT[4] LRP Polarity selec for LRCLK/DSP mode select 0 = normal LRCLK poalrity/DSP mode A 1 = inverted LRCLK poarity/DSP mode B For SND_SOC_DAIFMT_DSP_A, we should set 0x000C instead of 0x0003. For SND_SOC_DAIFMT_DSP_B, we should set 0x001C instead of 0x0013. Signed-off-by: Axel Lin Acked-by: Liam Girdwood Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8741.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 25af901fe81..c173aee3390 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -337,10 +337,10 @@ static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai, iface |= 0x0004; break; case SND_SOC_DAIFMT_DSP_A: - iface |= 0x0003; + iface |= 0x000C; break; case SND_SOC_DAIFMT_DSP_B: - iface |= 0x0013; + iface |= 0x001C; break; default: return -EINVAL; From 681c941ad1d50d46d61d435304f386efd763be9d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 13 Oct 2011 02:03:54 -0700 Subject: [PATCH 0102/4025] ASoC: ak4642: fixup cache register table commit 19b115e523208a926813751aac8934cf3fc6085e upstream. ak4642 register was 8bit, but cache table was defined as 16bit. ak4642 doesn't work correctry without this patch. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/ak4642.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 65f46047b1c..79c1b3d79f1 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -162,17 +162,17 @@ struct ak4642_priv { /* * ak4642 register cache */ -static const u16 ak4642_reg[AK4642_CACHEREGNUM] = { - 0x0000, 0x0000, 0x0001, 0x0000, - 0x0002, 0x0000, 0x0000, 0x0000, - 0x00e1, 0x00e1, 0x0018, 0x0000, - 0x00e1, 0x0018, 0x0011, 0x0008, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, +static const u8 ak4642_reg[AK4642_CACHEREGNUM] = { + 0x00, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0xe1, 0xe1, 0x18, 0x00, + 0xe1, 0x18, 0x11, 0x08, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, }; /* From 772e6e8f76d6f0e01008b5c4bcd054be78a611ac Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 13 Oct 2011 17:17:06 +0800 Subject: [PATCH 0103/4025] ASoC: ak4535: fixup cache register table commit 7c04241acbdaf97f1448dcccd27ea0fcd1a57684 upstream. ak4535_reg should be 8bit, but cache table is defined as 16bit. Signed-off-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/ak4535.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index e1a214ee757..65abd09e1ca 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -40,11 +40,11 @@ struct ak4535_priv { /* * ak4535 register cache */ -static const u16 ak4535_reg[AK4535_CACHEREGNUM] = { - 0x0000, 0x0080, 0x0000, 0x0003, - 0x0002, 0x0000, 0x0011, 0x0001, - 0x0000, 0x0040, 0x0036, 0x0010, - 0x0000, 0x0000, 0x0057, 0x0000, +static const u8 ak4535_reg[AK4535_CACHEREGNUM] = { + 0x00, 0x80, 0x00, 0x03, + 0x02, 0x00, 0x11, 0x01, + 0x00, 0x40, 0x36, 0x10, + 0x00, 0x00, 0x57, 0x00, }; /* From 8f4d7cf1f6e6f18f96a196a07b54b575669582cc Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 20 Oct 2011 12:13:24 +0800 Subject: [PATCH 0104/4025] ASoC: wm8994: Use SND_SOC_DAPM_AIF_OUT for AIF3 Capture commit 35024f4922f7b271e7529673413889aa3d51c5fc upstream. Signed-off-by: Axel Lin Acked-by: Liam Girdwood Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8994.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 83014a7c2e1..fb9f08ab84c 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -1266,7 +1266,7 @@ SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_NOPM, 0, 0, &aif2dac_mux), SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux), SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0), -SND_SOC_DAPM_AIF_IN("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0), +SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0), From 9c0390e9a3d5e768dfb2e007509e59d30fec9bb0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 23 Sep 2011 21:26:33 +0100 Subject: [PATCH 0105/4025] ASoC: Remove direct register cache accesses from WM8962 driver commit 38f3f31a0a797bdbcc0cdb12553bbecc2f9a91c4 upstream. Also fix return values for speaker switch updates. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8962.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 5e05eed96c3..b9c0fbebd51 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -2018,7 +2018,6 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - u16 *reg_cache = codec->reg_cache; int ret; /* Apply the update (if any) */ @@ -2027,16 +2026,19 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol, return 0; /* If the left PGA is enabled hit that VU bit... */ - if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTL_PGA_ENA) - return snd_soc_write(codec, WM8962_SPKOUTL_VOLUME, - reg_cache[WM8962_SPKOUTL_VOLUME]); + ret = snd_soc_read(codec, WM8962_PWR_MGMT_2); + if (ret & WM8962_SPKOUTL_PGA_ENA) { + snd_soc_write(codec, WM8962_SPKOUTL_VOLUME, + snd_soc_read(codec, WM8962_SPKOUTL_VOLUME)); + return 1; + } /* ...otherwise the right. The VU is stereo. */ - if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTR_PGA_ENA) - return snd_soc_write(codec, WM8962_SPKOUTR_VOLUME, - reg_cache[WM8962_SPKOUTR_VOLUME]); + if (ret & WM8962_SPKOUTR_PGA_ENA) + snd_soc_write(codec, WM8962_SPKOUTR_VOLUME, + snd_soc_read(codec, WM8962_SPKOUTR_VOLUME)); - return 0; + return 1; } static const char *cap_hpf_mode_text[] = { @@ -2336,7 +2338,6 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - u16 *reg_cache = codec->reg_cache; int reg; switch (w->shift) { @@ -2359,7 +2360,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - return snd_soc_write(codec, reg, reg_cache[reg]); + return snd_soc_write(codec, reg, snd_soc_read(codec, reg)); default: BUG(); return -EINVAL; From 54a8a620cee91954666080a5525d7f43cad0a693 Mon Sep 17 00:00:00 2001 From: Susan Gao Date: Thu, 29 Sep 2011 11:08:18 +0100 Subject: [PATCH 0106/4025] ASoC: Fix a bug in WM8962 DSP_A and DSP_B settings commit fbc7c62a3ff831aef24894b7982cd1adb2b7e070 upstream. Signed-off-by: Susan Gao Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8962.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index b9c0fbebd51..6bc72a7b6b9 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3028,9 +3028,9 @@ static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) int aif0 = 0; switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_DSP_A: - aif0 |= WM8962_LRCLK_INV; case SND_SOC_DAIFMT_DSP_B: + aif0 |= WM8962_LRCLK_INV | 3; + case SND_SOC_DAIFMT_DSP_A: aif0 |= 3; switch (fmt & SND_SOC_DAIFMT_INV_MASK) { From d69540f85872860468e85ef8004f5580652b3335 Mon Sep 17 00:00:00 2001 From: Carsten Otte Date: Tue, 18 Oct 2011 12:27:12 +0200 Subject: [PATCH 0107/4025] KVM: s390: check cpu_id prior to using it commit 4d47555a80495657161a7e71ec3014ff2021e450 upstream. We use the cpu id provided by userspace as array index here. Thus we clearly need to check it first. Ooops. Signed-off-by: Carsten Otte Signed-off-by: Christian Borntraeger Signed-off-by: Marcelo Tosatti Signed-off-by: Greg Kroah-Hartman --- arch/s390/kvm/kvm-s390.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 67345ae7ce8..2ada634fc7c 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -301,11 +301,17 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) { - struct kvm_vcpu *vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL); - int rc = -ENOMEM; + struct kvm_vcpu *vcpu; + int rc = -EINVAL; + + if (id >= KVM_MAX_VCPUS) + goto out; + + rc = -ENOMEM; + vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL); if (!vcpu) - goto out_nomem; + goto out; vcpu->arch.sie_block = (struct kvm_s390_sie_block *) get_zeroed_page(GFP_KERNEL); @@ -341,7 +347,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, free_page((unsigned long)(vcpu->arch.sie_block)); out_free_cpu: kfree(vcpu); -out_nomem: +out: return ERR_PTR(rc); } From 0a85ef94c2af8630deb851e559c9d3bdf5530802 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sun, 30 Oct 2011 15:16:07 +0100 Subject: [PATCH 0108/4025] user per registers vs. ptrace single stepping commit a45aff5285871bf7be1781d9462d3fdbb6c913f9 upstream. git commit 5e9a2692 "[S390] ptrace cleanup" introduced a regression for the case when both a user PER set (e.g. a storage alteration trace) and PTRACE_SINGLESTEP are active. The new code will overrule the user PER set with a instruction-fetch PER set over the whole address space for ptrace single stepping. The inferior process will be stopped after each instruction with an instruction fetch event. Any other events that may have occurred concurrently are not reported (e.g. storage alteration event) because the control bits for them are not set. The solution is to merge the PER control bits of the user PER set with the PER_EVENT_IFETCH control bit for PTRACE_SINGLESTEP. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/ptrace.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index ef86ad24398..ae0e14b8880 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -47,29 +47,31 @@ enum s390_regset { void update_per_regs(struct task_struct *task) { - static const struct per_regs per_single_step = { - .control = PER_EVENT_IFETCH, - .start = 0, - .end = PSW_ADDR_INSN, - }; struct pt_regs *regs = task_pt_regs(task); struct thread_struct *thread = &task->thread; - const struct per_regs *new; - struct per_regs old; - - /* TIF_SINGLE_STEP overrides the user specified PER registers. */ - new = test_tsk_thread_flag(task, TIF_SINGLE_STEP) ? - &per_single_step : &thread->per_user; + struct per_regs old, new; + + /* Copy user specified PER registers */ + new.control = thread->per_user.control; + new.start = thread->per_user.start; + new.end = thread->per_user.end; + + /* merge TIF_SINGLE_STEP into user specified PER registers. */ + if (test_tsk_thread_flag(task, TIF_SINGLE_STEP)) { + new.control |= PER_EVENT_IFETCH; + new.start = 0; + new.end = PSW_ADDR_INSN; + } /* Take care of the PER enablement bit in the PSW. */ - if (!(new->control & PER_EVENT_MASK)) { + if (!(new.control & PER_EVENT_MASK)) { regs->psw.mask &= ~PSW_MASK_PER; return; } regs->psw.mask |= PSW_MASK_PER; __ctl_store(old, 9, 11); - if (memcmp(new, &old, sizeof(struct per_regs)) != 0) - __ctl_load(*new, 9, 11); + if (memcmp(&new, &old, sizeof(struct per_regs)) != 0) + __ctl_load(new, 9, 11); } void user_enable_single_step(struct task_struct *task) From cd1ee66bb5156203711560ee73b00e70bb8450b5 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Sun, 30 Oct 2011 15:16:08 +0100 Subject: [PATCH 0109/4025] memory leak with RCU_TABLE_FREE commit e73b7fffe487c315fd1a4fa22282e3362b440a06 upstream. The rcu page table free code uses a couple of bits in the page table pointer passed to tlb_remove_table to discern the different page table types. __tlb_remove_table extracts the type with an incorrect mask which leads to memory leaks. The correct mask is ((FRAG_MASK << 4) | FRAG_MASK). Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/mm/pgtable.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c index 37a23c22370..458893f5f6b 100644 --- a/arch/s390/mm/pgtable.c +++ b/arch/s390/mm/pgtable.c @@ -291,8 +291,9 @@ void page_table_free_rcu(struct mmu_gather *tlb, unsigned long *table) void __tlb_remove_table(void *_table) { - void *table = (void *)((unsigned long) _table & PAGE_MASK); - unsigned type = (unsigned long) _table & ~PAGE_MASK; + const unsigned long mask = (FRAG_MASK << 4) | FRAG_MASK; + void *table = (void *)((unsigned long) _table & ~mask); + unsigned type = (unsigned long) _table & mask; if (type) __page_table_free_rcu(table, type); From 761f2b411806f70dfaa3d248b4182e7ba154efd4 Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Sun, 30 Oct 2011 15:16:52 +0100 Subject: [PATCH 0110/4025] ccwgroup: move attributes to attribute group commit dbdf1afcaaabe83dea15a3cb9b9013e73ae3b1ad upstream. Put sysfs attributes of ccwgroup devices in an attribute group to ensure that these attributes are actually present when userspace is notified via uevents. Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- drivers/s390/cio/ccwgroup.c | 42 +++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 5c567414c4b..cda9bd6e48e 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -87,6 +87,12 @@ static void __ccwgroup_remove_cdev_refs(struct ccwgroup_device *gdev) } } +static ssize_t ccwgroup_online_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); +static ssize_t ccwgroup_online_show(struct device *dev, + struct device_attribute *attr, + char *buf); /* * Provide an 'ungroup' attribute so the user can remove group devices no * longer needed or accidentially created. Saves memory :) @@ -134,6 +140,20 @@ ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const } static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store); +static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store); + +static struct attribute *ccwgroup_attrs[] = { + &dev_attr_online.attr, + &dev_attr_ungroup.attr, + NULL, +}; +static struct attribute_group ccwgroup_attr_group = { + .attrs = ccwgroup_attrs, +}; +static const struct attribute_group *ccwgroup_attr_groups[] = { + &ccwgroup_attr_group, + NULL, +}; static void ccwgroup_release (struct device *dev) @@ -293,25 +313,17 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, } dev_set_name(&gdev->dev, "%s", dev_name(&gdev->cdev[0]->dev)); - + gdev->dev.groups = ccwgroup_attr_groups; rc = device_add(&gdev->dev); if (rc) goto error; get_device(&gdev->dev); - rc = device_create_file(&gdev->dev, &dev_attr_ungroup); - - if (rc) { - device_unregister(&gdev->dev); - goto error; - } - rc = __ccwgroup_create_symlinks(gdev); if (!rc) { mutex_unlock(&gdev->reg_mutex); put_device(&gdev->dev); return 0; } - device_remove_file(&gdev->dev, &dev_attr_ungroup); device_unregister(&gdev->dev); error: for (i = 0; i < num_devices; i++) @@ -423,7 +435,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const int ret; if (!dev->driver) - return -ENODEV; + return -EINVAL; gdev = to_ccwgroupdev(dev); gdrv = to_ccwgroupdrv(dev->driver); @@ -456,8 +468,6 @@ ccwgroup_online_show (struct device *dev, struct device_attribute *attr, char *b return sprintf(buf, online ? "1\n" : "0\n"); } -static DEVICE_ATTR(online, 0644, ccwgroup_online_show, ccwgroup_online_store); - static int ccwgroup_probe (struct device *dev) { @@ -469,12 +479,7 @@ ccwgroup_probe (struct device *dev) gdev = to_ccwgroupdev(dev); gdrv = to_ccwgroupdrv(dev->driver); - if ((ret = device_create_file(dev, &dev_attr_online))) - return ret; - ret = gdrv->probe ? gdrv->probe(gdev) : -ENODEV; - if (ret) - device_remove_file(dev, &dev_attr_online); return ret; } @@ -485,9 +490,6 @@ ccwgroup_remove (struct device *dev) struct ccwgroup_device *gdev; struct ccwgroup_driver *gdrv; - device_remove_file(dev, &dev_attr_online); - device_remove_file(dev, &dev_attr_ungroup); - if (!dev->driver) return 0; From cf541bb3f2532e7493720a208021e43b85156870 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 7 Sep 2011 15:00:02 -0700 Subject: [PATCH 0111/4025] WMI: properly cleanup devices to avoid crashes commit 023b9565972a4a5e0f01b9aa32680af6e9b5c388 upstream. We need to remove devices that we destroy from the list, otherwise we'll crash if there are more than one "_WDG" methods in DSDT. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=32052 Tested-by: Ilya Tumaykin Signed-off-by: Dmitry Torokhov Acked-by: Carlos Corbacho Signed-off-by: Matthew Garrett Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/wmi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index f23d5a84e7b..9b88be42b6c 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -754,9 +754,13 @@ static void wmi_free_devices(void) struct wmi_block *wblock, *next; /* Delete devices for all the GUIDs */ - list_for_each_entry_safe(wblock, next, &wmi_block_list, list) + list_for_each_entry_safe(wblock, next, &wmi_block_list, list) { + list_del(&wblock->list); if (wblock->dev.class) device_unregister(&wblock->dev); + else + kfree(wblock); + } } static bool guid_already_parsed(const char *guid_string) From 9bdb666778b0eb502554288ac3188139c3c45f0e Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 11 Oct 2011 17:41:32 +0200 Subject: [PATCH 0112/4025] iommu/amd: Fix wrong shift direction commit fcd0861db1cf4e6ed99f60a815b7b72c2ed36ea4 upstream. The shift direction was wrong because the function takes a page number and i is the address is the loop. Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/amd_iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c index d3d9d50d93a..bfd75ff5d5b 100644 --- a/arch/x86/kernel/amd_iommu.c +++ b/arch/x86/kernel/amd_iommu.c @@ -1203,7 +1203,7 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom, if (!pte || !IOMMU_PTE_PRESENT(*pte)) continue; - dma_ops_reserve_addresses(dma_dom, i << PAGE_SHIFT, 1); + dma_ops_reserve_addresses(dma_dom, i >> PAGE_SHIFT, 1); } update_domain(&dma_dom->domain); From c10d19f3ad8294dbe5d500a46891fe94558be8ea Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 8 Jul 2011 11:04:38 +0200 Subject: [PATCH 0113/4025] carminefb: Fix module parameters permissions commit c84c14224bbca6ec60d5851fcc87be0e34df2f44 upstream. The third parameter of module_param is supposed to be an octal value. The missing leading "0" causes the following: $ ls -l /sys/module/carminefb/parameters/ total 0 -rw-rwxr-- 1 root root 4096 Jul 8 08:55 fb_displays -rw-rwxr-- 1 root root 4096 Jul 8 08:55 fb_mode -rw-rwxr-- 1 root root 4096 Jul 8 08:55 fb_mode_str After fixing the perm parameter, we get the expected: $ ls -l /sys/module/carminefb/parameters/ total 0 -r--r--r-- 1 root root 4096 Jul 8 08:56 fb_displays -r--r--r-- 1 root root 4096 Jul 8 08:56 fb_mode -r--r--r-- 1 root root 4096 Jul 8 08:56 fb_mode_str Signed-off-by: Jean Delvare Cc: Paul Mundt Cc: Sebastian Siewior Signed-off-by: Paul Mundt Signed-off-by: Greg Kroah-Hartman --- drivers/video/carminefb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c index caaa27d4a46..cb09aa1fa13 100644 --- a/drivers/video/carminefb.c +++ b/drivers/video/carminefb.c @@ -32,11 +32,11 @@ #define CARMINEFB_DEFAULT_VIDEO_MODE 1 static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE; -module_param(fb_mode, uint, 444); +module_param(fb_mode, uint, 0444); MODULE_PARM_DESC(fb_mode, "Initial video mode as integer."); static char *fb_mode_str; -module_param(fb_mode_str, charp, 444); +module_param(fb_mode_str, charp, 0444); MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters."); /* @@ -46,7 +46,7 @@ MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters."); * 0b010 Display 1 */ static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1; -module_param(fb_displays, int, 444); +module_param(fb_displays, int, 0444); MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used"); struct carmine_hw { From 627afd48f8d28f14271b9ccf3b1f5d3e77237e2c Mon Sep 17 00:00:00 2001 From: Herton Ronaldo Krzesinski Date: Fri, 17 Jun 2011 19:02:39 +0000 Subject: [PATCH 0114/4025] fb: avoid possible deadlock caused by fb_set_suspend commit 9e769ff3f585db8f978f9113be83d36c7e3965dd upstream. A lock ordering issue can cause deadlocks: in framebuffer/console code, all needed struct fb_info locks are taken before acquire_console_sem(), in places which need to take console semaphore. But fb_set_suspend is always called with console semaphore held, and inside it we call lock_fb_info which gets the fb_info lock, inverse locking order of what the rest of the code does. This causes a real deadlock issue, when we write to state fb sysfs attribute (which calls fb_set_suspend) while a framebuffer is being unregistered by remove_conflicting_framebuffers, as can be shown by following show blocked state trace on a test program which loads i915 and runs another forked processes writing to state attribute: Test process with semaphore held and trying to get fb_info lock: .. fb-test2 D 0000000000000000 0 237 228 0x00000000 ffff8800774f3d68 0000000000000082 00000000000135c0 00000000000135c0 ffff880000000000 ffff8800774f3fd8 ffff8800774f3fd8 ffff880076ee4530 00000000000135c0 ffff8800774f3fd8 ffff8800774f2000 00000000000135c0 Call Trace: [] __mutex_lock_slowpath+0x11a/0x1e0 [] ? _raw_spin_lock_irq+0x22/0x40 [] mutex_lock+0x23/0x50 [] lock_fb_info+0x25/0x60 [] fb_set_suspend+0x20/0x80 [] store_fbstate+0x4f/0x70 [] dev_attr_store+0x20/0x30 [] sysfs_write_file+0xd4/0x160 [] vfs_write+0xc6/0x190 [] sys_write+0x51/0x90 [] system_call_fastpath+0x16/0x1b .. modprobe process stalled because has the fb_info lock (got inside unregister_framebuffer) but waiting for the semaphore held by the test process which is waiting to get the fb_info lock: .. modprobe D 0000000000000000 0 230 218 0x00000000 ffff880077a4d618 0000000000000082 0000000000000001 0000000000000001 ffff880000000000 ffff880077a4dfd8 ffff880077a4dfd8 ffff8800775a2e20 00000000000135c0 ffff880077a4dfd8 ffff880077a4c000 00000000000135c0 Call Trace: [] schedule_timeout+0x215/0x310 [] ? get_parent_ip+0x11/0x50 [] __down+0x6d/0xb0 [] down+0x41/0x50 [] acquire_console_sem+0x2c/0x50 [] unbind_con_driver+0xad/0x2d0 [] fbcon_event_notify+0x457/0x890 [] ? _raw_spin_unlock_irqrestore+0x1f/0x50 [] ? get_parent_ip+0x11/0x50 [] notifier_call_chain+0x4d/0x70 [] __blocking_notifier_call_chain+0x58/0x80 [] blocking_notifier_call_chain+0x16/0x20 [] fb_notifier_call_chain+0x1b/0x20 [] unregister_framebuffer+0x7c/0x130 [] remove_conflicting_framebuffers+0x153/0x180 [] register_framebuffer+0x93/0x2c0 [] drm_fb_helper_single_fb_probe+0x252/0x2f0 [drm_kms_helper] [] drm_fb_helper_initial_config+0x2f3/0x6d0 [drm_kms_helper] [] ? drm_fb_helper_single_add_all_connectors+0x5d/0x1c0 [drm_kms_helper] [] intel_fbdev_init+0xa8/0x160 [i915] [] i915_driver_load+0x854/0x12b0 [i915] [] drm_get_pci_dev+0x19e/0x360 [drm] [] ? sub_preempt_count+0x9d/0xd0 [] i915_pci_probe+0x15/0x17 [i915] [] local_pci_probe+0x5f/0xd0 [] pci_device_probe+0x119/0x120 [] ? driver_sysfs_add+0x7a/0xb0 [] driver_probe_device+0xa3/0x290 [] ? __driver_attach+0x0/0xb0 [] __driver_attach+0xab/0xb0 [] ? __driver_attach+0x0/0xb0 [] bus_for_each_dev+0x5e/0x90 [] driver_attach+0x1e/0x20 [] bus_add_driver+0xe2/0x320 [] ? i915_init+0x0/0x96 [i915] [] driver_register+0x76/0x140 [] ? i915_init+0x0/0x96 [i915] [] __pci_register_driver+0x56/0xd0 [] drm_pci_init+0xe4/0xf0 [drm] [] ? i915_init+0x0/0x96 [i915] [] drm_init+0x58/0x70 [drm] [] i915_init+0x94/0x96 [i915] [] do_one_initcall+0x44/0x190 [] sys_init_module+0xcb/0x210 [] system_call_fastpath+0x16/0x1b .. fb-test2 which reproduces above is available on kernel.org bug #26232. To solve this issue, avoid calling lock_fb_info inside fb_set_suspend, and move it out to where needed (callers of fb_set_suspend must call lock_fb_info before if needed). So far, the only place which needs to call lock_fb_info is store_fbstate, all other places which calls fb_set_suspend are suspend/resume hooks that should not need the lock as they should be run only when processes are already frozen in suspend/resume. References: https://bugzilla.kernel.org/show_bug.cgi?id=26232 Signed-off-by: Herton Ronaldo Krzesinski Signed-off-by: Florian Tobias Schandinat Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbmem.c | 3 --- drivers/video/fbsysfs.c | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 5aac00eb183..ad936295d8f 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1738,8 +1738,6 @@ void fb_set_suspend(struct fb_info *info, int state) { struct fb_event event; - if (!lock_fb_info(info)) - return; event.info = info; if (state) { fb_notifier_call_chain(FB_EVENT_SUSPEND, &event); @@ -1748,7 +1746,6 @@ void fb_set_suspend(struct fb_info *info, int state) info->state = FBINFO_STATE_RUNNING; fb_notifier_call_chain(FB_EVENT_RESUME, &event); } - unlock_fb_info(info); } /** diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c index 04251ce8918..67afa9c2289 100644 --- a/drivers/video/fbsysfs.c +++ b/drivers/video/fbsysfs.c @@ -399,9 +399,12 @@ static ssize_t store_fbstate(struct device *device, state = simple_strtoul(buf, &last, 0); + if (!lock_fb_info(fb_info)) + return -ENODEV; console_lock(); fb_set_suspend(fb_info, (int)state); console_unlock(); + unlock_fb_info(fb_info); return count; } From 3f199a7d6f2c769131f1c0dda2eb9b30d1e21617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= Date: Fri, 2 Sep 2011 19:24:03 +0200 Subject: [PATCH 0115/4025] fb: sh-mobile: Fix deadlock risk between lock_fb_info() and console_lock() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 4a47a0e09c504e3ce0ccdb405411aefc5b09deb8 upstream. Following on Herton's patch "fb: avoid possible deadlock caused by fb_set_suspend" which moves lock_fb_info() out of fb_set_suspend() to its callers, correct sh-mobile's locking around call to fb_set_suspend() and the same sort of deaklocks with console_lock() due to order of taking the lock. console_lock() must be taken while fb_info is already locked and fb_info must be locked while calling fb_set_suspend(). Signed-off-by: Bruno Prémont Signed-off-by: Guennadi Liakhovetski Signed-off-by: Florian Tobias Schandinat Signed-off-by: Greg Kroah-Hartman --- drivers/video/sh_mobile_hdmi.c | 47 +++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 7d54e2c612f..647ba984f00 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -1111,6 +1111,7 @@ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate, static void sh_hdmi_edid_work_fn(struct work_struct *work) { struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); + struct fb_info *info; struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; struct sh_mobile_lcdc_chan *ch; int ret; @@ -1123,8 +1124,9 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) mutex_lock(&hdmi->mutex); + info = hdmi->info; + if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) { - struct fb_info *info = hdmi->info; unsigned long parent_rate = 0, hdmi_rate; ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate); @@ -1148,42 +1150,45 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) ch = info->par; - console_lock(); + if (lock_fb_info(info)) { + console_lock(); - /* HDMI plug in */ - if (!sh_hdmi_must_reconfigure(hdmi) && - info->state == FBINFO_STATE_RUNNING) { - /* - * First activation with the default monitor - just turn - * on, if we run a resume here, the logo disappears - */ - if (lock_fb_info(info)) { + /* HDMI plug in */ + if (!sh_hdmi_must_reconfigure(hdmi) && + info->state == FBINFO_STATE_RUNNING) { + /* + * First activation with the default monitor - just turn + * on, if we run a resume here, the logo disappears + */ info->var.width = hdmi->var.width; info->var.height = hdmi->var.height; sh_hdmi_display_on(hdmi, info); - unlock_fb_info(info); + } else { + /* New monitor or have to wake up */ + fb_set_suspend(info, 0); } - } else { - /* New monitor or have to wake up */ - fb_set_suspend(info, 0); - } - console_unlock(); + console_unlock(); + unlock_fb_info(info); + } } else { ret = 0; - if (!hdmi->info) + if (!info) goto out; hdmi->monspec.modedb_len = 0; fb_destroy_modedb(hdmi->monspec.modedb); hdmi->monspec.modedb = NULL; - console_lock(); + if (lock_fb_info(info)) { + console_lock(); - /* HDMI disconnect */ - fb_set_suspend(hdmi->info, 1); + /* HDMI disconnect */ + fb_set_suspend(info, 1); - console_unlock(); + console_unlock(); + unlock_fb_info(info); + } } out: From cdf3e3448744d14b6307dfc7f7203cba6fecf199 Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Mon, 23 May 2011 21:39:58 +0000 Subject: [PATCH 0116/4025] viafb: use display information in info not in var for panning commit d933990c57b498c092ceef591c7c5d69dbfe9f30 upstream. As Laurent pointed out we must not use any information in the passed var besides xoffset, yoffset and vmode as otherwise applications might abuse it. Also use the aligned fix.line_length and not the (possible) unaligned xres_virtual. Signed-off-by: Florian Tobias Schandinat Reported-by: Laurent Pinchart Acked-by: Laurent Pinchart Signed-off-by: Greg Kroah-Hartman --- drivers/video/via/viafbdev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index cf43c80d27f..518f3ffa5a9 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -348,8 +348,9 @@ static int viafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct viafb_par *viapar = info->par; - u32 vram_addr = (var->yoffset * var->xres_virtual + var->xoffset) - * (var->bits_per_pixel / 8) + viapar->vram_addr; + u32 vram_addr = viapar->vram_addr + + var->yoffset * info->fix.line_length + + var->xoffset * info->var.bits_per_pixel / 8; DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr); if (!viafb_dual_fb) { From 76ec8cdcca9f8fa8e2546ed96a2715a6654487ad Mon Sep 17 00:00:00 2001 From: Florian Tobias Schandinat Date: Mon, 6 Jun 2011 01:27:34 +0000 Subject: [PATCH 0117/4025] viafb: improve pitch handling commit 936a3f770b8de7042d793272f008ef1bb08522e9 upstream. This patch adds checks for minimum and maximum pitch size to prevent invalid settings which could otherwise crash the machine. Also the alignment is done in a slightly more readable way. Signed-off-by: Florian Tobias Schandinat Signed-off-by: Greg Kroah-Hartman --- drivers/video/via/via_modesetting.h | 5 +++++ drivers/video/via/viafbdev.c | 11 ++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/video/via/via_modesetting.h b/drivers/video/via/via_modesetting.h index ae35cfdeb37..013884543e9 100644 --- a/drivers/video/via/via_modesetting.h +++ b/drivers/video/via/via_modesetting.h @@ -28,6 +28,11 @@ #include + +#define VIA_PITCH_SIZE (1<<3) +#define VIA_PITCH_MAX 0x3FF8 + + void via_set_primary_address(u32 addr); void via_set_secondary_address(u32 addr); void via_set_primary_pitch(u32 pitch); diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index 518f3ffa5a9..dd1276e886f 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c @@ -151,7 +151,8 @@ static void viafb_update_fix(struct fb_info *info) info->fix.visual = bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - info->fix.line_length = (info->var.xres_virtual * bpp / 8 + 7) & ~7; + info->fix.line_length = ALIGN(info->var.xres_virtual * bpp / 8, + VIA_PITCH_SIZE); } static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix, @@ -238,8 +239,12 @@ static int viafb_check_var(struct fb_var_screeninfo *var, depth = 24; viafb_fill_var_color_info(var, depth); - line = (var->xres_virtual * var->bits_per_pixel / 8 + 7) & ~7; - if (line * var->yres_virtual > ppar->memsize) + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + + line = ALIGN(var->xres_virtual * var->bits_per_pixel / 8, + VIA_PITCH_SIZE); + if (line > VIA_PITCH_MAX || line * var->yres_virtual > ppar->memsize) return -EINVAL; /* Based on var passed in to calculate the refresh, From 2ba0b8db49fe9f662eb20bd5fa84c91bcdaec206 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sat, 16 Jul 2011 00:51:00 -0300 Subject: [PATCH 0118/4025] uvcvideo: Set alternate setting 0 on resume if the bus has been reset commit d59a7b1dbce8b972ec2dc9fcaaae0bfa23687423 upstream. If the bus has been reset on resume, set the alternate setting to 0. This should be the default value, but some devices crash or otherwise misbehave if they don't receive a SET_INTERFACE request before any other video control request. Microdia's 0c45:6437 camera has been found to require this change or it will stop sending video data after resume. uvc_video.c] Signed-off-by: Ming Lei Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/uvc/uvc_driver.c | 2 +- drivers/media/video/uvc/uvc_video.c | 10 +++++++++- drivers/media/video/uvc/uvcvideo.h | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index b6eae48d7fb..1f962dc3a6a 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -1960,7 +1960,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset) list_for_each_entry(stream, &dev->streams, list) { if (stream->intf == intf) - return uvc_video_resume(stream); + return uvc_video_resume(stream, reset); } uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface " diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 49994793cc7..6f147defcce 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c @@ -1104,10 +1104,18 @@ int uvc_video_suspend(struct uvc_streaming *stream) * buffers, making sure userspace applications are notified of the problem * instead of waiting forever. */ -int uvc_video_resume(struct uvc_streaming *stream) +int uvc_video_resume(struct uvc_streaming *stream, int reset) { int ret; + /* If the bus has been reset on resume, set the alternate setting to 0. + * This should be the default value, but some devices crash or otherwise + * misbehave if they don't receive a SET_INTERFACE request before any + * other video control request. + */ + if (reset) + usb_set_interface(stream->dev->udev, stream->intfnum, 0); + stream->frozen = 0; ret = uvc_commit_video(stream, &stream->ctrl); diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index 20107fd3574..2a38d5e5535 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -639,7 +639,7 @@ extern void uvc_mc_cleanup_entity(struct uvc_entity *entity); /* Video */ extern int uvc_video_init(struct uvc_streaming *stream); extern int uvc_video_suspend(struct uvc_streaming *stream); -extern int uvc_video_resume(struct uvc_streaming *stream); +extern int uvc_video_resume(struct uvc_streaming *stream, int reset); extern int uvc_video_enable(struct uvc_streaming *stream, int enable); extern int uvc_probe_video(struct uvc_streaming *stream, struct uvc_streaming_control *probe); From 4d2ae8d3b315fbf36d760fd8dd755fb1d55a0f87 Mon Sep 17 00:00:00 2001 From: Patrick Boettcher Date: Wed, 3 Aug 2011 12:08:21 -0300 Subject: [PATCH 0119/4025] DiBcom: protect the I2C bufer access commit 79fcce3230b140f7675f8529ee53fe2f9644f902 upstream. This patch protects the I2C buffer access in order to manage concurrent access. This protection is done using mutex. Furthermore, for the dib9000, if a pid filtering command is received during the tuning, this pid filtering command is delayed to avoid any concurrent access issue. Cc: Mauro Carvalho Chehab Cc: Florian Mickler Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb/frontends/dib0070.c | 37 ++++- drivers/media/dvb/frontends/dib0090.c | 70 ++++++-- drivers/media/dvb/frontends/dib7000m.c | 27 ++- drivers/media/dvb/frontends/dib7000p.c | 32 +++- drivers/media/dvb/frontends/dib8000.c | 72 ++++++-- drivers/media/dvb/frontends/dib9000.c | 164 ++++++++++++++++--- drivers/media/dvb/frontends/dibx000_common.c | 76 +++++++-- drivers/media/dvb/frontends/dibx000_common.h | 1 + 8 files changed, 412 insertions(+), 67 deletions(-) diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c index 1d47d4da7d4..dc1cb17a6ea 100644 --- a/drivers/media/dvb/frontends/dib0070.c +++ b/drivers/media/dvb/frontends/dib0070.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "dvb_frontend.h" @@ -78,10 +79,18 @@ struct dib0070_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[3]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; -static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) +static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg; memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); @@ -96,13 +105,23 @@ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg) if (i2c_transfer(state->i2c, state->msg, 2) != 2) { printk(KERN_WARNING "DiB0070 I2C read failed\n"); - return 0; - } - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = 0; + } else + ret = (state->i2c_read_buffer[0] << 8) + | state->i2c_read_buffer[1]; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } state->i2c_write_buffer[0] = reg; state->i2c_write_buffer[1] = val >> 8; state->i2c_write_buffer[2] = val & 0xff; @@ -115,9 +134,12 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) if (i2c_transfer(state->i2c, state->msg, 1) != 1) { printk(KERN_WARNING "DiB0070 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; + ret = -EREMOTEIO; + } else + ret = 0; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } #define HARD_RESET(state) do { \ @@ -734,6 +756,7 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter state->cfg = cfg; state->i2c = i2c; state->fe = fe; + mutex_init(&state->i2c_buffer_lock); fe->tuner_priv = state; if (dib0070_reset(fe) != 0) diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c index c9c935ae41e..b174d1c7858 100644 --- a/drivers/media/dvb/frontends/dib0090.c +++ b/drivers/media/dvb/frontends/dib0090.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "dvb_frontend.h" @@ -196,6 +197,7 @@ struct dib0090_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[3]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; struct dib0090_fw_state { @@ -208,10 +210,18 @@ struct dib0090_fw_state { struct i2c_msg msg; u8 i2c_write_buffer[2]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg; memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); @@ -226,14 +236,24 @@ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) if (i2c_transfer(state->i2c, state->msg, 2) != 2) { printk(KERN_WARNING "DiB0090 I2C read failed\n"); - return 0; - } + ret = 0; + } else + ret = (state->i2c_read_buffer[0] << 8) + | state->i2c_read_buffer[1]; - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = reg & 0xff; state->i2c_write_buffer[1] = val >> 8; state->i2c_write_buffer[2] = val & 0xff; @@ -246,13 +266,23 @@ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) if (i2c_transfer(state->i2c, state->msg, 1) != 1) { printk(KERN_WARNING "DiB0090 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; + ret = -EREMOTEIO; + } else + ret = 0; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg; memset(&state->msg, 0, sizeof(struct i2c_msg)); @@ -262,13 +292,24 @@ static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) state->msg.len = 2; if (i2c_transfer(state->i2c, &state->msg, 1) != 1) { printk(KERN_WARNING "DiB0090 I2C read failed\n"); - return 0; - } - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = 0; + } else + ret = (state->i2c_read_buffer[0] << 8) + | state->i2c_read_buffer[1]; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = val >> 8; state->i2c_write_buffer[1] = val & 0xff; @@ -279,9 +320,12 @@ static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val) state->msg.len = 2; if (i2c_transfer(state->i2c, &state->msg, 1) != 1) { printk(KERN_WARNING "DiB0090 I2C write failed\n"); - return -EREMOTEIO; - } - return 0; + ret = -EREMOTEIO; + } else + ret = 0; + + mutex_unlock(&state->i2c_buffer_lock); + return ret; } #define HARD_RESET(state) do { if (cfg->reset) { if (cfg->sleep) cfg->sleep(fe, 0); msleep(10); cfg->reset(fe, 1); msleep(10); cfg->reset(fe, 0); msleep(10); } } while (0) @@ -2440,6 +2484,7 @@ struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapte st->config = config; st->i2c = i2c; st->fe = fe; + mutex_init(&st->i2c_buffer_lock); fe->tuner_priv = st; if (config->wbd == NULL) @@ -2471,6 +2516,7 @@ struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_ada st->config = config; st->i2c = i2c; st->fe = fe; + mutex_init(&st->i2c_buffer_lock); fe->tuner_priv = st; if (dib0090_fw_reset_digital(fe, st->config) != 0) diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c index 79cb1c20df2..dbb76d75c93 100644 --- a/drivers/media/dvb/frontends/dib7000m.c +++ b/drivers/media/dvb/frontends/dib7000m.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "dvb_frontend.h" @@ -55,6 +56,7 @@ struct dib7000m_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[4]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; enum dib7000m_power_mode { @@ -69,6 +71,13 @@ enum dib7000m_power_mode { static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = (reg >> 8) | 0x80; state->i2c_write_buffer[1] = reg & 0xff; @@ -85,11 +94,21 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2) dprintk("i2c read error on %d",reg); - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + mutex_unlock(&state->i2c_buffer_lock); + + return ret; } static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = (reg >> 8) & 0xff; state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[2] = (val >> 8) & 0xff; @@ -101,7 +120,10 @@ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) state->msg[0].buf = state->i2c_write_buffer; state->msg[0].len = 4; - return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; + ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? + -EREMOTEIO : 0); + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf) { @@ -1385,6 +1407,7 @@ struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, demod = &st->demod; demod->demodulator_priv = st; memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops)); + mutex_init(&st->i2c_buffer_lock); st->timf_default = cfg->bw->timf; diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c index 0c9f40c2a25..292bc19746b 100644 --- a/drivers/media/dvb/frontends/dib7000p.c +++ b/drivers/media/dvb/frontends/dib7000p.c @@ -10,6 +10,7 @@ #include #include #include +#include #include "dvb_math.h" #include "dvb_frontend.h" @@ -68,6 +69,7 @@ struct dib7000p_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[4]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; enum dib7000p_power_mode { @@ -81,6 +83,13 @@ static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff); static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg >> 8; state->i2c_write_buffer[1] = reg & 0xff; @@ -97,11 +106,20 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2) dprintk("i2c read error on %d", reg); - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = (reg >> 8) & 0xff; state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[2] = (val >> 8) & 0xff; @@ -113,7 +131,10 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) state->msg[0].buf = state->i2c_write_buffer; state->msg[0].len = 4; - return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; + ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? + -EREMOTEIO : 0); + mutex_unlock(&state->i2c_buffer_lock); + return ret; } static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf) @@ -1646,6 +1667,7 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau return -ENOMEM; dpst->i2c_adap = i2c; + mutex_init(&dpst->i2c_buffer_lock); for (k = no_of_demods - 1; k >= 0; k--) { dpst->cfg = cfg[k]; @@ -2324,6 +2346,7 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, demod = &st->demod; demod->demodulator_priv = st; memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops)); + mutex_init(&st->i2c_buffer_lock); dib7000p_write_word(st, 1287, 0x0003); /* sram lead in, rdy */ @@ -2333,8 +2356,9 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, st->version = dib7000p_read_word(st, 897); /* FIXME: make sure the dev.parent field is initialized, or else - request_firmware() will hit an OOPS (this should be moved somewhere - more common) */ + request_firmware() will hit an OOPS (this should be moved somewhere + more common) */ + st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent; dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr); diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c index 7d2ea112ae2..fe284d5292f 100644 --- a/drivers/media/dvb/frontends/dib8000.c +++ b/drivers/media/dvb/frontends/dib8000.c @@ -10,6 +10,8 @@ #include #include #include +#include + #include "dvb_math.h" #include "dvb_frontend.h" @@ -37,6 +39,7 @@ struct i2c_device { u8 addr; u8 *i2c_write_buffer; u8 *i2c_read_buffer; + struct mutex *i2c_buffer_lock; }; struct dib8000_state { @@ -77,6 +80,7 @@ struct dib8000_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[4]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; enum dib8000_power_mode { @@ -86,24 +90,39 @@ enum dib8000_power_mode { static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) { + u16 ret; struct i2c_msg msg[2] = { - {.addr = i2c->addr >> 1, .flags = 0, - .buf = i2c->i2c_write_buffer, .len = 2}, - {.addr = i2c->addr >> 1, .flags = I2C_M_RD, - .buf = i2c->i2c_read_buffer, .len = 2}, + {.addr = i2c->addr >> 1, .flags = 0, .len = 2}, + {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2}, }; + if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + + msg[0].buf = i2c->i2c_write_buffer; msg[0].buf[0] = reg >> 8; msg[0].buf[1] = reg & 0xff; + msg[1].buf = i2c->i2c_read_buffer; if (i2c_transfer(i2c->adap, msg, 2) != 2) dprintk("i2c read error on %d", reg); - return (msg[1].buf[0] << 8) | msg[1].buf[1]; + ret = (msg[1].buf[0] << 8) | msg[1].buf[1]; + mutex_unlock(i2c->i2c_buffer_lock); + return ret; } static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) { + u16 ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + state->i2c_write_buffer[0] = reg >> 8; state->i2c_write_buffer[1] = reg & 0xff; @@ -120,7 +139,10 @@ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2) dprintk("i2c read error on %d", reg); - return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + mutex_unlock(&state->i2c_buffer_lock); + + return ret; } static u32 dib8000_read32(struct dib8000_state *state, u16 reg) @@ -135,22 +157,35 @@ static u32 dib8000_read32(struct dib8000_state *state, u16 reg) static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) { - struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, - .buf = i2c->i2c_write_buffer, .len = 4}; + struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4}; int ret = 0; + if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + + msg.buf = i2c->i2c_write_buffer; msg.buf[0] = (reg >> 8) & 0xff; msg.buf[1] = reg & 0xff; msg.buf[2] = (val >> 8) & 0xff; msg.buf[3] = val & 0xff; ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0; + mutex_unlock(i2c->i2c_buffer_lock); return ret; } static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + state->i2c_write_buffer[0] = (reg >> 8) & 0xff; state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[2] = (val >> 8) & 0xff; @@ -162,7 +197,11 @@ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) state->msg[0].buf = state->i2c_write_buffer; state->msg[0].len = 4; - return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0; + ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? + -EREMOTEIO : 0); + mutex_unlock(&state->i2c_buffer_lock); + + return ret; } static const s16 coeff_2k_sb_1seg_dqpsk[8] = { @@ -2434,8 +2473,15 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau if (!client.i2c_read_buffer) { dprintk("%s: not enough memory", __func__); ret = -ENOMEM; - goto error_memory; + goto error_memory_read; + } + client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL); + if (!client.i2c_buffer_lock) { + dprintk("%s: not enough memory", __func__); + ret = -ENOMEM; + goto error_memory_lock; } + mutex_init(client.i2c_buffer_lock); for (k = no_of_demods - 1; k >= 0; k--) { /* designated i2c address */ @@ -2476,8 +2522,10 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau } error: + kfree(client.i2c_buffer_lock); +error_memory_lock: kfree(client.i2c_read_buffer); -error_memory: +error_memory_read: kfree(client.i2c_write_buffer); return ret; @@ -2581,6 +2629,8 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s state->i2c.addr = i2c_addr; state->i2c.i2c_write_buffer = state->i2c_write_buffer; state->i2c.i2c_read_buffer = state->i2c_read_buffer; + mutex_init(&state->i2c_buffer_lock); + state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock; state->gpio_val = cfg->gpio_val; state->gpio_dir = cfg->gpio_dir; diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c index a0855883b5c..b931074a952 100644 --- a/drivers/media/dvb/frontends/dib9000.c +++ b/drivers/media/dvb/frontends/dib9000.c @@ -38,6 +38,15 @@ struct i2c_device { #define DibInitLock(lock) mutex_init(lock) #define DibFreeLock(lock) +struct dib9000_pid_ctrl { +#define DIB9000_PID_FILTER_CTRL 0 +#define DIB9000_PID_FILTER 1 + u8 cmd; + u8 id; + u16 pid; + u8 onoff; +}; + struct dib9000_state { struct i2c_device i2c; @@ -99,6 +108,10 @@ struct dib9000_state { struct i2c_msg msg[2]; u8 i2c_write_buffer[255]; u8 i2c_read_buffer[255]; + DIB_LOCK demod_lock; + u8 get_frontend_internal; + struct dib9000_pid_ctrl pid_ctrl[10]; + s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */ }; static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1743,19 +1756,56 @@ EXPORT_SYMBOL(dib9000_set_gpio); int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) { struct dib9000_state *state = fe->demodulator_priv; - u16 val = dib9000_read_word(state, 294 + 1) & 0xffef; + u16 val; + int ret; + + if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) { + /* postpone the pid filtering cmd */ + dprintk("pid filter cmd postpone"); + state->pid_ctrl_index++; + state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL; + state->pid_ctrl[state->pid_ctrl_index].onoff = onoff; + return 0; + } + + DibAcquireLock(&state->demod_lock); + + val = dib9000_read_word(state, 294 + 1) & 0xffef; val |= (onoff & 0x1) << 4; dprintk("PID filter enabled %d", onoff); - return dib9000_write_word(state, 294 + 1, val); + ret = dib9000_write_word(state, 294 + 1, val); + DibReleaseLock(&state->demod_lock); + return ret; + } EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl); int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) { struct dib9000_state *state = fe->demodulator_priv; + int ret; + + if (state->pid_ctrl_index != -2) { + /* postpone the pid filtering cmd */ + dprintk("pid filter postpone"); + if (state->pid_ctrl_index < 9) { + state->pid_ctrl_index++; + state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER; + state->pid_ctrl[state->pid_ctrl_index].id = id; + state->pid_ctrl[state->pid_ctrl_index].pid = pid; + state->pid_ctrl[state->pid_ctrl_index].onoff = onoff; + } else + dprintk("can not add any more pid ctrl cmd"); + return 0; + } + + DibAcquireLock(&state->demod_lock); dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); - return dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0); + ret = dib9000_write_word(state, 300 + 1 + id, + onoff ? (1 << 13) | pid : 0); + DibReleaseLock(&state->demod_lock); + return ret; } EXPORT_SYMBOL(dib9000_fw_pid_filter); @@ -1778,6 +1828,7 @@ static void dib9000_release(struct dvb_frontend *demod) DibFreeLock(&state->platform.risc.mbx_lock); DibFreeLock(&state->platform.risc.mem_lock); DibFreeLock(&state->platform.risc.mem_mbx_lock); + DibFreeLock(&state->demod_lock); dibx000_exit_i2c_master(&st->i2c_master); i2c_del_adapter(&st->tuner_adap); @@ -1795,14 +1846,19 @@ static int dib9000_sleep(struct dvb_frontend *fe) { struct dib9000_state *state = fe->demodulator_priv; u8 index_frontend; - int ret; + int ret = 0; + DibAcquireLock(&state->demod_lock); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]); if (ret < 0) - return ret; + goto error; } - return dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0); + ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0); + +error: + DibReleaseLock(&state->demod_lock); + return ret; } static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune) @@ -1816,7 +1872,10 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par struct dib9000_state *state = fe->demodulator_priv; u8 index_frontend, sub_index_frontend; fe_status_t stat; - int ret; + int ret = 0; + + if (state->get_frontend_internal == 0) + DibAcquireLock(&state->demod_lock); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); @@ -1846,14 +1905,15 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par state->fe[index_frontend]->dtv_property_cache.rolloff; } } - return 0; + ret = 0; + goto return_value; } } /* get the channel from master chip */ ret = dib9000_fw_get_channel(fe, fep); if (ret != 0) - return ret; + goto return_value; /* synchronize the cache with the other frontends */ for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { @@ -1866,8 +1926,12 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP; state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff; } + ret = 0; - return 0; +return_value: + if (state->get_frontend_internal == 0) + DibReleaseLock(&state->demod_lock); + return ret; } static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state) @@ -1912,6 +1976,10 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par dprintk("dib9000: must specify bandwidth "); return 0; } + + state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */ + DibAcquireLock(&state->demod_lock); + fe->dtv_property_cache.delivery_system = SYS_DVBT; /* set the master status */ @@ -1974,13 +2042,18 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par /* check the tune result */ if (exit_condition == 1) { /* tune failed */ dprintk("tune failed"); + DibReleaseLock(&state->demod_lock); + /* tune failed; put all the pid filtering cmd to junk */ + state->pid_ctrl_index = -1; return 0; } dprintk("tune success on frontend%i", index_frontend_success); /* synchronize all the channel cache */ + state->get_frontend_internal = 1; dib9000_get_frontend(state->fe[0], fep); + state->get_frontend_internal = 0; /* retune the other frontends with the found channel */ channel_status.status = CHANNEL_STATUS_PARAMETERS_SET; @@ -2025,6 +2098,28 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par /* turn off the diversity for the last frontend */ dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0); + DibReleaseLock(&state->demod_lock); + if (state->pid_ctrl_index >= 0) { + u8 index_pid_filter_cmd; + u8 pid_ctrl_index = state->pid_ctrl_index; + + state->pid_ctrl_index = -2; + for (index_pid_filter_cmd = 0; + index_pid_filter_cmd <= pid_ctrl_index; + index_pid_filter_cmd++) { + if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER_CTRL) + dib9000_fw_pid_filter_ctrl(state->fe[0], + state->pid_ctrl[index_pid_filter_cmd].onoff); + else if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER) + dib9000_fw_pid_filter(state->fe[0], + state->pid_ctrl[index_pid_filter_cmd].id, + state->pid_ctrl[index_pid_filter_cmd].pid, + state->pid_ctrl[index_pid_filter_cmd].onoff); + } + } + /* do not postpone any more the pid filtering */ + state->pid_ctrl_index = -2; + return 0; } @@ -2041,6 +2136,7 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) u8 index_frontend; u16 lock = 0, lock_slave = 0; + DibAcquireLock(&state->demod_lock); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) lock_slave |= dib9000_read_lock(state->fe[index_frontend]); @@ -2059,6 +2155,8 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat) if ((lock & 0x0008) || (lock_slave & 0x0008)) *stat |= FE_HAS_LOCK; + DibReleaseLock(&state->demod_lock); + return 0; } @@ -2066,10 +2164,14 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) { struct dib9000_state *state = fe->demodulator_priv; u16 *c; + int ret = 0; + DibAcquireLock(&state->demod_lock); DibAcquireLock(&state->platform.risc.mem_mbx_lock); - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) - return -EIO; + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { + ret = -EIO; + goto error; + } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, state->i2c_read_buffer, 16 * 2); DibReleaseLock(&state->platform.risc.mem_mbx_lock); @@ -2077,7 +2179,10 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) c = (u16 *)state->i2c_read_buffer; *ber = c[10] << 16 | c[11]; - return 0; + +error: + DibReleaseLock(&state->demod_lock); + return ret; } static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) @@ -2086,7 +2191,9 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) u8 index_frontend; u16 *c = (u16 *)state->i2c_read_buffer; u16 val; + int ret = 0; + DibAcquireLock(&state->demod_lock); *strength = 0; for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val); @@ -2097,8 +2204,10 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) } DibAcquireLock(&state->platform.risc.mem_mbx_lock); - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) - return -EIO; + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { + ret = -EIO; + goto error; + } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); DibReleaseLock(&state->platform.risc.mem_mbx_lock); @@ -2107,7 +2216,10 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) *strength = 65535; else *strength += val; - return 0; + +error: + DibReleaseLock(&state->demod_lock); + return ret; } static u32 dib9000_get_snr(struct dvb_frontend *fe) @@ -2151,6 +2263,7 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) u8 index_frontend; u32 snr_master; + DibAcquireLock(&state->demod_lock); snr_master = dib9000_get_snr(fe); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) snr_master += dib9000_get_snr(state->fe[index_frontend]); @@ -2161,6 +2274,8 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) } else *snr = 0; + DibReleaseLock(&state->demod_lock); + return 0; } @@ -2168,15 +2283,22 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) { struct dib9000_state *state = fe->demodulator_priv; u16 *c = (u16 *)state->i2c_read_buffer; + int ret = 0; + DibAcquireLock(&state->demod_lock); DibAcquireLock(&state->platform.risc.mem_mbx_lock); - if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) - return -EIO; + if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { + ret = -EIO; + goto error; + } dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2); DibReleaseLock(&state->platform.risc.mem_mbx_lock); *unc = c[12]; - return 0; + +error: + DibReleaseLock(&state->demod_lock); + return ret; } int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr) @@ -2322,6 +2444,10 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c DibInitLock(&st->platform.risc.mbx_lock); DibInitLock(&st->platform.risc.mem_lock); DibInitLock(&st->platform.risc.mem_mbx_lock); + DibInitLock(&st->demod_lock); + st->get_frontend_internal = 0; + + st->pid_ctrl_index = -2; st->fe[0] = fe; fe->demodulator_priv = st; diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c index dc5d17a6757..774d507b66c 100644 --- a/drivers/media/dvb/frontends/dibx000_common.c +++ b/drivers/media/dvb/frontends/dibx000_common.c @@ -1,4 +1,5 @@ #include +#include #include "dibx000_common.h" @@ -10,6 +11,13 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) { + int ret; + + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + mst->i2c_write_buffer[0] = (reg >> 8) & 0xff; mst->i2c_write_buffer[1] = reg & 0xff; mst->i2c_write_buffer[2] = (val >> 8) & 0xff; @@ -21,11 +29,21 @@ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) mst->msg[0].buf = mst->i2c_write_buffer; mst->msg[0].len = 4; - return i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0; + ret = i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0; + mutex_unlock(&mst->i2c_buffer_lock); + + return ret; } static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) { + u16 ret; + + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + mst->i2c_write_buffer[0] = reg >> 8; mst->i2c_write_buffer[1] = reg & 0xff; @@ -42,7 +60,10 @@ static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2) dprintk("i2c read error on %d", reg); - return (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1]; + ret = (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1]; + mutex_unlock(&mst->i2c_buffer_lock); + + return ret; } static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst) @@ -257,6 +278,7 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) { struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); + int ret; if (num > 32) { dprintk("%s: too much I2C message to be transmitted (%i).\ @@ -264,10 +286,15 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, return -ENOMEM; } - memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); - dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7); + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + + memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); + /* open the gate */ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); mst->msg[0].addr = mst->i2c_addr; @@ -282,7 +309,11 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, mst->msg[num + 1].buf = &mst->i2c_write_buffer[4]; mst->msg[num + 1].len = 4; - return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO; + ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? + num : -EIO); + + mutex_unlock(&mst->i2c_buffer_lock); + return ret; } static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = { @@ -294,6 +325,7 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) { struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); + int ret; if (num > 32) { dprintk("%s: too much I2C message to be transmitted (%i).\ @@ -301,10 +333,14 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, return -ENOMEM; } - memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); - dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); + /* open the gate */ dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); mst->msg[0].addr = mst->i2c_addr; @@ -319,7 +355,10 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, mst->msg[num + 1].buf = &mst->i2c_write_buffer[4]; mst->msg[num + 1].len = 4; - return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO; + ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? + num : -EIO); + mutex_unlock(&mst->i2c_buffer_lock); + return ret; } static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = { @@ -390,8 +429,18 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap, int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, struct i2c_adapter *i2c_adap, u8 i2c_addr) { - u8 tx[4]; - struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 }; + int ret; + + mutex_init(&mst->i2c_buffer_lock); + if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return -EINVAL; + } + memset(mst->msg, 0, sizeof(struct i2c_msg)); + mst->msg[0].addr = i2c_addr >> 1; + mst->msg[0].flags = 0; + mst->msg[0].buf = mst->i2c_write_buffer; + mst->msg[0].len = 4; mst->device_rev = device_rev; mst->i2c_adap = i2c_adap; @@ -431,9 +480,12 @@ int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, "DiBX000: could not initialize the master i2c_adapter\n"); /* initialize the i2c-master by closing the gate */ - dibx000_i2c_gate_ctrl(mst, tx, 0, 0); + dibx000_i2c_gate_ctrl(mst, mst->i2c_write_buffer, 0, 0); + + ret = (i2c_transfer(i2c_adap, mst->msg, 1) == 1); + mutex_unlock(&mst->i2c_buffer_lock); - return i2c_transfer(i2c_adap, &m, 1) == 1; + return ret; } EXPORT_SYMBOL(dibx000_init_i2c_master); diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h index f031165c045..5e011474be4 100644 --- a/drivers/media/dvb/frontends/dibx000_common.h +++ b/drivers/media/dvb/frontends/dibx000_common.h @@ -33,6 +33,7 @@ struct dibx000_i2c_master { struct i2c_msg msg[34]; u8 i2c_write_buffer[8]; u8 i2c_read_buffer[2]; + struct mutex i2c_buffer_lock; }; extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, From 10d65fc3a3348315c2d30e19419e8db6ed486b8a Mon Sep 17 00:00:00 2001 From: Olivier Grenie Date: Mon, 1 Aug 2011 12:45:58 -0300 Subject: [PATCH 0120/4025] dib0700: protect the dib0700 buffer access commit bff469f4167fdabfe15294f375577d7eadbaa1bb upstream. This patch protects the common buffer access inside the dib0700 in order to manage concurrent access. This protection is done using mutex. Cc: Mauro Carvalho Chehab Cc: Florian Mickler Signed-off-by: Javier Marcet Signed-off-by: Olivier Grenie Signed-off-by: Patrick Boettcher [mchehab@redhat.com: dprint requires 3 arguments. Replaced by dib_info] Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb/dvb-usb/dib0700_core.c | 81 +++++++++++++++++++++--- 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c index 5eb91b4f8fd..a224e94325b 100644 --- a/drivers/media/dvb/dvb-usb/dib0700_core.c +++ b/drivers/media/dvb/dvb-usb/dib0700_core.c @@ -30,6 +30,11 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, struct dib0700_state *st = d->priv; int ret; + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, @@ -46,6 +51,7 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, if (fwtype != NULL) *fwtype = (st->buf[12] << 24) | (st->buf[13] << 16) | (st->buf[14] << 8) | st->buf[15]; + mutex_unlock(&d->usb_mutex); return ret; } @@ -108,7 +114,12 @@ int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val) { struct dib0700_state *st = d->priv; - s16 ret; + int ret; + + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } st->buf[0] = REQUEST_SET_GPIO; st->buf[1] = gpio; @@ -116,6 +127,7 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_ ret = dib0700_ctrl_wr(d, st->buf, 3); + mutex_unlock(&d->usb_mutex); return ret; } @@ -125,6 +137,11 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) int ret; if (st->fw_version >= 0x10201) { + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + st->buf[0] = REQUEST_SET_USB_XFER_LEN; st->buf[1] = (nb_ts_packets >> 8) & 0xff; st->buf[2] = nb_ts_packets & 0xff; @@ -132,6 +149,7 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets) deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets); ret = dib0700_ctrl_wr(d, st->buf, 3); + mutex_unlock(&d->usb_mutex); } else { deb_info("this firmware does not allow to change the USB xfer len\n"); ret = -EIO; @@ -208,6 +226,10 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, } else { /* Write request */ + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } st->buf[0] = REQUEST_NEW_I2C_WRITE; st->buf[1] = msg[i].addr << 1; st->buf[2] = (en_start << 7) | (en_stop << 6) | @@ -227,6 +249,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, st->buf, msg[i].len + 4, USB_CTRL_GET_TIMEOUT); + mutex_unlock(&d->usb_mutex); if (result < 0) { deb_info("i2c write error (status = %d)\n", result); break; @@ -249,6 +272,10 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, if (mutex_lock_interruptible(&d->i2c_mutex) < 0) return -EAGAIN; + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } for (i = 0; i < num; i++) { /* fill in the address */ @@ -279,6 +306,7 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap, break; } } + mutex_unlock(&d->usb_mutex); mutex_unlock(&d->i2c_mutex); return i; @@ -337,7 +365,12 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, u16 pll_loopdiv, u16 free_div, u16 dsuScaler) { struct dib0700_state *st = d->priv; - s16 ret; + int ret; + + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } st->buf[0] = REQUEST_SET_CLOCK; st->buf[1] = (en_pll << 7) | (pll_src << 6) | @@ -352,6 +385,7 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll, st->buf[9] = dsuScaler & 0xff; /* LSB */ ret = dib0700_ctrl_wr(d, st->buf, 10); + mutex_unlock(&d->usb_mutex); return ret; } @@ -360,10 +394,16 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) { struct dib0700_state *st = d->priv; u16 divider; + int ret; if (scl_kHz == 0) return -EINVAL; + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + st->buf[0] = REQUEST_SET_I2C_PARAM; divider = (u16) (30000 / scl_kHz); st->buf[1] = 0; @@ -379,7 +419,11 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz) deb_info("setting I2C speed: %04x %04x %04x (%d kHz).", (st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) | st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz); - return dib0700_ctrl_wr(d, st->buf, 8); + + ret = dib0700_ctrl_wr(d, st->buf, 8); + mutex_unlock(&d->usb_mutex); + + return ret; } @@ -515,6 +559,11 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) } } + if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + st->buf[0] = REQUEST_ENABLE_VIDEO; /* this bit gives a kind of command, * rather than enabling something or not */ @@ -548,7 +597,10 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]); - return dib0700_ctrl_wr(adap->dev, st->buf, 4); + ret = dib0700_ctrl_wr(adap->dev, st->buf, 4); + mutex_unlock(&adap->dev->usb_mutex); + + return ret; } int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) @@ -557,6 +609,11 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) struct dib0700_state *st = d->priv; int new_proto, ret; + if (mutex_lock_interruptible(&d->usb_mutex) < 0) { + deb_info("could not acquire lock"); + return 0; + } + st->buf[0] = REQUEST_SET_RC; st->buf[1] = 0; st->buf[2] = 0; @@ -567,23 +624,29 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) else if (rc_type == RC_TYPE_NEC) new_proto = 0; else if (rc_type == RC_TYPE_RC6) { - if (st->fw_version < 0x10200) - return -EINVAL; + if (st->fw_version < 0x10200) { + ret = -EINVAL; + goto out; + } new_proto = 2; - } else - return -EINVAL; + } else { + ret = -EINVAL; + goto out; + } st->buf[1] = new_proto; ret = dib0700_ctrl_wr(d, st->buf, 3); if (ret < 0) { err("ir protocol setup failed"); - return ret; + goto out; } d->props.rc.core.protocol = rc_type; +out: + mutex_unlock(&d->usb_mutex); return ret; } From 1eac959e6961083087486015d87d0209a0ae45a8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 28 Jul 2011 16:38:54 -0300 Subject: [PATCH 0121/4025] tuner_xc2028: Allow selection of the frequency adjustment code for XC3028 commit 9bed77ee2fb46b74782d0d9d14b92e9d07f3df6e upstream. This device is not using the proper demod IF. Instead of using the IF macro, it is specifying a IF frequency. This doesn't work, as xc3028 needs to load an specific SCODE for the tuner. In this case, there's no IF table for 5 MHz. Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/cx23885/cx23885-dvb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 3c315f94cc8..2b5cd2145c3 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -843,7 +843,7 @@ static int dvb_register(struct cx23885_tsport *port) static struct xc2028_ctrl ctl = { .fname = XC3028L_DEFAULT_FIRMWARE, .max_len = 64, - .demod = 5000, + .demod = XC3028_FE_DIBCOM52, /* This is true for all demods with v36 firmware? */ .type = XC2028_D2633, From b5e074a6ff4cfa090f7aa8a87f5079d19206d91c Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 31 Oct 2011 17:06:32 -0700 Subject: [PATCH 0122/4025] /proc/self/numa_maps: restore "huge" tag for hugetlb vmas commit fc360bd9cdcf875639a77f07fafec26699c546f3 upstream. The display of the "huge" tag was accidentally removed in 29ea2f698 ("mm: use walk_page_range() instead of custom page table walking code"). Reported-by: Stephen Hemminger Tested-by: Stephen Hemminger Reviewed-by: Stephen Wilson Cc: KOSAKI Motohiro Cc: Hugh Dickins Acked-by: David Rientjes Cc: Lee Schermerhorn Cc: Alexey Dobriyan Cc: Christoph Lameter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/proc/task_mmu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 5afaa58a863..c7d4ee663f1 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -1039,6 +1039,9 @@ static int show_numa_map(struct seq_file *m, void *v) seq_printf(m, " stack"); } + if (is_vm_hugetlb_page(vma)) + seq_printf(m, " huge"); + walk_page_range(vma->vm_start, vma->vm_end, &walk); if (!md->pages) From 513c4eb162aecea92e0b05a7c5e206474526eda2 Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Mon, 10 Oct 2011 11:19:23 +0400 Subject: [PATCH 0123/4025] plat-mxc: iomux-v3.h: implicitly enable pull-up/down when that's desired commit 6571534b600b8ca1936ff5630b9e0947f21faf16 upstream. To configure pads during the initialisation a set of special constants is used, e.g. #define MX25_PAD_FEC_MDIO__FEC_MDIO IOMUX_PAD(0x3c4, 0x1cc, 0x10, 0, 0, PAD_CTL_HYS | PAD_CTL_PUS_22K_UP) The problem is that no pull-up/down is getting activated unless both PAD_CTL_PUE (pull-up enable) and PAD_CTL_PKE (pull/keeper module enable) set. This is clearly stated in the i.MX25 datasheet and is confirmed by the measurements on hardware. This leads to some rather hard to understand bugs such as misdetecting an absent ethernet PHY (a real bug i had), unstable data transfer etc. This might affect mx25, mx35, mx50, mx51 and mx53 SoCs. It's reasonable to expect that if the pullup value is specified, the intention was to have it actually active, so we implicitly add the needed bits. Signed-off-by: Paul Fertser Signed-off-by: Sascha Hauer Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-mxc/include/mach/iomux-v3.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/plat-mxc/include/mach/iomux-v3.h b/arch/arm/plat-mxc/include/mach/iomux-v3.h index ebbce33097a..45099566fec 100644 --- a/arch/arm/plat-mxc/include/mach/iomux-v3.h +++ b/arch/arm/plat-mxc/include/mach/iomux-v3.h @@ -89,11 +89,11 @@ typedef u64 iomux_v3_cfg_t; #define PAD_CTL_HYS (1 << 8) #define PAD_CTL_PKE (1 << 7) -#define PAD_CTL_PUE (1 << 6) -#define PAD_CTL_PUS_100K_DOWN (0 << 4) -#define PAD_CTL_PUS_47K_UP (1 << 4) -#define PAD_CTL_PUS_100K_UP (2 << 4) -#define PAD_CTL_PUS_22K_UP (3 << 4) +#define PAD_CTL_PUE (1 << 6 | PAD_CTL_PKE) +#define PAD_CTL_PUS_100K_DOWN (0 << 4 | PAD_CTL_PUE) +#define PAD_CTL_PUS_47K_UP (1 << 4 | PAD_CTL_PUE) +#define PAD_CTL_PUS_100K_UP (2 << 4 | PAD_CTL_PUE) +#define PAD_CTL_PUS_22K_UP (3 << 4 | PAD_CTL_PUE) #define PAD_CTL_ODE (1 << 3) From ad417042d59a26bedf600ab162b20b79fdcd1fa1 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 12 Aug 2011 13:54:42 +0200 Subject: [PATCH 0124/4025] ARM: mach-ux500: unlock I&D l2x0 caches before init commit 1bf6d2c1bb23533af6930581cc39b74685bc29de upstream. Apparently U8500 U-Boot versions may leave the l2x0 locked down before executing the kernel. Make sure we unlock it before we initialize the l2x0. This fixes a performance problem reported by Jan Rinze. The l2x0 core has been modified to unlock the l2x0 by default, but it will not touch the locking registers if the l2x0 was already enabled, as on the ux500, so we need this quirk to make sure it is properly turned off. Cc: Srinidhi Kasagar Cc: Rabin Vincent Cc: Adrian Bunk Reported-by: Jan Rinze Tested-by: Robert Marklund Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-ux500/cpu.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c index 1da23bb87c1..8aa104a4711 100644 --- a/arch/arm/mach-ux500/cpu.c +++ b/arch/arm/mach-ux500/cpu.c @@ -99,7 +99,27 @@ static void ux500_l2x0_inv_all(void) ux500_cache_sync(); } -static int ux500_l2x0_init(void) +static int __init ux500_l2x0_unlock(void) +{ + int i; + + /* + * Unlock Data and Instruction Lock if locked. Ux500 U-Boot versions + * apparently locks both caches before jumping to the kernel. The + * l2x0 core will not touch the unlock registers if the l2x0 is + * already enabled, so we do it right here instead. The PL310 has + * 8 sets of registers, one per possible CPU. + */ + for (i = 0; i < 8; i++) { + writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE + + i * L2X0_LOCKDOWN_STRIDE); + writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE + + i * L2X0_LOCKDOWN_STRIDE); + } + return 0; +} + +static int __init ux500_l2x0_init(void) { if (cpu_is_u5500()) l2x0_base = __io_address(U5500_L2CC_BASE); @@ -108,6 +128,9 @@ static int ux500_l2x0_init(void) else ux500_unknown_soc(); + /* Unlock before init */ + ux500_l2x0_unlock(); + /* 64KB way size, 8 way associativity, force WA */ l2x0_init(l2x0_base, 0x3e060000, 0xc0000fff); From 38af8ddb4b8877c0b90f8413a20517ba245c4d0b Mon Sep 17 00:00:00 2001 From: Mitsuo Hayasaka Date: Mon, 31 Oct 2011 17:08:13 -0700 Subject: [PATCH 0125/4025] mm: avoid null pointer access in vm_struct via /proc/vmallocinfo commit f5252e009d5b87071a919221e4f6624184005368 upstream. The /proc/vmallocinfo shows information about vmalloc allocations in vmlist that is a linklist of vm_struct. It, however, may access pages field of vm_struct where a page was not allocated. This results in a null pointer access and leads to a kernel panic. Why this happens: In __vmalloc_node_range() called from vmalloc(), newly allocated vm_struct is added to vmlist at __get_vm_area_node() and then, some fields of vm_struct such as nr_pages and pages are set at __vmalloc_area_node(). In other words, it is added to vmlist before it is fully initialized. At the same time, when the /proc/vmallocinfo is read, it accesses the pages field of vm_struct according to the nr_pages field at show_numa_info(). Thus, a null pointer access happens. The patch adds the newly allocated vm_struct to the vmlist *after* it is fully initialized. So, it can avoid accessing the pages field with unallocated page when show_numa_info() is called. Signed-off-by: Mitsuo Hayasaka Cc: Andrew Morton Cc: David Rientjes Cc: Namhyung Kim Cc: "Paul E. McKenney" Cc: Jeremy Fitzhardinge Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/vmalloc.h | 1 + mm/vmalloc.c | 65 ++++++++++++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 9332e52ea8c..687fb11e201 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -13,6 +13,7 @@ struct vm_area_struct; /* vma defining user mapping in mm_types.h */ #define VM_MAP 0x00000004 /* vmap()ed pages */ #define VM_USERMAP 0x00000008 /* suitable for remap_vmalloc_range */ #define VM_VPAGES 0x00000010 /* buffer for pages was vmalloc'ed */ +#define VM_UNLIST 0x00000020 /* vm_struct is not listed in vmlist */ /* bits [20..32] reserved for arch specific ioremap internals */ /* diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 45ece8967e4..65d5fd2453e 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -1267,18 +1267,22 @@ EXPORT_SYMBOL_GPL(map_vm_area); DEFINE_RWLOCK(vmlist_lock); struct vm_struct *vmlist; -static void insert_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va, +static void setup_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va, unsigned long flags, void *caller) { - struct vm_struct *tmp, **p; - vm->flags = flags; vm->addr = (void *)va->va_start; vm->size = va->va_end - va->va_start; vm->caller = caller; va->private = vm; va->flags |= VM_VM_AREA; +} + +static void insert_vmalloc_vmlist(struct vm_struct *vm) +{ + struct vm_struct *tmp, **p; + vm->flags &= ~VM_UNLIST; write_lock(&vmlist_lock); for (p = &vmlist; (tmp = *p) != NULL; p = &tmp->next) { if (tmp->addr >= vm->addr) @@ -1289,6 +1293,13 @@ static void insert_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va, write_unlock(&vmlist_lock); } +static void insert_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va, + unsigned long flags, void *caller) +{ + setup_vmalloc_vm(vm, va, flags, caller); + insert_vmalloc_vmlist(vm); +} + static struct vm_struct *__get_vm_area_node(unsigned long size, unsigned long align, unsigned long flags, unsigned long start, unsigned long end, int node, gfp_t gfp_mask, void *caller) @@ -1327,7 +1338,18 @@ static struct vm_struct *__get_vm_area_node(unsigned long size, return NULL; } - insert_vmalloc_vm(area, va, flags, caller); + /* + * When this function is called from __vmalloc_node_range, + * we do not add vm_struct to vmlist here to avoid + * accessing uninitialized members of vm_struct such as + * pages and nr_pages fields. They will be set later. + * To distinguish it from others, we use a VM_UNLIST flag. + */ + if (flags & VM_UNLIST) + setup_vmalloc_vm(area, va, flags, caller); + else + insert_vmalloc_vm(area, va, flags, caller); + return area; } @@ -1395,17 +1417,20 @@ struct vm_struct *remove_vm_area(const void *addr) va = find_vmap_area((unsigned long)addr); if (va && va->flags & VM_VM_AREA) { struct vm_struct *vm = va->private; - struct vm_struct *tmp, **p; - /* - * remove from list and disallow access to this vm_struct - * before unmap. (address range confliction is maintained by - * vmap.) - */ - write_lock(&vmlist_lock); - for (p = &vmlist; (tmp = *p) != vm; p = &tmp->next) - ; - *p = tmp->next; - write_unlock(&vmlist_lock); + + if (!(vm->flags & VM_UNLIST)) { + struct vm_struct *tmp, **p; + /* + * remove from list and disallow access to + * this vm_struct before unmap. (address range + * confliction is maintained by vmap.) + */ + write_lock(&vmlist_lock); + for (p = &vmlist; (tmp = *p) != vm; p = &tmp->next) + ; + *p = tmp->next; + write_unlock(&vmlist_lock); + } vmap_debug_free_range(va->va_start, va->va_end); free_unmap_vmap_area(va); @@ -1616,14 +1641,20 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align, if (!size || (size >> PAGE_SHIFT) > totalram_pages) return NULL; - area = __get_vm_area_node(size, align, VM_ALLOC, start, end, node, - gfp_mask, caller); + area = __get_vm_area_node(size, align, VM_ALLOC | VM_UNLIST, + start, end, node, gfp_mask, caller); if (!area) return NULL; addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller); + /* + * In this function, newly allocated vm_struct is not added + * to vmlist at __get_vm_area_node(). so, it is added here. + */ + insert_vmalloc_vmlist(area); + /* * A ref_count = 3 is needed because the vm_struct and vmap_area * structures allocated in the __get_vm_area_node() function contain From 73e2fc5d34007574d25d00e7088bbd42e988bb3e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 14 Oct 2011 15:26:20 +0200 Subject: [PATCH 0126/4025] ALSA: hda - Fix ADC input-amp handling for Cx20549 codec commit 6b45214277bec2193ad3ccb8d7aa6100b5a0f1a9 upstream. It seems that Conexant CX20549 chip handle only a single input-amp even though the audio-input widget has multiple sources. This has been never clear, and I implemented in the current way based on the debug information I got at the early time -- the device reacts individual input-amp values for different sources. This is true for another Conexant codec, but it's not applied to CX20549 actually. This patch changes the auto-parser code to handle a single input-amp per audio-in widget for CX20549. After applying this, you'll see only a single "Capture" volume control instead of separate "Mic" or "Line" captures when the device is set up to use a single ADC. We haven't tested 20551 and 20561 codecs yet. If these show the similar behavior like 20549, they need to set spec->single_adc_amp=1, too. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_conexant.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index cf1fa36728b..3c2381ca372 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -136,6 +136,7 @@ struct conexant_spec { unsigned int thinkpad:1; unsigned int hp_laptop:1; unsigned int asus:1; + unsigned int single_adc_amp:1; unsigned int adc_switching:1; @@ -4205,6 +4206,8 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, int idx = get_input_connection(codec, adc_nid, nid); if (idx < 0) continue; + if (spec->single_adc_amp) + idx = 0; return cx_auto_add_volume_idx(codec, label, pfx, cidx, adc_nid, HDA_INPUT, idx); } @@ -4245,14 +4248,21 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) struct hda_input_mux *imux = &spec->private_imux; const char *prev_label; int input_conn[HDA_MAX_NUM_INPUTS]; - int i, err, cidx; + int i, j, err, cidx; int multi_connection; + if (!imux->num_items) + return 0; + multi_connection = 0; for (i = 0; i < imux->num_items; i++) { cidx = get_input_connection(codec, spec->imux_info[i].adc, spec->imux_info[i].pin); - input_conn[i] = (spec->imux_info[i].adc << 8) | cidx; + if (cidx < 0) + continue; + input_conn[i] = spec->imux_info[i].adc; + if (!spec->single_adc_amp) + input_conn[i] |= cidx << 8; if (i > 0 && input_conn[i] != input_conn[0]) multi_connection = 1; } @@ -4281,6 +4291,15 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) err = cx_auto_add_capture_volume(codec, nid, "Capture", "", cidx); } else { + bool dup_found = false; + for (j = 0; j < i; j++) { + if (input_conn[j] == input_conn[i]) { + dup_found = true; + break; + } + } + if (dup_found) + continue; err = cx_auto_add_capture_volume(codec, nid, label, " Capture", cidx); } @@ -4357,6 +4376,13 @@ static int patch_conexant_auto(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; codec->pin_amp_workaround = 1; + + switch (codec->vendor_id) { + case 0x14f15045: + spec->single_adc_amp = 1; + break; + } + err = cx_auto_search_adcs(codec); if (err < 0) return err; From 5f0d9e03e7e0792fbd36ba9fb9859f0ef7956a20 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 2 Nov 2011 13:17:27 +0100 Subject: [PATCH 0127/4025] um: fix ubd cow size commit 8535639810e578960233ad39def3ac2157b0c3ec upstream. ubd_file_size() cannot use ubd_dev->cow.file because at this time ubd_dev->cow.file is not initialized. Therefore, ubd_file_size() will always report a wrong disk size when COW files are used. Reading from /dev/ubd* would crash the kernel. We have to read the correct disk size from the COW file's backing file. Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- arch/um/drivers/ubd_kern.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 620f5b70957..0491e40d696 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c @@ -513,8 +513,37 @@ __uml_exitcall(kill_io_thread); static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out) { char *file; + int fd; + int err; + + __u32 version; + __u32 align; + char *backing_file; + time_t mtime; + unsigned long long size; + int sector_size; + int bitmap_offset; + + if (ubd_dev->file && ubd_dev->cow.file) { + file = ubd_dev->cow.file; + + goto out; + } - file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file; + fd = os_open_file(ubd_dev->file, global_openflags, 0); + if (fd < 0) + return fd; + + err = read_cow_header(file_reader, &fd, &version, &backing_file, \ + &mtime, &size, §or_size, &align, &bitmap_offset); + os_close_file(fd); + + if(err == -EINVAL) + file = ubd_dev->file; + else + file = backing_file; + +out: return os_file_size(file, size_out); } From b0917c31699319f0b0ce0747e26bd66e8ed83491 Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Wed, 2 Nov 2011 09:44:39 +0100 Subject: [PATCH 0128/4025] readlinkat: ensure we return ENOENT for the empty pathname for normal lookups commit 1fa1e7f615f4d3ae436fa319af6e4eebdd4026a8 upstream. Since the commit below which added O_PATH support to the *at() calls, the error return for readlink/readlinkat for the empty pathname has switched from ENOENT to EINVAL: commit 65cfc6722361570bfe255698d9cd4dccaf47570d Author: Al Viro Date: Sun Mar 13 15:56:26 2011 -0400 readlinkat(), fchownat() and fstatat() with empty relative pathnames This is both unexpected for userspace and makes readlink/readlinkat inconsistant with all other interfaces; and inconsistant with our stated return for these pathnames. As the readlinkat call does not have a flags parameter we cannot use the AT_EMPTY_PATH approach used in the other calls. Therefore expose whether the original path is infact entry via a new user_path_at_empty() path lookup function. Use this to determine whether to default to EINVAL or ENOENT for failures. Addresses http://bugs.launchpad.net/bugs/817187 [akpm@linux-foundation.org: remove unused getname_flags()] Signed-off-by: Andy Whitcroft Cc: Christoph Hellwig Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman --- fs/namei.c | 18 +++++++++++++----- fs/stat.c | 5 +++-- include/linux/namei.h | 1 + 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index b456c7a2e6b..7bab4add8a1 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -136,7 +136,7 @@ static int do_getname(const char __user *filename, char *page) return retval; } -static char *getname_flags(const char __user * filename, int flags) +static char *getname_flags(const char __user *filename, int flags, int *empty) { char *tmp, *result; @@ -147,6 +147,8 @@ static char *getname_flags(const char __user * filename, int flags) result = tmp; if (retval < 0) { + if (retval == -ENOENT && empty) + *empty = 1; if (retval != -ENOENT || !(flags & LOOKUP_EMPTY)) { __putname(tmp); result = ERR_PTR(retval); @@ -159,7 +161,7 @@ static char *getname_flags(const char __user * filename, int flags) char *getname(const char __user * filename) { - return getname_flags(filename, 0); + return getname_flags(filename, 0, 0); } #ifdef CONFIG_AUDITSYSCALL @@ -1747,11 +1749,11 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) return __lookup_hash(&this, base, NULL); } -int user_path_at(int dfd, const char __user *name, unsigned flags, - struct path *path) +int user_path_at_empty(int dfd, const char __user *name, unsigned flags, + struct path *path, int *empty) { struct nameidata nd; - char *tmp = getname_flags(name, flags); + char *tmp = getname_flags(name, flags, empty); int err = PTR_ERR(tmp); if (!IS_ERR(tmp)) { @@ -1765,6 +1767,12 @@ int user_path_at(int dfd, const char __user *name, unsigned flags, return err; } +int user_path_at(int dfd, const char __user *name, unsigned flags, + struct path *path) +{ + return user_path_at_empty(dfd, name, flags, path, 0); +} + static int user_path_parent(int dfd, const char __user *path, struct nameidata *nd, char **name) { diff --git a/fs/stat.c b/fs/stat.c index 961039121cb..02a606141b8 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -296,15 +296,16 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname, { struct path path; int error; + int empty = 0; if (bufsiz <= 0) return -EINVAL; - error = user_path_at(dfd, pathname, LOOKUP_EMPTY, &path); + error = user_path_at_empty(dfd, pathname, LOOKUP_EMPTY, &path, &empty); if (!error) { struct inode *inode = path.dentry->d_inode; - error = -EINVAL; + error = empty ? -ENOENT : -EINVAL; if (inode->i_op->readlink) { error = security_inode_readlink(path.dentry); if (!error) { diff --git a/include/linux/namei.h b/include/linux/namei.h index eba45ea1029..549b7d290d1 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -67,6 +67,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; #define LOOKUP_EMPTY 0x4000 extern int user_path_at(int, const char __user *, unsigned, struct path *); +extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty); #define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path) #define user_lpath(name, path) user_path_at(AT_FDCWD, name, 0, path) From f537ffabb3ed687da15ec46d72c839971b142d0a Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 25 Oct 2011 13:59:45 +0200 Subject: [PATCH 0129/4025] VFS: Fix automount for negative autofs dentries commit 5a30d8a2b8ddd5102c440c7e5a7c8e1fd729c818 upstream. [ backport for 3.0.x: LOOKUP_PARENT => LOOKUP_CONTINUE by Chuck Ebbert ] Autofs may set the DCACHE_NEED_AUTOMOUNT flag on negative dentries. These need attention from the automounter daemon regardless of the LOOKUP_FOLLOW flag. Signed-off-by: David Howells Acked-by: Ian Kent Signed-off-by: Al Viro Cc: Chuck Ebbert Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/namei.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 7bab4add8a1..80e239d685c 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -781,19 +781,25 @@ static int follow_automount(struct path *path, unsigned flags, if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_CONTINUE)) return -EISDIR; /* we actually want to stop here */ - /* We want to mount if someone is trying to open/create a file of any - * type under the mountpoint, wants to traverse through the mountpoint - * or wants to open the mounted directory. - * + /* * We don't want to mount if someone's just doing a stat and they've * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and * appended a '/' to the name. */ - if (!(flags & LOOKUP_FOLLOW) && - !(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY | - LOOKUP_OPEN | LOOKUP_CREATE))) - return -EISDIR; - + if (!(flags & LOOKUP_FOLLOW)) { + /* We do, however, want to mount if someone wants to open or + * create a file of any type under the mountpoint, wants to + * traverse through the mountpoint or wants to open the mounted + * directory. + * Also, autofs may mark negative dentries as being automount + * points. These will need the attentions of the daemon to + * instantiate them before they can be used. + */ + if (!(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY | + LOOKUP_OPEN | LOOKUP_CREATE)) && + path->dentry->d_inode) + return -EISDIR; + } current->total_link_count++; if (current->total_link_count >= 40) return -ELOOP; From def3f17094d20fa85d17ff11dea54a6c6bfb3f8c Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 25 Oct 2011 13:59:46 +0200 Subject: [PATCH 0130/4025] vfs: automount should ignore LOOKUP_FOLLOW commit 0ec26fd0698285b31248e34bf1abb022c00f23d6 upstream. Prior to 2.6.38 automount would not trigger on either stat(2) or lstat(2) on the automount point. After 2.6.38, with the introduction of the ->d_automount() infrastructure, stat(2) and others would start triggering automount while lstat(2), etc. still would not. This is a regression and a userspace ABI change. Problem originally reported here: http://thread.gmane.org/gmane.linux.kernel.autofs/6098 It appears that there was an attempt at fixing various userspace tools to not trigger the automount. But since the stat system call is rather common it is impossible to "fix" all userspace. This patch reverts the original behavior, which is to not trigger on stat(2) and other symlink following syscalls. [ It's not really clear what the right behavior is. Apparently Solaris does the "automount on stat, leave alone on lstat". And some programs can get unhappy when "stat+open+fstat" ends up giving a different result from the fstat than from the initial stat. But the change in 2.6.38 resulted in problems for some people, so we're going back to old behavior. Maybe we can re-visit this discussion at some future date - Linus ] Reported-by: Leonardo Chiquitto Acked-by: Ian Kent Cc: David Howells Signed-off-by: Linus Torvalds Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/namei.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 80e239d685c..fc12ad53ecd 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -781,25 +781,22 @@ static int follow_automount(struct path *path, unsigned flags, if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_CONTINUE)) return -EISDIR; /* we actually want to stop here */ - /* - * We don't want to mount if someone's just doing a stat and they've - * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and - * appended a '/' to the name. + /* We don't want to mount if someone's just doing a stat - + * unless they're stat'ing a directory and appended a '/' to + * the name. + * + * We do, however, want to mount if someone wants to open or + * create a file of any type under the mountpoint, wants to + * traverse through the mountpoint or wants to open the + * mounted directory. Also, autofs may mark negative dentries + * as being automount points. These will need the attentions + * of the daemon to instantiate them before they can be used. */ - if (!(flags & LOOKUP_FOLLOW)) { - /* We do, however, want to mount if someone wants to open or - * create a file of any type under the mountpoint, wants to - * traverse through the mountpoint or wants to open the mounted - * directory. - * Also, autofs may mark negative dentries as being automount - * points. These will need the attentions of the daemon to - * instantiate them before they can be used. - */ - if (!(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY | - LOOKUP_OPEN | LOOKUP_CREATE)) && - path->dentry->d_inode) - return -EISDIR; - } + if (!(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY | + LOOKUP_OPEN | LOOKUP_CREATE)) && + path->dentry->d_inode) + return -EISDIR; + current->total_link_count++; if (current->total_link_count >= 40) return -ELOOP; From 6c36547293e6c46fe5df46e5e1b9ce9babb9eb37 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 25 Oct 2011 13:59:47 +0200 Subject: [PATCH 0131/4025] VFS: Fix the remaining automounter semantics regressions commit 815d405ceff0d6964683f033e18b9b23a88fba87 upstream. The concensus seems to be that system calls such as stat() etc should not trigger an automount. Neither should the l* versions. This patch therefore adds a LOOKUP_AUTOMOUNT flag to tag those lookups that _should_ trigger an automount on the last path element. Signed-off-by: Trond Myklebust [ Edited to leave out the cases that are already covered by LOOKUP_OPEN, LOOKUP_DIRECTORY and LOOKUP_CREATE - all of which also fundamentally force automounting for their own reasons - Linus ] Signed-off-by: Linus Torvalds Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/namespace.c | 2 +- fs/nfs/super.c | 2 +- fs/quota/quota.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 304a55d0aa8..537dd96bea0 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1758,7 +1758,7 @@ static int do_loopback(struct path *path, char *old_name, return err; if (!old_name || !*old_name) return -EINVAL; - err = kern_path(old_name, LOOKUP_FOLLOW, &old_path); + err = kern_path(old_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path); if (err) return err; diff --git a/fs/nfs/super.c b/fs/nfs/super.c index ce40e5c568b..858d31be29c 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -2793,7 +2793,7 @@ static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, goto out_put_mnt_ns; ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt, - export_path, LOOKUP_FOLLOW, nd); + export_path, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, nd); nfs_referral_loop_unprotect(); put_mnt_ns(ns_private); diff --git a/fs/quota/quota.c b/fs/quota/quota.c index b34bdb25490..10b6be3ca28 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -355,7 +355,7 @@ SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special, * resolution (think about autofs) and thus deadlocks could arise. */ if (cmds == Q_QUOTAON) { - ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW, &path); + ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path); if (ret) pathp = ERR_PTR(ret); else From eb4b2df8f20d4479eceeb9bc51695caaa7bcd229 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 25 Oct 2011 13:59:48 +0200 Subject: [PATCH 0132/4025] vfs pathname lookup: Add LOOKUP_AUTOMOUNT flag Since we've now turned around and made LOOKUP_FOLLOW *not* force an automount, we want to add the ability to force an automount event on lookup even if we don't happen to have one of the other flags that force it implicitly (LOOKUP_OPEN, LOOKUP_DIRECTORY, LOOKUP_PARENT..) Most cases will never want to use this, since you'd normally want to delay automounting as long as possible, which usually implies LOOKUP_OPEN (when we open a file or directory, we really cannot avoid the automount any more). But Trond argued sufficiently forcefully that at a minimum bind mounting a file and quotactl will want to force the automount lookup. Some other cases (like nfs_follow_remote_path()) could use it too, although LOOKUP_DIRECTORY would work there as well. This commit just adds the flag and logic, no users yet, though. It also doesn't actually touch the LOOKUP_NO_AUTOMOUNT flag that is related, and was made irrelevant by the same change that made us not follow on LOOKUP_FOLLOW. Cc: Trond Myklebust Cc: Ian Kent Cc: Jeff Layton Cc: Miklos Szeredi Cc: David Howells Cc: Al Viro Signed-off-by: Linus Torvalds Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/namei.c | 2 +- include/linux/namei.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/namei.c b/fs/namei.c index fc12ad53ecd..49472a1b79e 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -793,7 +793,7 @@ static int follow_automount(struct path *path, unsigned flags, * of the daemon to instantiate them before they can be used. */ if (!(flags & (LOOKUP_CONTINUE | LOOKUP_DIRECTORY | - LOOKUP_OPEN | LOOKUP_CREATE)) && + LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_AUTOMOUNT)) && path->dentry->d_inode) return -EISDIR; diff --git a/include/linux/namei.h b/include/linux/namei.h index 549b7d290d1..82ab16b8cf9 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -49,6 +49,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; #define LOOKUP_FOLLOW 0x0001 #define LOOKUP_DIRECTORY 0x0002 #define LOOKUP_CONTINUE 0x0004 +#define LOOKUP_AUTOMOUNT 0x0008 #define LOOKUP_PARENT 0x0010 #define LOOKUP_REVAL 0x0020 From 43742b14ffbe87453e96f4411389445fc707df57 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Mon, 26 Sep 2011 19:06:32 +0200 Subject: [PATCH 0133/4025] ptrace: don't clear GROUP_STOP_SIGMASK on double-stop [This does not correspond to any specific patch in the upstream tree as it was fixed accidentally by rewriting the code in the 3.1 release] https://bugzilla.redhat.com/show_bug.cgi?id=740121 1. Luke Macken triggered WARN_ON(!(group_stop & GROUP_STOP_SIGMASK)) in do_signal_stop(). This is because do_signal_stop() clears GROUP_STOP_SIGMASK part unconditionally but doesn't update it if task_is_stopped(). 2. Looking at this problem I noticed that WARN_ON_ONCE(!ptrace) is not right, a stopped-but-resumed tracee can clone the untraced thread in the SIGNAL_STOP_STOPPED group, the new thread can start another group-stop. Remove this warning, we need more fixes to make it true. Reported-by: Luke Macken Signed-off-by: Oleg Nesterov Signed-off-by: Greg Kroah-Hartman --- kernel/signal.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kernel/signal.c b/kernel/signal.c index 415d85d6f6c..43fee1cf50d 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1894,21 +1894,19 @@ static int do_signal_stop(int signr) */ if (!(sig->flags & SIGNAL_STOP_STOPPED)) sig->group_exit_code = signr; - else - WARN_ON_ONCE(!task_ptrace(current)); current->group_stop &= ~GROUP_STOP_SIGMASK; current->group_stop |= signr | gstop; sig->group_stop_count = 1; for (t = next_thread(current); t != current; t = next_thread(t)) { - t->group_stop &= ~GROUP_STOP_SIGMASK; /* * Setting state to TASK_STOPPED for a group * stop is always done with the siglock held, * so this check has no races. */ if (!(t->flags & PF_EXITING) && !task_is_stopped(t)) { + t->group_stop &= ~GROUP_STOP_SIGMASK; t->group_stop |= signr | gstop; sig->group_stop_count++; signal_wake_up(t, 0); From 6c3ad7aee6e6d62169948d09f2b4a1279d253cbe Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Wed, 24 Aug 2011 13:14:22 -0300 Subject: [PATCH 0134/4025] jsm: remove buggy write queue commit 9d898966c4a07e4a5092215b5a2829d0ef02baa2 upstream. jsm uses a write queue that copies from uart_core circular buffer. This copying however has some bugs, like not wrapping the head counter. Since this write queue is also a circular buffer, the consumer function is ready to use the uart_core circular buffer directly. This buggy copying function was making some bytes be dropped when transmitting to a raw tty, doing something like this. [root@hostname ~]$ cat /dev/ttyn1 > cascardo/dump & [1] 2658 [root@hostname ~]$ cat /proc/tty/drivers > /dev/ttyn0 [root@hostname ~]$ cat /proc/tty/drivers /dev/tty /dev/tty 5 0 system:/dev/tty /dev/console /dev/console 5 1 system:console /dev/ptmx /dev/ptmx 5 2 system /dev/vc/0 /dev/vc/0 4 0 system:vtmaster jsm /dev/ttyn 250 0-31 serial serial /dev/ttyS 4 64-95 serial hvc /dev/hvc 229 0-7 system pty_slave /dev/pts 136 0-1048575 pty:slave pty_master /dev/ptm 128 0-1048575 pty:master unknown /dev/tty 4 1-63 console [root@hostname ~]$ cat cascardo/dump /dev/tty /dev/tty 5 0 system:/dev/tty /dev/console /dev/console 5 1 system:console /dev/ptmx /dev/ptmx 5 2 system /dev/vc/0 /dev/vc/0 4 0 system:vtmaste[root@hostname ~]$ This patch drops the driver write queue entirely, using the circular buffer from uart_core only. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/jsm/jsm.h | 7 --- drivers/tty/serial/jsm/jsm_driver.c | 1 - drivers/tty/serial/jsm/jsm_neo.c | 29 ++++----- drivers/tty/serial/jsm/jsm_tty.c | 94 ++++------------------------- 4 files changed, 28 insertions(+), 103 deletions(-) diff --git a/drivers/tty/serial/jsm/jsm.h b/drivers/tty/serial/jsm/jsm.h index b704c8ce0d7..5b837e749c1 100644 --- a/drivers/tty/serial/jsm/jsm.h +++ b/drivers/tty/serial/jsm/jsm.h @@ -183,10 +183,8 @@ struct jsm_board /* Our Read/Error/Write queue sizes */ #define RQUEUEMASK 0x1FFF /* 8 K - 1 */ #define EQUEUEMASK 0x1FFF /* 8 K - 1 */ -#define WQUEUEMASK 0x0FFF /* 4 K - 1 */ #define RQUEUESIZE (RQUEUEMASK + 1) #define EQUEUESIZE RQUEUESIZE -#define WQUEUESIZE (WQUEUEMASK + 1) /************************************************************************ @@ -226,10 +224,6 @@ struct jsm_channel { u16 ch_e_head; /* Head location of the error queue */ u16 ch_e_tail; /* Tail location of the error queue */ - u8 *ch_wqueue; /* Our write queue buffer - malloc'ed */ - u16 ch_w_head; /* Head location of the write queue */ - u16 ch_w_tail; /* Tail location of the write queue */ - u64 ch_rxcount; /* total of data received so far */ u64 ch_txcount; /* total of data transmitted so far */ @@ -378,7 +372,6 @@ extern int jsm_debug; * Prototypes for non-static functions used in more than one module * *************************************************************************/ -int jsm_tty_write(struct uart_port *port); int jsm_tty_init(struct jsm_board *); int jsm_uart_port_init(struct jsm_board *); int jsm_remove_uart_port(struct jsm_board *); diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c index 96da17868cf..2aaafa9c58a 100644 --- a/drivers/tty/serial/jsm/jsm_driver.c +++ b/drivers/tty/serial/jsm/jsm_driver.c @@ -211,7 +211,6 @@ static void __devexit jsm_remove_one(struct pci_dev *pdev) if (brd->channels[i]) { kfree(brd->channels[i]->ch_rqueue); kfree(brd->channels[i]->ch_equeue); - kfree(brd->channels[i]->ch_wqueue); kfree(brd->channels[i]); } } diff --git a/drivers/tty/serial/jsm/jsm_neo.c b/drivers/tty/serial/jsm/jsm_neo.c index 4538c3e3646..bd6e84699e1 100644 --- a/drivers/tty/serial/jsm/jsm_neo.c +++ b/drivers/tty/serial/jsm/jsm_neo.c @@ -496,12 +496,15 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) int s; int qlen; u32 len_written = 0; + struct circ_buf *circ; if (!ch) return; + circ = &ch->uart_port.state->xmit; + /* No data to write to the UART */ - if (ch->ch_w_tail == ch->ch_w_head) + if (uart_circ_empty(circ)) return; /* If port is "stopped", don't send any data to the UART */ @@ -517,11 +520,10 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) if (ch->ch_cached_lsr & UART_LSR_THRE) { ch->ch_cached_lsr &= ~(UART_LSR_THRE); - writeb(ch->ch_wqueue[ch->ch_w_tail], &ch->ch_neo_uart->txrx); + writeb(circ->buf[circ->tail], &ch->ch_neo_uart->txrx); jsm_printk(WRITE, INFO, &ch->ch_bd->pci_dev, - "Tx data: %x\n", ch->ch_wqueue[ch->ch_w_head]); - ch->ch_w_tail++; - ch->ch_w_tail &= WQUEUEMASK; + "Tx data: %x\n", circ->buf[circ->head]); + circ->tail = (circ->tail + 1) & (UART_XMIT_SIZE - 1); ch->ch_txcount++; } return; @@ -536,36 +538,36 @@ static void neo_copy_data_from_queue_to_uart(struct jsm_channel *ch) n = UART_17158_TX_FIFOSIZE - ch->ch_t_tlevel; /* cache head and tail of queue */ - head = ch->ch_w_head & WQUEUEMASK; - tail = ch->ch_w_tail & WQUEUEMASK; - qlen = (head - tail) & WQUEUEMASK; + head = circ->head & (UART_XMIT_SIZE - 1); + tail = circ->tail & (UART_XMIT_SIZE - 1); + qlen = uart_circ_chars_pending(circ); /* Find minimum of the FIFO space, versus queue length */ n = min(n, qlen); while (n > 0) { - s = ((head >= tail) ? head : WQUEUESIZE) - tail; + s = ((head >= tail) ? head : UART_XMIT_SIZE) - tail; s = min(s, n); if (s <= 0) break; - memcpy_toio(&ch->ch_neo_uart->txrxburst, ch->ch_wqueue + tail, s); + memcpy_toio(&ch->ch_neo_uart->txrxburst, circ->buf + tail, s); /* Add and flip queue if needed */ - tail = (tail + s) & WQUEUEMASK; + tail = (tail + s) & (UART_XMIT_SIZE - 1); n -= s; ch->ch_txcount += s; len_written += s; } /* Update the final tail */ - ch->ch_w_tail = tail & WQUEUEMASK; + circ->tail = tail & (UART_XMIT_SIZE - 1); if (len_written >= ch->ch_t_tlevel) ch->ch_flags &= ~(CH_TX_FIFO_EMPTY | CH_TX_FIFO_LWM); - if (!jsm_tty_write(&ch->uart_port)) + if (uart_circ_empty(circ)) uart_write_wakeup(&ch->uart_port); } @@ -946,7 +948,6 @@ static void neo_param(struct jsm_channel *ch) if ((ch->ch_c_cflag & (CBAUD)) == 0) { ch->ch_r_head = ch->ch_r_tail = 0; ch->ch_e_head = ch->ch_e_tail = 0; - ch->ch_w_head = ch->ch_w_tail = 0; neo_flush_uart_write(ch); neo_flush_uart_read(ch); diff --git a/drivers/tty/serial/jsm/jsm_tty.c b/drivers/tty/serial/jsm/jsm_tty.c index 7a4a914ecff..434bd881fca 100644 --- a/drivers/tty/serial/jsm/jsm_tty.c +++ b/drivers/tty/serial/jsm/jsm_tty.c @@ -118,6 +118,19 @@ static void jsm_tty_set_mctrl(struct uart_port *port, unsigned int mctrl) udelay(10); } +/* + * jsm_tty_write() + * + * Take data from the user or kernel and send it out to the FEP. + * In here exists all the Transparent Print magic as well. + */ +static void jsm_tty_write(struct uart_port *port) +{ + struct jsm_channel *channel; + channel = container_of(port, struct jsm_channel, uart_port); + channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel); +} + static void jsm_tty_start_tx(struct uart_port *port) { struct jsm_channel *channel = (struct jsm_channel *)port; @@ -216,14 +229,6 @@ static int jsm_tty_open(struct uart_port *port) return -ENOMEM; } } - if (!channel->ch_wqueue) { - channel->ch_wqueue = kzalloc(WQUEUESIZE, GFP_KERNEL); - if (!channel->ch_wqueue) { - jsm_printk(INIT, ERR, &channel->ch_bd->pci_dev, - "unable to allocate write queue buf"); - return -ENOMEM; - } - } channel->ch_flags &= ~(CH_OPENING); /* @@ -237,7 +242,6 @@ static int jsm_tty_open(struct uart_port *port) */ channel->ch_r_head = channel->ch_r_tail = 0; channel->ch_e_head = channel->ch_e_tail = 0; - channel->ch_w_head = channel->ch_w_tail = 0; brd->bd_ops->flush_uart_write(channel); brd->bd_ops->flush_uart_read(channel); @@ -836,75 +840,3 @@ void jsm_check_queue_flow_control(struct jsm_channel *ch) } } } - -/* - * jsm_tty_write() - * - * Take data from the user or kernel and send it out to the FEP. - * In here exists all the Transparent Print magic as well. - */ -int jsm_tty_write(struct uart_port *port) -{ - int bufcount; - int data_count = 0,data_count1 =0; - u16 head; - u16 tail; - u16 tmask; - u32 remain; - int temp_tail = port->state->xmit.tail; - struct jsm_channel *channel = (struct jsm_channel *)port; - - tmask = WQUEUEMASK; - head = (channel->ch_w_head) & tmask; - tail = (channel->ch_w_tail) & tmask; - - if ((bufcount = tail - head - 1) < 0) - bufcount += WQUEUESIZE; - - bufcount = min(bufcount, 56); - remain = WQUEUESIZE - head; - - data_count = 0; - if (bufcount >= remain) { - bufcount -= remain; - while ((port->state->xmit.head != temp_tail) && - (data_count < remain)) { - channel->ch_wqueue[head++] = - port->state->xmit.buf[temp_tail]; - - temp_tail++; - temp_tail &= (UART_XMIT_SIZE - 1); - data_count++; - } - if (data_count == remain) head = 0; - } - - data_count1 = 0; - if (bufcount > 0) { - remain = bufcount; - while ((port->state->xmit.head != temp_tail) && - (data_count1 < remain)) { - channel->ch_wqueue[head++] = - port->state->xmit.buf[temp_tail]; - - temp_tail++; - temp_tail &= (UART_XMIT_SIZE - 1); - data_count1++; - - } - } - - port->state->xmit.tail = temp_tail; - - data_count += data_count1; - if (data_count) { - head &= tmask; - channel->ch_w_head = head; - } - - if (data_count) { - channel->ch_bd->bd_ops->copy_data_from_queue_to_uart(channel); - } - - return data_count; -} From e8c492bd9cbc8dd1002bf4bc316f21f0a002b10f Mon Sep 17 00:00:00 2001 From: Mitsuo Hayasaka Date: Wed, 12 Oct 2011 16:04:29 +0000 Subject: [PATCH 0135/4025] bonding: use local function pointer of bond->recv_probe in bond_handle_frame [ Upstream commit 4d97480b1806e883eb1c7889d4e7a87e936e06d9 ] The bond->recv_probe is called in bond_handle_frame() when a packet is received, but bond_close() sets it to NULL. So, a panic occurs when both functions work in parallel. Why this happen: After null pointer check of bond->recv_probe, an sk_buff is duplicated and bond->recv_probe is called in bond_handle_frame. So, a panic occurs when bond_close() is called between the check and call of bond->recv_probe. Patch: This patch uses a local function pointer of bond->recv_probe in bond_handle_frame(). So, it can avoid the null pointer dereference. Signed-off-by: Mitsuo Hayasaka Cc: Jay Vosburgh Cc: Andy Gospodarek Cc: Eric Dumazet Cc: WANG Cong Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 9ea2f21443e..2065cb4002b 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1500,6 +1500,8 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) struct sk_buff *skb = *pskb; struct slave *slave; struct bonding *bond; + void (*recv_probe)(struct sk_buff *, struct bonding *, + struct slave *); skb = skb_share_check(skb, GFP_ATOMIC); if (unlikely(!skb)) @@ -1513,11 +1515,12 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) if (bond->params.arp_interval) slave->dev->last_rx = jiffies; - if (bond->recv_probe) { + recv_probe = ACCESS_ONCE(bond->recv_probe); + if (recv_probe) { struct sk_buff *nskb = skb_clone(skb, GFP_ATOMIC); if (likely(nskb)) { - bond->recv_probe(nskb, bond, slave); + recv_probe(nskb, bond, slave); dev_kfree_skb(nskb); } } From 99dfac8ab234555a54f7fa6e4b7bb08bb355158b Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Thu, 6 Oct 2011 11:19:41 +0000 Subject: [PATCH 0136/4025] bridge: fix hang on removal of bridge via netlink [ Upstream commit 1ce5cce895309862d2c35d922816adebe094fe4a ] Need to cleanup bridge device timers and ports when being bridge device is being removed via netlink. This fixes the problem of observed when doing: ip link add br0 type bridge ip link set dev eth1 master br0 ip link set br0 up ip link del br0 which would cause br0 to hang in unregister_netdev because of leftover reference count. Reported-by: Sridhar Samudrala Signed-off-by: Stephen Hemminger Acked-by: Sridhar Samudrala Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/bridge/br_if.c | 9 +++++---- net/bridge/br_netlink.c | 1 + net/bridge/br_private.h | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 6f156c19999..449087373d8 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -161,9 +161,10 @@ static void del_nbp(struct net_bridge_port *p) call_rcu(&p->rcu, destroy_nbp_rcu); } -/* called with RTNL */ -static void del_br(struct net_bridge *br, struct list_head *head) +/* Delete bridge device */ +void br_dev_delete(struct net_device *dev, struct list_head *head) { + struct net_bridge *br = netdev_priv(dev); struct net_bridge_port *p, *n; list_for_each_entry_safe(p, n, &br->port_list, list) { @@ -268,7 +269,7 @@ int br_del_bridge(struct net *net, const char *name) } else - del_br(netdev_priv(dev), NULL); + br_dev_delete(dev, NULL); rtnl_unlock(); return ret; @@ -445,7 +446,7 @@ void __net_exit br_net_exit(struct net *net) rtnl_lock(); for_each_netdev(net, dev) if (dev->priv_flags & IFF_EBRIDGE) - del_br(netdev_priv(dev), &list); + br_dev_delete(dev, &list); unregister_netdevice_many(&list); rtnl_unlock(); diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index ffb0dc4cc0e..2c160552568 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -208,6 +208,7 @@ static struct rtnl_link_ops br_link_ops __read_mostly = { .priv_size = sizeof(struct net_bridge), .setup = br_dev_setup, .validate = br_validate, + .dellink = br_dev_delete, }; int __init br_netlink_init(void) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 78cc364997d..857a021deea 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -294,6 +294,7 @@ static inline int br_is_root_bridge(const struct net_bridge *br) /* br_device.c */ extern void br_dev_setup(struct net_device *dev); +extern void br_dev_delete(struct net_device *dev, struct list_head *list); extern netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev); #ifdef CONFIG_NET_POLL_CONTROLLER From 92dc979cf8a5b2439ac2764cd56675407136d329 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Fri, 23 Sep 2011 08:23:47 +0000 Subject: [PATCH 0137/4025] can bcm: fix tx_setup off-by-one errors [ Upstream commit aabdcb0b553b9c9547b1a506b34d55a764745870 ] This patch fixes two off-by-one errors that canceled each other out. Checking for the same condition two times in bcm_tx_timeout_tsklet() reduced the count of frames to be sent by one. This did not show up the first time tx_setup is invoked as an additional frame is sent due to TX_ANNONCE. Invoking a second tx_setup on the same item led to a reduced (by 1) number of sent frames. Reported-by: Andre Naujoks Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/can/bcm.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/net/can/bcm.c b/net/can/bcm.c index 184a6572b67..8838b86f2f2 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -364,9 +364,6 @@ static void bcm_tx_timeout_tsklet(unsigned long data) bcm_send_to_user(op, &msg_head, NULL, 0); } - } - - if (op->kt_ival1.tv64 && (op->count > 0)) { /* send (next) frame */ bcm_can_tx(op); @@ -969,8 +966,9 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, /* spec: send can_frame when starting timer */ op->flags |= TX_ANNOUNCE; - if (op->kt_ival1.tv64 && (op->count > 0)) { - /* op->count-- is done in bcm_tx_timeout_handler */ + /* only start timer when having more frames than sent below */ + if (op->kt_ival1.tv64 && (op->count > 1)) { + /* op->count-- is done in bcm_tx_timeout_tsklet */ hrtimer_start(&op->timer, op->kt_ival1, HRTIMER_MODE_REL); } else @@ -978,8 +976,11 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, HRTIMER_MODE_REL); } - if (op->flags & TX_ANNOUNCE) + if (op->flags & TX_ANNOUNCE) { bcm_can_tx(op); + if (op->kt_ival1.tv64 && (op->count > 0)) + op->count--; + } return msg_head->nframes * CFSIZ + MHSIZ; } From cbbd42eb61241fcd721f3b02bcb612894e2f02e6 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Sat, 22 Oct 2011 21:58:20 +0000 Subject: [PATCH 0138/4025] ipv4: fix ipsec forward performance regression [ Upstream commit b73233960a59ee66e09d642f13d0592b13651e94 ] There is bug in commit 5e2b61f(ipv4: Remove flowi from struct rtable). It makes xfrm4_fill_dst() modify wrong data structure. Signed-off-by: Zheng Yan Reported-by: Kim Phillips Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/xfrm4_policy.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 981e43eaf70..581fe0ab409 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -79,13 +79,13 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, struct rtable *rt = (struct rtable *)xdst->route; const struct flowi4 *fl4 = &fl->u.ip4; - rt->rt_key_dst = fl4->daddr; - rt->rt_key_src = fl4->saddr; - rt->rt_key_tos = fl4->flowi4_tos; - rt->rt_route_iif = fl4->flowi4_iif; - rt->rt_iif = fl4->flowi4_iif; - rt->rt_oif = fl4->flowi4_oif; - rt->rt_mark = fl4->flowi4_mark; + xdst->u.rt.rt_key_dst = fl4->daddr; + xdst->u.rt.rt_key_src = fl4->saddr; + xdst->u.rt.rt_key_tos = fl4->flowi4_tos; + xdst->u.rt.rt_route_iif = fl4->flowi4_iif; + xdst->u.rt.rt_iif = fl4->flowi4_iif; + xdst->u.rt.rt_oif = fl4->flowi4_oif; + xdst->u.rt.rt_mark = fl4->flowi4_mark; xdst->u.dst.dev = dev; dev_hold(dev); From c11deb8d898318a2fea9a291b16a7a2b2507cc94 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 7 Oct 2011 05:35:46 +0000 Subject: [PATCH 0139/4025] l2tp: fix a potential skb leak in l2tp_xmit_skb() [ Upstream commit 835acf5da239b91edb9f7ebe36516999e156e6ee ] l2tp_xmit_skb() can leak one skb if skb_cow_head() returns an error. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index ed8a2335442..71c292e3e03 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1045,8 +1045,10 @@ int l2tp_xmit_skb(struct l2tp_session *session, struct sk_buff *skb, int hdr_len headroom = NET_SKB_PAD + sizeof(struct iphdr) + uhlen + hdr_len; old_headroom = skb_headroom(skb); - if (skb_cow_head(skb, headroom)) + if (skb_cow_head(skb, headroom)) { + dev_kfree_skb(skb); goto abort; + } new_headroom = skb_headroom(skb); skb_orphan(skb); From 89c32c14c190c6113187c7c57784695701e314e4 Mon Sep 17 00:00:00 2001 From: David Ward Date: Sun, 18 Sep 2011 12:53:20 +0000 Subject: [PATCH 0140/4025] macvlan/macvtap: Fix unicast between macvtap interfaces in bridge mode [ Upstream commit cb2d0f3e968bff7c6d262aca3e3ab8d4184e69b2 ] Packets should always be forwarded to the lowerdev using dev_forward_skb. vlan->forward is for packets being forwarded directly to another macvlan/ macvtap device (used for multicast in bridge mode). Reported-and-tested-by: Shlomo Pongratz Signed-off-by: David Ward Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/macvlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 2f3c48da586..ab4723d92a6 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -239,7 +239,7 @@ static int macvlan_queue_xmit(struct sk_buff *skb, struct net_device *dev) dest = macvlan_hash_lookup(port, eth->h_dest); if (dest && dest->mode == MACVLAN_MODE_BRIDGE) { /* send to lowerdev first for its network taps */ - vlan->forward(vlan->lowerdev, skb); + dev_forward_skb(vlan->lowerdev, skb); return NET_XMIT_SUCCESS; } From 18743353b3154f0ff7c29f3c5ae3a8466a70d73a Mon Sep 17 00:00:00 2001 From: Gao feng Date: Tue, 11 Oct 2011 16:08:11 +0000 Subject: [PATCH 0141/4025] netconsole: enable netconsole can make net_device refcnt incorrent [ Upstream commit d5123480b1d6f7d1a5fe1a13520cef88fb5d4c84 ] There is no check if netconsole is enabled current. so when exec echo 1 > enabled; the reference of net_device will increment always. Signed-off-by: Gao feng Acked-by: Flavio Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/netconsole.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index dfc82720065..4840ab7e7f8 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -307,6 +307,11 @@ static ssize_t store_enabled(struct netconsole_target *nt, return err; if (enabled < 0 || enabled > 1) return -EINVAL; + if (enabled == nt->enabled) { + printk(KERN_INFO "netconsole: network logging has already %s\n", + nt->enabled ? "started" : "stopped"); + return -EINVAL; + } if (enabled) { /* 1 */ From 37c88f5fe7f287a945949e6f4570700c210ebe0f Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Thu, 29 Sep 2011 17:10:10 +0000 Subject: [PATCH 0142/4025] tcp: properly handle md5sig_pool references [ Upstream commit 260fcbeb1ae9e768a44c9925338fbacb0d7e5ba9 ] tcp_v4_clear_md5_list() assumes that multiple tcp md5sig peers only hold one reference to md5sig_pool. but tcp_v4_md5_do_add() increases use count of md5sig_pool for each peer. This patch makes tcp_v4_md5_do_add() only increases use count for the first tcp md5sig peer. Signed-off-by: Zheng Yan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_ipv4.c | 11 +++++++---- net/ipv6/tcp_ipv6.c | 8 +++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index b3e6956d7ba..69790aa3198 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -909,18 +909,21 @@ int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, } sk_nocaps_add(sk, NETIF_F_GSO_MASK); } - if (tcp_alloc_md5sig_pool(sk) == NULL) { + + md5sig = tp->md5sig_info; + if (md5sig->entries4 == 0 && + tcp_alloc_md5sig_pool(sk) == NULL) { kfree(newkey); return -ENOMEM; } - md5sig = tp->md5sig_info; if (md5sig->alloced4 == md5sig->entries4) { keys = kmalloc((sizeof(*keys) * (md5sig->entries4 + 1)), GFP_ATOMIC); if (!keys) { kfree(newkey); - tcp_free_md5sig_pool(); + if (md5sig->entries4 == 0) + tcp_free_md5sig_pool(); return -ENOMEM; } @@ -964,6 +967,7 @@ int tcp_v4_md5_do_del(struct sock *sk, __be32 addr) kfree(tp->md5sig_info->keys4); tp->md5sig_info->keys4 = NULL; tp->md5sig_info->alloced4 = 0; + tcp_free_md5sig_pool(); } else if (tp->md5sig_info->entries4 != i) { /* Need to do some manipulation */ memmove(&tp->md5sig_info->keys4[i], @@ -971,7 +975,6 @@ int tcp_v4_md5_do_del(struct sock *sk, __be32 addr) (tp->md5sig_info->entries4 - i) * sizeof(struct tcp4_md5sig_key)); } - tcp_free_md5sig_pool(); return 0; } } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 7c43e861475..af78a16c830 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -605,7 +605,8 @@ static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer, } sk_nocaps_add(sk, NETIF_F_GSO_MASK); } - if (tcp_alloc_md5sig_pool(sk) == NULL) { + if (tp->md5sig_info->entries6 == 0 && + tcp_alloc_md5sig_pool(sk) == NULL) { kfree(newkey); return -ENOMEM; } @@ -614,8 +615,9 @@ static int tcp_v6_md5_do_add(struct sock *sk, const struct in6_addr *peer, (tp->md5sig_info->entries6 + 1)), GFP_ATOMIC); if (!keys) { - tcp_free_md5sig_pool(); kfree(newkey); + if (tp->md5sig_info->entries6 == 0) + tcp_free_md5sig_pool(); return -ENOMEM; } @@ -661,6 +663,7 @@ static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer) kfree(tp->md5sig_info->keys6); tp->md5sig_info->keys6 = NULL; tp->md5sig_info->alloced6 = 0; + tcp_free_md5sig_pool(); } else { /* shrink the database */ if (tp->md5sig_info->entries6 != i) @@ -669,7 +672,6 @@ static int tcp_v6_md5_do_del(struct sock *sk, const struct in6_addr *peer) (tp->md5sig_info->entries6 - i) * sizeof (tp->md5sig_info->keys6[0])); } - tcp_free_md5sig_pool(); return 0; } } From b00654416d4baccf2269ec888e55d6df069cd36f Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Sun, 2 Oct 2011 04:21:50 +0000 Subject: [PATCH 0143/4025] tcp: properly update lost_cnt_hint during shifting [ Upstream commit 1e5289e121372a3494402b1b131b41bfe1cf9b7f ] lost_skb_hint is used by tcp_mark_head_lost() to mark the first unhandled skb. lost_cnt_hint is the number of packets or sacked packets before the lost_skb_hint; When shifting a skb that is before the lost_skb_hint, if tcp_is_fack() is ture, the skb has already been counted in the lost_cnt_hint; if tcp_is_fack() is false, tcp_sacktag_one() will increase the lost_cnt_hint. So tcp_shifted_skb() does not need to adjust the lost_cnt_hint by itself. When shifting a skb that is equal to lost_skb_hint, the shifted packets will not be counted by tcp_mark_head_lost(). So tcp_shifted_skb() should adjust the lost_cnt_hint even tcp_is_fack(tp) is true. Signed-off-by: Zheng Yan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b6771f9eb9d..c68040fe9cd 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1380,9 +1380,7 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, BUG_ON(!pcount); - /* Tweak before seqno plays */ - if (!tcp_is_fack(tp) && tcp_is_sack(tp) && tp->lost_skb_hint && - !before(TCP_SKB_CB(tp->lost_skb_hint)->seq, TCP_SKB_CB(skb)->seq)) + if (skb == tp->lost_skb_hint) tp->lost_cnt_hint += pcount; TCP_SKB_CB(prev)->end_seq += shifted; From ec668dbad7f732767d5484e1c7b317c767777f27 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Tue, 11 Oct 2011 23:00:41 +0000 Subject: [PATCH 0144/4025] tg3: negate USE_PHYLIB flag check [ Upstream commit e730c82347b9dc75914da998c44c3f348965db41 ] USE_PHYLIB flag in tg3_remove_one() is being checked incorrectly. This results tg3_phy_fini->phy_disconnect is never called and when tg3 module is removed. In my case this resulted in panics in phy_state_machine calling function phydev->adjust_link. So correct this check. Signed-off-by: Jiri Pirko Acked-by: Matt Carlson Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- 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 38f68594f76..bc8c183d622 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -15278,7 +15278,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) cancel_work_sync(&tp->reset_task); - if (!tg3_flag(tp, USE_PHYLIB)) { + if (tg3_flag(tp, USE_PHYLIB)) { tg3_phy_fini(tp); tg3_mdio_fini(tp); } From 2146d4667b5fbdb0e186ca8bc6d9cbe7ac42dfdc Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Sun, 25 Sep 2011 02:21:30 +0000 Subject: [PATCH 0145/4025] ipv6: nullify ipv6_ac_list and ipv6_fl_list when creating new socket [ Upstream commit 676a1184e8afd4fed7948232df1ff91517400859 ] ipv6_ac_list and ipv6_fl_list from listening socket are inadvertently shared with new socket created for connection. Signed-off-by: Zheng Yan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/tcp_ipv6.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index af78a16c830..296510a82c3 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1409,6 +1409,8 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newtp->af_specific = &tcp_sock_ipv6_mapped_specific; #endif + newnp->ipv6_ac_list = NULL; + newnp->ipv6_fl_list = NULL; newnp->pktoptions = NULL; newnp->opt = NULL; newnp->mcast_oif = inet6_iif(skb); @@ -1473,6 +1475,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, First: no IPv4 options. */ newinet->inet_opt = NULL; + newnp->ipv6_ac_list = NULL; newnp->ipv6_fl_list = NULL; /* Clone RX bits */ From 62d8d0b9b6c459789876335156c56110042f2158 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Fri, 30 Sep 2011 10:38:28 +0000 Subject: [PATCH 0146/4025] make PACKET_STATISTICS getsockopt report consistently between ring and non-ring [ Upstream commit 7091fbd82cd5686444ffe9935ed6a8190101fe9d ] This is a minor change. Up until kernel 2.6.32, getsockopt(fd, SOL_PACKET, PACKET_STATISTICS, ...) would return total and dropped packets since its last invocation. The introduction of socket queue overflow reporting [1] changed drop rate calculation in the normal packet socket path, but not when using a packet ring. As a result, the getsockopt now returns different statistics depending on the reception method used. With a ring, it still returns the count since the last call, as counts are incremented in tpacket_rcv and reset in getsockopt. Without a ring, it returns 0 if no drops occurred since the last getsockopt and the total drops over the lifespan of the socket otherwise. The culprit is this line in packet_rcv, executed on a drop: drop_n_acct: po->stats.tp_drops = atomic_inc_return(&sk->sk_drops); As it shows, the new drop number it taken from the socket drop counter, which is not reset at getsockopt. I put together a small example that demonstrates the issue [2]. It runs for 10 seconds and overflows the queue/ring on every odd second. The reported drop rates are: ring: 16, 0, 16, 0, 16, ... non-ring: 0, 15, 0, 30, 0, 46, 0, 60, 0 , 74. Note how the even ring counts monotonically increase. Because the getsockopt adds tp_drops to tp_packets, total counts are similarly reported cumulatively. Long story short, reinstating the original code, as the below patch does, fixes the issue at the cost of additional per-packet cycles. Another solution that does not introduce per-packet overhead is be to keep the current data path, record the value of sk_drops at getsockopt() at call N in a new field in struct packetsock and subtract that when reporting at call N+1. I'll be happy to code that, instead, it's just more messy. [1] http://patchwork.ozlabs.org/patch/35665/ [2] http://kernel.googlecode.com/files/test-packetsock-getstatistics.c Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/packet/af_packet.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index c0c3cda1971..fafb96830e7 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -654,7 +654,10 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, return 0; drop_n_acct: - po->stats.tp_drops = atomic_inc_return(&sk->sk_drops); + spin_lock(&sk->sk_receive_queue.lock); + po->stats.tp_drops++; + atomic_inc(&sk->sk_drops); + spin_unlock(&sk->sk_receive_queue.lock); drop_n_restore: if (skb_head != skb->data && skb_shared(skb)) { From a00fb1451d630898c1380349ac3776688e58010f Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Fri, 30 Sep 2011 06:37:51 +0000 Subject: [PATCH 0147/4025] net: xen-netback: correctly restart Tx after a VM restore/migrate [ Upstream commit d0e5d83284dac15c015bb48115b6780f5a6413cd ] If a VM is saved and restored (or migrated) the netback driver will no longer process any Tx packets from the frontend. xenvif_up() does not schedule the processing of any pending Tx requests from the front end because the carrier is off. Without this initial kick the frontend just adds Tx requests to the ring without raising an event (until the ring is full). This was caused by 47103041e91794acdbc6165da0ae288d844c820b (net: xen-netback: convert to hw_features) which reordered the calls to xenvif_up() and netif_carrier_on() in xenvif_connect(). Signed-off-by: David Vrabel Cc: Ian Campbell Acked-by: Ian Campbell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netback/interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 0ca86f9ec4e..182562952c7 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -327,12 +327,12 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, xenvif_get(vif); rtnl_lock(); - if (netif_running(vif->dev)) - xenvif_up(vif); if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN) dev_set_mtu(vif->dev, ETH_DATA_LEN); netdev_update_features(vif->dev); netif_carrier_on(vif->dev); + if (netif_running(vif->dev)) + xenvif_up(vif); rtnl_unlock(); return 0; From 68fe9d9c796303de600dbc622086768ca4d8408b Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Wed, 2 Nov 2011 13:36:59 -0700 Subject: [PATCH 0148/4025] mm: thp: tail page refcounting fix commit 70b50f94f1644e2aa7cb374819cfd93f3c28d725 upstream. Michel while working on the working set estimation code, noticed that calling get_page_unless_zero() on a random pfn_to_page(random_pfn) wasn't safe, if the pfn ended up being a tail page of a transparent hugepage under splitting by __split_huge_page_refcount(). He then found the problem could also theoretically materialize with page_cache_get_speculative() during the speculative radix tree lookups that uses get_page_unless_zero() in SMP if the radix tree page is freed and reallocated and get_user_pages is called on it before page_cache_get_speculative has a chance to call get_page_unless_zero(). So the best way to fix the problem is to keep page_tail->_count zero at all times. This will guarantee that get_page_unless_zero() can never succeed on any tail page. page_tail->_mapcount is guaranteed zero and is unused for all tail pages of a compound page, so we can simply account the tail page references there and transfer them to tail_page->_count in __split_huge_page_refcount() (in addition to the head_page->_mapcount). While debugging this s/_count/_mapcount/ change I also noticed get_page is called by direct-io.c on pages returned by get_user_pages. That wasn't entirely safe because the two atomic_inc in get_page weren't atomic. As opposed to other get_user_page users like secondary-MMU page fault to establish the shadow pagetables would never call any superflous get_page after get_user_page returns. It's safer to make get_page universally safe for tail pages and to use get_page_foll() within follow_page (inside get_user_pages()). get_page_foll() is safe to do the refcounting for tail pages without taking any locks because it is run within PT lock protected critical sections (PT lock for pte and page_table_lock for pmd_trans_huge). The standard get_page() as invoked by direct-io instead will now take the compound_lock but still only for tail pages. The direct-io paths are usually I/O bound and the compound_lock is per THP so very finegrined, so there's no risk of scalability issues with it. A simple direct-io benchmarks with all lockdep prove locking and spinlock debugging infrastructure enabled shows identical performance and no overhead. So it's worth it. Ideally direct-io should stop calling get_page() on pages returned by get_user_pages(). The spinlock in get_page() is already optimized away for no-THP builds but doing get_page() on tail pages returned by GUP is generally a rare operation and usually only run in I/O paths. This new refcounting on page_tail->_mapcount in addition to avoiding new RCU critical sections will also allow the working set estimation code to work without any further complexity associated to the tail page refcounting with THP. Signed-off-by: Andrea Arcangeli Reported-by: Michel Lespinasse Reviewed-by: Michel Lespinasse Reviewed-by: Minchan Kim Cc: Peter Zijlstra Cc: Hugh Dickins Cc: Johannes Weiner Cc: Rik van Riel Cc: Mel Gorman Cc: KOSAKI Motohiro Cc: Benjamin Herrenschmidt Cc: David Gibson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/gup.c | 5 ++- arch/x86/mm/gup.c | 5 ++- include/linux/mm.h | 56 +++++++++++---------------- include/linux/mm_types.h | 22 +++++++++-- mm/huge_memory.c | 37 ++++++++++++------ mm/internal.h | 46 ++++++++++++++++++++++ mm/memory.c | 2 +- mm/swap.c | 83 +++++++++++++++++++++++++--------------- 8 files changed, 172 insertions(+), 84 deletions(-) diff --git a/arch/powerpc/mm/gup.c b/arch/powerpc/mm/gup.c index fec13200868..b9e1c7ff5f6 100644 --- a/arch/powerpc/mm/gup.c +++ b/arch/powerpc/mm/gup.c @@ -22,8 +22,9 @@ static inline void get_huge_page_tail(struct page *page) * __split_huge_page_refcount() cannot run * from under us. */ - VM_BUG_ON(atomic_read(&page->_count) < 0); - atomic_inc(&page->_count); + VM_BUG_ON(page_mapcount(page) < 0); + VM_BUG_ON(atomic_read(&page->_count) != 0); + atomic_inc(&page->_mapcount); } /* diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c index dbe34b93137..3b5032a62b0 100644 --- a/arch/x86/mm/gup.c +++ b/arch/x86/mm/gup.c @@ -114,8 +114,9 @@ static inline void get_huge_page_tail(struct page *page) * __split_huge_page_refcount() cannot run * from under us. */ - VM_BUG_ON(atomic_read(&page->_count) < 0); - atomic_inc(&page->_count); + VM_BUG_ON(page_mapcount(page) < 0); + VM_BUG_ON(atomic_read(&page->_count) != 0); + atomic_inc(&page->_mapcount); } static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr, diff --git a/include/linux/mm.h b/include/linux/mm.h index ec6e33d4ed0..26fd168c670 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -355,36 +355,39 @@ static inline struct page *compound_head(struct page *page) return page; } +/* + * The atomic page->_mapcount, starts from -1: so that transitions + * both from it and to it can be tracked, using atomic_inc_and_test + * and atomic_add_negative(-1). + */ +static inline void reset_page_mapcount(struct page *page) +{ + atomic_set(&(page)->_mapcount, -1); +} + +static inline int page_mapcount(struct page *page) +{ + return atomic_read(&(page)->_mapcount) + 1; +} + static inline int page_count(struct page *page) { return atomic_read(&compound_head(page)->_count); } +extern bool __get_page_tail(struct page *page); + static inline void get_page(struct page *page) { + if (unlikely(PageTail(page))) + if (likely(__get_page_tail(page))) + return; /* * Getting a normal page or the head of a compound page - * requires to already have an elevated page->_count. Only if - * we're getting a tail page, the elevated page->_count is - * required only in the head page, so for tail pages the - * bugcheck only verifies that the page->_count isn't - * negative. + * requires to already have an elevated page->_count. */ - VM_BUG_ON(atomic_read(&page->_count) < !PageTail(page)); + VM_BUG_ON(atomic_read(&page->_count) <= 0); atomic_inc(&page->_count); - /* - * Getting a tail page will elevate both the head and tail - * page->_count(s). - */ - if (unlikely(PageTail(page))) { - /* - * This is safe only because - * __split_huge_page_refcount can't run under - * get_page(). - */ - VM_BUG_ON(atomic_read(&page->first_page->_count) <= 0); - atomic_inc(&page->first_page->_count); - } } static inline struct page *virt_to_head_page(const void *x) @@ -802,21 +805,6 @@ static inline pgoff_t page_index(struct page *page) return page->index; } -/* - * The atomic page->_mapcount, like _count, starts from -1: - * so that transitions both from it and to it can be tracked, - * using atomic_inc_and_test and atomic_add_negative(-1). - */ -static inline void reset_page_mapcount(struct page *page) -{ - atomic_set(&(page)->_mapcount, -1); -} - -static inline int page_mapcount(struct page *page) -{ - return atomic_read(&(page)->_mapcount) + 1; -} - /* * Return true if this page is mapped into pagetables. */ diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 027935c86c6..059839c7000 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -36,10 +36,24 @@ struct page { * updated asynchronously */ atomic_t _count; /* Usage count, see below. */ union { - atomic_t _mapcount; /* Count of ptes mapped in mms, - * to show when page is mapped - * & limit reverse map searches. - */ + /* + * Count of ptes mapped in + * mms, to show when page is + * mapped & limit reverse map + * searches. + * + * Used also for tail pages + * refcounting instead of + * _count. Tail pages cannot + * be mapped and keeping the + * tail page _count zero at + * all times guarantees + * get_page_unless_zero() will + * never succeed on tail + * pages. + */ + atomic_t _mapcount; + struct { /* SLUB */ u16 inuse; u16 objects; diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 81532f297fd..cc5acf9998b 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -989,7 +989,7 @@ struct page *follow_trans_huge_pmd(struct mm_struct *mm, page += (addr & ~HPAGE_PMD_MASK) >> PAGE_SHIFT; VM_BUG_ON(!PageCompound(page)); if (flags & FOLL_GET) - get_page(page); + get_page_foll(page); out: return page; @@ -1156,6 +1156,7 @@ static void __split_huge_page_refcount(struct page *page) unsigned long head_index = page->index; struct zone *zone = page_zone(page); int zonestat; + int tail_count = 0; /* prevent PageLRU to go away from under us, and freeze lru stats */ spin_lock_irq(&zone->lru_lock); @@ -1164,11 +1165,27 @@ static void __split_huge_page_refcount(struct page *page) for (i = 1; i < HPAGE_PMD_NR; i++) { struct page *page_tail = page + i; - /* tail_page->_count cannot change */ - atomic_sub(atomic_read(&page_tail->_count), &page->_count); - BUG_ON(page_count(page) <= 0); - atomic_add(page_mapcount(page) + 1, &page_tail->_count); - BUG_ON(atomic_read(&page_tail->_count) <= 0); + /* tail_page->_mapcount cannot change */ + BUG_ON(page_mapcount(page_tail) < 0); + tail_count += page_mapcount(page_tail); + /* check for overflow */ + BUG_ON(tail_count < 0); + BUG_ON(atomic_read(&page_tail->_count) != 0); + /* + * tail_page->_count is zero and not changing from + * under us. But get_page_unless_zero() may be running + * from under us on the tail_page. If we used + * atomic_set() below instead of atomic_add(), we + * would then run atomic_set() concurrently with + * get_page_unless_zero(), and atomic_set() is + * implemented in C not using locked ops. spin_unlock + * on x86 sometime uses locked ops because of PPro + * errata 66, 92, so unless somebody can guarantee + * atomic_set() here would be safe on all archs (and + * not only on x86), it's safer to use atomic_add(). + */ + atomic_add(page_mapcount(page) + page_mapcount(page_tail) + 1, + &page_tail->_count); /* after clearing PageTail the gup refcount can be released */ smp_mb(); @@ -1186,10 +1203,7 @@ static void __split_huge_page_refcount(struct page *page) (1L << PG_uptodate))); page_tail->flags |= (1L << PG_dirty); - /* - * 1) clear PageTail before overwriting first_page - * 2) clear PageTail before clearing PageHead for VM_BUG_ON - */ + /* clear PageTail before overwriting first_page */ smp_wmb(); /* @@ -1206,7 +1220,6 @@ static void __split_huge_page_refcount(struct page *page) * status is achieved setting a reserved bit in the * pmd, not by clearing the present bit. */ - BUG_ON(page_mapcount(page_tail)); page_tail->_mapcount = page->_mapcount; BUG_ON(page_tail->mapping); @@ -1223,6 +1236,8 @@ static void __split_huge_page_refcount(struct page *page) lru_add_page_tail(zone, page, page_tail); } + atomic_sub(tail_count, &page->_count); + BUG_ON(atomic_read(&page->_count) <= 0); __dec_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES); __mod_zone_page_state(zone, NR_ANON_PAGES, HPAGE_PMD_NR); diff --git a/mm/internal.h b/mm/internal.h index d071d380fb4..2189af49178 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -37,6 +37,52 @@ static inline void __put_page(struct page *page) atomic_dec(&page->_count); } +static inline void __get_page_tail_foll(struct page *page, + bool get_page_head) +{ + /* + * If we're getting a tail page, the elevated page->_count is + * required only in the head page and we will elevate the head + * page->_count and tail page->_mapcount. + * + * We elevate page_tail->_mapcount for tail pages to force + * page_tail->_count to be zero at all times to avoid getting + * false positives from get_page_unless_zero() with + * speculative page access (like in + * page_cache_get_speculative()) on tail pages. + */ + VM_BUG_ON(atomic_read(&page->first_page->_count) <= 0); + VM_BUG_ON(atomic_read(&page->_count) != 0); + VM_BUG_ON(page_mapcount(page) < 0); + if (get_page_head) + atomic_inc(&page->first_page->_count); + atomic_inc(&page->_mapcount); +} + +/* + * This is meant to be called as the FOLL_GET operation of + * follow_page() and it must be called while holding the proper PT + * lock while the pte (or pmd_trans_huge) is still mapping the page. + */ +static inline void get_page_foll(struct page *page) +{ + if (unlikely(PageTail(page))) + /* + * This is safe only because + * __split_huge_page_refcount() can't run under + * get_page_foll() because we hold the proper PT lock. + */ + __get_page_tail_foll(page, true); + else { + /* + * Getting a normal page or the head of a compound page + * requires to already have an elevated page->_count. + */ + VM_BUG_ON(atomic_read(&page->_count) <= 0); + atomic_inc(&page->_count); + } +} + extern unsigned long highest_memmap_pfn; /* diff --git a/mm/memory.c b/mm/memory.c index d961e1914d1..95a77998ab5 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1514,7 +1514,7 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address, } if (flags & FOLL_GET) - get_page(page); + get_page_foll(page); if (flags & FOLL_TOUCH) { if ((flags & FOLL_WRITE) && !pte_dirty(pte) && !PageDirty(page)) diff --git a/mm/swap.c b/mm/swap.c index 3a442f18b0b..87627f181c3 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -78,39 +78,22 @@ static void put_compound_page(struct page *page) { if (unlikely(PageTail(page))) { /* __split_huge_page_refcount can run under us */ - struct page *page_head = page->first_page; - smp_rmb(); - /* - * If PageTail is still set after smp_rmb() we can be sure - * that the page->first_page we read wasn't a dangling pointer. - * See __split_huge_page_refcount() smp_wmb(). - */ - if (likely(PageTail(page) && get_page_unless_zero(page_head))) { + struct page *page_head = compound_trans_head(page); + + if (likely(page != page_head && + get_page_unless_zero(page_head))) { unsigned long flags; /* - * Verify that our page_head wasn't converted - * to a a regular page before we got a - * reference on it. + * page_head wasn't a dangling pointer but it + * may not be a head page anymore by the time + * we obtain the lock. That is ok as long as it + * can't be freed from under us. */ - if (unlikely(!PageHead(page_head))) { - /* PageHead is cleared after PageTail */ - smp_rmb(); - VM_BUG_ON(PageTail(page)); - goto out_put_head; - } - /* - * Only run compound_lock on a valid PageHead, - * after having it pinned with - * get_page_unless_zero() above. - */ - smp_mb(); - /* page_head wasn't a dangling pointer */ flags = compound_lock_irqsave(page_head); if (unlikely(!PageTail(page))) { /* __split_huge_page_refcount run before us */ compound_unlock_irqrestore(page_head, flags); VM_BUG_ON(PageHead(page_head)); - out_put_head: if (put_page_testzero(page_head)) __put_single_page(page_head); out_put_single: @@ -121,16 +104,17 @@ static void put_compound_page(struct page *page) VM_BUG_ON(page_head != page->first_page); /* * We can release the refcount taken by - * get_page_unless_zero now that - * split_huge_page_refcount is blocked on the - * compound_lock. + * get_page_unless_zero() now that + * __split_huge_page_refcount() is blocked on + * the compound_lock. */ if (put_page_testzero(page_head)) VM_BUG_ON(1); /* __split_huge_page_refcount will wait now */ - VM_BUG_ON(atomic_read(&page->_count) <= 0); - atomic_dec(&page->_count); + VM_BUG_ON(page_mapcount(page) <= 0); + atomic_dec(&page->_mapcount); VM_BUG_ON(atomic_read(&page_head->_count) <= 0); + VM_BUG_ON(atomic_read(&page->_count) != 0); compound_unlock_irqrestore(page_head, flags); if (put_page_testzero(page_head)) { if (PageHead(page_head)) @@ -160,6 +144,45 @@ void put_page(struct page *page) } EXPORT_SYMBOL(put_page); +/* + * This function is exported but must not be called by anything other + * than get_page(). It implements the slow path of get_page(). + */ +bool __get_page_tail(struct page *page) +{ + /* + * This takes care of get_page() if run on a tail page + * returned by one of the get_user_pages/follow_page variants. + * get_user_pages/follow_page itself doesn't need the compound + * lock because it runs __get_page_tail_foll() under the + * proper PT lock that already serializes against + * split_huge_page(). + */ + unsigned long flags; + bool got = false; + struct page *page_head = compound_trans_head(page); + + if (likely(page != page_head && get_page_unless_zero(page_head))) { + /* + * page_head wasn't a dangling pointer but it + * may not be a head page anymore by the time + * we obtain the lock. That is ok as long as it + * can't be freed from under us. + */ + flags = compound_lock_irqsave(page_head); + /* here __split_huge_page_refcount won't run anymore */ + if (likely(PageTail(page))) { + __get_page_tail_foll(page, false); + got = true; + } + compound_unlock_irqrestore(page_head, flags); + if (unlikely(!got)) + put_page(page_head); + } + return got; +} +EXPORT_SYMBOL(__get_page_tail); + /** * put_pages_list() - release a list of pages * @pages: list of pages threaded on page->lru From bfcf6092c5b8789a179e40992ca041bbdbb859cc Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 2 Nov 2011 13:37:41 -0700 Subject: [PATCH 0149/4025] binfmt_elf: fix PIE execution with randomization disabled commit a3defbe5c337dbc6da911f8cc49ae3cc3b49b453 upstream. The case of address space randomization being disabled in runtime through randomize_va_space sysctl is not treated properly in load_elf_binary(), resulting in SIGKILL coming at exec() time for certain PIE-linked binaries in case the randomization has been disabled at runtime prior to calling exec(). Handle the randomize_va_space == 0 case the same way as if we were not supporting .text randomization at all. Based on original patch by H.J. Lu and Josh Boyer. Signed-off-by: Jiri Kosina Cc: Ingo Molnar Cc: Russell King Cc: H.J. Lu Cc: Tested-by: Josh Boyer Acked-by: Nicolas Pitre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/binfmt_elf.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 303983fabfd..9ba2ac755a7 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -796,7 +796,16 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) * might try to exec. This is because the brk will * follow the loader, and is not movable. */ #if defined(CONFIG_X86) || defined(CONFIG_ARM) - load_bias = 0; + /* Memory randomization might have been switched off + * in runtime via sysctl. + * If that is the case, retain the original non-zero + * load_bias value in order to establish proper + * non-randomized mappings. + */ + if (current->flags & PF_RANDOMIZE) + load_bias = 0; + else + load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); #else load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); #endif From 4f0bf01fabfa6519f8d96b089e44eeaf6cc085c2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 6 Aug 2011 11:51:33 -0700 Subject: [PATCH 0150/4025] vfs: show O_CLOEXE bit properly in /proc//fdinfo/ files commit 1117f72ea0217ba0cc19f05adbbd8b9a397f5ab7 upstream. The CLOEXE bit is magical, and for performance (and semantic) reasons we don't actually maintain it in the file descriptor itself, but in a separate bit array. Which means that when we show f_flags, the CLOEXE status is shown incorrectly: we show the status not as it is now, but as it was when the file was opened. Fix that by looking up the bit properly in the 'fdt->close_on_exec' bit array. Uli needs this in order to re-implement the pfiles program: "For normal file descriptors (not sockets) this was the last piece of information which wasn't available. This is all part of my 'give Solaris users no reason to not switch' effort. I intend to offer the code to the util-linux-ng maintainers." Requested-by: Ulrich Drepper Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/proc/base.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 5bff4c6b831..f0390177be9 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1920,6 +1920,14 @@ static int proc_fd_info(struct inode *inode, struct path *path, char *info) spin_lock(&files->file_lock); file = fcheck_files(files, fd); if (file) { + unsigned int f_flags; + struct fdtable *fdt; + + fdt = files_fdtable(files); + f_flags = file->f_flags & ~O_CLOEXEC; + if (FD_ISSET(fd, fdt->close_on_exec)) + f_flags |= O_CLOEXEC; + if (path) { *path = file->f_path; path_get(&file->f_path); @@ -1929,7 +1937,7 @@ static int proc_fd_info(struct inode *inode, struct path *path, char *info) "pos:\t%lli\n" "flags:\t0%o\n", (long long) file->f_pos, - file->f_flags); + f_flags); spin_unlock(&files->file_lock); put_files_struct(files); return 0; From 179b05367d02451ebf4d4b655632b6f979fcac8a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 3 Nov 2011 13:46:08 +0100 Subject: [PATCH 0151/4025] iwlagn: do not use interruptible waits Upstream commit effd4d9aece9184f526e6556786a94d335e38b71. Since the dawn of its time, iwlwifi has used interruptible waits to wait for synchronous commands and firmware loading. This leads to "interesting" bugs, because it can't actually handle the interruptions; for example when a command sending is interrupted it will assume the command completed fully, and then leave it pending, which leads to all kinds of trouble when the command finishes later. Since there's no easy way to gracefully deal with interruptions, fix the driver to not use interruptible waits. This at least fixes the error iwlagn 0000:02:00.0: Error: Response NULL in 'REPLY_SCAN_ABORT_CMD' I have seen in P2P testing, but it is likely that there are other errors caused by this. Cc: Stanislaw Gruszka Signed-off-by: Johannes Berg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-agn-ucode.c | 9 ++------- drivers/net/wireless/iwlwifi/iwl-agn.c | 2 +- drivers/net/wireless/iwlwifi/iwl-core.c | 4 ++-- drivers/net/wireless/iwlwifi/iwl-hcmd.c | 2 +- drivers/net/wireless/iwlwifi/iwl-rx.c | 2 +- drivers/net/wireless/iwlwifi/iwl-tx.c | 2 +- 6 files changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c index 97de5d9de67..a03dbcc46d0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c @@ -144,13 +144,8 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name, FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); IWL_DEBUG_INFO(priv, "%s uCode section being loaded...\n", name); - ret = wait_event_interruptible_timeout(priv->wait_command_queue, - priv->ucode_write_complete, 5 * HZ); - if (ret == -ERESTARTSYS) { - IWL_ERR(priv, "Could not load the %s uCode section due " - "to interrupt\n", name); - return ret; - } + ret = wait_event_timeout(priv->wait_command_queue, + priv->ucode_write_complete, 5 * HZ); if (!ret) { IWL_ERR(priv, "Could not load the %s uCode section\n", name); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index f24165d2698..baec52d191b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -797,7 +797,7 @@ static void iwl_irq_tasklet(struct iwl_priv *priv) handled |= CSR_INT_BIT_FH_TX; /* Wake up uCode load routine, now that load is complete */ priv->ucode_write_complete = 1; - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->wait_command_queue); } if (inta & ~handled) { diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 45cc51c9c93..56384078336 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -899,7 +899,7 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand) * commands by clearing the ready bit */ clear_bit(STATUS_READY, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->wait_command_queue); if (!ondemand) { /* @@ -950,7 +950,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv) */ clear_bit(STATUS_READY, &priv->status); clear_bit(STATUS_HCMD_ACTIVE, &priv->status); - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->wait_command_queue); IWL_ERR(priv, "RF is used by WiMAX\n"); return; } diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 76f99662314..fc1127763ba 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -194,7 +194,7 @@ int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd) return ret; } - ret = wait_event_interruptible_timeout(priv->wait_command_queue, + ret = wait_event_timeout(priv->wait_command_queue, !test_bit(STATUS_HCMD_ACTIVE, &priv->status), HOST_COMPLETE_TIMEOUT); if (!ret) { diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index b774517aa9f..865ac1a61bb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -738,7 +738,7 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv, wiphy_rfkill_set_hw_state(priv->hw->wiphy, test_bit(STATUS_RF_KILL_HW, &priv->status)); else - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->wait_command_queue); } static void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index c368c50fb31..93152c38b67 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -821,7 +821,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) clear_bit(STATUS_HCMD_ACTIVE, &priv->status); IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n", get_cmd_string(cmd->hdr.cmd)); - wake_up_interruptible(&priv->wait_command_queue); + wake_up(&priv->wait_command_queue); } /* Mark as unmapped */ From 044ee31ce0a51153f27a9d8c55ea12db32e59667 Mon Sep 17 00:00:00 2001 From: Alexandre Bounine Date: Wed, 2 Nov 2011 13:39:15 -0700 Subject: [PATCH 0152/4025] drivers/net/rionet.c: fix ethernet address macros for LE platforms commit e0c87bd95e8dad455c23bc56513af8dcb1737e55 upstream. Modify Ethernet addess macros to be compatible with BE/LE platforms Signed-off-by: Alexandre Bounine Cc: Chul Kim Cc: Kumar Gala Cc: Matt Porter Cc: Li Yang Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/net/rionet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index ca4694e8a58..1f421d73a88 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -88,8 +88,8 @@ static struct rio_dev **rionet_active; #define dev_rionet_capable(dev) \ is_rionet_capable(dev->src_ops, dev->dst_ops) -#define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001) -#define RIONET_GET_DESTID(x) (*(u16 *)(x + 4)) +#define RIONET_MAC_MATCH(x) (!memcmp((x), "\00\01\00\01", 4)) +#define RIONET_GET_DESTID(x) ((*((u8 *)x + 4) << 8) | *((u8 *)x + 5)) static int rionet_rx_clean(struct net_device *ndev) { From b323615a633b4ac47834844f330f9cc329aeaf2b Mon Sep 17 00:00:00 2001 From: Juan Gutierrez Date: Tue, 6 Sep 2011 09:30:16 +0300 Subject: [PATCH 0153/4025] hwspinlock/core: use a mutex to protect the radix tree commit 93b465c2e186d96fb90012ba0f9372eb9952e732 upstream. Since we're using non-atomic radix tree allocations, we should be protecting the tree using a mutex and not a spinlock. Non-atomic allocations and process context locking is good enough, as the tree is manipulated only when locks are registered/ unregistered/requested/freed. The locks themselves are still protected by spinlocks of course, and mutexes are not involved in the locking/unlocking paths. Signed-off-by: Juan Gutierrez [ohad@wizery.com: rewrite the commit log, #include mutex.h, add minor commentary] [ohad@wizery.com: update register/unregister parts in hwspinlock.txt] Signed-off-by: Ohad Ben-Cohen Signed-off-by: Greg Kroah-Hartman --- Documentation/hwspinlock.txt | 18 +++++------ drivers/hwspinlock/hwspinlock_core.c | 45 +++++++++++++--------------- 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/Documentation/hwspinlock.txt b/Documentation/hwspinlock.txt index 7dcd1a4e726..69966813d59 100644 --- a/Documentation/hwspinlock.txt +++ b/Documentation/hwspinlock.txt @@ -39,23 +39,20 @@ independent, drivers. in case an unused hwspinlock isn't available. Users of this API will usually want to communicate the lock's id to the remote core before it can be used to achieve synchronization. - Can be called from an atomic context (this function will not sleep) but - not from within interrupt context. + Should be called from a process context (might sleep). struct hwspinlock *hwspin_lock_request_specific(unsigned int id); - assign a specific hwspinlock id and return its address, or NULL if that hwspinlock is already in use. Usually board code will be calling this function in order to reserve specific hwspinlock ids for predefined purposes. - Can be called from an atomic context (this function will not sleep) but - not from within interrupt context. + Should be called from a process context (might sleep). int hwspin_lock_free(struct hwspinlock *hwlock); - free a previously-assigned hwspinlock; returns 0 on success, or an appropriate error code on failure (e.g. -EINVAL if the hwspinlock is already free). - Can be called from an atomic context (this function will not sleep) but - not from within interrupt context. + Should be called from a process context (might sleep). int hwspin_lock_timeout(struct hwspinlock *hwlock, unsigned int timeout); - lock a previously-assigned hwspinlock with a timeout limit (specified in @@ -232,15 +229,14 @@ int hwspinlock_example2(void) int hwspin_lock_register(struct hwspinlock *hwlock); - to be called from the underlying platform-specific implementation, in - order to register a new hwspinlock instance. Can be called from an atomic - context (this function will not sleep) but not from within interrupt - context. Returns 0 on success, or appropriate error code on failure. + order to register a new hwspinlock instance. Should be called from + a process context (this function might sleep). + Returns 0 on success, or appropriate error code on failure. struct hwspinlock *hwspin_lock_unregister(unsigned int id); - to be called from the underlying vendor-specific implementation, in order to unregister an existing (and unused) hwspinlock instance. - Can be called from an atomic context (will not sleep) but not from - within interrupt context. + Should be called from a process context (this function might sleep). Returns the address of hwspinlock on success, or NULL on error (e.g. if the hwspinlock is sill in use). diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c index 43a62714b4f..12f7c8300c7 100644 --- a/drivers/hwspinlock/hwspinlock_core.c +++ b/drivers/hwspinlock/hwspinlock_core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include "hwspinlock_internal.h" @@ -52,10 +53,12 @@ static RADIX_TREE(hwspinlock_tree, GFP_KERNEL); /* - * Synchronization of access to the tree is achieved using this spinlock, + * Synchronization of access to the tree is achieved using this mutex, * as the radix-tree API requires that users provide all synchronisation. + * A mutex is needed because we're using non-atomic radix tree allocations. */ -static DEFINE_SPINLOCK(hwspinlock_tree_lock); +static DEFINE_MUTEX(hwspinlock_tree_lock); + /** * __hwspin_trylock() - attempt to lock a specific hwspinlock @@ -261,8 +264,7 @@ EXPORT_SYMBOL_GPL(__hwspin_unlock); * This function should be called from the underlying platform-specific * implementation, to register a new hwspinlock instance. * - * Can be called from an atomic context (will not sleep) but not from - * within interrupt context. + * Should be called from a process context (might sleep) * * Returns 0 on success, or an appropriate error code on failure */ @@ -279,7 +281,7 @@ int hwspin_lock_register(struct hwspinlock *hwlock) spin_lock_init(&hwlock->lock); - spin_lock(&hwspinlock_tree_lock); + mutex_lock(&hwspinlock_tree_lock); ret = radix_tree_insert(&hwspinlock_tree, hwlock->id, hwlock); if (ret) @@ -293,7 +295,7 @@ int hwspin_lock_register(struct hwspinlock *hwlock) WARN_ON(tmp != hwlock); out: - spin_unlock(&hwspinlock_tree_lock); + mutex_unlock(&hwspinlock_tree_lock); return ret; } EXPORT_SYMBOL_GPL(hwspin_lock_register); @@ -305,8 +307,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_register); * This function should be called from the underlying platform-specific * implementation, to unregister an existing (and unused) hwspinlock. * - * Can be called from an atomic context (will not sleep) but not from - * within interrupt context. + * Should be called from a process context (might sleep) * * Returns the address of hwspinlock @id on success, or NULL on failure */ @@ -315,7 +316,7 @@ struct hwspinlock *hwspin_lock_unregister(unsigned int id) struct hwspinlock *hwlock = NULL; int ret; - spin_lock(&hwspinlock_tree_lock); + mutex_lock(&hwspinlock_tree_lock); /* make sure the hwspinlock is not in use (tag is set) */ ret = radix_tree_tag_get(&hwspinlock_tree, id, HWSPINLOCK_UNUSED); @@ -331,7 +332,7 @@ struct hwspinlock *hwspin_lock_unregister(unsigned int id) } out: - spin_unlock(&hwspinlock_tree_lock); + mutex_unlock(&hwspinlock_tree_lock); return hwlock; } EXPORT_SYMBOL_GPL(hwspin_lock_unregister); @@ -400,9 +401,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_get_id); * to the remote core before it can be used for synchronization (to get the * id of a given hwlock, use hwspin_lock_get_id()). * - * Can be called from an atomic context (will not sleep) but not from - * within interrupt context (simply because there is no use case for - * that yet). + * Should be called from a process context (might sleep) * * Returns the address of the assigned hwspinlock, or NULL on error */ @@ -411,7 +410,7 @@ struct hwspinlock *hwspin_lock_request(void) struct hwspinlock *hwlock; int ret; - spin_lock(&hwspinlock_tree_lock); + mutex_lock(&hwspinlock_tree_lock); /* look for an unused lock */ ret = radix_tree_gang_lookup_tag(&hwspinlock_tree, (void **)&hwlock, @@ -431,7 +430,7 @@ struct hwspinlock *hwspin_lock_request(void) hwlock = NULL; out: - spin_unlock(&hwspinlock_tree_lock); + mutex_unlock(&hwspinlock_tree_lock); return hwlock; } EXPORT_SYMBOL_GPL(hwspin_lock_request); @@ -445,9 +444,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_request); * Usually early board code will be calling this function in order to * reserve specific hwspinlock ids for predefined purposes. * - * Can be called from an atomic context (will not sleep) but not from - * within interrupt context (simply because there is no use case for - * that yet). + * Should be called from a process context (might sleep) * * Returns the address of the assigned hwspinlock, or NULL on error */ @@ -456,7 +453,7 @@ struct hwspinlock *hwspin_lock_request_specific(unsigned int id) struct hwspinlock *hwlock; int ret; - spin_lock(&hwspinlock_tree_lock); + mutex_lock(&hwspinlock_tree_lock); /* make sure this hwspinlock exists */ hwlock = radix_tree_lookup(&hwspinlock_tree, id); @@ -482,7 +479,7 @@ struct hwspinlock *hwspin_lock_request_specific(unsigned int id) hwlock = NULL; out: - spin_unlock(&hwspinlock_tree_lock); + mutex_unlock(&hwspinlock_tree_lock); return hwlock; } EXPORT_SYMBOL_GPL(hwspin_lock_request_specific); @@ -495,9 +492,7 @@ EXPORT_SYMBOL_GPL(hwspin_lock_request_specific); * Should only be called with an @hwlock that was retrieved from * an earlier call to omap_hwspin_lock_request{_specific}. * - * Can be called from an atomic context (will not sleep) but not from - * within interrupt context (simply because there is no use case for - * that yet). + * Should be called from a process context (might sleep) * * Returns 0 on success, or an appropriate error code on failure */ @@ -511,7 +506,7 @@ int hwspin_lock_free(struct hwspinlock *hwlock) return -EINVAL; } - spin_lock(&hwspinlock_tree_lock); + mutex_lock(&hwspinlock_tree_lock); /* make sure the hwspinlock is used */ ret = radix_tree_tag_get(&hwspinlock_tree, hwlock->id, @@ -538,7 +533,7 @@ int hwspin_lock_free(struct hwspinlock *hwlock) module_put(hwlock->owner); out: - spin_unlock(&hwspinlock_tree_lock); + mutex_unlock(&hwspinlock_tree_lock); return ret; } EXPORT_SYMBOL_GPL(hwspin_lock_free); From 24e53017e03e9b70765cd244c5304cee4e3ef38b Mon Sep 17 00:00:00 2001 From: Clifton Barnes Date: Wed, 2 Nov 2011 13:39:50 -0700 Subject: [PATCH 0154/4025] drivers/power/ds2780_battery.c: create central point for calling w1 interface commit 853eee72f74f449797f0500ea19fc1bf497428d8 upstream. Simply creates one point to call the w1 interface. Signed-off-by: Clifton Barnes Cc: Evgeniy Polyakov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/power/ds2780_battery.c | 77 ++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/drivers/power/ds2780_battery.c b/drivers/power/ds2780_battery.c index 1fefe82e12e..2571b414378 100644 --- a/drivers/power/ds2780_battery.c +++ b/drivers/power/ds2780_battery.c @@ -49,8 +49,8 @@ enum current_types { static const char model[] = "DS2780"; static const char manufacturer[] = "Maxim/Dallas"; -static inline struct ds2780_device_info *to_ds2780_device_info( - struct power_supply *psy) +static inline struct ds2780_device_info * +to_ds2780_device_info(struct power_supply *psy) { return container_of(psy, struct ds2780_device_info, bat); } @@ -60,17 +60,25 @@ static inline struct power_supply *to_power_supply(struct device *dev) return dev_get_drvdata(dev); } -static inline int ds2780_read8(struct device *dev, u8 *val, int addr) +static inline int ds2780_battery_io(struct ds2780_device_info *dev_info, + char *buf, int addr, size_t count, int io) { - return w1_ds2780_io(dev, val, addr, sizeof(u8), 0); + return w1_ds2780_io(dev_info->w1_dev, buf, addr, count, io); } -static int ds2780_read16(struct device *dev, s16 *val, int addr) +static inline int ds2780_read8(struct ds2780_device_info *dev_info, u8 *val, + int addr) +{ + return ds2780_battery_io(dev_info, val, addr, sizeof(u8), 0); +} + +static int ds2780_read16(struct ds2780_device_info *dev_info, s16 *val, + int addr) { int ret; u8 raw[2]; - ret = w1_ds2780_io(dev, raw, addr, sizeof(u8) * 2, 0); + ret = ds2780_battery_io(dev_info, raw, addr, sizeof(raw), 0); if (ret < 0) return ret; @@ -79,16 +87,16 @@ static int ds2780_read16(struct device *dev, s16 *val, int addr) return 0; } -static inline int ds2780_read_block(struct device *dev, u8 *val, int addr, - size_t count) +static inline int ds2780_read_block(struct ds2780_device_info *dev_info, + u8 *val, int addr, size_t count) { - return w1_ds2780_io(dev, val, addr, count, 0); + return ds2780_battery_io(dev_info, val, addr, count, 0); } -static inline int ds2780_write(struct device *dev, u8 *val, int addr, - size_t count) +static inline int ds2780_write(struct ds2780_device_info *dev_info, u8 *val, + int addr, size_t count) { - return w1_ds2780_io(dev, val, addr, count, 1); + return ds2780_battery_io(dev_info, val, addr, count, 1); } static inline int ds2780_store_eeprom(struct device *dev, int addr) @@ -122,7 +130,7 @@ static int ds2780_set_sense_register(struct ds2780_device_info *dev_info, { int ret; - ret = ds2780_write(dev_info->w1_dev, &conductance, + ret = ds2780_write(dev_info, &conductance, DS2780_RSNSP_REG, sizeof(u8)); if (ret < 0) return ret; @@ -134,7 +142,7 @@ static int ds2780_set_sense_register(struct ds2780_device_info *dev_info, static int ds2780_get_rsgain_register(struct ds2780_device_info *dev_info, u16 *rsgain) { - return ds2780_read16(dev_info->w1_dev, rsgain, DS2780_RSGAIN_MSB_REG); + return ds2780_read16(dev_info, rsgain, DS2780_RSGAIN_MSB_REG); } /* Set RSGAIN value from 0 to 1.999 in steps of 0.001 */ @@ -144,8 +152,8 @@ static int ds2780_set_rsgain_register(struct ds2780_device_info *dev_info, int ret; u8 raw[] = {rsgain >> 8, rsgain & 0xFF}; - ret = ds2780_write(dev_info->w1_dev, raw, - DS2780_RSGAIN_MSB_REG, sizeof(u8) * 2); + ret = ds2780_write(dev_info, raw, + DS2780_RSGAIN_MSB_REG, sizeof(raw)); if (ret < 0) return ret; @@ -167,7 +175,7 @@ static int ds2780_get_voltage(struct ds2780_device_info *dev_info, * Bits 2 - 0 of the voltage value are in bits 7 - 5 of the * voltage LSB register */ - ret = ds2780_read16(dev_info->w1_dev, &voltage_raw, + ret = ds2780_read16(dev_info, &voltage_raw, DS2780_VOLT_MSB_REG); if (ret < 0) return ret; @@ -196,7 +204,7 @@ static int ds2780_get_temperature(struct ds2780_device_info *dev_info, * Bits 2 - 0 of the temperature value are in bits 7 - 5 of the * temperature LSB register */ - ret = ds2780_read16(dev_info->w1_dev, &temperature_raw, + ret = ds2780_read16(dev_info, &temperature_raw, DS2780_TEMP_MSB_REG); if (ret < 0) return ret; @@ -222,13 +230,13 @@ static int ds2780_get_current(struct ds2780_device_info *dev_info, * The units of measurement for current are dependent on the value of * the sense resistor. */ - ret = ds2780_read8(dev_info->w1_dev, &sense_res_raw, DS2780_RSNSP_REG); + ret = ds2780_read8(dev_info, &sense_res_raw, DS2780_RSNSP_REG); if (ret < 0) return ret; if (sense_res_raw == 0) { dev_err(dev_info->dev, "sense resistor value is 0\n"); - return -ENXIO; + return -EINVAL; } sense_res = 1000 / sense_res_raw; @@ -248,7 +256,7 @@ static int ds2780_get_current(struct ds2780_device_info *dev_info, * Bits 7 - 0 of the current value are in bits 7 - 0 of the current * LSB register */ - ret = ds2780_read16(dev_info->w1_dev, ¤t_raw, reg_msb); + ret = ds2780_read16(dev_info, ¤t_raw, reg_msb); if (ret < 0) return ret; @@ -267,7 +275,7 @@ static int ds2780_get_accumulated_current(struct ds2780_device_info *dev_info, * The units of measurement for accumulated current are dependent on * the value of the sense resistor. */ - ret = ds2780_read8(dev_info->w1_dev, &sense_res_raw, DS2780_RSNSP_REG); + ret = ds2780_read8(dev_info, &sense_res_raw, DS2780_RSNSP_REG); if (ret < 0) return ret; @@ -285,7 +293,7 @@ static int ds2780_get_accumulated_current(struct ds2780_device_info *dev_info, * Bits 7 - 0 of the ACR value are in bits 7 - 0 of the ACR * LSB register */ - ret = ds2780_read16(dev_info->w1_dev, ¤t_raw, DS2780_ACR_MSB_REG); + ret = ds2780_read16(dev_info, ¤t_raw, DS2780_ACR_MSB_REG); if (ret < 0) return ret; @@ -299,7 +307,7 @@ static int ds2780_get_capacity(struct ds2780_device_info *dev_info, int ret; u8 raw; - ret = ds2780_read8(dev_info->w1_dev, &raw, DS2780_RARC_REG); + ret = ds2780_read8(dev_info, &raw, DS2780_RARC_REG); if (ret < 0) return ret; @@ -345,7 +353,7 @@ static int ds2780_get_charge_now(struct ds2780_device_info *dev_info, * Bits 7 - 0 of the RAAC value are in bits 7 - 0 of the RAAC * LSB register */ - ret = ds2780_read16(dev_info->w1_dev, &charge_raw, DS2780_RAAC_MSB_REG); + ret = ds2780_read16(dev_info, &charge_raw, DS2780_RAAC_MSB_REG); if (ret < 0) return ret; @@ -356,7 +364,7 @@ static int ds2780_get_charge_now(struct ds2780_device_info *dev_info, static int ds2780_get_control_register(struct ds2780_device_info *dev_info, u8 *control_reg) { - return ds2780_read8(dev_info->w1_dev, control_reg, DS2780_CONTROL_REG); + return ds2780_read8(dev_info, control_reg, DS2780_CONTROL_REG); } static int ds2780_set_control_register(struct ds2780_device_info *dev_info, @@ -364,7 +372,7 @@ static int ds2780_set_control_register(struct ds2780_device_info *dev_info, { int ret; - ret = ds2780_write(dev_info->w1_dev, &control_reg, + ret = ds2780_write(dev_info, &control_reg, DS2780_CONTROL_REG, sizeof(u8)); if (ret < 0) return ret; @@ -503,7 +511,7 @@ static ssize_t ds2780_get_sense_resistor_value(struct device *dev, struct power_supply *psy = to_power_supply(dev); struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); - ret = ds2780_read8(dev_info->w1_dev, &sense_resistor, DS2780_RSNSP_REG); + ret = ds2780_read8(dev_info, &sense_resistor, DS2780_RSNSP_REG); if (ret < 0) return ret; @@ -584,7 +592,7 @@ static ssize_t ds2780_get_pio_pin(struct device *dev, struct power_supply *psy = to_power_supply(dev); struct ds2780_device_info *dev_info = to_ds2780_device_info(psy); - ret = ds2780_read8(dev_info->w1_dev, &sfr, DS2780_SFR_REG); + ret = ds2780_read8(dev_info, &sfr, DS2780_SFR_REG); if (ret < 0) return ret; @@ -611,7 +619,7 @@ static ssize_t ds2780_set_pio_pin(struct device *dev, return -EINVAL; } - ret = ds2780_write(dev_info->w1_dev, &new_setting, + ret = ds2780_write(dev_info, &new_setting, DS2780_SFR_REG, sizeof(u8)); if (ret < 0) return ret; @@ -632,7 +640,7 @@ static ssize_t ds2780_read_param_eeprom_bin(struct file *filp, DS2780_EEPROM_BLOCK1_END - DS2780_EEPROM_BLOCK1_START + 1 - off); - return ds2780_read_block(dev_info->w1_dev, buf, + return ds2780_read_block(dev_info, buf, DS2780_EEPROM_BLOCK1_START + off, count); } @@ -650,7 +658,7 @@ static ssize_t ds2780_write_param_eeprom_bin(struct file *filp, DS2780_EEPROM_BLOCK1_END - DS2780_EEPROM_BLOCK1_START + 1 - off); - ret = ds2780_write(dev_info->w1_dev, buf, + ret = ds2780_write(dev_info, buf, DS2780_EEPROM_BLOCK1_START + off, count); if (ret < 0) return ret; @@ -685,9 +693,8 @@ static ssize_t ds2780_read_user_eeprom_bin(struct file *filp, DS2780_EEPROM_BLOCK0_END - DS2780_EEPROM_BLOCK0_START + 1 - off); - return ds2780_read_block(dev_info->w1_dev, buf, + return ds2780_read_block(dev_info, buf, DS2780_EEPROM_BLOCK0_START + off, count); - } static ssize_t ds2780_write_user_eeprom_bin(struct file *filp, @@ -704,7 +711,7 @@ static ssize_t ds2780_write_user_eeprom_bin(struct file *filp, DS2780_EEPROM_BLOCK0_END - DS2780_EEPROM_BLOCK0_START + 1 - off); - ret = ds2780_write(dev_info->w1_dev, buf, + ret = ds2780_write(dev_info, buf, DS2780_EEPROM_BLOCK0_START + off, count); if (ret < 0) return ret; From 101884f69106faf7c76602ad6fd12eac388b64b8 Mon Sep 17 00:00:00 2001 From: Clifton Barnes Date: Wed, 2 Nov 2011 13:39:52 -0700 Subject: [PATCH 0155/4025] drivers/power/ds2780_battery.c: add a nolock function to w1 interface commit 9fe678fa2feb4aaac0b4220de63e1b7f8ccebae6 upstream. Adds a nolock function to the w1 interface to avoid locking the mutex if needed. Signed-off-by: Clifton Barnes Cc: Evgeniy Polyakov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/w1/slaves/w1_ds2780.c | 48 +++++++++++++++++++++++++---------- drivers/w1/slaves/w1_ds2780.h | 2 ++ 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/drivers/w1/slaves/w1_ds2780.c b/drivers/w1/slaves/w1_ds2780.c index 274c8f38303..505b17d8c67 100644 --- a/drivers/w1/slaves/w1_ds2780.c +++ b/drivers/w1/slaves/w1_ds2780.c @@ -26,20 +26,14 @@ #include "../w1_family.h" #include "w1_ds2780.h" -int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count, - int io) +static int w1_ds2780_do_io(struct device *dev, char *buf, int addr, + size_t count, int io) { struct w1_slave *sl = container_of(dev, struct w1_slave, dev); - if (!dev) - return -ENODEV; + if (addr > DS2780_DATA_SIZE || addr < 0) + return 0; - mutex_lock(&sl->master->mutex); - - if (addr > DS2780_DATA_SIZE || addr < 0) { - count = 0; - goto out; - } count = min_t(int, count, DS2780_DATA_SIZE - addr); if (w1_reset_select_slave(sl) == 0) { @@ -47,7 +41,6 @@ int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count, w1_write_8(sl->master, W1_DS2780_WRITE_DATA); w1_write_8(sl->master, addr); w1_write_block(sl->master, buf, count); - /* XXX w1_write_block returns void, not n_written */ } else { w1_write_8(sl->master, W1_DS2780_READ_DATA); w1_write_8(sl->master, addr); @@ -55,13 +48,42 @@ int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count, } } -out: + return count; +} + +int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count, + int io) +{ + struct w1_slave *sl = container_of(dev, struct w1_slave, dev); + int ret; + + if (!dev) + return -ENODEV; + + mutex_lock(&sl->master->mutex); + + ret = w1_ds2780_do_io(dev, buf, addr, count, io); + mutex_unlock(&sl->master->mutex); - return count; + return ret; } EXPORT_SYMBOL(w1_ds2780_io); +int w1_ds2780_io_nolock(struct device *dev, char *buf, int addr, size_t count, + int io) +{ + int ret; + + if (!dev) + return -ENODEV; + + ret = w1_ds2780_do_io(dev, buf, addr, count, io); + + return ret; +} +EXPORT_SYMBOL(w1_ds2780_io_nolock); + int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd) { struct w1_slave *sl = container_of(dev, struct w1_slave, dev); diff --git a/drivers/w1/slaves/w1_ds2780.h b/drivers/w1/slaves/w1_ds2780.h index a1fba79eb1b..73737936502 100644 --- a/drivers/w1/slaves/w1_ds2780.h +++ b/drivers/w1/slaves/w1_ds2780.h @@ -124,6 +124,8 @@ extern int w1_ds2780_io(struct device *dev, char *buf, int addr, size_t count, int io); +extern int w1_ds2780_io_nolock(struct device *dev, char *buf, int addr, + size_t count, int io); extern int w1_ds2780_eeprom_cmd(struct device *dev, int addr, int cmd); #endif /* !_W1_DS2780_H */ From b97cdd64caeac76928c0bac6a844743fa2431200 Mon Sep 17 00:00:00 2001 From: Clifton Barnes Date: Wed, 2 Nov 2011 13:39:55 -0700 Subject: [PATCH 0156/4025] drivers/power/ds2780_battery.c: fix deadlock upon insertion and removal commit 0e053fcbbbc4d945247cb32cad2767b483cb65f8 upstream. Fixes the deadlock when inserting and removing the ds2780. Signed-off-by: Clifton Barnes Cc: Evgeniy Polyakov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/power/ds2780_battery.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/power/ds2780_battery.c b/drivers/power/ds2780_battery.c index 2571b414378..91a783d7236 100644 --- a/drivers/power/ds2780_battery.c +++ b/drivers/power/ds2780_battery.c @@ -39,6 +39,7 @@ struct ds2780_device_info { struct device *dev; struct power_supply bat; struct device *w1_dev; + struct task_struct *mutex_holder; }; enum current_types { @@ -63,6 +64,9 @@ static inline struct power_supply *to_power_supply(struct device *dev) static inline int ds2780_battery_io(struct ds2780_device_info *dev_info, char *buf, int addr, size_t count, int io) { + if (dev_info->mutex_holder == current) + return w1_ds2780_io_nolock(dev_info->w1_dev, buf, addr, count, io); + else return w1_ds2780_io(dev_info->w1_dev, buf, addr, count, io); } @@ -775,6 +779,7 @@ static int __devinit ds2780_battery_probe(struct platform_device *pdev) dev_info->bat.properties = ds2780_battery_props; dev_info->bat.num_properties = ARRAY_SIZE(ds2780_battery_props); dev_info->bat.get_property = ds2780_battery_get_property; + dev_info->mutex_holder = current; ret = power_supply_register(&pdev->dev, &dev_info->bat); if (ret) { @@ -804,6 +809,8 @@ static int __devinit ds2780_battery_probe(struct platform_device *pdev) goto fail_remove_bin_file; } + dev_info->mutex_holder = NULL; + return 0; fail_remove_bin_file: @@ -823,6 +830,8 @@ static int __devexit ds2780_battery_remove(struct platform_device *pdev) { struct ds2780_device_info *dev_info = platform_get_drvdata(pdev); + dev_info->mutex_holder = current; + /* remove attributes */ sysfs_remove_group(&dev_info->bat.dev->kobj, &ds2780_attr_group); From d24f405b711a4247f31358339dc1112ca659e6fe Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 31 Aug 2011 11:54:51 -0400 Subject: [PATCH 0157/4025] ext2,ext3,ext4: don't inherit APPEND_FL or IMMUTABLE_FL for new inodes commit 1cd9f0976aa4606db8d6e3dc3edd0aca8019372a upstream. This doesn't make much sense, and it exposes a bug in the kernel where attempts to create a new file in an append-only directory using O_CREAT will fail (but still leave a zero-length file). This was discovered when xfstests #79 was generalized so it could run on all file systems. Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ext4.h | 3 +-- include/linux/ext2_fs.h | 4 ++-- include/linux/ext3_fs.h | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 354619a1aed..4bc683806ea 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -357,8 +357,7 @@ struct flex_groups { /* Flags that should be inherited by new inodes from their parent. */ #define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\ - EXT4_SYNC_FL | EXT4_IMMUTABLE_FL | EXT4_APPEND_FL |\ - EXT4_NODUMP_FL | EXT4_NOATIME_FL |\ + EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\ EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\ EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL) diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h index 2dfa7076e8b..0bfcb76bf95 100644 --- a/include/linux/ext2_fs.h +++ b/include/linux/ext2_fs.h @@ -196,8 +196,8 @@ struct ext2_group_desc /* Flags that should be inherited by new inodes from their parent. */ #define EXT2_FL_INHERITED (EXT2_SECRM_FL | EXT2_UNRM_FL | EXT2_COMPR_FL |\ - EXT2_SYNC_FL | EXT2_IMMUTABLE_FL | EXT2_APPEND_FL |\ - EXT2_NODUMP_FL | EXT2_NOATIME_FL | EXT2_COMPRBLK_FL|\ + EXT2_SYNC_FL | EXT2_NODUMP_FL |\ + EXT2_NOATIME_FL | EXT2_COMPRBLK_FL |\ EXT2_NOCOMP_FL | EXT2_JOURNAL_DATA_FL |\ EXT2_NOTAIL_FL | EXT2_DIRSYNC_FL) diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h index 5e06acf95d0..7b14d251c78 100644 --- a/include/linux/ext3_fs.h +++ b/include/linux/ext3_fs.h @@ -180,8 +180,8 @@ struct ext3_group_desc /* Flags that should be inherited by new inodes from their parent. */ #define EXT3_FL_INHERITED (EXT3_SECRM_FL | EXT3_UNRM_FL | EXT3_COMPR_FL |\ - EXT3_SYNC_FL | EXT3_IMMUTABLE_FL | EXT3_APPEND_FL |\ - EXT3_NODUMP_FL | EXT3_NOATIME_FL | EXT3_COMPRBLK_FL|\ + EXT3_SYNC_FL | EXT3_NODUMP_FL |\ + EXT3_NOATIME_FL | EXT3_COMPRBLK_FL |\ EXT3_NOCOMPR_FL | EXT3_JOURNAL_DATA_FL |\ EXT3_NOTAIL_FL | EXT3_DIRSYNC_FL) From a848dee39f54f1eb9d9b90ef172ec4e813815e21 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 31 Aug 2011 11:58:51 -0400 Subject: [PATCH 0158/4025] ext4: ext4_rename should dirty dir_bh with the correct directory commit bcaa992975041e40449be8c010c26192b8c8b409 upstream. When ext4_rename performs a directory rename (move), dir_bh is a buffer that is modified to update the '..' link in the directory being moved (old_inode). However, ext4_handle_dirty_metadata is called with the old parent directory inode (old_dir) and dir_bh, which is incorrect because dir_bh does not belong to the parent inode. Fix this error. Signed-off-by: Darrick J. Wong Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 458a394f6d3..92875a41f51 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2540,7 +2540,7 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) = cpu_to_le32(new_dir->i_ino); BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata"); - retval = ext4_handle_dirty_metadata(handle, old_dir, dir_bh); + retval = ext4_handle_dirty_metadata(handle, old_inode, dir_bh); if (retval) { ext4_std_error(old_dir->i_sb, retval); goto end_rename; From 37915713a96e05b5d731b9457a0cf22ced00f36f Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 31 Aug 2011 12:00:51 -0400 Subject: [PATCH 0159/4025] ext4: ext4_mkdir should dirty dir_block with newly created directory inode commit f9287c1f2d329f4d78a3bbc9cf0db0ebae6f146a upstream. ext4_mkdir calls ext4_handle_dirty_metadata with dir_block and the inode "dir". Unfortunately, dir_block belongs to the newly created directory (which is "inode"), not the parent directory (which is "dir"). Fix the incorrect association. Signed-off-by: Darrick J. Wong Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 92875a41f51..b1fba2c8c18 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1866,7 +1866,7 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, int mode) ext4_set_de_type(dir->i_sb, de, S_IFDIR); inode->i_nlink = 2; BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_metadata(handle, dir, dir_block); + err = ext4_handle_dirty_metadata(handle, inode, dir_block); if (err) goto out_clear_inode; err = ext4_mark_inode_dirty(handle, inode); From 3c607445bbf6ff07c755656df331069d753569ea Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 31 Aug 2011 12:02:51 -0400 Subject: [PATCH 0160/4025] ext4: call ext4_handle_dirty_metadata with correct inode in ext4_dx_add_entry commit 5930ea643805feb50a2f8383ae12eb6f10935e49 upstream. ext4_dx_add_entry manipulates bh2 and frames[0].bh, which are two buffer_heads that point to directory blocks assigned to the directory inode. However, the function calls ext4_handle_dirty_metadata with the inode of the file that's being added to the directory, not the directory inode itself. Therefore, correct the code to dirty the directory buffers with the directory inode, not the file inode. Signed-off-by: Darrick J. Wong Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/namei.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index b1fba2c8c18..3d36d5a1e19 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1589,7 +1589,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, dxtrace(dx_show_index("node", frames[1].entries)); dxtrace(dx_show_index("node", ((struct dx_node *) bh2->b_data)->entries)); - err = ext4_handle_dirty_metadata(handle, inode, bh2); + err = ext4_handle_dirty_metadata(handle, dir, bh2); if (err) goto journal_error; brelse (bh2); @@ -1615,7 +1615,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry, if (err) goto journal_error; } - err = ext4_handle_dirty_metadata(handle, inode, frames[0].bh); + err = ext4_handle_dirty_metadata(handle, dir, frames[0].bh); if (err) { ext4_std_error(inode->i_sb, err); goto cleanup; From 628ee980d92cd25b8b794af59823fb93090500c3 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Sat, 29 Oct 2011 10:15:35 -0400 Subject: [PATCH 0161/4025] ext4: fix race in xattr block allocation path commit 6d6a435190bdf2e04c9465cde5bdc3ac68cf11a4 upstream. Ceph users reported that when using Ceph on ext4, the filesystem would often become corrupted, containing inodes with incorrect i_blocks counters. I managed to reproduce this with a very hacked-up "streamtest" binary from the Ceph tree. Ceph is doing a lot of xattr writes, to out-of-inode blocks. There is also another thread which does sync_file_range and close, of the same files. The problem appears to happen due to this race: sync/flush thread xattr-set thread ----------------- ---------------- do_writepages ext4_xattr_set ext4_da_writepages ext4_xattr_set_handle mpage_da_map_blocks ext4_xattr_block_set set DELALLOC_RESERVE ext4_new_meta_blocks ext4_mb_new_blocks if (!i_delalloc_reserved_flag) vfs_dq_alloc_block ext4_get_blocks down_write(i_data_sem) set i_delalloc_reserved_flag ... up_write(i_data_sem) if (i_delalloc_reserved_flag) vfs_dq_alloc_block_nofail In other words, the sync/flush thread pops in and sets i_delalloc_reserved_flag on the inode, which makes the xattr thread think that it's in a delalloc path in ext4_new_meta_blocks(), and add the block for a second time, after already having added it once in the !i_delalloc_reserved_flag case in ext4_mb_new_blocks The real problem is that we shouldn't be using the DELALLOC_RESERVED state flag, and instead we should be passing EXT4_GET_BLOCKS_DELALLOC_RESERVE down to ext4_map_blocks() instead of using an inode state flag. We'll fix this for now with using i_data_sem to prevent this race, but this is really not the right way to fix things. Signed-off-by: Eric Sandeen Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/xattr.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index c757adc9725..19fe4e3d39e 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -820,8 +820,14 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) goal = goal & EXT4_MAX_BLOCK_FILE_PHYS; + /* + * take i_data_sem because we will test + * i_delalloc_reserved_flag in ext4_mb_new_blocks + */ + down_read((&EXT4_I(inode)->i_data_sem)); block = ext4_new_meta_blocks(handle, inode, goal, 0, NULL, &error); + up_read((&EXT4_I(inode)->i_data_sem)); if (error) goto cleanup; From c3db5c3702bfc283b3ea65dc1ebbf256e688baee Mon Sep 17 00:00:00 2001 From: Vasanthy Kolluri Date: Thu, 9 Jun 2011 10:37:07 +0000 Subject: [PATCH 0162/4025] enic: Bug Fix: Fix hardware transmit queue indexing in enic_poll_controller commit b880a954b9e2585ce325aedd76e4741880cab180 upstream. Signed-off-by: Christian Benvenuti Signed-off-by: Danny Guo Signed-off-by: Vasanthy Kolluri Signed-off-by: Roopa Prabhu Signed-off-by: David Wang Signed-off-by: David S. Miller Cc: Chun-Yi Lee Signed-off-by: Greg Kroah-Hartman --- drivers/net/enic/enic_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 2f433fbfca0..51fba5fe94b 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1718,8 +1718,12 @@ static void enic_poll_controller(struct net_device *netdev) enic_isr_msix_rq(enic->msix_entry[intr].vector, &enic->napi[i]); } - intr = enic_msix_wq_intr(enic, i); - enic_isr_msix_wq(enic->msix_entry[intr].vector, enic); + + for (i = 0; i < enic->wq_count; i++) { + intr = enic_msix_wq_intr(enic, i); + enic_isr_msix_wq(enic->msix_entry[intr].vector, enic); + } + break; case VNIC_DEV_INTR_MODE_MSI: enic_isr_msi(enic->pdev->irq, enic); From cfaef012006eddcba833b33cb7953a68b36869c6 Mon Sep 17 00:00:00 2001 From: huajun li Date: Sun, 7 Aug 2011 03:03:31 +0000 Subject: [PATCH 0163/4025] rtl8150: rtl8150_disconnect(...) does not need tasklet_disable(...) commit c2e2a313ff8fdc25cedef5e63da712a6a0d35dfe upstream. Executing cmd 'rmmod rtl8150' does not return(if your device connects to host), the root cause is tasklet_disable() causes tasklet_kill() block, remove it from rtl8150_disconnect(). Signed-off-by: Huajun Li Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/rtl8150.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 041fb7d43c4..ef3b236b514 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -977,7 +977,6 @@ static void rtl8150_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); if (dev) { set_bit(RTL8150_UNPLUG, &dev->flags); - tasklet_disable(&dev->tl); tasklet_kill(&dev->tl); unregister_netdev(dev->netdev); unlink_all_urbs(dev); From 00c37d53fdc0f671cc07228e0faf1938da741e68 Mon Sep 17 00:00:00 2001 From: Boris Todorov Date: Mon, 11 Jul 2011 12:03:33 +0300 Subject: [PATCH 0164/4025] USB: EHCI: Fix test mode sequence commit 77636c86a600b83de01719efad83567e46d7e8ce upstream. The sequence to put port in test mode is not complete. According EHCI specification all enabled ports must be put in suspend. Signed-off-by: Boris Todorov Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hub.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 0f3a7248008..f5d7fed4a4c 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -1120,7 +1120,19 @@ static int ehci_hub_control ( if (!selector || selector > 5) goto error; ehci_quiesce(ehci); + + /* Put all enabled ports into suspend */ + while (ports--) { + u32 __iomem *sreg = + &ehci->regs->port_status[ports]; + + temp = ehci_readl(ehci, sreg) & ~PORT_RWC_BITS; + if (temp & PORT_PE) + ehci_writel(ehci, temp | PORT_SUSPEND, + sreg); + } ehci_halt(ehci); + temp = ehci_readl(ehci, status_reg); temp |= selector << 16; ehci_writel(ehci, temp, status_reg); break; From e530d1a21e5c2fe3202b2fdf2f0b61100c12c70e Mon Sep 17 00:00:00 2001 From: Arvid Brodin Date: Wed, 20 Jul 2011 03:13:46 +0200 Subject: [PATCH 0165/4025] usb/isp1760: Added missing call to usb_hcd_check_unlink_urb() during unlink commit 17d3e145a4ad680b3d1b1c30d0696a5bbb2b65c4 upstream. Signed-off-by: Arvid Brodin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/isp1760-hcd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 55d3d5859ac..840beda66dd 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -1583,6 +1583,9 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int retval = 0; spin_lock_irqsave(&priv->lock, spinflags); + retval = usb_hcd_check_unlink_urb(hcd, urb, status); + if (retval) + goto out; qh = urb->ep->hcpriv; if (!qh) { From 5be5de4dfc6715b424207c367dc2ed234b0bd6ce Mon Sep 17 00:00:00 2001 From: Florian Echtler Date: Tue, 9 Aug 2011 13:37:49 +0200 Subject: [PATCH 0166/4025] USB: Serial: Add device ID for Sierra Wireless MC8305 commit 2f1def2695c223b2aa325e5e47d0d64200a45d23 upstream. A new device ID pair is added for Sierra Wireless MC8305. Signed-off-by: Florian Echtler Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/qcserial.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 7ec639860c5..b9bb24729c9 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -80,6 +80,7 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x1199, 0x9008)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ {USB_DEVICE(0x1199, 0x9009)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ {USB_DEVICE(0x1199, 0x900a)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ + {USB_DEVICE(0x1199, 0x9011)}, /* Sierra Wireless Gobi 2000 Modem device (MC8305) */ {USB_DEVICE(0x16d8, 0x8001)}, /* CMDTech Gobi 2000 QDL device (VU922) */ {USB_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ {USB_DEVICE(0x05c6, 0x9204)}, /* Gobi 2000 QDL device */ From 510c6bcea7b81acf7c86d2d72944ed516223fcbb Mon Sep 17 00:00:00 2001 From: Artur Zimmer Date: Wed, 10 Aug 2011 03:51:28 +0200 Subject: [PATCH 0167/4025] USB: Serial: Add PID(0xF7C0) to FTDI SIO driver for a zeitcontrol-device commit ce7e9065958191e6b7ca49d7ed0e1099c486d198 upstream. Here is a patch for a new PID (zeitcontrol-device mifare-reader FT232BL(like FT232BM but lead free)). Signed-off-by: Artur Zimmer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 1f7da48a0fb..1b51d43f1da 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -156,6 +156,7 @@ static struct ftdi_sio_quirk ftdi_8u2232c_quirk = { * /sys/bus/usb/ftdi_sio/new_id, then send patch/report! */ static struct usb_device_id id_table_combined [] = { + { USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index f35ee4d1245..571fa96b49c 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1162,4 +1162,8 @@ /* USB-Nano-485*/ #define FTDI_CTI_NANO_PID 0xF60B - +/* + * ZeitControl cardsystems GmbH rfid-readers http://zeitconrol.de + */ +/* TagTracer MIFARE*/ +#define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID 0xF7C0 From 91c193f925d75b03f5a7f31ae1358a87af33c78a Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 8 Aug 2011 02:34:07 +0000 Subject: [PATCH 0168/4025] usbnet/cdc_ncm: Don't use stack variables for DMA commit 75bc8ef528f7c4ea7e80384c5593487b6b3b535e upstream. The cdc_ncm driver still has a few places where stack variables are passed to the cdc_ncm_do_request function. This triggers a stack trace in lib/dma-debug.c if the CONFIG_DEBUG_DMA_API option is set. Adjust these calls to pass parameters that have been allocated with kzalloc. Signed-off-by: Josh Boyer Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/cdc_ncm.c | 47 +++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index d3b9e958db0..6a53161102c 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -229,23 +229,40 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) { if (flags & USB_CDC_NCM_NCAP_NTB_INPUT_SIZE) { - struct usb_cdc_ncm_ndp_input_size ndp_in_sz; + struct usb_cdc_ncm_ndp_input_size *ndp_in_sz; + + ndp_in_sz = kzalloc(sizeof(*ndp_in_sz), GFP_KERNEL); + if (!ndp_in_sz) { + err = -ENOMEM; + goto size_err; + } + err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0), USB_CDC_SET_NTB_INPUT_SIZE, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, - 0, iface_no, &ndp_in_sz, 8, 1000); + 0, iface_no, ndp_in_sz, 8, 1000); + kfree(ndp_in_sz); } else { - __le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max); + __le32 *dwNtbInMaxSize; + dwNtbInMaxSize = kzalloc(sizeof(*dwNtbInMaxSize), + GFP_KERNEL); + if (!dwNtbInMaxSize) { + err = -ENOMEM; + goto size_err; + } + *dwNtbInMaxSize = cpu_to_le32(ctx->rx_max); + err = usb_control_msg(ctx->udev, usb_sndctrlpipe(ctx->udev, 0), USB_CDC_SET_NTB_INPUT_SIZE, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, - 0, iface_no, &dwNtbInMaxSize, 4, 1000); + 0, iface_no, dwNtbInMaxSize, 4, 1000); + kfree(dwNtbInMaxSize); } - +size_err: if (err < 0) pr_debug("Setting NTB Input Size failed\n"); } @@ -326,19 +343,29 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) /* set Max Datagram Size (MTU) */ if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) { - __le16 max_datagram_size; + __le16 *max_datagram_size; u16 eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize); + + max_datagram_size = kzalloc(sizeof(*max_datagram_size), + GFP_KERNEL); + if (!max_datagram_size) { + err = -ENOMEM; + goto max_dgram_err; + } + err = usb_control_msg(ctx->udev, usb_rcvctrlpipe(ctx->udev, 0), USB_CDC_GET_MAX_DATAGRAM_SIZE, USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE, - 0, iface_no, &max_datagram_size, + 0, iface_no, max_datagram_size, 2, 1000); if (err < 0) { pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n", CDC_NCM_MIN_DATAGRAM_SIZE); + kfree(max_datagram_size); } else { - ctx->max_datagram_size = le16_to_cpu(max_datagram_size); + ctx->max_datagram_size = + le16_to_cpu(*max_datagram_size); /* Check Eth descriptor value */ if (eth_max_sz < CDC_NCM_MAX_DATAGRAM_SIZE) { if (ctx->max_datagram_size > eth_max_sz) @@ -361,8 +388,10 @@ static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx) USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE, 0, - iface_no, &max_datagram_size, + iface_no, max_datagram_size, 2, 1000); + kfree(max_datagram_size); +max_dgram_err: if (err < 0) pr_debug("SET_MAX_DATAGRAM_SIZE failed\n"); } From f6fad686650aaf264b2acee848825e2183a944e3 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Tue, 9 Aug 2011 16:31:54 -0700 Subject: [PATCH 0169/4025] USB: Avoid NULL pointer deref in usb_hcd_alloc_bandwidth. commit 8a9af4fdf6d5eeb3200a088354d266a87e8260b0 upstream. usb_ifnum_to_if() can return NULL if the USB device does not have a configuration installed (usb_device->actconfig == NULL), or if we can't find the interface number in the installed configuration. Return an error instead of crashing. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index ace9f8442e5..39ea00bfb9c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1764,6 +1764,8 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev, struct usb_interface *iface = usb_ifnum_to_if(udev, cur_alt->desc.bInterfaceNumber); + if (!iface) + return -EINVAL; if (iface->resetting_device) { /* * The USB core just reset the device, so the xHCI host From 869b18a75765d4f29e26ea8de123608fc9907903 Mon Sep 17 00:00:00 2001 From: Kavan Smith Date: Wed, 31 Aug 2011 05:12:05 +0000 Subject: [PATCH 0170/4025] ipheth: iPhone 4 Verizon CDMA USB Product ID add commit 02009afc223aae43b8e18918fc816e4520791537 upstream. Add USB product ID for iPhone 4 CDMA Verizon Tested on at least 2 devices Signed-off-by: Kavan Smith Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/ipheth.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index 81126ff85e0..8f9b7f76045 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -59,6 +59,7 @@ #define USB_PRODUCT_IPHONE_3G 0x1292 #define USB_PRODUCT_IPHONE_3GS 0x1294 #define USB_PRODUCT_IPHONE_4 0x1297 +#define USB_PRODUCT_IPHONE_4_VZW 0x129c #define IPHETH_USBINTF_CLASS 255 #define IPHETH_USBINTF_SUBCLASS 253 @@ -98,6 +99,10 @@ static struct usb_device_id ipheth_table[] = { USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4, IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, IPHETH_USBINTF_PROTO) }, + { USB_DEVICE_AND_INTERFACE_INFO( + USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, + IPHETH_USBINTF_PROTO) }, { } }; MODULE_DEVICE_TABLE(usb, ipheth_table); From 1a0a3b4ea5782d6f1ca10f3254b56d7be24ec4d0 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Mon, 19 Sep 2011 16:05:12 -0700 Subject: [PATCH 0171/4025] USB: xHCI: prevent infinite loop when processing MSE event commit c2d7b49f42f50d7fc5cbfd195b785a128723fdf4 upstream. When a xHC host is unable to handle isochronous transfer in the interval, it reports a Missed Service Error event and skips some tds. Currently xhci driver handles MSE event in the following ways: 1. When encounter a MSE event, set ep->skip flag, update event ring dequeue pointer and return. 2. When encounter the next event on this ep, the driver will run the do-while loop, fetch td from ep's td_list to find the td corresponding to this event. All tds missed are marked as short transfer(-EXDEV). The do-while loop will end in two ways: 1. If the td pointed by the event trb is found; 2. If the ep ring's td_list is empty. However, if a buggy HW reports some unpredicted event (for example, an overrun event following a MSE event while the ep ring is actually not empty), the driver will never find the td, and it will loop until the td_list is empty. Unfortunately, the spinlock is dropped when give back a urb in the do-while loop. During the spinlock released period, the class driver may still submit urbs and add tds to the td_list. This may cause disaster, since the td_list will never be empty and the loop never ends, and the system hangs. To fix this, count the number of TDs on the ep ring before skipping TDs, and quit the loop when skipped that number of tds. This guarantees the do-while loop will end after certain number of cycles, and driver will not be trapped in an infinite loop. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman Signed-off-by: Linus Torvalds --- drivers/usb/host/xhci-ring.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index e64bd6f9bfb..b68939703a9 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1942,8 +1942,10 @@ static int handle_tx_event(struct xhci_hcd *xhci, int status = -EINPROGRESS; struct urb_priv *urb_priv; struct xhci_ep_ctx *ep_ctx; + struct list_head *tmp; u32 trb_comp_code; int ret = 0; + int td_num = 0; slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); xdev = xhci->devs[slot_id]; @@ -1965,6 +1967,12 @@ static int handle_tx_event(struct xhci_hcd *xhci, return -ENODEV; } + /* Count current td numbers if ep->skip is set */ + if (ep->skip) { + list_for_each(tmp, &ep_ring->td_list) + td_num++; + } + event_dma = le64_to_cpu(event->buffer); trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); /* Look for common error cases */ @@ -2076,7 +2084,18 @@ static int handle_tx_event(struct xhci_hcd *xhci, goto cleanup; } + /* We've skipped all the TDs on the ep ring when ep->skip set */ + if (ep->skip && td_num == 0) { + ep->skip = false; + xhci_dbg(xhci, "All tds on the ep_ring skipped. " + "Clear skip flag.\n"); + ret = 0; + goto cleanup; + } + td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list); + if (ep->skip) + td_num--; /* Is this a TRB in the currently executing TD? */ event_seg = trb_in_td(ep_ring->deq_seg, ep_ring->dequeue, From 611778cd2a87a9b7376994caf4faa0caac9d1037 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 26 Jul 2011 16:44:46 +0000 Subject: [PATCH 0172/4025] ASIX: Simplify condition in rx_fixup() commit bc466e678d0a98f445bf3f9c76fedf18e7dcc6b0 upstream. Signed-off-by: Marek Vasut Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/asix.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index 52502883523..d5b62a46340 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -314,10 +314,9 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) skb_pull(skb, 4); while (skb->len > 0) { - if ((short)(header & 0x0000ffff) != - ~((short)((header & 0xffff0000) >> 16))) { + if ((header & 0xffff) != ((~header >> 16) & 0xffff)) netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); - } + /* get the packet length */ size = (u16) (header & 0x0000ffff); From f7f00215ba28400e0f61c55e14e3d619888231ae Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 26 Jul 2011 16:44:47 +0000 Subject: [PATCH 0173/4025] ASIX: Use only 11 bits of header for data size commit bca0beb9363f8487ac902931a50eb00180a2d14a upstream. The AX88772B uses only 11 bits of the header for the actual size. The other bits are used for something else. This causes dmesg full of messages: asix_rx_fixup() Bad Header Length This patch trims the check to only 11 bits. I believe on older chips, the remaining 5 top bits are unused. Signed-off-by: Marek Vasut Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/asix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index d5b62a46340..c5c4b4def7f 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -314,11 +314,11 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) skb_pull(skb, 4); while (skb->len > 0) { - if ((header & 0xffff) != ((~header >> 16) & 0xffff)) + if ((header & 0x07ff) != ((~header >> 16) & 0x07ff)) netdev_err(dev->net, "asix_rx_fixup() Bad Header Length\n"); /* get the packet length */ - size = (u16) (header & 0x0000ffff); + size = (u16) (header & 0x000007ff); if ((skb->len) - ((size + 1) & 0xfffe) == 0) { u8 alignment = (unsigned long)skb->data & 0x3; From efb1497bcc3a72b1617c6915bb62cf4dfa38c952 Mon Sep 17 00:00:00 2001 From: Pieter-Augustijn Van Malleghem Date: Wed, 7 Sep 2011 02:28:10 -0400 Subject: [PATCH 0174/4025] Bluetooth: Add MacBookAir4,1 support commit a63b723d02531f7add0b2b8a0e6a77ee176f1626 upstream. This patch against current git adds the hardware ID for the Apple MacBookAir4,1, released in July 2011. The device features a BCM2046 USB chip. The patch was inspired by the previous modifications adding support for the MacBookAir3,x. Signed-off-by: Pieter-Augustijn Van Malleghem Signed-off-by: Gustavo F. Padovan Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c2de8951e3f..e5fa4377444 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -71,6 +71,9 @@ static struct usb_device_id btusb_table[] = { /* Apple MacBookAir3,1, MacBookAir3,2 */ { USB_DEVICE(0x05ac, 0x821b) }, + /* Apple MacBookAir4,1 */ + { USB_DEVICE(0x05ac, 0x821f) }, + /* Apple MacBookPro8,2 */ { USB_DEVICE(0x05ac, 0x821a) }, From 39361fcb63d49f4036af08473c503e006e063ddc Mon Sep 17 00:00:00 2001 From: Ricardo Mendoza Date: Wed, 13 Jul 2011 16:04:29 +0100 Subject: [PATCH 0175/4025] Bluetooth: Add Toshiba laptops AR30XX device ID commit 8e7c3d2e4ba18ee4cdcc1f89aec944fbff4ce735 upstream. Blacklist Toshiba-branded AR3011 based AR5B195 [0930:0215] and add to ath3k.c for firmware loading. Signed-off-by: Ricardo Mendoza Signed-off-by: Gustavo F. Padovan Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/ath3k.c | 1 + drivers/bluetooth/btusb.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 6bacef368fa..1631fd05510 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -63,6 +63,7 @@ static struct usb_device_id ath3k_table[] = { /* Atheros AR3011 with sflash firmware*/ { USB_DEVICE(0x0CF3, 0x3002) }, { USB_DEVICE(0x13d3, 0x3304) }, + { USB_DEVICE(0x0930, 0x0215) }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03F0, 0x311D) }, diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index e5fa4377444..b8483ac0c74 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -108,6 +108,7 @@ static struct usb_device_id blacklist_table[] = { /* Atheros 3011 with sflash firmware */ { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE }, /* Atheros AR9285 Malbec with sflash firmware */ { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, From 4770ac2af6255b6c64d290606b54fa2e2bfcbe08 Mon Sep 17 00:00:00 2001 From: "Steven.Li" Date: Fri, 1 Jul 2011 14:02:36 +0800 Subject: [PATCH 0176/4025] Bluetooth: Add Atheros AR3012 one PID/VID supported commit 2d25f8b462f3b849d8913d02978657ef06e67dd8 upstream. The new Ath3k needs to download patch and radio table, and it keeps same PID/VID even after downloading the patch and radio table. This patch is to use the bcdDevice (Device Release Number) to judge whether the chip has been patched or not. The init bcdDevice value of the chip is 0x0001, this value increases after patch and radio table downloading. Signed-off-by: Steven.Li Signed-off-by: Gustavo F. Padovan Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/ath3k.c | 5 +++++ drivers/bluetooth/btusb.c | 12 +++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 1631fd05510..db7cb8111fb 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -376,6 +376,11 @@ static int ath3k_probe(struct usb_interface *intf, /* load patch and sysconfig files for AR3012 */ if (id->driver_info & BTUSB_ATH3012) { + + /* New firmware with patch and sysconfig files already loaded */ + if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x0001) + return -ENODEV; + ret = ath3k_load_patch(udev); if (ret < 0) { BT_ERR("Loading patch file failed"); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b8483ac0c74..97f155e6c44 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -54,6 +54,7 @@ static struct usb_driver btusb_driver; #define BTUSB_BCM92035 0x10 #define BTUSB_BROKEN_ISOC 0x20 #define BTUSB_WRONG_SCO_MTU 0x40 +#define BTUSB_ATH3012 0x80 static struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -114,7 +115,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE }, /* Atheros 3012 with sflash firmware */ - { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, @@ -918,6 +919,15 @@ static int btusb_probe(struct usb_interface *intf, if (ignore_sniffer && id->driver_info & BTUSB_SNIFFER) return -ENODEV; + if (id->driver_info & BTUSB_ATH3012) { + struct usb_device *udev = interface_to_usbdev(intf); + + /* Old firmware would otherwise let ath3k driver load + * patch and sysconfig files */ + if (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x0001) + return -ENODEV; + } + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; From 661a0d9aba272ad9e55449ce8eb9570a221b8489 Mon Sep 17 00:00:00 2001 From: Jurgen Kramer Date: Sun, 4 Sep 2011 18:01:42 +0200 Subject: [PATCH 0177/4025] Bluetooth: add support for 2011 mac mini commit f78b68261e80899f81a21dfdf91e2a1456ea8175 upstream. Today I noticed that the usb bluetooth adapter (BCM2046B1) on my 2011 mac mini was not working. I've created a patch to get it going. Signed-off-by: Jurgen Kramer Signed-off-by: Gustavo F. Padovan Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 97f155e6c44..ffda6c82a54 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -78,6 +78,9 @@ static struct usb_device_id btusb_table[] = { /* Apple MacBookPro8,2 */ { USB_DEVICE(0x05ac, 0x821a) }, + /* Apple MacMini5,1 */ + { USB_DEVICE(0x05ac, 0x8281) }, + /* AVM BlueFRITZ! USB v2.0 */ { USB_DEVICE(0x057c, 0x3800) }, From b710365a9a762cb6cf931a066648daf9a941a9af Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Wed, 21 Sep 2011 11:41:45 +0200 Subject: [PATCH 0178/4025] btusb: add device entry for Broadcom SoftSailing commit c510eae377c773241ff0b6369a8f3581da941a51 upstream. This device declares itself to be vendor specific It therefore needs to be added to the device table to make btusb bind. Signed-off-by: Oliver Neukum Signed-off-by: Gustavo F. Padovan Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index ffda6c82a54..b9af6dbb46d 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -60,6 +60,9 @@ static struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ { USB_DEVICE_INFO(0xe0, 0x01, 0x01) }, + /* Broadcom SoftSailing reporting vendor specific */ + { USB_DEVICE(0x05ac, 0x21e1) }, + /* Apple MacBookPro 7,1 */ { USB_DEVICE(0x05ac, 0x8213) }, From 6eb006c6079fd54a260caf7dfb3c750f65f4b1fc Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Tue, 26 Jul 2011 09:56:07 -0500 Subject: [PATCH 0179/4025] usb_storage: Don't freeze in usb-stor-scan commit f02fe890ece7d695a5744b20525d45312382e6e4 upstream. Scanning cannot be run during suspend or hibernation, but if usb-stor-scan freezes another thread waiting on scanning to complete may fail to freeze. However, if usb-stor-scan is left freezable without ever actually freezing then the freezer will wait on it to exit, and threads waiting for scanning to finish will no longer be blocked. One problem with this approach is that usb-stor-scan has a delay to wait for devices to settle (which is currently the only point where it can freeze). To work around this we can request that the freezer send a fake signal when freezing, then use interruptible sleep to wake the thread early when freezing happens. To make this happen, the following changes are made to usb-stor-scan: * Use set_freezable_with_signal() instead of set_freezable() to request a fake signal when freezing * Use wait_event_interruptible_timeout() instead of wait_event_freezable_timeout() to avoid freezing Signed-off-by: Seth Forshee Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 0ca095820f3..c325e69415a 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -831,12 +831,22 @@ static int usb_stor_scan_thread(void * __us) dev_dbg(dev, "device found\n"); - set_freezable(); - /* Wait for the timeout to expire or for a disconnect */ + set_freezable_with_signal(); + /* + * Wait for the timeout to expire or for a disconnect + * + * We can't freeze in this thread or we risk causing khubd to + * fail to freeze, but we can't be non-freezable either. Nor can + * khubd freeze while waiting for scanning to complete as it may + * hold the device lock, causing a hang when suspending devices. + * So we request a fake signal when freezing and use + * interruptible sleep to kick us out of our wait early when + * freezing happens. + */ if (delay_use > 0) { dev_dbg(dev, "waiting for device to settle " "before scanning\n"); - wait_event_freezable_timeout(us->delay_wait, + wait_event_interruptible_timeout(us->delay_wait, test_bit(US_FLIDX_DONT_SCAN, &us->dflags), delay_use * HZ); } From 567c6a1ce9d9417c33176bb848a6287f5bae6dd4 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Fri, 2 Sep 2011 11:05:40 -0700 Subject: [PATCH 0180/4025] xhci: If no endpoints changed, don't issue BW command. commit 2dc3753997f3c80ce8b950242ab9bb3fb936acfd upstream. Some alternate interface settings have no endpoints associated with them. This shows up in some USB webcams, particularly the Logitech HD 1080p, which uses the uvcvideo driver. If a driver switches between two alt settings with no endpoints, there is no need to issue a configure endpoint command, because there is no endpoint information to update. The only time a configure endpoint command with just the add slot flag set makes sense is when the driver is updating hub characteristics in the slot context. However, that code never calls xhci_check_bandwidth, so we should be safe not issuing a command if only the slot context add flag is set. Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 7ea48b342aa..fb61e9d8e17 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1889,6 +1889,12 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); ctrl_ctx->add_flags &= cpu_to_le32(~EP0_FLAG); ctrl_ctx->drop_flags &= cpu_to_le32(~(SLOT_FLAG | EP0_FLAG)); + + /* Don't issue the command if there's no endpoints to update. */ + if (ctrl_ctx->add_flags == cpu_to_le32(SLOT_FLAG) && + ctrl_ctx->drop_flags == 0) + return 0; + xhci_dbg(xhci, "New Input Control Context:\n"); slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx); xhci_dbg_ctx(xhci, virt_dev->in_ctx, From 1c349398c8583d23bdf397363aedaae55d889c03 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Fri, 23 Sep 2011 14:19:49 -0700 Subject: [PATCH 0181/4025] xHCI: test and clear RWC bit commit d2f52c9e585bbb1a3c164e02b8dcd0d996c67353 upstream. Introduce xhci_test_and_clear_bit() to clear RWC bit in PORTSC register. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 22 ++++++++++++++++------ drivers/usb/host/xhci-ring.c | 6 ++---- drivers/usb/host/xhci.h | 2 ++ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 723f8231193..ce9f974dac0 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -392,6 +392,20 @@ static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array) return max_ports; } +/* Test and clear port RWC bit */ +void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, + int port_id, u32 port_bit) +{ + u32 temp; + + temp = xhci_readl(xhci, port_array[port_id]); + if (temp & port_bit) { + temp = xhci_port_state_to_neutral(temp); + temp |= port_bit; + xhci_writel(xhci, temp, port_array[port_id]); + } +} + int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { @@ -938,12 +952,8 @@ int xhci_bus_resume(struct usb_hcd *hcd) spin_lock_irqsave(&xhci->lock, flags); /* Clear PLC */ - temp = xhci_readl(xhci, port_array[port_index]); - if (temp & PORT_PLC) { - temp = xhci_port_state_to_neutral(temp); - temp |= PORT_PLC; - xhci_writel(xhci, temp, port_array[port_index]); - } + xhci_test_and_clear_bit(xhci, port_array, port_index, + PORT_PLC); slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index b68939703a9..cbf7ed01c72 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1347,10 +1347,8 @@ static void handle_port_status(struct xhci_hcd *xhci, xhci_ring_device(xhci, slot_id); xhci_dbg(xhci, "resume SS port %d finished\n", port_id); /* Clear PORT_PLC */ - temp = xhci_readl(xhci, port_array[faked_port_index]); - temp = xhci_port_state_to_neutral(temp); - temp |= PORT_PLC; - xhci_writel(xhci, temp, port_array[faked_port_index]); + xhci_test_and_clear_bit(xhci, port_array, + faked_port_index, PORT_PLC); } else { xhci_dbg(xhci, "resume HS port %d\n", port_id); bus_state->resume_done[faked_port_index] = jiffies + diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 8a98416e535..49ce76c6b41 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1566,6 +1566,8 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, unsigned int stream_id); /* xHCI roothub code */ +void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, + int port_id, u32 port_bit); int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength); int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); From 6d3607b179804e8ff4e2a1304ee238a4f6dc035c Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Fri, 23 Sep 2011 14:19:50 -0700 Subject: [PATCH 0182/4025] xHCI: Clear PLC for USB2 root hub ports commit 6fd4562178508a0949c9fdecd8558d8b10d671bd upstream. When the link state changes, xHC will report a port status change event and set the PORT_PLC bit, for both USB3 and USB2 root hub ports. The PLC will be cleared by usbcore for USB3 root hub ports, but not for USB2 ports, because they do not report USB_PORT_STAT_C_LINK_STATE in wPortChange. Clear it for USB2 root hub ports in handle_port_status(). Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index cbf7ed01c72..b20d2f7221c 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1359,6 +1359,10 @@ static void handle_port_status(struct xhci_hcd *xhci, } } + if (hcd->speed != HCD_USB3) + xhci_test_and_clear_bit(xhci, port_array, faked_port_index, + PORT_PLC); + cleanup: /* Update event ring dequeue pointer before dropping the lock */ inc_deq(xhci, xhci->event_ring, true); From 8adc3d3df0562b8dc4008f458081dcc2d8b98863 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Thu, 29 Sep 2011 15:33:47 -0400 Subject: [PATCH 0183/4025] can bcm: fix incomplete tx_setup fix commit 12d0d0d3a7349daa95dbfd5d7df8146255bc7c67 upstream. The commit aabdcb0b553b9c9547b1a506b34d55a764745870 ("can bcm: fix tx_setup off-by-one errors") fixed only a part of the original problem reported by Andre Naujoks. It turned out that the original code needed to be re-ordered to reduce complexity and to finally fix the reported frame counting issues. Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/can/bcm.c | 48 +++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/net/can/bcm.c b/net/can/bcm.c index 8838b86f2f2..c6cc66f7286 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -343,6 +343,18 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head, } } +static void bcm_tx_start_timer(struct bcm_op *op) +{ + if (op->kt_ival1.tv64 && op->count) + hrtimer_start(&op->timer, + ktime_add(ktime_get(), op->kt_ival1), + HRTIMER_MODE_ABS); + else if (op->kt_ival2.tv64) + hrtimer_start(&op->timer, + ktime_add(ktime_get(), op->kt_ival2), + HRTIMER_MODE_ABS); +} + static void bcm_tx_timeout_tsklet(unsigned long data) { struct bcm_op *op = (struct bcm_op *)data; @@ -364,23 +376,12 @@ static void bcm_tx_timeout_tsklet(unsigned long data) bcm_send_to_user(op, &msg_head, NULL, 0); } - - /* send (next) frame */ bcm_can_tx(op); - hrtimer_start(&op->timer, - ktime_add(ktime_get(), op->kt_ival1), - HRTIMER_MODE_ABS); - } else { - if (op->kt_ival2.tv64) { + } else if (op->kt_ival2.tv64) + bcm_can_tx(op); - /* send (next) frame */ - bcm_can_tx(op); - hrtimer_start(&op->timer, - ktime_add(ktime_get(), op->kt_ival2), - HRTIMER_MODE_ABS); - } - } + bcm_tx_start_timer(op); } /* @@ -960,28 +961,21 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, hrtimer_cancel(&op->timer); } - if ((op->flags & STARTTIMER) && - ((op->kt_ival1.tv64 && op->count) || op->kt_ival2.tv64)) { - + if (op->flags & STARTTIMER) { + hrtimer_cancel(&op->timer); /* spec: send can_frame when starting timer */ op->flags |= TX_ANNOUNCE; - - /* only start timer when having more frames than sent below */ - if (op->kt_ival1.tv64 && (op->count > 1)) { - /* op->count-- is done in bcm_tx_timeout_tsklet */ - hrtimer_start(&op->timer, op->kt_ival1, - HRTIMER_MODE_REL); - } else - hrtimer_start(&op->timer, op->kt_ival2, - HRTIMER_MODE_REL); } if (op->flags & TX_ANNOUNCE) { bcm_can_tx(op); - if (op->kt_ival1.tv64 && (op->count > 0)) + if (op->count) op->count--; } + if (op->flags & STARTTIMER) + bcm_tx_start_timer(op); + return msg_head->nframes * CFSIZ + MHSIZ; } From 45a2755f0fd17acf45c7cea183815c65f28154c3 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Wed, 2 Nov 2011 13:37:03 -0700 Subject: [PATCH 0184/4025] powerpc: remove superfluous PageTail checks on the pte gup_fast commit 2839bdc1bfc0af76a2f0f11eca011590520a04fa upstream. This part of gup_fast doesn't seem capable of handling hugetlbfs ptes, those should be handled by gup_hugepd only, so these checks are superfluous. Plus if this wasn't a noop, it would have oopsed because, the insistence of using the speculative refcounting would trigger a VM_BUG_ON if a tail page was encountered in the page_cache_get_speculative(). Signed-off-by: Andrea Arcangeli Cc: Peter Zijlstra Cc: Hugh Dickins Cc: Johannes Weiner Cc: Rik van Riel Cc: Mel Gorman Cc: KOSAKI Motohiro Cc: Benjamin Herrenschmidt Acked-by: David Gibson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/gup.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/arch/powerpc/mm/gup.c b/arch/powerpc/mm/gup.c index b9e1c7ff5f6..d7efdbf640c 100644 --- a/arch/powerpc/mm/gup.c +++ b/arch/powerpc/mm/gup.c @@ -16,17 +16,6 @@ #ifdef __HAVE_ARCH_PTE_SPECIAL -static inline void get_huge_page_tail(struct page *page) -{ - /* - * __split_huge_page_refcount() cannot run - * from under us. - */ - VM_BUG_ON(page_mapcount(page) < 0); - VM_BUG_ON(atomic_read(&page->_count) != 0); - atomic_inc(&page->_mapcount); -} - /* * The performance critical leaf functions are made noinline otherwise gcc * inlines everything into a single function which results in too much @@ -58,8 +47,6 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr, put_page(page); return 0; } - if (PageTail(page)) - get_huge_page_tail(page); pages[*nr] = page; (*nr)++; From acafc792476742f042e2d7a3679dbaa097444ccc Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Wed, 2 Nov 2011 13:37:08 -0700 Subject: [PATCH 0185/4025] powerpc: get_hugepte() don't put_page() the wrong page commit 405e44f2e312dd5dd63e5a9f459bffcbcd4368ef upstream. "page" may have changed to point to the next hugepage after the loop completed, The references have been taken on the head page, so the put_page must happen there too. This is a longstanding issue pre-thp inclusion. It's totally unclear how these page_cache_add_speculative and pte_val(pte) != pte_val(*ptep) checks are necessary across all the powerpc gup_fast code, when x86 doesn't need any of that: there's no way the page can be freed with irq disabled so we're guaranteed the atomic_inc will happen on a page with page_count > 0 (so not needing the speculative check). The pte check is also meaningless on x86: no need to rollback on x86 if the pte changed, because the pte can still change a CPU tick after the check succeeded and it won't be rolled back in that case. The important thing is we got a reference on a valid page that was mapped there a CPU tick ago. So not knowing the soft tlb refill code of ppc64 in great detail I'm not removing the "speculative" page_count increase and the pte checks across all the code, but unless there's a strong reason for it they should be later cleaned up too. If a pte can change from huge to non-huge (like it could happen with THP) passing a pte_t *ptep to gup_hugepte() would also require to repeat the is_hugepd in gup_hugepte(), but that shouldn't happen with hugetlbfs only so I'm not altering that. Signed-off-by: Andrea Arcangeli Cc: Peter Zijlstra Cc: Hugh Dickins Cc: Johannes Weiner Cc: Rik van Riel Cc: Mel Gorman Cc: KOSAKI Motohiro Cc: Benjamin Herrenschmidt Acked-by: David Gibson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/hugetlbpage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 0b9a5c1901b..b649c288af9 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -429,7 +429,7 @@ static noinline int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long add if (unlikely(pte_val(pte) != pte_val(*ptep))) { /* Could be optimized better */ while (*nr) { - put_page(page); + put_page(head); (*nr)--; } } From cf2f493ba5c49afe9efd3afa02a505e9b060832d Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Wed, 2 Nov 2011 13:37:11 -0700 Subject: [PATCH 0186/4025] powerpc: gup_hugepte() avoid freeing the head page too many times commit 8596468487e2062cae2aad56e973784e03959245 upstream. We only taken "refs" pins on the head page not "*nr" pins. Signed-off-by: Andrea Arcangeli Cc: Peter Zijlstra Cc: Hugh Dickins Cc: Johannes Weiner Cc: Rik van Riel Cc: Mel Gorman Cc: KOSAKI Motohiro Cc: Benjamin Herrenschmidt Acked-by: David Gibson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/hugetlbpage.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index b649c288af9..78b14abded6 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -428,10 +428,9 @@ static noinline int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long add if (unlikely(pte_val(pte) != pte_val(*ptep))) { /* Could be optimized better */ - while (*nr) { + *nr -= refs; + while (refs--) put_page(head); - (*nr)--; - } } return 1; From 87c2bd66eef0c5685bb29fd995f6b77fa4d07ed1 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Wed, 2 Nov 2011 13:37:15 -0700 Subject: [PATCH 0187/4025] powerpc: gup_hugepte() support THP based tail recounting commit 3526741f0964c88bc2ce511e1078359052bf225b upstream. Up to this point the code assumed old refcounting for hugepages (pre-thp). This updates the code directly to the thp mapcount tail page refcounting. Signed-off-by: Andrea Arcangeli Cc: Peter Zijlstra Cc: Hugh Dickins Cc: Johannes Weiner Cc: Rik van Riel Cc: Mel Gorman Cc: KOSAKI Motohiro Cc: Benjamin Herrenschmidt Cc: David Gibson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/hugetlbpage.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 78b14abded6..a618ef01bfa 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -385,12 +385,23 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address, return NULL; } +static inline void get_huge_page_tail(struct page *page) +{ + /* + * __split_huge_page_refcount() cannot run + * from under us. + */ + VM_BUG_ON(page_mapcount(page) < 0); + VM_BUG_ON(atomic_read(&page->_count) != 0); + atomic_inc(&page->_mapcount); +} + static noinline int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr, unsigned long end, int write, struct page **pages, int *nr) { unsigned long mask; unsigned long pte_end; - struct page *head, *page; + struct page *head, *page, *tail; pte_t pte; int refs; @@ -413,6 +424,7 @@ static noinline int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long add head = pte_page(pte); page = head + ((addr & (sz-1)) >> PAGE_SHIFT); + tail = page; do { VM_BUG_ON(compound_head(page) != head); pages[*nr] = page; @@ -431,6 +443,16 @@ static noinline int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long add *nr -= refs; while (refs--) put_page(head); + } else { + /* + * Any tail page need their mapcount reference taken + * before we return. + */ + while (refs--) { + if (PageTail(tail)) + get_huge_page_tail(tail); + tail++; + } } return 1; From 2429d1c2f20466effdc70ced613f591f8675059f Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Wed, 2 Nov 2011 13:37:19 -0700 Subject: [PATCH 0188/4025] powerpc: gup_huge_pmd() return 0 if pte changes commit cf592bf768c4fa40282b8fce58a80820065de2cb upstream. powerpc didn't return 0 in that case, if it's rolling back the *nr pointer it should also return zero to avoid adding pages to the array at the wrong offset. Signed-off-by: Andrea Arcangeli Cc: Peter Zijlstra Cc: Hugh Dickins Cc: Johannes Weiner Cc: Rik van Riel Cc: Mel Gorman Cc: KOSAKI Motohiro Cc: Benjamin Herrenschmidt Acked-by: David Gibson Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: David Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/hugetlbpage.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index a618ef01bfa..1c59d94f594 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -443,16 +443,17 @@ static noinline int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long add *nr -= refs; while (refs--) put_page(head); - } else { - /* - * Any tail page need their mapcount reference taken - * before we return. - */ - while (refs--) { - if (PageTail(tail)) - get_huge_page_tail(tail); - tail++; - } + return 0; + } + + /* + * Any tail page need their mapcount reference taken before we + * return. + */ + while (refs--) { + if (PageTail(tail)) + get_huge_page_tail(tail); + tail++; } return 1; From 7a093bf2f9356230afccb4b79091787feb5aed97 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Wed, 2 Nov 2011 13:37:25 -0700 Subject: [PATCH 0189/4025] s390: gup_huge_pmd() support THP tail recounting commit 220a2eb228d032acde60e9fd044ca802706ff583 upstream. Up to this point the code assumed old refcounting for hugepages (pre-thp). This updates the code directly to the thp mapcount tail page refcounting. Signed-off-by: Andrea Arcangeli Cc: Peter Zijlstra Cc: Hugh Dickins Cc: Johannes Weiner Cc: Rik van Riel Cc: Mel Gorman Cc: KOSAKI Motohiro Cc: Benjamin Herrenschmidt Cc: David Gibson Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: David Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/s390/mm/gup.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c index 45b405ca256..668dda964f2 100644 --- a/arch/s390/mm/gup.c +++ b/arch/s390/mm/gup.c @@ -48,11 +48,22 @@ static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr, return 1; } +static inline void get_huge_page_tail(struct page *page) +{ + /* + * __split_huge_page_refcount() cannot run + * from under us. + */ + VM_BUG_ON(page_mapcount(page) < 0); + VM_BUG_ON(atomic_read(&page->_count) != 0); + atomic_inc(&page->_mapcount); +} + static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr, unsigned long end, int write, struct page **pages, int *nr) { unsigned long mask, result; - struct page *head, *page; + struct page *head, *page, *tail; int refs; result = write ? 0 : _SEGMENT_ENTRY_RO; @@ -64,6 +75,7 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr, refs = 0; head = pmd_page(pmd); page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT); + tail = page; do { VM_BUG_ON(compound_head(page) != head); pages[*nr] = page; @@ -81,6 +93,16 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr, *nr -= refs; while (refs--) put_page(head); + } else { + /* + * Any tail page need their mapcount reference taken + * before we return. + */ + while (refs--) { + if (PageTail(tail)) + get_huge_page_tail(tail); + tail++; + } } return 1; From 1a2417c30c86961992afae7eb8f803acca2f6b9b Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Wed, 2 Nov 2011 13:37:28 -0700 Subject: [PATCH 0190/4025] s390: gup_huge_pmd() return 0 if pte changes commit 0693bc9ce2cc4f6a1b9c3c05790fc149a74c0b87 upstream. s390 didn't return 0 in that case, if it's rolling back the *nr pointer it should also return zero to avoid adding pages to the array at the wrong offset. Signed-off-by: Andrea Arcangeli Cc: Peter Zijlstra Cc: Hugh Dickins Cc: Johannes Weiner Cc: Rik van Riel Cc: Mel Gorman Cc: KOSAKI Motohiro Cc: Benjamin Herrenschmidt Cc: David Gibson Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: David Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/s390/mm/gup.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c index 668dda964f2..da33a0281d9 100644 --- a/arch/s390/mm/gup.c +++ b/arch/s390/mm/gup.c @@ -93,16 +93,17 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr, *nr -= refs; while (refs--) put_page(head); - } else { - /* - * Any tail page need their mapcount reference taken - * before we return. - */ - while (refs--) { - if (PageTail(tail)) - get_huge_page_tail(tail); - tail++; - } + return 0; + } + + /* + * Any tail page need their mapcount reference taken before we + * return. + */ + while (refs--) { + if (PageTail(tail)) + get_huge_page_tail(tail); + tail++; } return 1; From 621112ec06bbe3a6dbb6af5f4db3451d01b309f9 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Wed, 2 Nov 2011 13:37:36 -0700 Subject: [PATCH 0191/4025] thp: share get_huge_page_tail() commit b35a35b556f5e6b7993ad0baf20173e75c09ce8c upstream. This avoids duplicating the function in every arch gup_fast. Signed-off-by: Andrea Arcangeli Cc: Peter Zijlstra Cc: Hugh Dickins Cc: Johannes Weiner Cc: Rik van Riel Cc: Mel Gorman Cc: KOSAKI Motohiro Cc: Benjamin Herrenschmidt Cc: David Gibson Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: David Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/hugetlbpage.c | 11 ----------- arch/s390/mm/gup.c | 11 ----------- arch/x86/mm/gup.c | 11 ----------- include/linux/mm.h | 11 +++++++++++ 4 files changed, 11 insertions(+), 33 deletions(-) diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 1c59d94f594..da5eb388570 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -385,17 +385,6 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address, return NULL; } -static inline void get_huge_page_tail(struct page *page) -{ - /* - * __split_huge_page_refcount() cannot run - * from under us. - */ - VM_BUG_ON(page_mapcount(page) < 0); - VM_BUG_ON(atomic_read(&page->_count) != 0); - atomic_inc(&page->_mapcount); -} - static noinline int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr, unsigned long end, int write, struct page **pages, int *nr) { diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c index da33a0281d9..65cb06e2af4 100644 --- a/arch/s390/mm/gup.c +++ b/arch/s390/mm/gup.c @@ -48,17 +48,6 @@ static inline int gup_pte_range(pmd_t *pmdp, pmd_t pmd, unsigned long addr, return 1; } -static inline void get_huge_page_tail(struct page *page) -{ - /* - * __split_huge_page_refcount() cannot run - * from under us. - */ - VM_BUG_ON(page_mapcount(page) < 0); - VM_BUG_ON(atomic_read(&page->_count) != 0); - atomic_inc(&page->_mapcount); -} - static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr, unsigned long end, int write, struct page **pages, int *nr) { diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c index 3b5032a62b0..ea305856151 100644 --- a/arch/x86/mm/gup.c +++ b/arch/x86/mm/gup.c @@ -108,17 +108,6 @@ static inline void get_head_page_multiple(struct page *page, int nr) SetPageReferenced(page); } -static inline void get_huge_page_tail(struct page *page) -{ - /* - * __split_huge_page_refcount() cannot run - * from under us. - */ - VM_BUG_ON(page_mapcount(page) < 0); - VM_BUG_ON(atomic_read(&page->_count) != 0); - atomic_inc(&page->_mapcount); -} - static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr, unsigned long end, int write, struct page **pages, int *nr) { diff --git a/include/linux/mm.h b/include/linux/mm.h index 26fd168c670..18eea056b47 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -375,6 +375,17 @@ static inline int page_count(struct page *page) return atomic_read(&compound_head(page)->_count); } +static inline void get_huge_page_tail(struct page *page) +{ + /* + * __split_huge_page_refcount() cannot run + * from under us. + */ + VM_BUG_ON(page_mapcount(page) < 0); + VM_BUG_ON(atomic_read(&page->_count) != 0); + atomic_inc(&page->_mapcount); +} + extern bool __get_page_tail(struct page *page); static inline void get_page(struct page *page) From ce0f562ecf544f386b6ae95f490cd06f7da2deb4 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Mon, 3 Oct 2011 18:14:45 +0000 Subject: [PATCH 0192/4025] bridge: leave carrier on for empty bridge [ Upstream commit b64b73d7d0c480f75684519c6134e79d50c1b341 ] This resolves a regression seen by some users of bridging. Some users use the bridge like a dummy device. They expect to be able to put an IPv6 address on the device with no ports attached. Although there are better ways of doing this, there is no reason to not allow it. Note: the bridge still will reflect the state of ports in the bridge if there are any added. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/bridge/br_device.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 32b8f9f7f79..ff3ed6086ce 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -91,7 +91,6 @@ static int br_dev_open(struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); - netif_carrier_off(dev); netdev_update_features(dev); netif_start_queue(dev); br_stp_enable_bridge(br); @@ -108,8 +107,6 @@ static int br_dev_stop(struct net_device *dev) { struct net_bridge *br = netdev_priv(dev); - netif_carrier_off(dev); - br_stp_disable_bridge(br); br_multicast_stop(br); From 5796ee30587cb5f887a7fe6182c2bbcc3d31f0ad Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 25 Oct 2011 02:30:50 +0000 Subject: [PATCH 0193/4025] net: Unlock sock before calling sk_free() [ Upstream commit b0691c8ee7c28a72748ff32e91b165ec12ae4de6 ] Signed-off-by: Thomas Gleixner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/sock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/core/sock.c b/net/core/sock.c index 6e819780c23..aebb419519b 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1257,6 +1257,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) /* It is still raw copy of parent, so invalidate * destructor and make plain sk_free() */ newsk->sk_destruct = NULL; + bh_unlock_sock(newsk); sk_free(newsk); newsk = NULL; goto out; From c52e585cf03d3faa89ace0368bf66a3298e66a8b Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sat, 15 Oct 2011 23:19:25 +0200 Subject: [PATCH 0194/4025] ALSA: ua101: fix crash when unplugging commit 862a6244eb9f9f5123fe819454fcfcae0ee1f2f9 upstream. If the device is unplugged while running, it is possible for a PCM device to be closed after the disconnect callback has returned. This means that kill_stream_urb() and disable_iso_interface() would try to access already-invalid or freed USB data structures. The function free_usb_related_resources() was intended to prevent this, but forgot to clear the affected variables. Reported-and-tested-by: Olivier Courtay Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/misc/ua101.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index fb5d68fa7ff..96c381e16bc 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -459,7 +459,8 @@ static void kill_stream_urbs(struct ua101_stream *stream) unsigned int i; for (i = 0; i < stream->queue_length; ++i) - usb_kill_urb(&stream->urbs[i]->urb); + if (stream->urbs[i]) + usb_kill_urb(&stream->urbs[i]->urb); } static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index) @@ -484,6 +485,9 @@ static void disable_iso_interface(struct ua101 *ua, unsigned int intf_index) { struct usb_host_interface *alts; + if (!ua->intf[intf_index]) + return; + alts = ua->intf[intf_index]->cur_altsetting; if (alts->desc.bAlternateSetting != 0) { int err = usb_set_interface(ua->dev, @@ -1144,27 +1148,37 @@ static void free_stream_urbs(struct ua101_stream *stream) { unsigned int i; - for (i = 0; i < stream->queue_length; ++i) + for (i = 0; i < stream->queue_length; ++i) { kfree(stream->urbs[i]); + stream->urbs[i] = NULL; + } } static void free_usb_related_resources(struct ua101 *ua, struct usb_interface *interface) { unsigned int i; + struct usb_interface *intf; + mutex_lock(&ua->mutex); free_stream_urbs(&ua->capture); free_stream_urbs(&ua->playback); + mutex_unlock(&ua->mutex); free_stream_buffers(ua, &ua->capture); free_stream_buffers(ua, &ua->playback); - for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) - if (ua->intf[i]) { - usb_set_intfdata(ua->intf[i], NULL); - if (ua->intf[i] != interface) + for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) { + mutex_lock(&ua->mutex); + intf = ua->intf[i]; + ua->intf[i] = NULL; + mutex_unlock(&ua->mutex); + if (intf) { + usb_set_intfdata(intf, NULL); + if (intf != interface) usb_driver_release_interface(&ua101_driver, - ua->intf[i]); + intf); } + } } static void ua101_card_free(struct snd_card *card) From a7ae01515249c673c1e8e8ad5addd6920b980a3b Mon Sep 17 00:00:00 2001 From: Charles Chin Date: Wed, 2 Nov 2011 07:53:30 +0100 Subject: [PATCH 0195/4025] ALSA: hda - Disable power-widget control for IDT 92HD83/93 as default commit 35c11777b906042eca9e6f1c03e464726c7faa07 upstream. The power-widget control in patch_stac92hd83xxx() never worked properly, thus it's safer to turn it off as default for now. Signed-off-by: Charles Chin Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_sigmatel.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 24a99e040f4..28086432837 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5465,26 +5465,8 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) stac92xx_set_config_regs(codec, stac92hd83xxx_brd_tbl[spec->board_config]); - switch (codec->vendor_id) { - case 0x111d76d1: - case 0x111d76d9: - case 0x111d76df: - case 0x111d76e5: - case 0x111d7666: - case 0x111d7667: - case 0x111d7668: - case 0x111d7669: - case 0x111d76e3: - case 0x111d7604: - case 0x111d76d4: - case 0x111d7605: - case 0x111d76d5: - case 0x111d76e7: - if (spec->board_config == STAC_92HD83XXX_PWR_REF) - break; + if (spec->board_config != STAC_92HD83XXX_PWR_REF) spec->num_pwrs = 0; - break; - } codec->patch_ops = stac92xx_patch_ops; From ec0baacddc46b83b95b6bb4245f16a3c7d16988b Mon Sep 17 00:00:00 2001 From: Charles Chin Date: Wed, 2 Nov 2011 07:56:58 +0100 Subject: [PATCH 0196/4025] ALSA: hda - Add support for 92HD65 / 92HD66 family of codecs commit ad5d8755116b431f0709c745ee17cb567a478d43 upstream. These codecs have SPDIF-in, which is new to the 92HD83xxx compatible families, so a bit of logic is added to support them. Signed-off-by: Charles Chin Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_sigmatel.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 28086432837..5d2e97abb2e 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -5486,7 +5486,11 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) } #endif - err = stac92xx_parse_auto_config(codec, 0x1d, 0); + /* 92HD65/66 series has S/PDIF-IN */ + if (codec->vendor_id >= 0x111d76e8 && codec->vendor_id <= 0x111d76f3) + err = stac92xx_parse_auto_config(codec, 0x1d, 0x22); + else + err = stac92xx_parse_auto_config(codec, 0x1d, 0); if (!err) { if (spec->board_config < 0) { printk(KERN_WARNING "hda_codec: No auto-config is " @@ -6369,6 +6373,18 @@ static const struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d76e3, .name = "92HD98BXX", .patch = patch_stac92hd83xxx}, { .id = 0x111d76e5, .name = "92HD99BXX", .patch = patch_stac92hd83xxx}, { .id = 0x111d76e7, .name = "92HD90BXX", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76e8, .name = "92HD66B1X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76e9, .name = "92HD66B2X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76ea, .name = "92HD66B3X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76eb, .name = "92HD66C1X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76ec, .name = "92HD66C2X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76ed, .name = "92HD66C3X5", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76ee, .name = "92HD66B1X3", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76ef, .name = "92HD66B2X3", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76f0, .name = "92HD66B3X3", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76f1, .name = "92HD66C1X3", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76f2, .name = "92HD66C2X3", .patch = patch_stac92hd83xxx}, + { .id = 0x111d76f3, .name = "92HD66C3/65", .patch = patch_stac92hd83xxx}, {} /* terminator */ }; From d429701077f158a4b7bdf4a8490d3ed9847217e5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 3 Nov 2011 16:54:06 +0100 Subject: [PATCH 0197/4025] ALSA: hda/realtek - Skip invalid digital out pins commit 51e4152a969aa6d2306492ebf143932dcb535c9b upstream. Some BIOS report invalid pins as digital output pins. The driver checks the connection but it doesn't do it fully correctly, and it leaves some undefined value as the audio-out widget, which makes the driver spewing warnings. This patch fixes the issue. Reference: https://bugzilla.novell.com/show_bug.cgi?id=727348 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 62b13141876..e7dc0340da6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2088,25 +2088,27 @@ static void alc_auto_init_digital(struct hda_codec *codec) static void alc_auto_parse_digital(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - int i, err; + int i, err, nums; hda_nid_t dig_nid; /* support multiple SPDIFs; the secondary is set up as a slave */ + nums = 0; for (i = 0; i < spec->autocfg.dig_outs; i++) { err = snd_hda_get_connections(codec, spec->autocfg.dig_out_pins[i], &dig_nid, 1); - if (err < 0) + if (err <= 0) continue; - if (!i) { + if (!nums) { spec->multiout.dig_out_nid = dig_nid; spec->dig_out_type = spec->autocfg.dig_out_type[0]; } else { spec->multiout.slave_dig_outs = spec->slave_dig_outs; - if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) + if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) break; - spec->slave_dig_outs[i - 1] = dig_nid; + spec->slave_dig_outs[nums - 1] = dig_nid; } + nums++; } if (spec->autocfg.dig_in_pin) { From 3fa1ae816c22f98f0f933ad77da681ab28f7845d Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Mon, 24 Oct 2011 18:16:34 -0400 Subject: [PATCH 0198/4025] drm/radeon: avoid bouncing connector status btw disconnected & unknown commit 340764465aa4a586ca332e61ae64883e5ad6f183 upstream. Since force handling rework of d0d0a225e6ad43314c9aa7ea081f76adc5098ad4 we could end up bouncing connector status btw disconnected and unknown. When connector status change a call to output_poll_changed happen which in turn ask again for detect but with force set. So set the load detect flags whenever we report the connector as connected or unknown this avoid bouncing btw disconnected and unknown. Signed-off-by: Jerome Glisse Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie Cc: Stefan Lippers-Hollmann Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_connectors.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 404a220a570..2109c17a982 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -755,7 +755,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force) if (radeon_connector->dac_load_detect && encoder) { encoder_funcs = encoder->helper_private; ret = encoder_funcs->detect(encoder, connector); - if (ret == connector_status_connected) + if (ret != connector_status_disconnected) radeon_connector->detected_by_load = true; } } @@ -996,8 +996,9 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) ret = encoder_funcs->detect(encoder, connector); if (ret == connector_status_connected) { radeon_connector->use_digital = false; - radeon_connector->detected_by_load = true; } + if (ret != connector_status_disconnected) + radeon_connector->detected_by_load = true; } break; } From fd33e34e106cb531435e4f7ed058c0c93a26c9d7 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 25 Oct 2011 14:58:49 -0400 Subject: [PATCH 0199/4025] drm/radeon/kms: split MSI check into a separate function commit 8f6c25c59b0c895c68cae59d1b34e9a7b36971bc upstream. This makes it easier to add quirks for certain systems. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_irq_kms.c | 29 ++++++++++++++++++++----- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 9ec830c77af..f0e660b10fe 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -108,6 +108,27 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) radeon_irq_set(rdev); } +static bool radeon_msi_ok(struct radeon_device *rdev) +{ + /* RV370/RV380 was first asic with MSI support */ + if (rdev->family < CHIP_RV380) + return false; + + /* MSIs don't work on AGP */ + if (rdev->flags & RADEON_IS_AGP) + return false; + + if (rdev->flags & RADEON_IS_IGP) { + /* APUs work fine with MSIs */ + if (rdev->family >= CHIP_PALM) + return true; + /* lots of IGPs have problems with MSIs */ + return false; + } + + return true; +} + int radeon_irq_kms_init(struct radeon_device *rdev) { int i; @@ -124,12 +145,8 @@ int radeon_irq_kms_init(struct radeon_device *rdev) } /* enable msi */ rdev->msi_enabled = 0; - /* MSIs don't seem to work reliably on all IGP - * chips. Disable MSI on them for now. - */ - if ((rdev->family >= CHIP_RV380) && - ((!(rdev->flags & RADEON_IS_IGP)) || (rdev->family >= CHIP_PALM)) && - (!(rdev->flags & RADEON_IS_AGP))) { + + if (radeon_msi_ok(rdev)) { int ret = pci_enable_msi(rdev->pdev); if (!ret) { rdev->msi_enabled = 1; From be72d16568ac4058c41baa5fb75ce906d39b9dcd Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 25 Oct 2011 15:11:08 -0400 Subject: [PATCH 0200/4025] drm/radeon/kms: Add MSI quirk for HP RS690 commit b362105f7f5223fa4d2e03ceeea0e51da754ccc6 upstream. Some HP laptops only seem to work with MSIs. This looks like a platform/bios bug. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=37679 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_irq_kms.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index f0e660b10fe..b0ed0e16456 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -118,6 +118,13 @@ static bool radeon_msi_ok(struct radeon_device *rdev) if (rdev->flags & RADEON_IS_AGP) return false; + /* Quirks */ + /* HP RS690 only seems to work with MSIs. */ + if ((rdev->pdev->device == 0x791f) && + (rdev->pdev->subsystem_vendor == 0x103c) && + (rdev->pdev->subsystem_device == 0x30c2)) + return true; + if (rdev->flags & RADEON_IS_IGP) { /* APUs work fine with MSIs */ if (rdev->family >= CHIP_PALM) From ff356c22478a5487e2edaaad31f60bc3868c43f5 Mon Sep 17 00:00:00 2001 From: Jerome Glisse Date: Fri, 28 Oct 2011 17:52:34 -0400 Subject: [PATCH 0201/4025] drm/radeon: set hpd polarity at init time so hotplug detect works commit 8ab250d4484b72ccc78e34276c5ffa84c1d41303 upstream. Polarity needs to be set accordingly to connector status (connected or disconnected). Set it up at module init so first hotplug works reliably no matter what is the initial set of connector. Signed-off-by: Jerome Glisse Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_connectors.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 2109c17a982..ffdff8d94c2 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1779,6 +1779,7 @@ radeon_add_atom_connector(struct drm_device *dev, connector->polled = DRM_CONNECTOR_POLL_CONNECT; } else connector->polled = DRM_CONNECTOR_POLL_HPD; + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); connector->display_info.subpixel_order = subpixel_order; drm_sysfs_connector_add(connector); From 35f6259abb1d8153d6a7552895e8126b8bcf2c61 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 31 Oct 2011 08:54:41 -0400 Subject: [PATCH 0202/4025] drm/radeon/kms: properly set panel mode for eDP commit 00dfb8df5bf8c3afe4c0bb8361133156b06b7a2c upstream. This should make eDP more reliable. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_dp.c | 11 +++++++++++ include/drm/drm_dp_helper.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 79e8ebc0530..b5628ce1228 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -553,6 +553,7 @@ static void radeon_dp_set_panel_mode(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; if (!ASIC_IS_DCE4(rdev)) @@ -560,10 +561,20 @@ static void radeon_dp_set_panel_mode(struct drm_encoder *encoder, if (radeon_connector_encoder_is_dp_bridge(connector)) panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE; + else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + u8 tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); + if (tmp & 1) + panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; + } atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP_PANEL_MODE, panel_mode); + + if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) && + (panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)) { + radeon_write_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_SET, 1); + } } void radeon_dp_set_link_config(struct drm_connector *connector, diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 91567bbdb02..03eb1d68d50 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -72,6 +72,7 @@ #define DP_MAIN_LINK_CHANNEL_CODING 0x006 +#define DP_EDP_CONFIGURATION_CAP 0x00d #define DP_TRAINING_AUX_RD_INTERVAL 0x00e /* link configuration */ @@ -133,6 +134,8 @@ #define DP_MAIN_LINK_CHANNEL_CODING_SET 0x108 # define DP_SET_ANSI_8B10B (1 << 0) +#define DP_EDP_CONFIGURATION_SET 0x10a + #define DP_LANE0_1_STATUS 0x202 #define DP_LANE2_3_STATUS 0x203 # define DP_LANE_CR_DONE (1 << 0) From 957450510b2c59f3689e6114de6b32d5d3aad7c6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 1 Nov 2011 14:14:18 -0400 Subject: [PATCH 0203/4025] drm/radeon/kms: Add MSI quirk for Dell RS690 commit 01e718ec194e30b3e8eb3858c742c13649757efc upstream. Some Dell laptops only seem to work with MSIs. This looks like a platform/bios bug. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=37679 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_irq_kms.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index b0ed0e16456..a68c626652c 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -125,6 +125,12 @@ static bool radeon_msi_ok(struct radeon_device *rdev) (rdev->pdev->subsystem_device == 0x30c2)) return true; + /* Dell RS690 only seems to work with MSIs. */ + if ((rdev->pdev->device == 0x791f) && + (rdev->pdev->subsystem_vendor == 0x1028) && + (rdev->pdev->subsystem_device == 0x01fd)) + return true; + if (rdev->flags & RADEON_IS_IGP) { /* APUs work fine with MSIs */ if (rdev->family >= CHIP_PALM) From 053b6d52c7484feaaea4945140dd0a2dde3461e8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 1 Nov 2011 14:20:30 -0400 Subject: [PATCH 0204/4025] drm/radeon/kms: add MSI module parameter commit a18cee15ed4c8b6a35f96b7b26a46bac32e04bd9 upstream. Allow the user to override whether MSIs are enabled or not on supported ASICs. MSIs are disabled by default on IGP chips as they tend not to work. However certain IGP chips only seem to work with MSIs enabled. I suspect this is a chipset or bios issue, but I'm not sure what the proper fix is. This will at least make diagnosing and working around the problem much easier. See: https://bugs.freedesktop.org/show_bug.cgi?id=37679 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon.h | 1 + drivers/gpu/drm/radeon/radeon_drv.c | 4 ++++ drivers/gpu/drm/radeon/radeon_irq_kms.c | 6 ++++++ 3 files changed, 11 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 0bb4ddf792f..59d72d0f5a8 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -93,6 +93,7 @@ extern int radeon_audio; extern int radeon_disp_priority; extern int radeon_hw_i2c; extern int radeon_pcie_gen2; +extern int radeon_msi; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 73dfbe8e5f9..60e160578f7 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -117,6 +117,7 @@ int radeon_audio = 0; int radeon_disp_priority = 0; int radeon_hw_i2c = 0; int radeon_pcie_gen2 = 0; +int radeon_msi = -1; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -163,6 +164,9 @@ module_param_named(hw_i2c, radeon_hw_i2c, int, 0444); MODULE_PARM_DESC(pcie_gen2, "PCIE Gen2 mode (1 = enable)"); module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444); +MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)"); +module_param_named(msi, radeon_msi, int, 0444); + static int radeon_suspend(struct drm_device *dev, pm_message_t state) { drm_radeon_private_t *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index a68c626652c..fecc1aae382 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -118,6 +118,12 @@ static bool radeon_msi_ok(struct radeon_device *rdev) if (rdev->flags & RADEON_IS_AGP) return false; + /* force MSI on */ + if (radeon_msi == 1) + return true; + else if (radeon_msi == 0) + return false; + /* Quirks */ /* HP RS690 only seems to work with MSIs. */ if ((rdev->pdev->device == 0x791f) && From 7a427e433356a354b29459b745ebd8103df96329 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 3 Nov 2011 11:21:39 -0400 Subject: [PATCH 0205/4025] drm/radeon/kms: set HPD polarity in hpd_init() commit 64912e997f0fe13512e4c7b90e4f7c11cb922ab5 upstream. Polarity needs to be set accordingly to connector status (connected or disconnected). Set it up in hpd_init() so first hotplug works reliably no matter what is the initial set of connector. hpd_init() also covers resume so HPD will work correctly after resume as well. Signed-off-by: Alex Deucher Cc: Jerome Glisse Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen.c | 1 + drivers/gpu/drm/radeon/r100.c | 1 + drivers/gpu/drm/radeon/r600.c | 19 +++++++++---------- drivers/gpu/drm/radeon/radeon_connectors.c | 1 - drivers/gpu/drm/radeon/rs600.c | 1 + 5 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index ea7a24ed5c0..f1bdb58ff91 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -353,6 +353,7 @@ void evergreen_hpd_init(struct radeon_device *rdev) default: break; } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) evergreen_irq_set(rdev); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 7fcdbbbf297..c9a0dae481f 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -434,6 +434,7 @@ void r100_hpd_init(struct radeon_device *rdev) default: break; } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) r100_irq_set(rdev); diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 1dea9d65b04..1a4ed433eba 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -762,13 +762,14 @@ void r600_hpd_init(struct radeon_device *rdev) struct drm_device *dev = rdev->ddev; struct drm_connector *connector; - if (ASIC_IS_DCE3(rdev)) { - u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) | DC_HPDx_RX_INT_TIMER(0xfa); - if (ASIC_IS_DCE32(rdev)) - tmp |= DC_HPDx_EN; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + if (ASIC_IS_DCE3(rdev)) { + u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) | DC_HPDx_RX_INT_TIMER(0xfa); + if (ASIC_IS_DCE32(rdev)) + tmp |= DC_HPDx_EN; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); switch (radeon_connector->hpd.hpd) { case RADEON_HPD_1: WREG32(DC_HPD1_CONTROL, tmp); @@ -798,10 +799,7 @@ void r600_hpd_init(struct radeon_device *rdev) default: break; } - } - } else { - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); + } else { switch (radeon_connector->hpd.hpd) { case RADEON_HPD_1: WREG32(DC_HOT_PLUG_DETECT1_CONTROL, DC_HOT_PLUG_DETECTx_EN); @@ -819,6 +817,7 @@ void r600_hpd_init(struct radeon_device *rdev) break; } } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) r600_irq_set(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index ffdff8d94c2..2109c17a982 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1779,7 +1779,6 @@ radeon_add_atom_connector(struct drm_device *dev, connector->polled = DRM_CONNECTOR_POLL_CONNECT; } else connector->polled = DRM_CONNECTOR_POLL_HPD; - radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); connector->display_info.subpixel_order = subpixel_order; drm_sysfs_connector_add(connector); diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 1f5850e473c..aea28c38ca4 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -287,6 +287,7 @@ void rs600_hpd_init(struct radeon_device *rdev) default: break; } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) rs600_irq_set(rdev); From 2d92f691cd1a1be5cdefb10d559fdd7443d4df7a Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 2 Aug 2011 18:49:52 +0100 Subject: [PATCH 0206/4025] kbuild: Fix help text not displayed in choice option. commit 3f198dfee49d2e9c30583c62b0c79286c78c7b44 upstream. Help text under choice menu is never displayed because it does not have symbol name associated with it, however many kconfigs have help text under choice, assuming that it will be displayed when user selects help. for example in Kconfig if we have: choice prompt "Choice" ---help--- HELP TEXT ... config A bool "A" config B bool "B" endchoice Without this patch "HELP TEXT" is not displayed when user selects help option when "Choice" is highlighted from menuconfig or xconfig or gconfig. This patch changes the logic in menu_get_ext_help to display help for cases which dont have symbol names like choice. Signed-off-by: Srinivas Kandagatla Reviewed-by: Stuart Menefy Reviewed-by: Arnaud Lacombe Signed-off-by: Michal Marek Signed-off-by: Greg Kroah-Hartman --- scripts/kconfig/menu.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 5fdf10dc1d8..b1a3ceeb215 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -596,11 +596,10 @@ void menu_get_ext_help(struct menu *menu, struct gstr *help) struct symbol *sym = menu->sym; if (menu_has_help(menu)) { - if (sym->name) { + if (sym->name) str_printf(help, "%s%s:\n\n", CONFIG_, sym->name); - str_append(help, _(menu_get_help(menu))); - str_append(help, "\n"); - } + str_append(help, _(menu_get_help(menu))); + str_append(help, "\n"); } else { str_append(help, nohelp_text); } From 8dc9c7911421d8e45901ffaf483b5dca99cbb055 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 3 Nov 2011 23:39:18 +0100 Subject: [PATCH 0207/4025] PM / Runtime: Automatically retry failed autosuspends commit 886486b792e4f6f96d4fbe8ec5bf20811cab7d6a upstream. Originally, the runtime PM core would send an idle notification whenever a suspend attempt failed. The idle callback routine could then schedule a delayed suspend for some time later. However this behavior was changed by commit f71648d73c1650b8b4aceb3856bebbde6daa3b86 (PM / Runtime: Remove idle notification after failing suspend). No notifications were sent, and there was no clear mechanism to retry failed suspends. This caused problems for the usbhid driver, because it fails autosuspend attempts as long as a key is being held down. Therefore this patch (as1492) adds a mechanism for retrying failed autosuspends. If the callback routine updates the last_busy field so that the next autosuspend expiration time is in the future, the autosuspend will automatically be rescheduled. Signed-off-by: Alan Stern Tested-by: Henrik Rydberg Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- Documentation/power/runtime_pm.txt | 10 ++++++++++ drivers/base/power/runtime.c | 18 ++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index b24875b1ced..6ade987ecb6 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -708,6 +708,16 @@ will behave normally, not taking the autosuspend delay into account. Similarly, if the power.use_autosuspend field isn't set then the autosuspend helper functions will behave just like the non-autosuspend counterparts. +Under some circumstances a driver or subsystem may want to prevent a device +from autosuspending immediately, even though the usage counter is zero and the +autosuspend delay time has expired. If the ->runtime_suspend() callback +returns -EAGAIN or -EBUSY, and if the next autosuspend delay expiration time is +in the future (as it normally would be if the callback invoked +pm_runtime_mark_last_busy()), the PM core will automatically reschedule the +autosuspend. The ->runtime_suspend() callback can't do this rescheduling +itself because no suspend requests of any kind are accepted while the device is +suspending (i.e., while the callback is running). + The implementation is well suited for asynchronous use in interrupt contexts. However such use inevitably involves races, because the PM core can't synchronize ->runtime_suspend() callbacks with the arrival of I/O requests. diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 0d4587b15c5..102339213c5 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -278,6 +278,9 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev) * If a deferred resume was requested while the callback was running then carry * it out; otherwise send an idle notification for the device (if the suspend * failed) or for its parent (if the suspend succeeded). + * If ->runtime_suspend failed with -EAGAIN or -EBUSY, and if the RPM_AUTO + * flag is set and the next autosuspend-delay expiration time is in the + * future, schedule another autosuspend attempt. * * This function must be called under dev->power.lock with interrupts disabled. */ @@ -389,10 +392,21 @@ static int rpm_suspend(struct device *dev, int rpmflags) if (retval) { __update_runtime_status(dev, RPM_ACTIVE); dev->power.deferred_resume = 0; - if (retval == -EAGAIN || retval == -EBUSY) + if (retval == -EAGAIN || retval == -EBUSY) { dev->power.runtime_error = 0; - else + + /* + * If the callback routine failed an autosuspend, and + * if the last_busy time has been updated so that there + * is a new autosuspend expiration time, automatically + * reschedule another autosuspend. + */ + if ((rpmflags & RPM_AUTO) && + pm_runtime_autosuspend_expiration(dev) != 0) + goto repeat; + } else { pm_runtime_cancel_pending(dev); + } } else { no_callback: __update_runtime_status(dev, RPM_SUSPENDED); From 5432c16a57990f12d41f57ed99ba194c368c30d0 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 4 Nov 2011 00:52:46 +0100 Subject: [PATCH 0208/4025] USB: Update last_busy time after autosuspend fails commit b2c0a863e14676fa5760c6d828fd373288e2f64a upstream. Originally, the runtime PM core would send an idle notification whenever a suspend attempt failed. The idle callback routine could then schedule a delayed suspend for some time later. However this behavior was changed by commit f71648d73c1650b8b4aceb3856bebbde6daa3b86 (PM / Runtime: Remove idle notification after failing suspend). No notifications were sent, and there was no clear mechanism to retry failed suspends. This caused problems for the usbhid driver, because it fails autosuspend attempts as long as a key is being held down. A companion patch changes the PM core's behavior, but we also need to change the USB core. In particular, this patch (as1493) updates the device's last_busy time when an autosuspend fails, so that the PM core will retry the autosuspend in the future when the delay time expires again. Signed-off-by: Alan Stern Tested-by: Henrik Rydberg Acked-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/driver.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 14b83f2a4e8..75b4bc03e2e 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1668,6 +1668,11 @@ int usb_runtime_suspend(struct device *dev) return -EAGAIN; status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); + + /* Allow a retry if autosuspend failed temporarily */ + if (status == -EAGAIN || status == -EBUSY) + usb_mark_last_busy(udev); + /* The PM core reacts badly unless the return code is 0, * -EAGAIN, or -EBUSY, so always return -EBUSY on an error. */ From fa7e2a6289195e502003f59768837107a59678c0 Mon Sep 17 00:00:00 2001 From: Mike Miller Date: Thu, 20 Oct 2011 22:19:17 +0200 Subject: [PATCH 0209/4025] cciss: add small delay when using PCI Power Management to reset for kump commit ab5dbebe33e0c353e8545f09c34553ac3351dad6 upstream. The P600 requires a small delay when changing states. Otherwise we may think the board did not reset and we bail. This for kdump only and is particular to the P600. Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/cciss.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 8f4ef656a1a..c2f9b3e3dec 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -4533,6 +4533,13 @@ static int cciss_controller_hard_reset(struct pci_dev *pdev, pmcsr &= ~PCI_PM_CTRL_STATE_MASK; pmcsr |= PCI_D0; pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr); + + /* + * The P600 requires a small delay when changing states. + * Otherwise we may think the board did not reset and we bail. + * This for kdump only and is particular to the P600. + */ + msleep(500); } return 0; } From 0fb2a32e2c8f58b5d43846e4de46364998f9af5d Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sun, 6 Nov 2011 20:25:18 +0100 Subject: [PATCH 0210/4025] hwmon: (coretemp) Fix for non-SMP builds commit 2aba6cac2a84f3b80e11a680c34d55e7739b474d upstream. The definition of TO_ATTR_NO in the non-SMP case is wrong. As the SMP definition resolves to the correct value, just use this for both cases. Without this fix the temperature attributes are named temp0_* instead of temp2_*, so libsensors won't pick them. Broken since kernel 3.0. Signed-off-by: Jean Delvare Tested-by: Phil Sutter Acked-by: Durgadoss R Acked-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/coretemp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 0070d5476dd..f6421940841 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -50,14 +50,13 @@ #ifdef CONFIG_SMP #define TO_PHYS_ID(cpu) cpu_data(cpu).phys_proc_id #define TO_CORE_ID(cpu) cpu_data(cpu).cpu_core_id -#define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO) #define for_each_sibling(i, cpu) for_each_cpu(i, cpu_sibling_mask(cpu)) #else #define TO_PHYS_ID(cpu) (cpu) #define TO_CORE_ID(cpu) (cpu) -#define TO_ATTR_NO(cpu) (cpu) #define for_each_sibling(i, cpu) for (i = 0; false; ) #endif +#define TO_ATTR_NO(cpu) (TO_CORE_ID(cpu) + BASE_SYSFS_ATTR_NO) /* * Per-Core Temperature Data From e3c298129b14f1591e647320bba3f9bc21ea63f1 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Nov 2011 12:00:47 +0100 Subject: [PATCH 0211/4025] hwmon: (w83627ehf) Properly report PECI and AMD-SI sensor types commit 2265cef2751b3441df91f85e0107f9f549e5b711 upstream. When temperature sources are PECI or AMD-SI agents, it makes no sense to report their type as diode or thermistor. Instead we must report their digital nature. Signed-off-by: Jean Delvare Acked-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83627ehf.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 36d7f270b14..7be763df2d8 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1756,7 +1756,14 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data, diode = 0x70; } for (i = 0; i < 3; i++) { - if ((tmp & (0x02 << i))) + const char *label = data->temp_label[data->temp_src[i]]; + + /* Digital source overrides analog type */ + if (strncmp(label, "PECI", 4) == 0) + data->temp_type[i] = 6; + else if (strncmp(label, "AMD", 3) == 0) + data->temp_type[i] = 5; + else if ((tmp & (0x02 << i))) data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 3; else data->temp_type[i] = 4; /* thermistor */ From 24b791339f0e80761de402cbb13ff2ddb19b8c03 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 6 Nov 2011 20:25:18 +0100 Subject: [PATCH 0212/4025] hwmon: (w83627ehf) Fix broken driver init commit bfa02b0da66965caf46e441270af87edda4fea14 upstream. Commit 2265cef2 (hwmon: (w83627ehf) Properly report PECI and AMD-SI sensor types) results in kernel panic if data->temp_label was not initialized. The problem was found with chip W83627DHG-P. Add check if data->temp->label was set before use. Based on incomplete patch by Alexander Beregalov. Reported-by: Alexander Beregalov Tested-by: Alexander Beregalov Signed-off-by: Guenter Roeck Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83627ehf.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 7be763df2d8..4b2fc50c84f 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1756,12 +1756,15 @@ static inline void __devinit w83627ehf_init_device(struct w83627ehf_data *data, diode = 0x70; } for (i = 0; i < 3; i++) { - const char *label = data->temp_label[data->temp_src[i]]; + const char *label = NULL; + + if (data->temp_label) + label = data->temp_label[data->temp_src[i]]; /* Digital source overrides analog type */ - if (strncmp(label, "PECI", 4) == 0) + if (label && strncmp(label, "PECI", 4) == 0) data->temp_type[i] = 6; - else if (strncmp(label, "AMD", 3) == 0) + else if (label && strncmp(label, "AMD", 3) == 0) data->temp_type[i] = 5; else if ((tmp & (0x02 << i))) data->temp_type[i] = (diode & (0x10 << i)) ? 1 : 3; From fef547148349098f58bcea1c6cda5be1f6f8719c Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 24 Oct 2011 13:35:37 -0700 Subject: [PATCH 0213/4025] tcm_loop: Add explict read buffer memset for SCF_SCSI_CONTROL_SG_IO_CDB commit 8cd79f24350826b81e16990d9e12bc878e67d385 upstream. This patch addresses an issue with buggy userspace code sending I/O via scsi-generic that does not explictly clear their associated read buffers. It adds an explict memset of the first SGL entry within tcm_loop_new_cmd_map() for SCF_SCSI_CONTROL_SG_IO_CDB payloads that are currently guaranteed to be a single SGL by target-core code. This issue is a side effect of the v3.1-rc1 merge to remove the extra memcpy between certain control CDB types using a contigious + cleared buffer in target-core, and performing a memcpy into the SGL list within tcm_loop. It was originally mainfesting itself by udev + scsi_id + scsi-generic not properly setting up the expected /dev/disk/by-id/ symlinks because the INQUIRY payload was containing extra bogus data preventing the proper NAA IEEE WWN from being parsed by userspace. Cc: Christoph Hellwig Cc: Andy Grover Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/loopback/tcm_loop.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 70c2e7fa666..4b5421b391d 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -127,6 +127,24 @@ static struct se_cmd *tcm_loop_allocate_core_cmd( set_host_byte(sc, DID_NO_CONNECT); return NULL; } + /* + * Because some userspace code via scsi-generic do not memset their + * associated read buffers, go ahead and do that here for type + * SCF_SCSI_CONTROL_SG_IO_CDB. Also note that this is currently + * guaranteed to be a single SGL for SCF_SCSI_CONTROL_SG_IO_CDB + * by target core in transport_generic_allocate_tasks() -> + * transport_generic_cmd_sequencer(). + */ + if (se_cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB && + se_cmd->data_direction == DMA_FROM_DEVICE) { + struct scatterlist *sg = scsi_sglist(sc); + unsigned char *buf = kmap(sg_page(sg)) + sg->offset; + + if (buf != NULL) { + memset(buf, 0, sg->length); + kunmap(sg_page(sg)); + } + } transport_device_setup_cmd(se_cmd); return se_cmd; From 292b3893b8e010398a338b482f40cbcd62e01a97 Mon Sep 17 00:00:00 2001 From: Petr Uzel Date: Fri, 21 Oct 2011 13:31:09 +0200 Subject: [PATCH 0214/4025] st: fix race in st_scsi_execute_end MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c68bf8eeaa57c852e74adcf597237be149eef830 upstream. The call to complete() in st_scsi_execute_end() wakes up sleeping thread in write_behind_check(), which frees the st_request, thus invalidating the pointer to the associated bio structure, which is then passed to the blk_rq_unmap_user(). Fix by storing pointer to bio structure into temporary local variable. This bug is present since at least linux-2.6.32. Signed-off-by: Petr Uzel Reported-by: Juergen Groß Reviewed-by: Jan Kara Acked-by: Kai Mäkisara Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/st.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 1871b8ae83a..9b28f39bac2 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -462,14 +462,16 @@ static void st_scsi_execute_end(struct request *req, int uptodate) { struct st_request *SRpnt = req->end_io_data; struct scsi_tape *STp = SRpnt->stp; + struct bio *tmp; STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors; STp->buffer->cmdstat.residual = req->resid_len; + tmp = SRpnt->bio; if (SRpnt->waiting) complete(SRpnt->waiting); - blk_rq_unmap_user(SRpnt->bio); + blk_rq_unmap_user(tmp); __blk_put_request(req->q, req); } From 51b702dc3de6c2b5ba3c091f755271776bce7ee4 Mon Sep 17 00:00:00 2001 From: "Moger, Babu" Date: Wed, 26 Oct 2011 14:29:38 -0400 Subject: [PATCH 0215/4025] scsi_dh: check queuedata pointer before proceeding further commit a18a920c70d48a8e4a2b750d8a183b3c1a4be514 upstream. This patch validates sdev pointer in scsi_dh_activate before proceeding further. Without this check we might see the panic as below. I have seen this panic multiple times.. Call trace: #0 [ffff88007d647b50] machine_kexec at ffffffff81020902 #1 [ffff88007d647ba0] crash_kexec at ffffffff810875b0 #2 [ffff88007d647c70] oops_end at ffffffff8139c650 #3 [ffff88007d647c90] __bad_area_nosemaphore at ffffffff8102dd15 #4 [ffff88007d647d50] page_fault at ffffffff8139b8cf [exception RIP: scsi_dh_activate+0x82] RIP: ffffffffa0041922 RSP: ffff88007d647e00 RFLAGS: 00010046 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 00000000000093c5 RDX: 00000000000093c5 RSI: ffffffffa02e6640 RDI: ffff88007cc88988 RBP: 000000000000000f R8: ffff88007d646000 R9: 0000000000000000 R10: ffff880082293790 R11: 00000000ffffffff R12: ffff88007cc88988 R13: 0000000000000000 R14: 0000000000000286 R15: ffff880037b845e0 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0000 #5 [ffff88007d647e38] run_workqueue at ffffffff81060268 #6 [ffff88007d647e78] worker_thread at ffffffff81060386 #7 [ffff88007d647ee8] kthread at ffffffff81064436 #8 [ffff88007d647f48] kernel_thread at ffffffff81003fba Signed-off-by: Babu Moger Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/device_handler/scsi_dh.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 0119b814779..d973325ded2 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -398,7 +398,15 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) spin_lock_irqsave(q->queue_lock, flags); sdev = q->queuedata; - if (sdev && sdev->scsi_dh_data) + if (!sdev) { + spin_unlock_irqrestore(q->queue_lock, flags); + err = SCSI_DH_NOSYS; + if (fn) + fn(data, err); + return err; + } + + if (sdev->scsi_dh_data) scsi_dh = sdev->scsi_dh_data->scsi_dh; dev = get_device(&sdev->sdev_gendev); if (!scsi_dh || !dev || From 8fa9474347f32c7991adc1271e6f34e01479dd31 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 23 Sep 2011 19:48:18 +0200 Subject: [PATCH 0216/4025] Make scsi_free_queue() kill pending SCSI commands commit 3308511c93e6ad0d3c58984ecd6e5e57f96b12c8 upstream. Make sure that SCSI device removal via scsi_remove_host() does finish all pending SCSI commands. Currently that's not the case and hence removal of a SCSI host during I/O can cause a deadlock. See also "blkdev_issue_discard() hangs forever if underlying storage device is removed" (http://bugzilla.kernel.org/show_bug.cgi?id=40472). See also http://lkml.org/lkml/2011/8/27/6. Signed-off-by: Bart Van Assche Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/hosts.c | 9 ++++++--- drivers/scsi/scsi_lib.c | 9 +++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 4f7a5829ea4..351dc0b86fa 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -286,6 +286,7 @@ static void scsi_host_dev_release(struct device *dev) { struct Scsi_Host *shost = dev_to_shost(dev); struct device *parent = dev->parent; + struct request_queue *q; scsi_proc_hostdir_rm(shost->hostt); @@ -293,9 +294,11 @@ static void scsi_host_dev_release(struct device *dev) kthread_stop(shost->ehandler); if (shost->work_q) destroy_workqueue(shost->work_q); - if (shost->uspace_req_q) { - kfree(shost->uspace_req_q->queuedata); - scsi_free_queue(shost->uspace_req_q); + q = shost->uspace_req_q; + if (q) { + kfree(q->queuedata); + q->queuedata = NULL; + scsi_free_queue(q); } scsi_destroy_command_freelist(shost); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 28d9c9d6b4b..f97acffdddc 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1697,6 +1697,15 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) void scsi_free_queue(struct request_queue *q) { + unsigned long flags; + + WARN_ON(q->queuedata); + + /* cause scsi_request_fn() to kill all non-finished requests */ + spin_lock_irqsave(q->queue_lock, flags); + q->request_fn(q); + spin_unlock_irqrestore(q->queue_lock, flags); + blk_cleanup_queue(q); } From 6fffe112243a02792d352087d32bf05ccb2cf90d Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Thu, 3 Nov 2011 08:56:22 +1100 Subject: [PATCH 0217/4025] Fix block queue and elevator memory leak in scsi_alloc_sdev commit f7c9c6bb14f3104608a3a83cadea10a6943d2804 upstream. When looking at memory consumption issues I noticed quite a lot of memory in the kmalloc-2048 bucket: OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME 6561 6471 98% 2.30K 243 27 15552K kmalloc-2048 Over 15MB. slub debug shows that cfq is responsible for almost all of it: # sort -nr /sys/kernel/slab/kmalloc-2048/alloc_calls 6402 .cfq_init_queue+0xec/0x460 age=43423/43564/43655 pid=1 cpus=4,11,13 In scsi_alloc_sdev we do scsi_alloc_queue but if slave_alloc fails we don't free it with scsi_free_queue. The patch below fixes the issue: OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME 135 72 53% 2.30K 5 27 320K kmalloc-2048 # cat /sys/kernel/slab/kmalloc-2048/alloc_calls 3 .cfq_init_queue+0xec/0x460 age=3811/3876/3925 pid=1 cpus=4,11,13 Signed-off-by: Anton Blanchard Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_scan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 44e8ca398ef..72273a0e566 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -322,6 +322,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, scsi_device_set_state(sdev, SDEV_DEL); transport_destroy_device(&sdev->sdev_gendev); put_device(&sdev->sdev_dev); + scsi_free_queue(sdev->request_queue); put_device(&sdev->sdev_gendev); out: if (display_failure_msg) From ac310457b4fd7634983788faf0c4f29cd2d5384b Mon Sep 17 00:00:00 2001 From: "nagalakshmi.nandigama@lsi.com" Date: Fri, 21 Oct 2011 10:06:33 +0530 Subject: [PATCH 0218/4025] mpt2sas: Fix for system hang when discovery in progress commit 0167ac67ff6f35bf2364f7672c8012b0cd40277f upstream. Fix for issue : While discovery is in progress, hot unplug and hot plug of enclosure connected to the controller card is causing system to hang. When a device is in the process of being detected at driver load time then if it is removed, the device that is no longer present will not be added to the list. So the code in _scsih_probe_sas() is rearranged as such so the devices that failed to be detected are not added to the list. Signed-off-by: Nagalakshmi Nandigama Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 8dc2ad4a0a3..5690f09e010 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -7318,22 +7318,27 @@ _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc) /* SAS Device List */ list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list, list) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_move_tail(&sas_device->list, &ioc->sas_device_list); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (ioc->hide_drives) continue; if (!mpt2sas_transport_port_add(ioc, sas_device->handle, sas_device->sas_address_parent)) { - _scsih_sas_device_remove(ioc, sas_device); + list_del(&sas_device->list); + kfree(sas_device); + continue; } else if (!sas_device->starget) { mpt2sas_transport_port_remove(ioc, sas_device->sas_address, sas_device->sas_address_parent); - _scsih_sas_device_remove(ioc, sas_device); + list_del(&sas_device->list); + kfree(sas_device); + continue; + } + spin_lock_irqsave(&ioc->sas_device_lock, flags); + list_move_tail(&sas_device->list, &ioc->sas_device_list); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } } From 9eb72dda42ed9162026d69aabcdc0528d7994193 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Oct 2011 11:08:01 +0800 Subject: [PATCH 0219/4025] ASoC: wm8711: Fix wrong mask for setting input audio data bit length select commit 04c57163c8edfbc50e022737014069998ba4fc5f upstream. The Input Audio Data Bit Length Select is controlled by BIT[3:2] of WM8711_IFACE(07h) register. Current code incorrectly masks BIT[1:0] which is for Audio Data Format Select. Signed-off-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8711.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index a537e4af6ae..15be229b388 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -150,7 +150,7 @@ static int wm8711_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec); - u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc; + u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfff3; int i = get_coeff(wm8711->sysclk, params_rate(params)); u16 srate = (coeff_div[i].sr << 2) | (coeff_div[i].bosr << 1) | coeff_div[i].usb; From a8c34bb24eb25d50481528cbfc70e29bde147cc2 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Oct 2011 15:17:56 +0800 Subject: [PATCH 0220/4025] ASoC: Leave input audio data bit length settings untouched in wm8711_set_dai_fmt commit d558cfc30064a97c2c65dbd2b3a4f5a1dea7ec1b upstream. Current implementation in wm8711_set_dai_fmt always clear BIT[3:2] (the Input Audio Data Bit Length Select) of WM8711_IFACE(07h) register. Input Audio Data Bit Length Select bits are set by wm8711_hw_params, we should leave BIT[3:2] untouched in wm8711_set_dai_fmt. Signed-off-by: Axel Lin Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8711.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 15be229b388..1dae5c4d993 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -231,7 +231,7 @@ static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; - u16 iface = 0; + u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0x000c; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { From f11d1a122ac23d7da2dedd0104851b58461e32b3 Mon Sep 17 00:00:00 2001 From: Hong Xu Date: Fri, 28 Oct 2011 15:36:39 +0800 Subject: [PATCH 0221/4025] ASoC: WM8904: Set `invert' bit for Capture Switch commit 5a7c5f26df3c0122814dfa1c13ef6dfbdbffdb86 upstream. Set `invert' bit for Capture Switch. Otherwise analogue is muted when Capture Switch is ON. Signed-off-by: Hong Xu Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8904.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 9b3bba4df5b..0fce199a727 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -868,7 +868,7 @@ SOC_ENUM("Right Capture Mode", rin_mode), SOC_DOUBLE_R("Capture Volume", WM8904_ANALOGUE_LEFT_INPUT_0, WM8904_ANALOGUE_RIGHT_INPUT_0, 0, 31, 0), SOC_DOUBLE_R("Capture Switch", WM8904_ANALOGUE_LEFT_INPUT_0, - WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 0), + WM8904_ANALOGUE_RIGHT_INPUT_0, 7, 1, 1), SOC_SINGLE("High Pass Filter Switch", WM8904_ADC_DIGITAL_0, 4, 1, 0), SOC_ENUM("High Pass Filter Mode", hpf_mode), From 6601dc2a3a0518851fd47b8a7e34e624c3ddceef Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 1 Nov 2011 13:36:10 +0000 Subject: [PATCH 0222/4025] ASoC: Ensure WM8962 PLL registers are reset commit 4f4488abc97c1c27ff029f887944e6a6da1f5733 upstream. The WM8962 has a separate software reset for the PLL registers. Ensure that these are reset also on startup. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8962.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 6bc72a7b6b9..ebff8ad788a 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -1957,7 +1957,13 @@ static int wm8962_readable_register(struct snd_soc_codec *codec, unsigned int re static int wm8962_reset(struct snd_soc_codec *codec) { - return snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0x6243); + int ret; + + ret = snd_soc_write(codec, WM8962_SOFTWARE_RESET, 0x6243); + if (ret != 0) + return ret; + + return snd_soc_write(codec, WM8962_PLL_SOFTWARE_RESET, 0); } static const DECLARE_TLV_DB_SCALE(inpga_tlv, -2325, 75, 0); From 22bef71b2e411ee05b9b9199394c3a209924926f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 1 Nov 2011 13:53:37 +0000 Subject: [PATCH 0223/4025] ASoC: Ensure the WM8962 oscillator and PLLs start up disabled commit 2af8de8c39cf58e5a5e40a9d5d71332da98e6ba7 upstream. Since there is no current software control for these they would otherwise be left enabled, consuming power. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8962.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index ebff8ad788a..4a0f666a90b 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3829,6 +3829,11 @@ static int wm8962_probe(struct snd_soc_codec *codec) */ snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_ENA, 0); + /* Ensure that the oscillator and PLLs are disabled */ + snd_soc_update_bits(codec, WM8962_PLL2, + WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA, + 0); + regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies); if (pdata) { From 6fa9e3e3e01b8741eead6e00bb968ef3b4fddc3f Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 25 Oct 2011 10:25:49 +1100 Subject: [PATCH 0224/4025] NFS/sunrpc: don't use a credential with extra groups. commit dc6f55e9f8dac4b6479be67c5c9128ad37bb491f upstream. The sunrpc layer keeps a cache of recently used credentials and 'unx_match' is used to find the credential which matches the current process. However unx_match allows a match when the cached credential has extra groups at the end of uc_gids list which are not in the process group list. So if a process with a list of (say) 4 group accesses a file and gains access because of the last group in the list, then another process with the same uid and gid, and a gid list being the first tree of the gids of the original process tries to access the file, it will be granted access even though it shouldn't as the wrong rpc credential will be used. Signed-off-by: NeilBrown Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/auth_unix.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index 4cb70dc6e7a..e50502d8ceb 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c @@ -129,6 +129,9 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags) for (i = 0; i < groups ; i++) if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i)) return 0; + if (groups < NFS_NGROUPS && + cred->uc_gids[groups] != NOGROUP) + return 0; return 1; } From f53881e6463124c910b17a5ea722a5cf5ab67fb3 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Mon, 17 Oct 2011 13:42:43 +0200 Subject: [PATCH 0225/4025] block: make gendisk hold a reference to its queue commit f992ae801a7dec34a4ed99a6598bbbbfb82af4fb upstream. The following command sequence triggers an oops. # mount /dev/sdb1 /mnt # echo 1 > /sys/class/scsi_device/0\:0\:1\:0/device/delete # umount /mnt general protection fault: 0000 [#1] PREEMPT SMP CPU 2 Modules linked in: Pid: 791, comm: umount Not tainted 3.1.0-rc3-work+ #8 Bochs Bochs RIP: 0010:[] [] __lock_acquire+0x389/0x1d60 ... Call Trace: [] lock_acquire+0x95/0x140 [] _raw_spin_lock+0x3b/0x50 [] bdi_lock_two+0x5c/0x70 [] bdev_inode_switch_bdi+0x4c/0xf0 [] __blkdev_put+0x11b/0x1d0 [] __blkdev_put+0x160/0x1d0 [] blkdev_put+0x5f/0x190 [] kill_block_super+0x4d/0x80 [] deactivate_locked_super+0x45/0x70 [] deactivate_super+0x4a/0x70 [] mntput_no_expire+0xed/0x130 [] sys_umount+0x7e/0x3a0 [] system_call_fastpath+0x16/0x1b This is because bdev holds on to disk but disk doesn't pin the associated queue. If a SCSI device is removed while the device is still open, the sdev puts the base reference to the queue on release. When the bdev is finally released, the associated queue is already gone along with the bdi and bdev_inode_switch_bdi() ends up dereferencing already freed bdi. Even if it were not for this bug, disk not holding onto the associated queue is very unusual and error-prone. Fix it by making add_disk() take an extra reference to its queue and put it on disk_release() and ensuring that disk and its fops owner are put in that order after all accesses to the disk and queue are complete. Signed-off-by: Tejun Heo Cc: Jens Axboe Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/genhd.c | 8 ++++++++ fs/block_dev.c | 13 ++++++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/block/genhd.c b/block/genhd.c index 3608289c8ec..8c0829a3637 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -611,6 +611,12 @@ void add_disk(struct gendisk *disk) register_disk(disk); blk_register_queue(disk); + /* + * Take an extra ref on queue which will be put on disk_release() + * so that it sticks around as long as @disk is there. + */ + WARN_ON_ONCE(blk_get_queue(disk->queue)); + retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj, "bdi"); WARN_ON(retval); @@ -1103,6 +1109,8 @@ static void disk_release(struct device *dev) disk_replace_part_tbl(disk, NULL); free_part_stats(&disk->part0); free_part_info(&disk->part0); + if (disk->queue) + blk_put_queue(disk->queue); kfree(disk); } struct class block_class = { diff --git a/fs/block_dev.c b/fs/block_dev.c index 194cf66bc8f..34503ba6c07 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1075,6 +1075,7 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part); static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) { struct gendisk *disk; + struct module *owner; int ret; int partno; int perm = 0; @@ -1100,6 +1101,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) disk = get_gendisk(bdev->bd_dev, &partno); if (!disk) goto out; + owner = disk->fops->owner; disk_block_events(disk); mutex_lock_nested(&bdev->bd_mutex, for_part); @@ -1127,8 +1129,8 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) bdev->bd_disk = NULL; mutex_unlock(&bdev->bd_mutex); disk_unblock_events(disk); - module_put(disk->fops->owner); put_disk(disk); + module_put(owner); goto restart; } } @@ -1184,8 +1186,8 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) goto out_unlock_bdev; } /* only one opener holds refs to the module and disk */ - module_put(disk->fops->owner); put_disk(disk); + module_put(owner); } bdev->bd_openers++; if (for_part) @@ -1205,8 +1207,8 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) out_unlock_bdev: mutex_unlock(&bdev->bd_mutex); disk_unblock_events(disk); - module_put(disk->fops->owner); put_disk(disk); + module_put(owner); out: bdput(bdev); @@ -1432,14 +1434,15 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) if (!bdev->bd_openers) { struct module *owner = disk->fops->owner; - put_disk(disk); - module_put(owner); disk_put_part(bdev->bd_part); bdev->bd_part = NULL; bdev->bd_disk = NULL; if (bdev != bdev->bd_contains) victim = bdev->bd_contains; bdev->bd_contains = NULL; + + put_disk(disk); + module_put(owner); } mutex_unlock(&bdev->bd_mutex); bdput(bdev); From 9ad93ba528bf5555a96ef64b7ec1af398277ad52 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Mon, 10 Oct 2011 12:33:21 -0400 Subject: [PATCH 0226/4025] xen/blkback: Report VBD_WSECT (wr_sect) properly. commit 5c62cb48602dba95159c81ffeca179d3852e25be upstream. We did not increment the amount of sectors written to disk b/c we tested for the == WRITE which is incorrect - as the operations are more of WRITE_FLUSH, WRITE_ODIRECT. This patch fixes it by doing a & WRITE check. Reported-by: Andy Burns Suggested-by: Ian Campbell Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/block/xen-blkback/blkback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 5cf2993a833..54139d0f5fe 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -667,7 +667,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, if (operation == READ) blkif->st_rd_sect += preq.nr_sects; - else if (operation == WRITE || operation == WRITE_FLUSH) + else if (operation & WRITE) blkif->st_wr_sect += preq.nr_sects; return 0; From 8185df43d48a71605934d9a7c6db4d93e7b25d5c Mon Sep 17 00:00:00 2001 From: Dan McGee Date: Tue, 1 Nov 2011 18:23:10 -0500 Subject: [PATCH 0227/4025] VFS: fix statfs() automounter semantics regression commit 5c8a0fbba543d9428a486f0d1282bbcf3cf1d95a upstream. No one in their right mind would expect statfs() to not work on a automounter managed mount point. Fix it. [ I'm not sure about the "no one in their right mind" part. It's not mounted, and you didn't ask for it to be mounted. But nobody will really care, and this probably makes it match previous semantics, so.. - Linus ] This mirrors the fix made to the quota code in 815d405ceff0d69646. Signed-off-by: Dan McGee Cc: Trond Myklebust Cc: Alexander Viro Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/statfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/statfs.c b/fs/statfs.c index 8244924dec5..9cf04a11896 100644 --- a/fs/statfs.c +++ b/fs/statfs.c @@ -76,7 +76,7 @@ EXPORT_SYMBOL(vfs_statfs); int user_statfs(const char __user *pathname, struct kstatfs *st) { struct path path; - int error = user_path(pathname, &path); + int error = user_path_at(AT_FDCWD, pathname, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path); if (!error) { error = vfs_statfs(&path, st); path_put(&path); From 0447f4d5654bb5d95008f16dad839104f8d0d39a Mon Sep 17 00:00:00 2001 From: Mike Miller Date: Fri, 21 Oct 2011 08:19:43 +0200 Subject: [PATCH 0228/4025] hpsa: add small delay when using PCI Power Management to reset for kump commit c4853efec665134b2e6fc9c13447323240980351 upstream. The P600 requires a small delay when changing states. Otherwise we may think the board did not reset and we bail. This for kdump only and is particular to the P600. Signed-off-by: Mike Miller Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/hpsa.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 78c2e20b202..6689d5d4d40 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -3300,6 +3300,13 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev, pmcsr &= ~PCI_PM_CTRL_STATE_MASK; pmcsr |= PCI_D0; pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr); + + /* + * The P600 requires a small delay when changing states. + * Otherwise we may think the board did not reset and we bail. + * This for kdump only and is particular to the P600. + */ + msleep(500); } return 0; } From 656460cd7714653cf60a10c79e02cbfe2d9bf732 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 7 Nov 2011 21:21:26 +0000 Subject: [PATCH 0229/4025] VFS: we need to set LOOKUP_JUMPED on mountpoint crossing commit a3fbbde70a0cec017f2431e8f8de208708c76acc upstream. Mountpoint crossing is similar to following procfs symlinks - we do not get ->d_revalidate() called for dentry we have arrived at, with unpleasant consequences for NFS4. Simple way to reproduce the problem in mainline: cat >/tmp/a.c <<'EOF' #include #include #include main() { struct flock fl = {.l_type = F_RDLCK, .l_whence = SEEK_SET, .l_len = 1}; if (fcntl(0, F_SETLK, &fl)) perror("setlk"); } EOF cc /tmp/a.c -o /tmp/test then on nfs4: mount --bind file1 file2 /tmp/test < file1 # ok /tmp/test < file2 # spews "setlk: No locks available"... What happens is the missing call of ->d_revalidate() after mountpoint crossing and that's where NFS4 would issue OPEN request to server. The fix is simple - treat mountpoint crossing the same way we deal with following procfs-style symlinks. I.e. set LOOKUP_JUMPED... Signed-off-by: Al Viro Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/namei.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/fs/namei.c b/fs/namei.c index 49472a1b79e..f7593c0899d 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -910,7 +910,7 @@ static int follow_managed(struct path *path, unsigned flags) mntput(path->mnt); if (ret == -EISDIR) ret = 0; - return ret; + return ret < 0 ? ret : need_mntput; } int follow_down_one(struct path *path) @@ -958,6 +958,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, break; path->mnt = mounted; path->dentry = mounted->mnt_root; + nd->flags |= LOOKUP_JUMPED; nd->seq = read_seqcount_begin(&path->dentry->d_seq); /* * Update the inode too. We don't need to re-check the @@ -1232,6 +1233,8 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, path_put_conditional(path, nd); return err; } + if (err) + nd->flags |= LOOKUP_JUMPED; *inode = path->dentry->d_inode; return 0; } @@ -2118,6 +2121,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path, } /* create side of things */ + /* + * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED has been + * cleared when we got to the last component we are about to look up + */ error = complete_walk(nd); if (error) return ERR_PTR(error); @@ -2186,6 +2193,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path, if (error < 0) goto exit_dput; + if (error) + nd->flags |= LOOKUP_JUMPED; + error = -ENOENT; if (!path->dentry->d_inode) goto exit_dput; @@ -2195,6 +2205,10 @@ static struct file *do_last(struct nameidata *nd, struct path *path, path_to_nameidata(path, nd); nd->inode = path->dentry->d_inode; + /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ + error = complete_walk(nd); + if (error) + goto exit; error = -EISDIR; if (S_ISDIR(nd->inode->i_mode)) goto exit; From 2b7940d84f184ad4b71cf66465bb55212d3b3fd8 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 10 Aug 2011 20:44:21 +0000 Subject: [PATCH 0230/4025] powerpc/numa: Remove double of_node_put in hot_add_node_scn_to_nid commit 6083184269fd723affca4f6340e491950267622a upstream. During memory hotplug testing, I got the following warning: ERROR: Bad of_node_put() on /memory@0 of_node_release kref_put of_node_put of_find_node_by_type hot_add_node_scn_to_nid hot_add_scn_to_nid memory_add_physaddr_to_nid ... of_find_node_by_type() loop does the of_node_put for us so we only need the handle the case where we terminate the loop early. As suggested by Stephen Rothwell we can do the of_node_put unconditionally outside of the loop since of_node_put handles a NULL argument fine. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/numa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c index 2164006fe17..2c1ae7a5fb5 100644 --- a/arch/powerpc/mm/numa.c +++ b/arch/powerpc/mm/numa.c @@ -1214,11 +1214,12 @@ int hot_add_node_scn_to_nid(unsigned long scn_addr) break; } - of_node_put(memory); if (nid >= 0) break; } + of_node_put(memory); + return nid; } From 55a6bcf9d9a66921b7a7a854ca86356e901114fe Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 10 Aug 2011 20:44:24 +0000 Subject: [PATCH 0231/4025] powerpc: Fix oops when echoing bad values to /sys/devices/system/memory/probe commit a11940978bd598e65996b4f807cf4904793f7025 upstream. If we echo an address the hypervisor doesn't like to /sys/devices/system/memory/probe we oops the box: # echo 0x10000000000 > /sys/devices/system/memory/probe kernel BUG at arch/powerpc/mm/hash_utils_64.c:541! The backtrace is: create_section_mapping arch_add_memory add_memory memory_probe_store sysdev_class_store sysfs_write_file vfs_write SyS_write In create_section_mapping we BUG if htab_bolt_mapping returned an error. A better approach is to return an error which will propagate back to userspace. Rerunning the test with this patch applied: # echo 0x10000000000 > /sys/devices/system/memory/probe -bash: echo: write error: Invalid argument Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/sparsemem.h | 2 +- arch/powerpc/mm/hash_utils_64.c | 6 +++--- arch/powerpc/mm/mem.c | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/include/asm/sparsemem.h b/arch/powerpc/include/asm/sparsemem.h index 54a47ea2c3a..0c5fa314561 100644 --- a/arch/powerpc/include/asm/sparsemem.h +++ b/arch/powerpc/include/asm/sparsemem.h @@ -16,7 +16,7 @@ #endif /* CONFIG_SPARSEMEM */ #ifdef CONFIG_MEMORY_HOTPLUG -extern void create_section_mapping(unsigned long start, unsigned long end); +extern int create_section_mapping(unsigned long start, unsigned long end); extern int remove_section_mapping(unsigned long start, unsigned long end); #ifdef CONFIG_NUMA extern int hot_add_scn_to_nid(unsigned long scn_addr); diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 26b2872b3d0..07f9e9f0d87 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -534,11 +534,11 @@ static unsigned long __init htab_get_table_size(void) } #ifdef CONFIG_MEMORY_HOTPLUG -void create_section_mapping(unsigned long start, unsigned long end) +int create_section_mapping(unsigned long start, unsigned long end) { - BUG_ON(htab_bolt_mapping(start, end, __pa(start), + return htab_bolt_mapping(start, end, __pa(start), pgprot_val(PAGE_KERNEL), mmu_linear_psize, - mmu_kernel_ssize)); + mmu_kernel_ssize); } int remove_section_mapping(unsigned long start, unsigned long end) diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 29d4dde65c4..278ec8ef4f6 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -123,7 +123,8 @@ int arch_add_memory(int nid, u64 start, u64 size) pgdata = NODE_DATA(nid); start = (unsigned long)__va(start); - create_section_mapping(start, start + size); + if (create_section_mapping(start, start + size)) + return -EINVAL; /* this should work for most non-highmem platforms */ zone = pgdata->node_zones; From 747613961425127da9e14e020500b184d4f7a42c Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Sun, 14 Aug 2011 14:30:30 +0000 Subject: [PATCH 0232/4025] powerpc/pseries: Avoid spurious error during hotplug CPU add commit 9c740025c51a26ab00192cfc464064d4ccbfe3fc upstream. During hotplug CPU add we get the following error: Unexpected Error (0) returned from configure-connector ibm,configure-connector returns 0 for configuration complete, so catch this and avoid the error. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/dlpar.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 57ceb92b228..82766e5a79e 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -112,6 +112,7 @@ void dlpar_free_cc_nodes(struct device_node *dn) dlpar_free_one_cc_node(dn); } +#define COMPLETE 0 #define NEXT_SIBLING 1 #define NEXT_CHILD 2 #define NEXT_PROPERTY 3 @@ -158,6 +159,9 @@ struct device_node *dlpar_configure_connector(u32 drc_index) spin_unlock(&rtas_data_buf_lock); switch (rc) { + case COMPLETE: + break; + case NEXT_SIBLING: dn = dlpar_parse_cc_node(ccwa); if (!dn) From 71b1a9d35d6cbd2e37c1101ca5f779ca55f7fb03 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Fri, 26 Aug 2011 10:36:31 +0000 Subject: [PATCH 0233/4025] powerpc/eeh: Fix /proc/ppc64/eeh creation commit 8feaa43494cee5e938fd5a57b9e9bf1c827e6ccd upstream. Since commit 188917e183cf9ad0374b571006d0fc6d48a7f447, /proc/ppc64 is a symlink to /proc/powerpc/. That means that creating /proc/ppc64/eeh will end up with a unaccessible file, that is not listed under /proc/powerpc/ and, then, not listed under /proc/ppc64/. Creating /proc/powerpc/eeh fixes that problem and maintain the compatibility intended with the ppc64 symlink. Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/eeh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index 46b55cf563e..3608704554d 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c @@ -1338,7 +1338,7 @@ static const struct file_operations proc_eeh_operations = { static int __init eeh_init_proc(void) { if (machine_is(pseries)) - proc_create("ppc64/eeh", 0, NULL, &proc_eeh_operations); + proc_create("powerpc/eeh", 0, NULL, &proc_eeh_operations); return 0; } __initcall(eeh_init_proc); From eaeafcd898108e4e026faf43ca41817f5de6ee66 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 14 Sep 2011 09:43:15 +0000 Subject: [PATCH 0234/4025] powerpc: Fix deadlock in icswx code commit 8bdafa39a47265bc029838b35cc6585f69224afa upstream. The icswx code introduced an A-B B-A deadlock: CPU0 CPU1 ---- ---- lock(&anon_vma->mutex); lock(&mm->mmap_sem); lock(&anon_vma->mutex); lock(&mm->mmap_sem); Instead of using the mmap_sem to keep mm_users constant, take the page table spinlock. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/mmu_context_hash64.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c index 3bafc3deca6..4ff587e3825 100644 --- a/arch/powerpc/mm/mmu_context_hash64.c +++ b/arch/powerpc/mm/mmu_context_hash64.c @@ -136,8 +136,8 @@ int use_cop(unsigned long acop, struct mm_struct *mm) if (!mm || !acop) return -EINVAL; - /* We need to make sure mm_users doesn't change */ - down_read(&mm->mmap_sem); + /* The page_table_lock ensures mm_users won't change under us */ + spin_lock(&mm->page_table_lock); spin_lock(mm->context.cop_lockp); if (mm->context.cop_pid == COP_PID_NONE) { @@ -164,7 +164,7 @@ int use_cop(unsigned long acop, struct mm_struct *mm) out: spin_unlock(mm->context.cop_lockp); - up_read(&mm->mmap_sem); + spin_unlock(&mm->page_table_lock); return ret; } @@ -185,8 +185,8 @@ void drop_cop(unsigned long acop, struct mm_struct *mm) if (WARN_ON_ONCE(!mm)) return; - /* We need to make sure mm_users doesn't change */ - down_read(&mm->mmap_sem); + /* The page_table_lock ensures mm_users won't change under us */ + spin_lock(&mm->page_table_lock); spin_lock(mm->context.cop_lockp); mm->context.acop &= ~acop; @@ -213,7 +213,7 @@ void drop_cop(unsigned long acop, struct mm_struct *mm) } spin_unlock(mm->context.cop_lockp); - up_read(&mm->mmap_sem); + spin_unlock(&mm->page_table_lock); } EXPORT_SYMBOL_GPL(drop_cop); From 1dc88f68f554b318691763867aab4ec7adc60945 Mon Sep 17 00:00:00 2001 From: "Luck, Tony" Date: Fri, 21 Oct 2011 14:42:55 -0700 Subject: [PATCH 0235/4025] ACPI atomicio: Convert width in bits to bytes in __acpi_ioremap_fast() commit 3bf3f8b19d2bfccc40f13c456bf339fd8f535ebc upstream. Callers to __acpi_ioremap_fast() pass the bit_width that they found in the acpi_generic_address structure. Convert from bits to bytes when passing to __acpi_find_iomap() - as it wants to see bytes, not bits. Signed-off-by: Tony Luck Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/atomicio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c index 7489b89c300..f151afe61aa 100644 --- a/drivers/acpi/atomicio.c +++ b/drivers/acpi/atomicio.c @@ -76,7 +76,7 @@ static void __iomem *__acpi_ioremap_fast(phys_addr_t paddr, { struct acpi_iomap *map; - map = __acpi_find_iomap(paddr, size); + map = __acpi_find_iomap(paddr, size/8); if (map) return map->vaddr + (paddr - map->paddr); else From 6167ded5698377fca7830c22be0ba976f91f2434 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 3 Nov 2011 00:07:32 +0000 Subject: [PATCH 0236/4025] netlink: validate NLA_MSECS length commit c30bc94758ae2a38a5eb31767c1985c0aae0950b upstream. L2TP for example uses NLA_MSECS like this: policy: [L2TP_ATTR_RECV_TIMEOUT] = { .type = NLA_MSECS, }, code: if (info->attrs[L2TP_ATTR_RECV_TIMEOUT]) cfg.reorder_timeout = nla_get_msecs(info->attrs[L2TP_ATTR_RECV_TIMEOUT]); As nla_get_msecs() is essentially nla_get_u64() plus the conversion to a HZ-based value, this will not properly reject attributes from userspace that aren't long enough and might overrun the message. Add NLA_MSECS to the attribute minlen array to check the size properly. Cc: Thomas Graf Signed-off-by: Johannes Berg Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- lib/nlattr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/nlattr.c b/lib/nlattr.c index ac09f2226dc..a8408b6cacd 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -20,6 +20,7 @@ static const u16 nla_attr_minlen[NLA_TYPE_MAX+1] = { [NLA_U16] = sizeof(u16), [NLA_U32] = sizeof(u32), [NLA_U64] = sizeof(u64), + [NLA_MSECS] = sizeof(u64), [NLA_NESTED] = NLA_HDRLEN, }; From 1cc8631784f67c62a8309897f7d4cb885a05ed6f Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Mon, 24 Oct 2011 18:13:40 +0530 Subject: [PATCH 0237/4025] ath9k_hw: Update AR9485 initvals to fix system hang issue commit 98fb2cc115b4ef1ea0a2d87a170c183bd395dd6c upstream. This patch fixes system hang when resuming from S3 state and lower rate sens failure issue. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ar9485_initvals.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index 611ea6ce850..d16d029f81a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -521,7 +521,7 @@ static const u32 ar9485_1_1_radio_postamble[][2] = { {0x000160ac, 0x24611800}, {0x000160b0, 0x03284f3e}, {0x0001610c, 0x00170000}, - {0x00016140, 0x10804008}, + {0x00016140, 0x50804008}, }; static const u32 ar9485_1_1_mac_postamble[][5] = { @@ -603,7 +603,7 @@ static const u32 ar9485_1_1_radio_core[][2] = { static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_enable_L1[][2] = { /* Addr allmodes */ - {0x00018c00, 0x10052e5e}, + {0x00018c00, 0x18052e5e}, {0x00018c04, 0x000801d8}, {0x00018c08, 0x0000080c}, }; @@ -776,7 +776,7 @@ static const u32 ar9485_modes_green_ob_db_tx_gain_1_1[][5] = { static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = { /* Addr allmodes */ - {0x00018c00, 0x10013e5e}, + {0x00018c00, 0x18013e5e}, {0x00018c04, 0x000801d8}, {0x00018c08, 0x0000080c}, }; @@ -882,7 +882,7 @@ static const u32 ar9485_fast_clock_1_1_baseband_postamble[][3] = { static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = { /* Addr allmodes */ - {0x00018c00, 0x10012e5e}, + {0x00018c00, 0x18012e5e}, {0x00018c04, 0x000801d8}, {0x00018c08, 0x0000080c}, }; @@ -1021,7 +1021,7 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = { static const u32 ar9485_1_1_pcie_phy_clkreq_enable_L1[][2] = { /* Addr allmodes */ - {0x00018c00, 0x10053e5e}, + {0x00018c00, 0x18053e5e}, {0x00018c04, 0x000801d8}, {0x00018c08, 0x0000080c}, }; From 632abf8b3f714da01daec2d43ffd9cd7b47f53a9 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 20 Oct 2011 19:05:49 +0200 Subject: [PATCH 0238/4025] mac80211: fix remain_off_channel regression commit eaa7af2ae582c9a8c51b374c48d5970b748a5ce2 upstream. The offchannel code is currently broken - we should remain_off_channel if the work was started, and the work's channel and channel_type are the same as local->tmp_channel and local->tmp_channel_type. However, if wk->chan_type and local->tmp_channel_type coexist (e.g. have the same channel type), we won't remain_off_channel. This behavior was introduced by commit da2fd1f ("mac80211: Allow work items to use existing channel type.") Tested-by: Ben Greear Signed-off-by: Eliad Peller Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/work.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/work.c b/net/mac80211/work.c index dc8ec05a8fc..0199f979aa4 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -1060,8 +1060,8 @@ static void ieee80211_work_work(struct work_struct *work) continue; if (wk->chan != local->tmp_channel) continue; - if (ieee80211_work_ct_coexists(wk->chan_type, - local->tmp_channel_type)) + if (!ieee80211_work_ct_coexists(wk->chan_type, + local->tmp_channel_type)) continue; remain_off_channel = true; } From 42c6d01ce89d43598fc804cf7c141d3252fe93b5 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 20 Oct 2011 19:05:50 +0200 Subject: [PATCH 0239/4025] mac80211: config hw when going back on-channel commit 6911bf0453e0d6ea8eb694a4ce67a68d071c538e upstream. When going back on-channel, we should reconfigure the hw iff the hardware is not already configured to the operational channel. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/work.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 0199f979aa4..52b758dbff5 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@ -1067,7 +1067,6 @@ static void ieee80211_work_work(struct work_struct *work) } if (!remain_off_channel && local->tmp_channel) { - bool on_oper_chan = ieee80211_cfg_on_oper_channel(local); local->tmp_channel = NULL; /* If tmp_channel wasn't operating channel, then * we need to go back on-channel. @@ -1077,7 +1076,7 @@ static void ieee80211_work_work(struct work_struct *work) * we still need to do a hardware config. Currently, * we cannot be here while scanning, however. */ - if (ieee80211_cfg_on_oper_channel(local) && !on_oper_chan) + if (!ieee80211_cfg_on_oper_channel(local)) ieee80211_hw_config(local, 0); /* At the least, we need to disable offchannel_ps, From 041f9e20b7f794fd7b4932e05d0c938a9ebbf658 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 28 Oct 2011 11:59:47 +0200 Subject: [PATCH 0240/4025] mac80211: disable powersave for broken APs commit 05cb91085760ca378f28fc274fbf77fc4fd9886c upstream. Only AID values 1-2007 are valid, but some APs have been found to send random bogus values, in the reported case an AP that was sending the AID field value 0xffff, an AID of 0x3fff (16383). There isn't much we can do but disable powersave since there's no way it can work properly in this case. Reported-by: Bill C Riemers Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0c5aed2257f..3fdac77b9cc 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -373,6 +373,7 @@ struct ieee80211_if_managed { unsigned long timers_running; /* used for quiesce/restart */ bool powersave; /* powersave requested for this iface */ + bool broken_ap; /* AP is broken -- turn off powersave */ enum ieee80211_smps_mode req_smps, /* requested smps mode */ ap_smps, /* smps mode AP thinks we're in */ driver_smps_mode; /* smps mode request */ diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 7a334fdd8d6..1563250a557 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -613,6 +613,9 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) if (!mgd->powersave) return false; + if (mgd->broken_ap) + return false; + if (!mgd->associated) return false; @@ -1450,10 +1453,21 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk, capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) - printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " - "set\n", sdata->name, aid); + printk(KERN_DEBUG + "%s: invalid AID value 0x%x; bits 15:14 not set\n", + sdata->name, aid); aid &= ~(BIT(15) | BIT(14)); + ifmgd->broken_ap = false; + + if (aid == 0 || aid > IEEE80211_MAX_AID) { + printk(KERN_DEBUG + "%s: invalid AID value %d (out of range), turn off PS\n", + sdata->name, aid); + aid = 0; + ifmgd->broken_ap = true; + } + pos = mgmt->u.assoc_resp.variable; ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); From 5805ad8491edbc343a07de169f32ade07dcb3406 Mon Sep 17 00:00:00 2001 From: Peter Wippich Date: Mon, 6 Jun 2011 15:50:58 +0200 Subject: [PATCH 0241/4025] mtd: mtdchar: add missing initializer on raw write commit bf5140817b2d65faac9b32fc9057a097044ac35b upstream. On writes in MODE_RAW the mtd_oob_ops struct is not sufficiently initialized which may cause nandwrite to fail. With this patch it is possible to write raw nand/oob data without additional ECC (either for testing or when some sectors need different oob layout e.g. bootloader) like nandwrite -n -r -o /dev/mtd0 Signed-off-by: Peter Wippich Tested-by: Ricard Wanderlof Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/mtdchar.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 3f92731a5b9..9f8658ef946 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -320,6 +320,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count ops.mode = MTD_OOB_RAW; ops.datbuf = kbuf; ops.oobbuf = NULL; + ops.ooboffs = 0; ops.len = len; ret = mtd->write_oob(mtd, *ppos, &ops); From 1bd1046f37d0a9a76bbcd45284229edacb8d890d Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Fri, 14 Oct 2011 07:33:20 -0700 Subject: [PATCH 0242/4025] mtd: provide an alias for the redboot module name commit d5de1907d0af22e1a02de2b16a624148517a39c2 upstream. parse_mtd_partitions takes a list of partition types; if the driver isn't loaded, it attempts to load it, and then it grabs the partition parser. For redboot, the module name is "redboot.ko", while the parser name is "RedBoot". Since modprobe is case-sensitive, attempting to modprobe "RedBoot" will never work. I suspect the embedded systems that make use of redboot just always manually loaded redboot prior to loading their specific nand chip drivers (or statically compiled it in). Signed-off-by: Andres Salomon Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/redboot.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 7a87d07cd79..4938bd0b024 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -297,6 +297,9 @@ static struct mtd_part_parser redboot_parser = { .name = "RedBoot", }; +/* mtd parsers will request the module by parser name */ +MODULE_ALIAS("RedBoot"); + static int __init redboot_parser_init(void) { return register_mtd_parser(&redboot_parser); From 7b333e0ef8a1efa488ad98956c6701884b0c2b4b Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Tue, 7 Jun 2011 03:01:06 -0700 Subject: [PATCH 0243/4025] mtd: pxa3xx_nand: fix nand detection issue commit 0fab028b77d714ad302404b23306cf7adb885223 upstream. When keep_config is set, the detection would goes different routine. That the driver would read out the setting which is set previously by bootloader. While most bootloader keep the irq mask as off, and current driver need all irq default open, keep_config behavior would lead to no irq at all. Signed-off-by: Lei Wen Tested-by: Daniel Mack Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/pxa3xx_nand.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 1fb3b3a8058..faa0edd2825 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -813,7 +813,7 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; /* set info fields needed to read id */ info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; - info->reg_ndcr = ndcr; + info->reg_ndcr = ndcr & ~NDCR_INT_MASK; info->cmdset = &default_cmdset; info->ndtr0cs0 = nand_readl(info, NDTR0CS0); @@ -882,7 +882,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) struct pxa3xx_nand_info *info = mtd->priv; struct platform_device *pdev = info->pdev; struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; - struct nand_flash_dev pxa3xx_flash_ids[2] = { {NULL,}, {NULL,} }; + struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL; const struct pxa3xx_nand_flash *f = NULL; struct nand_chip *chip = mtd->priv; uint32_t id = -1; @@ -942,8 +942,10 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) pxa3xx_flash_ids[0].erasesize = f->page_size * f->page_per_block; if (f->flash_width == 16) pxa3xx_flash_ids[0].options = NAND_BUSWIDTH_16; + pxa3xx_flash_ids[1].name = NULL; + def = pxa3xx_flash_ids; KEEP_CONFIG: - if (nand_scan_ident(mtd, 1, pxa3xx_flash_ids)) + if (nand_scan_ident(mtd, 1, def)) return -ENODEV; /* calculate addressing information */ info->col_addr_cycles = (mtd->writesize >= 2048) ? 2 : 1; @@ -954,9 +956,9 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) info->row_addr_cycles = 2; mtd->name = mtd_names[0]; chip->ecc.mode = NAND_ECC_HW; - chip->ecc.size = f->page_size; + chip->ecc.size = info->page_size; - chip->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16 : 0; + chip->options = (info->reg_ndcr & NDCR_DWIDTH_M) ? NAND_BUSWIDTH_16 : 0; chip->options |= NAND_NO_AUTOINCR; chip->options |= NAND_NO_READRDY; From 2fc862e051e87f66de8b505b339e55c509d684a3 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 7 Jun 2011 03:01:07 -0700 Subject: [PATCH 0244/4025] mtd: pxa3xx_nand: Fix blank page ECC mismatch commit 543e32d5ff165d0d68deedb0e3557478c7c36a4a upstream. This bug was introduced in f8155a40 ("mtd: pxa3xx_nand: rework irq logic") and causes the PXA3xx NAND controller fail to operate with NAND flash that has empty pages. According to the comment in this block, the hardware controller will report a double-bit error for empty pages, which can and must be ignored. This patch restores the original behaviour of the driver. Signed-off-by: Daniel Mack Acked-by: Lei Wen Cc: Haojian Zhuang Cc: David Woodhouse Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/pxa3xx_nand.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index faa0edd2825..30689cc2b3c 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -685,6 +685,8 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, * OOB, ignore such double bit errors */ if (is_buf_blank(buf, mtd->writesize)) + info->retcode = ERR_NONE; + else mtd->ecc_stats.failed++; } From ef52f3936f9f5d770ea177e5c769e68af1701a90 Mon Sep 17 00:00:00 2001 From: Jiaying Zhang Date: Wed, 31 Aug 2011 11:50:51 -0400 Subject: [PATCH 0245/4025] ext4: remove i_mutex lock in ext4_evict_inode to fix lockdep complaining commit 8c0bec2151a47906bf779c6715a10ce04453ab77 upstream. The i_mutex lock and flush_completed_IO() added by commit 2581fdc810 in ext4_evict_inode() causes lockdep complaining about potential deadlock in several places. In most/all of these LOCKDEP complaints it looks like it's a false positive, since many of the potential circular locking cases can't take place by the time the ext4_evict_inode() is called; but since at the very least it may mask real problems, we need to address this. This change removes the flush_completed_IO() and i_mutex lock in ext4_evict_inode(). Instead, we take a different approach to resolve the software lockup that commit 2581fdc810 intends to fix. Rather than having ext4-dio-unwritten thread wait for grabing the i_mutex lock of an inode, we use mutex_trylock() instead, and simply requeue the work item if we fail to grab the inode's i_mutex lock. This should speed up work queue processing in general and also prevents the following deadlock scenario: During page fault, shrink_icache_memory is called that in turn evicts another inode B. Inode B has some pending io_end work so it calls ext4_ioend_wait() that waits for inode B's i_ioend_count to become zero. However, inode B's ioend work was queued behind some of inode A's ioend work on the same cpu's ext4-dio-unwritten workqueue. As the ext4-dio-unwritten thread on that cpu is processing inode A's ioend work, it tries to grab inode A's i_mutex lock. Since the i_mutex lock of inode A is still hold before the page fault happened, we enter a deadlock. Signed-off-by: Jiaying Zhang Signed-off-by: "Theodore Ts'o" Cc: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- fs/ext4/ext4.h | 1 + fs/ext4/inode.c | 3 --- fs/ext4/page-io.c | 18 +++++++++++++++++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 4bc683806ea..1a34c1c8460 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -175,6 +175,7 @@ struct mpage_da_data { */ #define EXT4_IO_END_UNWRITTEN 0x0001 #define EXT4_IO_END_ERROR 0x0002 +#define EXT4_IO_END_QUEUED 0x0004 struct ext4_io_page { struct page *p_page; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index c94774c3276..1265904a239 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -190,9 +190,6 @@ void ext4_evict_inode(struct inode *inode) trace_ext4_evict_inode(inode); - mutex_lock(&inode->i_mutex); - ext4_flush_completed_IO(inode); - mutex_unlock(&inode->i_mutex); ext4_ioend_wait(inode); if (inode->i_nlink) { diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 97e5e98fd42..bd6a85e33c9 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -142,7 +142,23 @@ static void ext4_end_io_work(struct work_struct *work) unsigned long flags; int ret; - mutex_lock(&inode->i_mutex); + if (!mutex_trylock(&inode->i_mutex)) { + /* + * Requeue the work instead of waiting so that the work + * items queued after this can be processed. + */ + queue_work(EXT4_SB(inode->i_sb)->dio_unwritten_wq, &io->work); + /* + * To prevent the ext4-dio-unwritten thread from keeping + * requeueing end_io requests and occupying cpu for too long, + * yield the cpu if it sees an end_io request that has already + * been requeued. + */ + if (io->flag & EXT4_IO_END_QUEUED) + yield(); + io->flag |= EXT4_IO_END_QUEUED; + return; + } ret = ext4_end_io_nolock(io); if (ret < 0) { mutex_unlock(&inode->i_mutex); From 867ca3109d0289d0a62bb3c7fc3d365e9d478fae Mon Sep 17 00:00:00 2001 From: David Ward Date: Mon, 5 Sep 2011 16:47:23 +0000 Subject: [PATCH 0246/4025] net: Align AF-specific flowi structs to long commit 728871bc05afc8ff310b17dba3e57a2472792b13 upstream. AF-specific flowi structs are now passed to flow_key_compare, which must also be aligned to a long. Signed-off-by: David Ward Signed-off-by: David S. Miller Cc: Kim Phillips Signed-off-by: Greg Kroah-Hartman --- include/net/flow.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/net/flow.h b/include/net/flow.h index c6d5fe5ec1b..a33385366ed 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -68,7 +68,7 @@ struct flowi4 { #define fl4_ipsec_spi uli.spi #define fl4_mh_type uli.mht.type #define fl4_gre_key uli.gre_key -}; +} __attribute__((__aligned__(BITS_PER_LONG/8))); static inline void flowi4_init_output(struct flowi4 *fl4, int oif, __u32 mark, __u8 tos, __u8 scope, @@ -112,7 +112,7 @@ struct flowi6 { #define fl6_ipsec_spi uli.spi #define fl6_mh_type uli.mht.type #define fl6_gre_key uli.gre_key -}; +} __attribute__((__aligned__(BITS_PER_LONG/8))); struct flowidn { struct flowi_common __fl_common; @@ -127,7 +127,7 @@ struct flowidn { union flowi_uli uli; #define fld_sport uli.ports.sport #define fld_dport uli.ports.dport -}; +} __attribute__((__aligned__(BITS_PER_LONG/8))); struct flowi { union { From 3fa57c1bf5fb311544199b7837a08b9f5bf5e6e4 Mon Sep 17 00:00:00 2001 From: dpward Date: Mon, 5 Sep 2011 16:47:24 +0000 Subject: [PATCH 0247/4025] net: Handle different key sizes between address families in flow cache commit aa1c366e4febc7f5c2b84958a2dd7cd70e28f9d0 upstream. With the conversion of struct flowi to a union of AF-specific structs, some operations on the flow cache need to account for the exact size of the key. Signed-off-by: David Ward Signed-off-by: David S. Miller Cc: Kim Phillips Signed-off-by: Greg Kroah-Hartman --- include/net/flow.h | 19 +++++++++++++++++++ net/core/flow.c | 31 +++++++++++++++++-------------- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/include/net/flow.h b/include/net/flow.h index a33385366ed..32359fdc7e7 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -7,6 +7,7 @@ #ifndef _NET_FLOW_H #define _NET_FLOW_H +#include #include #include @@ -161,6 +162,24 @@ static inline struct flowi *flowidn_to_flowi(struct flowidn *fldn) return container_of(fldn, struct flowi, u.dn); } +typedef unsigned long flow_compare_t; + +static inline size_t flow_key_size(u16 family) +{ + switch (family) { + case AF_INET: + BUILD_BUG_ON(sizeof(struct flowi4) % sizeof(flow_compare_t)); + return sizeof(struct flowi4) / sizeof(flow_compare_t); + case AF_INET6: + BUILD_BUG_ON(sizeof(struct flowi6) % sizeof(flow_compare_t)); + return sizeof(struct flowi6) / sizeof(flow_compare_t); + case AF_DECnet: + BUILD_BUG_ON(sizeof(struct flowidn) % sizeof(flow_compare_t)); + return sizeof(struct flowidn) / sizeof(flow_compare_t); + } + return 0; +} + #define FLOW_DIR_IN 0 #define FLOW_DIR_OUT 1 #define FLOW_DIR_FWD 2 diff --git a/net/core/flow.c b/net/core/flow.c index 990703b8863..a6bda2a514f 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -172,29 +172,26 @@ static void flow_new_hash_rnd(struct flow_cache *fc, static u32 flow_hash_code(struct flow_cache *fc, struct flow_cache_percpu *fcp, - const struct flowi *key) + const struct flowi *key, + size_t keysize) { const u32 *k = (const u32 *) key; + const u32 length = keysize * sizeof(flow_compare_t) / sizeof(u32); - return jhash2(k, (sizeof(*key) / sizeof(u32)), fcp->hash_rnd) + return jhash2(k, length, fcp->hash_rnd) & (flow_cache_hash_size(fc) - 1); } -typedef unsigned long flow_compare_t; - /* I hear what you're saying, use memcmp. But memcmp cannot make - * important assumptions that we can here, such as alignment and - * constant size. + * important assumptions that we can here, such as alignment. */ -static int flow_key_compare(const struct flowi *key1, const struct flowi *key2) +static int flow_key_compare(const struct flowi *key1, const struct flowi *key2, + size_t keysize) { const flow_compare_t *k1, *k1_lim, *k2; - const int n_elem = sizeof(struct flowi) / sizeof(flow_compare_t); - - BUILD_BUG_ON(sizeof(struct flowi) % sizeof(flow_compare_t)); k1 = (const flow_compare_t *) key1; - k1_lim = k1 + n_elem; + k1_lim = k1 + keysize; k2 = (const flow_compare_t *) key2; @@ -215,6 +212,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, struct flow_cache_entry *fle, *tfle; struct hlist_node *entry; struct flow_cache_object *flo; + size_t keysize; unsigned int hash; local_bh_disable(); @@ -222,6 +220,11 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, fle = NULL; flo = NULL; + + keysize = flow_key_size(family); + if (!keysize) + goto nocache; + /* Packet really early in init? Making flow_cache_init a * pre-smp initcall would solve this. --RR */ if (!fcp->hash_table) @@ -230,11 +233,11 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, if (fcp->hash_rnd_recalc) flow_new_hash_rnd(fc, fcp); - hash = flow_hash_code(fc, fcp, key); + hash = flow_hash_code(fc, fcp, key, keysize); hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) { if (tfle->family == family && tfle->dir == dir && - flow_key_compare(key, &tfle->key) == 0) { + flow_key_compare(key, &tfle->key, keysize) == 0) { fle = tfle; break; } @@ -248,7 +251,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, if (fle) { fle->family = family; fle->dir = dir; - memcpy(&fle->key, key, sizeof(*key)); + memcpy(&fle->key, key, keysize * sizeof(flow_compare_t)); fle->object = NULL; hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]); fcp->hash_count++; From f450df800450e9c7ec8c53bdb72d6c4ef5f17d4e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 21 Sep 2011 20:55:04 +0200 Subject: [PATCH 0248/4025] PM / Suspend: Off by one in pm_suspend() commit 528f7ce6e439edeac38f6b3f8561f1be129b5e91 upstream. In enter_state() we use "state" as an offset for the pm_states[] array. The pm_states[] array only has PM_SUSPEND_MAX elements so this test is off by one. Signed-off-by: Dan Carpenter Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- kernel/power/suspend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 1c41ba21541..449ccc9c0a4 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -307,7 +307,7 @@ int enter_state(suspend_state_t state) */ int pm_suspend(suspend_state_t state) { - if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX) + if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX) return enter_state(state); return -EINVAL; } From 6dd160db729a0c96cc640a848e6df88ca6c19d2a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 19 Aug 2011 16:11:23 +0800 Subject: [PATCH 0249/4025] crypto: cryptd - Use subsys_initcall to prevent races with aesni commit b2bac6acf86d05d8af0499f37d91ecac15722803 upstream. As cryptd is depeneded on by other algorithms such as aesni-intel, it needs to be registered before them. When everything is built as modules, this occurs naturally. However, for this to work when they are built-in, we need to use subsys_initcall in cryptd. Tested-by: Josh Boyer Signed-off-by: Herbert Xu Cc: Kerin Millar Signed-off-by: Greg Kroah-Hartman --- crypto/cryptd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/cryptd.c b/crypto/cryptd.c index e46d21ae26b..671d4d6d14d 100644 --- a/crypto/cryptd.c +++ b/crypto/cryptd.c @@ -945,7 +945,7 @@ static void __exit cryptd_exit(void) crypto_unregister_template(&cryptd_tmpl); } -module_init(cryptd_init); +subsys_initcall(cryptd_init); module_exit(cryptd_exit); MODULE_LICENSE("GPL"); From ed288aed0796683495c51684d56f9328813c59c7 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 21 Oct 2011 00:49:16 +0000 Subject: [PATCH 0250/4025] dp83640: use proper function to free transmit time stamping packets commit f5ff7cd1a84caa9545d952a37ac872ccb73825fb upstream. The previous commit enforces a new rule for handling the cloned packets for transmit time stamping. These packets must not be freed using any other function than skb_complete_tx_timestamp. This commit fixes the one and only driver using this API. The driver first appeared in v3.0. Signed-off-by: Richard Cochran Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/dp83640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index db659c5f0fe..364cd67bb70 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1067,7 +1067,7 @@ static void dp83640_txtstamp(struct phy_device *phydev, struct dp83640_private *dp83640 = phydev->priv; if (!dp83640->hwts_tx_en) { - kfree_skb(skb); + skb_complete_tx_timestamp(skb, NULL); return; } skb_queue_tail(&dp83640->tx_queue, skb); From 82eaf854859022f7bf1aa9122ed533516187cbff Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Thu, 20 Oct 2011 14:22:43 +0530 Subject: [PATCH 0251/4025] ath9k_hw: Fix regression of register offset for AR9003 chips commit 52d6d4ef5e6d1517688e27c11c01ab303ec681dd upstream. My recent commits (3782c69d, 324c74a) introduced regression for register offset selection that based on the macversion. Not using parentheses in proper manner for ternary operator leads to select wrong offset for the registers. This issue was observed with AR9462 chip that immediate disconnect after the association with the following message ieee80211 phy3: wlan0: Failed to send nullfunc to AP 00:23:69:12:ea:47 after 500ms, disconnecting. Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ar9003_phy.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index efdbe98fa7e..2364b5f4114 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -570,12 +570,12 @@ #define AR_PHY_TXGAIN_TABLE (AR_SM_BASE + 0x300) -#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + AR_SREV_9485(ah) ? \ - 0x3c8 : 0x448) -#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + AR_SREV_9485(ah) ? \ - 0x3c4 : 0x440) -#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + AR_SREV_9485(ah) ? \ - 0x3f0 : 0x48c) +#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + (AR_SREV_9485(ah) ? \ + 0x3c8 : 0x448)) +#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + (AR_SREV_9485(ah) ? \ + 0x3c4 : 0x440)) +#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + (AR_SREV_9485(ah) ? \ + 0x3f0 : 0x48c)) #define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i) (AR_SM_BASE + \ (AR_SREV_9485(ah) ? \ 0x3d0 : 0x450) + ((_i) << 2)) From 02376e54a976843aaa722b661123a6acc2b70b14 Mon Sep 17 00:00:00 2001 From: "THOMSON, Adam (Adam)" Date: Tue, 14 Jun 2011 16:52:38 +0200 Subject: [PATCH 0252/4025] mtd: nand_base: always initialise oob_poi before writing OOB data commit f722013ee9fd24623df31dec9a91a6d02c3e2f2f upstream. In nand_do_write_ops() code it is possible for a caller to provide ops.oobbuf populated and ops.mode == MTD_OOB_AUTO, which currently means that the chip->oob_poi buffer isn't initialised to all 0xFF. The nand_fill_oob() method then carries out the task of copying the provided OOB data to oob_poi, but with MTD_OOB_AUTO it skips areas marked as unavailable by the layout struct, including the bad block marker bytes. An example of this causing issues is when the last OOB data read was from the start of a bad block where the markers are not 0xFF, and the caller wishes to write new OOB data at the beginning of another block. In this scenario the caller would provide OOB data, but nand_fill_oob() would skip the bad block marker bytes in oob_poi before copying the OOB data provided by the caller. This means that when the OOB data is written back to NAND, the block is inadvertently marked as bad without the caller knowing. This has been witnessed when using YAFFS2 where tags are stored in the OOB. To avoid this oob_poi is always initialised to 0xFF to make sure no left over data is inadvertently written back to the OOB area. Credits to Brian Norris for fixing this patch. Signed-off-by: Adam Thomson Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/nand_base.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a46e9bb847b..86f05f45780 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2097,14 +2097,22 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, /** * nand_fill_oob - [Internal] Transfer client buffer to oob - * @chip: nand chip structure + * @mtd: MTD device structure * @oob: oob data buffer * @len: oob data write length * @ops: oob ops structure */ -static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, - struct mtd_oob_ops *ops) +static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, + struct mtd_oob_ops *ops) { + struct nand_chip *chip = mtd->priv; + + /* + * Initialise to all 0xFF, to avoid the possibility of left over OOB + * data from a previous OOB read. + */ + memset(chip->oob_poi, 0xff, mtd->oobsize); + switch (ops->mode) { case MTD_OOB_PLACE: @@ -2201,10 +2209,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, (chip->pagebuf << chip->page_shift) < (to + ops->len)) chip->pagebuf = -1; - /* If we're not given explicit OOB data, let it be 0xFF */ - if (likely(!oob)) - memset(chip->oob_poi, 0xff, mtd->oobsize); - /* Don't allow multipage oob writes with offset */ if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) return -EINVAL; @@ -2226,8 +2230,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (unlikely(oob)) { size_t len = min(oobwritelen, oobmaxlen); - oob = nand_fill_oob(chip, oob, len, ops); + oob = nand_fill_oob(mtd, oob, len, ops); oobwritelen -= len; + } else { + /* We still need to erase leftover OOB data */ + memset(chip->oob_poi, 0xff, mtd->oobsize); } ret = chip->write_page(mtd, chip, wbuf, page, cached, @@ -2401,10 +2408,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, if (page == chip->pagebuf) chip->pagebuf = -1; - memset(chip->oob_poi, 0xff, mtd->oobsize); - nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops); + nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops); status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); - memset(chip->oob_poi, 0xff, mtd->oobsize); if (status) return status; From 81e0a487f87844c9b4ef5d7816ef4e02482db6c6 Mon Sep 17 00:00:00 2001 From: Dan Bastone Date: Sun, 31 Jul 2011 07:40:49 -0400 Subject: [PATCH 0253/4025] HID: add support for new revision of Apple aluminum keyboard commit 4a4c879904aa0cc64629e14a49b64fb3d149bf1a upstream. Add USB device ids for the new revision (MB110LL/B) of Apple's wired aluminum keyboard. I have only confirmed that the ANSI version is correct - it is assumed that the ISO and JIS versions follow the standard numbering convention. Signed-off-by: Dan Bastone Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-apple.c | 6 ++++++ drivers/hid/hid-core.c | 3 +++ drivers/hid/hid-ids.h | 3 +++ 3 files changed, 12 insertions(+) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index b85744fe846..18b3bc646bf 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -444,6 +444,12 @@ static const struct hid_device_id apple_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | APPLE_RDESC_JIS }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO), + .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS), + .driver_data = APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO), diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 6f3289a5788..b90a0d0f7ea 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1340,6 +1340,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index c946d90f0ae..8c9f6e8eb89 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -109,6 +109,9 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245 #define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246 #define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247 +#define USB_DEVICE_ID_APPLE_ALU_REVB_ANSI 0x024f +#define USB_DEVICE_ID_APPLE_ALU_REVB_ISO 0x0250 +#define USB_DEVICE_ID_APPLE_ALU_REVB_JIS 0x0251 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b From 385df62a595823f09fa9447f79c5a14ea1990a7d Mon Sep 17 00:00:00 2001 From: Clemens Werther Date: Thu, 25 Aug 2011 15:35:14 +0200 Subject: [PATCH 0254/4025] HID: add support for HuiJia USB Gamepad connector commit 6d1db0777981e1626ae71243984ac300b61789ff upstream. Create each gamepad as a separate joystick Signed-off-by: Clemens Werther Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-ids.h | 1 + drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 8c9f6e8eb89..00716c71a19 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -277,6 +277,7 @@ #define USB_DEVICE_ID_PENPOWER 0x00f4 #define USB_VENDOR_ID_GREENASIA 0x0e8f +#define USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD 0x3013 #define USB_VENDOR_ID_GRETAGMACBETH 0x0971 #define USB_DEVICE_ID_GRETAGMACBETH_HUEY 0x2005 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 4bdb5d46c52..3146fdcda27 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -47,6 +47,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL }, { USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT }, From c3f24bd0dcf2076ed16b8f5ea80ea001500d8095 Mon Sep 17 00:00:00 2001 From: "Joshua V. Dillon" Date: Fri, 5 Aug 2011 12:05:22 -0700 Subject: [PATCH 0255/4025] HID: add support for MacBookAir4,2 keyboard. commit 5d922baa631058c7e37ae33e81c4d3e6437f8d1d upstream. Added USB device IDs for MacBookAir4,2 keyboard. Device constants were copied from the MacBookAir3,2 constants. The 4,2 device specification is reportedly unchanged from the 3,2 predecessor and seems to work well. Signed-off-by: Joshua V Dillon Signed-off-by: Chase Douglas Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-apple.c | 9 +++++++++ drivers/hid/hid-ids.h | 3 +++ 2 files changed, 12 insertions(+) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 18b3bc646bf..12db5e1ca0f 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -183,6 +183,9 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) table = macbookair_fn_keys; + else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI && + hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) + table = macbookair_fn_keys; else if (hid->product < 0x21d || hid->product >= 0x300) table = powerbook_fn_keys; else @@ -493,6 +496,12 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO), + .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS), + .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 00716c71a19..69958bb7513 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -109,6 +109,9 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245 #define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246 #define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247 +#define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI 0x024c +#define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO 0x024d +#define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS 0x024e #define USB_DEVICE_ID_APPLE_ALU_REVB_ANSI 0x024f #define USB_DEVICE_ID_APPLE_ALU_REVB_ISO 0x0250 #define USB_DEVICE_ID_APPLE_ALU_REVB_JIS 0x0251 From bab08e54790e51a7541faf1e3029eeefc051e36c Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Mon, 15 Aug 2011 21:12:09 -0700 Subject: [PATCH 0256/4025] HID: hid-multitouch: Add LG Display Multitouch device. commit c50bb1a4005630f47b5da26336f74a485033a515 upstream. This panel is also known as the Dell ST2220Tc. Signed-off-by: jeffbrown@android.com Reviewed-By: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/Kconfig | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-multitouch.c | 5 +++++ 4 files changed, 10 insertions(+) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index a1f3c0ddd01..7e0acf46c35 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -314,6 +314,7 @@ config HID_MULTITOUCH - Hanvon dual touch panels - Ilitek dual touch panels - IrTouch Infrared USB panels + - LG Display panels (Dell ST2220Tc) - Lumio CrystalTouch panels - MosArt dual-touch panels - PenMount dual touch panels diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index b90a0d0f7ea..4f68ca13e44 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1398,6 +1398,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LG, USB_DEVICE_ID_LG_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 69958bb7513..00bb50e9785 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -423,6 +423,9 @@ #define USB_DEVICE_ID_LD_HYBRID 0x2090 #define USB_DEVICE_ID_LD_HEATCONTROL 0x20A0 +#define USB_VENDOR_ID_LG 0x1fd2 +#define USB_DEVICE_ID_LG_MULTITOUCH 0x0064 + #define USB_VENDOR_ID_LOGITECH 0x046d #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 62cac4dc3b6..685d8e42587 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -672,6 +672,11 @@ static const struct hid_device_id mt_devices[] = { HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) }, + /* LG Display panels */ + { .driver_data = MT_CLS_DEFAULT, + HID_USB_DEVICE(USB_VENDOR_ID_LG, + USB_DEVICE_ID_LG_MULTITOUCH) }, + /* Lumio panels */ { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, From 9148573623711a6932b729f5bb752534f4834714 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 10 Aug 2011 14:12:52 +0200 Subject: [PATCH 0257/4025] HID: add MacBookAir4,2 to hid_have_special_driver[] commit f6f554f09c5b831efdaf67c449e18ca06ee648fe upstream. Otherwise the generic driver wouldn't unbind from it and wouldn't let hid-apple to automatically take over. Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 4f68ca13e44..3cc2d19c845 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1340,6 +1340,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS) }, From 4bdfc7d622b8a17bf55a7745ae77f8925843ea9d Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Sat, 1 Oct 2011 15:54:53 +0900 Subject: [PATCH 0258/4025] HID: Add support MacbookAir 4,1 keyboard commit d762cc290b9f17e346f4297fd5984b70ce71ef66 upstream. Added USB device IDs and keyboard map for MacBookAir 4,1 keyboard. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-apple.c | 31 +++++++++++++++++++++++++++++++ drivers/hid/hid-core.c | 3 +++ drivers/hid/hid-ids.h | 3 +++ 3 files changed, 37 insertions(+) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 12db5e1ca0f..2bab9abb4dc 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -82,6 +82,28 @@ static const struct apple_key_translation macbookair_fn_keys[] = { { } }; +static const struct apple_key_translation macbookair4_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, + { KEY_ENTER, KEY_INSERT }, + { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, + { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, + { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY }, + { KEY_F4, KEY_DASHBOARD, APPLE_FLAG_FKEY }, + { KEY_F5, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY }, + { KEY_F6, KEY_KBDILLUMUP, APPLE_FLAG_FKEY }, + { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY }, + { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, + { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY }, + { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, + { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, + { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, + { KEY_UP, KEY_PAGEUP }, + { KEY_DOWN, KEY_PAGEDOWN }, + { KEY_LEFT, KEY_HOME }, + { KEY_RIGHT, KEY_END }, + { } +}; + static const struct apple_key_translation apple_fn_keys[] = { { KEY_BACKSPACE, KEY_DELETE }, { KEY_ENTER, KEY_INSERT }, @@ -186,6 +208,9 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI && hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) table = macbookair_fn_keys; + else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI && + hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) + table = macbookair4_fn_keys; else if (hid->product < 0x21d || hid->product >= 0x300) table = powerbook_fn_keys; else @@ -502,6 +527,12 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO), + .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS), + .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 3cc2d19c845..a43b5b57f85 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1343,6 +1343,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 00bb50e9785..8d8d56fa39a 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -109,6 +109,9 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245 #define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246 #define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247 +#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI 0x0249 +#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO 0x024a +#define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS 0x024b #define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI 0x024c #define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO 0x024d #define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS 0x024e From 63472b615266723cb9af12e09fd32736be6b3477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6k=C3=A7en=20Eraslan?= Date: Sat, 22 Oct 2011 22:39:06 +0300 Subject: [PATCH 0259/4025] HID: Add device IDs for Macbook Pro 8 keyboards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 213f9da80533940560bef8fa43b10c590895459c upstream. This patch adds keyboard support for Macbook Pro 8 models which has WELLSPRING5A model name and 0x0252, 0x0253 and 0x0254 USB IDs. Trackpad support for those models are added to bcm5974 in c331eb580a0a7906c0cdb8dbae3cfe99e3c0e555 ("Input: bcm5974 - Add support for newer MacBookPro8,2). Signed-off-by: Gökçen Eraslan Acked-by: Henrik Rydberg Signed-off-by: Jiri Kosina Cc: Chase Douglas Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-apple.c | 6 ++++++ drivers/hid/hid-core.c | 6 ++++++ drivers/hid/hid-ids.h | 3 +++ 3 files changed, 15 insertions(+) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 2bab9abb4dc..6f7dd6f77b9 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -533,6 +533,12 @@ static const struct hid_device_id apple_devices[] = { .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS), .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI), + .driver_data = APPLE_HAS_FN }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO), + .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS), + .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index a43b5b57f85..aa414f1e507 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1340,6 +1340,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) }, @@ -1893,6 +1896,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 8d8d56fa39a..b6ed6a42f32 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -118,6 +118,9 @@ #define USB_DEVICE_ID_APPLE_ALU_REVB_ANSI 0x024f #define USB_DEVICE_ID_APPLE_ALU_REVB_ISO 0x0250 #define USB_DEVICE_ID_APPLE_ALU_REVB_JIS 0x0251 +#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI 0x0252 +#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO 0x0253 +#define USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS 0x0254 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b From fc7c292ac74b41af17e9e8eab039322d3847bad3 Mon Sep 17 00:00:00 2001 From: Andreas Krist Date: Fri, 28 Oct 2011 18:50:39 +0200 Subject: [PATCH 0260/4025] HID: hid-apple: add device ID of another wireless aluminium commit ad734bc1565364f9e4b70888d3ce5743b3c1030a upstream. I've recently bought a Apple wireless aluminum keyboard (model 2011) which is not yet supported by the kernel - it seems they just changed the device id. After applying the attached patch, the device is fully functional. Signed-off-by: Andreas Krist Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-apple.c | 3 +++ drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + 3 files changed, 5 insertions(+) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 6f7dd6f77b9..a893a9f8031 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -483,6 +483,9 @@ static const struct hid_device_id apple_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | APPLE_ISO_KEYBOARD }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN | + APPLE_ISO_KEYBOARD }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index aa414f1e507..4f81d2048a7 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1355,6 +1355,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b6ed6a42f32..c97003c1b0b 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -124,6 +124,7 @@ #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b +#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b #define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241 From 8ac6255b5f8d69d58d4fb8ed62df2780756d4b0c Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 5 Oct 2011 16:54:45 +0200 Subject: [PATCH 0261/4025] HID: consolidate MacbookAir 4,1 mappings commit da617c7cb915545dda4280df888dd6f8d5697420 upstream. MacbookAir 4,1 doesn't require extra mapping table, as the mappings are identical to apple_fn_keys[]. Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-apple.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index a893a9f8031..8cdb4b45b30 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -82,28 +82,6 @@ static const struct apple_key_translation macbookair_fn_keys[] = { { } }; -static const struct apple_key_translation macbookair4_fn_keys[] = { - { KEY_BACKSPACE, KEY_DELETE }, - { KEY_ENTER, KEY_INSERT }, - { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, - { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, - { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY }, - { KEY_F4, KEY_DASHBOARD, APPLE_FLAG_FKEY }, - { KEY_F5, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY }, - { KEY_F6, KEY_KBDILLUMUP, APPLE_FLAG_FKEY }, - { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY }, - { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, - { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY }, - { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, - { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, - { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, - { KEY_UP, KEY_PAGEUP }, - { KEY_DOWN, KEY_PAGEDOWN }, - { KEY_LEFT, KEY_HOME }, - { KEY_RIGHT, KEY_END }, - { } -}; - static const struct apple_key_translation apple_fn_keys[] = { { KEY_BACKSPACE, KEY_DELETE }, { KEY_ENTER, KEY_INSERT }, @@ -208,9 +186,6 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI && hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) table = macbookair_fn_keys; - else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI && - hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) - table = macbookair4_fn_keys; else if (hid->product < 0x21d || hid->product >= 0x300) table = powerbook_fn_keys; else From c54e04e9a9993da6968c8b21bdb905d07f0caed7 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 6 Nov 2011 18:34:03 -0800 Subject: [PATCH 0262/4025] hid/apple: modern macbook airs use the standard apple function key translations commit 21404b772a1c65f7b935b8c0fddc388a949f4e31 upstream. This removes the use of the special "macbookair_fn_keys" keyboard translation table for the MacBookAir4,x models (ie the 2011 refresh). They use the standard apple_fn_keys[] translation. Apparently only the old MacBook Air's need a different translation table. This mirrors the change that commit da617c7cb915 ("HID: consolidate MacbookAir 4,1 mappings") did for the WELLSPRING6A ones, but does it for the WELLSPRING6 model used on the MacBookAir4,2. Reported-and-tested-by: Dirk Hohndel Cc: Jiri Kosina Cc: Joshua V Dillon Cc: Chase Douglas Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-apple.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 8cdb4b45b30..299d2387112 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -183,9 +183,6 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI && hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) table = macbookair_fn_keys; - else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI && - hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) - table = macbookair_fn_keys; else if (hid->product < 0x21d || hid->product >= 0x300) table = powerbook_fn_keys; else From 999c1d6bc999d67657033ec780a561aa172c75a9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 11 Nov 2011 10:12:24 -0800 Subject: [PATCH 0263/4025] Linux 3.0.9 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9f6e3cd3854..438c11a865e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 8 +SUBLEVEL = 9 EXTRAVERSION = NAME = Sneaky Weasel From eef8e7b4bd22c91c2b227662da03f232d49a0245 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Thu, 17 Nov 2011 11:23:10 -0800 Subject: [PATCH 0264/4025] empty commit From fd6f075d1e29791d0e4b42da2e6962665f90de1b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 10 Nov 2011 12:28:38 +0100 Subject: [PATCH 0265/4025] ALSA: hda - Don't add elements of other codecs to vmaster slave commit aeb4b88ec0a948efce8e3a23a8f964d3560a7308 upstream. When a virtual mater control is created, the driver looks for slave elements from the assigned card instance. But this may include the elements of other codecs when multiple codecs are on the same HD-audio bus. This works at the first time, but it'll give Oops when it's once freed and re-created via reconfig sysfs. This patch changes the element-look-up strategy to limit only to the mixer elements of the same codec. Reported-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_codec.c | 60 +++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 45b4a8d70e0..21958518467 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2187,6 +2187,39 @@ int snd_hda_codec_reset(struct hda_codec *codec) return 0; } +typedef int (*map_slave_func_t)(void *, struct snd_kcontrol *); + +/* apply the function to all matching slave ctls in the mixer list */ +static int map_slaves(struct hda_codec *codec, const char * const *slaves, + map_slave_func_t func, void *data) +{ + struct hda_nid_item *items; + const char * const *s; + int i, err; + + items = codec->mixers.list; + for (i = 0; i < codec->mixers.used; i++) { + struct snd_kcontrol *sctl = items[i].kctl; + if (!sctl || !sctl->id.name || + sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER) + continue; + for (s = slaves; *s; s++) { + if (!strcmp(sctl->id.name, *s)) { + err = func(data, sctl); + if (err) + return err; + break; + } + } + } + return 0; +} + +static int check_slave_present(void *data, struct snd_kcontrol *sctl) +{ + return 1; +} + /** * snd_hda_add_vmaster - create a virtual master control and add slaves * @codec: HD-audio codec @@ -2207,12 +2240,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char * const *slaves) { struct snd_kcontrol *kctl; - const char * const *s; int err; - for (s = slaves; *s && !snd_hda_find_mixer_ctl(codec, *s); s++) - ; - if (!*s) { + err = map_slaves(codec, slaves, check_slave_present, NULL); + if (err != 1) { snd_printdd("No slave found for %s\n", name); return 0; } @@ -2223,23 +2254,10 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, if (err < 0) return err; - for (s = slaves; *s; s++) { - struct snd_kcontrol *sctl; - int i = 0; - for (;;) { - sctl = _snd_hda_find_mixer_ctl(codec, *s, i); - if (!sctl) { - if (!i) - snd_printdd("Cannot find slave %s, " - "skipped\n", *s); - break; - } - err = snd_ctl_add_slave(kctl, sctl); - if (err < 0) - return err; - i++; - } - } + err = map_slaves(codec, slaves, (map_slave_func_t)snd_ctl_add_slave, + kctl); + if (err < 0) + return err; return 0; } EXPORT_SYMBOL_HDA(snd_hda_add_vmaster); From d4ff27e92b1073f854b8e8a58599f0c565204443 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 7 Nov 2011 18:37:05 +0200 Subject: [PATCH 0266/4025] virtio-pci: fix use after free commit 72103bd1285211440621f2c46f4fce377584de54 upstream. Commit 31a3ddda166cda86d2b5111e09ba4bda5239fae6 introduced a use after free in virtio-pci. The main issue is that the release method signals removal of the virtio device, while remove signals removal of the pci device. For example, on driver removal or hot-unplug, virtio_pci_release_dev is called before virtio_pci_remove. We then might get a crash as virtio_pci_remove tries to use the device freed by virtio_pci_release_dev. We allocate/free all resources together with the pci device, so we can leave the release method empty. Signed-off-by: Michael S. Tsirkin Acked-by: Amit Shah Signed-off-by: Rusty Russell Signed-off-by: Greg Kroah-Hartman --- drivers/virtio/virtio_pci.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index 4bcc8b82640..ecb925411e0 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c @@ -590,11 +590,11 @@ static struct virtio_config_ops virtio_pci_config_ops = { static void virtio_pci_release_dev(struct device *_d) { - struct virtio_device *dev = container_of(_d, struct virtio_device, - dev); - struct virtio_pci_device *vp_dev = to_vp_device(dev); - - kfree(vp_dev); + /* + * No need for a release method as we allocate/free + * all devices together with the pci devices. + * Provide an empty one to avoid getting a warning from core. + */ } /* the PCI probing function */ @@ -682,6 +682,7 @@ static void __devexit virtio_pci_remove(struct pci_dev *pci_dev) pci_iounmap(pci_dev, vp_dev->ioaddr); pci_release_regions(pci_dev); pci_disable_device(pci_dev); + kfree(vp_dev); } #ifdef CONFIG_PM From 6c43a5e42ca88c5770de53fb969a0b6f04d86982 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 4 Nov 2011 15:52:31 +0000 Subject: [PATCH 0267/4025] ASoC: Don't use wm8994->control_data in wm8994_readable_register() commit 8eeea521d9d0fa6afd62df8c6e6566ee946117fa upstream. The field is no longer initialised so this will crash if running on wm8958. Reported-by: Thomas Abraham Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8994.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index fb9f08ab84c..21949123787 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -56,7 +56,7 @@ static int wm8994_retune_mobile_base[] = { static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg) { struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); - struct wm8994 *control = wm8994->control_data; + struct wm8994 *control = codec->control_data; switch (reg) { case WM8994_GPIO_1: From f5116ff776a68277c0b60ba57e74c7074b72ab65 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Fri, 4 Nov 2011 22:13:50 +0900 Subject: [PATCH 0268/4025] sh: Fix cached/uncaced address calculation in 29bit mode commit dfd3b596fbbfa48b8e7966ef996d587157554b69 upstream. In the case of 29bit mode, CAC/UNCAC_ADDR does not return a right address. This revises this problem by using P1SEGADDR and P2SEGADDR in 29bit mode. Reported-by: Yutaro Ebihara Signed-off-by: Nobuhiro Iwamatsu Tested-by: Kuninori Morimoto Tested-by: Simon Horman Signed-off-by: Paul Mundt Signed-off-by: Greg Kroah-Hartman --- arch/sh/include/asm/page.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h index 822d6084195..abcc4dcc2d9 100644 --- a/arch/sh/include/asm/page.h +++ b/arch/sh/include/asm/page.h @@ -141,8 +141,13 @@ typedef struct page *pgtable_t; #endif /* !__ASSEMBLY__ */ #ifdef CONFIG_UNCACHED_MAPPING +#if defined(CONFIG_29BIT) +#define UNCAC_ADDR(addr) P2SEGADDR(addr) +#define CAC_ADDR(addr) P1SEGADDR(addr) +#else #define UNCAC_ADDR(addr) ((addr) - PAGE_OFFSET + uncached_start) #define CAC_ADDR(addr) ((addr) - uncached_start + PAGE_OFFSET) +#endif #else #define UNCAC_ADDR(addr) ((addr)) #define CAC_ADDR(addr) ((addr)) From 1db61fd3401a6520375293de302b3a9034edca1b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 31 Oct 2011 23:16:21 -0700 Subject: [PATCH 0269/4025] drm/i915: Fix object refcount leak on mmappable size limit error path. commit 14660ccd599dc7bd6ecef17408bd76dc853f9b77 upstream. I've been seeing memory leaks on my system in the form of large (300-400MB) GEM objects created by now-dead processes laying around clogging up memory. I usually notice when it gets to about 1.2GB of them. Hopefully this clears up the issue, but I just found this bug by inspection. Signed-off-by: Eric Anholt Signed-off-by: Keith Packard Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a087e1bf0c2..5548593040b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1475,7 +1475,7 @@ i915_gem_mmap_gtt(struct drm_file *file, if (obj->base.size > dev_priv->mm.gtt_mappable_end) { ret = -E2BIG; - goto unlock; + goto out; } if (obj->madv != I915_MADV_WILLNEED) { From 53b6b123d40eda9bde41232b2c76d0e1e896b83d Mon Sep 17 00:00:00 2001 From: Marcin Slusarz Date: Fri, 9 Sep 2011 14:16:42 +0200 Subject: [PATCH 0270/4025] drm/nouveau: initialize chan->fence.lock before use commit 5e60ee780e792efe6dce97eceb110b1d30bab850 upstream. Fence lock needs to be initialized before any call to nouveau_channel_put because it calls nouveau_channel_idle->nouveau_fence_update which uses fence lock. BUG: spinlock bad magic on CPU#0, test/24134 lock: ffff88019f90dba8, .magic: 00000000, .owner: /-1, .owner_cpu: 0 Pid: 24134, comm: test Not tainted 3.0.0-nv+ #800 Call Trace: spin_bug+0x9c/0xa3 do_raw_spin_lock+0x29/0x13c _raw_spin_lock+0x1e/0x22 nouveau_fence_update+0x2d/0xf1 nouveau_channel_idle+0x22/0xa0 nouveau_channel_put_unlocked+0x84/0x1bd nouveau_channel_put+0x20/0x24 nouveau_channel_alloc+0x4ec/0x585 nouveau_ioctl_fifo_alloc+0x50/0x130 drm_ioctl+0x289/0x361 do_vfs_ioctl+0x4dd/0x52c sys_ioctl+0x42/0x65 system_call_fastpath+0x16/0x1b It's easily triggerable from userspace. Additionally remove double initialization of chan->fence.pending. Signed-off-by: Marcin Slusarz Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nouveau_channel.c | 1 + drivers/gpu/drm/nouveau/nouveau_fence.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index a7583a8ddb0..d31d355f5ed 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -159,6 +159,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, INIT_LIST_HEAD(&chan->nvsw.vbl_wait); INIT_LIST_HEAD(&chan->nvsw.flip); INIT_LIST_HEAD(&chan->fence.pending); + spin_lock_init(&chan->fence.lock); /* Allocate DMA push buffer */ chan->pushbuf_bo = nouveau_channel_user_pushbuf_alloc(dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 7347075ca5b..56f06b0cfdb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -542,8 +542,6 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) return ret; } - INIT_LIST_HEAD(&chan->fence.pending); - spin_lock_init(&chan->fence.lock); atomic_set(&chan->fence.last_sequence_irq, 0); return 0; } From f73870d6d33cd24c8fe2a7b39b2f99c433804945 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 8 Nov 2011 10:09:58 -0500 Subject: [PATCH 0271/4025] drm/radeon/kms: make an aux failure debug only commit 091264f0bc12419560ac64fcef4567809d611658 upstream. Can happen when there is no DP panel attached, confusing users. Make it debug only. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_dp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index b5628ce1228..3b77ad60ed5 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -283,7 +283,7 @@ int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, } } - DRM_ERROR("aux i2c too many retries, giving up\n"); + DRM_DEBUG_KMS("aux i2c too many retries, giving up\n"); return -EREMOTEIO; } From 9338f407e30015cd9d236d8a678cacd2c72d4a31 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 19 Aug 2011 08:30:53 +0200 Subject: [PATCH 0272/4025] ALSA: usb-audio - Check the dB-range validity in the later read, too commit 9fcd0ab130579d9742538340edda3225f2b49a3e upstream. When the initial check of dB-range failed due to the read error, try to check again at the later read, too. When an invalid dB range is found, remove TLV flags and notify the mixer info change. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/mixer.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index cdd19d7fe50..a033129e973 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -881,8 +881,17 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_ uinfo->value.integer.min = 0; uinfo->value.integer.max = 1; } else { - if (! cval->initialized) - get_min_max(cval, 0); + if (!cval->initialized) { + get_min_max(cval, 0); + if (cval->initialized && cval->dBmin >= cval->dBmax) { + kcontrol->vd[0].access &= + ~(SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK); + snd_ctl_notify(cval->mixer->chip->card, + SNDRV_CTL_EVENT_MASK_INFO, + &kcontrol->id); + } + } uinfo->value.integer.min = 0; uinfo->value.integer.max = (cval->max - cval->min + cval->res - 1) / cval->res; From 6861f2aa5840d7237aa0249a76ae29c939e7c93a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Nov 2011 17:50:27 +0100 Subject: [PATCH 0273/4025] ALSA: usb-audio - Fix the missing volume quirks at delayed init commit dcaaf9f2c16b56f8bb316881fcd3f15c18fc71e7 upstream. In the recent usb-audio driver, the initialization of volume ranges may be delayed when the device doesn't respond well at the probing time. But the volume quirks for certain devices are applied only in mixer_ctl_feature_info() thus only at the very first probe and will be missing when the volume range is initialized later. This patch moves the volume quirk code to be always called from the volume-range extraction (get_min_max()), so that the quirks are properly applied in the later init time. Reported-and-tested-by: Alexey Fisher Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/mixer.c | 109 +++++++++++++++++++++++++--------------------- 1 file changed, 59 insertions(+), 50 deletions(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index a033129e973..0de7cbd99ea 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -765,10 +765,60 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl) * interface to ALSA control for feature/mixer units */ +/* volume control quirks */ +static void volume_control_quirks(struct usb_mixer_elem_info *cval, + struct snd_kcontrol *kctl) +{ + switch (cval->mixer->chip->usb_id) { + case USB_ID(0x0471, 0x0101): + case USB_ID(0x0471, 0x0104): + case USB_ID(0x0471, 0x0105): + case USB_ID(0x0672, 0x1041): + /* quirk for UDA1321/N101. + * note that detection between firmware 2.1.1.7 (N101) + * and later 2.1.1.21 is not very clear from datasheets. + * I hope that the min value is -15360 for newer firmware --jk + */ + if (!strcmp(kctl->id.name, "PCM Playback Volume") && + cval->min == -15616) { + snd_printk(KERN_INFO + "set volume quirk for UDA1321/N101 chip\n"); + cval->max = -256; + } + break; + + case USB_ID(0x046d, 0x09a4): + if (!strcmp(kctl->id.name, "Mic Capture Volume")) { + snd_printk(KERN_INFO + "set volume quirk for QuickCam E3500\n"); + cval->min = 6080; + cval->max = 8768; + cval->res = 192; + } + break; + + case USB_ID(0x046d, 0x0808): + case USB_ID(0x046d, 0x0809): + case USB_ID(0x046d, 0x0991): + /* Most audio usb devices lie about volume resolution. + * Most Logitech webcams have res = 384. + * Proboly there is some logitech magic behind this number --fishor + */ + if (!strcmp(kctl->id.name, "Mic Capture Volume")) { + snd_printk(KERN_INFO + "set resolution quirk: cval->res = 384\n"); + cval->res = 384; + } + break; + + } +} + /* * retrieve the minimum and maximum values for the specified control */ -static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) +static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval, + int default_min, struct snd_kcontrol *kctl) { /* for failsafe */ cval->min = default_min; @@ -844,6 +894,9 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) cval->initialized = 1; } + if (kctl) + volume_control_quirks(cval, kctl); + /* USB descriptions contain the dB scale in 1/256 dB unit * while ALSA TLV contains in 1/100 dB unit */ @@ -864,6 +917,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) return 0; } +#define get_min_max(cval, def) get_min_max_with_quirks(cval, def, NULL) /* get a feature/mixer unit info */ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -882,7 +936,7 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol, struct snd_ctl_ uinfo->value.integer.max = 1; } else { if (!cval->initialized) { - get_min_max(cval, 0); + get_min_max_with_quirks(cval, 0, kcontrol); if (cval->initialized && cval->dBmin >= cval->dBmax) { kcontrol->vd[0].access &= ~(SNDRV_CTL_ELEM_ACCESS_TLV_READ | @@ -1045,9 +1099,6 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, cval->ch_readonly = readonly_mask; } - /* get min/max values */ - get_min_max(cval, 0); - /* if all channels in the mask are marked read-only, make the control * read-only. set_cur_mix_value() will check the mask again and won't * issue write commands to read-only channels. */ @@ -1069,6 +1120,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); + /* get min/max values */ + get_min_max_with_quirks(cval, 0, kctl); + switch (control) { case UAC_FU_MUTE: case UAC_FU_VOLUME: @@ -1118,51 +1172,6 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, break; } - /* volume control quirks */ - switch (state->chip->usb_id) { - case USB_ID(0x0471, 0x0101): - case USB_ID(0x0471, 0x0104): - case USB_ID(0x0471, 0x0105): - case USB_ID(0x0672, 0x1041): - /* quirk for UDA1321/N101. - * note that detection between firmware 2.1.1.7 (N101) - * and later 2.1.1.21 is not very clear from datasheets. - * I hope that the min value is -15360 for newer firmware --jk - */ - if (!strcmp(kctl->id.name, "PCM Playback Volume") && - cval->min == -15616) { - snd_printk(KERN_INFO - "set volume quirk for UDA1321/N101 chip\n"); - cval->max = -256; - } - break; - - case USB_ID(0x046d, 0x09a4): - if (!strcmp(kctl->id.name, "Mic Capture Volume")) { - snd_printk(KERN_INFO - "set volume quirk for QuickCam E3500\n"); - cval->min = 6080; - cval->max = 8768; - cval->res = 192; - } - break; - - case USB_ID(0x046d, 0x0808): - case USB_ID(0x046d, 0x0809): - case USB_ID(0x046d, 0x0991): - /* Most audio usb devices lie about volume resolution. - * Most Logitech webcams have res = 384. - * Proboly there is some logitech magic behind this number --fishor - */ - if (!strcmp(kctl->id.name, "Mic Capture Volume")) { - snd_printk(KERN_INFO - "set resolution quirk: cval->res = 384\n"); - cval->res = 384; - } - break; - - } - range = (cval->max - cval->min) / cval->res; /* Are there devices with volume range more than 255? I use a bit more * to be sure. 384 is a resolution magic number found on Logitech From 31a05f7dd79da9b4889008847e2a851835c14269 Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 15 Nov 2011 22:09:45 +0000 Subject: [PATCH 0274/4025] KEYS: Fix a NULL pointer deref in the user-defined key type commit 9f35a33b8d06263a165efe3541d9aa0cdbd70b3b upstream. Fix a NULL pointer deref in the user-defined key type whereby updating a negative key into a fully instantiated key will cause an oops to occur when the code attempts to free the non-existent old payload. This results in an oops that looks something like the following: BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 IP: [] __call_rcu+0x11/0x13e PGD 3391d067 PUD 3894a067 PMD 0 Oops: 0002 [#1] SMP CPU 1 Pid: 4354, comm: keyctl Not tainted 3.1.0-fsdevel+ #1140 /DG965RY RIP: 0010:[] [] __call_rcu+0x11/0x13e RSP: 0018:ffff88003d591df8 EFLAGS: 00010246 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 000000000000006e RDX: ffffffff8161d0c0 RSI: 0000000000000000 RDI: 0000000000000000 RBP: ffff88003d591e18 R08: 0000000000000000 R09: ffffffff8152fa6c R10: 0000000000000000 R11: 0000000000000300 R12: ffff88003b8f9538 R13: ffffffff8161d0c0 R14: ffff88003b8f9d50 R15: ffff88003c69f908 FS: 00007f97eb18c720(0000) GS:ffff88003bd00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000008 CR3: 000000003d47a000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process keyctl (pid: 4354, threadinfo ffff88003d590000, task ffff88003c78a040) Stack: ffff88003e0ffde0 ffff88003b8f9538 0000000000000001 ffff88003b8f9d50 ffff88003d591e28 ffffffff810860f0 ffff88003d591e68 ffffffff8117bfea ffff88003d591e68 ffffffff00000000 ffff88003e0ffde1 ffff88003e0ffde0 Call Trace: [] call_rcu_sched+0x10/0x12 [] user_update+0x8d/0xa2 [] key_create_or_update+0x236/0x270 [] sys_add_key+0x123/0x17e [] system_call_fastpath+0x16/0x1b Signed-off-by: David Howells Acked-by: Jeff Layton Acked-by: Neil Horman Acked-by: Steve Dickson Acked-by: James Morris Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- security/keys/user_defined.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index 5b366d7af3c..69ff52c08e9 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c @@ -102,7 +102,8 @@ int user_update(struct key *key, const void *data, size_t datalen) key->expiry = 0; } - kfree_rcu(zap, rcu); + if (zap) + kfree_rcu(zap, rcu); error: return ret; From 3bbea6b4bca6ac2529fbbb71e58323a00592edae Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 14 Nov 2011 17:52:08 +0300 Subject: [PATCH 0275/4025] hfs: add sanity check for file name length commit bc5b8a9003132ae44559edd63a1623b7b99dfb68 upstream. On a corrupted file system the ->len field could be wrong leading to a buffer overflow. Reported-and-acked-by: Clement LECIGNE Signed-off-by: Dan Carpenter Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/hfs/trans.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/hfs/trans.c b/fs/hfs/trans.c index e673a88b8ae..b1ce4c7ad3f 100644 --- a/fs/hfs/trans.c +++ b/fs/hfs/trans.c @@ -40,6 +40,8 @@ int hfs_mac2asc(struct super_block *sb, char *out, const struct hfs_name *in) src = in->name; srclen = in->len; + if (srclen > HFS_NAMELEN) + srclen = HFS_NAMELEN; dst = out; dstlen = HFS_MAX_NAMELEN; if (nls_io) { From 30b205cbe5b6b239e13829ff435c726c2a206e8d Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 15 Nov 2011 14:35:52 -0800 Subject: [PATCH 0276/4025] Revert "leds: save the delay values after a successful call to blink_set()" commit cb871513f656bdfc48b185b55f37857b5c750c40 upstream. Revert commit 6123b0e274503a0d3588e84fbe07c9aa01bfaf5d. The problem this patch intends to solve has alreadqy been fixed by commit 7a5caabd090b ("drivers/leds/ledtrig-timer.c: fix broken sysfs delay handling"). Signed-off-by: Johan Hovold Cc: Antonio Ospite Cc: Johannes Berg Cc: Richard Purdie Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/leds/led-class.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 661b692573e..6d5628bb060 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -270,11 +270,8 @@ void led_blink_set(struct led_classdev *led_cdev, del_timer_sync(&led_cdev->blink_timer); if (led_cdev->blink_set && - !led_cdev->blink_set(led_cdev, delay_on, delay_off)) { - led_cdev->blink_delay_on = *delay_on; - led_cdev->blink_delay_off = *delay_off; + !led_cdev->blink_set(led_cdev, delay_on, delay_off)) return; - } /* blink with 1 Hz as default if nothing specified */ if (!*delay_on && !*delay_off) From efd5ea63c5632e2365373458e013e2d4d0fc73ac Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 14 Nov 2011 09:33:56 -0500 Subject: [PATCH 0277/4025] drm/radeon: add some missing FireMV pci ids commit b872a37437e93df9d112ce674752b3b3a0a17020 upstream. Noticed by Egbert. Signed-off-by: Alex Deucher Cc: Egbert Eich Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- include/drm/drm_pciids.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 3d53efd25ab..f81676f1b31 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -4,6 +4,7 @@ */ #define radeon_PCI_IDS \ {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \ + {0x1002, 0x3151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x3155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ @@ -55,6 +56,7 @@ {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \ + {0x1002, 0x4C6E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \ {0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ {0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ {0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \ From 987ccebc15b3f1256dbcdfbb81ad542d1e2ad6a8 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 29 Jun 2011 13:34:36 -0700 Subject: [PATCH 0278/4025] drm/i915: enable ring freq scaling, RC6 and graphics turbo on Ivy Bridge v3 commit 1c70c0cebd1295a42fec75045b8a6b4419cedef3 upstream. They use the same register interfaces, so we can simply enable the existing code on IVB. v2: - resolve conflict with ring freq scaling, we can enable it too v3: - resolve conflict again, this time on drm-intel-next Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard Signed-off-by: Robert Hooker Acked-by: Leann Ogasawara Acked-by: Herton Krzesinski Signed-off-by: Tim Gardner Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 0a893f7400f..e36efdc67e1 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -865,7 +865,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) MEMSTAT_VID_SHIFT); seq_printf(m, "Current P-state: %d\n", (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); - } else if (IS_GEN6(dev)) { + } else if (IS_GEN6(dev) || IS_GEN7(dev)) { u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS); u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5609c065aaf..cbf4c4ce3a2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7943,7 +7943,7 @@ void intel_modeset_init(struct drm_device *dev) intel_init_emon(dev); } - if (IS_GEN6(dev)) + if (IS_GEN6(dev) || IS_GEN7(dev)) gen6_enable_rps(dev_priv); INIT_WORK(&dev_priv->idle_work, intel_idle_update); @@ -7985,7 +7985,7 @@ void intel_modeset_cleanup(struct drm_device *dev) if (IS_IRONLAKE_M(dev)) ironlake_disable_drps(dev); - if (IS_GEN6(dev)) + if (IS_GEN6(dev) || IS_GEN7(dev)) gen6_disable_rps(dev); if (IS_IRONLAKE_M(dev)) From 03ff90c0f9c9ea4ab0840ac21a393da859784d4d Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Fri, 26 Aug 2011 12:20:59 +0100 Subject: [PATCH 0279/4025] sfi: table irq 0xFF means 'no interrupt' commit a94cc4e6c0a26a7c8f79a432ab2c89534aa674d5 upstream. According to the SFI specification irq number 0xFF means device has no interrupt or interrupt attached via GPIO. Currently, we don't handle this special case and set irq field in *_board_info structs to 255. It leads to confusion in some drivers. Accelerometer driver tries to register interrupt 255, fails and prints "Cannot get IRQ" to dmesg. Signed-off-by: Kirill A. Shutemov Signed-off-by: Alan Cox Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/platform/mrst/mrst.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c index 7000e74b308..58425adc22c 100644 --- a/arch/x86/platform/mrst/mrst.c +++ b/arch/x86/platform/mrst/mrst.c @@ -689,7 +689,9 @@ static int __init sfi_parse_devs(struct sfi_table_header *table) irq_attr.trigger = 1; irq_attr.polarity = 1; io_apic_set_pci_routing(NULL, pentry->irq, &irq_attr); - } + } else + pentry->irq = 0; /* No irq */ + switch (pentry->type) { case SFI_DEV_TYPE_IPC: /* ID as IRQ is a hack that will go away */ From 54e6e8d507358facee8b7f5dca27231914676fd8 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 13 Oct 2011 12:04:20 +0300 Subject: [PATCH 0280/4025] x86, mrst: use a temporary variable for SFI irq commit 153b19a3b9fd8b9478495b9ee1f93f6a77c564f9 upstream. SFI tables reside in RAM and should not be modified once they are written. Current code went to set pentry->irq to zero which causes subsequent reads to fail with invalid SFI table checksum. This will break kexec as the second kernel fails to validate SFI tables. To fix this we use temporary variable for irq number. Signed-off-by: Mika Westerberg Reviewed-by: Kirill A. Shutemov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/platform/mrst/mrst.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c index 58425adc22c..fe73276e026 100644 --- a/arch/x86/platform/mrst/mrst.c +++ b/arch/x86/platform/mrst/mrst.c @@ -678,38 +678,40 @@ static int __init sfi_parse_devs(struct sfi_table_header *table) pentry = (struct sfi_device_table_entry *)sb->pentry; for (i = 0; i < num; i++, pentry++) { - if (pentry->irq != (u8)0xff) { /* native RTE case */ + int irq = pentry->irq; + + if (irq != (u8)0xff) { /* native RTE case */ /* these SPI2 devices are not exposed to system as PCI * devices, but they have separate RTE entry in IOAPIC * so we have to enable them one by one here */ - ioapic = mp_find_ioapic(pentry->irq); + ioapic = mp_find_ioapic(irq); irq_attr.ioapic = ioapic; - irq_attr.ioapic_pin = pentry->irq; + irq_attr.ioapic_pin = irq; irq_attr.trigger = 1; irq_attr.polarity = 1; - io_apic_set_pci_routing(NULL, pentry->irq, &irq_attr); + io_apic_set_pci_routing(NULL, irq, &irq_attr); } else - pentry->irq = 0; /* No irq */ + irq = 0; /* No irq */ switch (pentry->type) { case SFI_DEV_TYPE_IPC: /* ID as IRQ is a hack that will go away */ - pdev = platform_device_alloc(pentry->name, pentry->irq); + pdev = platform_device_alloc(pentry->name, irq); if (pdev == NULL) { pr_err("out of memory for SFI platform device '%s'.\n", pentry->name); continue; } - install_irq_resource(pdev, pentry->irq); + install_irq_resource(pdev, irq); pr_debug("info[%2d]: IPC bus, name = %16.16s, " - "irq = 0x%2x\n", i, pentry->name, pentry->irq); + "irq = 0x%2x\n", i, pentry->name, irq); sfi_handle_ipc_dev(pdev); break; case SFI_DEV_TYPE_SPI: memset(&spi_info, 0, sizeof(spi_info)); strncpy(spi_info.modalias, pentry->name, SFI_NAME_LEN); - spi_info.irq = pentry->irq; + spi_info.irq = irq; spi_info.bus_num = pentry->host_num; spi_info.chip_select = pentry->addr; spi_info.max_speed_hz = pentry->max_freq; @@ -726,7 +728,7 @@ static int __init sfi_parse_devs(struct sfi_table_header *table) memset(&i2c_info, 0, sizeof(i2c_info)); bus = pentry->host_num; strncpy(i2c_info.type, pentry->name, SFI_NAME_LEN); - i2c_info.irq = pentry->irq; + i2c_info.irq = irq; i2c_info.addr = pentry->addr; pr_debug("info[%2d]: I2C bus = %d, name = %16.16s, " "irq = 0x%2x, addr = 0x%x\n", i, bus, From 91ed232dabe5c813aa506c218223a484e78092eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Tue, 8 Nov 2011 17:15:03 +0100 Subject: [PATCH 0281/4025] b43: refuse to load unsupported firmware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [This patch is supposed to be applied in 3.1 (and maybe older) branches only.] New kernels support newer firmware that users may try to incorrectly use with older kernels. Display error and explain the problem in such a case Signed-off-by: Rafał Miłecki Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/b43/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index b1fe4fe322a..7c2e09a1cc0 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2401,6 +2401,13 @@ static int b43_upload_microcode(struct b43_wldev *dev) b43_print_fw_helptext(dev->wl, 1); err = -EOPNOTSUPP; goto error; + } else if (fwrev >= 598) { + b43err(dev->wl, "YOUR FIRMWARE IS TOO NEW. Support for " + "firmware 598 and up requires kernel 3.2 or newer. You " + "have to install older firmware or upgrade kernel.\n"); + b43_print_fw_helptext(dev->wl, 1); + err = -EOPNOTSUPP; + goto error; } dev->fw.rev = fwrev; dev->fw.patch = fwpatch; From 79d96b2756e325e484f27ed4f61addc83935e196 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 8 Nov 2011 16:22:01 +1100 Subject: [PATCH 0282/4025] md/raid5: abort any pending parity operations when array fails. commit 9a3f530f39f4490eaa18b02719fb74ce5f4d2d86 upstream. When the number of failed devices exceeds the allowed number we must abort any active parity operations (checks or updates) as they are no longer meaningful, and can lead to a BUG_ON in handle_parity_checks6. This bug was introduce by commit 6c0069c0ae9659e3a91b68eaed06a5c6c37f45c8 in 2.6.29. Reported-by: Manish Katiyar Tested-by: Manish Katiyar Acked-by: Dan Williams Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid5.c | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e509147318e..cbb50d3883a 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3120,12 +3120,16 @@ static void handle_stripe5(struct stripe_head *sh) /* check if the array has lost two devices and, if so, some requests might * need to be failed */ - if (s.failed > 1 && s.to_read+s.to_write+s.written) - handle_failed_stripe(conf, sh, &s, disks, &return_bi); - if (s.failed > 1 && s.syncing) { - md_done_sync(conf->mddev, STRIPE_SECTORS,0); - clear_bit(STRIPE_SYNCING, &sh->state); - s.syncing = 0; + if (s.failed > 1) { + sh->check_state = 0; + sh->reconstruct_state = 0; + if (s.to_read+s.to_write+s.written) + handle_failed_stripe(conf, sh, &s, disks, &return_bi); + if (s.syncing) { + md_done_sync(conf->mddev, STRIPE_SECTORS,0); + clear_bit(STRIPE_SYNCING, &sh->state); + s.syncing = 0; + } } /* might be able to return some write requests if the parity block @@ -3412,12 +3416,16 @@ static void handle_stripe6(struct stripe_head *sh) /* check if the array has lost >2 devices and, if so, some requests * might need to be failed */ - if (s.failed > 2 && s.to_read+s.to_write+s.written) - handle_failed_stripe(conf, sh, &s, disks, &return_bi); - if (s.failed > 2 && s.syncing) { - md_done_sync(conf->mddev, STRIPE_SECTORS,0); - clear_bit(STRIPE_SYNCING, &sh->state); - s.syncing = 0; + if (s.failed > 2) { + sh->check_state = 0; + sh->reconstruct_state = 0; + if (s.to_read+s.to_write+s.written) + handle_failed_stripe(conf, sh, &s, disks, &return_bi); + if (s.syncing) { + md_done_sync(conf->mddev, STRIPE_SECTORS,0); + clear_bit(STRIPE_SYNCING, &sh->state); + s.syncing = 0; + } } /* From 11b8fc6ae54bf18a48c94e181c37ca135b858b42 Mon Sep 17 00:00:00 2001 From: Thomas Weber Date: Mon, 5 Sep 2011 11:26:33 +0200 Subject: [PATCH 0283/4025] mfd: Fix twl4030 dependencies for audio codec commit f09ee0451a44a4e913a7c3cec3805508f7de6c54 upstream. The codec for Devkit8000 (TWL4030) was not detected except when build with CONFIG_SND_SOC_ALL_CODECS. twl-core.c still uses the CONFIG_TWL4030_CODEC for twl_has_codec(). In commit 57fe7251f5bfc4332f24479376de48a1e8ca6211 the CONFIG_TWL4030_CODEC was renamed into CONFIG_MFD_TWL4030_AUDIO, thatswhy the codec was not detected. This patch renames the CONFIG_ TWL4030_CODEC into CONFIG_MFD_TWL4030_AUDIO in twl-core.c. Signed-off-by: Thomas Weber Acked-by: Peter Ujfalusi Signed-off-by: Samuel Ortiz Cc: Jarkko Nikula Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/twl-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index b8f2a4e7f6e..b9188a23389 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -109,7 +109,7 @@ #define twl_has_watchdog() false #endif -#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE) ||\ +#if defined(CONFIG_MFD_TWL4030_AUDIO) || defined(CONFIG_MFD_TWL4030_AUDIO_MODULE) ||\ defined(CONFIG_SND_SOC_TWL6040) || defined(CONFIG_SND_SOC_TWL6040_MODULE) #define twl_has_codec() true #else From 66e85a1675dc6d4e05e0fd152ef1ad485b3fb985 Mon Sep 17 00:00:00 2001 From: Zhenzhong Duan Date: Thu, 27 Oct 2011 22:28:59 -0700 Subject: [PATCH 0284/4025] xen:pvhvm: enable PVHVM VCPU placement when using more than 32 CPUs. commit 90d4f5534d14815bd94c10e8ceccc57287657ecc upstream. PVHVM running with more than 32 vcpus and pv_irq/pv_time enabled need VCPU placement to work, or else it will softlockup. Acked-by: Stefano Stabellini Signed-off-by: Zhenzhong Duan Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/enlighten.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index 67d69f1e2b7..0fb662abceb 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -1337,7 +1337,7 @@ static int __cpuinit xen_hvm_cpu_notify(struct notifier_block *self, int cpu = (long)hcpu; switch (action) { case CPU_UP_PREPARE: - per_cpu(xen_vcpu, cpu) = &HYPERVISOR_shared_info->vcpu_info[cpu]; + xen_vcpu_setup(cpu); if (xen_have_vector_callback) xen_init_lock_cpu(cpu); break; @@ -1367,7 +1367,6 @@ static void __init xen_hvm_guest_init(void) xen_hvm_smp_init(); register_cpu_notifier(&xen_hvm_cpu_notifier); xen_unplug_emulated_devices(); - have_vcpu_info_placement = 0; x86_init.irqs.intr_init = xen_init_IRQ; xen_hvm_init_time_ops(); xen_hvm_init_mmu_ops(); From 2c59105ba0af5df97d9b614c999553f79d6ece67 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 4 Nov 2011 21:24:08 +0300 Subject: [PATCH 0285/4025] xen-gntalloc: integer overflow in gntalloc_ioctl_alloc() commit 21643e69a4c06f7ef155fbc70e3fba13fba4a756 upstream. On 32 bit systems a high value of op.count could lead to an integer overflow in the kzalloc() and gref_ids would be smaller than expected. If the you triggered another integer overflow in "if (gref_size + op.count > limit)" then you'd probably get memory corruption inside add_grefs(). Signed-off-by: Dan Carpenter Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/xen/gntalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c index f6832f46aea..23c60cf4313 100644 --- a/drivers/xen/gntalloc.c +++ b/drivers/xen/gntalloc.c @@ -280,7 +280,7 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv, goto out; } - gref_ids = kzalloc(sizeof(gref_ids[0]) * op.count, GFP_TEMPORARY); + gref_ids = kcalloc(op.count, sizeof(gref_ids[0]), GFP_TEMPORARY); if (!gref_ids) { rc = -ENOMEM; goto out; From 015be9f48be43814f14326555e9ea576cf0343d7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 4 Nov 2011 21:24:36 +0300 Subject: [PATCH 0286/4025] xen-gntalloc: signedness bug in add_grefs() commit 99cb2ddcc617f43917e94a4147aa3ccdb2bcd77e upstream. gref->gref_id is unsigned so the error handling didn't work. gnttab_grant_foreign_access() returns an int type, so we can add a cast here, and it doesn't cause any problems. gnttab_grant_foreign_access() can return a variety of errors including -ENOSPC, -ENOSYS and -ENOMEM. Signed-off-by: Dan Carpenter Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/xen/gntalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c index 23c60cf4313..e1c4c6e5b46 100644 --- a/drivers/xen/gntalloc.c +++ b/drivers/xen/gntalloc.c @@ -135,7 +135,7 @@ static int add_grefs(struct ioctl_gntalloc_alloc_gref *op, /* Grant foreign access to the page. */ gref->gref_id = gnttab_grant_foreign_access(op->domid, pfn_to_mfn(page_to_pfn(gref->page)), readonly); - if (gref->gref_id < 0) { + if ((int)gref->gref_id < 0) { rc = gref->gref_id; goto undo; } From 9db74684bd2f8261cef34d2398f32d48c8ad8e2f Mon Sep 17 00:00:00 2001 From: Geoff Levand Date: Tue, 8 Nov 2011 12:37:26 +0000 Subject: [PATCH 0287/4025] powerpc/ps3: Fix lost SMP IPIs commit 72f3bea075287785ed32b777b6dd2636aa7002e8 upstream. Fixes the PS3 bootup hang introduced in 3.0-rc1 by: commit 317f394160e9beb97d19a84c39b7e5eb3d7815a sched: Move the second half of ttwu() to the remote cpu Move the PS3's LV1 EOI call lv1_end_of_interrupt_ext() from ps3_chip_eoi() to ps3_get_irq() for IPI messages. If lv1_send_event_locally() is called between a previous call to lv1_send_event_locally() and the coresponding call to lv1_end_of_interrupt_ext() the second event will not be delivered to the target cpu. The PS3's SMP IPIs are implemented using lv1_send_event_locally(), so if two IPI messages of the same type are sent to the same target in a relatively short period of time the second IPI event can become lost when lv1_end_of_interrupt_ext() is called from ps3_chip_eoi(). Signed-off-by: Geoff Levand Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/ps3/interrupt.c | 23 ++++++++++++++++++++++- arch/powerpc/platforms/ps3/platform.h | 1 + arch/powerpc/platforms/ps3/smp.c | 2 ++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 600ed2c0ed5..1aa478b97aa 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c @@ -88,6 +88,7 @@ struct ps3_private { struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN))); u64 ppe_id; u64 thread_id; + unsigned long ipi_mask; }; static DEFINE_PER_CPU(struct ps3_private, ps3_private); @@ -144,7 +145,11 @@ static void ps3_chip_unmask(struct irq_data *d) static void ps3_chip_eoi(struct irq_data *d) { const struct ps3_private *pd = irq_data_get_irq_chip_data(d); - lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq); + + /* non-IPIs are EOIed here. */ + + if (!test_bit(63 - d->irq, &pd->ipi_mask)) + lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq); } /** @@ -691,6 +696,16 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) cpu, virq, pd->bmp.ipi_debug_brk_mask); } +void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq) +{ + struct ps3_private *pd = &per_cpu(ps3_private, cpu); + + set_bit(63 - virq, &pd->ipi_mask); + + DBG("%s:%d: cpu %u, virq %u, ipi_mask %lxh\n", __func__, __LINE__, + cpu, virq, pd->ipi_mask); +} + static unsigned int ps3_get_irq(void) { struct ps3_private *pd = &__get_cpu_var(ps3_private); @@ -720,6 +735,12 @@ static unsigned int ps3_get_irq(void) BUG(); } #endif + + /* IPIs are EOIed here. */ + + if (test_bit(63 - plug, &pd->ipi_mask)) + lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, plug); + return plug; } diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 9a196a88eda..1a633ed0fe9 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h @@ -43,6 +43,7 @@ void ps3_mm_shutdown(void); void ps3_init_IRQ(void); void ps3_shutdown_IRQ(int cpu); void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq); +void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq); /* smp */ diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index 4c44794faac..f609345b6c3 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c @@ -94,6 +94,8 @@ static void __init ps3_smp_setup_cpu(int cpu) if (result) virqs[i] = NO_IRQ; + else + ps3_register_ipi_irq(cpu, virqs[i]); } ps3_register_ipi_debug_brk(cpu, virqs[PPC_MSG_DEBUGGER_BREAK]); From 214af5d355ce204cd0bcf630245cdc37853cb484 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 14 Nov 2011 12:54:47 +0000 Subject: [PATCH 0288/4025] powerpc: Copy down exception vectors after feature fixups commit d715e433b7ad19c02fc4becf0d5e9a59f97925de upstream. kdump fails because we try to execute an HV only instruction. Feature fixups are being applied after we copy the exception vectors down to 0 so they miss out on any updates. We have always had this issue but it only became critical in v3.0 when we added CFAR support (breaks POWER5) and v3.1 when we added POWERNV (breaks everyone). Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/sections.h | 2 +- arch/powerpc/include/asm/synch.h | 1 + arch/powerpc/kernel/kvm.c | 1 - arch/powerpc/kernel/setup_32.c | 2 ++ arch/powerpc/kernel/setup_64.c | 1 + arch/powerpc/lib/feature-fixups.c | 23 +++++++++++++++++++++++ 6 files changed, 28 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h index 6fbce725c71..a0f358d4a00 100644 --- a/arch/powerpc/include/asm/sections.h +++ b/arch/powerpc/include/asm/sections.h @@ -8,7 +8,7 @@ #ifdef __powerpc64__ -extern char _end[]; +extern char __end_interrupts[]; static inline int in_kernel_text(unsigned long addr) { diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h index d7cab44643c..87878c68d1c 100644 --- a/arch/powerpc/include/asm/synch.h +++ b/arch/powerpc/include/asm/synch.h @@ -13,6 +13,7 @@ extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup; extern void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end); +extern void do_final_fixups(void); static inline void eieio(void) { diff --git a/arch/powerpc/kernel/kvm.c b/arch/powerpc/kernel/kvm.c index b06bdae0406..ad892f7a757 100644 --- a/arch/powerpc/kernel/kvm.c +++ b/arch/powerpc/kernel/kvm.c @@ -131,7 +131,6 @@ static void kvm_patch_ins_b(u32 *inst, int addr) /* On relocatable kernels interrupts handlers and our code can be in different regions, so we don't patch them */ - extern u32 __end_interrupts; if ((ulong)inst < (ulong)&__end_interrupts) return; #endif diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 620d792b52e..c7e7b8c718d 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -107,6 +107,8 @@ notrace unsigned long __init early_init(unsigned long dt_ptr) PTRRELOC(&__start___lwsync_fixup), PTRRELOC(&__stop___lwsync_fixup)); + do_final_fixups(); + return KERNELBASE + offset; } diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index a88bf2713d4..7867fd17a0d 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -352,6 +352,7 @@ void __init setup_system(void) &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); do_lwsync_fixups(cur_cpu_spec->cpu_features, &__start___lwsync_fixup, &__stop___lwsync_fixup); + do_final_fixups(); /* * Unflatten the device-tree passed by prom_init or kexec diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c index 0d08d017139..7a8a7487cee 100644 --- a/arch/powerpc/lib/feature-fixups.c +++ b/arch/powerpc/lib/feature-fixups.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include struct fixup_entry { @@ -128,6 +130,27 @@ void do_lwsync_fixups(unsigned long value, void *fixup_start, void *fixup_end) } } +void do_final_fixups(void) +{ +#if defined(CONFIG_PPC64) && defined(CONFIG_RELOCATABLE) + int *src, *dest; + unsigned long length; + + if (PHYSICAL_START == 0) + return; + + src = (int *)(KERNELBASE + PHYSICAL_START); + dest = (int *)KERNELBASE; + length = (__end_interrupts - _stext) / sizeof(int); + + while (length--) { + patch_instruction(dest, *src); + src++; + dest++; + } +#endif +} + #ifdef CONFIG_FTR_FIXUP_SELFTEST #define check(x) \ From 1f36bbbe41ab7043a428175a71b3948574938752 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 11 Nov 2011 13:29:04 +0100 Subject: [PATCH 0289/4025] backing-dev: ensure wakeup_timer is deleted commit 7a401a972df8e184b3d1a3fc958c0a4ddee8d312 upstream. bdi_prune_sb() in bdi_unregister() attempts to removes the bdi links from all super_blocks and then del_timer_sync() the writeback timer. However, this can race with __mark_inode_dirty(), leading to bdi_wakeup_thread_delayed() rearming the writeback timer on the bdi we're unregistering, after we've called del_timer_sync(). This can end up with the bdi being freed with an active timer inside it, as in the case of the following dump after the removal of an SD card. Fix this by redoing the del_timer_sync() in bdi_destory(). ------------[ cut here ]------------ WARNING: at /home/rabin/kernel/arm/lib/debugobjects.c:262 debug_print_object+0x9c/0xc8() ODEBUG: free active (active state 0) object type: timer_list hint: wakeup_timer_fn+0x0/0x180 Modules linked in: Backtrace: [] (dump_backtrace+0x0/0x110) from [] (dump_stack+0x18/0x1c) r6:c02bc638 r5:00000106 r4:c79f5d18 r3:00000000 [] (dump_stack+0x0/0x1c) from [] (warn_slowpath_common+0x54/0x6c) [] (warn_slowpath_common+0x0/0x6c) from [] (warn_slowpath_fmt+0x38/0x40) r8:20000013 r7:c780c6f0 r6:c031613c r5:c780c6f0 r4:c02b1b29 r3:00000009 [] (warn_slowpath_fmt+0x0/0x40) from [] (debug_print_object+0x9c/0xc8) r3:c02b1b29 r2:c02bc662 [] (debug_print_object+0x0/0xc8) from [] (debug_check_no_obj_freed+0xac/0x1dc) r6:c7964000 r5:00000001 r4:c7964000 [] (debug_check_no_obj_freed+0x0/0x1dc) from [] (kmem_cache_free+0x88/0x1f8) [] (kmem_cache_free+0x0/0x1f8) from [] (blk_release_queue+0x70/0x78) [] (blk_release_queue+0x0/0x78) from [] (kobject_release+0x70/0x84) r5:c79641f0 r4:c796420c [] (kobject_release+0x0/0x84) from [] (kref_put+0x68/0x80) r7:00000083 r6:c74083d0 r5:c015289c r4:c796420c [] (kref_put+0x0/0x80) from [] (kobject_put+0x48/0x5c) r5:c79643b4 r4:c79641f0 [] (kobject_put+0x0/0x5c) from [] (blk_cleanup_queue+0x68/0x74) r4:c7964000 [] (blk_cleanup_queue+0x0/0x74) from [] (mmc_blk_put+0x78/0xe8) r5:00000000 r4:c794c400 [] (mmc_blk_put+0x0/0xe8) from [] (mmc_blk_release+0x24/0x38) r5:c794c400 r4:c0322824 [] (mmc_blk_release+0x0/0x38) from [] (__blkdev_put+0xe8/0x170) r5:c78d5e00 r4:c74083c0 [] (__blkdev_put+0x0/0x170) from [] (blkdev_put+0x11c/0x12c) r8:c79f5f70 r7:00000001 r6:c74083d0 r5:00000083 r4:c74083c0 r3:00000000 [] (blkdev_put+0x0/0x12c) from [] (kill_block_super+0x60/0x6c) r7:c7942300 r6:c79f4000 r5:00000083 r4:c74083c0 [] (kill_block_super+0x0/0x6c) from [] (deactivate_locked_super+0x44/0x70) r6:c79f4000 r5:c031af64 r4:c794dc00 r3:c00b06c4 [] (deactivate_locked_super+0x0/0x70) from [] (deactivate_super+0x6c/0x70) r5:c794dc00 r4:c794dc00 [] (deactivate_super+0x0/0x70) from [] (mntput_no_expire+0x188/0x194) r5:c794dc00 r4:c7942300 [] (mntput_no_expire+0x0/0x194) from [] (sys_umount+0x2e4/0x310) r6:c7942300 r5:00000000 r4:00000000 r3:00000000 [] (sys_umount+0x0/0x310) from [] (ret_fast_syscall+0x0/0x30) ---[ end trace e5c83c92ada51c76 ]--- Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- mm/backing-dev.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mm/backing-dev.c b/mm/backing-dev.c index e56fe35cef0..b3b122f4630 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -686,6 +686,14 @@ void bdi_destroy(struct backing_dev_info *bdi) bdi_unregister(bdi); + /* + * If bdi_unregister() had already been called earlier, the + * wakeup_timer could still be armed because bdi_prune_sb() + * can race with the bdi_wakeup_thread_delayed() calls from + * __mark_inode_dirty(). + */ + del_timer_sync(&bdi->wb.wakeup_timer); + for (i = 0; i < NR_BDI_STAT_ITEMS; i++) percpu_counter_destroy(&bdi->bdi_stat[i]); From acc1887e7e0da5d19fb77b2a5e5c5db2d57667f9 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sun, 13 Nov 2011 19:58:09 +0100 Subject: [PATCH 0290/4025] block: Always check length of all iov entries in blk_rq_map_user_iov() commit 6b76106d8ef31111d6fc469564b83b5f5542794f upstream. Even after commit 5478755616ae2ef1ce144dded589b62b2a50d575 ("block: check for proper length of iov entries earlier ...") we still won't check for zero-length entries after an unaligned entry. Remove the break-statement, so all entries are checked. Signed-off-by: Ben Hutchings Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/blk-map.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/block/blk-map.c b/block/blk-map.c index e663ac2d8e6..164cd005970 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -204,10 +204,11 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, if (!iov[i].iov_len) return -EINVAL; - if (uaddr & queue_dma_alignment(q)) { + /* + * Keep going so we check length of all segments + */ + if (uaddr & queue_dma_alignment(q)) unaligned = 1; - break; - } } if (unaligned || (q->dma_pad_mask & len) || map_data) From c7e2ea59cdd74342d3614bee9fc42fa2fb5add7e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 21 Nov 2011 14:37:44 -0800 Subject: [PATCH 0291/4025] Linux 3.0.10 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 438c11a865e..36036d13433 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 9 +SUBLEVEL = 10 EXTRAVERSION = NAME = Sneaky Weasel From 2cecc3d5df1bfb3356234b81cda993e187ac4f89 Mon Sep 17 00:00:00 2001 From: Edward Donovan Date: Tue, 1 Nov 2011 15:29:44 -0400 Subject: [PATCH 0292/4025] genirq: Fix irqfixup, irqpoll regression commit c75d720fca8a91ce99196d33adea383621027bf2 upstream. commit d05c65fff0 ("genirq: spurious: Run only one poller at a time") introduced a regression, leaving the boot options 'irqfixup' and 'irqpoll' non-functional. The patch placed tests in each function, to exit if the function is already running. The test in 'misrouted_irq' exited when it should have proceeded, effectively disabling 'misrouted_irq' and 'poll_spurious_irqs'. The check for an already running poller needs to be "!= 1" not "== 1" as "1" is the value when the first poller starts running. Signed-off-by: Edward Donovan Cc: maciej.rutecki@gmail.com Link: http://lkml.kernel.org/r/1320175784-6745-1-git-send-email-edward.donovan@numble.net Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/irq/spurious.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index aa57d5da18c..b5f4742693c 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -115,7 +115,7 @@ static int misrouted_irq(int irq) struct irq_desc *desc; int i, ok = 0; - if (atomic_inc_return(&irq_poll_active) == 1) + if (atomic_inc_return(&irq_poll_active) != 1) goto out; irq_poll_cpu = smp_processor_id(); From 9c6e9f7596fb2c2dbcbb32d45efdb0baf6ae2e52 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 7 Nov 2011 08:51:24 -0600 Subject: [PATCH 0293/4025] fix WARNING: at drivers/scsi/scsi_lib.c:1704 commit 4e6c82b3614a18740ef63109d58743a359266daf upstream. On Mon, 2011-11-07 at 17:24 +1100, Stephen Rothwell wrote: > Hi all, > > Starting some time last week I am getting the following during boot on > our PPC970 blade: > > calling .ipr_init+0x0/0x68 @ 1 > ipr: IBM Power RAID SCSI Device Driver version: 2.5.2 (April 27, 2011) > ipr 0000:01:01.0: Found IOA with IRQ: 26 > ipr 0000:01:01.0: Starting IOA initialization sequence. > ipr 0000:01:01.0: Adapter firmware version: 06160039 > ipr 0000:01:01.0: IOA initialized. > scsi0 : IBM 572E Storage Adapter > ------------[ cut here ]------------ > WARNING: at drivers/scsi/scsi_lib.c:1704 > Modules linked in: > NIP: c00000000053b3d4 LR: c00000000053e5b0 CTR: c000000000541d70 > REGS: c0000000783c2f60 TRAP: 0700 Not tainted (3.1.0-autokern1) > MSR: 8000000000029032 CR: 24002024 XER: 20000002 > TASK = c0000000783b8000[1] 'swapper' THREAD: c0000000783c0000 CPU: 0 > GPR00: 0000000000000001 c0000000783c31e0 c000000000cf38b0 c00000000239a9d0 > GPR04: c000000000cbe8f8 0000000000000000 c0000000783c3040 0000000000000000 > GPR08: c000000075daf488 c000000078a3b7ff c000000000bcacc8 0000000000000000 > GPR12: 0000000044002028 c000000007ffb000 0000000002e40000 000000000099b800 > GPR16: 0000000000000000 c000000000bba5fc c000000000a61db8 0000000000000000 > GPR20: 0000000001b77200 0000000000000000 c000000078990000 0000000000000001 > GPR24: c000000002396828 0000000000000000 0000000000000000 c000000078a3b938 > GPR28: fffffffffffffffa c0000000008ad2c0 c000000000c7faa8 c00000000239a9d0 > NIP [c00000000053b3d4] .scsi_free_queue+0x24/0x90 > LR [c00000000053e5b0] .scsi_alloc_sdev+0x280/0x2e0 > Call Trace: > [c0000000783c31e0] [c000000000c7faa8] wireless_seq_fops+0x278d0/0x2eb88 (unreliable) > [c0000000783c3270] [c00000000053e5b0] .scsi_alloc_sdev+0x280/0x2e0 > [c0000000783c3330] [c00000000053eba0] .scsi_probe_and_add_lun+0x390/0xb40 > [c0000000783c34a0] [c00000000053f7ec] .__scsi_scan_target+0x16c/0x650 > [c0000000783c35f0] [c00000000053fd90] .scsi_scan_channel+0xc0/0x100 > [c0000000783c36a0] [c00000000053fefc] .scsi_scan_host_selected+0x12c/0x1c0 > [c0000000783c3750] [c00000000083dcb4] .ipr_probe+0x2c0/0x390 > [c0000000783c3830] [c0000000003f50b4] .local_pci_probe+0x34/0x50 > [c0000000783c38a0] [c0000000003f5f78] .pci_device_probe+0x148/0x150 > [c0000000783c3950] [c0000000004e1e8c] .driver_probe_device+0xdc/0x210 > [c0000000783c39f0] [c0000000004e20cc] .__driver_attach+0x10c/0x110 > [c0000000783c3a80] [c0000000004e1228] .bus_for_each_dev+0x98/0xf0 > [c0000000783c3b30] [c0000000004e1bf8] .driver_attach+0x28/0x40 > [c0000000783c3bb0] [c0000000004e07d8] .bus_add_driver+0x218/0x340 > [c0000000783c3c60] [c0000000004e2a2c] .driver_register+0x9c/0x1b0 > [c0000000783c3d00] [c0000000003f62d4] .__pci_register_driver+0x64/0x140 > [c0000000783c3da0] [c000000000b99f88] .ipr_init+0x4c/0x68 > [c0000000783c3e20] [c00000000000ad24] .do_one_initcall+0x1a4/0x1e0 > [c0000000783c3ee0] [c000000000b512d0] .kernel_init+0x14c/0x1fc > [c0000000783c3f90] [c000000000022468] .kernel_thread+0x54/0x70 > Instruction dump: > ebe1fff8 7c0803a6 4e800020 7c0802a6 fba1ffe8 fbe1fff8 7c7f1b78 f8010010 > f821ff71 e8030398 3120ffff 7c090110 <0b000000> e86303b0 482de065 60000000 > ---[ end trace 759bed76a85e8dec ]--- > scsi 0:0:1:0: Direct-Access IBM-ESXS MAY2036RC T106 PQ: 0 ANSI: 5 > ------------[ cut here ]------------ > > I get lots more of these. The obvious commit to point the finger at > is 3308511c93e6 ("[SCSI] Make scsi_free_queue() kill pending SCSI > commands") but the root cause may be something different. Caused by commit f7c9c6bb14f3104608a3a83cadea10a6943d2804 Author: Anton Blanchard Date: Thu Nov 3 08:56:22 2011 +1100 [SCSI] Fix block queue and elevator memory leak in scsi_alloc_sdev Doesn't completely do the teardown. The true fix is to do a proper teardown instead of hand rolling it Reported-by: Stephen Rothwell Tested-by: Stephen Rothwell Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_scan.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 72273a0e566..b3c6d957fbd 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -319,11 +319,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, return sdev; out_device_destroy: - scsi_device_set_state(sdev, SDEV_DEL); - transport_destroy_device(&sdev->sdev_gendev); - put_device(&sdev->sdev_dev); - scsi_free_queue(sdev->request_queue); - put_device(&sdev->sdev_gendev); + __scsi_remove_device(sdev); out: if (display_failure_msg) printk(ALLOC_FAILURE_MSG, __func__); From 4987223080c8390203a0a588df04d58eafde4a07 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 11 Nov 2011 11:14:23 -0500 Subject: [PATCH 0294/4025] hpsa: Disable ASPM commit e5a44df85e8d78e5c2d3d2e4f59b460905691e2f upstream. The Windows driver .inf disables ASPM on hpsa devices. Do the same because the selection of a non default ASPM policy can cause the device to hang. Signed-off-by: Matthew Garrett Acked-by: Mike Miller Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/hpsa.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 6689d5d4d40..56a9f3f676e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -3887,6 +3888,10 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) dev_warn(&h->pdev->dev, "controller appears to be disabled\n"); return -ENODEV; } + + pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S | + PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM); + err = pci_enable_device(h->pdev); if (err) { dev_warn(&h->pdev->dev, "unable to enable PCI device\n"); From 6e5dcf64dfc2415a59987a4096b4ebbf03469bf6 Mon Sep 17 00:00:00 2001 From: Vasily Averin Date: Fri, 11 Nov 2011 13:42:16 +0400 Subject: [PATCH 0295/4025] aacraid: controller hangs if kernel uses non-default ASPM policy commit cf16123c9c8e346ed1dd171295a678d77648d7f8 upstream. Aacraid controller can hang on some nodes if kernel uses non-default (powersave) ASPM policy. Controller hangs shortly after successful load and hardware detection. Scsi error handler detects this hang and tries to restart hardware but it does not help. Initially it was noticed on RHEL6-based openVZ kernel after backporting aacraid driver from mainline (RHEL6 kernel with original driver works well) http://bugzilla.openvz.org/show_bug.cgi?id=2043 This issue happens because default ASPM policy was changed in Red Hat kernels. Therefore guys from Red Hat have noticed this problem long time ago: on Fedora 12 https://bugzilla.redhat.com/show_bug.cgi?id=540478 on Fedora 14 https://bugzilla.redhat.com/show_bug.cgi?id=679385 In RHEL6 kernel this issue was fixed, ASPM was disabled in aacraid driver. In kernel changelog I've found that seems it was done by Matthew Garrett: - [scsi] aacraid: Disable ASPM by default (Matthew Garrett) [599735] However seems this patch was not submitted to mainline. I've reproduced this issue on vanilla 3.1.0 kernel booted with "pcie_aspm.policy=powersave" option, So I believe it makes sense to do it now. Signed-off-by: Vasily Averin [mjg: Checking the Windows drivers indicates that they disable ASPM under all circumstances, so:] Acked-by: Matthew Garrett Acked-by: Achim Leubner Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/aacraid/linit.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 3382475dc22..c7b6fed8873 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -1108,6 +1109,9 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, unique_id++; } + pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | + PCIE_LINK_STATE_CLKPM); + error = pci_enable_device(pdev); if (error) goto out; From ef2b44d1861ec01b9058ab3bcf82ad4c138551fe Mon Sep 17 00:00:00 2001 From: Tony Jago Date: Fri, 12 Aug 2011 00:19:11 -0300 Subject: [PATCH 0296/4025] saa7164: Add support for another HVR2200 hardware revision commit 62dd28d0c659db29bdb89cfe9f0aefe42f0adfe9 upstream. Hauppauge have released a new model rev, sub id 8940, this adds support. [stoth@kernellabs.com: I modified Tony's patch slightly in relation to the card numbering in saa7164.h, appending rather than inserting the new card - normal practise] Signed-off-by: Tony Jago Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Stefan Bader Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/saa7164/saa7164-cards.c | 66 +++++++++++++++++++++ drivers/media/video/saa7164/saa7164-dvb.c | 1 + drivers/media/video/saa7164/saa7164.h | 1 + 3 files changed, 68 insertions(+) diff --git a/drivers/media/video/saa7164/saa7164-cards.c b/drivers/media/video/saa7164/saa7164-cards.c index 69822a4e727..c71369173fa 100644 --- a/drivers/media/video/saa7164/saa7164-cards.c +++ b/drivers/media/video/saa7164/saa7164-cards.c @@ -203,6 +203,66 @@ struct saa7164_board saa7164_boards[] = { .i2c_reg_len = REGLEN_8bit, } }, }, + [SAA7164_BOARD_HAUPPAUGE_HVR2200_4] = { + .name = "Hauppauge WinTV-HVR2200", + .porta = SAA7164_MPEG_DVB, + .portb = SAA7164_MPEG_DVB, + .portc = SAA7164_MPEG_ENCODER, + .portd = SAA7164_MPEG_ENCODER, + .porte = SAA7164_MPEG_VBI, + .portf = SAA7164_MPEG_VBI, + .chiprev = SAA7164_CHIP_REV3, + .unit = {{ + .id = 0x1d, + .type = SAA7164_UNIT_EEPROM, + .name = "4K EEPROM", + .i2c_bus_nr = SAA7164_I2C_BUS_0, + .i2c_bus_addr = 0xa0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x04, + .type = SAA7164_UNIT_TUNER, + .name = "TDA18271-1", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x05, + .type = SAA7164_UNIT_ANALOG_DEMODULATOR, + .name = "TDA8290-1", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0x84 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x1b, + .type = SAA7164_UNIT_TUNER, + .name = "TDA18271-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0xc0 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x1c, + .type = SAA7164_UNIT_ANALOG_DEMODULATOR, + .name = "TDA8290-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0x84 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x1e, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "TDA10048-1", + .i2c_bus_nr = SAA7164_I2C_BUS_1, + .i2c_bus_addr = 0x10 >> 1, + .i2c_reg_len = REGLEN_8bit, + }, { + .id = 0x1f, + .type = SAA7164_UNIT_DIGITAL_DEMODULATOR, + .name = "TDA10048-2", + .i2c_bus_nr = SAA7164_I2C_BUS_2, + .i2c_bus_addr = 0x12 >> 1, + .i2c_reg_len = REGLEN_8bit, + } }, + }, [SAA7164_BOARD_HAUPPAUGE_HVR2250] = { .name = "Hauppauge WinTV-HVR2250", .porta = SAA7164_MPEG_DVB, @@ -426,6 +486,10 @@ struct saa7164_subid saa7164_subids[] = { .subvendor = 0x0070, .subdevice = 0x8851, .card = SAA7164_BOARD_HAUPPAUGE_HVR2250_2, + }, { + .subvendor = 0x0070, + .subdevice = 0x8940, + .card = SAA7164_BOARD_HAUPPAUGE_HVR2200_4, }, }; const unsigned int saa7164_idcount = ARRAY_SIZE(saa7164_subids); @@ -469,6 +533,7 @@ void saa7164_gpio_setup(struct saa7164_dev *dev) case SAA7164_BOARD_HAUPPAUGE_HVR2200: case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: + case SAA7164_BOARD_HAUPPAUGE_HVR2200_4: case SAA7164_BOARD_HAUPPAUGE_HVR2250: case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: @@ -549,6 +614,7 @@ void saa7164_card_setup(struct saa7164_dev *dev) case SAA7164_BOARD_HAUPPAUGE_HVR2200: case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: + case SAA7164_BOARD_HAUPPAUGE_HVR2200_4: case SAA7164_BOARD_HAUPPAUGE_HVR2250: case SAA7164_BOARD_HAUPPAUGE_HVR2250_2: case SAA7164_BOARD_HAUPPAUGE_HVR2250_3: diff --git a/drivers/media/video/saa7164/saa7164-dvb.c b/drivers/media/video/saa7164/saa7164-dvb.c index f65eab63ca8..d3779379197 100644 --- a/drivers/media/video/saa7164/saa7164-dvb.c +++ b/drivers/media/video/saa7164/saa7164-dvb.c @@ -475,6 +475,7 @@ int saa7164_dvb_register(struct saa7164_port *port) case SAA7164_BOARD_HAUPPAUGE_HVR2200: case SAA7164_BOARD_HAUPPAUGE_HVR2200_2: case SAA7164_BOARD_HAUPPAUGE_HVR2200_3: + case SAA7164_BOARD_HAUPPAUGE_HVR2200_4: i2c_bus = &dev->i2c_bus[port->nr + 1]; switch (port->nr) { case 0: diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h index 16745d2fb34..13bd27e9bd1 100644 --- a/drivers/media/video/saa7164/saa7164.h +++ b/drivers/media/video/saa7164/saa7164.h @@ -83,6 +83,7 @@ #define SAA7164_BOARD_HAUPPAUGE_HVR2200_3 6 #define SAA7164_BOARD_HAUPPAUGE_HVR2250_2 7 #define SAA7164_BOARD_HAUPPAUGE_HVR2250_3 8 +#define SAA7164_BOARD_HAUPPAUGE_HVR2200_4 9 #define SAA7164_MAX_UNITS 8 #define SAA7164_TS_NUMBER_OF_LINES 312 From 6e99164ee37d513fb99c7b941e3eecbcd8ae8573 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 26 Jul 2011 16:53:06 -0400 Subject: [PATCH 0297/4025] drm/i915/pch: Save/restore PCH_PORT_HOTPLUG across suspend commit cda2bb78c24de7674eafa3210314dc75bed344a6 upstream. At least on a Lenovo X220 the HPD bits of this are enabled at boot but cleared after resume, which means plug interrupts stop working. This also happens to fix DP displays re-lighting on resume. I'm quite certain that's an accident: the first DP link train inevitably fails on that machine, and it's only serendipity that we're getting multiple plug interrupts and the second train works. But I shall take my victories where I get them. Signed-off-by: Adam Jackson Tested-by: Keith Packard Reviewed-by: Keith Packard Signed-off-by: Keith Packard Cc: Jonathan Nieder Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_suspend.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ce7914c4c04..e0d0e278f62 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -541,6 +541,7 @@ typedef struct drm_i915_private { u32 savePIPEB_LINK_M1; u32 savePIPEB_LINK_N1; u32 saveMCHBAR_RENDER_STANDBY; + u32 savePCH_PORT_HOTPLUG; struct { /** Bridge to intel-gtt-ko */ diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 5257cfc34c3..27693c05c6d 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -814,6 +814,7 @@ int i915_save_state(struct drm_device *dev) dev_priv->saveFDI_RXB_IMR = I915_READ(_FDI_RXB_IMR); dev_priv->saveMCHBAR_RENDER_STANDBY = I915_READ(RSTDBYCTL); + dev_priv->savePCH_PORT_HOTPLUG = I915_READ(PCH_PORT_HOTPLUG); } else { dev_priv->saveIER = I915_READ(IER); dev_priv->saveIMR = I915_READ(IMR); @@ -865,6 +866,7 @@ int i915_restore_state(struct drm_device *dev) I915_WRITE(GTIMR, dev_priv->saveGTIMR); I915_WRITE(_FDI_RXA_IMR, dev_priv->saveFDI_RXA_IMR); I915_WRITE(_FDI_RXB_IMR, dev_priv->saveFDI_RXB_IMR); + I915_WRITE(PCH_PORT_HOTPLUG, dev_priv->savePCH_PORT_HOTPLUG); } else { I915_WRITE(IER, dev_priv->saveIER); I915_WRITE(IMR, dev_priv->saveIMR); From a633bc89bb5626c6d700c3fc5c3bee01da79ce47 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Mon, 7 Nov 2011 18:05:53 +0100 Subject: [PATCH 0298/4025] ARM: 7150/1: Allow kernel unaligned accesses on ARMv6+ processors commit 8428e84d42179c2a00f5f6450866e70d802d1d05 upstream. Recent gcc versions generate unaligned accesses by default on ARMv6 and later processors. This patch ensures that the SCTLR.A bit is always cleared on such processors to avoid kernel traping before alignment_init() is called. Signed-off-by: Catalin Marinas Tested-by: John Linn Acked-by: Nicolas Pitre Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/head.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S index 278c1b0ebb2..673151c7f54 100644 --- a/arch/arm/kernel/head.S +++ b/arch/arm/kernel/head.S @@ -348,7 +348,7 @@ __secondary_data: * r13 = *virtual* address to jump to upon completion */ __enable_mmu: -#ifdef CONFIG_ALIGNMENT_TRAP +#if defined(CONFIG_ALIGNMENT_TRAP) && __LINUX_ARM_ARCH__ < 6 orr r0, r0, #CR_A #else bic r0, r0, #CR_A From 78724db116c88705db2d6acbe66c56bed90fc991 Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Sun, 13 Nov 2011 22:14:32 +0100 Subject: [PATCH 0299/4025] Net, libertas: Resolve memory leak in if_spi_host_to_card() commit fe09b32a4361bea44169b2063e8c867cabb6a8ba upstream. If we hit the default case in the switch in if_spi_host_to_card() we'll leak the memory we allocated for 'packet'. This patch resolves the leak by freeing the allocated memory in that case. Signed-off-by: Jesper Juhl Acked-by: Dan Williams Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/libertas/if_spi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 463352c890d..db39742db3a 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -997,6 +997,7 @@ static int if_spi_host_to_card(struct lbs_private *priv, spin_unlock_irqrestore(&card->buffer_lock, flags); break; default: + kfree(packet); netdev_err(priv->dev, "can't transfer buffer of type %d\n", type); err = -EINVAL; From 11885cd854b27c1dcf35ab44d4899e8d20e08290 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Sat, 12 Nov 2011 19:10:44 +0100 Subject: [PATCH 0300/4025] rt2x00: Fix sleep-while-atomic bug in powersaving code. commit ed66ba472a742cd8df37d7072804b2111cdb1014 upstream. The generic powersaving code that determines after reception of a frame whether the device should go back to sleep or whether is could stay awake was calling rt2x00lib_config directly from RX tasklet context. On a number of the devices this call can actually sleep, due to having to confirm that the sleeping commands have been executed successfully. Fix this by moving the call to rt2x00lib_config to a workqueue call. This fixes bug https://bugzilla.redhat.com/show_bug.cgi?id=731672 Tested-by: Tomas Trnka Signed-off-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2x00.h | 1 + drivers/net/wireless/rt2x00/rt2x00dev.c | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index c446db69bd3..8c822113b08 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -922,6 +922,7 @@ struct rt2x00_dev { * Powersaving work */ struct delayed_work autowakeup_work; + struct work_struct sleep_work; /* * Data queue arrays for RX, TX, Beacon and ATIM. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 939821b4af2..dffaa8f45f1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -449,6 +449,23 @@ static u8 *rt2x00lib_find_ie(u8 *data, unsigned int len, u8 ie) return NULL; } +static void rt2x00lib_sleep(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, sleep_work); + + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return; + + /* + * Check again is powersaving is enabled, to prevent races from delayed + * work execution. + */ + if (!test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) + rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, + IEEE80211_CONF_CHANGE_PS); +} + static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, struct rxdone_entry_desc *rxdesc) @@ -496,8 +513,7 @@ static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, cam |= (tim_ie->bitmap_ctrl & 0x01); if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) - rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, - IEEE80211_CONF_CHANGE_PS); + queue_work(rt2x00dev->workqueue, &rt2x00dev->sleep_work); } static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, @@ -1108,6 +1124,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup); + INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep); /* * Let the driver probe the device to detect the capabilities. @@ -1164,6 +1181,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) */ cancel_work_sync(&rt2x00dev->intf_work); cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); + cancel_work_sync(&rt2x00dev->sleep_work); if (rt2x00_is_usb(rt2x00dev)) { del_timer_sync(&rt2x00dev->txstatus_timer); cancel_work_sync(&rt2x00dev->rxdone_work); From 492d7eff2def54c6e5521ee82764ca22025e7030 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 8 Nov 2011 12:28:33 +0100 Subject: [PATCH 0301/4025] mac80211: fix NULL dereference in radiotap code commit f8d1ccf15568268c76f913b45ecdd33134387f1a upstream. When receiving failed PLCP frames is enabled, there won't be a rate pointer when we add the radiotap header and thus the kernel will crash. Fix this by not assuming the rate pointer is always valid. It's still always valid for frames that have good PLCP though, and that is checked & enforced. This was broken by my commit fc88518916793af8ad6a02e05ff254d95c36d875 Author: Johannes Berg Date: Fri Jul 30 13:23:12 2010 +0200 mac80211: don't check rates on PLCP error frames where I removed the check in this case but didn't take into account that the rate info would be used. Reported-by: Xiaokang Qin Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/rx.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 7fa8c6be7bf..378bd67334b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -140,8 +140,9 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, pos++; /* IEEE80211_RADIOTAP_RATE */ - if (status->flag & RX_FLAG_HT) { + if (!rate || status->flag & RX_FLAG_HT) { /* + * Without rate information don't add it. If we have, * MCS information is a separate field in radiotap, * added below. The byte here is needed as padding * for the channel though, so initialise it to 0. @@ -162,12 +163,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, else if (status->flag & RX_FLAG_HT) put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ, pos); - else if (rate->flags & IEEE80211_RATE_ERP_G) + else if (rate && rate->flags & IEEE80211_RATE_ERP_G) put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, pos); - else + else if (rate) put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, pos); + else + put_unaligned_le16(IEEE80211_CHAN_2GHZ, pos); pos += 2; /* IEEE80211_RADIOTAP_DBM_ANTSIGNAL */ From ae1e9df381d5197015356e22de9d7acaf646a9ab Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 8 Nov 2011 13:04:41 +0100 Subject: [PATCH 0302/4025] mac80211: fix bug in ieee80211_build_probe_req commit 5b2bbf75a24d6b06afff6de0eb4819413fd81971 upstream. ieee80211_probereq_get() can return NULL in which case we should clean up & return NULL in ieee80211_build_probe_req() as well. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/util.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index d3fe2d23748..2124db8e72b 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1047,6 +1047,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, skb = ieee80211_probereq_get(&local->hw, &sdata->vif, ssid, ssid_len, buf, buf_len); + if (!skb) + goto out; if (dst) { mgmt = (struct ieee80211_mgmt *) skb->data; @@ -1055,6 +1057,8 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata, } IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + + out: kfree(buf); return skb; From c1ce1705eb0778927a0b81a6eb29e8ff193aa3de Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 3 Nov 2011 09:27:01 +0100 Subject: [PATCH 0303/4025] nl80211: fix HT capability attribute validation commit 6c7394197af90f6a332180e33f5d025d3037d883 upstream. Since the NL80211_ATTR_HT_CAPABILITY attribute is used as a struct, it needs a minimum, not maximum length. Enforce that properly. Not doing so could potentially lead to reading after the buffer. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/wireless/nl80211.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1ac9443b526..3dac76f33b9 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -126,8 +126,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED }, [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG }, - [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, - .len = NL80211_HT_CAPABILITY_LEN }, + [NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN }, [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 }, [NL80211_ATTR_IE] = { .type = NLA_BINARY, From 5c02e3ae0a16cfc2fb86549cca9898ead2b0d666 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 8 Nov 2011 14:28:06 -0800 Subject: [PATCH 0304/4025] cfg80211: fix bug on regulatory core exit on access to last_request commit 58ebacc66bd11be2327edcefc79de94bd6f5bb4a upstream. Commit 4d9d88d1 by Scott James Remnant added the .uevent() callback for the regulatory device used during the platform device registration. The change was done to account for queuing up udev change requests through udevadm triggers. The change also meant that upon regulatory core exit we will now send a uevent() but the uevent() callback, reg_device_uevent(), also accessed last_request. Right before commiting device suicide we free'd last_request but never set it to NULL so platform_device_unregister() would lead to bogus kernel paging request. Fix this and also simply supress uevents right before we commit suicide as they are pointless. This fix is required for kernels >= v2.6.39 $ git describe --contains 4d9d88d1 v2.6.39-rc1~468^2~25^2^2~21 The impact of not having this present is that a bogus paging access may occur (only read) upon cfg80211 unload time. You may also get this BUG complaint below. Although Johannes could not reproduce the issue this fix is theoretically correct. mac80211_hwsim: unregister radios mac80211_hwsim: closing netlink BUG: unable to handle kernel paging request at ffff88001a06b5ab IP: [] reg_device_uevent+0x1a/0x50 [cfg80211] PGD 1836063 PUD 183a063 PMD 1ffcb067 PTE 1a06b160 Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC CPU 0 Modules linked in: cfg80211(-) [last unloaded: mac80211] Pid: 2279, comm: rmmod Tainted: G W 3.1.0-wl+ #663 Bochs Bochs RIP: 0010:[] [] reg_device_uevent+0x1a/0x50 [cfg80211] RSP: 0000:ffff88001c5f9d58 EFLAGS: 00010286 RAX: 0000000000000000 RBX: ffff88001d2eda88 RCX: ffff88001c7468fc RDX: ffff88001a06b5a0 RSI: ffff88001c7467b0 RDI: ffff88001c7467b0 RBP: ffff88001c5f9d58 R08: 000000000000ffff R09: 000000000000ffff R10: 0000000000000000 R11: 0000000000000001 R12: ffff88001c7467b0 R13: ffff88001d2eda78 R14: ffffffff8164a840 R15: 0000000000000001 FS: 00007f8a91d8a6e0(0000) GS:ffff88001fc00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: ffff88001a06b5ab CR3: 000000001c62e000 CR4: 00000000000006f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process rmmod (pid: 2279, threadinfo ffff88001c5f8000, task ffff88000023c780) Stack: ffff88001c5f9d98 ffffffff812ff7e5 ffffffff8176ab3d ffff88001c7468c2 000000000000ffff ffff88001d2eda88 ffff88001c7467b0 ffff880000114820 ffff88001c5f9e38 ffffffff81241dc7 ffff88001c5f9db8 ffffffff81040189 Call Trace: [] dev_uevent+0xc5/0x170 [] kobject_uevent_env+0x1f7/0x490 [] ? sub_preempt_count+0x29/0x60 [] ? _raw_spin_unlock_irqrestore+0x4a/0x90 [] ? devres_release_all+0x27/0x60 [] kobject_uevent+0xb/0x10 [] device_del+0x157/0x1b0 [] platform_device_del+0x1d/0x90 [] platform_device_unregister+0x16/0x30 [] regulatory_exit+0x5d/0x180 [cfg80211] [] cfg80211_exit+0x2b/0x45 [cfg80211] [] sys_delete_module+0x16c/0x220 [] ? trace_hardirqs_on_caller+0x7e/0x120 [] system_call_fastpath+0x16/0x1b Code: RIP [] reg_device_uevent+0x1a/0x50 [cfg80211] RSP CR2: ffff88001a06b5ab ---[ end trace 147c5099a411e8c0 ]--- Reported-by: Johannes Berg Cc: Scott James Remnant Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/wireless/reg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 379574c30ad..213103e3f99 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2254,6 +2254,9 @@ void /* __init_or_exit */ regulatory_exit(void) kfree(last_request); + last_request = NULL; + dev_set_uevent_suppress(®_pdev->dev, true); + platform_device_unregister(reg_pdev); spin_lock_bh(®_pending_beacons_lock); From d11d8cff78f91d5b956975b5c9e4c271e15f864e Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Thu, 10 Nov 2011 15:10:23 +0000 Subject: [PATCH 0305/4025] ip6_tunnel: copy parms.name after register_netdevice commit 731abb9cb27aef6013ce60808a04e04a545f3f4e upstream. Commit 1c5cae815d removed an explicit call to dev_alloc_name in ip6_tnl_create because register_netdevice will now create a valid name. This works for the net_device itself. However the tunnel keeps a copy of the name in the parms structure for the ip6_tnl associated with the tunnel. parms.name is set by copying the net_device name in ip6_tnl_dev_init_gen. That function is called from ip6_tnl_dev_init in ip6_tnl_create, but it is done before register_netdevice is called so the name is set to a bogus value in the parms.name structure. This shows up if you do a simple tunnel add, followed by a tunnel show: [root@localhost ~]# ip -6 tunnel add remote fec0::100 local fec0::200 [root@localhost ~]# ip -6 tunnel show ip6tnl0: ipv6/ipv6 remote :: local :: encaplimit 0 hoplimit 0 tclass 0x00 flowlabel 0x00000 (flowinfo 0x00000000) ip6tnl%d: ipv6/ipv6 remote fec0::100 local fec0::200 encaplimit 4 hoplimit 64 tclass 0x00 flowlabel 0x00000 (flowinfo 0x00000000) [root@localhost ~]# Fix this by moving the strcpy out of ip6_tnl_dev_init_gen, and calling it after register_netdevice has successfully returned. Signed-off-by: Josh Boyer Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_tunnel.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 36c2842a86b..848e494fa3c 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -289,6 +289,8 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p) if ((err = register_netdevice(dev)) < 0) goto failed_free; + strcpy(t->parms.name, dev->name); + dev_hold(dev); ip6_tnl_link(ip6n, t); return t; @@ -1397,7 +1399,6 @@ ip6_tnl_dev_init_gen(struct net_device *dev) struct ip6_tnl *t = netdev_priv(dev); t->dev = dev; - strcpy(t->parms.name, dev->name); dev->tstats = alloc_percpu(struct pcpu_tstats); if (!dev->tstats) return -ENOMEM; @@ -1477,6 +1478,7 @@ static void __net_exit ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) static int __net_init ip6_tnl_init_net(struct net *net) { struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + struct ip6_tnl *t = NULL; int err; ip6n->tnls[0] = ip6n->tnls_wc; @@ -1497,6 +1499,10 @@ static int __net_init ip6_tnl_init_net(struct net *net) err = register_netdev(ip6n->fb_tnl_dev); if (err < 0) goto err_register; + + t = netdev_priv(ip6n->fb_tnl_dev); + + strcpy(t->parms.name, ip6n->fb_tnl_dev->name); return 0; err_register: From 4fed2211f1f82bcf36f5b41942dfc453e85eac60 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Tue, 15 Nov 2011 21:52:29 +0100 Subject: [PATCH 0306/4025] PM / driver core: disable device's runtime PM during shutdown commit af8db1508f2c9f3b6e633e2d2d906c6557c617f9 upstream. There may be an issue when the user issue "reboot/shutdown" command, then the device has shut down its hardware, after that, this runtime-pm featured device's driver will probably be scheduled to do its suspend routine, and at its suspend routine, it may access hardware, but the device has already shutdown physically, then the system hang may be occurred. I ran out this issue using an auto-suspend supported USB devices, like 3G modem, keyboard. The usb runtime suspend routine may be scheduled after the usb controller has been shut down, and the usb runtime suspend routine will try to suspend its roothub(controller), it will access register, then the system hang occurs as the controller is shutdown. Signed-off-by: Peter Chen Acked-by: Ming Lei Acked-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/base/core.c b/drivers/base/core.c index bc8729d603a..78445f40c43 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "base.h" #include "power/power.h" @@ -1742,6 +1743,8 @@ void device_shutdown(void) */ list_del_init(&dev->kobj.entry); spin_unlock(&devices_kset->list_lock); + /* Disable all device's runtime power management */ + pm_runtime_disable(dev); if (dev->bus && dev->bus->shutdown) { dev_dbg(dev, "shutdown\n"); From 3be76a63e71aa11a614415426b30df3b171089e0 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Fri, 28 Oct 2011 09:33:13 +0900 Subject: [PATCH 0307/4025] pch_phub: Support new device LAPIS Semiconductor ML7831 IOH commit 584ad00ce4bfe594e4c4a89944b3c635187a1ca1 upstream. ML7831 is companion chip for Intel Atom E6xx series. Signed-off-by: Tomoya MORINAGA Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Kconfig | 15 ++++++++------- drivers/misc/pch_phub.c | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 3546474428f..56c05efa027 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -471,7 +471,7 @@ config BMP085 module will be called bmp085. config PCH_PHUB - tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223) PHUB" + tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB" depends on PCI help This driver is for PCH(Platform controller Hub) PHUB(Packet Hub) of @@ -479,12 +479,13 @@ config PCH_PHUB processor. The Topcliff has MAC address and Option ROM data in SROM. This driver can access MAC address and Option ROM data in SROM. - This driver also can be used for OKI SEMICONDUCTOR IOH(Input/ - Output Hub), ML7213 and ML7223. - ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is - for MP(Media Phone) use. - ML7213/ML7223 is companion chip for Intel Atom E6xx series. - ML7213/ML7223 is completely compatible for Intel EG20T PCH. + This driver also can be used for LAPIS Semiconductor's IOH, + ML7213/ML7223/ML7831. + ML7213 which is for IVI(In-Vehicle Infotainment) use. + ML7223 IOH is for MP(Media Phone) use. + ML7831 IOH is for general purpose use. + ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. + ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. To compile this driver as a module, choose M here: the module will be called pch_phub. diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index 5fe79df4483..7c70e7540fb 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c @@ -73,6 +73,9 @@ #define PCI_DEVICE_ID_ROHM_ML7223_mPHUB 0x8012 /* for Bus-m */ #define PCI_DEVICE_ID_ROHM_ML7223_nPHUB 0x8002 /* for Bus-n */ +/* Macros for ML7831 */ +#define PCI_DEVICE_ID_ROHM_ML7831_PHUB 0x8801 + /* SROM ACCESS Macro */ #define PCH_WORD_ADDR_MASK (~((1 << 2) - 1)) @@ -754,6 +757,22 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev, chip->pch_opt_rom_start_address =\ PCH_PHUB_ROM_START_ADDR_ML7223; chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_ML7223; + } else if (id->driver_data == 5) { /* ML7831 */ + retval = sysfs_create_file(&pdev->dev.kobj, + &dev_attr_pch_mac.attr); + if (retval) + goto err_sysfs_create; + + retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr); + if (retval) + goto exit_bin_attr; + + /* set the prefech value */ + iowrite32(0x000affaa, chip->pch_phub_base_address + 0x14); + /* set the interrupt delay value */ + iowrite32(0x25, chip->pch_phub_base_address + 0x44); + chip->pch_opt_rom_start_address = PCH_PHUB_ROM_START_ADDR_EG20T; + chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_EG20T; } chip->ioh_type = id->driver_data; @@ -838,6 +857,7 @@ static struct pci_device_id pch_phub_pcidev_id[] = { { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7213_PHUB), 2, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_mPHUB), 3, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_nPHUB), 4, }, + { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7831_PHUB), 5, }, { } }; MODULE_DEVICE_TABLE(pci, pch_phub_pcidev_id); From dbe52bb9fc1e9bf2efd515cc9fab874e8da59de1 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Fri, 11 Nov 2011 10:12:18 +0900 Subject: [PATCH 0308/4025] pch_phub: Fix MAC address writing issue for LAPIS ML7831 commit 2a9887919457c6e1bd482e8448223be59d19010a upstream. ISSUE: Using ML7831, MAC address writing doesn't work well. CAUSE: ML7831 and EG20T have the same register map for MAC address access. However, this driver processes the writing the same as ML7223. This is not true. This driver must process the writing the same as EG20T. This patch fixes the issue. Signed-off-by: Tomoya MORINAGA Cc: Masayuki Ohtak Cc: Alexander Stein Cc: Denis Turischev Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pch_phub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index 7c70e7540fb..97e1a1f18a9 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c @@ -467,7 +467,7 @@ static int pch_phub_write_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) int retval; int i; - if (chip->ioh_type == 1) /* EG20T */ + if ((chip->ioh_type == 1) || (chip->ioh_type == 5)) /* EG20T or ML7831*/ retval = pch_phub_gbe_serial_rom_conf(chip); else /* ML7223 */ retval = pch_phub_gbe_serial_rom_conf_mp(chip); From 3f04930ad551f504006e35ba5b6d6f717406638c Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Thu, 27 Oct 2011 15:45:18 +0900 Subject: [PATCH 0309/4025] pch_uart: Fix hw-flow control issue commit a1d7cfe29f13cf45f8094929864b9c66bf0cd91b upstream. Using hardware flow control, currently, register of the control-bit(AFE) is not set. This patch fixes the issue. Signed-off-by: Tomoya MORINAGA Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 46521093089..df72c2c0717 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1277,6 +1277,7 @@ static void pch_uart_set_termios(struct uart_port *port, if (rtn) goto out; + pch_uart_set_mctrl(&priv->port, priv->port.mctrl); /* Don't rewrite B0 */ if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); From b74d0a317e75a602085cf73428bfe7ad456aee85 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Fri, 11 Nov 2011 10:55:27 +0900 Subject: [PATCH 0310/4025] pch_uart: Fix DMA resource leak issue commit 90f04c2926cfb5bf74533b0a7766bc896f6a0c0e upstream. Changing UART mode PIO->DMA->PIO->DMA like below, pch_uart driver can't get DMA channel resource. setserial /dev/ttyPCH0 ^low_latency setserial /dev/ttyPCH0 low_latency CAUSE: Changing mode using setserial command, ".startup" function which gets DMA channel is called before ".verify_port" function which sets dma-flag(use_dma/use_dma_flag) as 1. PIO->DMA .startup: Since dma-flag is 0, DMA channel is not requested. .verify_port: dma-flag is set as 1. .shutdown: N/A DMA->PIO .startup: Since dma-flag is 1, DMA channel is requested. .verify_port: dma-flag is set as 0. .shutdown: Since dma-flag is 0, DMA channel is not released. This means DMA channel resource leak occurs. Next time, this driver can't get DMA channel resource forever. MODIFICATION: Currently, when release DMA channel resource, this driver checks dma-flag. However, this specification occurs the above issue. This driver must check whether dma_request_channel is executed or not. The values are saved in private data variable "chan_tx/chan_tx". These variables mean if the value is NULL, DMA channel is not requested, if not NULL, DMA channel is requested. This patch fixes the issue. Signed-off-by: Tomoya MORINAGA Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index df72c2c0717..f8c4ff6ffc9 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -625,6 +625,7 @@ static void pch_request_dma(struct uart_port *port) dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Rx)\n", __func__); dma_release_channel(priv->chan_tx); + priv->chan_tx = NULL; return; } @@ -1212,8 +1213,7 @@ static void pch_uart_shutdown(struct uart_port *port) dev_err(priv->port.dev, "pch_uart_hal_set_fifo Failed(ret=%d)\n", ret); - if (priv->use_dma_flag) - pch_free_dma(port); + pch_free_dma(port); free_irq(priv->port.irq, priv); } From 6e6d3ebc5179779d72837ff38749843506fd6f7f Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Fri, 28 Oct 2011 09:38:49 +0900 Subject: [PATCH 0311/4025] pch_uart: Support new device LAPIS Semiconductor ML7831 IOH commit 8249f743f732ccbc3056428945ab1d9bd36d46bf upstream. ML7831 is companion chip for Intel Atom E6xx series. Signed-off-by: Tomoya MORINAGA Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 14 +++++++------- drivers/tty/serial/pch_uart.c | 8 ++++++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index b3692e6e3c1..9789293a844 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1585,7 +1585,7 @@ config SERIAL_IFX6X60 Support for the IFX6x60 modem devices on Intel MID platforms. config SERIAL_PCH_UART - tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223) UART" + tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART" depends on PCI select SERIAL_CORE help @@ -1593,12 +1593,12 @@ config SERIAL_PCH_UART which is an IOH(Input/Output Hub) for x86 embedded processor. Enabling PCH_DMA, this PCH UART works as DMA mode. - This driver also can be used for OKI SEMICONDUCTOR IOH(Input/ - Output Hub), ML7213 and ML7223. - ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is - for MP(Media Phone) use. - ML7213/ML7223 is companion chip for Intel Atom E6xx series. - ML7213/ML7223 is completely compatible for Intel EG20T PCH. + This driver also can be used for LAPIS Semiconductor IOH(Input/ + Output Hub), ML7213, ML7223 and ML7831. + ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is + for MP(Media Phone) use and ML7831 IOH is for general purpose use. + ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. + ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. config SERIAL_MSM_SMD bool "Enable tty device interface for some SMD ports" diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index f8c4ff6ffc9..902588b2a12 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -256,6 +256,8 @@ enum pch_uart_num_t { pch_ml7213_uart2, pch_ml7223_uart0, pch_ml7223_uart1, + pch_ml7831_uart0, + pch_ml7831_uart1, }; static struct pch_uart_driver_data drv_dat[] = { @@ -268,6 +270,8 @@ static struct pch_uart_driver_data drv_dat[] = { [pch_ml7213_uart2] = {PCH_UART_2LINE, 2}, [pch_ml7223_uart0] = {PCH_UART_8LINE, 0}, [pch_ml7223_uart1] = {PCH_UART_2LINE, 1}, + [pch_ml7831_uart0] = {PCH_UART_8LINE, 0}, + [pch_ml7831_uart1] = {PCH_UART_2LINE, 1}, }; static unsigned int default_baud = 9600; @@ -1546,6 +1550,10 @@ static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = { .driver_data = pch_ml7223_uart0}, {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x800D), .driver_data = pch_ml7223_uart1}, + {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8811), + .driver_data = pch_ml7831_uart0}, + {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8812), + .driver_data = pch_ml7831_uart1}, {0,}, }; From 5e3092bd68b8ed5d17ece466ba98e02f4ad035ec Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 25 Oct 2011 19:19:43 -0700 Subject: [PATCH 0312/4025] tty: hvc_dcc: Fix duplicate character inputs commit c2a3e84f950e7ddba1f3914b005861d46ae60359 upstream. Reading from the DCC grabs a character from the buffer and clears the status bit. Since this is a context-changing operation, instructions following the character read that rely on the status bit being accurate need to be synchronized with an ISB. In this case, the status bit check needs to execute after the character read otherwise we run the risk of reading the character and checking the status bit before the read can clear the status bit in the first place. When this happens, the user will see the same character they typed twice, instead of once. Add an ISB after the read and the write, so that the status check is synchronized with the read/write operations. Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_dcc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/hvc/hvc_dcc.c b/drivers/tty/hvc/hvc_dcc.c index 435f6facbc2..44fbebab507 100644 --- a/drivers/tty/hvc/hvc_dcc.c +++ b/drivers/tty/hvc/hvc_dcc.c @@ -46,6 +46,7 @@ static inline char __dcc_getchar(void) asm volatile("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg" : "=r" (__c)); + isb(); return __c; } @@ -55,6 +56,7 @@ static inline void __dcc_putchar(char c) asm volatile("mcr p14, 0, %0, c0, c5, 0 @ write a char" : /* no output register */ : "r" (c)); + isb(); } static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count) From f8b8a240e2879d9680238e27953cdc0c7f88131f Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 16 Nov 2011 16:27:07 +0100 Subject: [PATCH 0313/4025] TTY: ldisc, allow waiting for ldisc arbitrarily long commit df92d0561de364de53c42abc5d43e04ab6f326a5 upstream. To fix a nasty bug in ldisc hup vs. reinit we need to wait infinitely long for ldisc to be gone. So here we add a parameter to tty_ldisc_wait_idle to allow that. This is only a preparation for the real fix which is done in the following patches. Signed-off-by: Jiri Slaby Cc: Dave Young Cc: Dave Jones Cc: Ben Hutchings Cc: Dmitriy Matrosov Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ldisc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index ef925d58171..363d5689a84 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -548,15 +548,16 @@ static void tty_ldisc_flush_works(struct tty_struct *tty) /** * tty_ldisc_wait_idle - wait for the ldisc to become idle * @tty: tty to wait for + * @timeout: for how long to wait at most * * Wait for the line discipline to become idle. The discipline must * have been halted for this to guarantee it remains idle. */ -static int tty_ldisc_wait_idle(struct tty_struct *tty) +static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout) { - int ret; + long ret; ret = wait_event_timeout(tty_ldisc_idle, - atomic_read(&tty->ldisc->users) == 1, 5 * HZ); + atomic_read(&tty->ldisc->users) == 1, timeout); if (ret < 0) return ret; return ret > 0 ? 0 : -EBUSY; @@ -666,7 +667,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) tty_ldisc_flush_works(tty); - retval = tty_ldisc_wait_idle(tty); + retval = tty_ldisc_wait_idle(tty, 5 * HZ); tty_lock(); mutex_lock(&tty->ldisc_mutex); @@ -763,7 +764,7 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc) if (IS_ERR(ld)) return -1; - WARN_ON_ONCE(tty_ldisc_wait_idle(tty)); + WARN_ON_ONCE(tty_ldisc_wait_idle(tty, 5 * HZ)); tty_ldisc_close(tty, tty->ldisc); tty_ldisc_put(tty->ldisc); From 57ee681901463f23076fa730c7aa1c4cee63952e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 16 Nov 2011 16:27:08 +0100 Subject: [PATCH 0314/4025] TTY: ldisc, move wait idle to caller commit 300420722e0734a4254f3b634e0f82664495d210 upstream. It is the only place where reinit is called from. And we really need to wait for the old ldisc to go once. Actually this is the place where the waiting originally was (before removed and re-added later). This will make the fix in the following patch easier to implement. Signed-off-by: Jiri Slaby Cc: Dave Young Cc: Dave Jones Cc: Ben Hutchings Cc: Dmitriy Matrosov Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ldisc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 363d5689a84..ba59b0a1fe4 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -764,8 +764,6 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc) if (IS_ERR(ld)) return -1; - WARN_ON_ONCE(tty_ldisc_wait_idle(tty, 5 * HZ)); - tty_ldisc_close(tty, tty->ldisc); tty_ldisc_put(tty->ldisc); tty->ldisc = NULL; @@ -849,6 +847,8 @@ void tty_ldisc_hangup(struct tty_struct *tty) it means auditing a lot of other paths so this is a FIXME */ if (tty->ldisc) { /* Not yet closed */ + WARN_ON_ONCE(tty_ldisc_wait_idle(tty, 5 * HZ)); + if (reset == 0) { if (!tty_ldisc_reinit(tty, tty->termios->c_line)) From ecaaa92488e2589cc6b0a409ce44e7e47a3bb846 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Wed, 16 Nov 2011 16:27:09 +0100 Subject: [PATCH 0315/4025] TTY: ldisc, wait for ldisc infinitely in hangup commit 0c73c08ec73dbe080b9ec56696ee21d32754d918 upstream. For /dev/console case, we do not kill all ldisc users. It's due to redirected_tty_write test in __tty_hangup. In that case there still might be a process waiting e.g. in n_tty_read for input. We wait for such processes to disappear. The problem is that we use a timeout. After this timeout, we continue closing the ldisc and start freeing tty resources. It obviously leads to crashes when the other process is woken. So to fix this, we wait infinitely before reiniting the ldisc. (The tiocsetd remains untouched -- times out after 5s.) This is nicely reproducible with this run from shell: exec 0<>/dev/console 1<>/dev/console 2<>/dev/console and stopping a getty like: systemctl stop serial-getty@ttyS0.service The crash proper may be produced only under load or with constified timing the same as for 92f6fa09b. Signed-off-by: Jiri Slaby Cc: Dave Young Cc: Dave Jones Cc: Ben Hutchings Cc: Dmitriy Matrosov Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_ldisc.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index ba59b0a1fe4..a76c808afad 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -36,6 +36,7 @@ #include #include +#include /* * This guards the refcounted line discipline lists. The lock @@ -838,7 +839,7 @@ void tty_ldisc_hangup(struct tty_struct *tty) tty_unlock(); cancel_work_sync(&tty->buf.work); mutex_unlock(&tty->ldisc_mutex); - +retry: tty_lock(); mutex_lock(&tty->ldisc_mutex); @@ -847,7 +848,21 @@ void tty_ldisc_hangup(struct tty_struct *tty) it means auditing a lot of other paths so this is a FIXME */ if (tty->ldisc) { /* Not yet closed */ - WARN_ON_ONCE(tty_ldisc_wait_idle(tty, 5 * HZ)); + if (atomic_read(&tty->ldisc->users) != 1) { + char cur_n[TASK_COMM_LEN], tty_n[64]; + long timeout = 3 * HZ; + tty_unlock(); + + while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { + timeout = MAX_SCHEDULE_TIMEOUT; + printk_ratelimited(KERN_WARNING + "%s: waiting (%s) for %s took too long, but we keep waiting...\n", + __func__, get_task_comm(cur_n, current), + tty_name(tty, tty_n)); + } + mutex_unlock(&tty->ldisc_mutex); + goto retry; + } if (reset == 0) { From 124e35242a58c479cea2a3d6d2b2605737e27309 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 4 Nov 2011 13:31:21 -0400 Subject: [PATCH 0316/4025] nfs: when attempting to open a directory, fall back on normal lookup (try #5) commit 1788ea6e3b2a58cf4fb00206e362d9caff8d86a7 upstream. commit d953126 changed how nfs_atomic_lookup handles an -EISDIR return from an OPEN call. Prior to that patch, that caused the client to fall back to doing a normal lookup. When that patch went in, the code began returning that error to userspace. The d_revalidate codepath however never had the corresponding change, so it was still possible to end up with a NULL ctx->state pointer after that. That patch caused a regression. When we attempt to open a directory that does not have a cached dentry, that open now errors out with EISDIR. If you attempt the same open with a cached dentry, it will succeed. Fix this by reverting the change in nfs_atomic_lookup and allowing attempts to open directories to fall back to a normal lookup Also, add a NFSv4-specific f_ops->open routine that just returns -ENOTDIR. This should never be called if things are working properly, but if it ever is, then the dprintk may help in debugging. To facilitate this, a new file_operations field is also added to the nfs_rpc_ops struct. Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/dir.c | 2 +- fs/nfs/file.c | 32 ++++++++++++++++++++++++++++++++ fs/nfs/inode.c | 2 +- fs/nfs/nfs3proc.c | 1 + fs/nfs/nfs4proc.c | 1 + fs/nfs/proc.c | 1 + include/linux/nfs_fs.h | 3 +++ include/linux/nfs_xdr.h | 1 + 8 files changed, 41 insertions(+), 2 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index f91c62d48ff..462a0060173 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1458,12 +1458,12 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry res = NULL; goto out; /* This turned out not to be a regular file */ + case -EISDIR: case -ENOTDIR: goto no_open; case -ELOOP: if (!(nd->intent.open.flags & O_NOFOLLOW)) goto no_open; - /* case -EISDIR: */ /* case -EINVAL: */ default: res = ERR_CAST(inode); diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 2f093ed1698..dd2f13077be 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -887,3 +887,35 @@ static int nfs_setlease(struct file *file, long arg, struct file_lock **fl) file->f_path.dentry->d_name.name, arg); return -EINVAL; } + +#ifdef CONFIG_NFS_V4 +static int +nfs4_file_open(struct inode *inode, struct file *filp) +{ + /* + * NFSv4 opens are handled in d_lookup and d_revalidate. If we get to + * this point, then something is very wrong + */ + dprintk("NFS: %s called! inode=%p filp=%p\n", __func__, inode, filp); + return -ENOTDIR; +} + +const struct file_operations nfs4_file_operations = { + .llseek = nfs_file_llseek, + .read = do_sync_read, + .write = do_sync_write, + .aio_read = nfs_file_read, + .aio_write = nfs_file_write, + .mmap = nfs_file_mmap, + .open = nfs4_file_open, + .flush = nfs_file_flush, + .release = nfs_file_release, + .fsync = nfs_file_fsync, + .lock = nfs_lock, + .flock = nfs_flock, + .splice_read = nfs_file_splice_read, + .splice_write = nfs_file_splice_write, + .check_flags = nfs_check_flags, + .setlease = nfs_setlease, +}; +#endif /* CONFIG_NFS_V4 */ diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6f4850deb27..c48f9f6ad72 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -291,7 +291,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) */ inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->file_inode_ops; if (S_ISREG(inode->i_mode)) { - inode->i_fop = &nfs_file_operations; + inode->i_fop = NFS_SB(sb)->nfs_client->rpc_ops->file_ops; inode->i_data.a_ops = &nfs_file_aops; inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info; } else if (S_ISDIR(inode->i_mode)) { diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index 38053d823eb..771741f1479 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -853,6 +853,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = { .dentry_ops = &nfs_dentry_operations, .dir_inode_ops = &nfs3_dir_inode_operations, .file_inode_ops = &nfs3_file_inode_operations, + .file_ops = &nfs_file_operations, .getroot = nfs3_proc_get_root, .getattr = nfs3_proc_getattr, .setattr = nfs3_proc_setattr, diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 92cfd2e1131..a2a7d0a8daf 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -6008,6 +6008,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = { .dentry_ops = &nfs4_dentry_operations, .dir_inode_ops = &nfs4_dir_inode_operations, .file_inode_ops = &nfs4_file_inode_operations, + .file_ops = &nfs4_file_operations, .getroot = nfs4_proc_get_root, .getattr = nfs4_proc_getattr, .setattr = nfs4_proc_setattr, diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index ac40b8535d7..f48125da198 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c @@ -710,6 +710,7 @@ const struct nfs_rpc_ops nfs_v2_clientops = { .dentry_ops = &nfs_dentry_operations, .dir_inode_ops = &nfs_dir_inode_operations, .file_inode_ops = &nfs_file_inode_operations, + .file_ops = &nfs_file_operations, .getroot = nfs_proc_get_root, .getattr = nfs_proc_getattr, .setattr = nfs_proc_setattr, diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index b522370fcc2..acdc370086a 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -410,6 +410,9 @@ extern const struct inode_operations nfs_file_inode_operations; extern const struct inode_operations nfs3_file_inode_operations; #endif /* CONFIG_NFS_V3 */ extern const struct file_operations nfs_file_operations; +#ifdef CONFIG_NFS_V4 +extern const struct file_operations nfs4_file_operations; +#endif /* CONFIG_NFS_V4 */ extern const struct address_space_operations nfs_file_aops; extern const struct address_space_operations nfs_dir_aops; diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index be2eba7725a..0012fc3d2c1 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1149,6 +1149,7 @@ struct nfs_rpc_ops { const struct dentry_operations *dentry_ops; const struct inode_operations *dir_inode_ops; const struct inode_operations *file_inode_ops; + const struct file_operations *file_ops; int (*getroot) (struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *); From 0f48082f6606cedf53b8a3beb3ca9e73134b8005 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 31 Oct 2011 10:20:28 +0800 Subject: [PATCH 0317/4025] pcie-gadget-spear: Add "platform:" prefix for platform modalias commit 161f14191dc166c4e3f37f68af1bc199c6868b7d upstream. Since 43cc71eed1250755986da4c0f9898f9a635cb3bf (platform: prefix MODALIAS with "platform:"), the platform modalias is prefixed with "platform:". Signed-off-by: Axel Lin Acked-by: Pratyush Anand Signed-off-by: Greg Kroah-Hartman --- drivers/misc/spear13xx_pcie_gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c index cfbddbef11d..43d073bc1d9 100644 --- a/drivers/misc/spear13xx_pcie_gadget.c +++ b/drivers/misc/spear13xx_pcie_gadget.c @@ -903,6 +903,6 @@ static void __exit spear_pcie_gadget_exit(void) } module_exit(spear_pcie_gadget_exit); -MODULE_ALIAS("pcie-gadget-spear"); +MODULE_ALIAS("platform:pcie-gadget-spear"); MODULE_AUTHOR("Pratyush Anand"); MODULE_LICENSE("GPL"); From f353fc7d4deafe84db514a3acb691fb84c7c69ec Mon Sep 17 00:00:00 2001 From: Claudio Scordino Date: Thu, 17 Nov 2011 11:08:32 +0100 Subject: [PATCH 0318/4025] drivers/base/node.c: fix compilation error with older versions of gcc commit 91a13c281d7d4648c0b32dede11a0144c4e7984c upstream. Patch to fix the error message "directives may not be used inside a macro argument" which appears when the kernel is compiled for the cris architecture. Signed-off-by: Claudio Scordino Acked-by: David Rientjes Signed-off-by: Greg Kroah-Hartman --- drivers/base/node.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/base/node.c b/drivers/base/node.c index 793f796c4da..5693ecee9a4 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -127,12 +127,13 @@ static ssize_t node_read_meminfo(struct sys_device * dev, nid, K(node_page_state(nid, NR_WRITEBACK)), nid, K(node_page_state(nid, NR_FILE_PAGES)), nid, K(node_page_state(nid, NR_FILE_MAPPED)), - nid, K(node_page_state(nid, NR_ANON_PAGES) #ifdef CONFIG_TRANSPARENT_HUGEPAGE + nid, K(node_page_state(nid, NR_ANON_PAGES) + node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) * - HPAGE_PMD_NR + HPAGE_PMD_NR), +#else + nid, K(node_page_state(nid, NR_ANON_PAGES)), #endif - ), nid, K(node_page_state(nid, NR_SHMEM)), nid, node_page_state(nid, NR_KERNEL_STACK) * THREAD_SIZE / 1024, @@ -143,13 +144,14 @@ static ssize_t node_read_meminfo(struct sys_device * dev, nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) + node_page_state(nid, NR_SLAB_UNRECLAIMABLE)), nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)), - nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)) #ifdef CONFIG_TRANSPARENT_HUGEPAGE + nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)) , nid, K(node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) * - HPAGE_PMD_NR) + HPAGE_PMD_NR)); +#else + nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE))); #endif - ); n += hugetlb_report_node_meminfo(nid, buf + n); return n; } From bd8a076ec08b1dab5fe3d7bf5499990a552ff51f Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 3 Nov 2011 13:06:08 -0700 Subject: [PATCH 0319/4025] xhci: Set slot and ep0 flags for address command. commit d31c285b3a71cf9056e6a060de41f37780b0af86 upstream. Matt's AsMedia xHCI host controller was responding with a Context Error to an address device command after a configured device reset. Some sequence of events leads both the slot and endpoint zero add flags cleared to zero, which the AsMedia host doesn't like: [ 223.701839] xhci_hcd 0000:03:00.0: Slot ID 1 Input Context: [ 223.701841] xhci_hcd 0000:03:00.0: @ffff880137b25000 (virt) @ffffc000 (dma) 0x000000 - drop flags [ 223.701843] xhci_hcd 0000:03:00.0: @ffff880137b25004 (virt) @ffffc004 (dma) 0x000000 - add flags [ 223.701846] xhci_hcd 0000:03:00.0: @ffff880137b25008 (virt) @ffffc008 (dma) 0x000000 - rsvd2[0] [ 223.701848] xhci_hcd 0000:03:00.0: @ffff880137b2500c (virt) @ffffc00c (dma) 0x000000 - rsvd2[1] [ 223.701850] xhci_hcd 0000:03:00.0: @ffff880137b25010 (virt) @ffffc010 (dma) 0x000000 - rsvd2[2] [ 223.701852] xhci_hcd 0000:03:00.0: @ffff880137b25014 (virt) @ffffc014 (dma) 0x000000 - rsvd2[3] [ 223.701854] xhci_hcd 0000:03:00.0: @ffff880137b25018 (virt) @ffffc018 (dma) 0x000000 - rsvd2[4] [ 223.701857] xhci_hcd 0000:03:00.0: @ffff880137b2501c (virt) @ffffc01c (dma) 0x000000 - rsvd2[5] [ 223.701858] xhci_hcd 0000:03:00.0: Slot Context: [ 223.701860] xhci_hcd 0000:03:00.0: @ffff880137b25020 (virt) @ffffc020 (dma) 0x8400000 - dev_info [ 223.701862] xhci_hcd 0000:03:00.0: @ffff880137b25024 (virt) @ffffc024 (dma) 0x010000 - dev_info2 [ 223.701864] xhci_hcd 0000:03:00.0: @ffff880137b25028 (virt) @ffffc028 (dma) 0x000000 - tt_info [ 223.701866] xhci_hcd 0000:03:00.0: @ffff880137b2502c (virt) @ffffc02c (dma) 0x000000 - dev_state [ 223.701869] xhci_hcd 0000:03:00.0: @ffff880137b25030 (virt) @ffffc030 (dma) 0x000000 - rsvd[0] [ 223.701871] xhci_hcd 0000:03:00.0: @ffff880137b25034 (virt) @ffffc034 (dma) 0x000000 - rsvd[1] [ 223.701873] xhci_hcd 0000:03:00.0: @ffff880137b25038 (virt) @ffffc038 (dma) 0x000000 - rsvd[2] [ 223.701875] xhci_hcd 0000:03:00.0: @ffff880137b2503c (virt) @ffffc03c (dma) 0x000000 - rsvd[3] [ 223.701877] xhci_hcd 0000:03:00.0: Endpoint 00 Context: [ 223.701879] xhci_hcd 0000:03:00.0: @ffff880137b25040 (virt) @ffffc040 (dma) 0x000000 - ep_info [ 223.701881] xhci_hcd 0000:03:00.0: @ffff880137b25044 (virt) @ffffc044 (dma) 0x2000026 - ep_info2 [ 223.701883] xhci_hcd 0000:03:00.0: @ffff880137b25048 (virt) @ffffc048 (dma) 0xffffe8e0 - deq [ 223.701885] xhci_hcd 0000:03:00.0: @ffff880137b25050 (virt) @ffffc050 (dma) 0x000000 - tx_info [ 223.701887] xhci_hcd 0000:03:00.0: @ffff880137b25054 (virt) @ffffc054 (dma) 0x000000 - rsvd[0] [ 223.701889] xhci_hcd 0000:03:00.0: @ffff880137b25058 (virt) @ffffc058 (dma) 0x000000 - rsvd[1] [ 223.701892] xhci_hcd 0000:03:00.0: @ffff880137b2505c (virt) @ffffc05c (dma) 0x000000 - rsvd[2] ... [ 223.701927] xhci_hcd 0000:03:00.0: // Ding dong! [ 223.701992] xhci_hcd 0000:03:00.0: Setup ERROR: address device command for slot 1. The xHCI spec says that both flags must be set to one for the Address Device command. When the device is first enumerated, xhci_setup_addressable_virt_dev() does set those flags. However, when the device is addressed after it has been reset in the configured state, xhci_setup_addressable_virt_dev() is not called, and xhci_copy_ep0_dequeue_into_input_ctx() is called instead. That function relies on the flags being set up by previous commands, which apparently isn't a good assumption. Move the setting of the flags into the common parent function. This should be queued for stable kernels as old as 2.6.35, since that was the first introduction of xhci_copy_ep0_dequeue_into_input_ctx. Signed-off-by: Sarah Sharp Tested-by: Matt Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 5 ----- drivers/usb/host/xhci.c | 5 ++++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 104620b3764..ffeee575fd2 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -875,7 +875,6 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud struct xhci_virt_device *dev; struct xhci_ep_ctx *ep0_ctx; struct xhci_slot_ctx *slot_ctx; - struct xhci_input_control_ctx *ctrl_ctx; u32 port_num; struct usb_device *top_dev; @@ -887,12 +886,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud return -EINVAL; } ep0_ctx = xhci_get_ep_ctx(xhci, dev->in_ctx, 0); - ctrl_ctx = xhci_get_input_control_ctx(xhci, dev->in_ctx); slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx); - /* 2) New slot context and endpoint 0 context are valid*/ - ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG); - /* 3) Only the control endpoint is valid - one endpoint context */ slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | (u32) udev->route); switch (udev->speed) { diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index fb61e9d8e17..eb31f9e45ba 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2875,6 +2875,10 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) /* Otherwise, update the control endpoint ring enqueue pointer. */ else xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev); + ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); + ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG); + ctrl_ctx->drop_flags = 0; + xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); @@ -2956,7 +2960,6 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK) + 1; /* Zero the input context control for later use */ - ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); ctrl_ctx->add_flags = 0; ctrl_ctx->drop_flags = 0; From 2e6f55fcd95ef6da9e095eb97cb70fe48be13882 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Thu, 3 Nov 2011 09:07:18 -0400 Subject: [PATCH 0320/4025] usb, xhci: Clear warm reset change event during init commit 79c3dd8150fd5236d95766a9e662e3e932b462c9 upstream. I noticed on my Panther Point system that I wasn't getting hotplug events for my usb3.0 disk on a usb3 port. I tracked it down to the fact that the system had the warm reset change bit still set. This seemed to block future events from being received, including a hotplug event. Clearing this bit during initialization allowed the hotplug event to be received and the disk to be recognized correctly. This patch should be backported to kernels as old as 2.6.39. Signed-off-by: Don Zickus Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index a428aa080a3..210e3597091 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -813,6 +813,12 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) USB_PORT_FEAT_C_PORT_LINK_STATE); } + if ((portchange & USB_PORT_STAT_C_BH_RESET) && + hub_is_superspeed(hub->hdev)) { + need_debounce_delay = true; + clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_BH_PORT_RESET); + } /* We can forget about a "removed" device when there's a * physical disconnect or the connect status changes. */ From 614b35af53468f13a41192ffb4ea34f264035b91 Mon Sep 17 00:00:00 2001 From: Don Zickus Date: Thu, 20 Oct 2011 23:52:14 -0400 Subject: [PATCH 0321/4025] usb, xhci: fix lockdep warning on endpoint timeout commit f43d623164022dcbf6750ef220b7a1133a1183eb upstream. While debugging a usb3 problem, I stumbled upon this lockdep warning. Oct 18 21:41:17 dhcp47-74 kernel: ================================= Oct 18 21:41:17 dhcp47-74 kernel: [ INFO: inconsistent lock state ] Oct 18 21:41:17 dhcp47-74 kernel: 3.1.0-rc4nmi+ #456 Oct 18 21:41:17 dhcp47-74 kernel: --------------------------------- Oct 18 21:41:17 dhcp47-74 kernel: inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage. Oct 18 21:41:17 dhcp47-74 kernel: swapper/0 [HC0[0]:SC1[1]:HE1:SE0] takes: Oct 18 21:41:17 dhcp47-74 kernel: (&(&xhci->lock)->rlock){?.-...}, at: [] xhci_stop_endpoint_command_watchdog+0x30/0x340 [xhci_hcd] Oct 18 21:41:17 dhcp47-74 kernel: {IN-HARDIRQ-W} state was registered at: Oct 18 21:41:17 dhcp47-74 kernel: [] __lock_acquire+0x781/0x1660 Oct 18 21:41:17 dhcp47-74 kernel: [] lock_acquire+0x97/0x170 Oct 18 21:41:17 dhcp47-74 kernel: [] _raw_spin_lock+0x46/0x80 Oct 18 21:41:17 dhcp47-74 kernel: [] xhci_irq+0x3a/0x1960 [xhci_hcd] Oct 18 21:41:17 dhcp47-74 kernel: [] xhci_msi_irq+0x31/0x40 [xhci_hcd] Oct 18 21:41:17 dhcp47-74 kernel: [] handle_irq_event_percpu+0x85/0x320 Oct 18 21:41:17 dhcp47-74 kernel: [] handle_irq_event+0x48/0x70 Oct 18 21:41:17 dhcp47-74 kernel: [] handle_edge_irq+0x6d/0x130 Oct 18 21:41:17 dhcp47-74 kernel: [] handle_irq+0x49/0xa0 Oct 18 21:41:17 dhcp47-74 kernel: [] do_IRQ+0x5d/0xe0 Oct 18 21:41:17 dhcp47-74 kernel: [] ret_from_intr+0x0/0x13 Oct 18 21:41:17 dhcp47-74 kernel: [] usb_set_device_state+0x8a/0x180 Oct 18 21:41:17 dhcp47-74 kernel: [] usb_add_hcd+0x2b8/0x730 Oct 18 21:41:17 dhcp47-74 kernel: [] xhci_pci_probe+0x9e/0xd4 [xhci_hcd] Oct 18 21:41:17 dhcp47-74 kernel: [] local_pci_probe+0x5f/0xd0 Oct 18 21:41:17 dhcp47-74 kernel: [] pci_device_probe+0x119/0x120 Oct 18 21:41:17 dhcp47-74 kernel: [] driver_probe_device+0xa3/0x2c0 Oct 18 21:41:17 dhcp47-74 kernel: [] __driver_attach+0xab/0xb0 Oct 18 21:41:17 dhcp47-74 kernel: [] bus_for_each_dev+0x6c/0xa0 Oct 18 21:41:17 dhcp47-74 kernel: [] driver_attach+0x1e/0x20 Oct 18 21:41:17 dhcp47-74 kernel: [] bus_add_driver+0x1f8/0x2b0 Oct 18 21:41:17 dhcp47-74 kernel: [] driver_register+0x76/0x140 Oct 18 21:41:17 dhcp47-74 kernel: [] __pci_register_driver+0x66/0xe0 Oct 18 21:41:17 dhcp47-74 kernel: [] snd_timer_find+0x4a/0x70 [snd_timer] Oct 18 21:41:17 dhcp47-74 kernel: [] snd_timer_find+0xe/0x70 [snd_timer] Oct 18 21:41:17 dhcp47-74 kernel: [] do_one_initcall+0x43/0x180 Oct 18 21:41:17 dhcp47-74 kernel: [] sys_init_module+0x92/0x1f0 Oct 18 21:41:17 dhcp47-74 kernel: [] system_call_fastpath+0x16/0x1b Oct 18 21:41:17 dhcp47-74 kernel: irq event stamp: 631984 Oct 18 21:41:17 dhcp47-74 kernel: hardirqs last enabled at (631984): [] _raw_spin_unlock_irq+0x30/0x50 Oct 18 21:41:17 dhcp47-74 kernel: hardirqs last disabled at (631983): [] _raw_spin_lock_irq+0x19/0x90 Oct 18 21:41:17 dhcp47-74 kernel: softirqs last enabled at (631980): [] _local_bh_enable+0x13/0x20 Oct 18 21:41:17 dhcp47-74 kernel: softirqs last disabled at (631981): [] call_softirq+0x1c/0x30 Oct 18 21:41:17 dhcp47-74 kernel: Oct 18 21:41:17 dhcp47-74 kernel: other info that might help us debug this: Oct 18 21:41:17 dhcp47-74 kernel: Possible unsafe locking scenario: Oct 18 21:41:17 dhcp47-74 kernel: Oct 18 21:41:17 dhcp47-74 kernel: CPU0 Oct 18 21:41:17 dhcp47-74 kernel: ---- Oct 18 21:41:17 dhcp47-74 kernel: lock(&(&xhci->lock)->rlock); Oct 18 21:41:17 dhcp47-74 kernel: Oct 18 21:41:17 dhcp47-74 kernel: lock(&(&xhci->lock)->rlock); Oct 18 21:41:17 dhcp47-74 kernel: Oct 18 21:41:17 dhcp47-74 kernel: *** DEADLOCK *** Oct 18 21:41:17 dhcp47-74 kernel: Oct 18 21:41:17 dhcp47-74 kernel: 1 lock held by swapper/0: Oct 18 21:41:17 dhcp47-74 kernel: #0: (&ep->stop_cmd_timer){+.-...}, at: [] run_timer_softirq+0x162/0x570 Oct 18 21:41:17 dhcp47-74 kernel: Oct 18 21:41:17 dhcp47-74 kernel: stack backtrace: Oct 18 21:41:17 dhcp47-74 kernel: Pid: 0, comm: swapper Tainted: G W 3.1.0-rc4nmi+ #456 Oct 18 21:41:17 dhcp47-74 kernel: Call Trace: Oct 18 21:41:17 dhcp47-74 kernel: [] print_usage_bug+0x227/0x270 Oct 18 21:41:17 dhcp47-74 kernel: [] mark_lock+0x346/0x410 Oct 18 21:41:17 dhcp47-74 kernel: [] __lock_acquire+0x61e/0x1660 Oct 18 21:41:17 dhcp47-74 kernel: [] ? mark_lock+0x213/0x410 Oct 18 21:41:17 dhcp47-74 kernel: [] lock_acquire+0x97/0x170 Oct 18 21:41:17 dhcp47-74 kernel: [] ? xhci_stop_endpoint_command_watchdog+0x30/0x340 [xhci_hcd] Oct 18 21:41:17 dhcp47-74 kernel: [] _raw_spin_lock+0x46/0x80 Oct 18 21:41:17 dhcp47-74 kernel: [] ? xhci_stop_endpoint_command_watchdog+0x30/0x340 [xhci_hcd] Oct 18 21:41:17 dhcp47-74 kernel: [] xhci_stop_endpoint_command_watchdog+0x30/0x340 [xhci_hcd] Oct 18 21:41:17 dhcp47-74 kernel: [] ? run_timer_softirq+0x162/0x570 Oct 18 21:41:17 dhcp47-74 kernel: [] run_timer_softirq+0x20d/0x570 Oct 18 21:41:17 dhcp47-74 kernel: [] ? run_timer_softirq+0x162/0x570 Oct 18 21:41:17 dhcp47-74 kernel: [] ? xhci_queue_isoc_tx_prepare+0x8e0/0x8e0 [xhci_hcd] Oct 18 21:41:17 dhcp47-74 kernel: [] __do_softirq+0xf2/0x3f0 Oct 18 21:41:17 dhcp47-74 kernel: [] ? lapic_next_event+0x1d/0x30 Oct 18 21:41:17 dhcp47-74 kernel: [] ? clockevents_program_event+0x5e/0x90 Oct 18 21:41:17 dhcp47-74 kernel: [] call_softirq+0x1c/0x30 Oct 18 21:41:17 dhcp47-74 kernel: [] do_softirq+0x8d/0xc0 Oct 18 21:41:17 dhcp47-74 kernel: [] irq_exit+0xe5/0x100 Oct 18 21:41:17 dhcp47-74 kernel: [] smp_apic_timer_interrupt+0x6e/0x99 Oct 18 21:41:17 dhcp47-74 kernel: [] apic_timer_interrupt+0x70/0x80 Oct 18 21:41:17 dhcp47-74 kernel: [] ? trace_hardirqs_off+0xd/0x10 Oct 18 21:41:17 dhcp47-74 kernel: [] ? acpi_idle_enter_bm+0x227/0x25b Oct 18 21:41:17 dhcp47-74 kernel: [] ? acpi_idle_enter_bm+0x222/0x25b Oct 18 21:41:17 dhcp47-74 kernel: [] cpuidle_idle_call+0x103/0x290 Oct 18 21:41:17 dhcp47-74 kernel: [] cpu_idle+0xe5/0x160 Oct 18 21:41:17 dhcp47-74 kernel: [] rest_init+0xe0/0xf0 Oct 18 21:41:17 dhcp47-74 kernel: [] ? csum_partial_copy_generic+0x170/0x170 Oct 18 21:41:17 dhcp47-74 kernel: [] start_kernel+0x3fc/0x407 Oct 18 21:41:17 dhcp47-74 kernel: [] x86_64_start_reservations+0x131/0x135 Oct 18 21:41:17 dhcp47-74 kernel: [] x86_64_start_kernel+0xed/0xf4 Oct 18 21:41:17 dhcp47-74 kernel: xhci_hcd 0000:00:14.0: xHCI host not responding to stop endpoint command. Oct 18 21:41:17 dhcp47-74 kernel: xhci_hcd 0000:00:14.0: Assuming host is dying, halting host. Oct 18 21:41:17 dhcp47-74 kernel: xhci_hcd 0000:00:14.0: HC died; cleaning up Oct 18 21:41:17 dhcp47-74 kernel: usb 3-4: device descriptor read/8, error -110 Oct 18 21:41:17 dhcp47-74 kernel: usb 3-4: device descriptor read/8, error -22 Oct 18 21:41:17 dhcp47-74 kernel: hub 3-0:1.0: cannot disable port 4 (err = -19) Basically what is happening is in xhci_stop_endpoint_command_watchdog() the xhci->lock is grabbed with just spin_lock. What lockdep deduces is that if an interrupt occurred while in this function it would deadlock with xhci_irq because that function also grabs the xhci->lock. Fixing it is trivial by using spin_lock_irqsave instead. This should be queued to stable kernels as far back as 2.6.33. Signed-off-by: Don Zickus Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index b20d2f7221c..b4b06910f68 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -819,23 +819,24 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) struct xhci_ring *ring; struct xhci_td *cur_td; int ret, i, j; + unsigned long flags; ep = (struct xhci_virt_ep *) arg; xhci = ep->xhci; - spin_lock(&xhci->lock); + spin_lock_irqsave(&xhci->lock, flags); ep->stop_cmds_pending--; if (xhci->xhc_state & XHCI_STATE_DYING) { xhci_dbg(xhci, "Stop EP timer ran, but another timer marked " "xHCI as DYING, exiting.\n"); - spin_unlock(&xhci->lock); + spin_unlock_irqrestore(&xhci->lock, flags); return; } if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) { xhci_dbg(xhci, "Stop EP timer ran, but no command pending, " "exiting.\n"); - spin_unlock(&xhci->lock); + spin_unlock_irqrestore(&xhci->lock, flags); return; } @@ -847,11 +848,11 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) xhci->xhc_state |= XHCI_STATE_DYING; /* Disable interrupts from the host controller and start halting it */ xhci_quiesce(xhci); - spin_unlock(&xhci->lock); + spin_unlock_irqrestore(&xhci->lock, flags); ret = xhci_halt(xhci); - spin_lock(&xhci->lock); + spin_lock_irqsave(&xhci->lock, flags); if (ret < 0) { /* This is bad; the host is not responding to commands and it's * not allowing itself to be halted. At least interrupts are @@ -899,7 +900,7 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) } } } - spin_unlock(&xhci->lock); + spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "Calling usb_hc_died()\n"); usb_hc_died(xhci_to_hcd(xhci)->primary_hcd); xhci_dbg(xhci, "xHCI host controller is dead.\n"); From a07b39fcd6a9aecdc4093f5b7480ba0bdfc85854 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 3 Nov 2011 11:37:10 -0400 Subject: [PATCH 0322/4025] USB: XHCI: resume root hubs when the controller resumes commit f69e3120df82391a0ee8118e0a156239a06b2afb upstream. This patch (as1494) fixes a problem in xhci-hcd's resume routine. When the controller is runtime-resumed, this can only mean that one of the two root hubs has made a wakeup request and therefore needs to be resumed as well. Rather than try to determine which root hub requires attention (which might be difficult in the case where a new non-SuperSpeed device has been plugged in), the patch simply resumes both root hubs. Without this change, there is a race: The controller might be put back to sleep before it can activate its IRQ line, and the wakeup condition might never get handled. The patch also simplifies the logic in xhci_resume a little, combining some repeated flag settings into a single pair of statements. Signed-off-by: Alan Stern CC: Sarah Sharp Tested-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index eb31f9e45ba..1f0e198a865 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -749,7 +749,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) u32 command, temp = 0; struct usb_hcd *hcd = xhci_to_hcd(xhci); struct usb_hcd *secondary_hcd; - int retval; + int retval = 0; /* Wait a bit if either of the roothubs need to settle from the * transition into bus suspend. @@ -759,6 +759,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) xhci->bus_state[1].next_statechange)) msleep(100); + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); + spin_lock_irq(&xhci->lock); if (xhci->quirks & XHCI_RESET_ON_RESUME) hibernated = true; @@ -828,20 +831,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) return retval; xhci_dbg(xhci, "Start the primary HCD\n"); retval = xhci_run(hcd->primary_hcd); - if (retval) - goto failed_restart; - - xhci_dbg(xhci, "Start the secondary HCD\n"); - retval = xhci_run(secondary_hcd); if (!retval) { - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - set_bit(HCD_FLAG_HW_ACCESSIBLE, - &xhci->shared_hcd->flags); + xhci_dbg(xhci, "Start the secondary HCD\n"); + retval = xhci_run(secondary_hcd); } -failed_restart: hcd->state = HC_STATE_SUSPENDED; xhci->shared_hcd->state = HC_STATE_SUSPENDED; - return retval; + goto done; } /* step 4: set Run/Stop bit */ @@ -860,11 +856,14 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) * Running endpoints by ringing their doorbells */ - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); - spin_unlock_irq(&xhci->lock); - return 0; + + done: + if (retval == 0) { + usb_hcd_resume_root_hub(hcd); + usb_hcd_resume_root_hub(xhci->shared_hcd); + } + return retval; } #endif /* CONFIG_PM */ From ad8a9b61e60399e909b99ae9be457d5c4450c69d Mon Sep 17 00:00:00 2001 From: "zheng.zhijian@zte.com.cn" Date: Thu, 17 Nov 2011 19:23:25 +0800 Subject: [PATCH 0323/4025] USB: option: release new PID for ZTE 3G modem commit 46b5a277ed90317a4d17e936c16037e76011b219 upstream. This patch adds new PIDs for ZTE 3G modem, after we confirm it and tested. Thanks for Dan's work at kernel option devier. Signed-off-by: Alvin.Zheng Signed-off-by: wsalvin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 89ae1f65e1b..903dd78c173 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -316,6 +316,9 @@ static void option_instat_callback(struct urb *urb); #define ZTE_PRODUCT_AC8710 0xfff1 #define ZTE_PRODUCT_AC2726 0xfff5 #define ZTE_PRODUCT_AC8710T 0xffff +#define ZTE_PRODUCT_MC2718 0xffe8 +#define ZTE_PRODUCT_AD3812 0xffeb +#define ZTE_PRODUCT_MC2716 0xffed #define BENQ_VENDOR_ID 0x04a5 #define BENQ_PRODUCT_H10 0x4068 @@ -500,6 +503,18 @@ static const struct option_blacklist_info zte_k3765_z_blacklist = { .reserved = BIT(4), }; +static const struct option_blacklist_info zte_ad3812_z_blacklist = { + .sendsetup = BIT(0) | BIT(1) | BIT(2), +}; + +static const struct option_blacklist_info zte_mc2718_z_blacklist = { + .sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4), +}; + +static const struct option_blacklist_info zte_mc2716_z_blacklist = { + .sendsetup = BIT(1) | BIT(2) | BIT(3), +}; + static const struct option_blacklist_info huawei_cdc12_blacklist = { .reserved = BIT(1) | BIT(2), }; @@ -1043,6 +1058,12 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&zte_mc2718_z_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AD3812, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist }, { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, { USB_DEVICE(ALINK_VENDOR_ID, DLINK_PRODUCT_DWM_652_U5) }, /* Yes, ALINK_VENDOR_ID */ From fe18f66a2d61962b28d319e9d8a5bf68edaeb215 Mon Sep 17 00:00:00 2001 From: Ferenc Wagner Date: Thu, 17 Nov 2011 16:44:58 +0100 Subject: [PATCH 0324/4025] USB: option: add PID of Huawei E173s 3G modem commit 4aa3648c719265bac9c2742c9ebb043e6dbdd790 upstream. Signed-off-by: Ferenc Wagner Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 903dd78c173..3a47cbe9fc5 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -156,6 +156,7 @@ static void option_instat_callback(struct urb *urb); #define HUAWEI_PRODUCT_K4511 0x14CC #define HUAWEI_PRODUCT_ETS1220 0x1803 #define HUAWEI_PRODUCT_E353 0x1506 +#define HUAWEI_PRODUCT_E173S 0x1C05 #define QUANTA_VENDOR_ID 0x0408 #define QUANTA_PRODUCT_Q101 0xEA02 @@ -637,6 +638,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff), From 0841db56cfb4cd090cbdd52dc2c7f39a70042e15 Mon Sep 17 00:00:00 2001 From: wangyanqing Date: Thu, 10 Nov 2011 14:04:08 +0800 Subject: [PATCH 0325/4025] USB: serial: pl2303: rm duplicate id commit 0c16595539b612fe948559433dda08ff96a8bdc7 upstream. I get report from customer that his usb-serial converter doesn't work well,it sometimes work, but sometimes it doesn't. The usb-serial converter's id: vendor_id product_id 0x4348 0x5523 Then I search the usb-serial codes, and there are two drivers announce support this device, pl2303 and ch341, commit 026dfaf1 cause it. Through many times to test, ch341 works well with this device, and pl2303 doesn't work quite often(it just work quite little). ch341 works well with this device, so we doesn't need pl2303 to support.I try to revert 026dfaf1 first, but it failed. So I prepare this patch by hand to revert it. Signed-off-by: Wang YanQing Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/pl2303.c | 1 - drivers/usb/serial/pl2303.h | 4 ---- 2 files changed, 5 deletions(-) diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 614fabc6a15..d44c669cc48 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -91,7 +91,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, - { USB_DEVICE(WINCHIPHEAD_VENDOR_ID, WINCHIPHEAD_USBSER_PRODUCT_ID) }, { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 3d10d7f0207..c38b8c00c06 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -145,10 +145,6 @@ #define ADLINK_VENDOR_ID 0x0b63 #define ADLINK_ND6530_PRODUCT_ID 0x6530 -/* WinChipHead USB->RS 232 adapter */ -#define WINCHIPHEAD_VENDOR_ID 0x4348 -#define WINCHIPHEAD_USBSER_PRODUCT_ID 0x5523 - /* SMART USB Serial Adapter */ #define SMART_VENDOR_ID 0x0b8c #define SMART_PRODUCT_ID 0x2303 From bbf54d177037d268d9a744ee4c2add570ba8a9ad Mon Sep 17 00:00:00 2001 From: Havard Skinnemoen Date: Wed, 9 Nov 2011 13:47:38 -0800 Subject: [PATCH 0326/4025] USB: cdc-acm: Fix disconnect() vs close() race commit 5dc2470c602da8851907ec18942cd876c3b4ecc1 upstream. There's a race between the USB disconnect handler and the TTY close handler which may cause the acm object to be freed while it's still being used. This may lead to things like http://article.gmane.org/gmane.linux.usb.general/54250 and https://lkml.org/lkml/2011/5/29/64 This is the simplest fix I could come up with. Holding on to open_mutex while closing the TTY device prevents acm_disconnect() from freeing the acm object between acm->port.count drops to 0 and the TTY side of the cleanups are finalized. Signed-off-by: Havard Skinnemoen Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 5112f572677..2ffcaa0b0b7 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -539,7 +539,6 @@ static void acm_port_down(struct acm *acm) { int i; - mutex_lock(&open_mutex); if (acm->dev) { usb_autopm_get_interface(acm->control); acm_set_control(acm, acm->ctrlout = 0); @@ -551,14 +550,15 @@ static void acm_port_down(struct acm *acm) acm->control->needs_remote_wakeup = 0; usb_autopm_put_interface(acm->control); } - mutex_unlock(&open_mutex); } static void acm_tty_hangup(struct tty_struct *tty) { struct acm *acm = tty->driver_data; tty_port_hangup(&acm->port); + mutex_lock(&open_mutex); acm_port_down(acm); + mutex_unlock(&open_mutex); } static void acm_tty_close(struct tty_struct *tty, struct file *filp) @@ -569,8 +569,9 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) shutdown */ if (!acm) return; + + mutex_lock(&open_mutex); if (tty_port_close_start(&acm->port, tty, filp) == 0) { - mutex_lock(&open_mutex); if (!acm->dev) { tty_port_tty_set(&acm->port, NULL); acm_tty_unregister(acm); @@ -582,6 +583,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) acm_port_down(acm); tty_port_close_end(&acm->port, tty); tty_port_tty_set(&acm->port, NULL); + mutex_unlock(&open_mutex); } static int acm_tty_write(struct tty_struct *tty, From 3d396a3b21f381ffb651f481252508243c0325a6 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 27 Oct 2011 11:20:21 -0400 Subject: [PATCH 0327/4025] USB: workaround for bug in old version of GCC commit 97ff22ee3b4cb3a334f7385e269773141aed702f upstream. This patch (as1491) works around a bug in GCC-3.4.6, which is still supposed to be supported. The number of microseconds in the udelay() call in quirk_usb_disable_ehci() is fixed at 100, but the compiler doesn't understand this and generates a link-time error. So we replace the otherwise unused variable "delta" with a simple constant 100. This same pattern is already used in other delay loops in that source file. Signed-off-by: Alan Stern Reported-by: Konrad Rzepecki Tested-by: Konrad Rzepecki Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 629a96813fd..a495d489918 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -626,7 +626,7 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) void __iomem *base, *op_reg_base; u32 hcc_params, cap, val; u8 offset, cap_length; - int wait_time, delta, count = 256/4; + int wait_time, count = 256/4; if (!mmio_resource_enabled(pdev, 0)) return; @@ -672,11 +672,10 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) writel(val, op_reg_base + EHCI_USBCMD); wait_time = 2000; - delta = 100; do { writel(0x3f, op_reg_base + EHCI_USBSTS); - udelay(delta); - wait_time -= delta; + udelay(100); + wait_time -= 100; val = readl(op_reg_base + EHCI_USBSTS); if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) { break; From 1c9e0eba2b5954bfb213ce2facfd439eeb3cda3b Mon Sep 17 00:00:00 2001 From: Bart Hartgers Date: Wed, 26 Oct 2011 13:29:42 +0200 Subject: [PATCH 0328/4025] USB: ark3116 initialisation fix commit 583182ba5f02c8c9be82ea550f2051eaec15b975 upstream. This patch for the usb serial ark3116 driver fixes an initialisation ordering bug that gets triggered on hotplug when using at least recent debian/ubuntu userspace. Without it, ark3116 serial cables don't work. Signed-off-by: Bart Hartgers Tested-by: law_ence.dev@ntlworld.com Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ark3116.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 5cdb9d91227..18e875b92e0 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -42,7 +42,7 @@ static int debug; * Version information */ -#define DRIVER_VERSION "v0.6" +#define DRIVER_VERSION "v0.7" #define DRIVER_AUTHOR "Bart Hartgers " #define DRIVER_DESC "USB ARK3116 serial/IrDA driver" #define DRIVER_DEV_DESC "ARK3116 RS232/IrDA" @@ -380,10 +380,6 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) goto err_out; } - /* setup termios */ - if (tty) - ark3116_set_termios(tty, port, NULL); - /* remove any data still left: also clears error state */ ark3116_read_reg(serial, UART_RX, buf); @@ -406,6 +402,10 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) /* enable DMA */ ark3116_write_reg(port->serial, UART_FCR, UART_FCR_DMA_SELECT); + /* setup termios */ + if (tty) + ark3116_set_termios(tty, port, NULL); + err_out: kfree(buf); return result; From b987edee414235e29984d424043761b735bb4a5e Mon Sep 17 00:00:00 2001 From: Andrew Worsley Date: Fri, 18 Nov 2011 23:13:33 +1100 Subject: [PATCH 0329/4025] USB: Fix Corruption issue in USB ftdi driver ftdi_sio.c commit b1ffb4c851f185e9051ba837c16d9b84ef688d26 upstream. Fix for ftdi_set_termios() glitching output ftdi_set_termios() is constantly setting the baud rate, data bits and parity unnecessarily on every call, . When called while characters are being transmitted can cause the FTDI chip to corrupt the serial port bit stream output by stalling the output half a bit during the output of a character. Simple fix by skipping this setting if the baud rate/data bits/parity are unchanged. Signed-off-by: Andrew Worsley Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 1b51d43f1da..486769c0f35 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -2080,13 +2080,19 @@ static void ftdi_set_termios(struct tty_struct *tty, cflag = termios->c_cflag; - /* FIXME -For this cut I don't care if the line is really changing or - not - so just do the change regardless - should be able to - compare old_termios and tty->termios */ + if (old_termios->c_cflag == termios->c_cflag + && old_termios->c_ispeed == termios->c_ispeed + && old_termios->c_ospeed == termios->c_ospeed) + goto no_c_cflag_changes; + /* NOTE These routines can get interrupted by ftdi_sio_read_bulk_callback - need to examine what this means - don't see any problems yet */ + if ((old_termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)) == + (termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB))) + goto no_data_parity_stop_changes; + /* Set number of data bits, parity, stop bits */ urb_value = 0; @@ -2127,6 +2133,7 @@ static void ftdi_set_termios(struct tty_struct *tty, } /* Now do the baudrate */ +no_data_parity_stop_changes: if ((cflag & CBAUD) == B0) { /* Disable flow control */ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), @@ -2154,6 +2161,7 @@ static void ftdi_set_termios(struct tty_struct *tty, /* Set flow control */ /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ +no_c_cflag_changes: if (cflag & CRTSCTS) { dbg("%s Setting to CRTSCTS flow control", __func__); if (usb_control_msg(dev, From a7a656cfe46e8278458a8c897aacd6bf28def1fe Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 25 Oct 2011 10:50:58 -0400 Subject: [PATCH 0330/4025] usb-storage: Accept 8020i-protocol commands longer than 12 bytes commit 2f640bf4c94324aeaa1b6385c10aab8c5ad1e1cf upstream. The 8020i protocol (also 8070i and QIC-157) uses 12-byte commands; shorter commands must be padded. Simon Detheridge reports that his 3-TB USB disk drive claims to use the 8020i protocol (which is normally meant for ATAPI devices like CD drives), and because of its large size, the disk drive requires the use of 16-byte commands. However the usb_stor_pad12_command() routine in usb-storage always sets the command length to 12, making the drive impossible to use. Since the SFF-8020i specification allows for 16-byte commands in future extensions, we may as well accept them. This patch (as1490) changes usb_stor_pad12_command() to leave commands larger than 12 bytes alone rather than truncating them. Signed-off-by: Alan Stern Tested-by: Simon Detheridge CC: Matthew Dharm Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/protocol.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c index fc310f75ead..0fded39e3b3 100644 --- a/drivers/usb/storage/protocol.c +++ b/drivers/usb/storage/protocol.c @@ -58,7 +58,9 @@ void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us) { - /* Pad the SCSI command with zeros out to 12 bytes + /* + * Pad the SCSI command with zeros out to 12 bytes. If the + * command already is 12 bytes or longer, leave it alone. * * NOTE: This only works because a scsi_cmnd struct field contains * a unsigned char cmnd[16], so we know we have storage available @@ -66,9 +68,6 @@ void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us) for (; srb->cmd_len<12; srb->cmd_len++) srb->cmnd[srb->cmd_len] = 0; - /* set command length to 12 bytes */ - srb->cmd_len = 12; - /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); } From 317451c11fefcb0e05383f0a0080bb7f5445cfcf Mon Sep 17 00:00:00 2001 From: Thomas Poussevin Date: Thu, 27 Oct 2011 18:46:48 +0200 Subject: [PATCH 0331/4025] USB: EHCI: fix HUB TT scheduling issue with iso transfer commit 811c926c538f7e8d3c08b630dd5844efd7e000f6 upstream. The current TT scheduling doesn't allow to play and then record on a full-speed device connected to a high speed hub. The IN iso stream can only start on the first uframe (0-2 for a 165 us) because of CSPLIT transactions. For the OUT iso stream there no such restriction. uframe 0-5 are possible. The idea of this patch is that the first uframe are precious (for IN TT iso stream) and we should allocate the last uframes first if possible. For that we reverse the order of uframe allocation (last uframe first). Here an example : hid interrupt stream ---------------------------------------------------------------------- uframe | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ---------------------------------------------------------------------- max_tt_usecs | 125 | 125 | 125 | 125 | 125 | 125 | 30 | 0 | ---------------------------------------------------------------------- used usecs on a frame | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ---------------------------------------------------------------------- iso OUT stream ---------------------------------------------------------------------- uframe | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ---------------------------------------------------------------------- max_tt_usecs | 125 | 125 | 125 | 125 | 125 | 125 | 30 | 0 | ---------------------------------------------------------------------- used usecs on a frame | 13 | 125 | 39 | 0 | 0 | 0 | 0 | 0 | ---------------------------------------------------------------------- There no place for iso IN stream (uframe 0-2 are used) and we got "cannot submit datapipe for urb 0, error -28: not enough bandwidth" error. With the patch this become. iso OUT stream ---------------------------------------------------------------------- uframe | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ---------------------------------------------------------------------- max_tt_usecs | 125 | 125 | 125 | 125 | 125 | 125 | 30 | 0 | ---------------------------------------------------------------------- used usecs on a frame | 13 | 0 | 0 | 0 | 125 | 39 | 0 | 0 | ---------------------------------------------------------------------- iso IN stream ---------------------------------------------------------------------- uframe | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ---------------------------------------------------------------------- max_tt_usecs | 125 | 125 | 125 | 125 | 125 | 125 | 30 | 0 | ---------------------------------------------------------------------- used usecs on a frame | 13 | 0 | 125 | 40 | 125 | 39 | 0 | 0 | ---------------------------------------------------------------------- Signed-off-by: Matthieu Castet Signed-off-by: Thomas Poussevin Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 063c630d246..fb2d0c2f067 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1483,10 +1483,15 @@ iso_stream_schedule ( /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ - /* find a uframe slot with enough bandwidth */ - next = start + period; - for (; start < next; start++) { - + /* find a uframe slot with enough bandwidth. + * Early uframes are more precious because full-speed + * iso IN transfers can't use late uframes, + * and therefore they should be allocated last. + */ + next = start; + start += period; + do { + start--; /* check schedule: enough space? */ if (stream->highspeed) { if (itd_slot_ok(ehci, mod, start, @@ -1499,7 +1504,7 @@ iso_stream_schedule ( start, sched, period)) break; } - } + } while (start > next); /* no room in the schedule */ if (start == next) { From 85e9996fdfe3e3095ab24c4f926695ad2e4ea8d9 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Wed, 26 Oct 2011 13:53:17 -0400 Subject: [PATCH 0332/4025] USB: add quirk for Logitech C600 web cam commit 60c71ca972a2dd3fd9d0165b405361c8ad48349b upstream. We've had another report of the "chipmunk" sound on a Logitech C600 webcam. This patch resolves the issue. Signed-off-by: Josh Boyer Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index d6a8d8269bf..caa19914806 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -50,6 +50,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Logitech Webcam B/C500 */ { USB_DEVICE(0x046d, 0x0807), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam C600 */ + { USB_DEVICE(0x046d, 0x0808), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam Pro 9000 */ { USB_DEVICE(0x046d, 0x0809), .driver_info = USB_QUIRK_RESET_RESUME }, From 10318b5517baa2ae7e4bb884c6acb9cf572eebc8 Mon Sep 17 00:00:00 2001 From: sordna Date: Thu, 27 Oct 2011 21:06:26 -0700 Subject: [PATCH 0333/4025] USB: quirks: adding more quirky webcams to avoid squeaky audio commit 0d145d7d4a241c321c832a810bb6edad18e2217b upstream. The following patch contains additional affected webcam models, on top of the patches commited to linux-next 2394d67e446bf616a0885167d5f0d397bdacfdfc and 5b253d88cc6c65a23cefc457a5a4ef139913c5fc Signed-off-by: sordna Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index caa19914806..ecf12e15a7e 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -56,12 +56,36 @@ static const struct usb_device_id usb_quirk_list[] = { /* Logitech Webcam Pro 9000 */ { USB_DEVICE(0x046d, 0x0809), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam C905 */ + { USB_DEVICE(0x046d, 0x080a), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C210 */ + { USB_DEVICE(0x046d, 0x0819), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C260 */ + { USB_DEVICE(0x046d, 0x081a), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam C310 */ { USB_DEVICE(0x046d, 0x081b), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam C910 */ + { USB_DEVICE(0x046d, 0x0821), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C160 */ + { USB_DEVICE(0x046d, 0x0824), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam C270 */ { USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Quickcam Pro 9000 */ + { USB_DEVICE(0x046d, 0x0990), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Quickcam E3500 */ + { USB_DEVICE(0x046d, 0x09a4), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Quickcam Vision Pro */ + { USB_DEVICE(0x046d, 0x09a6), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Harmony 700-series */ { USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT }, From e62cccfcf5535487daf8c1d3613b9dabc2315b44 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 19 Nov 2011 13:13:37 -0500 Subject: [PATCH 0334/4025] xfs: fix error handling for synchronous writes If removed storage while synchronous buffer write underway, "xfslogd" hangs. Detailed log http://oss.sgi.com/archives/xfs/2011-07/msg00740.html Related work bfc60177f8ab509bc225becbb58f7e53a0e33e81 "xfs: fix error handling for synchronous writes" Given that xfs_bwrite actually does the shutdown already after waiting for the b_iodone completion and given that we actually found that calling xfs_force_shutdown from inside xfs_buf_iodone_callbacks was a major contributor the problem it better to drop this call. Signed-off-by: Ajeet Yadav Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_buf_item.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index a7342e840d7..7888a756307 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -1023,7 +1023,6 @@ xfs_buf_iodone_callbacks( XFS_BUF_UNDELAYWRITE(bp); trace_xfs_buf_error_relse(bp, _RET_IP_); - xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); do_callbacks: xfs_buf_do_callbacks(bp); From afd717d6cd334fc89f3ac938e19aade2f939b629 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 19 Nov 2011 13:13:38 -0500 Subject: [PATCH 0335/4025] xfs: fix xfs_mark_inode_dirty during umount commit 866e4ed77448a0c311e1b055eb72ea05423fd799 upstream. During umount we do not add a dirty inode to the lru and wait for it to become clean first, but force writeback of data and metadata with I_WILL_FREE set. Currently there is no way for XFS to detect that the inode has been redirtied for metadata operations, as we skip the mark_inode_dirty call during teardown. Fix this by setting i_update_core nanually in that case, so that the inode gets flushed during inode reclaim. Alternatively we could enable calling mark_inode_dirty for inodes in I_WILL_FREE state, and let the VFS dirty tracking handle this. I decided against this as we will get better I/O patterns from reclaim compared to the synchronous writeout in write_inode_now, and always marking the inode dirty in some way from xfs_mark_inode_dirty is a better safetly net in either case. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- fs/xfs/linux-2.6/xfs_iops.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index d44d92cd12b..a9b3e1e7112 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -69,9 +69,8 @@ xfs_synchronize_times( } /* - * If the linux inode is valid, mark it dirty. - * Used when committing a dirty inode into a transaction so that - * the inode will get written back by the linux code + * If the linux inode is valid, mark it dirty, else mark the dirty state + * in the XFS inode to make sure we pick it up when reclaiming the inode. */ void xfs_mark_inode_dirty_sync( @@ -81,6 +80,10 @@ xfs_mark_inode_dirty_sync( if (!(inode->i_state & (I_WILL_FREE|I_FREEING))) mark_inode_dirty_sync(inode); + else { + barrier(); + ip->i_update_core = 1; + } } void @@ -91,6 +94,11 @@ xfs_mark_inode_dirty( if (!(inode->i_state & (I_WILL_FREE|I_FREEING))) mark_inode_dirty(inode); + else { + barrier(); + ip->i_update_core = 1; + } + } /* From 16ba92e591d31d3213956e581867f46892648038 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Sat, 19 Nov 2011 13:13:40 -0500 Subject: [PATCH 0336/4025] xfs: dont serialise direct IO reads on page cache commit 0c38a2512df272b14ef4238b476a2e4f70da1479 upstream. There is no need to grab the i_mutex of the IO lock in exclusive mode if we don't need to invalidate the page cache. Taking these locks on every direct IO effective serialises them as taking the IO lock in exclusive mode has to wait for all shared holders to drop the lock. That only happens when IO is complete, so effective it prevents dispatch of concurrent direct IO reads to the same inode. Fix this by taking the IO lock shared to check the page cache state, and only then drop it and take the IO lock exclusively if there is work to be done. Hence for the normal direct IO case, no exclusive locking will occur. Signed-off-by: Dave Chinner Tested-by: Joern Engel Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- fs/xfs/linux-2.6/xfs_file.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 7f782af286b..93cc02d70c6 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -309,7 +309,19 @@ xfs_file_aio_read( if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; - if (unlikely(ioflags & IO_ISDIRECT)) { + /* + * Locking is a bit tricky here. If we take an exclusive lock + * for direct IO, we effectively serialise all new concurrent + * read IO to this file and block it behind IO that is currently in + * progress because IO in progress holds the IO lock shared. We only + * need to hold the lock exclusive to blow away the page cache, so + * only take lock exclusively if the page cache needs invalidation. + * This allows the normal direct IO case of no page cache pages to + * proceeed concurrently without serialisation. + */ + xfs_rw_ilock(ip, XFS_IOLOCK_SHARED); + if ((ioflags & IO_ISDIRECT) && inode->i_mapping->nrpages) { + xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED); xfs_rw_ilock(ip, XFS_IOLOCK_EXCL); if (inode->i_mapping->nrpages) { @@ -322,8 +334,7 @@ xfs_file_aio_read( } } xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL); - } else - xfs_rw_ilock(ip, XFS_IOLOCK_SHARED); + } trace_xfs_file_read(ip, size, iocb->ki_pos, ioflags); From 3da97f9710ca1df6cebe2558896dae3ed62337be Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 19 Nov 2011 13:13:41 -0500 Subject: [PATCH 0337/4025] xfs: avoid direct I/O write vs buffered I/O race commit c58cb165bd44de8aaee9755a144136ae743be116 upstream. Currently a buffered reader or writer can add pages to the pagecache while we are waiting for the iolock in xfs_file_dio_aio_write. Prevent this by re-checking mapping->nrpages after we got the iolock, and if nessecary upgrade the lock to exclusive mode. To simplify this a bit only take the ilock inside of xfs_file_aio_write_checks. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- fs/xfs/linux-2.6/xfs_file.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 93cc02d70c6..b679198dcc0 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -669,6 +669,7 @@ xfs_file_aio_write_checks( xfs_fsize_t new_size; int error = 0; + xfs_rw_ilock(ip, XFS_ILOCK_EXCL); error = generic_write_checks(file, pos, count, S_ISBLK(inode->i_mode)); if (error) { xfs_rw_iunlock(ip, XFS_ILOCK_EXCL | *iolock); @@ -760,14 +761,24 @@ xfs_file_dio_aio_write( *iolock = XFS_IOLOCK_EXCL; else *iolock = XFS_IOLOCK_SHARED; - xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock); + xfs_rw_ilock(ip, *iolock); ret = xfs_file_aio_write_checks(file, &pos, &count, iolock); if (ret) return ret; + /* + * Recheck if there are cached pages that need invalidate after we got + * the iolock to protect against other threads adding new pages while + * we were waiting for the iolock. + */ + if (mapping->nrpages && *iolock == XFS_IOLOCK_SHARED) { + xfs_rw_iunlock(ip, *iolock); + *iolock = XFS_IOLOCK_EXCL; + xfs_rw_ilock(ip, *iolock); + } + if (mapping->nrpages) { - WARN_ON(*iolock != XFS_IOLOCK_EXCL); ret = -xfs_flushinval_pages(ip, (pos & PAGE_CACHE_MASK), -1, FI_REMAPF_LOCKED); if (ret) @@ -812,7 +823,7 @@ xfs_file_buffered_aio_write( size_t count = ocount; *iolock = XFS_IOLOCK_EXCL; - xfs_rw_ilock(ip, XFS_ILOCK_EXCL | *iolock); + xfs_rw_ilock(ip, *iolock); ret = xfs_file_aio_write_checks(file, &pos, &count, iolock); if (ret) From 5b9d69bca6a43e7cd61df13e820ee4e5f99e1615 Mon Sep 17 00:00:00 2001 From: Mitsuo Hayasaka Date: Sat, 19 Nov 2011 13:13:42 -0500 Subject: [PATCH 0338/4025] xfs: Return -EIO when xfs_vn_getattr() failed commit ed32201e65e15f3e6955cb84cbb544b08f81e5a5 upstream. An attribute of inode can be fetched via xfs_vn_getattr() in XFS. Currently it returns EIO, not negative value, when it failed. As a result, the system call returns not negative value even though an error occured. The stat(2), ls and mv commands cannot handle this error and do not work correctly. This patch fixes this bug, and returns -EIO, not EIO when an error is detected in xfs_vn_getattr(). Signed-off-by: Mitsuo Hayasaka Reviewed-by: Christoph Hellwig Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- fs/xfs/linux-2.6/xfs_iops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index a9b3e1e7112..f5b697bf39f 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -464,7 +464,7 @@ xfs_vn_getattr( trace_xfs_getattr(ip); if (XFS_FORCED_SHUTDOWN(mp)) - return XFS_ERROR(EIO); + return -XFS_ERROR(EIO); stat->size = XFS_ISIZE(ip); stat->dev = inode->i_sb->s_dev; From 70f589ceb96bbf1d4c2c2f5b6c3d6dff19ddd31d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 19 Nov 2011 13:13:43 -0500 Subject: [PATCH 0339/4025] xfs: fix buffer flushing during unmount commit 87c7bec7fc3377b3873eb3a0f4b603981ea16ebb upstream. The code to flush buffers in the umount code is a bit iffy: we first flush all delwri buffers out, but then might be able to queue up a new one when logging the sb counts. On a normal shutdown that one would get flushed out when doing the synchronous superblock write in xfs_unmountfs_writesb, but we skip that one if the filesystem has been shut down. Fix this by moving the delwri list flushing until just before unmounting the log, and while we're at it also remove the superflous delwri list and buffer lru flusing for the rt and log device that can never have cached or delwri buffers. Signed-off-by: Christoph Hellwig Reported-by: Amit Sahrawat Tested-by: Amit Sahrawat Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- fs/xfs/linux-2.6/xfs_buf.h | 1 - fs/xfs/xfs_mount.c | 29 ++++++++++------------------- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index 50a7d5fb3b7..36d6ee44386 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -346,7 +346,6 @@ extern struct list_head *xfs_get_buftarg_list(void); #define xfs_getsize_buftarg(buftarg) block_size((buftarg)->bt_bdev) #define xfs_readonly_buftarg(buftarg) bdev_read_only((buftarg)->bt_bdev) -#define xfs_binval(buftarg) xfs_flush_buftarg(buftarg, 1) #define XFS_bflush(buftarg) xfs_flush_buftarg(buftarg, 1) #endif /* __XFS_BUF_H__ */ diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index b49b82363d2..9afdd497369 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -44,9 +44,6 @@ #include "xfs_trace.h" -STATIC void xfs_unmountfs_wait(xfs_mount_t *); - - #ifdef HAVE_PERCPU_SB STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t, int); @@ -1507,11 +1504,6 @@ xfs_unmountfs( */ xfs_log_force(mp, XFS_LOG_SYNC); - xfs_binval(mp->m_ddev_targp); - if (mp->m_rtdev_targp) { - xfs_binval(mp->m_rtdev_targp); - } - /* * Unreserve any blocks we have so that when we unmount we don't account * the reserved free space as used. This is really only necessary for @@ -1537,7 +1529,16 @@ xfs_unmountfs( xfs_warn(mp, "Unable to update superblock counters. " "Freespace may not be correct on next mount."); xfs_unmountfs_writesb(mp); - xfs_unmountfs_wait(mp); /* wait for async bufs */ + + /* + * Make sure all buffers have been flushed and completed before + * unmounting the log. + */ + error = xfs_flush_buftarg(mp->m_ddev_targp, 1); + if (error) + xfs_warn(mp, "%d busy buffers during unmount.", error); + xfs_wait_buftarg(mp->m_ddev_targp); + xfs_log_unmount_write(mp); xfs_log_unmount(mp); xfs_uuid_unmount(mp); @@ -1548,16 +1549,6 @@ xfs_unmountfs( xfs_free_perag(mp); } -STATIC void -xfs_unmountfs_wait(xfs_mount_t *mp) -{ - if (mp->m_logdev_targp != mp->m_ddev_targp) - xfs_wait_buftarg(mp->m_logdev_targp); - if (mp->m_rtdev_targp) - xfs_wait_buftarg(mp->m_rtdev_targp); - xfs_wait_buftarg(mp->m_ddev_targp); -} - int xfs_fs_writable(xfs_mount_t *mp) { From 626ff2d51fc1127814fa28bdfb1df761ea894755 Mon Sep 17 00:00:00 2001 From: Carlos Maiolino Date: Sat, 19 Nov 2011 13:13:44 -0500 Subject: [PATCH 0340/4025] xfs: Fix possible memory corruption in xfs_readlink commit b52a360b2aa1c59ba9970fb0f52bbb093fcc7a24 upstream. Fixes a possible memory corruption when the link is larger than MAXPATHLEN and XFS_DEBUG is not enabled. This also remove the S_ISLNK assert, since the inode mode is checked previously in xfs_readlink_by_handle() and via VFS. Updated to address concerns raised by Ben Hutchings about the loose attention paid to 32- vs 64-bit values, and the lack of handling a potentially negative pathlen value: - Changed type of "pathlen" to be xfs_fsize_t, to match that of ip->i_d.di_size - Added checking for a negative pathlen to the too-long pathlen test, and generalized the message that gets reported in that case to reflect the change As a result, if a negative pathlen were encountered, this function would return EFSCORRUPTED (and would fail an assertion for a debug build)--just as would a too-long pathlen. Signed-off-by: Alex Elder Signed-off-by: Carlos Maiolino Reviewed-by: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_vnodeops.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 619720705bc..6cc4d41fb0d 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -535,7 +535,7 @@ xfs_readlink( char *link) { xfs_mount_t *mp = ip->i_mount; - int pathlen; + xfs_fsize_t pathlen; int error = 0; trace_xfs_readlink(ip); @@ -545,13 +545,19 @@ xfs_readlink( xfs_ilock(ip, XFS_ILOCK_SHARED); - ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK); - ASSERT(ip->i_d.di_size <= MAXPATHLEN); - pathlen = ip->i_d.di_size; if (!pathlen) goto out; + if (pathlen < 0 || pathlen > MAXPATHLEN) { + xfs_alert(mp, "%s: inode (%llu) bad symlink length (%lld)", + __func__, (unsigned long long) ip->i_ino, + (long long) pathlen); + ASSERT(0); + return XFS_ERROR(EFSCORRUPTED); + } + + if (ip->i_df.if_flags & XFS_IFINLINE) { memcpy(link, ip->i_df.if_u1.if_data, pathlen); link[pathlen] = '\0'; From 7d7e5d33408819c084528dcff139fc4564c7bdda Mon Sep 17 00:00:00 2001 From: Mitsuo Hayasaka Date: Sat, 19 Nov 2011 13:13:45 -0500 Subject: [PATCH 0341/4025] xfs: use doalloc flag in xfs_qm_dqattach_one() commit db3e74b582915d66e10b0c73a62763418f54c340 upstream The doalloc arg in xfs_qm_dqattach_one() is a flag that indicates whether a new area to handle quota information will be allocated if needed. Originally, it was passed to xfs_qm_dqget(), but has been removed by the following commit (probably by mistake): commit 8e9b6e7fa4544ea8a0e030c8987b918509c8ff47 Author: Christoph Hellwig Date: Sun Feb 8 21:51:42 2009 +0100 xfs: remove the unused XFS_QMOPT_DQLOCK flag As the result, xfs_qm_dqget() called from xfs_qm_dqattach_one() never allocates the new area even if it is needed. This patch gives the doalloc arg to xfs_qm_dqget() in xfs_qm_dqattach_one() to fix this problem. Signed-off-by: Mitsuo Hayasaka Cc: Alex Elder Cc: Christoph Hellwig Reviewed-by: Christoph Hellwig Signed-off-by: Ben Myers Signed-off-by: Greg Kroah-Hartman --- fs/xfs/quota/xfs_qm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index b94dace4e78..e70c7fc95e2 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -714,7 +714,8 @@ xfs_qm_dqattach_one( * disk and we didn't ask it to allocate; * ESRCH if quotas got turned off suddenly. */ - error = xfs_qm_dqget(ip->i_mount, ip, id, type, XFS_QMOPT_DOWARN, &dqp); + error = xfs_qm_dqget(ip->i_mount, ip, id, type, + doalloc | XFS_QMOPT_DOWARN, &dqp); if (error) return error; From ae6c19cd6c32f88b2d8549984ff2a5fcdcc932b2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 19 Nov 2011 13:13:39 -0500 Subject: [PATCH 0342/4025] xfs: fix ->write_inode return values patch 58d84c4ee0389ddeb86238d5d8359a982c9f7a5b upstream. Currently we always redirty an inode that was attempted to be written out synchronously but has been cleaned by an AIL pushed internall, which is rather bogus. Fix that by doing the i_update_core check early on and return 0 for it. Also include async calls for it, as doing any work for those is just as pointless. While we're at it also fix the sign for the EIO return in case of a filesystem shutdown, and fix the completely non-sensical locking around xfs_log_inode. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- fs/xfs/linux-2.6/xfs_super.c | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 347cae965e8..28de70b9122 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -878,33 +878,17 @@ xfs_log_inode( struct xfs_trans *tp; int error; - xfs_iunlock(ip, XFS_ILOCK_SHARED); tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS); error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0); - if (error) { xfs_trans_cancel(tp, 0); - /* we need to return with the lock hold shared */ - xfs_ilock(ip, XFS_ILOCK_SHARED); return error; } xfs_ilock(ip, XFS_ILOCK_EXCL); - - /* - * Note - it's possible that we might have pushed ourselves out of the - * way during trans_reserve which would flush the inode. But there's - * no guarantee that the inode buffer has actually gone out yet (it's - * delwri). Plus the buffer could be pinned anyway if it's part of - * an inode in another recent transaction. So we play it safe and - * fire off the transaction anyway. - */ - xfs_trans_ijoin(tp, ip); + xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - error = xfs_trans_commit(tp, 0); - xfs_ilock_demote(ip, XFS_ILOCK_EXCL); - - return error; + return xfs_trans_commit(tp, 0); } STATIC int @@ -919,7 +903,9 @@ xfs_fs_write_inode( trace_xfs_write_inode(ip); if (XFS_FORCED_SHUTDOWN(mp)) - return XFS_ERROR(EIO); + return -XFS_ERROR(EIO); + if (!ip->i_update_core) + return 0; if (wbc->sync_mode == WB_SYNC_ALL) { /* @@ -930,12 +916,10 @@ xfs_fs_write_inode( * of synchronous log foces dramatically. */ xfs_ioend_wait(ip); - xfs_ilock(ip, XFS_ILOCK_SHARED); - if (ip->i_update_core) { - error = xfs_log_inode(ip); - if (error) - goto out_unlock; - } + error = xfs_log_inode(ip); + if (error) + goto out; + return 0; } else { /* * We make this non-blocking if the inode is contended, return From e01b0328fa4df58b3d0ccd03f8b1b2768f05e539 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Wed, 12 Oct 2011 11:10:21 -0700 Subject: [PATCH 0343/4025] drm/i915: fix IVB cursor support commit 65a21cd65316145f9302594be8e69074369e1050 upstream. The cursor regs have moved around, add the offsets and new macros for getting at them. Signed-off-by: Jesse Barnes Tested-By: Eugeni Dodonov Reviewed-By: Eugeni Dodonov Signed-off-by: Keith Packard Signed-off-by: Robert Hooker Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 8 ++++++ drivers/gpu/drm/i915/intel_display.c | 40 ++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5d5def756c9..27e0e93a6ae 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2544,10 +2544,18 @@ #define _CURBBASE 0x700c4 #define _CURBPOS 0x700c8 +#define _CURBCNTR_IVB 0x71080 +#define _CURBBASE_IVB 0x71084 +#define _CURBPOS_IVB 0x71088 + #define CURCNTR(pipe) _PIPE(pipe, _CURACNTR, _CURBCNTR) #define CURBASE(pipe) _PIPE(pipe, _CURABASE, _CURBBASE) #define CURPOS(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS) +#define CURCNTR_IVB(pipe) _PIPE(pipe, _CURACNTR, _CURBCNTR_IVB) +#define CURBASE_IVB(pipe) _PIPE(pipe, _CURABASE, _CURBBASE_IVB) +#define CURPOS_IVB(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS_IVB) + /* Display A control */ #define _DSPACNTR 0x70180 #define DISPLAY_PLANE_ENABLE (1<<31) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cbf4c4ce3a2..d08a6002d0e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5334,6 +5334,31 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base) I915_WRITE(CURBASE(pipe), base); } +static void ivb_update_cursor(struct drm_crtc *crtc, u32 base) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + int pipe = intel_crtc->pipe; + bool visible = base != 0; + + if (intel_crtc->cursor_visible != visible) { + uint32_t cntl = I915_READ(CURCNTR_IVB(pipe)); + if (base) { + cntl &= ~CURSOR_MODE; + cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; + } else { + cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); + cntl |= CURSOR_MODE_DISABLE; + } + I915_WRITE(CURCNTR_IVB(pipe), cntl); + + intel_crtc->cursor_visible = visible; + } + /* and commit changes on next vblank */ + I915_WRITE(CURBASE_IVB(pipe), base); +} + /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */ static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on) @@ -5381,11 +5406,16 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc, if (!visible && !intel_crtc->cursor_visible) return; - I915_WRITE(CURPOS(pipe), pos); - if (IS_845G(dev) || IS_I865G(dev)) - i845_update_cursor(crtc, base); - else - i9xx_update_cursor(crtc, base); + if (IS_IVYBRIDGE(dev)) { + I915_WRITE(CURPOS_IVB(pipe), pos); + ivb_update_cursor(crtc, base); + } else { + I915_WRITE(CURPOS(pipe), pos); + if (IS_845G(dev) || IS_I865G(dev)) + i845_update_cursor(crtc, base); + else + i9xx_update_cursor(crtc, base); + } if (visible) intel_mark_busy(dev, to_intel_framebuffer(crtc->fb)->obj); From 49b3e19e8062ab93b1c313e6c7934ff5987426c7 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Mon, 10 Oct 2011 14:28:52 -0700 Subject: [PATCH 0344/4025] drm/i915: always set FDI composite sync bit commit c4f9c4c2b3f1831e932e04db992cf6fe92c2a95a upstream. It's needed for 3 pipe support as well as just regular functionality (e.g. DisplayPort). Signed-off-by: Jesse Barnes Tested-by: Adam Jackson Tested-by: Eugeni Dodonov Signed-off-by: Keith Packard Signed-off-by: Robert Hooker Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 27e0e93a6ae..8936d40d225 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3141,6 +3141,7 @@ #define FDI_LINK_TRAIN_NONE_IVB (3<<8) /* both Tx and Rx */ +#define FDI_COMPOSITE_SYNC (1<<11) #define FDI_LINK_TRAIN_AUTO (1<<10) #define FDI_SCRAMBLING_ENABLE (0<<7) #define FDI_SCRAMBLING_DISABLE (1<<7) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d08a6002d0e..853bddb96ea 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2340,6 +2340,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) temp |= FDI_LINK_TRAIN_PATTERN_1_IVB; temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; + temp |= FDI_COMPOSITE_SYNC; I915_WRITE(reg, temp | FDI_TX_ENABLE); reg = FDI_RX_CTL(pipe); @@ -2347,6 +2348,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) temp &= ~FDI_LINK_TRAIN_AUTO; temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; temp |= FDI_LINK_TRAIN_PATTERN_1_CPT; + temp |= FDI_COMPOSITE_SYNC; I915_WRITE(reg, temp | FDI_RX_ENABLE); POSTING_READ(reg); From 7a576d2dcd5807a7310032b380442eeba8c1c293 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 26 Nov 2011 09:11:26 -0800 Subject: [PATCH 0345/4025] Linux 3.0.11 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 36036d13433..eaa96c50147 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 10 +SUBLEVEL = 11 EXTRAVERSION = NAME = Sneaky Weasel From eb89536db55afc262a59e493a76b521c5c7ad89e Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 29 Nov 2011 07:38:25 +0900 Subject: [PATCH 0346/4025] Revert "USB: EHCI: fix HUB TT scheduling issue with iso transfer" This reverts commit 317451c11fefcb0e05383f0a0080bb7f5445cfcf. Cc: Matthieu Castet Cc: Thomas Poussevin Cc: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index fb2d0c2f067..063c630d246 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1483,15 +1483,10 @@ iso_stream_schedule ( /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ - /* find a uframe slot with enough bandwidth. - * Early uframes are more precious because full-speed - * iso IN transfers can't use late uframes, - * and therefore they should be allocated last. - */ - next = start; - start += period; - do { - start--; + /* find a uframe slot with enough bandwidth */ + next = start + period; + for (; start < next; start++) { + /* check schedule: enough space? */ if (stream->highspeed) { if (itd_slot_ok(ehci, mod, start, @@ -1504,7 +1499,7 @@ iso_stream_schedule ( start, sched, period)) break; } - } while (start > next); + } /* no room in the schedule */ if (start == next) { From ac6766564c0305ca020fe747dfd7dbdf0881369d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 29 Nov 2011 07:47:43 +0900 Subject: [PATCH 0347/4025] Linux 3.0.12 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index eaa96c50147..993fe0563e4 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 11 +SUBLEVEL = 12 EXTRAVERSION = NAME = Sneaky Weasel From dbb18fb2c1519b7810018580ee5123f9be73f213 Mon Sep 17 00:00:00 2001 From: "hyungseoung.yoo" Date: Fri, 18 Nov 2011 13:57:01 +0900 Subject: [PATCH 0348/4025] Bluetooth: Keep master role when SCO or eSCO is active This improves compatbility with a lot of headset / chipset combinations. Ideally this should not be needed. Change-Id: I8b676701e12e416aa7d60801b9d353b15d102709 Signed-off-by: hyungseoung.yoo Signed-off-by: Jaikumar Ganesh --- net/bluetooth/hci_event.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) mode change 100644 => 100755 net/bluetooth/hci_event.c diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c old mode 100644 new mode 100755 index a32571a22bb..5a7074a7b5b --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1462,6 +1462,15 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s hci_conn_check_pending(hdev); } +static inline bool is_sco_active(struct hci_dev *hdev) +{ + if (hci_conn_hash_lookup_state(hdev, SCO_LINK, BT_CONNECTED) || + (hci_conn_hash_lookup_state(hdev, ESCO_LINK, + BT_CONNECTED))) + return true; + return false; +} + static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_request *ev = (void *) skb->data; @@ -1505,7 +1514,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk bacpy(&cp.bdaddr, &ev->bdaddr); - if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) + if (lmp_rswitch_capable(hdev) && ((mask & HCI_LM_MASTER) + || is_sco_active(hdev))) cp.role = 0x00; /* Become master */ else cp.role = 0x01; /* Remain slave */ From 6a4a38525d60db7e915d559273d8c89db5a98edf Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Mon, 28 Nov 2011 18:01:03 -0800 Subject: [PATCH 0349/4025] usb: gadget: android: Reset next_string_id before enable Reset next_string_id to 0 before enabling the gadget driver. Otherwise, after a large number of enable/disable cycles, bind will fail because we cannot allocate new string ids. String ids cannot be larger than 254 per USB spec. Change-Id: I44f5fece45008b7a0a18c025d4eb5ce842585c28 Signed-off-by: Benoit Goby --- drivers/usb/gadget/android.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index d109bfb02f3..5d77899678f 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -823,6 +823,7 @@ static ssize_t enable_store(struct device *pdev, struct device_attribute *attr, sscanf(buff, "%d", &enabled); if (enabled && !dev->enabled) { + cdev->next_string_id = 0; /* update values in composite driver's copy of device descriptor */ cdev->desc.idVendor = device_desc.idVendor; cdev->desc.idProduct = device_desc.idProduct; From b86fd0b62252fbba6a5d6acda09fd325fb8e201b Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Tue, 29 Nov 2011 16:37:07 -0800 Subject: [PATCH 0350/4025] ARM: idle: call idle notifiers before stopping nohz tick If an idle notifier modifies a timer, calling the notifier after the sched tick has been stopped may leave the sched tick set too early. Move teh idle notifier call before the call to tick_nohz_stop_sched_tick. Change-Id: I0db3284bec6d0193bc5e2a57650ab06bd8342319 Signed-off-by: Colin Cross --- arch/arm/kernel/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 54c97eee617..7d66a6e66cb 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -223,8 +223,8 @@ void cpu_idle(void) /* endless idle loop with no priority at all */ while (1) { - tick_nohz_stop_sched_tick(1); idle_notifier_call_chain(IDLE_START); + tick_nohz_stop_sched_tick(1); while (!need_resched()) { #ifdef CONFIG_HOTPLUG_CPU if (cpu_is_offline(smp_processor_id())) From e0de0a507d83e84c833d01de9e46a44b12419431 Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Tue, 29 Nov 2011 13:49:27 -0800 Subject: [PATCH 0351/4025] usb: gadget: android: Cancel pending ctrlrequest before disabling Make sure there is no pending ctrlrequest before removing the config. Otherwise the ctrlrequest complete callback could access structures after they have been freed. Unbind cancels pending transfers but not ep0 requests. Bug: 5513065 5440193 Change-Id: I063c22bf5d104a3d2df71cf622409459fac5f27a Signed-off-by: Benoit Goby --- drivers/usb/gadget/android.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 5d77899678f..2b7631052ea 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -837,6 +837,8 @@ static ssize_t enable_store(struct device *pdev, struct device_attribute *attr, dev->enabled = true; } else if (!enabled && dev->enabled) { usb_gadget_disconnect(cdev->gadget); + /* Cancel pending control requests */ + usb_ep_dequeue(cdev->gadget->ep0, cdev->req); usb_remove_config(cdev, &android_config_driver); dev->enabled = false; } else { From 051726ea7a7d39c03cb5653c962b0b6f47b5cc37 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Mon, 21 Nov 2011 17:31:29 -0600 Subject: [PATCH 0352/4025] eCryptfs: Flush file in vma close commit 32001d6fe9ac6b0423e674a3093aa56740849f3b upstream. Dirty pages weren't being written back when an mmap'ed eCryptfs file was closed before the mapping was unmapped. Since f_ops->flush() is not called by the munmap() path, the lower file was simply being released. This patch flushes the eCryptfs file in the vm_ops->close() path. https://launchpad.net/bugs/870326 Signed-off-by: Tyler Hicks Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/file.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index 4ec9eb00a24..0c1a6527004 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -139,6 +139,27 @@ static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir) return rc; } +static void ecryptfs_vma_close(struct vm_area_struct *vma) +{ + filemap_write_and_wait(vma->vm_file->f_mapping); +} + +static const struct vm_operations_struct ecryptfs_file_vm_ops = { + .close = ecryptfs_vma_close, + .fault = filemap_fault, +}; + +static int ecryptfs_file_mmap(struct file *file, struct vm_area_struct *vma) +{ + int rc; + + rc = generic_file_mmap(file, vma); + if (!rc) + vma->vm_ops = &ecryptfs_file_vm_ops; + + return rc; +} + struct kmem_cache *ecryptfs_file_info_cache; /** @@ -348,7 +369,7 @@ const struct file_operations ecryptfs_main_fops = { #ifdef CONFIG_COMPAT .compat_ioctl = ecryptfs_compat_ioctl, #endif - .mmap = generic_file_mmap, + .mmap = ecryptfs_file_mmap, .open = ecryptfs_open, .flush = ecryptfs_flush, .release = ecryptfs_release, From e8cb7517f0bfa7cdc6dd91d244f95bdcecd5589c Mon Sep 17 00:00:00 2001 From: "Jeffrey (Sheng-Hui) Chu" Date: Wed, 23 Nov 2011 11:33:07 +0100 Subject: [PATCH 0353/4025] i2c-algo-bit: Generate correct i2c address sequence for 10-bit target commit cc6bcf7d2ec2234e7b41770185e4dc826390185e upstream. The wrong bits were put on the wire, fix that. This fixes kernel bug #42562. Signed-off-by: Sheng-Hui J. Chu Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/algos/i2c-algo-bit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index d6d58684712..eca3bcc4599 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -486,7 +486,7 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) if (flags & I2C_M_TEN) { /* a ten bit address */ - addr = 0xf0 | ((msg->addr >> 7) & 0x03); + addr = 0xf0 | ((msg->addr >> 7) & 0x06); bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr); /* try extended address code...*/ ret = try_address(i2c_adap, addr, retries); @@ -496,7 +496,7 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) return -EREMOTEIO; } /* the remaining 8 bit address */ - ret = i2c_outb(i2c_adap, msg->addr & 0x7f); + ret = i2c_outb(i2c_adap, msg->addr & 0xff); if ((ret != 1) && !nak_ok) { /* the chip did not ack / xmission error occurred */ dev_err(&i2c_adap->dev, "died at 2nd address code\n"); From 4d15dcb0e249cd9834afc9b44d674dbd9eb57116 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Wed, 23 Nov 2011 11:31:24 -0600 Subject: [PATCH 0354/4025] eCryptfs: Extend array bounds for all filename chars commit 0f751e641a71157aa584c2a2e22fda52b52b8a56 upstream. From mhalcrow's original commit message: Characters with ASCII values greater than the size of filename_rev_map[] are valid filename characters. ecryptfs_decode_from_filename() will access kernel memory beyond that array, and ecryptfs_parse_tag_70_packet() will then decrypt those characters. The attacker, using the FNEK of the crafted file, can then re-encrypt the characters to reveal the kernel memory past the end of the filename_rev_map[] array. I expect low security impact since this array is statically allocated in the text area, and the amount of memory past the array that is accessible is limited by the largest possible ASCII filename character. This patch solves the issue reported by mhalcrow but with an implementation suggested by Linus to simply extend the length of filename_rev_map[] to 256. Characters greater than 0x7A are mapped to 0x00, which is how invalid characters less than 0x7A were previously being handled. Signed-off-by: Tyler Hicks Reported-by: Michael Halcrow Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/crypto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 58609bde3b9..7cf5c3e9c17 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -1943,7 +1943,7 @@ static unsigned char *portable_filename_chars = ("-.0123456789ABCD" /* We could either offset on every reverse map or just pad some 0x00's * at the front here */ -static const unsigned char filename_rev_map[] = { +static const unsigned char filename_rev_map[256] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 7 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 15 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 23 */ @@ -1959,7 +1959,7 @@ static const unsigned char filename_rev_map[] = { 0x00, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, /* 103 */ 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, /* 111 */ 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, /* 119 */ - 0x3D, 0x3E, 0x3F + 0x3D, 0x3E, 0x3F /* 123 - 255 initialized to 0x00 */ }; /** From e84ce11bd0183328e00accb611893b9a819dc0ba Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 16 Nov 2011 18:28:01 +0100 Subject: [PATCH 0355/4025] crypto: mv_cesa - fix hashing of chunks > 1920 bytes commit 274252862f386b7868f35bf5ceaa5391a8ccfdf3 upstream. This was broken by commit 7759995c75ae0cbd4c861582908449f6b6208e7a (yes, myself). The basic problem here is since the digest state is only saved after the last chunk, the state array is only valid when handling the first chunk of the next buffer. Broken since linux-3.0. Signed-off-by: Phil Sutter Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/mv_cesa.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index 3cf303ee3fe..38a3297ae2b 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -342,11 +342,13 @@ static void mv_process_hash_current(int first_block) else op.config |= CFG_MID_FRAG; - writel(req_ctx->state[0], cpg->reg + DIGEST_INITIAL_VAL_A); - writel(req_ctx->state[1], cpg->reg + DIGEST_INITIAL_VAL_B); - writel(req_ctx->state[2], cpg->reg + DIGEST_INITIAL_VAL_C); - writel(req_ctx->state[3], cpg->reg + DIGEST_INITIAL_VAL_D); - writel(req_ctx->state[4], cpg->reg + DIGEST_INITIAL_VAL_E); + if (first_block) { + writel(req_ctx->state[0], cpg->reg + DIGEST_INITIAL_VAL_A); + writel(req_ctx->state[1], cpg->reg + DIGEST_INITIAL_VAL_B); + writel(req_ctx->state[2], cpg->reg + DIGEST_INITIAL_VAL_C); + writel(req_ctx->state[3], cpg->reg + DIGEST_INITIAL_VAL_D); + writel(req_ctx->state[4], cpg->reg + DIGEST_INITIAL_VAL_E); + } } memcpy(cpg->sram + SRAM_CONFIG, &op, sizeof(struct sec_accel_config)); From 61aff74833b86c735ee901c1038f0cbfcd606ae7 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Wed, 23 Nov 2011 01:12:01 -0500 Subject: [PATCH 0356/4025] drm: integer overflow in drm_mode_dirtyfb_ioctl() commit a5cd335165e31db9dbab636fd29895d41da55dd2 upstream. There is a potential integer overflow in drm_mode_dirtyfb_ioctl() if userspace passes in a large num_clips. The call to kmalloc would allocate a small buffer, and the call to fb->funcs->dirty may result in a memory corruption. Reported-by: Haogang Chen Signed-off-by: Xi Wang Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_crtc.c | 4 ++++ include/drm/drm_mode.h | 2 ++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 82db1850666..1367ced8c26 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1866,6 +1866,10 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, } if (num_clips && clips_ptr) { + if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { + ret = -EINVAL; + goto out_err1; + } clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL); if (!clips) { ret = -ENOMEM; diff --git a/include/drm/drm_mode.h b/include/drm/drm_mode.h index c4961ea50a4..53dfa1098b9 100644 --- a/include/drm/drm_mode.h +++ b/include/drm/drm_mode.h @@ -233,6 +233,8 @@ struct drm_mode_fb_cmd { #define DRM_MODE_FB_DIRTY_ANNOTATE_FILL 0x02 #define DRM_MODE_FB_DIRTY_FLAGS 0x03 +#define DRM_MODE_FB_DIRTY_MAX_CLIPS 256 + /* * Mark a region of a framebuffer as dirty. * From 1b0f670a0a181c8e222d3d8c512e7374c8e87eb2 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 21 Nov 2011 12:10:14 -0500 Subject: [PATCH 0357/4025] drm/radeon/kms: fix up gpio i2c mask bits for r4xx for real commit d724502a9d7a46f4a56a1663b1f50d2dc9d1ef40 upstream. Fixes i2c test failures when i2c_algo_bit.bit_test=1. The hw doesn't actually require a mask, so just set it to the default mask bits for r1xx-r4xx radeon ddc. I missed this part the first time through. Signed-off-by: Alex Deucher Cc: Jean Delvare Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_atombios.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index bf2b61584cd..9d996c6d4cb 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -169,6 +169,18 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev) gpio = &i2c_info->asGPIO_Info[i]; i2c.valid = false; + /* r4xx mask is technically not used by the hw, so patch in the legacy mask bits */ + if ((rdev->family == CHIP_R420) || + (rdev->family == CHIP_R423) || + (rdev->family == CHIP_RV410)) { + if ((le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0018) || + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0019) || + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x001a)) { + gpio->ucClkMaskShift = 0x19; + gpio->ucDataMaskShift = 0x18; + } + } + /* some evergreen boards have bad data for this entry */ if (ASIC_IS_DCE4(rdev)) { if ((i == 7) && From a00931691a6f42ddfd8e677ba30b4dbfa705b47b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 9 Oct 2011 21:52:01 +0200 Subject: [PATCH 0358/4025] drm/i915: Ivybridge still has fences! commit 775d17b6ca4357048f36c22151335addfe15db4b upstream. So don't forget to restore them on resume and dump them into the error state. Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Signed-off-by: Keith Packard Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_irq.c | 1 + drivers/gpu/drm/i915/i915_suspend.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 9b1d669f7d4..363564704b1 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -820,6 +820,7 @@ static void i915_gem_record_fences(struct drm_device *dev, /* Fences */ switch (INTEL_INFO(dev)->gen) { + case 7: case 6: for (i = 0; i < 16; i++) error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 27693c05c6d..cf15533aabf 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -370,6 +370,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) /* Fences */ switch (INTEL_INFO(dev)->gen) { + case 7: case 6: for (i = 0; i < 16; i++) dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); @@ -404,6 +405,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) /* Fences */ switch (INTEL_INFO(dev)->gen) { + case 7: case 6: for (i = 0; i < 16; i++) I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->saveFENCE[i]); From d37e37738433032fd7206b238c49c73969afc283 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 7 Nov 2011 16:07:04 -0800 Subject: [PATCH 0359/4025] drm/i915: Turn on a required 3D clock gating bit on Sandybridge. commit 406478dc911e16677fbd9c84d1d50cdffbc031ab upstream. Fixes rendering failures in Unigine Tropics and Sanctuary and the mesa "fire" demo. Signed-off-by: Eric Anholt Signed-off-by: Keith Packard Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_display.c | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8936d40d225..fb87b3c9d38 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3370,6 +3370,9 @@ #define GT_FIFO_FREE_ENTRIES 0x120008 +#define GEN6_UCGCTL2 0x9404 +# define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE (1 << 12) + #define GEN6_RPNSWREQ 0xA008 #define GEN6_TURBO_DISABLE (1<<31) #define GEN6_FREQUENCY(x) ((x)<<25) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 853bddb96ea..6e1165a436e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7405,6 +7405,15 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0); + /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock + * gating disable must be set. Failure to set it results in + * flickering pixels due to Z write ordering failures after + * some amount of runtime in the Mesa "fire" demo, and Unigine + * Sanctuary and Tropics, and apparently anything else with + * alpha test or pixel discard. + */ + I915_WRITE(GEN6_UCGCTL2, GEN6_RCPBUNIT_CLOCK_GATE_DISABLE); + /* * According to the spec the following bits should be * set in order to enable memory self-refresh and fbc: From 6d7f52a7e695b4a6d2ba32e477d283626bfbec00 Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Mon, 7 Nov 2011 16:07:05 -0800 Subject: [PATCH 0360/4025] drm/i915: Turn on another required clock gating bit on gen6. commit 9ca1d10d748e56964de95e3ed80211b192f56cf4 upstream. Unlike the previous one, I don't have known testcases it fixes. I'd rather not go through the same debug cycle on whatever testcases those might be. Signed-off-by: Eric Anholt Signed-off-by: Keith Packard Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index fb87b3c9d38..673f0d2cd4e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3372,6 +3372,7 @@ #define GEN6_UCGCTL2 0x9404 # define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE (1 << 12) +# define GEN6_RCCUNIT_CLOCK_GATE_DISABLE (1 << 11) #define GEN6_RPNSWREQ 0xA008 #define GEN6_TURBO_DISABLE (1<<31) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6e1165a436e..3976909b5dc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7411,8 +7411,13 @@ static void gen6_init_clock_gating(struct drm_device *dev) * some amount of runtime in the Mesa "fire" demo, and Unigine * Sanctuary and Tropics, and apparently anything else with * alpha test or pixel discard. + * + * According to the spec, bit 11 (RCCUNIT) must also be set, + * but we didn't debug actual testcases to find it out. */ - I915_WRITE(GEN6_UCGCTL2, GEN6_RCPBUNIT_CLOCK_GATE_DISABLE); + I915_WRITE(GEN6_UCGCTL2, + GEN6_RCPBUNIT_CLOCK_GATE_DISABLE | + GEN6_RCCUNIT_CLOCK_GATE_DISABLE); /* * According to the spec the following bits should be From 8215014c1d9d78ef14260a46ee2a136acc3d283a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 14 Sep 2011 06:08:06 +1000 Subject: [PATCH 0361/4025] drm/ttm: request zeroed system memory pages for new TT buffer objects commit ff02b13f6867af72682d7a9bb9bd705f9af2bab0 upstream. Fixes an information leak to userspace, we were handing out un-zeroed pages for any newly created TTM_PL_TT buffer. Reported-by: Marcin Slusarz Signed-off-by: Ben Skeggs Tested-by: Marcin Slusarz Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/ttm/ttm_bo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index e2b2d786687..81b68508dc1 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -394,7 +394,8 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) { if (bo->ttm == NULL) { - ret = ttm_bo_add_ttm(bo, false); + bool zero = !(old_man->flags & TTM_MEMTYPE_FLAG_FIXED); + ret = ttm_bo_add_ttm(bo, zero); if (ret) goto out_err; } From ed3035ddf88840f6e8355281e74b2b0bb9c93da0 Mon Sep 17 00:00:00 2001 From: Jesse Barnes Date: Thu, 28 Jul 2011 14:50:30 -0700 Subject: [PATCH 0362/4025] drm/i915: fix CB tuning check for ILK+ commit cb0e093162d7b6589c2217a00e2abfef686b32d6 upstream. CB tuning is needed to handle potential process variations that might cause clock jitter for certain PLL settings. However, we were setting it incorrectly since we were using the wrong M value as a check (M1 when we needed to use the whole M value). Fix it up, making my HDMI attached display a little prettier (used to have occasional dots crawl across the display). Signed-off-by: Jesse Barnes Signed-off-by: Keith Packard Signed-off-by: Timo Aaltonen Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3976909b5dc..fed87d6a5b9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4972,7 +4972,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, } else if (is_sdvo && is_tv) factor = 20; - if (clock.m1 < factor * clock.n) + if (clock.m < factor * clock.n) fp |= FP_CB_TUNE; dpll = 0; From 6717ca81e2dc5fafd8d37025465d4ba851237342 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 23 Aug 2011 10:16:43 -0600 Subject: [PATCH 0363/4025] PCI hotplug: shpchp: don't blindly claim non-AMD 0x7450 device IDs commit 4cac2eb158c6da0c761689345c6cc5df788a6292 upstream. Previously we claimed device ID 0x7450, regardless of the vendor, which is clearly wrong. Now we'll claim that device ID only for AMD. I suspect this was just a typo in the original code, but it's possible this change will break shpchp on non-7450 AMD bridges. If so, we'll have to fix them as we find them. Reference: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=638863 Reported-by: Ralf Jung Cc: Joerg Roedel Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/shpchp_core.c | 4 ++-- drivers/pci/hotplug/shpchp_hpc.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index aca972bbfb4..dd7e0c51a33 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -278,8 +278,8 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) static int is_shpc_capable(struct pci_dev *dev) { - if ((dev->vendor == PCI_VENDOR_ID_AMD) || (dev->device == - PCI_DEVICE_ID_AMD_GOLAM_7450)) + if (dev->vendor == PCI_VENDOR_ID_AMD && + dev->device == PCI_DEVICE_ID_AMD_GOLAM_7450) return 1; if (!pci_find_capability(dev, PCI_CAP_ID_SHPC)) return 0; diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 36547f0ce30..75ba2311b54 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -944,8 +944,8 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ ctrl_dbg(ctrl, "Hotplug Controller:\n"); - if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device == - PCI_DEVICE_ID_AMD_GOLAM_7450)) { + if (pdev->vendor == PCI_VENDOR_ID_AMD && + pdev->device == PCI_DEVICE_ID_AMD_GOLAM_7450) { /* amd shpc driver doesn't use Base Offset; assume 0 */ ctrl->mmio_base = pci_resource_start(pdev, 0); ctrl->mmio_size = pci_resource_len(pdev, 0); From ff17063daf7bcf76ee1b1cc59e20ae725affc555 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 14 Nov 2011 14:32:01 -0500 Subject: [PATCH 0364/4025] drm/radeon/kms: fix up gpio i2c mask bits for r4xx commit 6c47e5c23aa2a7c54ad7ac13af4bd56cd9e703bf upstream. Fixes i2c test failures when i2c_algo_bit.bit_test=1. The hw doesn't actually require a mask, so just set it to the default mask bits for r1xx-r4xx radeon ddc. Signed-off-by: Alex Deucher Cc: Jean Delvare Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_atombios.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 9d996c6d4cb..285acc4f1e1 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -85,6 +85,18 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev for (i = 0; i < num_indices; i++) { gpio = &i2c_info->asGPIO_Info[i]; + /* r4xx mask is technically not used by the hw, so patch in the legacy mask bits */ + if ((rdev->family == CHIP_R420) || + (rdev->family == CHIP_R423) || + (rdev->family == CHIP_RV410)) { + if ((le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0018) || + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0019) || + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x001a)) { + gpio->ucClkMaskShift = 0x19; + gpio->ucDataMaskShift = 0x18; + } + } + /* some evergreen boards have bad data for this entry */ if (ASIC_IS_DCE4(rdev)) { if ((i == 7) && From 47b52de3faa57f5849c71bdaee4cd041debcc1ff Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 21 Nov 2011 15:05:56 +0000 Subject: [PATCH 0365/4025] viafb: correct sync polarity for OLPC DCON commit a32839696a8eef813a1aff604fbad9a32dff6c95 upstream. While the OLPC display appears to be able to handle either positive or negative sync, the Display Controller only recognises positive sync. This brings viafb (for XO-1.5) in line with lxfb (for XO-1) and fixes a recent regression where the XO-1.5 DCON could no longer be frozen. Thanks to Florian Tobias Schandinat for helping identify the fix. Test case: from a vt, echo 1 > /sys/devices/platform/dcon/freeze should cause the current screen contents to freeze, rather than garbage being displayed. Signed-off-by: Daniel Drake Signed-off-by: Florian Tobias Schandinat Signed-off-by: Greg Kroah-Hartman --- drivers/video/via/share.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h index 61b0bd596b8..1603023e3aa 100644 --- a/drivers/video/via/share.h +++ b/drivers/video/via/share.h @@ -557,8 +557,8 @@ #define M1200X720_R60_VSP POSITIVE /* 1200x900@60 Sync Polarity (DCON) */ -#define M1200X900_R60_HSP NEGATIVE -#define M1200X900_R60_VSP NEGATIVE +#define M1200X900_R60_HSP POSITIVE +#define M1200X900_R60_VSP POSITIVE /* 1280x600@60 Sync Polarity (GTF Mode) */ #define M1280x600_R60_HSP NEGATIVE From bfbcb8185dfbb5a9ecaa09bb816a96740e104c0f Mon Sep 17 00:00:00 2001 From: Haojian Zhuang Date: Thu, 10 Nov 2011 07:13:07 +0800 Subject: [PATCH 0366/4025] ARM: pxa: fix inconsistent CONFIG_USB_PXA27X commit c0a39151a4055332897cba615623d3de2f3896df upstream. Since CONFIG_USB_GADGET_PXA27X and other macros are renamed to CONFIG_USB_PXA27X. Update them in arch/arm/mach-pxa and arch/arm/configs to keep consistent. Signed-off-by: Haojian Zhuang Acked-by: Felipe Balbi Signed-off-by: Eric Miao Signed-off-by: Greg Kroah-Hartman --- arch/arm/configs/ezx_defconfig | 2 +- arch/arm/configs/imote2_defconfig | 2 +- arch/arm/configs/magician_defconfig | 2 +- arch/arm/configs/zeus_defconfig | 2 +- arch/arm/mach-pxa/balloon3.c | 2 +- arch/arm/mach-pxa/colibri-pxa320.c | 2 +- arch/arm/mach-pxa/gumstix.c | 2 +- arch/arm/mach-pxa/include/mach/palm27x.h | 4 ++-- arch/arm/mach-pxa/palm27x.c | 4 ++-- arch/arm/mach-pxa/palmtc.c | 2 +- arch/arm/mach-pxa/vpac270.c | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arm/configs/ezx_defconfig b/arch/arm/configs/ezx_defconfig index 227a477346e..d95763d5f0d 100644 --- a/arch/arm/configs/ezx_defconfig +++ b/arch/arm/configs/ezx_defconfig @@ -287,7 +287,7 @@ CONFIG_USB=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_OHCI_HCD=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_PXA27X=y +CONFIG_USB_PXA27X=y CONFIG_USB_ETH=m # CONFIG_USB_ETH_RNDIS is not set CONFIG_MMC=y diff --git a/arch/arm/configs/imote2_defconfig b/arch/arm/configs/imote2_defconfig index 176ec22af03..fd996bb1302 100644 --- a/arch/arm/configs/imote2_defconfig +++ b/arch/arm/configs/imote2_defconfig @@ -263,7 +263,7 @@ CONFIG_USB=y # CONFIG_USB_DEVICE_CLASS is not set CONFIG_USB_OHCI_HCD=y CONFIG_USB_GADGET=y -CONFIG_USB_GADGET_PXA27X=y +CONFIG_USB_PXA27X=y CONFIG_USB_ETH=m # CONFIG_USB_ETH_RNDIS is not set CONFIG_MMC=y diff --git a/arch/arm/configs/magician_defconfig b/arch/arm/configs/magician_defconfig index a88e64d4e9a..443675d317e 100644 --- a/arch/arm/configs/magician_defconfig +++ b/arch/arm/configs/magician_defconfig @@ -132,7 +132,7 @@ CONFIG_USB_MON=m CONFIG_USB_OHCI_HCD=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=500 -CONFIG_USB_GADGET_PXA27X=y +CONFIG_USB_PXA27X=y CONFIG_USB_ETH=m # CONFIG_USB_ETH_RNDIS is not set CONFIG_USB_GADGETFS=m diff --git a/arch/arm/configs/zeus_defconfig b/arch/arm/configs/zeus_defconfig index 59577ad3f4e..547a3c1e59d 100644 --- a/arch/arm/configs/zeus_defconfig +++ b/arch/arm/configs/zeus_defconfig @@ -140,7 +140,7 @@ CONFIG_USB_SERIAL=m CONFIG_USB_SERIAL_GENERIC=y CONFIG_USB_SERIAL_MCT_U232=m CONFIG_USB_GADGET=m -CONFIG_USB_GADGET_PXA27X=y +CONFIG_USB_PXA27X=y CONFIG_USB_ETH=m CONFIG_USB_GADGETFS=m CONFIG_USB_FILE_STORAGE=m diff --git a/arch/arm/mach-pxa/balloon3.c b/arch/arm/mach-pxa/balloon3.c index 810a982a66f..6ca327d956e 100644 --- a/arch/arm/mach-pxa/balloon3.c +++ b/arch/arm/mach-pxa/balloon3.c @@ -307,7 +307,7 @@ static inline void balloon3_mmc_init(void) {} /****************************************************************************** * USB Gadget ******************************************************************************/ -#if defined(CONFIG_USB_GADGET_PXA27X)||defined(CONFIG_USB_GADGET_PXA27X_MODULE) +#if defined(CONFIG_USB_PXA27X)||defined(CONFIG_USB_PXA27X_MODULE) static void balloon3_udc_command(int cmd) { if (cmd == PXA2XX_UDC_CMD_CONNECT) diff --git a/arch/arm/mach-pxa/colibri-pxa320.c b/arch/arm/mach-pxa/colibri-pxa320.c index ff9ff5f4fc4..fdf611cdacc 100644 --- a/arch/arm/mach-pxa/colibri-pxa320.c +++ b/arch/arm/mach-pxa/colibri-pxa320.c @@ -147,7 +147,7 @@ static void __init colibri_pxa320_init_eth(void) static inline void __init colibri_pxa320_init_eth(void) {} #endif /* CONFIG_AX88796 */ -#if defined(CONFIG_USB_GADGET_PXA27X)||defined(CONFIG_USB_GADGET_PXA27X_MODULE) +#if defined(CONFIG_USB_PXA27X)||defined(CONFIG_USB_PXA27X_MODULE) static struct gpio_vbus_mach_info colibri_pxa320_gpio_vbus_info = { .gpio_vbus = mfp_to_gpio(MFP_PIN_GPIO96), .gpio_pullup = -1, diff --git a/arch/arm/mach-pxa/gumstix.c b/arch/arm/mach-pxa/gumstix.c index d65e4bde9b9..b9e8233ac48 100644 --- a/arch/arm/mach-pxa/gumstix.c +++ b/arch/arm/mach-pxa/gumstix.c @@ -106,7 +106,7 @@ static void __init gumstix_mmc_init(void) } #endif -#ifdef CONFIG_USB_GADGET_PXA25X +#ifdef CONFIG_USB_PXA25X static struct gpio_vbus_mach_info gumstix_udc_info = { .gpio_vbus = GPIO_GUMSTIX_USB_GPIOn, .gpio_pullup = GPIO_GUMSTIX_USB_GPIOx, diff --git a/arch/arm/mach-pxa/include/mach/palm27x.h b/arch/arm/mach-pxa/include/mach/palm27x.h index 0a5e5eadebf..8d560437e6e 100644 --- a/arch/arm/mach-pxa/include/mach/palm27x.h +++ b/arch/arm/mach-pxa/include/mach/palm27x.h @@ -37,8 +37,8 @@ extern void __init palm27x_lcd_init(int power, static inline void palm27x_lcd_init(int power, struct pxafb_mode_info *mode) {} #endif -#if defined(CONFIG_USB_GADGET_PXA27X) || \ - defined(CONFIG_USB_GADGET_PXA27X_MODULE) +#if defined(CONFIG_USB_PXA27X) || \ + defined(CONFIG_USB_PXA27X_MODULE) extern void __init palm27x_udc_init(int vbus, int pullup, int vbus_inverted); #else diff --git a/arch/arm/mach-pxa/palm27x.c b/arch/arm/mach-pxa/palm27x.c index 325c245c0a0..fbc10d7b95d 100644 --- a/arch/arm/mach-pxa/palm27x.c +++ b/arch/arm/mach-pxa/palm27x.c @@ -164,8 +164,8 @@ void __init palm27x_lcd_init(int power, struct pxafb_mode_info *mode) /****************************************************************************** * USB Gadget ******************************************************************************/ -#if defined(CONFIG_USB_GADGET_PXA27X) || \ - defined(CONFIG_USB_GADGET_PXA27X_MODULE) +#if defined(CONFIG_USB_PXA27X) || \ + defined(CONFIG_USB_PXA27X_MODULE) static struct gpio_vbus_mach_info palm27x_udc_info = { .gpio_vbus_inverted = 1, }; diff --git a/arch/arm/mach-pxa/palmtc.c b/arch/arm/mach-pxa/palmtc.c index fb06bd04727..5193ce27b92 100644 --- a/arch/arm/mach-pxa/palmtc.c +++ b/arch/arm/mach-pxa/palmtc.c @@ -339,7 +339,7 @@ static inline void palmtc_mkp_init(void) {} /****************************************************************************** * UDC ******************************************************************************/ -#if defined(CONFIG_USB_GADGET_PXA25X)||defined(CONFIG_USB_GADGET_PXA25X_MODULE) +#if defined(CONFIG_USB_PXA25X)||defined(CONFIG_USB_PXA25X_MODULE) static struct gpio_vbus_mach_info palmtc_udc_info = { .gpio_vbus = GPIO_NR_PALMTC_USB_DETECT_N, .gpio_vbus_inverted = 1, diff --git a/arch/arm/mach-pxa/vpac270.c b/arch/arm/mach-pxa/vpac270.c index 67bd41488bf..10b80d47393 100644 --- a/arch/arm/mach-pxa/vpac270.c +++ b/arch/arm/mach-pxa/vpac270.c @@ -343,7 +343,7 @@ static inline void vpac270_uhc_init(void) {} /****************************************************************************** * USB Gadget ******************************************************************************/ -#if defined(CONFIG_USB_GADGET_PXA27X)||defined(CONFIG_USB_GADGET_PXA27X_MODULE) +#if defined(CONFIG_USB_PXA27X)||defined(CONFIG_USB_PXA27X_MODULE) static struct gpio_vbus_mach_info vpac270_gpio_vbus_info = { .gpio_vbus = GPIO41_VPAC270_UDC_DETECT, .gpio_pullup = -1, From 051a11b53377e312462be9423c083adfc44d600c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 10 Sep 2011 12:26:07 +0200 Subject: [PATCH 0367/4025] arm: mx28: fix bit operation in clock setting commit c2735391fbc68feae10d6d14e60956c8106e725f upstream. reg | (1 << clk->enable_shift) always evaluates to true. Switch it to & which makes much more sense. Same fix as 13be9f00 (ARM i.MX28: fix bit operation) at a different location. Signed-off-by: Wolfram Sang Cc: Sascha Hauer Cc: Shawn Guo Signed-off-by: Shawn Guo Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-mxs/clock-mx28.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c index 5dcc59d5b9e..b3a71245f38 100644 --- a/arch/arm/mach-mxs/clock-mx28.c +++ b/arch/arm/mach-mxs/clock-mx28.c @@ -404,7 +404,7 @@ static int name##_set_rate(struct clk *clk, unsigned long rate) \ reg = __raw_readl(CLKCTRL_BASE_ADDR + HW_CLKCTRL_##dr); \ reg &= ~BM_CLKCTRL_##dr##_DIV; \ reg |= div << BP_CLKCTRL_##dr##_DIV; \ - if (reg | (1 << clk->enable_shift)) { \ + if (reg & (1 << clk->enable_shift)) { \ pr_err("%s: clock is gated\n", __func__); \ return -EINVAL; \ } \ From e2dcdeea518813b728216fe52d94c3b0a5a0b599 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 23 Nov 2011 14:43:37 -0800 Subject: [PATCH 0368/4025] ARM: OMAP: smartreflex: fix IRQ handling bug commit 5a4f1844c2ba21f804d7729306d9b16eaeb724a8 upstream. Fix a bug which has been on this driver since it was added by the original commit 984aa6db which would never clear IRQSTATUS bits. Signed-off-by: Felipe Balbi Signed-off-by: Kevin Hilman Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/smartreflex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c index fb7dc52394a..f5a6bc1250c 100644 --- a/arch/arm/mach-omap2/smartreflex.c +++ b/arch/arm/mach-omap2/smartreflex.c @@ -137,7 +137,7 @@ static irqreturn_t sr_interrupt(int irq, void *data) sr_write_reg(sr_info, ERRCONFIG_V1, status); } else if (sr_info->ip_type == SR_TYPE_V2) { /* Read the status bits */ - sr_read_reg(sr_info, IRQSTATUS); + status = sr_read_reg(sr_info, IRQSTATUS); /* Clear them by writing back */ sr_write_reg(sr_info, IRQSTATUS, status); From 0443648aa178dbf8090edfd6dc54f31f916a174b Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Wed, 23 Nov 2011 14:44:50 -0800 Subject: [PATCH 0369/4025] ARM: OMAP2: select ARM_AMBA if OMAP3_EMU is defined commit a8a6565c7615cab3608d75af95b5c8a3522cd7c4 upstream. This patch selects ARM_AMBA if OMAP3_EMU is defined because OC_ETM depends on ARM_AMBA, so fix the link failure[1]. [1], arch/arm/kernel/built-in.o: In function `etm_remove': /home/tom/git/omap/linux-2.6-omap/arch/arm/kernel/etm.c:609: undefined reference to `amba_release_regions' arch/arm/kernel/built-in.o: In function `etb_remove': /home/tom/git/omap/linux-2.6-omap/arch/arm/kernel/etm.c:409: undefined reference to `amba_release_regions' arch/arm/kernel/built-in.o: In function `etm_init': /home/tom/git/omap/linux-2.6-omap/arch/arm/kernel/etm.c:640: undefined reference to `amba_driver_register' /home/tom/git/omap/linux-2.6-omap/arch/arm/kernel/etm.c:646: undefined reference to `amba_driver_register' /home/tom/git/omap/linux-2.6-omap/arch/arm/kernel/etm.c:648: undefined reference to `amba_driver_unregister' arch/arm/kernel/built-in.o: In function `etm_probe': /home/tom/git/omap/linux-2.6-omap/arch/arm/kernel/etm.c:545: undefined reference to `amba_request_regions' /home/tom/git/omap/linux-2.6-omap/arch/arm/kernel/etm.c:595: undefined reference to `amba_release_regions' arch/arm/kernel/built-in.o: In function `etb_probe': /home/tom/git/omap/linux-2.6-omap/arch/arm/kernel/etm.c:347: undefined reference to `amba_request_regions' /home/tom/git/omap/linux-2.6-omap/arch/arm/kernel/etm.c:392: undefined reference to `amba_release_regions' arch/arm/mach-omap2/built-in.o: In function `emu_init': /home/tom/git/omap/linux-2.6-omap/arch/arm/mach-omap2/emu.c:62: undefined reference to `amba_device_register' /home/tom/git/omap/linux-2.6-omap/arch/arm/mach-omap2/emu.c:63: undefined reference to `amba_device_register' make: *** [.tmp_vmlinux1] Error 1 making modules Signed-off-by: Ming Lei Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 19d5891c48e..841ae21f520 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -326,6 +326,7 @@ config MACH_OMAP4_PANDA config OMAP3_EMU bool "OMAP3 debugging peripherals" depends on ARCH_OMAP3 + select ARM_AMBA select OC_ETM help Say Y here to enable debugging hardware of omap3 From 341f278d7bfbe7233438a8512d183d62ddfae34e Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 14 Nov 2011 17:24:58 +0100 Subject: [PATCH 0370/4025] ARM: 7161/1: errata: no automatic store buffer drain commit 11ed0ba1754841316d4095478944300acf19acc3 upstream. This patch implements a workaround for PL310 erratum 769419. On revisions of the PL310 prior to r3p2, the Store Buffer does not automatically drain. This can cause normal, non-cacheable writes to be retained when the memory system is idle, leading to suboptimal I/O performance for drivers using coherent DMA. This patch adds an optional wmb() call to the cpu_idle loop. On systems with an outer cache, this causes an explicit flush of the store buffer. Acked-by: Catalin Marinas Tested-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/Kconfig | 12 ++++++++++++ arch/arm/kernel/process.c | 3 +++ 2 files changed, 15 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 91c84cbefcf..2456badc863 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1312,6 +1312,18 @@ config ARM_ERRATA_764369 relevant cache maintenance functions and sets a specific bit in the diagnostic control register of the SCU. +config PL310_ERRATA_769419 + bool "PL310 errata: no automatic Store Buffer drain" + depends on CACHE_L2X0 + help + On revisions of the PL310 prior to r3p2, the Store Buffer does + not automatically drain. This can cause normal, non-cacheable + writes to be retained when the memory system is idle, leading + to suboptimal I/O performance for drivers using coherent DMA. + This option adds a write barrier to the cpu_idle loop so that, + on systems with an outer cache, the store buffer is drained + explicitly. + endmenu menu "Kernel Features" diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index 5e1e5419722..74ae833e5c7 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -191,6 +191,9 @@ void cpu_idle(void) #endif local_irq_disable(); +#ifdef CONFIG_PL310_ERRATA_769419 + wmb(); +#endif if (hlt_counter) { local_irq_enable(); cpu_relax(); From 5599ae9741c55721765932bb9babead9b71e172b Mon Sep 17 00:00:00 2001 From: Tim Blechmann Date: Tue, 22 Nov 2011 11:15:45 +0100 Subject: [PATCH 0371/4025] ALSA: lx6464es - fix device communication via command bus commit a29878553a9a7b4c06f93c7e383527cf014d4ceb upstream. commit 6175ddf06b6172046a329e3abfd9c901a43efd2e optimized the mem*io functions that have been used to send commands to the device. these optimizations somehow corrupted the communication with the lx6464es, that resulted the device to be unusable with kernels after 2.6.33. this patch emulates the memcpy_*_io functions via a loop to avoid these problems. Signed-off-by: Tim Blechmann LKML-Reference: <4ECB5257.4040600@ladisch.de> Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/lx6464es/lx_core.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c index 617f98b0cba..713f7986e62 100644 --- a/sound/pci/lx6464es/lx_core.c +++ b/sound/pci/lx6464es/lx_core.c @@ -80,8 +80,12 @@ unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port) void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len) { - void __iomem *address = lx_dsp_register(chip, port); - memcpy_fromio(data, address, len*sizeof(u32)); + u32 __iomem *address = lx_dsp_register(chip, port); + int i; + + /* we cannot use memcpy_fromio */ + for (i = 0; i != len; ++i) + data[i] = ioread32(address + i); } @@ -94,8 +98,12 @@ void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data) void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data, u32 len) { - void __iomem *address = lx_dsp_register(chip, port); - memcpy_toio(address, data, len*sizeof(u32)); + u32 __iomem *address = lx_dsp_register(chip, port); + int i; + + /* we cannot use memcpy_to */ + for (i = 0; i != len; ++i) + iowrite32(data[i], address + i); } From 289c76ba6ee33daff3217881f0f4a63743ad41ab Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Mon, 14 Nov 2011 16:35:26 -0600 Subject: [PATCH 0372/4025] ASoC: fsl_ssi: properly initialize the sysfs attribute object commit 0f768a7235d3dfb6f4833030a95a06419df089cb upstream. Commit 6992f533 ("sysfs: Use one lockdep class per sysfs attribute") requires 'struct attribute' objects to be initialized with sysfs_attr_init(). Signed-off-by: Timur Tabi Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/fsl/fsl_ssi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 313e0ccedd5..bd811a04f42 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -698,6 +698,7 @@ static int __devinit fsl_ssi_probe(struct platform_device *pdev) /* Initialize the the device_attribute structure */ dev_attr = &ssi_private->dev_attr; + sysfs_attr_init(&dev_attr->attr); dev_attr->attr.name = "statistics"; dev_attr->attr.mode = S_IRUGO; dev_attr->show = fsl_sysfs_ssi_show; From e879974c3f5bdadc691d8114a547caac768f61de Mon Sep 17 00:00:00 2001 From: Timo Juhani Lindfors Date: Thu, 17 Nov 2011 02:52:50 +0200 Subject: [PATCH 0373/4025] ASoC: wm8753: Skip noop reconfiguration of DAI mode commit 2391a0e06789a3f1718dee30b282562f7ed28c87 upstream. This patch makes it possible to set DAI mode to its currently applied value even if codec is active. This is necessary to allow aplay -t raw -r 44100 -f S16_LE -c 2 < /dev/urandom & alsactl store -f backup.state alsactl restore -f backup.state to work without returning errors. This patch is based on a patch sent by Klaus Kurzmann . Signed-off-by: Timo Juhani Lindfors Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8753.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index aa091a0d818..66d18a3e57f 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -189,6 +189,9 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol, struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); u16 ioctl; + if (wm8753->dai_func == ucontrol->value.integer.value[0]) + return 0; + if (codec->active) return -EBUSY; From 6dbe15f453482a897c3db411cfdcffef27e71c6c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 21 Nov 2011 11:55:41 +0000 Subject: [PATCH 0374/4025] ASoC: Ensure WM8731 register cache is synced when resuming from disabled commit ed3e80c4c991a52f9fce3421536a78e331ae0949 upstream. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8731.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 76b4361e9b8..f5a0ec4ade5 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -463,6 +463,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, snd_soc_write(codec, WM8731_PWR, 0xffff); regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); + codec->cache_sync = 1; break; } codec->dapm.bias_level = level; From 421f55945fb8515c6f322d20e9b0a2d390235e05 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 22 Nov 2011 14:44:28 +0200 Subject: [PATCH 0375/4025] SUNRPC: Ensure we return EAGAIN in xs_nospace if congestion is cleared commit 24ca9a847791fd53d9b217330b15f3c285827a18 upstream. By returning '0' instead of 'EAGAIN' when the tests in xs_nospace() fail to find evidence of socket congestion, we are making the RPC engine believe that the message was incorrectly sent and so it disconnects the socket instead of just retrying. The bug appears to have been introduced by commit 5e3771ce2d6a69e10fcc870cdf226d121d868491 (SUNRPC: Ensure that xs_nospace return values are propagated). Reported-by: Andrew Cooper Signed-off-by: Trond Myklebust Tested-by: Andrew Cooper Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtsock.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 72abb735893..ea7507979b0 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -485,7 +485,7 @@ static int xs_nospace(struct rpc_task *task) struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); - int ret = 0; + int ret = -EAGAIN; dprintk("RPC: %5u xmit incomplete (%u left of %u)\n", task->tk_pid, req->rq_slen - req->rq_bytes_sent, @@ -497,7 +497,6 @@ static int xs_nospace(struct rpc_task *task) /* Don't race with disconnect */ if (xprt_connected(xprt)) { if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) { - ret = -EAGAIN; /* * Notify TCP that we're limited by the application * window size From 1c8ca629b774d8dd5fb85baf985f260cfcd68fc8 Mon Sep 17 00:00:00 2001 From: Edward Donovan Date: Sun, 27 Nov 2011 23:07:34 -0500 Subject: [PATCH 0376/4025] genirq: fix regression in irqfixup, irqpoll MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 52553ddffad76ccf192d4dd9ce88d5818f57f62a upstream. Commit fa27271bc8d2("genirq: Fixup poll handling") introduced a regression that broke irqfixup/irqpoll for some hardware configurations. Amidst reorganizing 'try_one_irq', that patch removed a test that checked for 'action->handler' returning IRQ_HANDLED, before acting on the interrupt. Restoring this test back returns the functionality lost since 2.6.39. In the current set of tests, after 'action' is set, it must precede '!action->next' to take effect. With this and my previous patch to irq/spurious.c, c75d720fca8a, all IRQ regressions that I have encountered are fixed. Signed-off-by: Edward Donovan Reported-and-tested-by: Rogério Brito Cc: Thomas Gleixner Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/irq/spurious.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c index b5f4742693c..dc813a948be 100644 --- a/kernel/irq/spurious.c +++ b/kernel/irq/spurious.c @@ -84,7 +84,9 @@ static int try_one_irq(int irq, struct irq_desc *desc, bool force) */ action = desc->action; if (!action || !(action->flags & IRQF_SHARED) || - (action->flags & __IRQF_TIMER) || !action->next) + (action->flags & __IRQF_TIMER) || + (action->handler(irq, action->dev_id) == IRQ_HANDLED) || + !action->next) goto out; /* Already running on another processor */ From 953d0c888eda75de7d248017f6dd2e5e254ad0cc Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Tue, 22 Nov 2011 07:44:47 -0800 Subject: [PATCH 0377/4025] cgroup_freezer: fix freezing groups with stopped tasks commit 884a45d964dd395eda945842afff5e16bcaedf56 upstream. 2d3cbf8b (cgroup_freezer: update_freezer_state() does incorrect state transitions) removed is_task_frozen_enough and replaced it with a simple frozen call. This, however, breaks freezing for a group with stopped tasks because those cannot be frozen and so the group remains in CGROUP_FREEZING state (update_if_frozen doesn't count stopped tasks) and never reaches CGROUP_FROZEN. Let's add is_task_frozen_enough back and use it at the original locations (update_if_frozen and try_to_freeze_cgroup). Semantically we consider stopped tasks as frozen enough so we should consider both cases when testing frozen tasks. Testcase: mkdir /dev/freezer mount -t cgroup -o freezer none /dev/freezer mkdir /dev/freezer/foo sleep 1h & pid=$! kill -STOP $pid echo $pid > /dev/freezer/foo/tasks echo FROZEN > /dev/freezer/foo/freezer.state while true do cat /dev/freezer/foo/freezer.state [ "`cat /dev/freezer/foo/freezer.state`" = "FROZEN" ] && break sleep 1 done echo OK Signed-off-by: Michal Hocko Acked-by: Li Zefan Cc: Tomasz Buchert Cc: Paul Menage Cc: Andrew Morton Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- kernel/cgroup_freezer.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index e691818d7e4..a3f638ac3de 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c @@ -153,6 +153,13 @@ static void freezer_destroy(struct cgroup_subsys *ss, kfree(cgroup_freezer(cgroup)); } +/* task is frozen or will freeze immediately when next it gets woken */ +static bool is_task_frozen_enough(struct task_struct *task) +{ + return frozen(task) || + (task_is_stopped_or_traced(task) && freezing(task)); +} + /* * The call to cgroup_lock() in the freezer.state write method prevents * a write to that file racing against an attach, and hence the @@ -231,7 +238,7 @@ static void update_if_frozen(struct cgroup *cgroup, cgroup_iter_start(cgroup, &it); while ((task = cgroup_iter_next(cgroup, &it))) { ntotal++; - if (frozen(task)) + if (is_task_frozen_enough(task)) nfrozen++; } @@ -284,7 +291,7 @@ static int try_to_freeze_cgroup(struct cgroup *cgroup, struct freezer *freezer) while ((task = cgroup_iter_next(cgroup, &it))) { if (!freeze_task(task, true)) continue; - if (frozen(task)) + if (is_task_frozen_enough(task)) continue; if (!freezing(task) && !freezer_should_skip(task)) num_cant_freeze_now++; From e1ef77bdad527601e9e47b377cbef5bee9df8248 Mon Sep 17 00:00:00 2001 From: Hector Palacios Date: Mon, 14 Nov 2011 11:15:25 +0100 Subject: [PATCH 0378/4025] timekeeping: add arch_offset hook to ktime_get functions commit d004e024058a0eaca097513ce62cbcf978913e0a upstream. ktime_get and ktime_get_ts were calling timekeeping_get_ns() but later they were not calling arch_gettimeoffset() so architectures using this mechanism returned 0 ns when calling these functions. This happened for example when running Busybox's ping which calls syscall(__NR_clock_gettime, CLOCK_MONOTONIC, ts) which eventually calls ktime_get. As a result the returned ping travel time was zero. Signed-off-by: Hector Palacios Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- kernel/time/timekeeping.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 342408cf68d..5f458310668 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -249,6 +249,8 @@ ktime_t ktime_get(void) secs = xtime.tv_sec + wall_to_monotonic.tv_sec; nsecs = xtime.tv_nsec + wall_to_monotonic.tv_nsec; nsecs += timekeeping_get_ns(); + /* If arch requires, add in gettimeoffset() */ + nsecs += arch_gettimeoffset(); } while (read_seqretry(&xtime_lock, seq)); /* @@ -280,6 +282,8 @@ void ktime_get_ts(struct timespec *ts) *ts = xtime; tomono = wall_to_monotonic; nsecs = timekeeping_get_ns(); + /* If arch requires, add in gettimeoffset() */ + nsecs += arch_gettimeoffset(); } while (read_seqretry(&xtime_lock, seq)); From 24ee8bfeb1dafdc8d2294d1c296bf4baa9324ad8 Mon Sep 17 00:00:00 2001 From: Jeff Ohlstein Date: Fri, 18 Nov 2011 15:47:10 -0800 Subject: [PATCH 0379/4025] hrtimer: Fix extra wakeups from __remove_hrtimer() commit 27c9cd7e601632b3794e1c3344d37b86917ffb43 upstream. __remove_hrtimer() attempts to reprogram the clockevent device when the timer being removed is the next to expire. However, __remove_hrtimer() reprograms the clockevent *before* removing the timer from the timerqueue and thus when hrtimer_force_reprogram() finds the next timer to expire it finds the timer we're trying to remove. This is especially noticeable when the system switches to NOHz mode and the system tick is removed. The timer tick is removed from the system but the clockevent is programmed to wakeup in another HZ anyway. Silence the extra wakeup by removing the timer from the timerqueue before calling hrtimer_force_reprogram() so that we actually program the clockevent for the next timer to expire. This was broken by 998adc3 "hrtimers: Convert hrtimers to use timerlist infrastructure". Signed-off-by: Jeff Ohlstein Link: http://lkml.kernel.org/r/1321660030-8520-1-git-send-email-johlstei@codeaurora.org Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/hrtimer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index a9205e32a05..2043c08d36c 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -885,10 +885,13 @@ static void __remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, unsigned long newstate, int reprogram) { + struct timerqueue_node *next_timer; if (!(timer->state & HRTIMER_STATE_ENQUEUED)) goto out; - if (&timer->node == timerqueue_getnext(&base->active)) { + next_timer = timerqueue_getnext(&base->active); + timerqueue_del(&base->active, &timer->node); + if (&timer->node == next_timer) { #ifdef CONFIG_HIGH_RES_TIMERS /* Reprogram the clock event device. if enabled */ if (reprogram && hrtimer_hres_active()) { @@ -901,7 +904,6 @@ static void __remove_hrtimer(struct hrtimer *timer, } #endif } - timerqueue_del(&base->active, &timer->node); if (!timerqueue_getnext(&base->active)) base->cpu_base->active_bases &= ~(1 << base->index); out: From 00b080367aca3dbb6191cbe522609d2055ea0fd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20B=C3=BCsch?= Date: Wed, 16 Nov 2011 23:48:31 +0100 Subject: [PATCH 0380/4025] p54spi: Add missing spin_lock_init commit 32d3a3922d617a5a685a5e2d24b20d0e88f192a9 upstream. The tx_lock is not initialized properly. Add spin_lock_init(). Signed-off-by: Michael Buesch Acked-by: Christian Lamparter Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/p54/p54spi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 6d9204fef90..72ec212e482 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -657,6 +657,7 @@ static int __devinit p54spi_probe(struct spi_device *spi) init_completion(&priv->fw_comp); INIT_LIST_HEAD(&priv->tx_pending); mutex_init(&priv->mutex); + spin_lock_init(&priv->tx_lock); SET_IEEE80211_DEV(hw, &spi->dev); priv->common.open = p54spi_op_start; priv->common.stop = p54spi_op_stop; From 23e76fdc4cc34c116b37eedc2a3a8ecaa081541e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20B=C3=BCsch?= Date: Wed, 16 Nov 2011 23:55:46 +0100 Subject: [PATCH 0381/4025] p54spi: Fix workqueue deadlock commit 2d1618170eb493d18f66f2ac03775409a6fb97c6 upstream. priv->work must not be synced while priv->mutex is locked, because the mutex is taken in the work handler. Move cancel_work_sync down to after the device shutdown code. This is safe, because the work handler checks fw_state and bails out early in case of a race. Signed-off-by: Michael Buesch Acked-by: Christian Lamparter Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/p54/p54spi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index 72ec212e482..b33ceb1c066 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -589,8 +589,6 @@ static void p54spi_op_stop(struct ieee80211_hw *dev) WARN_ON(priv->fw_state != FW_STATE_READY); - cancel_work_sync(&priv->work); - p54spi_power_off(priv); spin_lock_irqsave(&priv->tx_lock, flags); INIT_LIST_HEAD(&priv->tx_pending); @@ -598,6 +596,8 @@ static void p54spi_op_stop(struct ieee80211_hw *dev) priv->fw_state = FW_STATE_OFF; mutex_unlock(&priv->mutex); + + cancel_work_sync(&priv->work); } static int __devinit p54spi_probe(struct spi_device *spi) From 2e72634a130dcac5d9e88e9187d7eab6c0ea8713 Mon Sep 17 00:00:00 2001 From: Gertjan van Wingerde Date: Wed, 16 Nov 2011 23:16:15 +0100 Subject: [PATCH 0382/4025] rt2x00: Fix efuse EEPROM reading on PPC32. commit 68fa64ef606bcee688fce46d07aa68f175070156 upstream. Fix __le32 to __le16 conversion of the first word of an 8-word block of EEPROM read via the efuse method. Reported-and-tested-by: Ingvar Hagelund Signed-off-by: Gertjan van Wingerde Acked-by: Helmut Schaa Acked-by: Ivo van Doorn Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2800lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 3f7ea1ce295..e6e174caec8 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3514,7 +3514,7 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) /* Apparently the data is read from end to start */ rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, ®); /* The returned value is in CPU order, but eeprom is le */ - rt2x00dev->eeprom[i] = cpu_to_le32(reg); + *(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg); rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, ®); *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg); rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, ®); From e30922bd0c3d24c27f457a64997ed4a47161621e Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Thu, 24 Nov 2011 18:13:56 +0200 Subject: [PATCH 0383/4025] nl80211: fix MAC address validation commit e007b857e88097c96c45620bf3b04a4e309053d1 upstream. MAC addresses have a fixed length. The current policy allows passing < ETH_ALEN bytes, which might result in reading beyond the buffer. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/wireless/nl80211.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 3dac76f33b9..0c2b8080547 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -83,8 +83,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, [NL80211_ATTR_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ-1 }, - [NL80211_ATTR_MAC] = { .type = NLA_BINARY, .len = ETH_ALEN }, - [NL80211_ATTR_PREV_BSSID] = { .type = NLA_BINARY, .len = ETH_ALEN }, + [NL80211_ATTR_MAC] = { .len = ETH_ALEN }, + [NL80211_ATTR_PREV_BSSID] = { .len = ETH_ALEN }, [NL80211_ATTR_KEY] = { .type = NLA_NESTED, }, [NL80211_ATTR_KEY_DATA] = { .type = NLA_BINARY, From 6cb4e0db2f318c0730f31622fc5812a19e7ff379 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 21 Nov 2011 10:44:00 +0100 Subject: [PATCH 0384/4025] cfg80211: fix regulatory NULL dereference commit de3584bd62d87b4c250129fbc46ca52c80330add upstream. By the time userspace returns with a response to the regulatory domain request, the wiphy causing the request might have gone away. If this is so, reject the update but mark the request as having been processed anyway. Cc: Luis R. Rodriguez Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/wireless/reg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 213103e3f99..3c5ddeafb93 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2026,6 +2026,10 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) } request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); + if (!request_wiphy) { + reg_set_request_processed(); + return -ENODEV; + } if (!last_request->intersect) { int r; From 64a1b241dd84ed6b12b62bbb67b380609bdd50b2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 24 Nov 2011 20:06:14 +0100 Subject: [PATCH 0385/4025] mac80211: don't stop a single aggregation session twice commit 24f50a9d165745fd0701c6e089d35f58a229ea69 upstream. Nikolay noticed (by code review) that mac80211 can attempt to stop an aggregation session while it is already being stopped. So to fix it, check whether stop is already being done and bail out if so. Also move setting the STOPPING state into the lock so things are properly atomic. Reported-by: Nikolay Martynov Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/agg-tx.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index c8be8eff70d..23418753a4d 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -162,6 +162,12 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, return -ENOENT; } + /* if we're already stopping ignore any new requests to stop */ + if (test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { + spin_unlock_bh(&sta->lock); + return -EALREADY; + } + if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { /* not even started yet! */ ieee80211_assign_tid_tx(sta, tid, NULL); @@ -170,6 +176,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, return 0; } + set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); + spin_unlock_bh(&sta->lock); #ifdef CONFIG_MAC80211_HT_DEBUG @@ -177,8 +185,6 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, sta->sta.addr, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state); - del_timer_sync(&tid_tx->addba_resp_timer); /* From 20f8d725863ca926a199cab1bc5cf31f8bf53cb0 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 27 Nov 2011 15:29:44 +0200 Subject: [PATCH 0386/4025] mac80211: fix race between the AGG SM and the Tx data path commit 2a1e0fd175dcfd72096ba9291d31e3b1b5342e60 upstream. When a packet is supposed to sent be as an a-MPDU, mac80211 sets IEEE80211_TX_CTL_AMPDU to let the driver know. On the other hand, mac80211 configures the driver for aggregration with the ampdu_action callback. There is race between these two mechanisms since the following scenario can occur when the BA agreement is torn down: Tx softIRQ drv configuration ========== ================= check OPERATIONAL bit Set the TX_CTL_AMPDU bit in the packet clear OPERATIONAL bit stop Tx AGG Pass Tx packet to the driver. In that case the driver would get a packet with TX_CTL_AMPDU set although it has already been notified that the BA session has been torn down. To fix this, we need to synchronize all the Qdisc activity after we cleared the OPERATIONAL bit. After that step, all the following packets will be buffered until the driver reports it is ready to get new packets for this RA / TID. This buffering allows not to run into another race that would send packets with TX_CTL_AMPDU unset while the driver hasn't been requested to tear down the BA session yet. This race occurs in practice and iwlwifi complains with a WARN_ON when it happens. Signed-off-by: Emmanuel Grumbach Reviewed-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/agg-tx.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 23418753a4d..42a59c260e8 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -194,6 +194,20 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, */ clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); + /* + * There might be a few packets being processed right now (on + * another CPU) that have already gotten past the aggregation + * check when it was still OPERATIONAL and consequently have + * IEEE80211_TX_CTL_AMPDU set. In that case, this code might + * call into the driver at the same time or even before the + * TX paths calls into it, which could confuse the driver. + * + * Wait for all currently running TX paths to finish before + * telling the driver. New packets will not go through since + * the aggregation session is no longer OPERATIONAL. + */ + synchronize_net(); + tid_tx->stop_initiator = initiator; tid_tx->tx_stop = tx; From 0500898d30ba531cc932c2db171bf2f27ca78abe Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 1 Dec 2011 17:21:28 +0100 Subject: [PATCH 0387/4025] hwmon: (coretemp) Fix oops on driver load This is for stable kernel branch 3.0 only. Previous and later versions have different code paths and are not affected by this bug. If the CPU microcode is too old, the coretemp driver won't work. But instead of failing gracefully, it currently oops. Check for NULL platform device data to avoid this. Signed-off-by: Jean Delvare Acked-by: Durgadoss R Acked-by: Guenter Roeck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/coretemp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index f6421940841..835ae427d85 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -539,6 +539,8 @@ static void coretemp_add_core(unsigned int cpu, int pkg_flag) return; pdata = platform_get_drvdata(pdev); + if (!pdata) + return; err = create_core_data(pdata, pdev, cpu, pkg_flag); if (err) From 461738c023b19cbd8cbf4260801e248f2360514d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 2 Dec 2011 15:14:57 -0800 Subject: [PATCH 0388/4025] revert "mfd: Fix twl4030 dependencies for audio codec" This reverts commit 11b8fc6ae54bf18a48c94e181c37ca135b858b42, which was commit f09ee0451a44a4e913a7c3cec3805508f7de6c54 upstream. Koen Kooi reports that this shouldn't have been applied to the 3.0 kernel as it isn't relevant there, only 3.1. Reported-by: Koen Kooi Cc: Thomas Weber Cc: Peter Ujfalusi Cc: Samuel Ortiz Cc: Jarkko Nikula Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/twl-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index b9188a23389..b8f2a4e7f6e 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -109,7 +109,7 @@ #define twl_has_watchdog() false #endif -#if defined(CONFIG_MFD_TWL4030_AUDIO) || defined(CONFIG_MFD_TWL4030_AUDIO_MODULE) ||\ +#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE) ||\ defined(CONFIG_SND_SOC_TWL6040) || defined(CONFIG_SND_SOC_TWL6040_MODULE) #define twl_has_codec() true #else From bfc769031803ed194374d4e79d30e6ee103d822e Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Wed, 9 Nov 2011 08:39:24 +0100 Subject: [PATCH 0389/4025] SCSI: Silencing 'killing requests for dead queue' commit 745718132c3c7cac98a622b610e239dcd5217f71 upstream. When we tear down a device we try to flush all outstanding commands in scsi_free_queue(). However the check in scsi_request_fn() is imperfect as it only signals that we _might start_ aborting commands, not that we've actually aborted some. So move the printk inside the scsi_kill_request function, this will also give us a hint about which commands are aborted. Signed-off-by: Hannes Reinecke Signed-off-by: James Bottomley Cc: Christoph Biedl Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_lib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index f97acffdddc..72ab1e6da64 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1407,6 +1407,8 @@ static void scsi_kill_request(struct request *req, struct request_queue *q) blk_start_request(req); + scmd_printk(KERN_INFO, cmd, "killing request\n"); + sdev = cmd->device; starget = scsi_target(sdev); shost = sdev->host; @@ -1488,7 +1490,6 @@ static void scsi_request_fn(struct request_queue *q) struct request *req; if (!sdev) { - printk("scsi: killing requests for dead queue\n"); while ((req = blk_peek_request(q)) != NULL) scsi_kill_request(req, q); return; From d98627dd4a3e2cd4a7602a845fd1c1c78d372e97 Mon Sep 17 00:00:00 2001 From: Hillf Danton Date: Tue, 15 Nov 2011 14:36:12 -0800 Subject: [PATCH 0390/4025] hugetlb: release pages in the error path of hugetlb_cow() commit ea4039a34c4c206d015d34a49d0b00868e37db1d upstream. If we fail to prepare an anon_vma, the {new, old}_page should be released, or they will leak. Signed-off-by: Hillf Danton Reviewed-by: Andrea Arcangeli Cc: Hugh Dickins Cc: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Michal Hocko Signed-off-by: Greg Kroah-Hartman --- mm/hugetlb.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index bfcf153bc82..2b57cd96dd5 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -2415,6 +2415,8 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma, * anon_vma prepared. */ if (unlikely(anon_vma_prepare(vma))) { + page_cache_release(new_page); + page_cache_release(old_page); /* Caller expects lock to be held */ spin_lock(&mm->page_table_lock); return VM_FAULT_OOM; From 08d618b2080d8b3afac6db1a361c54d827b8d044 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 1 Dec 2011 11:02:11 -0500 Subject: [PATCH 0391/4025] drm/radeon/kms: add some new pci ids commit 2ed4d9d648cbd4fb1c232a646dbdbdfdd373ca94 upstream. Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- include/drm/drm_pciids.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index f81676f1b31..4e4fbb820e2 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -197,6 +197,14 @@ {0x1002, 0x6770, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6778, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6779, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6842, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6843, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6849, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6858, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6859, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6880, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6888, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6889, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CYPRESS|RADEON_NEW_MEMMAP}, \ From 6a82412403cee54e4ce87b9dea9c275a46d4e682 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 28 Nov 2011 14:49:26 -0500 Subject: [PATCH 0392/4025] drm/radeon/kms: add some loop timeouts in pageflip code commit f64964796dedca340608fb1075ab6baad5625851 upstream. Avoid infinite loops waiting for surface updates if a GPU reset happens while waiting for a page flip. See: https://bugs.freedesktop.org/show_bug.cgi?id=43191 Signed-off-by: Alex Deucher Reviewed-by: Mario Kleiner Tested-by: Simon Farnsworth Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen.c | 7 ++++++- drivers/gpu/drm/radeon/r100.c | 7 ++++++- drivers/gpu/drm/radeon/rs600.c | 7 ++++++- drivers/gpu/drm/radeon/rv770.c | 7 ++++++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index f1bdb58ff91..21c5aa070b9 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -82,6 +82,7 @@ u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset); + int i; /* Lock the graphics update lock */ tmp |= EVERGREEN_GRPH_UPDATE_LOCK; @@ -99,7 +100,11 @@ u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) (u32)crtc_base); /* Wait for update_pending to go high. */ - while (!(RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING)); + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING) + break; + udelay(1); + } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); /* Unlock the lock, so double-buffering can take place inside vblank */ diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index c9a0dae481f..b94d871487e 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -84,13 +84,18 @@ u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK; + int i; /* Lock the graphics update lock */ /* update the scanout addresses */ WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); /* Wait for update_pending to go high. */ - while (!(RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET)); + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET) + break; + udelay(1); + } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); /* Unlock the lock, so double-buffering can take place inside vblank */ diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index aea28c38ca4..a37a1efdd22 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -62,6 +62,7 @@ u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); + int i; /* Lock the graphics update lock */ tmp |= AVIVO_D1GRPH_UPDATE_LOCK; @@ -74,7 +75,11 @@ u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) (u32)crtc_base); /* Wait for update_pending to go high. */ - while (!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING)); + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING) + break; + udelay(1); + } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); /* Unlock the lock, so double-buffering can take place inside vblank */ diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index f2516e64805..84cf82fcac8 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -47,6 +47,7 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); + int i; /* Lock the graphics update lock */ tmp |= AVIVO_D1GRPH_UPDATE_LOCK; @@ -66,7 +67,11 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) (u32)crtc_base); /* Wait for update_pending to go high. */ - while (!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING)); + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING) + break; + udelay(1); + } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); /* Unlock the lock, so double-buffering can take place inside vblank */ From f18cc6ba85619dfee8ed4a9564ae8c0fcb874cbe Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 28 Nov 2011 09:44:14 +0100 Subject: [PATCH 0393/4025] firmware: Sigma: Prevent out of bounds memory access commit 4f718a29fe4908c2cea782f751e9805319684e2b upstream. The SigmaDSP firmware loader currently does not perform enough boundary size checks when processing the firmware. As a result it is possible that a malformed firmware can cause an out of bounds memory access. This patch adds checks which ensure that both the action header and the payload are completely inside the firmware data boundaries before processing them. Signed-off-by: Lars-Peter Clausen Acked-by: Mike Frysinger Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/sigma.c | 76 +++++++++++++++++++++++++++++----------- include/linux/sigma.h | 5 --- 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/drivers/firmware/sigma.c b/drivers/firmware/sigma.c index f10fc521951..c780baa59ed 100644 --- a/drivers/firmware/sigma.c +++ b/drivers/firmware/sigma.c @@ -14,13 +14,34 @@ #include #include -/* Return: 0==OK, <0==error, =1 ==no more actions */ +static size_t sigma_action_size(struct sigma_action *sa) +{ + size_t payload = 0; + + switch (sa->instr) { + case SIGMA_ACTION_WRITEXBYTES: + case SIGMA_ACTION_WRITESINGLE: + case SIGMA_ACTION_WRITESAFELOAD: + payload = sigma_action_len(sa); + break; + default: + break; + } + + payload = ALIGN(payload, 2); + + return payload + sizeof(struct sigma_action); +} + +/* + * Returns a negative error value in case of an error, 0 if processing of + * the firmware should be stopped after this action, 1 otherwise. + */ static int -process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw) +process_sigma_action(struct i2c_client *client, struct sigma_action *sa) { - struct sigma_action *sa = (void *)(ssfw->fw->data + ssfw->pos); size_t len = sigma_action_len(sa); - int ret = 0; + int ret; pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__, sa->instr, sa->addr, len); @@ -29,44 +50,50 @@ process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw) case SIGMA_ACTION_WRITEXBYTES: case SIGMA_ACTION_WRITESINGLE: case SIGMA_ACTION_WRITESAFELOAD: - if (ssfw->fw->size < ssfw->pos + len) - return -EINVAL; ret = i2c_master_send(client, (void *)&sa->addr, len); if (ret < 0) return -EINVAL; break; - case SIGMA_ACTION_DELAY: - ret = 0; udelay(len); len = 0; break; - case SIGMA_ACTION_END: - return 1; - + return 0; default: return -EINVAL; } - /* when arrive here ret=0 or sent data */ - ssfw->pos += sigma_action_size(sa, len); - return ssfw->pos == ssfw->fw->size; + return 1; } static int process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw) { - pr_debug("%s: processing %p\n", __func__, ssfw); + struct sigma_action *sa; + size_t size; + int ret; + + while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) { + sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos); + + size = sigma_action_size(sa); + ssfw->pos += size; + if (ssfw->pos > ssfw->fw->size || size == 0) + break; + + ret = process_sigma_action(client, sa); - while (1) { - int ret = process_sigma_action(client, ssfw); pr_debug("%s: action returned %i\n", __func__, ret); - if (ret == 1) - return 0; - else if (ret) + + if (ret <= 0) return ret; } + + if (ssfw->pos != ssfw->fw->size) + return -EINVAL; + + return 0; } int process_sigma_firmware(struct i2c_client *client, const char *name) @@ -89,7 +116,14 @@ int process_sigma_firmware(struct i2c_client *client, const char *name) /* then verify the header */ ret = -EINVAL; - if (fw->size < sizeof(*ssfw_head)) + + /* + * Reject too small or unreasonable large files. The upper limit has been + * chosen a bit arbitrarily, but it should be enough for all practical + * purposes and having the limit makes it easier to avoid integer + * overflows later in the loading process. + */ + if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) goto done; ssfw_head = (void *)fw->data; diff --git a/include/linux/sigma.h b/include/linux/sigma.h index e2accb3164d..9a138c2946b 100644 --- a/include/linux/sigma.h +++ b/include/linux/sigma.h @@ -50,11 +50,6 @@ static inline u32 sigma_action_len(struct sigma_action *sa) return (sa->len_hi << 16) | sa->len; } -static inline size_t sigma_action_size(struct sigma_action *sa, u32 payload_len) -{ - return sizeof(*sa) + payload_len + (payload_len % 2); -} - extern int process_sigma_firmware(struct i2c_client *client, const char *name); #endif From cd319e4350715b72939eec5c526ab60bd02b5229 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 28 Nov 2011 09:44:15 +0100 Subject: [PATCH 0394/4025] firmware: Sigma: Skip header during CRC generation commit c56935bdc0a8edf50237d3b0205133a5b0adc604 upstream. The firmware header is not part of the CRC, so skip it. Otherwise the firmware will be rejected due to non-matching CRCs. Signed-off-by: Lars-Peter Clausen Acked-by: Mike Frysinger Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/sigma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/sigma.c b/drivers/firmware/sigma.c index c780baa59ed..36265de0a9e 100644 --- a/drivers/firmware/sigma.c +++ b/drivers/firmware/sigma.c @@ -130,7 +130,8 @@ int process_sigma_firmware(struct i2c_client *client, const char *name) if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) goto done; - crc = crc32(0, fw->data, fw->size); + crc = crc32(0, fw->data + sizeof(*ssfw_head), + fw->size - sizeof(*ssfw_head)); pr_debug("%s: crc=%x\n", __func__, crc); if (crc != ssfw_head->crc) goto done; From f90312c8cf03b2294f6840c7dc01236838896acc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 28 Nov 2011 09:44:16 +0100 Subject: [PATCH 0395/4025] firmware: Sigma: Fix endianess issues commit bda63586bc5929e97288cdb371bb6456504867ed upstream. Currently the SigmaDSP firmware loader only works correctly on little-endian systems. Fix this by using the proper endianess conversion functions. Signed-off-by: Lars-Peter Clausen Acked-by: Mike Frysinger Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/sigma.c | 2 +- include/linux/sigma.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/firmware/sigma.c b/drivers/firmware/sigma.c index 36265de0a9e..1eedb6f7fda 100644 --- a/drivers/firmware/sigma.c +++ b/drivers/firmware/sigma.c @@ -133,7 +133,7 @@ int process_sigma_firmware(struct i2c_client *client, const char *name) crc = crc32(0, fw->data + sizeof(*ssfw_head), fw->size - sizeof(*ssfw_head)); pr_debug("%s: crc=%x\n", __func__, crc); - if (crc != ssfw_head->crc) + if (crc != le32_to_cpu(ssfw_head->crc)) goto done; ssfw.pos = sizeof(*ssfw_head); diff --git a/include/linux/sigma.h b/include/linux/sigma.h index 9a138c2946b..d0de882c0d9 100644 --- a/include/linux/sigma.h +++ b/include/linux/sigma.h @@ -24,7 +24,7 @@ struct sigma_firmware { struct sigma_firmware_header { unsigned char magic[7]; u8 version; - u32 crc; + __le32 crc; }; enum { @@ -40,14 +40,14 @@ enum { struct sigma_action { u8 instr; u8 len_hi; - u16 len; - u16 addr; + __le16 len; + __be16 addr; unsigned char payload[]; }; static inline u32 sigma_action_len(struct sigma_action *sa) { - return (sa->len_hi << 16) | sa->len; + return (sa->len_hi << 16) | le16_to_cpu(sa->len); } extern int process_sigma_firmware(struct i2c_client *client, const char *name); From 0a4527cdb58e712456e9c9e491df37fadd2d9256 Mon Sep 17 00:00:00 2001 From: Bart Westgeest Date: Tue, 1 Nov 2011 15:01:28 -0400 Subject: [PATCH 0396/4025] staging: usbip: bugfix for deadlock commit 438957f8d4a84daa7fa5be6978ad5897a2e9e5e5 upstream. Interrupts must be disabled prior to calling usb_hcd_unlink_urb_from_ep. If interrupts are not disabled, it can potentially lead to a deadlock. The deadlock is readily reproduceable on a slower (ARM based) device such as the TI Pandaboard. Signed-off-by: Bart Westgeest Signed-off-by: Greg Kroah-Hartman --- drivers/staging/usbip/vhci_rx.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c index e42ce9dab7a..5c4b5d94450 100644 --- a/drivers/staging/usbip/vhci_rx.c +++ b/drivers/staging/usbip/vhci_rx.c @@ -68,6 +68,7 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, { struct usbip_device *ud = &vdev->ud; struct urb *urb; + unsigned long flags; spin_lock(&vdev->priv_lock); urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum); @@ -101,9 +102,9 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, usbip_dbg_vhci_rx("now giveback urb %p\n", urb); - spin_lock(&the_controller->lock); + spin_lock_irqsave(&the_controller->lock, flags); usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); - spin_unlock(&the_controller->lock); + spin_unlock_irqrestore(&the_controller->lock, flags); usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); @@ -141,6 +142,7 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev, { struct vhci_unlink *unlink; struct urb *urb; + unsigned long flags; usbip_dump_header(pdu); @@ -170,9 +172,9 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev, urb->status = pdu->u.ret_unlink.status; pr_info("urb->status %d\n", urb->status); - spin_lock(&the_controller->lock); + spin_lock_irqsave(&the_controller->lock, flags); usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); - spin_unlock(&the_controller->lock); + spin_unlock_irqrestore(&the_controller->lock, flags); usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); From 9649803f2de0d2e77bdd7c5e1cbd4a7b3833f1e8 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Tue, 8 Nov 2011 21:23:03 +0000 Subject: [PATCH 0397/4025] staging: comedi: fix oops for USB DAQ devices. commit 3ffab428f40849ed5f21bcfd7285bdef7902f9ca upstream. This fixes kernel oops when an USB DAQ device is plugged out while it's communicating with the userspace software. Signed-off-by: Bernd Porr Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_fops.c | 71 +++++++++++++++++++++------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index c20694e6515..2cbb17945c5 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1452,9 +1452,6 @@ static struct vm_operations_struct comedi_vm_ops = { static int comedi_mmap(struct file *file, struct vm_area_struct *vma) { const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; struct comedi_async *async = NULL; unsigned long start = vma->vm_start; unsigned long size; @@ -1462,6 +1459,15 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) int i; int retval; struct comedi_subdevice *s; + struct comedi_device_file_info *dev_file_info; + struct comedi_device *dev; + + dev_file_info = comedi_get_device_file_info(minor); + if (dev_file_info == NULL) + return -ENODEV; + dev = dev_file_info->device; + if (dev == NULL) + return -ENODEV; mutex_lock(&dev->mutex); if (!dev->attached) { @@ -1528,11 +1534,17 @@ static unsigned int comedi_poll(struct file *file, poll_table * wait) { unsigned int mask = 0; const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; struct comedi_subdevice *read_subdev; struct comedi_subdevice *write_subdev; + struct comedi_device_file_info *dev_file_info; + struct comedi_device *dev; + dev_file_info = comedi_get_device_file_info(minor); + + if (dev_file_info == NULL) + return -ENODEV; + dev = dev_file_info->device; + if (dev == NULL) + return -ENODEV; mutex_lock(&dev->mutex); if (!dev->attached) { @@ -1578,9 +1590,15 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, int n, m, count = 0, retval = 0; DECLARE_WAITQUEUE(wait, current); const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; + struct comedi_device_file_info *dev_file_info; + struct comedi_device *dev; + dev_file_info = comedi_get_device_file_info(minor); + + if (dev_file_info == NULL) + return -ENODEV; + dev = dev_file_info->device; + if (dev == NULL) + return -ENODEV; if (!dev->attached) { DPRINTK("no driver configured on comedi%i\n", dev->minor); @@ -1683,9 +1701,15 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, int n, m, count = 0, retval = 0; DECLARE_WAITQUEUE(wait, current); const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; + struct comedi_device_file_info *dev_file_info; + struct comedi_device *dev; + dev_file_info = comedi_get_device_file_info(minor); + + if (dev_file_info == NULL) + return -ENODEV; + dev = dev_file_info->device; + if (dev == NULL) + return -ENODEV; if (!dev->attached) { DPRINTK("no driver configured on comedi%i\n", dev->minor); @@ -1885,11 +1909,17 @@ static int comedi_open(struct inode *inode, struct file *file) static int comedi_close(struct inode *inode, struct file *file) { const unsigned minor = iminor(inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; struct comedi_subdevice *s = NULL; int i; + struct comedi_device_file_info *dev_file_info; + struct comedi_device *dev; + dev_file_info = comedi_get_device_file_info(minor); + + if (dev_file_info == NULL) + return -ENODEV; + dev = dev_file_info->device; + if (dev == NULL) + return -ENODEV; mutex_lock(&dev->mutex); @@ -1923,10 +1953,15 @@ static int comedi_close(struct inode *inode, struct file *file) static int comedi_fasync(int fd, struct file *file, int on) { const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); + struct comedi_device_file_info *dev_file_info; + struct comedi_device *dev; + dev_file_info = comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; + if (dev_file_info == NULL) + return -ENODEV; + dev = dev_file_info->device; + if (dev == NULL) + return -ENODEV; return fasync_helper(fd, file, on, &dev->async_queue); } From 261dbf437bce1d339c358e6566925905e49c13fe Mon Sep 17 00:00:00 2001 From: Federico Vaga Date: Sat, 29 Oct 2011 09:45:39 +0200 Subject: [PATCH 0398/4025] Staging: comedi: fix mmap_count commit df30b21cb0eed5ba8a8e0cdfeebc66ba8cde821d upstream. In comedi_fops, mmap_count is decremented at comedi_vm_ops->close but it is not incremented at comedi_vm_ops->open. This may result in a negative counter. The patch introduces the open method to keep the counter consistent. The bug was triggerd by this sample code: mmap(0, ...., comedi_fd); fork(); exit(0); Acked-by: Alessandro Rubini Signed-off-by: Federico Vaga Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_fops.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 2cbb17945c5..69bd6f01bf6 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1432,7 +1432,21 @@ static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return ret; } -static void comedi_unmap(struct vm_area_struct *area) + +static void comedi_vm_open(struct vm_area_struct *area) +{ + struct comedi_async *async; + struct comedi_device *dev; + + async = area->vm_private_data; + dev = async->subdevice->device; + + mutex_lock(&dev->mutex); + async->mmap_count++; + mutex_unlock(&dev->mutex); +} + +static void comedi_vm_close(struct vm_area_struct *area) { struct comedi_async *async; struct comedi_device *dev; @@ -1446,7 +1460,8 @@ static void comedi_unmap(struct vm_area_struct *area) } static struct vm_operations_struct comedi_vm_ops = { - .close = comedi_unmap, + .open = comedi_vm_open, + .close = comedi_vm_close, }; static int comedi_mmap(struct file *file, struct vm_area_struct *vma) From 56448baac0c3d52501dc26868e15caba1811866d Mon Sep 17 00:00:00 2001 From: Federico Vaga Date: Sat, 29 Oct 2011 09:47:39 +0200 Subject: [PATCH 0399/4025] Staging: comedi: fix signal handling in read and write commit 6a9ce6b654e491981f6ef7e214cbd4f63e033848 upstream. After sleeping on a wait queue, signal_pending(current) should be checked (not before sleeping). Acked-by: Alessandro Rubini Signed-off-by: Federico Vaga Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_fops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 69bd6f01bf6..63e50f76182 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1673,11 +1673,11 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, retval = -EAGAIN; break; } + schedule(); if (signal_pending(current)) { retval = -ERESTARTSYS; break; } - schedule(); if (!s->busy) break; if (s->busy != file) { @@ -1780,11 +1780,11 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, retval = -EAGAIN; break; } + schedule(); if (signal_pending(current)) { retval = -ERESTARTSYS; break; } - schedule(); if (!s->busy) { retval = 0; break; From 8fafc7af6f7205249b730fc94df48b7dfb40517c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 22 Nov 2011 10:28:31 +0300 Subject: [PATCH 0400/4025] USB: whci-hcd: fix endian conversion in qset_clear() commit 8746c83d538cab273d335acb2be226d096f4a5af upstream. qset->qh.link is an __le64 field and we should be using cpu_to_le64() to fill it. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/whci/qset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index d6e17542861..a403b53e86b 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c @@ -124,7 +124,7 @@ void qset_clear(struct whc *whc, struct whc_qset *qset) { qset->td_start = qset->td_end = qset->ntds = 0; - qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T); + qset->qh.link = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T); qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK; qset->qh.err_count = 0; qset->qh.scratch[0] = 0; From 38ab0c5899c62dc2418ee153b7d713c42e35cb7a Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 16 Nov 2011 11:39:52 +0100 Subject: [PATCH 0401/4025] HID: Correct General touch PID commit b1807719f6acdf18cc4bde3b5400d05d77801494 upstream. Genera Touch told us that 0001 is their single point device and 0003 is the multitouch one. Apparently, we made the tests someone having a prototype, and not the final product. They said it should be safe to do the switch. This partially reverts 5572da0 ("HID: hid-mulitouch: add support for the 'Sensing Win7-TwoFinger'"). Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 2 +- drivers/hid/hid-ids.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 4f81d2048a7..763797da2d8 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1721,8 +1721,8 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) }, + { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) }, { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30) }, { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index c97003c1b0b..206f75021d5 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -266,7 +266,7 @@ #define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR 0x0002 #define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc -#define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0001 +#define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0003 #define USB_VENDOR_ID_GLAB 0x06c2 #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 From a92036166be8faf15d6d0dfb30b1b07020d4704c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= Date: Wed, 30 Nov 2011 17:01:04 +0100 Subject: [PATCH 0402/4025] usb: ftdi_sio: add PID for Propox ISPcable III MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 307369b0ca06b27b511b61714e335ddfccf19c4f upstream. Signed-off-by: Marcin Kościelnicki Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 486769c0f35..b02fd5027cc 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -735,6 +735,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) }, { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID), diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 571fa96b49c..055b64ef0bb 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -112,6 +112,7 @@ /* Propox devices */ #define FTDI_PROPOX_JTAGCABLEII_PID 0xD738 +#define FTDI_PROPOX_ISPCABLEIII_PID 0xD739 /* Lenz LI-USB Computer Interface. */ #define FTDI_LENZ_LIUSB_PID 0xD780 From 603eb878125425a73e02f6d78961217e16d1ec36 Mon Sep 17 00:00:00 2001 From: Dirk Nehring Date: Thu, 24 Nov 2011 19:22:23 +0100 Subject: [PATCH 0403/4025] usb: option: add Huawei E353 controlling interfaces commit 46b1848360c8e634e0b063932a1261062fa0f7d6 upstream. This patch creates the missing controlling devices for the Huawei E353 HSPA+ stick. Signed-off-by: Dirk Nehring Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 3a47cbe9fc5..eeab0ad9bf4 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -657,6 +657,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x31) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x32) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x02) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x03) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x08) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) }, From afbbd6cdb65e179d32e0eabe5505ab49c792456f Mon Sep 17 00:00:00 2001 From: Veli-Pekka Peltola Date: Thu, 24 Nov 2011 22:08:56 +0200 Subject: [PATCH 0404/4025] usb: option: add SIMCom SIM5218 commit ec0cd94d881ca89cc9fb61d00d0f4b2b52e605b3 upstream. Tested with SIM5218EVB-KIT evaluation kit. Signed-off-by: Veli-Pekka Peltola Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index eeab0ad9bf4..e98a1e1e508 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -746,6 +746,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) }, { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) }, From d886ad3f999fe0f647cdc24b3dda7d973f6c6213 Mon Sep 17 00:00:00 2001 From: Qinglin Ye Date: Wed, 23 Nov 2011 23:39:32 +0800 Subject: [PATCH 0405/4025] USB: usb-storage: unusual_devs entry for Kingston DT 101 G2 commit cec28a5428793b6bc64e56687fb239759d6da74e upstream. Kingston DT 101 G2 replies a wrong tag while transporting, add an unusal_devs entry to ignore the tag validation. Signed-off-by: Qinglin Ye Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 3041a974faf..24caba79d72 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1854,6 +1854,13 @@ UNUSUAL_DEV( 0x1370, 0x6828, 0x0110, 0x0110, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Qinglin Ye */ +UNUSUAL_DEV( 0x13fe, 0x3600, 0x0100, 0x0100, + "Kingston", + "DT 101 G2", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BULK_IGNORE_TAG ), + /* Reported by Francesco Foresti */ UNUSUAL_DEV( 0x14cd, 0x6600, 0x0201, 0x0201, "Super Top", From 775b1066cf7cc987d106d08433bd7188c95fba7d Mon Sep 17 00:00:00 2001 From: Thomas Poussevin Date: Thu, 27 Oct 2011 18:46:48 +0200 Subject: [PATCH 0406/4025] USB: EHCI: fix HUB TT scheduling issue with iso transfer commit 811c926c538f7e8d3c08b630dd5844efd7e000f6 upstream. The current TT scheduling doesn't allow to play and then record on a full-speed device connected to a high speed hub. The IN iso stream can only start on the first uframe (0-2 for a 165 us) because of CSPLIT transactions. For the OUT iso stream there no such restriction. uframe 0-5 are possible. The idea of this patch is that the first uframe are precious (for IN TT iso stream) and we should allocate the last uframes first if possible. For that we reverse the order of uframe allocation (last uframe first). Here an example : hid interrupt stream ---------------------------------------------------------------------- uframe | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ---------------------------------------------------------------------- max_tt_usecs | 125 | 125 | 125 | 125 | 125 | 125 | 30 | 0 | ---------------------------------------------------------------------- used usecs on a frame | 13 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ---------------------------------------------------------------------- iso OUT stream ---------------------------------------------------------------------- uframe | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ---------------------------------------------------------------------- max_tt_usecs | 125 | 125 | 125 | 125 | 125 | 125 | 30 | 0 | ---------------------------------------------------------------------- used usecs on a frame | 13 | 125 | 39 | 0 | 0 | 0 | 0 | 0 | ---------------------------------------------------------------------- There no place for iso IN stream (uframe 0-2 are used) and we got "cannot submit datapipe for urb 0, error -28: not enough bandwidth" error. With the patch this become. iso OUT stream ---------------------------------------------------------------------- uframe | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ---------------------------------------------------------------------- max_tt_usecs | 125 | 125 | 125 | 125 | 125 | 125 | 30 | 0 | ---------------------------------------------------------------------- used usecs on a frame | 13 | 0 | 0 | 0 | 125 | 39 | 0 | 0 | ---------------------------------------------------------------------- iso IN stream ---------------------------------------------------------------------- uframe | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ---------------------------------------------------------------------- max_tt_usecs | 125 | 125 | 125 | 125 | 125 | 125 | 30 | 0 | ---------------------------------------------------------------------- used usecs on a frame | 13 | 0 | 125 | 40 | 125 | 39 | 0 | 0 | ---------------------------------------------------------------------- Signed-off-by: Matthieu Castet Signed-off-by: Thomas Poussevin Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 063c630d246..fb2d0c2f067 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1483,10 +1483,15 @@ iso_stream_schedule ( /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ - /* find a uframe slot with enough bandwidth */ - next = start + period; - for (; start < next; start++) { - + /* find a uframe slot with enough bandwidth. + * Early uframes are more precious because full-speed + * iso IN transfers can't use late uframes, + * and therefore they should be allocated last. + */ + next = start; + start += period; + do { + start--; /* check schedule: enough space? */ if (stream->highspeed) { if (itd_slot_ok(ehci, mod, start, @@ -1499,7 +1504,7 @@ iso_stream_schedule ( start, sched, period)) break; } - } + } while (start > next); /* no room in the schedule */ if (start == next) { From 316624d43b9dbb64bb8e5eaf9908cfef6b4373a8 Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Mon, 28 Nov 2011 11:30:22 +0100 Subject: [PATCH 0407/4025] EHCI : Fix a regression in the ISO scheduler commit e3420901eba65b1c46bed86d360e3a8685d20734 upstream. Fix a regression that was introduced by commit 811c926c538f7e8d3c08b630dd5844efd7e000f6 (USB: EHCI: fix HUB TT scheduling issue with iso transfer). We detect an error if next == start, but this means uframe 0 can't be allocated anymore for iso transfer... Reported-by: Sander Eikelenboom Signed-off-by: Matthieu CASTET Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index fb2d0c2f067..8949b239dec 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1479,6 +1479,7 @@ iso_stream_schedule ( * jump until after the queue is primed. */ else { + int done = 0; start = SCHEDULE_SLOP + (now & ~0x07); /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ @@ -1496,18 +1497,18 @@ iso_stream_schedule ( if (stream->highspeed) { if (itd_slot_ok(ehci, mod, start, stream->usecs, period)) - break; + done = 1; } else { if ((start % 8) >= 6) continue; if (sitd_slot_ok(ehci, mod, stream, start, sched, period)) - break; + done = 1; } - } while (start > next); + } while (start > next && !done); /* no room in the schedule */ - if (start == next) { + if (!done) { ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n", urb, now, now + mod); status = -ENOSPC; From 15f2701a1eaf135eaab75987e4517daf5d88b880 Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Wed, 30 Nov 2011 16:37:41 +0800 Subject: [PATCH 0408/4025] xHCI: fix bug in xhci_clear_command_ring() commit 158886cd2cf4599e04f9b7e10cb767f5f39b14f1 upstream. When system enters suspend, xHCI driver clears command ring by writing zero to all the TRBs. However, this also writes zero to the Link TRB, and the ring is mangled. This may cause driver accesses wrong memory address and the result is unpredicted. When clear the command ring, keep the last Link TRB intact, only clear its cycle bit. This should fix the "command ring full" issue reported by Oliver Neukum. This should be backported to stable kernels as old as 2.6.37, since the commit 89821320 "xhci: Fix command ring replay after resume" is merged. Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Reported-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 1f0e198a865..221f14e1fdd 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -657,7 +657,10 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci) ring = xhci->cmd_ring; seg = ring->deq_seg; do { - memset(seg->trbs, 0, SEGMENT_SIZE); + memset(seg->trbs, 0, + sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1)); + seg->trbs[TRBS_PER_SEGMENT - 1].link.control &= + cpu_to_le32(~TRB_CYCLE); seg = seg->next; } while (seg != ring->deq_seg); From 1f076488aa92f7e26d34f385d3b4f738f975e2ff Mon Sep 17 00:00:00 2001 From: Salman Qazi Date: Tue, 15 Nov 2011 14:12:06 -0800 Subject: [PATCH 0409/4025] sched, x86: Avoid unnecessary overflow in sched_clock commit 4cecf6d401a01d054afc1e5f605bcbfe553cb9b9 upstream. (Added the missing signed-off-by line) In hundreds of days, the __cycles_2_ns calculation in sched_clock has an overflow. cyc * per_cpu(cyc2ns, cpu) exceeds 64 bits, causing the final value to become zero. We can solve this without losing any precision. We can decompose TSC into quotient and remainder of division by the scale factor, and then use this to convert TSC into nanoseconds. Signed-off-by: Salman Qazi Acked-by: John Stultz Reviewed-by: Paul Turner Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/r/20111115221121.7262.88871.stgit@dungbeetle.mtv.corp.google.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/timer.h | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/timer.h b/arch/x86/include/asm/timer.h index fa7b9176b76..431793e5d48 100644 --- a/arch/x86/include/asm/timer.h +++ b/arch/x86/include/asm/timer.h @@ -32,6 +32,22 @@ extern int no_timer_check; * (mathieu.desnoyers@polymtl.ca) * * -johnstul@us.ibm.com "math is hard, lets go shopping!" + * + * In: + * + * ns = cycles * cyc2ns_scale / SC + * + * Although we may still have enough bits to store the value of ns, + * in some cases, we may not have enough bits to store cycles * cyc2ns_scale, + * leading to an incorrect result. + * + * To avoid this, we can decompose 'cycles' into quotient and remainder + * of division by SC. Then, + * + * ns = (quot * SC + rem) * cyc2ns_scale / SC + * = quot * cyc2ns_scale + (rem * cyc2ns_scale) / SC + * + * - sqazi@google.com */ DECLARE_PER_CPU(unsigned long, cyc2ns); @@ -41,9 +57,14 @@ DECLARE_PER_CPU(unsigned long long, cyc2ns_offset); static inline unsigned long long __cycles_2_ns(unsigned long long cyc) { + unsigned long long quot; + unsigned long long rem; int cpu = smp_processor_id(); unsigned long long ns = per_cpu(cyc2ns_offset, cpu); - ns += cyc * per_cpu(cyc2ns, cpu) >> CYC2NS_SCALE_FACTOR; + quot = (cyc >> CYC2NS_SCALE_FACTOR); + rem = cyc & ((1ULL << CYC2NS_SCALE_FACTOR) - 1); + ns += quot * per_cpu(cyc2ns, cpu) + + ((rem * per_cpu(cyc2ns, cpu)) >> CYC2NS_SCALE_FACTOR); return ns; } From a1b8e912f4a2381f8d38996a87b183bce59f1920 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 25 Sep 2011 15:29:00 -0600 Subject: [PATCH 0410/4025] x86/mpparse: Account for bus types other than ISA and PCI commit 9e6866686bdf2dcf3aeb0838076237ede532dcc8 upstream. In commit f8924e770e04 ("x86: unify mp_bus_info"), the 32-bit and 64-bit versions of MP_bus_info were rearranged to match each other better. Unfortunately it introduced a regression: prior to that change we used to always set the mp_bus_not_pci bit, then clear it if we found a PCI bus. After it, we set mp_bus_not_pci for ISA buses, clear it for PCI buses, and leave it alone otherwise. In the cases of ISA and PCI, there's not much difference. But ISA is not the only non-PCI bus, so it's better to always set mp_bus_not_pci and clear it only for PCI. Without this change, Dan's Dell PowerEdge 4200 panics on boot with a log indicating interrupt routing trouble unless the "noapic" option is supplied. With this change, the machine boots reliably without "noapic". Fixes http://bugs.debian.org/586494 Reported-bisected-and-tested-by: Dan McGrath Signed-off-by: Bjorn Helgaas Cc: Dan McGrath Cc: Alexey Starikovskiy [jrnieder@gmail.com: clarified commit message] Signed-off-by: Jonathan Nieder Link: http://lkml.kernel.org/r/20111122215000.GA9151@elie.hsd1.il.comcast.net Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/mpparse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index 9103b89c145..0741b062a30 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -95,8 +95,8 @@ static void __init MP_bus_info(struct mpc_bus *m) } #endif + set_bit(m->busid, mp_bus_not_pci); if (strncmp(str, BUSTYPE_ISA, sizeof(BUSTYPE_ISA) - 1) == 0) { - set_bit(m->busid, mp_bus_not_pci); #if defined(CONFIG_EISA) || defined(CONFIG_MCA) mp_bus_id_to_type[m->busid] = MP_BUS_ISA; #endif From c060a3d5e9bba4271331b69b9e2c53105999b97f Mon Sep 17 00:00:00 2001 From: Peter Chubb Date: Mon, 5 Dec 2011 16:53:53 +0300 Subject: [PATCH 0411/4025] x86: Fix "Acer Aspire 1" reboot hang MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 1ef03890969932e9359b9a4c658f7f87771910ac upstream. Looks like on some Acer Aspire 1s with older bioses, reboot via bios fails. It works on my machine, (with BIOS version 0.3310) but not on some others (BIOS version 0.3309). There's a log of problems at: https://bbs.archlinux.org/viewtopic.php?id=124136 This patch adds a different callback to the reboot quirk table, to allow rebooting via keybaord controller. Reported-by: Uroš Vampl Tested-by: Vasily Khoruzhick Signed-off-by: Peter Chubb Cc: Don Zickus Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1323093233-9481-1-git-send-email-anarsoul@gmail.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/reboot.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 9242436e993..d4a705f2283 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -124,7 +124,7 @@ __setup("reboot=", reboot_setup); */ /* - * Some machines require the "reboot=b" commandline option, + * Some machines require the "reboot=b" or "reboot=k" commandline options, * this quirk makes that automatic. */ static int __init set_bios_reboot(const struct dmi_system_id *d) @@ -136,6 +136,15 @@ static int __init set_bios_reboot(const struct dmi_system_id *d) return 0; } +static int __init set_kbd_reboot(const struct dmi_system_id *d) +{ + if (reboot_type != BOOT_KBD) { + reboot_type = BOOT_KBD; + printk(KERN_INFO "%s series board detected. Selecting KBD-method for reboot.\n", d->ident); + } + return 0; +} + static struct dmi_system_id __initdata reboot_dmi_table[] = { { /* Handle problems with rebooting on Dell E520's */ .callback = set_bios_reboot, @@ -295,7 +304,7 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { }, }, { /* Handle reboot issue on Acer Aspire one */ - .callback = set_bios_reboot, + .callback = set_kbd_reboot, .ident = "Acer Aspire One A110", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), From 347736f0fa8ffc5f89df7bc507a0beb90a5127b5 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Tue, 15 Nov 2011 14:49:09 -0800 Subject: [PATCH 0412/4025] x86/paravirt: PTE updates in k(un)map_atomic need to be synchronous, regardless of lazy_mmu mode commit 2cd1c8d4dc7ecca9e9431e2dabe41ae9c7d89e51 upstream. Fix an outstanding issue that has been reported since 2.6.37. Under a heavy loaded machine processing "fork()" calls could crash with: BUG: unable to handle kernel paging request at f573fc8c IP: [] swap_count_continued+0x104/0x180 *pdpt = 000000002a3b9027 *pde = 0000000001bed067 *pte = 0000000000000000 Oops: 0000 [#1] SMP Modules linked in: Pid: 1638, comm: apache2 Not tainted 3.0.4-linode37 #1 EIP: 0061:[] EFLAGS: 00210246 CPU: 3 EIP is at swap_count_continued+0x104/0x180 .. snip.. Call Trace: [] ? __swap_duplicate+0xc2/0x160 [] ? pte_mfn_to_pfn+0x87/0xe0 [] ? swap_duplicate+0x14/0x40 [] ? copy_pte_range+0x45b/0x500 [] ? copy_page_range+0x195/0x200 [] ? dup_mmap+0x1c6/0x2c0 [] ? dup_mm+0xa8/0x130 [] ? copy_process+0x98a/0xb30 [] ? do_fork+0x4f/0x280 [] ? getnstimeofday+0x43/0x100 [] ? sys_clone+0x30/0x40 [] ? ptregs_clone+0x15/0x48 [] ? syscall_call+0x7/0xb The problem is that in copy_page_range() we turn lazy mode on, and then in swap_entry_free() we call swap_count_continued() which ends up in: map = kmap_atomic(page, KM_USER0) + offset; and then later we touch *map. Since we are running in batched mode (lazy) we don't actually set up the PTE mappings and the kmap_atomic is not done synchronously and ends up trying to dereference a page that has not been set. Looking at kmap_atomic_prot_pfn(), it uses 'arch_flush_lazy_mmu_mode' and doing the same in kmap_atomic_prot() and __kunmap_atomic() makes the problem go away. Interestingly, commit b8bcfe997e4615 ("x86/paravirt: remove lazy mode in interrupts") removed part of this to fix an interrupt issue - but it went to far and did not consider this scenario. Signed-off-by: Konrad Rzeszutek Wilk Cc: Peter Zijlstra Cc: Jeremy Fitzhardinge Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/highmem_32.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c index b4996266210..f4f29b19fac 100644 --- a/arch/x86/mm/highmem_32.c +++ b/arch/x86/mm/highmem_32.c @@ -45,6 +45,7 @@ void *kmap_atomic_prot(struct page *page, pgprot_t prot) vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); BUG_ON(!pte_none(*(kmap_pte-idx))); set_pte(kmap_pte-idx, mk_pte(page, prot)); + arch_flush_lazy_mmu_mode(); return (void *)vaddr; } @@ -88,6 +89,7 @@ void __kunmap_atomic(void *kvaddr) */ kpte_clear_flush(kmap_pte-idx, vaddr); kmap_atomic_idx_pop(); + arch_flush_lazy_mmu_mode(); } #ifdef CONFIG_DEBUG_HIGHMEM else { From 1e52c65de4b0f35f79ffa0a692f0a1174c7cf7ab Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 7 Oct 2011 13:36:40 +0200 Subject: [PATCH 0413/4025] perf/x86: Fix PEBS instruction unwind commit 57d1c0c03c6b48b2b96870d831b9ce6b917f53ac upstream. Masami spotted that we always try to decode the instruction stream as 64bit instructions when running a 64bit kernel, this doesn't work for ia32-compat proglets. Use TIF_IA32 to detect if we need to use the 32bit instruction decoder. Reported-by: Masami Hiramatsu Signed-off-by: Peter Zijlstra Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/perf_event_intel_ds.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c index bab491b8ee2..d812fe2d02b 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_ds.c +++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c @@ -508,6 +508,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs) unsigned long from = cpuc->lbr_entries[0].from; unsigned long old_to, to = cpuc->lbr_entries[0].to; unsigned long ip = regs->ip; + int is_64bit = 0; /* * We don't need to fixup if the PEBS assist is fault like @@ -559,7 +560,10 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs) } else kaddr = (void *)to; - kernel_insn_init(&insn, kaddr); +#ifdef CONFIG_X86_64 + is_64bit = kernel_ip(to) || !test_thread_flag(TIF_IA32); +#endif + insn_init(&insn, kaddr, is_64bit); insn_get_length(&insn); to += insn.length; } while (to < ip); From b3e838f4ee691c0e4f4e1a90d951f2acd63ab0ea Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 10 Oct 2011 16:21:10 +0200 Subject: [PATCH 0414/4025] oprofile, x86: Fix crash when unloading module (nmi timer mode) commit 97f7f8189fe54e3cfe324ef9ad35064f3d2d3bff upstream. If oprofile uses the nmi timer interrupt there is a crash while unloading the module. The bug can be triggered with oprofile build as module and kernel parameter nolapic set. This patch fixes this. oprofile: using NMI timer interrupt. BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 IP: [] unregister_syscore_ops+0x41/0x58 PGD 42dbca067 PUD 41da6a067 PMD 0 Oops: 0002 [#1] PREEMPT SMP CPU 5 Modules linked in: oprofile(-) [last unloaded: oprofile] Pid: 2518, comm: modprobe Not tainted 3.1.0-rc7-00019-gb2fb49d #19 Advanced Micro Device Anaheim/Anaheim RIP: 0010:[] [] unregister_syscore_ops+0x41/0x58 RSP: 0018:ffff88041ef71e98 EFLAGS: 00010296 RAX: 0000000000000000 RBX: ffffffffa0017100 RCX: dead000000200200 RDX: 0000000000000000 RSI: dead000000100100 RDI: ffffffff8178c620 RBP: ffff88041ef71ea8 R08: 0000000000000001 R09: 0000000000000082 R10: 0000000000000000 R11: ffff88041ef71de8 R12: 0000000000000080 R13: fffffffffffffff5 R14: 0000000000000001 R15: 0000000000610210 FS: 00007fc902f20700(0000) GS:ffff88042fd40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000008 CR3: 000000041cdb6000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process modprobe (pid: 2518, threadinfo ffff88041ef70000, task ffff88041d348040) Stack: ffff88041ef71eb8 ffffffffa0017790 ffff88041ef71eb8 ffffffffa0013532 ffff88041ef71ec8 ffffffffa00132d6 ffff88041ef71ed8 ffffffffa00159b2 ffff88041ef71f78 ffffffff81073115 656c69666f72706f 0000000000610200 Call Trace: [] op_nmi_exit+0x15/0x17 [oprofile] [] oprofile_arch_exit+0xe/0x10 [oprofile] [] oprofile_exit+0x1e/0x20 [oprofile] [] sys_delete_module+0x1c3/0x22f [] ? trace_hardirqs_on_thunk+0x3a/0x3f [] system_call_fastpath+0x16/0x1b Code: 20 c6 78 81 e8 c5 cc 23 00 48 8b 13 48 8b 43 08 48 be 00 01 10 00 00 00 ad de 48 b9 00 02 20 00 00 00 ad de 48 c7 c7 20 c6 78 81 89 42 08 48 89 10 48 89 33 48 89 4b 08 e8 a6 c0 23 00 5a 5b RIP [] unregister_syscore_ops+0x41/0x58 RSP CR2: 0000000000000008 ---[ end trace 43a541a52956b7b0 ]--- Signed-off-by: Robert Richter Signed-off-by: Greg Kroah-Hartman --- arch/x86/oprofile/init.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/x86/oprofile/init.c b/arch/x86/oprofile/init.c index cdfe4c54dec..f148cf65267 100644 --- a/arch/x86/oprofile/init.c +++ b/arch/x86/oprofile/init.c @@ -21,6 +21,7 @@ extern int op_nmi_timer_init(struct oprofile_operations *ops); extern void op_nmi_exit(void); extern void x86_backtrace(struct pt_regs * const regs, unsigned int depth); +static int nmi_timer; int __init oprofile_arch_init(struct oprofile_operations *ops) { @@ -31,8 +32,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) #ifdef CONFIG_X86_LOCAL_APIC ret = op_nmi_init(ops); #endif + nmi_timer = (ret != 0); #ifdef CONFIG_X86_IO_APIC - if (ret < 0) + if (nmi_timer) ret = op_nmi_timer_init(ops); #endif ops->backtrace = x86_backtrace; @@ -44,6 +46,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) void oprofile_arch_exit(void) { #ifdef CONFIG_X86_LOCAL_APIC - op_nmi_exit(); + if (!nmi_timer) + op_nmi_exit(); #endif } From a89c8adbd9813435ccc29699e3dd474c1b823058 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 1 Dec 2011 13:32:17 +0100 Subject: [PATCH 0415/4025] add missing .set function for NT_S390_LAST_BREAK regset commit b934069c991355d27a053a932591c77960f4e414 upstream. The last breaking event address is a read-only value, the regset misses the .set function. If a PTRACE_SETREGSET is done for NT_S390_LAST_BREAK we get an oops due to a branch to zero: Kernel BUG at 0000000000000002 verbose debug info unavailable illegal operation: 0001 #1 SMP ... Call Trace: (<0000000000158294> ptrace_regset+0x184/0x188) <00000000001595b6> ptrace_request+0x37a/0x4fc <0000000000109a78> arch_ptrace+0x108/0x1fc <00000000001590d6> SyS_ptrace+0xaa/0x12c <00000000005c7a42> sysc_noemu+0x16/0x1c <000003fffd5ec10c> 0x3fffd5ec10c Last Breaking-Event-Address: <0000000000158242> ptrace_regset+0x132/0x188 Add a nop .set function to prevent the branch to zero. Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/ptrace.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index ae0e14b8880..5804cfa7cba 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -897,6 +897,14 @@ static int s390_last_break_get(struct task_struct *target, return 0; } +static int s390_last_break_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + return 0; +} + #endif static const struct user_regset s390_regsets[] = { @@ -923,6 +931,7 @@ static const struct user_regset s390_regsets[] = { .size = sizeof(long), .align = sizeof(long), .get = s390_last_break_get, + .set = s390_last_break_set, }, #endif }; @@ -1080,6 +1089,14 @@ static int s390_compat_last_break_get(struct task_struct *target, return 0; } +static int s390_compat_last_break_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + return 0; +} + static const struct user_regset s390_compat_regsets[] = { [REGSET_GENERAL] = { .core_note_type = NT_PRSTATUS, @@ -1103,6 +1120,7 @@ static const struct user_regset s390_compat_regsets[] = { .size = sizeof(long), .align = sizeof(long), .get = s390_compat_last_break_get, + .set = s390_compat_last_break_set, }, [REGSET_GENERAL_EXTENDED] = { .core_note_type = NT_S390_HIGH_GPRS, From 3ed26be17352133a2dadbc4212a5d23b403b0980 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 28 Nov 2011 16:47:15 -0500 Subject: [PATCH 0416/4025] cfg80211: fix race on init and driver registration commit a042994dd377d86bff9446ee76151ceb6267c9ba upstream. There is a theoretical race that if hit will trigger a crash. The race is between when we issue the first regulatory hint, regulatory_hint_core(), gets processed by the workqueue and between when the first device gets registered to the wireless core. This is not easy to reproduce but it was easy to do so through the regulatory simulator I have been working on. This is a port of the fix I implemented there [1]. [1] https://github.com/mcgrof/regsim/commit/a246ccf81f059cb662eee288aa13100f631e4cc8 Cc: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/wireless/reg.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 3c5ddeafb93..0625adade96 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -57,8 +57,17 @@ #define REG_DBG_PRINT(args...) #endif +static struct regulatory_request core_request_world = { + .initiator = NL80211_REGDOM_SET_BY_CORE, + .alpha2[0] = '0', + .alpha2[1] = '0', + .intersect = false, + .processed = true, + .country_ie_env = ENVIRON_ANY, +}; + /* Receipt of information from last regulatory request */ -static struct regulatory_request *last_request; +static struct regulatory_request *last_request = &core_request_world; /* To trigger userspace events */ static struct platform_device *reg_pdev; @@ -150,7 +159,7 @@ static char user_alpha2[2]; module_param(ieee80211_regdom, charp, 0444); MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); -static void reset_regdomains(void) +static void reset_regdomains(bool full_reset) { /* avoid freeing static information or freeing something twice */ if (cfg80211_regdomain == cfg80211_world_regdom) @@ -165,6 +174,13 @@ static void reset_regdomains(void) cfg80211_world_regdom = &world_regdom; cfg80211_regdomain = NULL; + + if (!full_reset) + return; + + if (last_request != &core_request_world) + kfree(last_request); + last_request = &core_request_world; } /* @@ -175,7 +191,7 @@ static void update_world_regdomain(const struct ieee80211_regdomain *rd) { BUG_ON(!last_request); - reset_regdomains(); + reset_regdomains(false); cfg80211_world_regdom = rd; cfg80211_regdomain = rd; @@ -1396,7 +1412,8 @@ static int __regulatory_hint(struct wiphy *wiphy, } new_request: - kfree(last_request); + if (last_request != &core_request_world) + kfree(last_request); last_request = pending_request; last_request->intersect = intersect; @@ -1566,9 +1583,6 @@ static int regulatory_hint_core(const char *alpha2) { struct regulatory_request *request; - kfree(last_request); - last_request = NULL; - request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL); if (!request) @@ -1766,7 +1780,7 @@ static void restore_regulatory_settings(bool reset_user) mutex_lock(&cfg80211_mutex); mutex_lock(®_mutex); - reset_regdomains(); + reset_regdomains(true); restore_alpha2(alpha2, reset_user); /* @@ -2035,7 +2049,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) int r; if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) { - reset_regdomains(); + reset_regdomains(false); cfg80211_regdomain = rd; return 0; } @@ -2056,7 +2070,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) if (r) return r; - reset_regdomains(); + reset_regdomains(false); cfg80211_regdomain = rd; return 0; } @@ -2081,7 +2095,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) rd = NULL; - reset_regdomains(); + reset_regdomains(false); cfg80211_regdomain = intersected_rd; return 0; @@ -2101,7 +2115,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) kfree(rd); rd = NULL; - reset_regdomains(); + reset_regdomains(false); cfg80211_regdomain = intersected_rd; return 0; @@ -2254,11 +2268,8 @@ void /* __init_or_exit */ regulatory_exit(void) mutex_lock(&cfg80211_mutex); mutex_lock(®_mutex); - reset_regdomains(); - - kfree(last_request); + reset_regdomains(true); - last_request = NULL; dev_set_uevent_suppress(®_pdev->dev, true); platform_device_unregister(reg_pdev); From 7e06614ab127e8c9de4af2e8f9d66953d3e68297 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 28 Nov 2011 16:47:16 -0500 Subject: [PATCH 0417/4025] cfg80211: amend regulatory NULL dereference fix commit 0bac71af6e66dc798bf07d0c0dd14ee5503362f9 upstream. Johannes' patch for "cfg80211: fix regulatory NULL dereference" broke user regulaotry hints and it did not address the fact that last_request was left populated even if the previous regulatory hint was stale due to the wiphy disappearing. Fix user reguluatory hints by only bailing out if for those regulatory hints where a request_wiphy is expected. The stale last_request considerations are addressed through the previous fixes on last_request where we reset the last_request to a static world regdom request upon reset_regdomains(). In this case though we further enhance the effect by simply restoring reguluatory settings completely. Cc: Johannes Berg Signed-off-by: Luis R. Rodriguez Reviewed-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/wireless/reg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 0625adade96..ca76d8b55c4 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2040,8 +2040,10 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) } request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); - if (!request_wiphy) { - reg_set_request_processed(); + if (!request_wiphy && + (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER || + last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)) { + schedule_delayed_work(®_timeout, 0); return -ENODEV; } From 0198f84095f61e3ae0643eddb76df9ac684dae43 Mon Sep 17 00:00:00 2001 From: Ido Yariv Date: Thu, 1 Dec 2011 13:55:08 +0200 Subject: [PATCH 0418/4025] genirq: Fix race condition when stopping the irq thread commit 550acb19269d65f32e9ac4ddb26c2b2070e37f1c upstream. In irq_wait_for_interrupt(), the should_stop member is verified before setting the task's state to TASK_INTERRUPTIBLE and calling schedule(). In case kthread_stop sets should_stop and wakes up the process after should_stop is checked by the irq thread but before the task's state is changed, the irq thread might never exit: kthread_stop irq_wait_for_interrupt ------------ ---------------------- ... ... while (!kthread_should_stop()) { kthread->should_stop = 1; wake_up_process(k); wait_for_completion(&kthread->exited); ... set_current_state(TASK_INTERRUPTIBLE); ... schedule(); } Fix this by checking if the thread should stop after modifying the task's state. [ tglx: Simplified it a bit ] Signed-off-by: Ido Yariv Link: http://lkml.kernel.org/r/1322740508-22640-1-git-send-email-ido@wizery.com Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/irq/manage.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 0a7840aeb0f..a1aadab09aa 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -620,8 +620,9 @@ static irqreturn_t irq_nested_primary_handler(int irq, void *dev_id) static int irq_wait_for_interrupt(struct irqaction *action) { + set_current_state(TASK_INTERRUPTIBLE); + while (!kthread_should_stop()) { - set_current_state(TASK_INTERRUPTIBLE); if (test_and_clear_bit(IRQTF_RUNTHREAD, &action->thread_flags)) { @@ -629,7 +630,9 @@ static int irq_wait_for_interrupt(struct irqaction *action) return 0; } schedule(); + set_current_state(TASK_INTERRUPTIBLE); } + __set_current_state(TASK_RUNNING); return -1; } From ee6dfa64be0c1e8976f20246278121bc9fcf1a24 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 18 Oct 2011 10:11:07 -0700 Subject: [PATCH 0419/4025] NFS: Prevent 3.0 from crashing if it receives a partial layout This is a backport of critical parts of commit 7c24d9489f "NFSv4.1: File layout only supports whole file layouts" It prevents the file layout driver from (incorrectly) using partial layouts, but ignores the part of the referenced commmit that relies on additional machinery to change the LAYOUTGET request based on layout driver. Signed-off-by: Fred Isaman Acked-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4filelayout.c | 8 ++++++++ fs/nfs/pnfs.c | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 614c4d287d7..75af81211e4 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c @@ -428,6 +428,14 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo, dprintk("--> %s\n", __func__); + /* FIXME: remove this check when layout segment support is added */ + if (lgr->range.offset != 0 || + lgr->range.length != NFS4_MAX_UINT64) { + dprintk("%s Only whole file layouts supported. Use MDS i/o\n", + __func__); + goto out; + } + if (fl->pattern_offset > lgr->range.offset) { dprintk("%s pattern_offset %lld too large\n", __func__, fl->pattern_offset); diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index a726c0afa76..36d2a29bfbe 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -980,7 +980,8 @@ pnfs_update_layout(struct inode *ino, arg.offset -= pg_offset; arg.length += pg_offset; } - arg.length = PAGE_CACHE_ALIGN(arg.length); + if (arg.length != NFS4_MAX_UINT64) + arg.length = PAGE_CACHE_ALIGN(arg.length); lseg = send_layoutget(lo, ctx, &arg, gfp_flags); if (!lseg && first) { From a980e5dccb3ff8cb8f77ff27264b13837958119d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Dec 2011 16:21:05 -0500 Subject: [PATCH 0420/4025] xfs: validate acl count commit fa8b18edd752a8b4e9d1ee2cd615b82c93cf8bba upstream. This prevents in-memory corruption and possible panics if the on-disk ACL is badly corrupted. Signed-off-by: Christoph Hellwig Signed-off-by: Ben Myers Acked-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman --- fs/xfs/linux-2.6/xfs_acl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/xfs/linux-2.6/xfs_acl.c b/fs/xfs/linux-2.6/xfs_acl.c index 39f4f809bb6..4b9fb915d44 100644 --- a/fs/xfs/linux-2.6/xfs_acl.c +++ b/fs/xfs/linux-2.6/xfs_acl.c @@ -42,6 +42,8 @@ xfs_acl_from_disk(struct xfs_acl *aclp) int count, i; count = be32_to_cpu(aclp->acl_cnt); + if (count > XFS_ACL_MAX_ENTRIES) + return ERR_PTR(-EFSCORRUPTED); acl = posix_acl_alloc(count, GFP_KERNEL); if (!acl) From edb9a31845c5ba0ff325daa58f17f881d60d1559 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Dec 2011 16:21:15 -0500 Subject: [PATCH 0421/4025] xfs: force buffer writeback before blocking on the ilock in inode reclaim commit 4dd2cb4a28b7ab1f37163a4eba280926a13a8749 upstream. If we are doing synchronous inode reclaim we block the VM from making progress in memory reclaim. So if we encouter a flush locked inode promote it in the delwri list and wake up xfsbufd to write it out now. Without this we can get hangs of up to 30 seconds during workloads hitting synchronous inode reclaim. The scheme is copied from what we do for dquot reclaims. Reported-by: Simon Kirby Signed-off-by: Christoph Hellwig Tested-by: Simon Kirby Signed-off-by: Ben Myers Acked-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman --- fs/xfs/linux-2.6/xfs_sync.c | 11 +++++++++++ fs/xfs/xfs_inode.c | 21 +++++++++++++++++++++ fs/xfs/xfs_inode.h | 1 + 3 files changed, 33 insertions(+) diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index 8ecad5ff9f9..b69688d0776 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -772,6 +772,17 @@ xfs_reclaim_inode( if (!xfs_iflock_nowait(ip)) { if (!(sync_mode & SYNC_WAIT)) goto out; + + /* + * If we only have a single dirty inode in a cluster there is + * a fair chance that the AIL push may have pushed it into + * the buffer, but xfsbufd won't touch it until 30 seconds + * from now, and thus we will lock up here. + * + * Promote the inode buffer to the front of the delwri list + * and wake up xfsbufd now. + */ + xfs_promote_inode(ip); xfs_iflock(ip); } diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index a098a20ca63..c6888a420c5 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -3099,6 +3099,27 @@ xfs_iflush_int( return XFS_ERROR(EFSCORRUPTED); } +void +xfs_promote_inode( + struct xfs_inode *ip) +{ + struct xfs_buf *bp; + + ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); + + bp = xfs_incore(ip->i_mount->m_ddev_targp, ip->i_imap.im_blkno, + ip->i_imap.im_len, XBF_TRYLOCK); + if (!bp) + return; + + if (XFS_BUF_ISDELAYWRITE(bp)) { + xfs_buf_delwri_promote(bp); + wake_up_process(ip->i_mount->m_ddev_targp->bt_task); + } + + xfs_buf_relse(bp); +} + /* * Return a pointer to the extent record at file index idx. */ diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 964cfea7768..28b3596453e 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -509,6 +509,7 @@ int xfs_iunlink(struct xfs_trans *, xfs_inode_t *); void xfs_iext_realloc(xfs_inode_t *, int, int); void xfs_iunpin_wait(xfs_inode_t *); int xfs_iflush(xfs_inode_t *, uint); +void xfs_promote_inode(struct xfs_inode *); void xfs_lock_inodes(xfs_inode_t **, int, uint); void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint); From e006de470fa793b770cb098b39b46212a35b1b2b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Dec 2011 16:21:30 -0500 Subject: [PATCH 0422/4025] xfs: fix attr2 vs large data fork assert commit 4c393a6059f8442a70512a48ce4639b882b6f6ad upstream. With Dmitry fsstress updates I've seen very reproducible crashes in xfs_attr_shortform_remove because xfs_attr_shortform_bytesfit claims that the attributes would not fit inline into the inode after removing an attribute. It turns out that we were operating on an inode with lots of delalloc extents, and thus an if_bytes values for the data fork that is larger than biggest possible on-disk storage for it which utterly confuses the code near the end of xfs_attr_shortform_bytesfit. Fix this by always allowing the current attribute fork, like we already do for the attr1 format, given that delalloc conversion will take care for moving either the data or attribute area out of line if it doesn't fit at that point - or making the point moot by merging extents at this point. Also document the function better, and clean up some loose bits. Reviewed-by: Dave Chinner Signed-off-by: Christoph Hellwig Signed-off-by: Ben Myers Acked-by: Dave Chinner Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_attr_leaf.c | 64 +++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index 71e90dc2aeb..f49ecf2e7d3 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c @@ -110,6 +110,7 @@ xfs_attr_namesp_match(int arg_flags, int ondisk_flags) /* * Query whether the requested number of additional bytes of extended * attribute space will be able to fit inline. + * * Returns zero if not, else the di_forkoff fork offset to be used in the * literal area for attribute data once the new bytes have been added. * @@ -122,7 +123,7 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes) int offset; int minforkoff; /* lower limit on valid forkoff locations */ int maxforkoff; /* upper limit on valid forkoff locations */ - int dsize; + int dsize; xfs_mount_t *mp = dp->i_mount; offset = (XFS_LITINO(mp) - bytes) >> 3; /* rounded down */ @@ -136,47 +137,60 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes) return (offset >= minforkoff) ? minforkoff : 0; } - if (!(mp->m_flags & XFS_MOUNT_ATTR2)) { - if (bytes <= XFS_IFORK_ASIZE(dp)) - return dp->i_d.di_forkoff; + /* + * If the requested numbers of bytes is smaller or equal to the + * current attribute fork size we can always proceed. + * + * Note that if_bytes in the data fork might actually be larger than + * the current data fork size is due to delalloc extents. In that + * case either the extent count will go down when they are converted + * to real extents, or the delalloc conversion will take care of the + * literal area rebalancing. + */ + if (bytes <= XFS_IFORK_ASIZE(dp)) + return dp->i_d.di_forkoff; + + /* + * For attr2 we can try to move the forkoff if there is space in the + * literal area, but for the old format we are done if there is no + * space in the fixed attribute fork. + */ + if (!(mp->m_flags & XFS_MOUNT_ATTR2)) return 0; - } dsize = dp->i_df.if_bytes; - + switch (dp->i_d.di_format) { case XFS_DINODE_FMT_EXTENTS: - /* + /* * If there is no attr fork and the data fork is extents, - * determine if creating the default attr fork will result - * in the extents form migrating to btree. If so, the - * minimum offset only needs to be the space required for + * determine if creating the default attr fork will result + * in the extents form migrating to btree. If so, the + * minimum offset only needs to be the space required for * the btree root. - */ + */ if (!dp->i_d.di_forkoff && dp->i_df.if_bytes > xfs_default_attroffset(dp)) dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS); break; - case XFS_DINODE_FMT_BTREE: /* - * If have data btree then keep forkoff if we have one, - * otherwise we are adding a new attr, so then we set - * minforkoff to where the btree root can finish so we have + * If we have a data btree then keep forkoff if we have one, + * otherwise we are adding a new attr, so then we set + * minforkoff to where the btree root can finish so we have * plenty of room for attrs */ if (dp->i_d.di_forkoff) { - if (offset < dp->i_d.di_forkoff) + if (offset < dp->i_d.di_forkoff) return 0; - else - return dp->i_d.di_forkoff; - } else - dsize = XFS_BMAP_BROOT_SPACE(dp->i_df.if_broot); + return dp->i_d.di_forkoff; + } + dsize = XFS_BMAP_BROOT_SPACE(dp->i_df.if_broot); break; } - - /* - * A data fork btree root must have space for at least + + /* + * A data fork btree root must have space for at least * MINDBTPTRS key/ptr pairs if the data fork is small or empty. */ minforkoff = MAX(dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS)); @@ -186,10 +200,10 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes) maxforkoff = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(MINABTPTRS); maxforkoff = maxforkoff >> 3; /* rounded down */ - if (offset >= minforkoff && offset < maxforkoff) - return offset; if (offset >= maxforkoff) return maxforkoff; + if (offset >= minforkoff) + return offset; return 0; } From 4e3cd8129cf10c92c8e88251b519703dc65523be Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 23 Nov 2011 08:49:49 -0800 Subject: [PATCH 0423/4025] trace_events_filter: Use rcu_assign_pointer() when setting ftrace_event_call->filter commit d3d9acf646679c1981032b0985b386d12fccc60c upstream. ftrace_event_call->filter is sched RCU protected but didn't use rcu_assign_pointer(). Use it. TODO: Add proper __rcu annotation to call->filter and all its users. -v2: Use RCU_INIT_POINTER() for %NULL clearing as suggested by Eric. Link: http://lkml.kernel.org/r/20111123164949.GA29639@google.com Cc: Eric Dumazet Cc: Frederic Weisbecker Cc: Jiri Olsa Signed-off-by: Tejun Heo Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_events_filter.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 256764ecccd..bd3c6369f80 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c @@ -1766,7 +1766,7 @@ static int replace_system_preds(struct event_subsystem *system, * replace the filter for the call. */ filter = call->filter; - call->filter = filter_item->filter; + rcu_assign_pointer(call->filter, filter_item->filter); filter_item->filter = filter; fail = false; @@ -1821,7 +1821,7 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) filter = call->filter; if (!filter) goto out_unlock; - call->filter = NULL; + RCU_INIT_POINTER(call->filter, NULL); /* Make sure the filter is not being used */ synchronize_sched(); __free_filter(filter); @@ -1862,7 +1862,7 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string) * string */ tmp = call->filter; - call->filter = filter; + rcu_assign_pointer(call->filter, filter); if (tmp) { /* Make sure the call is done with the filter */ synchronize_sched(); From 4ebbdc2c9aad8e28e1335755c728d31032b24cfb Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 22 Nov 2011 11:03:14 +0100 Subject: [PATCH 0424/4025] rtc: Disable the alarm in the hardware commit c0afabd3d553c521e003779c127143ffde55a16f upstream. Currently, the RTC code does not disable the alarm in the hardware. This means that after a sequence such as the one below (the files are in the RTC sysfs), the box will boot up after 2 minutes even though we've asked for the alarm to be turned off. # echo $((`cat since_epoch`)+120) > wakealarm # echo 0 > wakealarm # poweroff Fix this by disabling the alarm when there are no timers to run. Cc: John Stultz Signed-off-by: Rabin Vincent Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/interface.c | 44 +++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index eb4c88316a1..bbb6f852c5a 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -318,6 +318,20 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) } EXPORT_SYMBOL_GPL(rtc_read_alarm); +static int ___rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) +{ + int err; + + if (!rtc->ops) + err = -ENODEV; + else if (!rtc->ops->set_alarm) + err = -EINVAL; + else + err = rtc->ops->set_alarm(rtc->dev.parent, alarm); + + return err; +} + static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { struct rtc_time tm; @@ -341,14 +355,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) * over right here, before we set the alarm. */ - if (!rtc->ops) - err = -ENODEV; - else if (!rtc->ops->set_alarm) - err = -EINVAL; - else - err = rtc->ops->set_alarm(rtc->dev.parent, alarm); - - return err; + return ___rtc_set_alarm(rtc, alarm); } int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) @@ -762,6 +769,20 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) return 0; } +static void rtc_alarm_disable(struct rtc_device *rtc) +{ + struct rtc_wkalrm alarm; + struct rtc_time tm; + + __rtc_read_time(rtc, &tm); + + alarm.time = rtc_ktime_to_tm(ktime_add(rtc_tm_to_ktime(tm), + ktime_set(300, 0))); + alarm.enabled = 0; + + ___rtc_set_alarm(rtc, &alarm); +} + /** * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue * @rtc rtc device @@ -783,8 +804,10 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) struct rtc_wkalrm alarm; int err; next = timerqueue_getnext(&rtc->timerqueue); - if (!next) + if (!next) { + rtc_alarm_disable(rtc); return; + } alarm.time = rtc_ktime_to_tm(next->expires); alarm.enabled = 1; err = __rtc_set_alarm(rtc, &alarm); @@ -846,7 +869,8 @@ void rtc_timer_do_work(struct work_struct *work) err = __rtc_set_alarm(rtc, &alarm); if (err == -ETIME) goto again; - } + } else + rtc_alarm_disable(rtc); mutex_unlock(&rtc->ops_lock); } From eda31b190f7c7033b86ff6e8de3866a4ca25b7df Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Mon, 31 Oct 2011 11:07:42 +0200 Subject: [PATCH 0425/4025] tracing: fix event_subsystem ref counting commit cb59974742aea24adf6637eb0c4b8e7b48bca6fb upstream. Fix a bug introduced by e9dbfae5, which prevents event_subsystem from ever being released. Ref_count was added to keep track of subsystem users, not for counting events. Subsystem is created with ref_count = 1, so there is no need to increment it for every event, we have nr_events for that. Fix this by touching ref_count only when we actually have a new user - subsystem_open(). Signed-off-by: Ilya Dryomov Link: http://lkml.kernel.org/r/1320052062-7846-1-git-send-email-idryomov@gmail.com Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_events.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 3e2a7c91c54..2d049368242 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -1096,7 +1096,6 @@ event_subsystem_dir(const char *name, struct dentry *d_events) /* First see if we did not already create this dir */ list_for_each_entry(system, &event_subsystems, list) { if (strcmp(system->name, name) == 0) { - __get_system(system); system->nr_events++; return system->entry; } From d80dee54533aa4bfe29def921edb31715fdba214 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 2 Dec 2011 12:34:16 +0100 Subject: [PATCH 0426/4025] tick-broadcast: Stop active broadcast device when replacing it commit c1be84309c58b1e7c6d626e28fba41a22b364c3d upstream. When a better rated broadcast device is installed, then the current active device is not disabled, which results in two running broadcast devices. Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/time/tick-broadcast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index c7218d13273..7a90d021b79 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -71,7 +71,7 @@ int tick_check_broadcast_device(struct clock_event_device *dev) (dev->features & CLOCK_EVT_FEAT_C3STOP)) return 0; - clockevents_exchange_device(NULL, dev); + clockevents_exchange_device(tick_broadcast_device.evtdev, dev); tick_broadcast_device.evtdev = dev; if (!cpumask_empty(tick_get_broadcast_mask())) tick_broadcast_start_periodic(dev); From 248f3235861683bb1ffc7316b56bf783b162666f Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 4 Nov 2011 16:32:25 -0400 Subject: [PATCH 0427/4025] perf: Fix parsing of __print_flags() in TP_printk() commit d06c27b22aa66e48e32f03f9387328a9af9b0625 upstream. A update is made to the sched:sched_switch event that adds some logic to the first parameter of the __print_flags() that shows the state of tasks. This change cause perf to fail parsing the flags. A simple fix is needed to have the parser be able to process ops within the argument. Reported-by: Andrew Vagin Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/trace-event-parse.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 0a7ed5b5e28..6c164dc9ee9 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1537,6 +1537,8 @@ process_flags(struct event *event, struct print_arg *arg, char **tok) field = malloc_or_die(sizeof(*field)); type = process_arg(event, field, &token); + while (type == EVENT_OP) + type = process_op(event, field, &token); if (test_type_token(type, token, EVENT_DELIM, ",")) goto out_free; From 9140096a5b039dcdfbb0a005f4b9e6b17eb3123e Mon Sep 17 00:00:00 2001 From: Gleb Natapov Date: Tue, 18 Oct 2011 19:55:51 +0200 Subject: [PATCH 0428/4025] jump_label: jump_label_inc may return before the code is patched commit bbbf7af4bf8fc69bc751818cf30521080fa47dcb upstream. If cpu A calls jump_label_inc() just after atomic_add_return() is called by cpu B, atomic_inc_not_zero() will return value greater then zero and jump_label_inc() will return to a caller before jump_label_update() finishes its job on cpu B. Link: http://lkml.kernel.org/r/20111018175551.GH17571@redhat.com Cc: Peter Zijlstra Acked-by: Jason Baron Signed-off-by: Gleb Natapov Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- kernel/jump_label.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/jump_label.c b/kernel/jump_label.c index a8ce45097f3..e6f1f24ad57 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c @@ -66,8 +66,9 @@ void jump_label_inc(struct jump_label_key *key) return; jump_label_lock(); - if (atomic_add_return(1, &key->enabled) == 1) + if (atomic_read(&key->enabled) == 0) jump_label_update(key, JUMP_LABEL_ENABLE); + atomic_inc(&key->enabled); jump_label_unlock(); } From 0bbf5c70251286fbc3b7aac5e7961b4568115bfd Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Fri, 7 Oct 2011 16:31:46 +0200 Subject: [PATCH 0429/4025] oprofile: Fix crash when unloading module (hr timer mode) commit 87121ca504fd1d963a66b3fb0c72054b0fd9a177 upstream. Oprofile may crash in a KVM guest while unlaoding modules. This happens if oprofile_arch_init() fails and oprofile switches to the hr timer mode as a fallback. In this case oprofile_arch_exit() is called, but it never was initialized properly which causes the crash. This patch fixes this. oprofile: using timer interrupt. BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 IP: [] unregister_syscore_ops+0x41/0x58 PGD 41da3f067 PUD 41d80e067 PMD 0 Oops: 0002 [#1] PREEMPT SMP CPU 5 Modules linked in: oprofile(-) Pid: 2382, comm: modprobe Not tainted 3.1.0-rc7-00018-g709a39d #18 Advanced Micro Device Anaheim/Anaheim RIP: 0010:[] [] unregister_syscore_ops+0x41/0x58 RSP: 0018:ffff88041de1de98 EFLAGS: 00010296 RAX: 0000000000000000 RBX: ffffffffa00060e0 RCX: dead000000200200 RDX: 0000000000000000 RSI: dead000000100100 RDI: ffffffff8178c620 RBP: ffff88041de1dea8 R08: 0000000000000001 R09: 0000000000000082 R10: 0000000000000000 R11: ffff88041de1dde8 R12: 0000000000000080 R13: fffffffffffffff5 R14: 0000000000000001 R15: 0000000000610210 FS: 00007f9ae5bef700(0000) GS:ffff88042fd40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000008 CR3: 000000041ca44000 CR4: 00000000000006e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process modprobe (pid: 2382, threadinfo ffff88041de1c000, task ffff88042db6d040) Stack: ffff88041de1deb8 ffffffffa0006770 ffff88041de1deb8 ffffffffa000251e ffff88041de1dec8 ffffffffa00022c2 ffff88041de1ded8 ffffffffa0004993 ffff88041de1df78 ffffffff81073115 656c69666f72706f 0000000000610200 Call Trace: [] op_nmi_exit+0x15/0x17 [oprofile] [] oprofile_arch_exit+0xe/0x10 [oprofile] [] oprofile_exit+0x13/0x15 [oprofile] [] sys_delete_module+0x1c3/0x22f [] ? trace_hardirqs_on_thunk+0x3a/0x3f [] system_call_fastpath+0x16/0x1b Code: 20 c6 78 81 e8 c5 cc 23 00 48 8b 13 48 8b 43 08 48 be 00 01 10 00 00 00 ad de 48 b9 00 02 20 00 00 00 ad de 48 c7 c7 20 c6 78 81 89 42 08 48 89 10 48 89 33 48 89 4b 08 e8 a6 c0 23 00 5a 5b RIP [] unregister_syscore_ops+0x41/0x58 RSP CR2: 0000000000000008 ---[ end trace 06d4e95b6aa3b437 ]--- Signed-off-by: Robert Richter Signed-off-by: Greg Kroah-Hartman --- drivers/oprofile/oprof.c | 29 ++++++++++++++++++++++++----- drivers/oprofile/timer_int.c | 1 + 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index dccd8636095..f8c752e408a 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -239,26 +239,45 @@ int oprofile_set_ulong(unsigned long *addr, unsigned long val) return err; } +static int timer_mode; + static int __init oprofile_init(void) { int err; + /* always init architecture to setup backtrace support */ err = oprofile_arch_init(&oprofile_ops); - if (err < 0 || timer) { - printk(KERN_INFO "oprofile: using timer interrupt.\n"); + + timer_mode = err || timer; /* fall back to timer mode on errors */ + if (timer_mode) { + if (!err) + oprofile_arch_exit(); err = oprofile_timer_init(&oprofile_ops); if (err) return err; } - return oprofilefs_register(); + + err = oprofilefs_register(); + if (!err) + return 0; + + /* failed */ + if (timer_mode) + oprofile_timer_exit(); + else + oprofile_arch_exit(); + + return err; } static void __exit oprofile_exit(void) { - oprofile_timer_exit(); oprofilefs_unregister(); - oprofile_arch_exit(); + if (timer_mode) + oprofile_timer_exit(); + else + oprofile_arch_exit(); } diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c index 3ef44624f51..878fba12658 100644 --- a/drivers/oprofile/timer_int.c +++ b/drivers/oprofile/timer_int.c @@ -110,6 +110,7 @@ int oprofile_timer_init(struct oprofile_operations *ops) ops->start = oprofile_hrtimer_start; ops->stop = oprofile_hrtimer_stop; ops->cpu_type = "timer"; + printk(KERN_INFO "oprofile: using timer interrupt.\n"); return 0; } From 4078977c46f627f553ed2d8ea047b9bf25dee48d Mon Sep 17 00:00:00 2001 From: "Yang Honggang (Joseph)" Date: Thu, 1 Dec 2011 22:22:41 -0500 Subject: [PATCH 0430/4025] clocksource: Fix bug with max_deferment margin calculation commit b1f919664d04a8d0ba29cb76673c7ca3325a2006 upstream. In order to leave a margin of 12.5% we should >> 3 not >> 5. Signed-off-by: Yang Honggang (Joseph) [jstultz: Modified commit subject] Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- kernel/time/clocksource.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index e0980f0d9a0..8b270063b51 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -531,7 +531,7 @@ static u64 clocksource_max_deferment(struct clocksource *cs) * note a margin of 12.5% is used because this can be computed with * a shift, versus say 10% which would require division. */ - return max_nsecs - (max_nsecs >> 5); + return max_nsecs - (max_nsecs >> 3); } #ifndef CONFIG_ARCH_USES_GETTIMEOFFSET @@ -653,7 +653,7 @@ void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq) * ~ 0.06ppm granularity for NTP. We apply the same 12.5% * margin as we do in clocksource_max_deferment() */ - sec = (cs->mask - (cs->mask >> 5)); + sec = (cs->mask - (cs->mask >> 3)); do_div(sec, freq); do_div(sec, scale); if (!sec) From b01b383bbd04e9dcf7d9fe6ca3751b77ccdc533c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 2 Dec 2011 16:02:45 +0100 Subject: [PATCH 0431/4025] clockevents: Set noop handler in clockevents_exchange_device() commit de28f25e8244c7353abed8de0c7792f5f883588c upstream. If a device is shutdown, then there might be a pending interrupt, which will be processed after we reenable interrupts, which causes the original handler to be run. If the old handler is the (broadcast) periodic handler the shutdown state might hang the kernel completely. Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/time/clockevents.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index e4c699dfa4e..13dfaaba406 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -286,6 +286,7 @@ void clockevents_exchange_device(struct clock_event_device *old, * released list and do a notify add later. */ if (old) { + old->event_handler = clockevents_handle_noop; clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED); list_del(&old->list); list_add(&old->list, &clockevents_released); From d986a8dbfd7358bfbda116650c4caf8a3b90d865 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 9 Dec 2011 08:53:50 -0800 Subject: [PATCH 0432/4025] Linux 3.0.13 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 993fe0563e4..5ccc9620617 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 12 +SUBLEVEL = 13 EXTRAVERSION = NAME = Sneaky Weasel From dc1b6340394ef744e210247ab786df66639f5a33 Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Fri, 9 Dec 2011 18:05:00 -0800 Subject: [PATCH 0433/4025] usb: gadget: android: Don't allow changing the functions list if enabled Change-Id: I3ad39b420ce79a8602a7eca1daac1f56b30bad5c Signed-off-by: Benoit Goby --- drivers/usb/gadget/android.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 2b7631052ea..00a446bce3f 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -100,6 +100,7 @@ struct android_dev { struct device *dev; bool enabled; + struct mutex mutex; bool connected; bool sw_connected; struct work_struct work; @@ -774,8 +775,13 @@ functions_show(struct device *pdev, struct device_attribute *attr, char *buf) struct android_usb_function *f; char *buff = buf; + mutex_lock(&dev->mutex); + list_for_each_entry(f, &dev->enabled_functions, enabled_list) buff += sprintf(buff, "%s,", f->name); + + mutex_unlock(&dev->mutex); + if (buff != buf) *(buff-1) = '\n'; return buff - buf; @@ -790,6 +796,13 @@ functions_store(struct device *pdev, struct device_attribute *attr, char buf[256], *b; int err; + mutex_lock(&dev->mutex); + + if (dev->enabled) { + mutex_unlock(&dev->mutex); + return -EBUSY; + } + INIT_LIST_HEAD(&dev->enabled_functions); strncpy(buf, buff, sizeof(buf)); @@ -804,6 +817,8 @@ functions_store(struct device *pdev, struct device_attribute *attr, } } + mutex_unlock(&dev->mutex); + return size; } @@ -821,6 +836,8 @@ static ssize_t enable_store(struct device *pdev, struct device_attribute *attr, struct usb_composite_dev *cdev = dev->cdev; int enabled = 0; + mutex_lock(&dev->mutex); + sscanf(buff, "%d", &enabled); if (enabled && !dev->enabled) { cdev->next_string_id = 0; @@ -845,6 +862,8 @@ static ssize_t enable_store(struct device *pdev, struct device_attribute *attr, pr_err("android_usb: already %s\n", dev->enabled ? "enabled" : "disabled"); } + + mutex_unlock(&dev->mutex); return size; } @@ -878,9 +897,9 @@ field ## _show(struct device *dev, struct device_attribute *attr, \ } \ static ssize_t \ field ## _store(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t size) \ + const char *buf, size_t size) \ { \ - int value; \ + int value; \ if (sscanf(buf, format_string, &value) == 1) { \ device_desc.field = value; \ return size; \ @@ -898,10 +917,10 @@ field ## _show(struct device *dev, struct device_attribute *attr, \ } \ static ssize_t \ field ## _store(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t size) \ + const char *buf, size_t size) \ { \ if (size >= sizeof(buffer)) return -EINVAL; \ - if (sscanf(buf, "%s", buffer) == 1) { \ + if (sscanf(buf, "%s", buffer) == 1) { \ return size; \ } \ return -1; \ @@ -1136,6 +1155,7 @@ static int __init init(void) dev->functions = supported_functions; INIT_LIST_HEAD(&dev->enabled_functions); INIT_WORK(&dev->work, android_work); + mutex_init(&dev->mutex); err = android_create_device(dev); if (err) { From d948ec4839368c01b6ba401e942abb42d040c8f7 Mon Sep 17 00:00:00 2001 From: Ezekeel Date: Sun, 18 Dec 2011 07:09:00 +0100 Subject: [PATCH 0434/4025] Add power saving state DEEP IDLE version 2. --- arch/arm/mach-s5pv210/Kconfig | 7 + arch/arm/mach-s5pv210/Makefile | 1 + arch/arm/mach-s5pv210/cpuidle.c | 475 ++++++++++++++++++- arch/arm/mach-s5pv210/didle.S | 218 +++++++++ arch/arm/mach-s5pv210/herring-rfkill.c | 18 + arch/arm/mach-s5pv210/herring-vibrator.c | 18 + arch/arm/mach-s5pv210/include/mach/cpuidle.h | 16 + drivers/misc/Makefile | 1 + drivers/misc/deep_idle.c | 206 ++++++++ drivers/tty/serial/samsung.c | 22 +- include/linux/deep_idle.h | 9 + kernel/power/suspend.c | 8 + 12 files changed, 985 insertions(+), 14 deletions(-) create mode 100644 arch/arm/mach-s5pv210/didle.S create mode 100644 arch/arm/mach-s5pv210/include/mach/cpuidle.h create mode 100644 drivers/misc/deep_idle.c create mode 100644 include/linux/deep_idle.h diff --git a/arch/arm/mach-s5pv210/Kconfig b/arch/arm/mach-s5pv210/Kconfig index b564c24f87d..26672b07aa8 100644 --- a/arch/arm/mach-s5pv210/Kconfig +++ b/arch/arm/mach-s5pv210/Kconfig @@ -18,6 +18,13 @@ config CPU_S5PV210 help Enable S5PV210 CPU support +config CPU_DIDLE + bool "Enable DEEP IDLE support for S5PV210 CPU" + depends on CPU_IDLE + default n + help + Enable DEEP IDLE support for S5PV210 CPU. + config S5PV210_SETUP_I2C1 bool default y diff --git a/arch/arm/mach-s5pv210/Makefile b/arch/arm/mach-s5pv210/Makefile index ea207cbafa7..1c79fc9c213 100644 --- a/arch/arm/mach-s5pv210/Makefile +++ b/arch/arm/mach-s5pv210/Makefile @@ -59,3 +59,4 @@ obj-$(CONFIG_S5PV210_SETUP_FIMC2) += setup-fimc2.o obj-$(CONFIG_CPU_IDLE) += cpuidle.o obj-$(CONFIG_CPU_FREQ) += dev-cpufreq.o +obj-$(CONFIG_CPU_DIDLE) += didle.o diff --git a/arch/arm/mach-s5pv210/cpuidle.c b/arch/arm/mach-s5pv210/cpuidle.c index d7d532a4b26..742bcfac0e5 100644 --- a/arch/arm/mach-s5pv210/cpuidle.c +++ b/arch/arm/mach-s5pv210/cpuidle.c @@ -2,6 +2,7 @@ * arch/arm/mach-s5pv210/cpuidle.c * * Copyright (c) Samsung Electronics Co. Ltd + * (c) 2011 Ezekeel * * CPU idle driver for S5PV210 * @@ -21,21 +22,381 @@ #include #include #include +#include #include #include -#include -#include +#ifdef CONFIG_CPU_DIDLE +#include +#include + +#include +#include +#include + +extern bool suspend_ongoing(void); +extern bool bt_is_running(void); +extern bool gps_is_running(void); +extern bool vibrator_is_running(void); + +/* + * For saving & restoring VIC register before entering + * didle mode + */ +static unsigned long vic_regs[4]; +static unsigned long *regs_save; +static dma_addr_t phy_regs_save; + +#define MAX_CHK_DEV 0xf + +/* + * Specific device list for checking before entering + * didle mode + */ +struct check_device_op { + void __iomem *base; + struct platform_device *pdev; +}; + +/* Array of checking devices list */ +static struct check_device_op chk_dev_op[] = { +#if defined(CONFIG_S3C_DEV_HSMMC) + {.base = 0, .pdev = &s3c_device_hsmmc0}, +#endif +#if defined(CONFIG_S3C_DEV_HSMMC1) + {.base = 0, .pdev = &s3c_device_hsmmc1}, +#endif +#if 0 + {.base = 0, .pdev = &s3c_device_hsmmc2}, +#endif +#if defined(CONFIG_S3C_DEV_HSMMC3) + {.base = 0, .pdev = &s3c_device_hsmmc3}, +#endif + {.base = 0, .pdev = NULL}, +}; + +#define S3C_HSMMC_PRNSTS (0x24) +#define S3C_HSMMC_CLKCON (0x2c) +#define S3C_HSMMC_CMD_INHIBIT 0x00000001 +#define S3C_HSMMC_DATA_INHIBIT 0x00000002 +#define S3C_HSMMC_CLOCK_CARD_EN 0x0004 + +static int sdmmc_dev_num; +/* If SD/MMC interface is working: return = 1 or not 0 */ +static int check_sdmmc_op(unsigned int ch) +{ + unsigned int reg1, reg2; + void __iomem *base_addr; + + if (unlikely(ch > sdmmc_dev_num)) { + printk(KERN_ERR "Invalid ch[%d] for SD/MMC\n", ch); + return 0; + } + + base_addr = chk_dev_op[ch].base; + /* Check CMDINHDAT[1] and CMDINHCMD [0] */ + reg1 = readl(base_addr + S3C_HSMMC_PRNSTS); + /* Check CLKCON [2]: ENSDCLK */ + reg2 = readl(base_addr + S3C_HSMMC_CLKCON); + + return !!(reg1 & (S3C_HSMMC_CMD_INHIBIT | S3C_HSMMC_DATA_INHIBIT)) || + (reg2 & (S3C_HSMMC_CLOCK_CARD_EN)); +} + +/* Check all sdmmc controller */ +static int loop_sdmmc_check(void) +{ + unsigned int iter; + + for (iter = 0; iter < sdmmc_dev_num + 1; iter++) { + if (check_sdmmc_op(iter)) + return 1; + } + return 0; +} + +/* + * Check USBOTG is working or not + * GOTGCTL(0xEC000000) + * BSesVld (Indicates the Device mode transceiver status) + * BSesVld = 1b : B-session is valid + * 0b : B-session is not valid + */ +static int check_usbotg_op(void) +{ + unsigned int val; + + val = __raw_readl(S3C_UDC_OTG_GOTGCTL); + + return val & (B_SESSION_VALID); +} + +/* + * Check power gating : LCD, CAM, TV, MFC, G3D + * Check clock gating : DMA, USBHOST, I2C + */ +extern volatile int s5p_rp_is_running; +extern int s5p_rp_get_op_level(void); + +static int check_power_clock_gating(void) +{ + unsigned long val; + + /* check power gating */ + val = __raw_readl(S5P_NORMAL_CFG); + if (val & (S5PV210_PD_LCD | S5PV210_PD_CAM | S5PV210_PD_TV + | S5PV210_PD_MFC | S5PV210_PD_G3D)) + return 1; + +#ifdef CONFIG_SND_S5P_RP + if (s5p_rp_get_op_level()) + return 1; +#endif + /* check clock gating */ + val = __raw_readl(S5P_CLKGATE_IP0); + if (val & (S5P_CLKGATE_IP0_MDMA | S5P_CLKGATE_IP0_PDMA0 + | S5P_CLKGATE_IP0_PDMA1)) + return 1; + + val = __raw_readl(S5P_CLKGATE_IP1); + if (val & S5P_CLKGATE_IP1_USBHOST) + return 1; + + val = __raw_readl(S5P_CLKGATE_IP3); + if (val & (S5P_CLKGATE_IP3_I2C0 | S5P_CLKGATE_IP3_I2C_HDMI_DDC + | S5P_CLKGATE_IP3_I2C2)) + return 1; + + return 0; +} + +/* + * Skipping enter the didle mode when RTC & I2S interrupts be issued + * during critical section of entering didle mode (around 20ms). + */ +#ifdef CONFIG_S5P_INTERNAL_DMA +static int check_idmapos(void) +{ + dma_addr_t src; + + i2sdma_getpos(&src); + src = src & 0x3FFF; + src = 0x4000 - src; + + return src < 0x150; +} +#endif + +static int check_rtcint(void) +{ + unsigned int current_cnt = get_rtc_cnt(); + + return current_cnt < 0x40; +} + +/* + * Before entering, didle mode GPIO Powe Down Mode + * Configuration register has to be set with same state + * in Normal Mode + */ +#define GPIO_OFFSET 0x20 +#define GPIO_CON_PDN_OFFSET 0x10 +#define GPIO_PUD_PDN_OFFSET 0x14 +#define GPIO_PUD_OFFSET 0x08 + +static unsigned int pud_pdn[(S5PV210_MP28_BASE - S5PV210_GPA0_BASE) / GPIO_OFFSET + 1]; +static unsigned int con_pdn[(S5PV210_MP28_BASE - S5PV210_GPA0_BASE) / GPIO_OFFSET + 1]; + +static void s5p_gpio_pdn_conf(void) +{ + void __iomem *gpio_base = S5PV210_GPA0_BASE; + unsigned int val; + int i = 0; -#define S5PC110_MAX_STATES 1 + do { + /* Save power down control state */ + con_pdn[i] = __raw_readl(gpio_base + GPIO_CON_PDN_OFFSET); + /* Keep the previous state in didle mode */ + __raw_writel(0xffff, gpio_base + GPIO_CON_PDN_OFFSET); + + /* Save power down pull up-down state */ + pud_pdn[i] = __raw_readl(gpio_base + GPIO_PUD_PDN_OFFSET); + /* Pull up-down state in didle is same as normal */ + val = __raw_readl(gpio_base + GPIO_PUD_OFFSET); + __raw_writel(val, gpio_base + GPIO_PUD_PDN_OFFSET); + + gpio_base += GPIO_OFFSET; + i++; + + } while (gpio_base <= S5PV210_MP28_BASE); + + return; +} + +static void s5p_gpio_restore_conf(void) +{ + void __iomem *gpio_base = S5PV210_GPA0_BASE; + int i = 0; + + do { + /* Restore power down control state */ + __raw_writel(con_pdn[i], gpio_base + GPIO_CON_PDN_OFFSET); + + /* Restore power down pull up-down state */ + __raw_writel(pud_pdn[i], gpio_base + GPIO_PUD_PDN_OFFSET); + + gpio_base += GPIO_OFFSET; + i++; + + } while (gpio_base <= S5PV210_MP28_BASE); + + return; +} + +static void s5p_enter_didle(bool top_on) +{ + unsigned long tmp; + unsigned long save_eint_mask; + + /* store the physical address of the register recovery block */ + __raw_writel(phy_regs_save, S5P_INFORM2); + + /* ensure at least INFORM0 has the resume address */ + __raw_writel(virt_to_phys(s5pv210_didle_resume), S5P_INFORM0); + + /* Save current VIC_INT_ENABLE register*/ + vic_regs[0] = __raw_readl(S5P_VIC0REG(VIC_INT_ENABLE)); + vic_regs[1] = __raw_readl(S5P_VIC1REG(VIC_INT_ENABLE)); + vic_regs[2] = __raw_readl(S5P_VIC2REG(VIC_INT_ENABLE)); + vic_regs[3] = __raw_readl(S5P_VIC3REG(VIC_INT_ENABLE)); + + /* Disable all interrupt through VIC */ + __raw_writel(0xffffffff, S5P_VIC0REG(VIC_INT_ENABLE_CLEAR)); + __raw_writel(0xffffffff, S5P_VIC1REG(VIC_INT_ENABLE_CLEAR)); + __raw_writel(0xffffffff, S5P_VIC2REG(VIC_INT_ENABLE_CLEAR)); + __raw_writel(0xffffffff, S5P_VIC3REG(VIC_INT_ENABLE_CLEAR)); + + if (!top_on) { + /* GPIO Power Down Control */ + s5p_gpio_pdn_conf(); + } + + /* + * Configure external interrupt wakeup mask + * We use the same wakeup mask as for sleep state plus make sure + * that at least XEINT[22] = GPH2[6] = GPIO_nPOWER = GPIO_N_POWER + * and XEINT[29] = GPH3[5] = GPIO_OK_KEY are enabled + */ + save_eint_mask = __raw_readl(S5P_EINT_WAKEUP_MASK); + tmp = s3c_irqwake_eintmask; + tmp &= ~((1<<22) | (1<<29)); + __raw_writel(tmp, S5P_EINT_WAKEUP_MASK); + + /* Clear wakeup status register */ + tmp = __raw_readl(S5P_WAKEUP_STAT); + __raw_writel(tmp, S5P_WAKEUP_STAT); + + /* + * Wakeup source configuration for didle + * We use the same wakeup mask as for sleep state plus make + * sure that at least RTC ALARM, RTC TICK, KEY, I2S and ST are + * enabled as wakeup sources + */ + tmp = s3c_irqwake_intmask; + tmp &= ~((1<<1) | (1<<2) | (1<<5) | (1<<13) | (1<<14)); + __raw_writel(tmp, S5P_WAKEUP_MASK); + + tmp = __raw_readl(S5P_IDLE_CFG); + tmp &= ~(0x3fU << 26); + if (top_on) { + /* + * IDLE config register set + * TOP_LOGIC = ON + * TOP_MEMORY = ON + * ARM_L2CACHE = Retention + * CFG_DIDLE = DEEP + */ + tmp |= ((2<<30) | (2<<28) | (1<<26) | (1<<0)); + } else { + /* + * IDLE config register set + * TOP_LOGIC = Retention + * TOP_MEMORY = Retention + * ARM_L2CACHE = Retention + * CFG_DIDLE = DEEP + */ + tmp |= ((1<<30) | (1<<28) | (1<<26) | (1<<0)); + } + __raw_writel(tmp, S5P_IDLE_CFG); + + /* Power mode Config setting */ + tmp = __raw_readl(S5P_PWR_CFG); + tmp &= S5P_CFG_WFI_CLEAN; + tmp |= S5P_CFG_WFI_IDLE; + __raw_writel(tmp, S5P_PWR_CFG); + + /* To check VIC Status register before enter didle mode */ + if ((__raw_readl(S5P_VIC0REG(VIC_RAW_STATUS)) & vic_regs[0]) | + (__raw_readl(S5P_VIC1REG(VIC_RAW_STATUS)) & vic_regs[1]) | + (__raw_readl(S5P_VIC2REG(VIC_RAW_STATUS)) & vic_regs[2]) | + (__raw_readl(S5P_VIC3REG(VIC_RAW_STATUS)) & vic_regs[3])) + goto skipped_didle; + + /* SYSCON_INT_DISABLE */ + tmp = __raw_readl(S5P_OTHERS); + tmp |= S5P_OTHER_SYSC_INTOFF; + __raw_writel(tmp, S5P_OTHERS); + + /* + * s5pv210_didle_save will also act as our return point from when + * we resume as it saves its own register state and restore it + * during the resume. + */ + s5pv210_didle_save(regs_save); + + /* restore the cpu state using the kernel's cpu init code. */ + cpu_init(); + +skipped_didle: + __raw_writel(save_eint_mask, S5P_EINT_WAKEUP_MASK); + + tmp = __raw_readl(S5P_IDLE_CFG); + tmp &= ~((3<<30) | (3<<28) | (3<<26) | (1<<0)); + tmp |= ((2<<30) | (2<<28)); + __raw_writel(tmp, S5P_IDLE_CFG); + + /* Power mode Config setting */ + tmp = __raw_readl(S5P_PWR_CFG); + tmp &= S5P_CFG_WFI_CLEAN; + __raw_writel(tmp, S5P_PWR_CFG); + + if (!top_on) { + /* Release retention GPIO/CF/MMC/UART IO */ + tmp = __raw_readl(S5P_OTHERS); + tmp |= (S5P_OTHERS_RET_IO | S5P_OTHERS_RET_CF | \ + S5P_OTHERS_RET_MMC | S5P_OTHERS_RET_UART); + __raw_writel(tmp, S5P_OTHERS); + } + + if (!top_on) { + /* Restore GPIO Power Down Configuration */ + s5p_gpio_restore_conf(); + } + + __raw_writel(vic_regs[0], S5P_VIC0REG(VIC_INT_ENABLE)); + __raw_writel(vic_regs[1], S5P_VIC1REG(VIC_INT_ENABLE)); + __raw_writel(vic_regs[2], S5P_VIC2REG(VIC_INT_ENABLE)); + __raw_writel(vic_regs[3], S5P_VIC3REG(VIC_INT_ENABLE)); +} +#endif static void s5p_enter_idle(void) { unsigned long tmp; tmp = __raw_readl(S5P_IDLE_CFG); - tmp &= ~((3<<30)|(3<<28)|(1<<0)); - tmp |= ((2<<30)|(2<<28)); + tmp &= ~((3U<<30)|(3<<28)|(1<<0)); + tmp |= ((2U<<30)|(2<<28)); __raw_writel(tmp, S5P_IDLE_CFG); tmp = __raw_readl(S5P_PWR_CFG); @@ -46,21 +407,43 @@ static void s5p_enter_idle(void) } /* Actual code that puts the SoC in different idle states */ -static int s5p_enter_idle_normal(struct cpuidle_device *dev, +static int s5p_enter_idle_state(struct cpuidle_device *dev, struct cpuidle_state *state) { struct timeval before, after; int idle_time; +#ifdef CONFIG_CPU_DIDLE + int idle_state = 0; +#endif local_irq_disable(); do_gettimeofday(&before); +#ifdef CONFIG_CPU_DIDLE +#ifdef CONFIG_S5P_INTERNAL_DMA + if (!deepidle_is_enabled() || check_power_clock_gating() || suspend_ongoing() || loop_sdmmc_check() || check_usbotg_op() || check_rtcint() || check_idmapos()) { +#else + if (!deepidle_is_enabled() || check_power_clock_gating() || suspend_ongoing() || loop_sdmmc_check() || check_usbotg_op() || check_rtcint()) { +#endif + s5p_enter_idle(); + } else if (bt_is_running() || gps_is_running() || vibrator_is_running()) { + s5p_enter_didle(true); + idle_state = 1; + } else { + s5p_enter_didle(false); + idle_state = 2; + } +#else s5p_enter_idle(); +#endif do_gettimeofday(&after); local_irq_enable(); idle_time = (after.tv_sec - before.tv_sec) * USEC_PER_SEC + - (after.tv_usec - before.tv_usec); + (after.tv_usec - before.tv_usec); +#ifdef CONFIG_CPU_DIDLE + report_idle_time(idle_state, idle_time); +#endif return idle_time; } @@ -75,26 +458,94 @@ static struct cpuidle_driver s5p_idle_driver = { static int s5p_init_cpuidle(void) { struct cpuidle_device *device; + int ret; - cpuidle_register_driver(&s5p_idle_driver); +#ifdef CONFIG_CPU_DIDLE + struct resource *res; + struct platform_device *pdev; + int i = 0; +#endif + + ret = cpuidle_register_driver(&s5p_idle_driver); + if (ret) { + printk(KERN_ERR "%s: Failed registering driver\n", __func__); + goto err; + } device = &per_cpu(s5p_cpuidle_device, smp_processor_id()); device->state_count = 1; /* Wait for interrupt state */ - device->states[0].enter = s5p_enter_idle_normal; + device->states[0].enter = s5p_enter_idle_state; device->states[0].exit_latency = 1; /* uS */ device->states[0].target_residency = 10000; device->states[0].flags = CPUIDLE_FLAG_TIME_VALID; +#ifdef CONFIG_CPU_DIDLE + strcpy(device->states[0].name, "(DEEP)IDLE"); + strcpy(device->states[0].desc, "ARM clock/power gating - WFI"); +#else strcpy(device->states[0].name, "IDLE"); strcpy(device->states[0].desc, "ARM clock gating - WFI"); +#endif + + ret = cpuidle_register_device(device); + if (ret) { + printk(KERN_ERR "%s: Failed registering device\n", __func__); + goto err_register_driver; + } - if (cpuidle_register_device(device)) { - printk(KERN_ERR "s5p_init_cpuidle: Failed registering\n"); - return -EIO; +#ifdef CONFIG_CPU_DIDLE + regs_save = dma_alloc_coherent(NULL, 4096, &phy_regs_save, GFP_KERNEL); + if (regs_save == NULL) { + printk(KERN_ERR "%s: DMA alloc error\n", __func__); + ret = -ENOMEM; + goto err_register_device; } + printk(KERN_INFO "cpuidle: phy_regs_save:0x%x\n", phy_regs_save); + + /* Allocate memory region to access IP's directly */ + for (i = 0 ; i < MAX_CHK_DEV ; i++) { + + pdev = chk_dev_op[i].pdev; + + if (pdev == NULL) { + sdmmc_dev_num = i - 1; + break; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + printk(KERN_ERR "%s: failed to get io memory region\n", + __func__); + ret = -EINVAL; + goto err_alloc; + } + chk_dev_op[i].base = ioremap_nocache(res->start, 4096); + + if (!chk_dev_op[i].base) { + printk(KERN_ERR "failed to remap io region\n"); + ret = -EINVAL; + goto err_resource; + } + } +#endif return 0; + +#ifdef CONFIG_CPU_DIDLE +err_alloc: + while (--i >= 0) { + iounmap(chk_dev_op[i].base); + } +err_resource: + dma_free_coherent(NULL, 4096, regs_save, phy_regs_save); +err_register_device: + cpuidle_unregister_device(device); +#endif +err_register_driver: + cpuidle_unregister_driver(&s5p_idle_driver); +err: + return ret; } device_initcall(s5p_init_cpuidle); diff --git a/arch/arm/mach-s5pv210/didle.S b/arch/arm/mach-s5pv210/didle.S new file mode 100644 index 00000000000..2abaca0eaa0 --- /dev/null +++ b/arch/arm/mach-s5pv210/didle.S @@ -0,0 +1,218 @@ +/* linux/arch/arm/mach-s5pv210/didle.S + * + * Copyright (c) 2010 Samsung Electronics Co., Ltd. + * http://www.samsung.com/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include +#include + +/* + * v7_flush_l1_dcache() + * + * Flush the L1 D-cache. + */ +ENTRY(v7_flush_l1_dcache) + dmb @ ensure ordering with previous memory accesses + mrc p15, 1, r0, c0, c0, 1 @ read clidr + ands r3, r0, #0x7000000 @ extract loc from clidr + mov r3, r3, lsr #23 @ left align loc bit field + beq finished @ if loc is 0, then no need to clean + mov r10, #0 @ start clean at cache level 0 +loop1: + add r2, r10, r10, lsr #1 @ work out 3x current cache level + mov r1, r0, lsr r2 @ extract cache type bits from clidr + and r1, r1, #7 @ mask of the bits for current cache only + cmp r1, #2 @ see what cache we have at this level + blt finished @ finish if no cache, or just i-cache + mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr + isb @ isb to sych the new cssr&csidr + mrc p15, 1, r1, c0, c0, 0 @ read the new csidr + and r2, r1, #7 @ extract the length of the cache lines + add r2, r2, #4 @ add 4 (line length offset) + ldr r4, =0x3ff + ands r4, r4, r1, lsr #3 @ find maximum number on the way size + clz r5, r4 @ find bit position of way size increment + ldr r7, =0x7fff + ands r7, r7, r1, lsr #13 @ extract max number of the index size +loop2: + mov r9, r4 @ create working copy of max way size +loop3: + orr r11, r10, r9, lsl r5 @ factor way and cache number into r11 + orr r11, r11, r7, lsl r2 @ factor index number into r11 + mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way + subs r9, r9, #1 @ decrement the way + bge loop3 + subs r7, r7, #1 @ decrement the index + bge loop2 +finished: + mov r10, #0 @ swith back to cache level 0 + mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr + dsb + isb + mov pc, lr +ENDPROC(v7_flush_l1_dcache) + +ENTRY(v7_flush_cache_for_didle) + stmfd sp!, {r4-r5, r7, r9-r11, lr} + bl v7_flush_l1_dcache + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate + ldmfd sp!, {r4-r5, r7, r9-r11, lr} + mov pc, lr +ENDPROC(v7_flush_cache_for_didle) + +ENTRY(s5pv210_didle) + stmfd sp!, {r4-r5, r7, r9-r11, lr} + + bl v7_flush_cache_for_didle + + ldmfd sp!, {r4-r5, r7, r9-r11, lr} + dmb + dsb + wfi + + b . + + .text + + /* s5pv210_didle_save + * + * entry: + * r0 = save address (virtual addr of s3c_sleep_save_phys) + */ + +ENTRY(s5pv210_didle_save) + + stmfd sp!, { r3 - r12, lr } + + mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID + mrc p15, 0, r5, c3, c0, 0 @ Domain ID + mrc p15, 0, r6, c2, c0, 0 @ Translation Table BASE0 + mrc p15, 0, r7, c2, c0, 1 @ Translation Table BASE1 + mrc p15, 0, r8, c2, c0, 2 @ Translation Table Control + mrc p15, 0, r9, c1, c0, 0 @ Control register + mrc p15, 0, r10, c1, c0, 1 @ Auxiliary control register + mrc p15, 0, r11, c1, c0, 2 @ Co-processor access controls + mrc p15, 0, r12, c10, c2, 0 @ Read PRRR + mrc p15, 0, r3, c10, c2, 1 @ READ NMRR + + /* Save CP15 registers */ + stmia r0, { r3 - r13 } + + bl s5pv210_didle + + @@ return to the caller, after having the MMU + @@ turned on, this restores the last bits from the + @@ stack +resume_with_mmu: + mrc p15, 0, r0, c1, c0, 1 @enable L2 cache + orr r0, r0, #(1<<1) + mcr p15, 0, r0, c1, c0, 1 + + mov r0, #1 + /* delete added mmu table list */ + ldr r9 , =(PAGE_OFFSET - PLAT_PHYS_OFFSET) + add r4, r4, r9 + str r12, [r4] + + ldmfd sp!, { r3 - r12, pc } + + .ltorg + + /* s5pv210_didle_resume + * + * resume code entry for bootloader to call + * + * we must put this code here in the data segment as we have no + * other way of restoring the stack pointer after sleep, and we + * must not write to the code segment (code is read-only) + */ + +ENTRY(s5pv210_didle_resume) + mov r0, #PSR_I_BIT | PSR_F_BIT | SVC_MODE + msr cpsr_c, r0 + + @@ load UART to allow us to print the two characters for + @@ resume debug + + mov r1, #0 + mcr p15, 0, r1, c8, c7, 0 @@ invalidate TLBs + mcr p15, 0, r1, c7, c5, 0 @@ invalidate I Cache + + ldr r1, =0xe010f008 @ Read INFORM2 register + ldr r0, [r1] @ Load phy_regs_save value + ldmia r0, { r3 - r13 } + + mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID + mcr p15, 0, r5, c3, c0, 0 @ Domain ID + + mcr p15, 0, r8, c2, c0, 2 @ Translation Table Control + mcr p15, 0, r7, c2, c0, 1 @ Translation Table BASE1 + mcr p15, 0, r6, c2, c0, 0 @ Translation Table BASE0 + + bic r10, r10, #(1<<1) @ disable L2cache + mcr p15, 0, r10, c1, c0, 1 @ Auxiliary control register + + mov r0, #0 + mcr p15, 0, r0, c8, c7, 0 @ Invalidate I & D TLB + + mov r0, #0 @ restore copro access controls + mcr p15, 0, r11, c1, c0, 2 @ Co-processor access controls + mcr p15, 0, r0, c7, c5, 4 + + mcr p15, 0, r12, c10, c2, 0 @ write PRRR + mcr p15, 0, r3, c10, c2, 1 @ write NMRR + + /* calculate first section address into r8 */ + mov r4, r6 + ldr r5, =0x3fff + bic r4, r4, r5 + ldr r11, =0xe010f000 + ldr r10, [r11, #0] + mov r10, r10 ,LSR #18 + bic r10, r10, #0x3 + orr r4, r4, r10 + + /* calculate mmu list value into r9 */ + mov r10, r10, LSL #18 + ldr r5, =0x40e + orr r10, r10, r5 + + /* back up originally data */ + ldr r12, [r4] + + /* Added list about mmu */ + str r10, [r4] + + ldr r2, =resume_with_mmu + mcr p15, 0, r9, c1, c0, 0 @ turn on MMU, etc + + nop + nop + nop + nop + nop @ second-to-last before mmu + + mov pc, r2 @ go back to virtual address + + .ltorg diff --git a/arch/arm/mach-s5pv210/herring-rfkill.c b/arch/arm/mach-s5pv210/herring-rfkill.c index 2115d9f242b..ce7408f16ca 100644 --- a/arch/arm/mach-s5pv210/herring-rfkill.c +++ b/arch/arm/mach-s5pv210/herring-rfkill.c @@ -49,6 +49,16 @@ static struct wake_lock rfkill_wake_lock; static struct rfkill *bt_rfk; static const char bt_name[] = "bcm4329"; +#ifdef CONFIG_CPU_DIDLE +static bool bt_running = false; + +bool bt_is_running(void) +{ + return bt_running; +} +EXPORT_SYMBOL(bt_is_running); +#endif + static int bluetooth_set_power(void *data, enum rfkill_user_states state) { int ret = 0; @@ -118,6 +128,10 @@ static int bluetooth_set_power(void *data, enum rfkill_user_states state) case RFKILL_USER_STATE_SOFT_BLOCKED: pr_debug("[BT] Device Powering OFF\n"); +#ifdef CONFIG_CPU_DIDLE + bt_running = false; +#endif + ret = disable_irq_wake(irq); if (ret < 0) pr_err("[BT] unset wakeup src failed\n"); @@ -159,6 +173,10 @@ irqreturn_t bt_host_wake_irq_handler(int irq, void *dev_id) { pr_debug("[BT] bt_host_wake_irq_handler start\n"); +#ifdef CONFIG_CPU_DIDLE + bt_running = true; +#endif + if (gpio_get_value(GPIO_BT_HOST_WAKE)) wake_lock(&rfkill_wake_lock); else diff --git a/arch/arm/mach-s5pv210/herring-vibrator.c b/arch/arm/mach-s5pv210/herring-vibrator.c index 323520f60b5..82959f5ae57 100644 --- a/arch/arm/mach-s5pv210/herring-vibrator.c +++ b/arch/arm/mach-s5pv210/herring-vibrator.c @@ -43,11 +43,25 @@ static struct vibrator { struct work_struct work; } vibdata; +#ifdef CONFIG_CPU_DIDLE +static bool vibrator_running = false; + +bool vibrator_is_running(void) +{ + return vibrator_running; +} +EXPORT_SYMBOL(vibrator_is_running); +#endif + static void herring_vibrator_off(void) { pwm_disable(vibdata.pwm_dev); gpio_direction_output(GPIO_VIBTONE_EN1, GPIO_LEVEL_LOW); wake_unlock(&vibdata.wklock); + +#ifdef CONFIG_CPU_DIDLE + vibrator_running = false; +#endif } static int herring_vibrator_get_time(struct timed_output_dev *dev) @@ -68,6 +82,10 @@ static void herring_vibrator_enable(struct timed_output_dev *dev, int value) hrtimer_cancel(&vibdata.timer); cancel_work_sync(&vibdata.work); if (value) { +#ifdef CONFIG_CPU_DIDLE + vibrator_running = true; +#endif + wake_lock(&vibdata.wklock); pwm_config(vibdata.pwm_dev, PWM_DUTY, PWM_PERIOD); pwm_enable(vibdata.pwm_dev); diff --git a/arch/arm/mach-s5pv210/include/mach/cpuidle.h b/arch/arm/mach-s5pv210/include/mach/cpuidle.h new file mode 100644 index 00000000000..7454ae4496e --- /dev/null +++ b/arch/arm/mach-s5pv210/include/mach/cpuidle.h @@ -0,0 +1,16 @@ +/* arch/arm/mach-s5pv210/include/mach/cpuidle.h + * + * Copyright 2010 Samsung Electronics + * Jaecheol Lee + * + * S5PV210 - CPUIDLE support + * + * 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. +*/ + +extern int s5pv210_didle_save(unsigned long *saveblk); +extern void s5pv210_didle_resume(void); +extern void i2sdma_getpos(dma_addr_t *src); +extern unsigned int get_rtc_cnt(void); diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 3794953b37a..46850d20e40 100755 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -57,3 +57,4 @@ obj-$(CONFIG_PN544) += pn544.o obj-$(CONFIG_SAMSUNG_JACK) += sec_jack.o obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o obj-$(CONFIG_SAMSUNG_MODEMCTL) += samsung_modemctl/ +obj-$(CONFIG_CPU_DIDLE) += deep_idle.o diff --git a/drivers/misc/deep_idle.c b/drivers/misc/deep_idle.c new file mode 100644 index 00000000000..0b2383e3dfe --- /dev/null +++ b/drivers/misc/deep_idle.c @@ -0,0 +1,206 @@ +/* drivers/misc/deep_idle.c + * + * Copyright 2011 Ezekeel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#define DEEPIDLE_VERSION 2 + +#define NUM_IDLESTATES 3 + +static DEFINE_MUTEX(lock); + +static bool deepidle_enabled = false; + +static unsigned long long num_idlecalls[NUM_IDLESTATES], time_in_idlestate[NUM_IDLESTATES]; + +static ssize_t deepidle_status_read(struct device * dev, struct device_attribute * attr, char * buf) +{ + return sprintf(buf, "%u\n", (deepidle_enabled ? 1 : 0)); +} + +static ssize_t deepidle_status_write(struct device * dev, struct device_attribute * attr, const char * buf, size_t size) +{ + unsigned int data; + + if(sscanf(buf, "%u\n", &data) == 1) + { + if (data == 1) + { + pr_info("%s: DEEPIDLE enabled\n", __FUNCTION__); + + deepidle_enabled = true; + } + else if (data == 0) + { + pr_info("%s: DEEPIDLE disabled\n", __FUNCTION__); + + deepidle_enabled = false; + } + else + { + pr_info("%s: invalid input range %u\n", __FUNCTION__, data); + } + } + else + { + pr_info("%s: invalid input\n", __FUNCTION__); + } + + return size; +} + +static ssize_t show_idle_stats(struct device * dev, struct device_attribute * attr, char * buf) +{ + int i; + unsigned long long msecs_in_idlestate[NUM_IDLESTATES], avg_in_idlestate[NUM_IDLESTATES]; + + mutex_lock(&lock); + + for (i = 0; i < NUM_IDLESTATES; i++) { + msecs_in_idlestate[i] = time_in_idlestate[i] + 500; + do_div(msecs_in_idlestate[i], 1000); + if (num_idlecalls[i] == 0) { + avg_in_idlestate[i] = 0; + } else { + avg_in_idlestate[i] = msecs_in_idlestate[i]; + do_div(avg_in_idlestate[i], num_idlecalls[i]); + } + } + + mutex_unlock(&lock); + + return sprintf(buf, "idle state total (average)\n===================================================\nIDLE %llums (%llums)\nDEEP IDLE (TOP=ON) %llums (%llums)\nDEEP IDLE (TOP=OFF) %llums (%llums)\n", + msecs_in_idlestate[0], avg_in_idlestate[0], msecs_in_idlestate[1], avg_in_idlestate[1], msecs_in_idlestate[2], avg_in_idlestate[2]); +} + +static void reset_stats(void) +{ + int i; + + for (i = 0; i < NUM_IDLESTATES; i++) + { + num_idlecalls[i] = 0; + time_in_idlestate[i] = 0; + } + + return; +} + +static ssize_t reset_idle_stats(struct device * dev, struct device_attribute * attr, const char * buf, size_t size) +{ + unsigned int data; + + if(sscanf(buf, "%u\n", &data) == 1) + { + if (data == 1) + { + mutex_lock(&lock); + reset_stats(); + mutex_unlock(&lock); + } + else + { + pr_info("%s: invalid input range %u\n", __FUNCTION__, data); + } + } + else + { + pr_info("%s: invalid input\n", __FUNCTION__); + } + + return size; +} + +static ssize_t deepidle_version(struct device * dev, struct device_attribute * attr, char * buf) +{ + return sprintf(buf, "%u\n", DEEPIDLE_VERSION); +} + +static DEVICE_ATTR(enabled, S_IRUGO | S_IWUGO, deepidle_status_read, deepidle_status_write); +static DEVICE_ATTR(idle_stats, S_IRUGO , show_idle_stats, NULL); +static DEVICE_ATTR(reset_stats, S_IWUGO , NULL, reset_idle_stats); +static DEVICE_ATTR(version, S_IRUGO , deepidle_version, NULL); + +static struct attribute *deepidle_attributes[] = + { + &dev_attr_enabled.attr, + &dev_attr_idle_stats.attr, + &dev_attr_reset_stats.attr, + &dev_attr_version.attr, + NULL + }; + +static struct attribute_group deepidle_group = + { + .attrs = deepidle_attributes, + }; + +static struct miscdevice deepidle_device = + { + .minor = MISC_DYNAMIC_MINOR, + .name = "deepidle", + }; + +bool deepidle_is_enabled(void) +{ + return deepidle_enabled; +} +EXPORT_SYMBOL(deepidle_is_enabled); + +void report_idle_time(int idle_state, int idle_time) +{ + mutex_lock(&lock); + + num_idlecalls[idle_state]++; + time_in_idlestate[idle_state] += (unsigned long long)idle_time; + + if (num_idlecalls[idle_state] == 0 || time_in_idlestate[idle_state] < (unsigned long long)idle_time) + { + reset_stats(); + } + + mutex_unlock(&lock); + + return; +} +EXPORT_SYMBOL(report_idle_time); + +static int __init deepidle_init(void) +{ + int ret; + + pr_info("%s misc_register(%s)\n", __FUNCTION__, deepidle_device.name); + + ret = misc_register(&deepidle_device); + + if (ret) + { + pr_err("%s misc_register(%s) fail\n", __FUNCTION__, deepidle_device.name); + + return 1; + } + + if (sysfs_create_group(&deepidle_device.this_device->kobj, &deepidle_group) < 0) + { + pr_err("%s sysfs_create_group fail\n", __FUNCTION__); + pr_err("Failed to create sysfs group for device (%s)!\n", deepidle_device.name); + } + + mutex_lock(&lock); + reset_stats(); + mutex_unlock(&lock); + + return 0; +} + +device_initcall(deepidle_init); diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index 00261961ca7..c7de7492cfc 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -448,6 +448,16 @@ static int s3c24xx_serial_startup(struct uart_port *port) /* power power management control */ +#ifdef CONFIG_CPU_DIDLE +static bool gps_running = false; + +bool gps_is_running(void) +{ + return gps_running; +} +EXPORT_SYMBOL(gps_is_running); +#endif + static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, unsigned int old) { @@ -462,13 +472,21 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level, if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL) clk_disable(ourport->baudclk); - +#ifdef CONFIG_CPU_DIDLE + if (ourport->port.irq == IRQ_S3CUART_RX1) + gps_running = false; +#endif clk_disable(ourport->clk); + break; case 0: - clk_enable(ourport->clk); + clk_enable(ourport->clk); +#ifdef CONFIG_CPU_DIDLE + if (ourport->port.irq == IRQ_S3CUART_RX1) + gps_running = true; +#endif if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL) clk_enable(ourport->baudclk); diff --git a/include/linux/deep_idle.h b/include/linux/deep_idle.h new file mode 100644 index 00000000000..7c24c7fafbb --- /dev/null +++ b/include/linux/deep_idle.h @@ -0,0 +1,9 @@ +/* include/linux/deep_idle.h */ + +#ifndef _LINUX_DEEPIDLE_H +#define _LINUX_DEEPIDLE_H + +bool deepidle_is_enabled(void); +void report_idle_time(int idle_state, int idle_time); + +#endif diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 63774df522b..ff90ec032f0 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -315,3 +315,11 @@ int pm_suspend(suspend_state_t state) return -EINVAL; } EXPORT_SYMBOL(pm_suspend); + +#ifdef CONFIG_CPU_DIDLE +bool suspend_ongoing(void) +{ + return mutex_is_locked(&pm_mutex); +} +EXPORT_SYMBOL(suspend_ongoing); +#endif From 7532f87a4639850c557f00c0e56836843915797c Mon Sep 17 00:00:00 2001 From: Adam Kent Date: Wed, 8 Jun 2011 14:40:32 +1000 Subject: [PATCH 0435/4025] Generic BLN with in-kernel blink --- arch/arm/mach-s5pv210/herring-touchkey-led.c | 31 +- arch/arm/mach-s5pv210/mach-herring.c | 18 ++ drivers/input/keyboard/cypress-touchkey.c | 73 +++++ drivers/misc/Kconfig | 7 + drivers/misc/Makefile | 1 + drivers/misc/bln.c | 313 +++++++++++++++++++ include/linux/bln.h | 13 + include/linux/input/cypress-touchkey.h | 1 + 8 files changed, 454 insertions(+), 3 deletions(-) create mode 100644 drivers/misc/bln.c create mode 100644 include/linux/bln.h diff --git a/arch/arm/mach-s5pv210/herring-touchkey-led.c b/arch/arm/mach-s5pv210/herring-touchkey-led.c index b36e0f0e740..91d86234fda 100644 --- a/arch/arm/mach-s5pv210/herring-touchkey-led.c +++ b/arch/arm/mach-s5pv210/herring-touchkey-led.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "herring.h" @@ -29,6 +30,23 @@ static void herring_touchkey_led_onoff(int onoff) gpio_direction_output(S5PV210_GPJ3(led_gpios[i]), !!onoff); } +#ifdef CONFIG_GENERIC_BLN +static void herring_touchkey_bln_enable(void) +{ + herring_touchkey_led_onoff(1); +} + +static void herring_touchkey_bln_disable(void) +{ + herring_touchkey_led_onoff(0); +} + +static struct bln_implementation herring_touchkey_bln = { + .enable = herring_touchkey_bln_enable, + .disable = herring_touchkey_bln_disable, +}; +#endif + static void herring_touchkey_led_early_suspend(struct early_suspend *h) { herring_touchkey_led_onoff(0); @@ -49,24 +67,31 @@ static int __init herring_init_touchkey_led(void) { int i; int ret = 0; + u32 gpio; if (!machine_is_herring() || !herring_is_tft_dev()) return 0; for (i = 0; i < ARRAY_SIZE(led_gpios); i++) { - ret = gpio_request(S5PV210_GPJ3(led_gpios[i]), "touchkey led"); + gpio = S5PV210_GPJ3(led_gpios[i]); + ret = gpio_request(gpio, "touchkey led"); if (ret) { pr_err("Failed to request touchkey led gpio %d\n", i); goto err_req; } - s3c_gpio_setpull(S5PV210_GPJ3(led_gpios[i]), - S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + s3c_gpio_slp_cfgpin(gpio, S3C_GPIO_SLP_PREV); + s3c_gpio_slp_setpull_updown(gpio, S3C_GPIO_PULL_NONE); } herring_touchkey_led_onoff(1); register_early_suspend(&early_suspend); +#ifdef CONFIG_GENERIC_BLN + register_bln_implementation(&herring_touchkey_bln); +#endif + return 0; err_req: diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c index a1f157c852e..7341e76afd6 100755 --- a/arch/arm/mach-s5pv210/mach-herring.c +++ b/arch/arm/mach-s5pv210/mach-herring.c @@ -2008,6 +2008,23 @@ static void touch_keypad_onoff(int onoff) msleep(50); } +static void touch_keypad_gpio_sleep(int onoff) +{ + if (onoff == TOUCHKEY_ON) { + /* + * reconfigure gpio to activate touchkey controller vdd in sleep mode + */ + s3c_gpio_slp_cfgpin(_3_GPIO_TOUCH_EN, S3C_GPIO_SLP_OUT1); + } else { + /* + * reconfigure gpio to deactivate touchkey vdd in sleep mode, + * this is the default + */ + s3c_gpio_slp_cfgpin(_3_GPIO_TOUCH_EN, S3C_GPIO_SLP_OUT0); + } + +} + static const int touch_keypad_code[] = { KEY_MENU, KEY_HOME, @@ -2019,6 +2036,7 @@ static struct touchkey_platform_data touchkey_data = { .keycode_cnt = ARRAY_SIZE(touch_keypad_code), .keycode = touch_keypad_code, .touchkey_onoff = touch_keypad_onoff, + .touchkey_sleep_onoff = touch_keypad_gpio_sleep, .fw_name = "cypress-touchkey.bin", .scl_pin = _3_TOUCH_SCL_28V, .sda_pin = _3_TOUCH_SDA_28V, diff --git a/drivers/input/keyboard/cypress-touchkey.c b/drivers/input/keyboard/cypress-touchkey.c index 296c0f44ff5..bf1a02eab56 100755 --- a/drivers/input/keyboard/cypress-touchkey.c +++ b/drivers/input/keyboard/cypress-touchkey.c @@ -1,6 +1,7 @@ /* * Copyright 2006-2010, Cypress Semiconductor Corporation. * Copyright (C) 2010, Samsung Electronics Co. Ltd. All Rights Reserved. + * Copyright 2011, Michael Richter (alias neldar) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,6 +29,7 @@ #include #include #include +#include #define SCANCODE_MASK 0x07 #define UPDOWN_EVENT_MASK 0x08 @@ -55,6 +57,8 @@ struct cypress_touchkey_devdata { bool has_legacy_keycode; }; +static struct cypress_touchkey_devdata *blndevdata; + static int i2c_touchkey_read_byte(struct cypress_touchkey_devdata *devdata, u8 *val) { @@ -209,6 +213,14 @@ static void cypress_touchkey_early_suspend(struct early_suspend *h) return; disable_irq(devdata->client->irq); + +#ifdef CONFIG_GENERIC_BLN + /* + * Disallow powering off the touchkey controller + * while a led notification is ongoing + */ + if(!bln_is_ongoing()) +#endif devdata->pdata->touchkey_onoff(TOUCHKEY_OFF); all_keys_up(devdata); @@ -292,6 +304,14 @@ static int update_firmware(struct cypress_touchkey_devdata *devdata) return ret; } +static void enable_touchkey_backlights(void){ + i2c_touchkey_write_byte(blndevdata, blndevdata->backlight_on); +} + +static void disable_touchkey_backlights(void){ + i2c_touchkey_write_byte(blndevdata, blndevdata->backlight_off); +} + static int cypress_touchkey_open(struct input_dev *input_dev) { struct device *dev = &input_dev->dev; @@ -330,6 +350,54 @@ static int cypress_touchkey_open(struct input_dev *input_dev) return 0; } +static void cypress_touchkey_enable_led_notification(void){ + /* is_powering_on signals whether touchkey lights are used for touchmode */ + if (blndevdata->is_powering_on){ + /* reconfigure gpio for sleep mode */ + blndevdata->pdata->touchkey_sleep_onoff(TOUCHKEY_ON); + + /* + * power on the touchkey controller + * This is actually not needed, but it is intentionally + * left for the case that the early_resume() function + * did not power on the touchkey controller for some reasons + */ + blndevdata->pdata->touchkey_onoff(TOUCHKEY_ON); + + /* write to i2cbus, enable backlights */ + enable_touchkey_backlights(); + } + else + pr_info("%s: cannot set notification led, touchkeys are enabled\n",__FUNCTION__); +} + +static void cypress_touchkey_disable_led_notification(void){ + /* + * reconfigure gpio for sleep mode, this has to be done + * independently from the power status + */ + blndevdata->pdata->touchkey_sleep_onoff(TOUCHKEY_OFF); + + /* if touchkeys lights are not used for touchmode */ + if (blndevdata->is_powering_on){ + disable_touchkey_backlights(); + + #if 0 + /* + * power off the touchkey controller + * This is actually not needed, the early_suspend function + * should take care of powering off the touchkey controller + */ + blndevdata->pdata->touchkey_onoff(TOUCHKEY_OFF); + #endif + } +} + +static struct bln_implementation cypress_touchkey_bln = { + .enable = cypress_touchkey_enable_led_notification, + .disable = cypress_touchkey_disable_led_notification, +}; + static int cypress_touchkey_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -429,8 +497,13 @@ static int cypress_touchkey_probe(struct i2c_client *client, devdata->is_powering_on = false; +#ifdef CONFIG_GENERIC_BLN + blndevdata = devdata; + register_bln_implementation(&cypress_touchkey_bln); +#endif return 0; + err_req_irq: err_backlight_on: input_unregister_device(input_dev); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index c3dc7dfe725..0a503a4a62d 100755 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -593,4 +593,11 @@ config PN544 help NXP PN544 Near Field Communication controller support. +config GENERIC_BLN + bool "Generic BLN support for backlight notification" + default y + help + Say Y here to enable the backlight notification + for android led-notification (modified liblight needed) + endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 3794953b37a..260e71e15b3 100755 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -57,3 +57,4 @@ obj-$(CONFIG_PN544) += pn544.o obj-$(CONFIG_SAMSUNG_JACK) += sec_jack.o obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o obj-$(CONFIG_SAMSUNG_MODEMCTL) += samsung_modemctl/ +obj-$(CONFIG_GENERIC_BLN) += bln.o diff --git a/drivers/misc/bln.c b/drivers/misc/bln.c new file mode 100644 index 00000000000..85300efc360 --- /dev/null +++ b/drivers/misc/bln.c @@ -0,0 +1,313 @@ +/* drivers/misc/bln.c + * + * Copyright 2011 Michael Richter (alias neldar) + * Copyright 2011 Adam Kent + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool bln_enabled = true; /* is BLN function is enabled */ +static bool bln_ongoing = false; /* ongoing LED Notification */ +static int bln_blink_state = 0; +static bool bln_suspended = false; /* is system suspended */ +static struct bln_implementation *bln_imp = NULL; +static bool in_kernel_blink = false; +static uint32_t blink_count; + +static struct wake_lock bln_wake_lock; + +void bl_timer_callback(unsigned long data); +static struct timer_list blink_timer = + TIMER_INITIALIZER(bl_timer_callback, 0, 0); +static void blink_callback(struct work_struct *blink_work); +static DECLARE_WORK(blink_work, blink_callback); + +#define BLINK_INTERVAL 500 /* on / off every 500ms */ +#define MAX_BLINK_COUNT 600 /* 10 minutes */ +#define BACKLIGHTNOTIFICATION_VERSION 9 + +static void bln_enable_backlights(void) +{ + if (bln_imp) + bln_imp->enable(); +} + +static void bln_disable_backlights(void) +{ + if (bln_imp) + bln_imp->disable(); +} + +static void bln_early_suspend(struct early_suspend *h) +{ + bln_suspended = true; +} + +static void bln_late_resume(struct early_suspend *h) +{ + bln_suspended = false; +} + +static struct early_suspend bln_suspend_data = { + .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1, + .suspend = bln_early_suspend, + .resume = bln_late_resume, +}; + +static void enable_led_notification(void) +{ + if (!bln_enabled) + return; + + if (in_kernel_blink) { + wake_lock(&bln_wake_lock); + + /* Start timer */ + blink_timer.expires = jiffies + + msecs_to_jiffies(BLINK_INTERVAL); + blink_count = MAX_BLINK_COUNT; + add_timer(&blink_timer); + } + + bln_enable_backlights(); + pr_info("%s: notification led enabled\n", __FUNCTION__); + bln_ongoing = true; +} + +static void disable_led_notification(void) +{ + pr_info("%s: notification led disabled\n", __FUNCTION__); + + bln_blink_state = 0; + bln_ongoing = false; + + if (bln_suspended) + bln_disable_backlights(); + + if (in_kernel_blink) + del_timer(&blink_timer); + + wake_unlock(&bln_wake_lock); + +} + +static ssize_t backlightnotification_status_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", (bln_enabled ? 1 : 0)); +} + +static ssize_t backlightnotification_status_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned int data; + if(sscanf(buf, "%u\n", &data) == 1) { + pr_devel("%s: %u \n", __FUNCTION__, data); + if (data == 1) { + pr_info("%s: BLN function enabled\n", __FUNCTION__); + bln_enabled = true; + } else if (data == 0) { + pr_info("%s: BLN function disabled\n", __FUNCTION__); + bln_enabled = false; + if (bln_ongoing) + disable_led_notification(); + } else { + pr_info("%s: invalid input range %u\n", __FUNCTION__, + data); + } + } else { + pr_info("%s: invalid input\n", __FUNCTION__); + } + + return size; +} + +static ssize_t notification_led_status_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%u\n", (bln_ongoing ? 1 : 0)); +} + +static ssize_t notification_led_status_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned int data; + + if (sscanf(buf, "%u\n", &data) == 1) { + if (data == 1) + enable_led_notification(); + else if (data == 0) + disable_led_notification(); + else + pr_info("%s: wrong input %u\n", __FUNCTION__, data); + } else { + pr_info("%s: input error\n", __FUNCTION__); + } + + return size; +} + +static ssize_t in_kernel_blink_status_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%u\n", (in_kernel_blink ? 1 : 0)); +} + +static ssize_t in_kernel_blink_status_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned int data; + + if (sscanf(buf, "%u\n", &data) == 1) + in_kernel_blink = !!(data); + else + pr_info("%s: input error\n", __FUNCTION__); + + return size; +} +static ssize_t blink_control_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", bln_blink_state); +} + +static ssize_t blink_control_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned int data; + + if (!bln_ongoing) + return size; + + if (sscanf(buf, "%u\n", &data) == 1) { + if (data == 1) { + bln_blink_state = 1; + bln_disable_backlights(); + } else if (data == 0) { + bln_blink_state = 0; + bln_enable_backlights(); + } else { + pr_info("%s: wrong input %u\n", __FUNCTION__, data); + } + } else { + pr_info("%s: input error\n", __FUNCTION__); + } + + return size; +} + +static ssize_t backlightnotification_version(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", BACKLIGHTNOTIFICATION_VERSION); +} + +static DEVICE_ATTR(blink_control, S_IRUGO | S_IWUGO, blink_control_read, + blink_control_write); +static DEVICE_ATTR(enabled, S_IRUGO | S_IWUGO, + backlightnotification_status_read, + backlightnotification_status_write); +static DEVICE_ATTR(notification_led, S_IRUGO | S_IWUGO, + notification_led_status_read, + notification_led_status_write); +static DEVICE_ATTR(in_kernel_blink, S_IRUGO | S_IWUGO, + in_kernel_blink_status_read, + in_kernel_blink_status_write); +static DEVICE_ATTR(version, S_IRUGO , backlightnotification_version, NULL); + +static struct attribute *bln_notification_attributes[] = { + &dev_attr_blink_control.attr, + &dev_attr_enabled.attr, + &dev_attr_notification_led.attr, + &dev_attr_in_kernel_blink.attr, + &dev_attr_version.attr, + NULL +}; + +static struct attribute_group bln_notification_group = { + .attrs = bln_notification_attributes, +}; + +static struct miscdevice bln_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "backlightnotification", +}; + +void register_bln_implementation(struct bln_implementation *imp) +{ + bln_imp = imp; +} +EXPORT_SYMBOL(register_bln_implementation); + +bool bln_is_ongoing() +{ + return bln_ongoing; +} +EXPORT_SYMBOL(bln_is_ongoing); + + +static void blink_callback(struct work_struct *blink_work) +{ + if (--blink_count == 0) { + pr_info("%s: notification timed out\n", __FUNCTION__); + bln_enable_backlights(); + del_timer(&blink_timer); + wake_unlock(&bln_wake_lock); + return; + } + + if (bln_blink_state) + bln_enable_backlights(); + else + bln_disable_backlights(); + + bln_blink_state = !bln_blink_state; +} + +void bl_timer_callback(unsigned long data) +{ + schedule_work(&blink_work); + mod_timer(&blink_timer, jiffies + msecs_to_jiffies(BLINK_INTERVAL)); +} + +static int __init bln_control_init(void) +{ + int ret; + + pr_info("%s misc_register(%s)\n", __FUNCTION__, bln_device.name); + ret = misc_register(&bln_device); + if (ret) { + pr_err("%s misc_register(%s) fail\n", __FUNCTION__, + bln_device.name); + return 1; + } + + /* add the bln attributes */ + if (sysfs_create_group(&bln_device.this_device->kobj, + &bln_notification_group) < 0) { + pr_err("%s sysfs_create_group fail\n", __FUNCTION__); + pr_err("Failed to create sysfs group for device (%s)!\n", + bln_device.name); + } + + register_early_suspend(&bln_suspend_data); + + /* Initialize wake locks */ + wake_lock_init(&bln_wake_lock, WAKE_LOCK_SUSPEND, "bln_wake"); + + return 0; +} + +device_initcall(bln_control_init); diff --git a/include/linux/bln.h b/include/linux/bln.h new file mode 100644 index 00000000000..a5de5e45dfd --- /dev/null +++ b/include/linux/bln.h @@ -0,0 +1,13 @@ +/* include/linux/bln.h */ + +#ifndef _LINUX_BLN_H +#define _LINUX_BLN_H + +struct bln_implementation { + void (*enable)(void); + void (*disable)(void); +}; + +void register_bln_implementation(struct bln_implementation *imp); +bool bln_is_ongoing(void); +#endif diff --git a/include/linux/input/cypress-touchkey.h b/include/linux/input/cypress-touchkey.h index ca65472f1e7..cd4ff4d57f6 100755 --- a/include/linux/input/cypress-touchkey.h +++ b/include/linux/input/cypress-touchkey.h @@ -25,6 +25,7 @@ struct touchkey_platform_data { int keycode_cnt; const int *keycode; void (*touchkey_onoff) (int); + void (*touchkey_sleep_onoff) (int); const char *fw_name; int scl_pin; int sda_pin; From 9df92c09e79699650f7355163149697f8ea1e1fb Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Sat, 17 Dec 2011 23:06:21 +0100 Subject: [PATCH 0436/4025] Remove blink from LED notification control This is done to encrease stability and more to preserve bettery --- drivers/input/keyboard/cypress-touchkey.c | 5 +- drivers/misc/bln.c | 111 +--------------------- 2 files changed, 7 insertions(+), 109 deletions(-) diff --git a/drivers/input/keyboard/cypress-touchkey.c b/drivers/input/keyboard/cypress-touchkey.c index bf1a02eab56..71e748dd3f7 100755 --- a/drivers/input/keyboard/cypress-touchkey.c +++ b/drivers/input/keyboard/cypress-touchkey.c @@ -219,7 +219,10 @@ static void cypress_touchkey_early_suspend(struct early_suspend *h) * Disallow powering off the touchkey controller * while a led notification is ongoing */ - if(!bln_is_ongoing()) + if(!bln_is_ongoing()) { + devdata->pdata->touchkey_onoff(TOUCHKEY_OFF); + devdata->pdata->touchkey_sleep_onoff(TOUCHKEY_OFF); + } #endif devdata->pdata->touchkey_onoff(TOUCHKEY_OFF); diff --git a/drivers/misc/bln.c b/drivers/misc/bln.c index 85300efc360..ce63bd921e3 100644 --- a/drivers/misc/bln.c +++ b/drivers/misc/bln.c @@ -20,22 +20,11 @@ static bool bln_enabled = true; /* is BLN function is enabled */ static bool bln_ongoing = false; /* ongoing LED Notification */ -static int bln_blink_state = 0; static bool bln_suspended = false; /* is system suspended */ static struct bln_implementation *bln_imp = NULL; -static bool in_kernel_blink = false; -static uint32_t blink_count; static struct wake_lock bln_wake_lock; -void bl_timer_callback(unsigned long data); -static struct timer_list blink_timer = - TIMER_INITIALIZER(bl_timer_callback, 0, 0); -static void blink_callback(struct work_struct *blink_work); -static DECLARE_WORK(blink_work, blink_callback); - -#define BLINK_INTERVAL 500 /* on / off every 500ms */ -#define MAX_BLINK_COUNT 600 /* 10 minutes */ #define BACKLIGHTNOTIFICATION_VERSION 9 static void bln_enable_backlights(void) @@ -71,16 +60,6 @@ static void enable_led_notification(void) if (!bln_enabled) return; - if (in_kernel_blink) { - wake_lock(&bln_wake_lock); - - /* Start timer */ - blink_timer.expires = jiffies + - msecs_to_jiffies(BLINK_INTERVAL); - blink_count = MAX_BLINK_COUNT; - add_timer(&blink_timer); - } - bln_enable_backlights(); pr_info("%s: notification led enabled\n", __FUNCTION__); bln_ongoing = true; @@ -90,15 +69,11 @@ static void disable_led_notification(void) { pr_info("%s: notification led disabled\n", __FUNCTION__); - bln_blink_state = 0; bln_ongoing = false; if (bln_suspended) bln_disable_backlights(); - if (in_kernel_blink) - del_timer(&blink_timer); - wake_unlock(&bln_wake_lock); } @@ -159,79 +134,23 @@ static ssize_t notification_led_status_write(struct device *dev, return size; } -static ssize_t in_kernel_blink_status_read(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n", (in_kernel_blink ? 1 : 0)); -} - -static ssize_t in_kernel_blink_status_write(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned int data; - - if (sscanf(buf, "%u\n", &data) == 1) - in_kernel_blink = !!(data); - else - pr_info("%s: input error\n", __FUNCTION__); - - return size; -} -static ssize_t blink_control_read(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%u\n", bln_blink_state); -} - -static ssize_t blink_control_write(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned int data; - - if (!bln_ongoing) - return size; - - if (sscanf(buf, "%u\n", &data) == 1) { - if (data == 1) { - bln_blink_state = 1; - bln_disable_backlights(); - } else if (data == 0) { - bln_blink_state = 0; - bln_enable_backlights(); - } else { - pr_info("%s: wrong input %u\n", __FUNCTION__, data); - } - } else { - pr_info("%s: input error\n", __FUNCTION__); - } - - return size; -} - static ssize_t backlightnotification_version(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%u\n", BACKLIGHTNOTIFICATION_VERSION); } -static DEVICE_ATTR(blink_control, S_IRUGO | S_IWUGO, blink_control_read, - blink_control_write); static DEVICE_ATTR(enabled, S_IRUGO | S_IWUGO, backlightnotification_status_read, backlightnotification_status_write); -static DEVICE_ATTR(notification_led, S_IRUGO | S_IWUGO, +static DEVICE_ATTR(led, S_IRUGO | S_IWUGO, notification_led_status_read, notification_led_status_write); -static DEVICE_ATTR(in_kernel_blink, S_IRUGO | S_IWUGO, - in_kernel_blink_status_read, - in_kernel_blink_status_write); static DEVICE_ATTR(version, S_IRUGO , backlightnotification_version, NULL); static struct attribute *bln_notification_attributes[] = { - &dev_attr_blink_control.attr, &dev_attr_enabled.attr, - &dev_attr_notification_led.attr, - &dev_attr_in_kernel_blink.attr, + &dev_attr_led.attr, &dev_attr_version.attr, NULL }; @@ -242,7 +161,7 @@ static struct attribute_group bln_notification_group = { static struct miscdevice bln_device = { .minor = MISC_DYNAMIC_MINOR, - .name = "backlightnotification", + .name = "notification", }; void register_bln_implementation(struct bln_implementation *imp) @@ -258,30 +177,6 @@ bool bln_is_ongoing() EXPORT_SYMBOL(bln_is_ongoing); -static void blink_callback(struct work_struct *blink_work) -{ - if (--blink_count == 0) { - pr_info("%s: notification timed out\n", __FUNCTION__); - bln_enable_backlights(); - del_timer(&blink_timer); - wake_unlock(&bln_wake_lock); - return; - } - - if (bln_blink_state) - bln_enable_backlights(); - else - bln_disable_backlights(); - - bln_blink_state = !bln_blink_state; -} - -void bl_timer_callback(unsigned long data) -{ - schedule_work(&blink_work); - mod_timer(&blink_timer, jiffies + msecs_to_jiffies(BLINK_INTERVAL)); -} - static int __init bln_control_init(void) { int ret; From 74e7d733c3f5daa27294cb957ca9d0c3c20a90bc Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Sun, 9 Oct 2011 10:54:32 +0200 Subject: [PATCH 0437/4025] Change battery percentage calculation. Compensate for chipset inaccuracies in returning battery percentage the way Samsung did it in its Froyo rom. This allows the battery to reach 100% (may require bump charging) and no visible battery drop is noticable (even after a reboot). The precision is also increased (no 2% jump) from the current method of calculation because the calculation is done where we have extra precision information from the chipset. added this pawitp implementation to joing more kernel work on CM devices. Change-Id: Id7f15dd3906f7a12949683c0d921ce7a8498e70a Conflicts: drivers/power/s5pc110_battery.c --- drivers/power/max17040_battery.c | 30 +++++++++++++++++++++++++++++- drivers/power/s5pc110_battery.c | 9 +++++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c index 54905b1ae49..aedb539abe2 100755 --- a/drivers/power/max17040_battery.c +++ b/drivers/power/max17040_battery.c @@ -129,11 +129,39 @@ static void max17040_get_soc(struct i2c_client *client) struct max17040_chip *chip = i2c_get_clientdata(client); u8 msb; u8 lsb; + u32 soc = 0; + u32 temp = 0; + u32 temp_soc = 0; msb = max17040_read_reg(client, MAX17040_SOC_MSB); lsb = max17040_read_reg(client, MAX17040_SOC_LSB); - chip->soc = min(msb, (u8)100); + temp = msb * 100 + ((lsb * 100) / 256); + + if (temp >= 100) + temp_soc = temp; + else { + if (temp >= 70) + temp_soc = 100; + else + temp_soc = 0; + } + + /* rounding off and Changing to percentage */ + soc = temp_soc / 100; + + if (temp_soc % 100 >= 50) + soc += 1; + + if (soc >= 26) + soc += 4; + else + soc = (30 * temp_soc) / 26 / 100; + + if (soc >= 100) + soc = 100; + + chip->soc = soc; } static void max17040_get_version(struct i2c_client *client) diff --git a/drivers/power/s5pc110_battery.c b/drivers/power/s5pc110_battery.c index 6cb3e9092ea..0da972310fb 100755 --- a/drivers/power/s5pc110_battery.c +++ b/drivers/power/s5pc110_battery.c @@ -199,10 +199,11 @@ static int s3c_bat_get_property(struct power_supply *bat_ps, break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: case POWER_SUPPLY_PROP_CAPACITY: - if (chg->pdata && chg->pdata->psy_fuelgauge && - chg->pdata->psy_fuelgauge->get_property && - chg->pdata->psy_fuelgauge->get_property(chg->pdata->psy_fuelgauge, - psp, (union power_supply_propval *)&val->intval) < 0) + if (chg->pdata && + chg->pdata->psy_fuelgauge && + chg->pdata->psy_fuelgauge->get_property && + chg->pdata->psy_fuelgauge->get_property( + chg->pdata->psy_fuelgauge, psp, val) < 0) return -EINVAL; break; case POWER_SUPPLY_PROP_TECHNOLOGY: From f2d3c60ac33443a9ccd66f858675a6561c8bf030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Sun, 27 Feb 2011 16:07:49 +0100 Subject: [PATCH 0438/4025] Voodoo color: documenting Super AMOLED driver --- drivers/video/samsung/s3cfb_tl2796.c | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/video/samsung/s3cfb_tl2796.c b/drivers/video/samsung/s3cfb_tl2796.c index 682997059a4..3b1e770958c 100755 --- a/drivers/video/samsung/s3cfb_tl2796.c +++ b/drivers/video/samsung/s3cfb_tl2796.c @@ -69,6 +69,18 @@ struct s5p_lcd{ static u32 gamma_lookup(struct s5p_lcd *lcd, u8 brightness, u32 val, int c) { + // c color (red, green, blue) + // val brightness value (BV_0, BV_1, BV_19, BV_43, BV_87, BV_171, BV_255) + // b brightness value divided by brightness level + + // bl brightness range - low + // bh brightness range - high + + // vl gamma table range - low + // vh gamma table range - high + + // ret return value from the gamma table + int i; u32 bl = 0; u32 bh = 0; @@ -95,16 +107,26 @@ static u32 gamma_lookup(struct s5p_lcd *lcd, u8 brightness, u32 val, int c) b = tmp + bv->v0; } + // find which entry of the gamma table fits for val + // as a result, i becomes the index in the gamma table for val and color c for (i = 0; i < pdata->gamma_table_size; i++) { bl = bh; bh = pdata->gamma_table[i].brightness; if (bh >= b) break; } + + // save corresponding value from the gamma table as vh + // high value of the range vh = pdata->gamma_table[i].v[c]; + + // for special black point and gamma 0 (i==0 or i==1), return value + // is static. vl = vh = same as the value in gamma table for i if (i == 0 || (b - bl) == 0) { ret = vl = vh; } else { + // simple proportional calculation of ret + // based on vl and vh from gamma table ranges vl = pdata->gamma_table[i - 1].v[c]; tmp = (u64)vh * (b - bl) + (u64)vl * (bh - b); do_div(tmp, bh - bl); @@ -124,13 +146,18 @@ static void setup_gamma_regs(struct s5p_lcd *lcd, u16 gamma_regs[]) u8 brightness = lcd->bl; const struct tl2796_gamma_adj_points *bv = lcd->gamma_adj_points; + // red, green then blue for (c = 0; c < 3; c++) { + // initialize v0 (black point) from the gamma table + // vx are gamma points 1 to 4. + // adj becomes one of the value sent to the panel u32 adj; u32 v0 = gamma_lookup(lcd, brightness, BV_0, c); u32 vx[6]; u32 v1; u32 v255; + // calculate gamma 0 value, based on v0 and v1 v1 = vx[0] = gamma_lookup(lcd, brightness, bv->v1, c); adj = 600 - 5 - DIV_ROUND_CLOSEST(600 * v1, v0); adj -= lcd->gamma_reg_offsets.v[c][0]; @@ -142,8 +169,10 @@ static void setup_gamma_regs(struct s5p_lcd *lcd, u16 gamma_regs[]) else adj = 140; } + // record gamma 0 gamma_regs[c] = adj | 0x100; + // calculate brightness value for color c v255 = vx[5] = gamma_lookup(lcd, brightness, bv->v255, c); adj = 600 - 120 - DIV_ROUND_CLOSEST(600 * v255, v0); adj -= lcd->gamma_reg_offsets.v[c][5]; @@ -155,7 +184,9 @@ static void setup_gamma_regs(struct s5p_lcd *lcd, u16 gamma_regs[]) else adj = 380; } + // command to set brightness value for color c: always 0x100 gamma_regs[3 * 5 + 2 * c] = adj >> 8 | 0x100; + // record brightness value for color c = adj gamma_regs[3 * 5 + 2 * c + 1] = (adj & 0xff) | 0x100; vx[1] = gamma_lookup(lcd, brightness, bv->v19, c); @@ -163,12 +194,19 @@ static void setup_gamma_regs(struct s5p_lcd *lcd, u16 gamma_regs[]) vx[3] = gamma_lookup(lcd, brightness, bv->v87, c); vx[4] = gamma_lookup(lcd, brightness, bv->v171, c); + // calculate gamma points 4 to 1 successively + // those are calculated from vx[4] to vx[1], based on + // gamma table values chosen to follow current brightness for (i = 4; i >= 1; i--) { if (v1 <= vx[i + 1]) { adj = -1; } else { + // actual calculation adj = DIV_ROUND_CLOSEST(320 * (v1 - vx[i]), v1 - vx[i + 1]) - 65; + // new in 2.3.3: offset value based on mtp + // offsets are calculated from screen hardware + // readings in tl2796_read_mtp_info() adj -= lcd->gamma_reg_offsets.v[c][i]; } if (adj > 255) { @@ -491,6 +529,7 @@ static void tl2796_adjust_brightness_from_mtp(struct s5p_lcd *lcd) int scale = gamma_lookup(lcd, 255, BV_0, c); v255[c] = DIV_ROUND_CLOSEST((600 - 120 - factory_v255_regs[c] - offset->v[c][5]) * scale, 600); + // new in 2.3.3, read voltages from the screen hardware bc[c] = tl2796_voltage_lookup(lcd, c, v255[c]); } From 31ea3ee7d1a503a73dea57ba1cb57cb8cf722980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Sun, 27 Feb 2011 19:39:39 +0100 Subject: [PATCH 0439/4025] Voodoo color: version 2 = ported to 2.3.3 driver with a few changes --- arch/arm/mach-s5pv210/herring-panel.c | 4 + drivers/video/samsung/Kconfig | 15 ++ drivers/video/samsung/s3cfb_tl2796.c | 206 ++++++++++++++++++++++++++ include/linux/tl2796.h | 4 + 4 files changed, 229 insertions(+) diff --git a/arch/arm/mach-s5pv210/herring-panel.c b/arch/arm/mach-s5pv210/herring-panel.c index 8f69681e620..ed619c23e12 100755 --- a/arch/arm/mach-s5pv210/herring-panel.c +++ b/arch/arm/mach-s5pv210/herring-panel.c @@ -163,7 +163,11 @@ static const struct tl2796_gamma_adj_points gamma_adj_points = { .v255 = BV_255, }; +#ifdef CONFIG_FB_VOODOO +struct gamma_entry gamma_table[] = { +#else static const struct gamma_entry gamma_table[] = { +#endif { BV_0, { 4200000, 4200000, 4200000, }, }, { 1, { 3994200, 4107600, 3910200, }, }, { 0x00000400, { 3669486, 3738030, 3655093, }, }, diff --git a/drivers/video/samsung/Kconfig b/drivers/video/samsung/Kconfig index 3434028ac07..7d389b926e7 100755 --- a/drivers/video/samsung/Kconfig +++ b/drivers/video/samsung/Kconfig @@ -111,6 +111,21 @@ config FB_S3C_TL2796 ---help--- This enables support for Samsung TL2796 WVGA LCD panel +config FB_VOODOO + bool "Voodoo Color" + depends on FB_S3C_TL2796 + default y + ---help--- + This enables support Voodoo color mods + +config FB_VOODOO_DEBUG_LOG + bool "Verbose Super AMOLED driver logs" + depends on FB_VOODOO + default n + ---help--- + Logging for developers + Super AMOLED hardware command decoding and driver calculations + config FB_S3C_NT35580 bool "NT35580" depends on FB_S3C diff --git a/drivers/video/samsung/s3cfb_tl2796.c b/drivers/video/samsung/s3cfb_tl2796.c index 3b1e770958c..869f491aa2e 100755 --- a/drivers/video/samsung/s3cfb_tl2796.c +++ b/drivers/video/samsung/s3cfb_tl2796.c @@ -31,6 +31,10 @@ #include #include #include +#ifdef CONFIG_FB_VOODOO +#include +#define VOODOO_COLOR_VERSION 2 +#endif #define SLEEPMSEC 0x1000 #define ENDDEF 0x2000 @@ -67,6 +71,10 @@ struct s5p_lcd{ struct dentry *debug_dir; }; +#ifdef CONFIG_FB_VOODOO +struct s5p_lcd *lcd_; +#endif + static u32 gamma_lookup(struct s5p_lcd *lcd, u8 brightness, u32 val, int c) { // c color (red, green, blue) @@ -247,20 +255,55 @@ static int s6e63m0_spi_write_driver(struct s5p_lcd *lcd, u16 reg) return ret ; } +#ifdef CONFIG_FB_VOODOO_DEBUG_LOG +static void voodoo_print_decoded_commands(short unsigned int commands_record[], int i) +{ + if (i == 25) + { + printk("Super AMOLED commands decoding:\n"); + printk("Brightness gains: Red = %3d, Green = %3d, Blue = %3d\n", + commands_record[18]-256, commands_record[20]-256, commands_record[22]-256); + printk("Gamma 0: Red = %3d, Green = %3d, Blue = %3d\n", + commands_record[2]-256, commands_record[3]-256, commands_record[4]-256); + printk("Gamma 1: Red = %3d, Green = %3d, Blue = %3d\n", + commands_record[5]-256, commands_record[6]-256, commands_record[7]-256); + printk("Gamma 2: Red = %3d, Green = %3d, Blue = %3d\n", + commands_record[8]-256, commands_record[9]-256, commands_record[10]-256); + printk("Gamma 3: Red = %3d, Green = %3d, Blue = %3d\n", + commands_record[11]-256, commands_record[12]-256, commands_record[13]-256); + printk("Gamma 4: Red = %3d, Green = %3d, Blue = %3d\n", + commands_record[14]-256, commands_record[15]-256, commands_record[16]-256); + } + +} +#endif + static void s6e63m0_panel_send_sequence(struct s5p_lcd *lcd, const u16 *wbuf) { int i = 0; +#ifdef CONFIG_FB_VOODOO_DEBUG_LOG + short unsigned int commands_record[256]; + printk("Beginning sending commands to the Super AMOLED panel:\n"); +#endif + while ((wbuf[i] & DEFMASK) != ENDDEF) { if ((wbuf[i] & DEFMASK) != SLEEPMSEC) { s6e63m0_spi_write_driver(lcd, wbuf[i]); +#ifdef CONFIG_FB_VOODOO_DEBUG_LOG + printk("%3d = %5d - 0x%X\n", i, wbuf[i], wbuf[i]); + commands_record[i] = wbuf[i]; +#endif i += 1; } else { msleep(wbuf[i+1]); i += 2; } } +#ifdef CONFIG_FB_VOODOO_DEBUG_LOG + voodoo_print_decoded_commands(commands_record, i); +#endif } static void update_brightness(struct s5p_lcd *lcd) @@ -616,6 +659,158 @@ static void tl2796_read_mtp_info(struct s5p_lcd *lcd) tl2796_adjust_brightness_from_mtp(lcd); } +#ifdef CONFIG_FB_VOODOO +/* + * + * Voodoo Color + * + */ + +static ssize_t gamma_table_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int point; + int color; + for(point = 0; point < lcd_->data->gamma_table_size; point++) + { + for(color = 0; color < 3; color++) + { + sprintf(buf,"%s%u", buf, lcd_->data->gamma_table[point].v[color] ); + if (color != 2) + sprintf(buf,"%s,", buf); + } + + sprintf(buf,"%s\n", buf); + } + + return sprintf(buf, "%s", buf); +} + +static ssize_t gamma_table_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + int point = 0; + u32 values[3]; + struct gamma_entry new_gamma_table[lcd_->data->gamma_table_size]; + int unsigned bytes_read = 0; + int color; + + // skip comments or whatever on top of the file, max 1kB + int i; + for ( i = 0; ! sscanf(buf, "%u,%u,%u%n", &values[0], &values[1], &values[2], &bytes_read) && i <= 1024; i++) + buf += 1; + + // read the standard gamma table format + while (sscanf(buf, "%u,%u,%u%n", &values[0], &values[1], &values[2], &bytes_read) && point < lcd_->data->gamma_table_size) + { + buf += bytes_read; + color = 0; + printk("Voodoo color: gamma table point %2d: ", point); + while (color < 3) + { + switch (color) + { + case 0: printk("red = %7d ", values[color]); break; + case 1: printk("green = %7d ", values[color]); break; + case 2: printk("blue = %7d\n", values[color]); break; + } + + new_gamma_table[point].v[color] = values[color]; + color++; + } + point++; + } + + if (point == lcd_->data->gamma_table_size) + { + printk("Voodoo color: updating gamma table (%d points)\n", point); + + // set the new gamma table in kernel + for (point = 0; point < lcd_->data->gamma_table_size; point++) + for (color=0; color < 3; color++) + lcd_->data->gamma_table[point].v[color] = new_gamma_table[point].v[color]; + + update_brightness(lcd_); + } + else + printk("Voodoo color: gamma table malformed: ignored\n"); + + return size; +} + +static ssize_t apply_custom_brightness_gammas_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + int bytes_read = 0; + int user_values[3]; + u16 gamma_regs[27]; + int i = 0; + int j = 0; + int k = 0; + + // copied from update_brightness() to generate easily a valid panel command sequence + gamma_regs[0] = 0x0FA; + gamma_regs[1] = 0x102; + gamma_regs[23] = 0x0FA; + gamma_regs[24] = 0x103; + gamma_regs[25] = ENDDEF; + gamma_regs[26] = 0x0000; + + setup_gamma_regs(lcd_, gamma_regs + 2); + + // replace calculated values by user values + printk("Voodoo color: send user brightness and gamma values to the Super AMOLED panel:\n"); + // scan for gamma points 1, 2, 3 and 4 and then brightness and black + while (sscanf(buf, "%d,%d,%d%n", &user_values[0], &user_values[1], &user_values[2], &bytes_read) && i <= 5) + { + printk("Voodoo color: [%d] = %d,%d,%d\n", i, user_values[0], user_values[1], user_values[2]); + buf += bytes_read; + + // brightness + if (i == 0) + for (j = 0; j < 3; j++) + { + gamma_regs[18+k] = user_values[j]+256; + // skip 2 registers + k = k+2; + } + + // gamma 0 to gamma 4 + if (i > 0 && i <= 5) + for (j = 0; j < 3; j++) + gamma_regs[2+((i-1)*3)+j] = user_values[j]+256; + + i++; + } + + s6e63m0_panel_send_sequence(lcd_, gamma_regs); + + return size; +} + +static ssize_t voodoo_color_version(struct device *dev, struct device_attribute *attr, char *buf) { + return sprintf(buf, "%u\n", VOODOO_COLOR_VERSION); +} + +static DEVICE_ATTR(gamma_table, S_IRUGO | S_IWUGO , gamma_table_show, gamma_table_store); +static DEVICE_ATTR(apply_custom_brightness_gammas, S_IWUGO , NULL, apply_custom_brightness_gammas_store); +static DEVICE_ATTR(version, S_IRUGO , voodoo_color_version, NULL); + + +static struct attribute *voodoo_color_attributes[] = { + &dev_attr_gamma_table.attr, + &dev_attr_apply_custom_brightness_gammas.attr, + &dev_attr_version.attr, + NULL +}; + +static struct attribute_group voodoo_color_group = { + .attrs = voodoo_color_attributes, +}; + +static struct miscdevice voodoo_color_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "voodoo_color", +}; +#endif + static int __devinit tl2796_probe(struct spi_device *spi) { struct s5p_lcd *lcd; @@ -689,6 +884,17 @@ static int __devinit tl2796_probe(struct spi_device *spi) debugfs_create_file("current_gamma", S_IRUGO, lcd->debug_dir, lcd, &tl2796_current_gamma_fops); +#ifdef CONFIG_FB_VOODOO + misc_register(&voodoo_color_device); + if (sysfs_create_group(&voodoo_color_device.this_device->kobj, &voodoo_color_group) < 0) + { + printk("%s sysfs_create_group fail\n", __FUNCTION__); + pr_err("Failed to create sysfs group for device (%s)!\n", voodoo_color_device.name); + } + + // make a copy of the codec pointer + lcd_ = lcd; +#endif pr_info("tl2796_probe successfully proved\n"); return 0; diff --git a/include/linux/tl2796.h b/include/linux/tl2796.h index fe6d47e47f1..2abeef6e998 100755 --- a/include/linux/tl2796.h +++ b/include/linux/tl2796.h @@ -48,7 +48,11 @@ struct s5p_panel_data { struct tl2796_color_adj color_adj; const struct tl2796_gamma_adj_points *gamma_adj_points; +#ifdef CONFIG_FB_VOODOO + struct gamma_entry *gamma_table; +#else const struct gamma_entry *gamma_table; +#endif int gamma_table_size; }; From 5e723d7d9204151f6cc5cda7f1aff1e0b3b8d653 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Mon, 28 Feb 2011 01:28:33 +0100 Subject: [PATCH 0440/4025] Voodoo color: add RGB multipliers via sysfs controls --- drivers/video/samsung/s3cfb_tl2796.c | 58 +++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/drivers/video/samsung/s3cfb_tl2796.c b/drivers/video/samsung/s3cfb_tl2796.c index 869f491aa2e..677910c6e77 100755 --- a/drivers/video/samsung/s3cfb_tl2796.c +++ b/drivers/video/samsung/s3cfb_tl2796.c @@ -785,18 +785,72 @@ static ssize_t apply_custom_brightness_gammas_store(struct device *dev, struct d return size; } +static ssize_t red_multiplier_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", lcd_->color_mult[0]); +} + +static ssize_t red_multiplier_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + u32 value; + if (sscanf(buf, "%u", &value) == 1) + { + lcd_->color_mult[0] = value; + update_brightness(lcd_); + } + return size; +} + +static ssize_t green_multiplier_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", lcd_->color_mult[1]); +} + +static ssize_t green_multiplier_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + u32 value; + if (sscanf(buf, "%u", &value) == 1) + { + lcd_->color_mult[1] = value; + update_brightness(lcd_); + } + return size; +} + +static ssize_t blue_multiplier_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", lcd_->color_mult[2]); +} + +static ssize_t blue_multiplier_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + u32 value; + if (sscanf(buf, "%u", &value) == 1) + { + lcd_->color_mult[2] = value; + update_brightness(lcd_); + } + return size; +} + static ssize_t voodoo_color_version(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%u\n", VOODOO_COLOR_VERSION); } -static DEVICE_ATTR(gamma_table, S_IRUGO | S_IWUGO , gamma_table_show, gamma_table_store); +static DEVICE_ATTR(gamma_table, S_IRUGO | S_IWUGO, gamma_table_show, gamma_table_store); static DEVICE_ATTR(apply_custom_brightness_gammas, S_IWUGO , NULL, apply_custom_brightness_gammas_store); -static DEVICE_ATTR(version, S_IRUGO , voodoo_color_version, NULL); +static DEVICE_ATTR(red_multiplier, S_IRUGO | S_IWUGO, red_multiplier_show, red_multiplier_store); +static DEVICE_ATTR(green_multiplier, S_IRUGO | S_IWUGO, green_multiplier_show, green_multiplier_store); +static DEVICE_ATTR(blue_multiplier, S_IRUGO | S_IWUGO, blue_multiplier_show, blue_multiplier_store); +static DEVICE_ATTR(version, S_IRUGO, voodoo_color_version, NULL); static struct attribute *voodoo_color_attributes[] = { &dev_attr_gamma_table.attr, &dev_attr_apply_custom_brightness_gammas.attr, + &dev_attr_red_multiplier.attr, + &dev_attr_green_multiplier.attr, + &dev_attr_blue_multiplier.attr, &dev_attr_version.attr, NULL }; From 2ce3f943765cd323fef1ae13f90709735c1b952a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Mon, 28 Feb 2011 01:55:29 +0100 Subject: [PATCH 0441/4025] Voodoo color: save RGB mulplier original calculated values and make them readable via sysfs controls --- drivers/video/samsung/s3cfb_tl2796.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/video/samsung/s3cfb_tl2796.c b/drivers/video/samsung/s3cfb_tl2796.c index 677910c6e77..42784061a4d 100755 --- a/drivers/video/samsung/s3cfb_tl2796.c +++ b/drivers/video/samsung/s3cfb_tl2796.c @@ -73,6 +73,8 @@ struct s5p_lcd{ #ifdef CONFIG_FB_VOODOO struct s5p_lcd *lcd_; + +u32 original_color_adj_mults[3]; #endif static u32 gamma_lookup(struct s5p_lcd *lcd, u8 brightness, u32 val, int c) @@ -599,6 +601,9 @@ static void tl2796_adjust_brightness_from_mtp(struct s5p_lcd *lcd) for (c = 0; c < 3; c++) { lcd->color_mult[c] = bc[c]; +#ifdef CONFIG_FB_VOODOO + original_color_adj_mults[c] = bc[c]; +#endif pr_info("tl2796: c%d, b-%08llx, got v %d, factory wants %d\n", c, bc[c], gamma_lookup(lcd, 255, BV_255, c), v255[c]); } @@ -790,6 +795,11 @@ static ssize_t red_multiplier_show(struct device *dev, struct device_attribute * return sprintf(buf, "%u\n", lcd_->color_mult[0]); } +static ssize_t red_multiplier_original_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", original_color_adj_mults[0]); +} + static ssize_t red_multiplier_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u32 value; @@ -806,6 +816,11 @@ static ssize_t green_multiplier_show(struct device *dev, struct device_attribute return sprintf(buf, "%u\n", lcd_->color_mult[1]); } +static ssize_t green_multiplier_original_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", original_color_adj_mults[1]); +} + static ssize_t green_multiplier_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u32 value; @@ -822,6 +837,11 @@ static ssize_t blue_multiplier_show(struct device *dev, struct device_attribute return sprintf(buf, "%u\n", lcd_->color_mult[2]); } +static ssize_t blue_multiplier_original_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", original_color_adj_mults[2]); +} + static ssize_t blue_multiplier_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u32 value; @@ -840,8 +860,11 @@ static ssize_t voodoo_color_version(struct device *dev, struct device_attribute static DEVICE_ATTR(gamma_table, S_IRUGO | S_IWUGO, gamma_table_show, gamma_table_store); static DEVICE_ATTR(apply_custom_brightness_gammas, S_IWUGO , NULL, apply_custom_brightness_gammas_store); static DEVICE_ATTR(red_multiplier, S_IRUGO | S_IWUGO, red_multiplier_show, red_multiplier_store); +static DEVICE_ATTR(red_multiplier_original, S_IRUGO, red_multiplier_original_show, NULL); static DEVICE_ATTR(green_multiplier, S_IRUGO | S_IWUGO, green_multiplier_show, green_multiplier_store); +static DEVICE_ATTR(green_multiplier_original, S_IRUGO, green_multiplier_original_show, NULL); static DEVICE_ATTR(blue_multiplier, S_IRUGO | S_IWUGO, blue_multiplier_show, blue_multiplier_store); +static DEVICE_ATTR(blue_multiplier_original, S_IRUGO, blue_multiplier_original_show, NULL); static DEVICE_ATTR(version, S_IRUGO, voodoo_color_version, NULL); @@ -849,8 +872,11 @@ static struct attribute *voodoo_color_attributes[] = { &dev_attr_gamma_table.attr, &dev_attr_apply_custom_brightness_gammas.attr, &dev_attr_red_multiplier.attr, + &dev_attr_red_multiplier_original.attr, &dev_attr_green_multiplier.attr, + &dev_attr_green_multiplier_original.attr, &dev_attr_blue_multiplier.attr, + &dev_attr_blue_multiplier_original.attr, &dev_attr_version.attr, NULL }; From 70095c9b617c296d00ebbc2e97ce98aace198e15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Mon, 28 Feb 2011 05:29:04 +0100 Subject: [PATCH 0442/4025] Voodoo color: added control to switch of panel initialization sequence between Samsung and Google 2.2.3 ones, allowing to revert live commit 921bfc57db1849d30481b9d8ac98ab1e42feb34c --- drivers/video/samsung/s3cfb_tl2796.c | 123 ++++++++++++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) diff --git a/drivers/video/samsung/s3cfb_tl2796.c b/drivers/video/samsung/s3cfb_tl2796.c index 42784061a4d..5eff5217e10 100755 --- a/drivers/video/samsung/s3cfb_tl2796.c +++ b/drivers/video/samsung/s3cfb_tl2796.c @@ -75,6 +75,98 @@ struct s5p_lcd{ struct s5p_lcd *lcd_; u32 original_color_adj_mults[3]; +unsigned int panel_config_sequence = 0; + +static const u16 s6e63m0_SEQ_ETC_SETTING_SAMSUNG[] = { + /* ETC Condition Set Command */ + 0x0F6, + 0x100, 0x18E, + 0x107, + 0x0B3, + 0x16C, + 0x0B5, + 0x12C, 0x112, + 0x10C, 0x10A, + 0x110, 0x10E, + 0x117, 0x113, + 0x11F, 0x11A, + 0x12A, 0x124, + 0x11F, 0x11B, + 0x11A, 0x117, + 0x12B, 0x126, + 0x122, 0x120, + 0x13A, 0x134, + 0x130, 0x12C, + 0x129, 0x126, + 0x125, 0x123, + 0x121, 0x120, + 0x11E, 0x11E, + 0x0B6, + 0x100, 0x100, + 0x111, 0x122, + 0x133, 0x144, + 0x144, 0x144, + 0x155, 0x155, + 0x166, 0x166, + 0x166, 0x166, + 0x166, 0x166, + 0x0B7, + 0x12C, 0x112, + 0x10C, 0x10A, + 0x110, 0x10E, + 0x117, 0x113, + 0x11F, 0x11A, + 0x12A, 0x124, + 0x11F, 0x11B, + 0x11A, 0x117, + 0x12B, 0x126, + 0x122, 0x120, + 0x13A, 0x134, + 0x130, 0x12C, + 0x129, 0x126, + 0x125, 0x123, + 0x121, 0x120, + 0x11E, 0x11E, + 0x0B8, + 0x100, 0x100, + 0x111, 0x122, + 0x133, 0x144, + 0x144, 0x144, + 0x155, 0x155, + 0x166, 0x166, + 0x166, 0x166, + 0x166, 0x166, + 0x0B9, + 0x12C, 0x112, + 0x10C, 0x10A, + 0x110, 0x10E, + 0x117, 0x113, + 0x11F, 0x11A, + 0x12A, 0x124, + 0x11F, 0x11B, + 0x11A, 0x117, + 0x12B, 0x126, + 0x122, 0x120, + 0x13A, 0x134, + 0x130, 0x12C, + 0x129, 0x126, + 0x125, 0x123, + 0x121, 0x120, + 0x11E, 0x11E, + 0x0BA, + 0x100, 0x100, + 0x111, 0x122, + 0x133, 0x144, + 0x144, 0x144, + 0x155, 0x155, + 0x166, 0x166, + 0x166, 0x166, + 0x166, 0x166, + 0x011, + SLEEPMSEC, 120, + 0x029, + ENDDEF, 0x0000 +}; #endif static u32 gamma_lookup(struct s5p_lcd *lcd, u8 brightness, u32 val, int c) @@ -332,7 +424,14 @@ static void tl2796_ldi_enable(struct s5p_lcd *lcd) s6e63m0_panel_send_sequence(lcd, pdata->seq_display_set); update_brightness(lcd); +#ifdef CONFIG_FB_VOODOO + if (panel_config_sequence == 1) + s6e63m0_panel_send_sequence(lcd, pdata->seq_etc_set); + else + s6e63m0_panel_send_sequence(lcd, s6e63m0_SEQ_ETC_SETTING_SAMSUNG); +#else s6e63m0_panel_send_sequence(lcd, pdata->seq_etc_set); +#endif lcd->ldi_enable = 1; mutex_unlock(&lcd->lock); @@ -853,12 +952,33 @@ static ssize_t blue_multiplier_store(struct device *dev, struct device_attribute return size; } +static ssize_t panel_config_sequence_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", panel_config_sequence); +} + +static ssize_t panel_config_sequence_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + struct s5p_panel_data *pdata = lcd_->data; + unsigned int value; + if (sscanf(buf, "%u", &value) == 1) + { + panel_config_sequence = value == 1 ? 1 : 0; + if (panel_config_sequence == 1) + s6e63m0_panel_send_sequence(lcd_, s6e63m0_SEQ_ETC_SETTING_SAMSUNG); + else + s6e63m0_panel_send_sequence(lcd_, pdata->seq_etc_set); + } + return size; +} + static ssize_t voodoo_color_version(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%u\n", VOODOO_COLOR_VERSION); } static DEVICE_ATTR(gamma_table, S_IRUGO | S_IWUGO, gamma_table_show, gamma_table_store); -static DEVICE_ATTR(apply_custom_brightness_gammas, S_IWUGO , NULL, apply_custom_brightness_gammas_store); +static DEVICE_ATTR(apply_custom_brightness_gammas, S_IWUGO, NULL, apply_custom_brightness_gammas_store); +static DEVICE_ATTR(panel_config_sequence, S_IRUGO | S_IWUGO, panel_config_sequence_show, panel_config_sequence_store); static DEVICE_ATTR(red_multiplier, S_IRUGO | S_IWUGO, red_multiplier_show, red_multiplier_store); static DEVICE_ATTR(red_multiplier_original, S_IRUGO, red_multiplier_original_show, NULL); static DEVICE_ATTR(green_multiplier, S_IRUGO | S_IWUGO, green_multiplier_show, green_multiplier_store); @@ -871,6 +991,7 @@ static DEVICE_ATTR(version, S_IRUGO, voodoo_color_version, NULL); static struct attribute *voodoo_color_attributes[] = { &dev_attr_gamma_table.attr, &dev_attr_apply_custom_brightness_gammas.attr, + &dev_attr_panel_config_sequence.attr, &dev_attr_red_multiplier.attr, &dev_attr_red_multiplier_original.attr, &dev_attr_green_multiplier.attr, From 32b5808fdfee0f870ab8a46bc42b533c1912906b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Mon, 28 Feb 2011 22:43:09 +0100 Subject: [PATCH 0443/4025] Voodoo color: dirty hack to apply a customizable offset to v0 gamma point. Looks good on screen despite the terrible code used Also adds new controls (that will be removed eventually) /sys/class/misc/voodoo_color/blue_v0_offset /sys/class/misc/voodoo_color/green_v0_offset /sys/class/misc/voodoo_color/red_v0_offset default values: -16, -16, -17 --- drivers/video/samsung/s3cfb_tl2796.c | 63 ++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/drivers/video/samsung/s3cfb_tl2796.c b/drivers/video/samsung/s3cfb_tl2796.c index 5eff5217e10..28dca344e3c 100755 --- a/drivers/video/samsung/s3cfb_tl2796.c +++ b/drivers/video/samsung/s3cfb_tl2796.c @@ -77,6 +77,8 @@ struct s5p_lcd *lcd_; u32 original_color_adj_mults[3]; unsigned int panel_config_sequence = 0; +int hacky_v0_offset[3] = {-16, -16, -17}; + static const u16 s6e63m0_SEQ_ETC_SETTING_SAMSUNG[] = { /* ETC Condition Set Command */ 0x0F6, @@ -272,7 +274,14 @@ static void setup_gamma_regs(struct s5p_lcd *lcd, u16 gamma_regs[]) adj = 140; } // record gamma 0 +#ifdef CONFIG_FB_VOODOO + // terrible shameful hack allowing to get back standard + // colors without fixing the real thing properly (gamma table) + // it consist on a simple (negative) offset applied on v0 + gamma_regs[c] = ((adj + hacky_v0_offset[c]) > 0 && (adj <=255)) ? (adj + hacky_v0_offset[c]) | 0x100 : adj | 0x100; +#else gamma_regs[c] = adj | 0x100; +#endif // calculate brightness value for color c v255 = vx[5] = gamma_lookup(lcd, brightness, bv->v255, c); @@ -972,6 +981,54 @@ static ssize_t panel_config_sequence_store(struct device *dev, struct device_att return size; } +static ssize_t red_v0_offset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", hacky_v0_offset[0]); +} + +static ssize_t red_v0_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + int value; + if (sscanf(buf, "%d", &value) == 1) + { + hacky_v0_offset[0] = value; + update_brightness(lcd_); + } + return size; +} + +static ssize_t green_v0_offset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", hacky_v0_offset[0]); +} + +static ssize_t green_v0_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + int value; + if (sscanf(buf, "%d", &value) == 1) + { + hacky_v0_offset[1] = value; + update_brightness(lcd_); + } + return size; +} + +static ssize_t blue_v0_offset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", hacky_v0_offset[0]); +} + +static ssize_t blue_v0_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + int value; + if (sscanf(buf, "%d", &value) == 1) + { + hacky_v0_offset[2] = value; + update_brightness(lcd_); + } + return size; +} + static ssize_t voodoo_color_version(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%u\n", VOODOO_COLOR_VERSION); } @@ -985,6 +1042,9 @@ static DEVICE_ATTR(green_multiplier, S_IRUGO | S_IWUGO, green_multiplier_show, g static DEVICE_ATTR(green_multiplier_original, S_IRUGO, green_multiplier_original_show, NULL); static DEVICE_ATTR(blue_multiplier, S_IRUGO | S_IWUGO, blue_multiplier_show, blue_multiplier_store); static DEVICE_ATTR(blue_multiplier_original, S_IRUGO, blue_multiplier_original_show, NULL); +static DEVICE_ATTR(red_v0_offset, S_IRUGO | S_IWUGO, red_v0_offset_show, red_v0_offset_store); +static DEVICE_ATTR(green_v0_offset, S_IRUGO | S_IWUGO, green_v0_offset_show, green_v0_offset_store); +static DEVICE_ATTR(blue_v0_offset, S_IRUGO | S_IWUGO, blue_v0_offset_show, blue_v0_offset_store); static DEVICE_ATTR(version, S_IRUGO, voodoo_color_version, NULL); @@ -998,6 +1058,9 @@ static struct attribute *voodoo_color_attributes[] = { &dev_attr_green_multiplier_original.attr, &dev_attr_blue_multiplier.attr, &dev_attr_blue_multiplier_original.attr, + &dev_attr_red_v0_offset.attr, + &dev_attr_green_v0_offset.attr, + &dev_attr_blue_v0_offset.attr, &dev_attr_version.attr, NULL }; From 6b8dcf84603dd1db271b2401149cb4ff4bef6d0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Mon, 28 Feb 2011 22:43:55 +0100 Subject: [PATCH 0444/4025] Voodoo color: incomplete documentation for seq_print_gamma_regs() - miss "v" explanations --- drivers/video/samsung/s3cfb_tl2796.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/video/samsung/s3cfb_tl2796.c b/drivers/video/samsung/s3cfb_tl2796.c index 28dca344e3c..e11b3dbce23 100755 --- a/drivers/video/samsung/s3cfb_tl2796.c +++ b/drivers/video/samsung/s3cfb_tl2796.c @@ -517,6 +517,14 @@ static void seq_print_gamma_regs(struct seq_file *m, const u16 gamma_regs[]) const struct tl2796_gamma_reg_offsets *offset = &lcd->gamma_reg_offsets; for (c = 0; c < 3; c++) { + // vt values are the direct result of gamma table lookups + // for a given brightness level and an adjustement point + + // adj values correspond to what is sent to the the screen + // for each adjustement points + + // v is ? + u32 adj[6]; u32 vt[6]; u32 v[6]; From 03fdb746546acb6c87a00bc04459c990678d676d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Wed, 2 Mar 2011 00:52:45 +0100 Subject: [PATCH 0445/4025] Voodoo color: v0 offsets tuning and fix forsysfs green_v0_offset and blue_v0_offset read controls --- drivers/video/samsung/s3cfb_tl2796.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/samsung/s3cfb_tl2796.c b/drivers/video/samsung/s3cfb_tl2796.c index e11b3dbce23..b9afc52aace 100755 --- a/drivers/video/samsung/s3cfb_tl2796.c +++ b/drivers/video/samsung/s3cfb_tl2796.c @@ -77,7 +77,7 @@ struct s5p_lcd *lcd_; u32 original_color_adj_mults[3]; unsigned int panel_config_sequence = 0; -int hacky_v0_offset[3] = {-16, -16, -17}; +int hacky_v0_offset[3] = {-12, -16, -14}; static const u16 s6e63m0_SEQ_ETC_SETTING_SAMSUNG[] = { /* ETC Condition Set Command */ @@ -1007,7 +1007,7 @@ static ssize_t red_v0_offset_store(struct device *dev, struct device_attribute * static ssize_t green_v0_offset_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", hacky_v0_offset[0]); + return sprintf(buf, "%d\n", hacky_v0_offset[1]); } static ssize_t green_v0_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) @@ -1023,7 +1023,7 @@ static ssize_t green_v0_offset_store(struct device *dev, struct device_attribute static ssize_t blue_v0_offset_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", hacky_v0_offset[0]); + return sprintf(buf, "%d\n", hacky_v0_offset[2]); } static ssize_t blue_v0_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) From e3d81d86f24c55be85cfaff670ffc7ded94817d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Wed, 2 Mar 2011 02:49:31 +0100 Subject: [PATCH 0446/4025] Voodoo color: change yet again v0 gamma offsets, there is only non-great values anyway --- drivers/video/samsung/s3cfb_tl2796.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/samsung/s3cfb_tl2796.c b/drivers/video/samsung/s3cfb_tl2796.c index b9afc52aace..6f5b3f850e2 100755 --- a/drivers/video/samsung/s3cfb_tl2796.c +++ b/drivers/video/samsung/s3cfb_tl2796.c @@ -77,7 +77,7 @@ struct s5p_lcd *lcd_; u32 original_color_adj_mults[3]; unsigned int panel_config_sequence = 0; -int hacky_v0_offset[3] = {-12, -16, -14}; +int hacky_v0_offset[3] = {-14, -17, -18}; static const u16 s6e63m0_SEQ_ETC_SETTING_SAMSUNG[] = { /* ETC Condition Set Command */ From 6873b3f1a43c08edaf748ac20b63632699e11577 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Mon, 7 Mar 2011 20:33:43 +0100 Subject: [PATCH 0447/4025] Voodoo color: v0 was incorrecty named, for real it's v1. code and controls renamed --- drivers/video/samsung/s3cfb_tl2796.c | 40 ++++++++++++++-------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/video/samsung/s3cfb_tl2796.c b/drivers/video/samsung/s3cfb_tl2796.c index 6f5b3f850e2..300798184b5 100755 --- a/drivers/video/samsung/s3cfb_tl2796.c +++ b/drivers/video/samsung/s3cfb_tl2796.c @@ -77,7 +77,7 @@ struct s5p_lcd *lcd_; u32 original_color_adj_mults[3]; unsigned int panel_config_sequence = 0; -int hacky_v0_offset[3] = {-14, -17, -18}; +int hacky_v1_offset[3] = {-14, -17, -18}; static const u16 s6e63m0_SEQ_ETC_SETTING_SAMSUNG[] = { /* ETC Condition Set Command */ @@ -278,7 +278,7 @@ static void setup_gamma_regs(struct s5p_lcd *lcd, u16 gamma_regs[]) // terrible shameful hack allowing to get back standard // colors without fixing the real thing properly (gamma table) // it consist on a simple (negative) offset applied on v0 - gamma_regs[c] = ((adj + hacky_v0_offset[c]) > 0 && (adj <=255)) ? (adj + hacky_v0_offset[c]) | 0x100 : adj | 0x100; + gamma_regs[c] = ((adj + hacky_v1_offset[c]) > 0 && (adj <=255)) ? (adj + hacky_v1_offset[c]) | 0x100 : adj | 0x100; #else gamma_regs[c] = adj | 0x100; #endif @@ -989,49 +989,49 @@ static ssize_t panel_config_sequence_store(struct device *dev, struct device_att return size; } -static ssize_t red_v0_offset_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t red_v1_offset_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", hacky_v0_offset[0]); + return sprintf(buf, "%d\n", hacky_v1_offset[0]); } -static ssize_t red_v0_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +static ssize_t red_v1_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int value; if (sscanf(buf, "%d", &value) == 1) { - hacky_v0_offset[0] = value; + hacky_v1_offset[0] = value; update_brightness(lcd_); } return size; } -static ssize_t green_v0_offset_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t green_v1_offset_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", hacky_v0_offset[1]); + return sprintf(buf, "%d\n", hacky_v1_offset[1]); } -static ssize_t green_v0_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +static ssize_t green_v1_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int value; if (sscanf(buf, "%d", &value) == 1) { - hacky_v0_offset[1] = value; + hacky_v1_offset[1] = value; update_brightness(lcd_); } return size; } -static ssize_t blue_v0_offset_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t blue_v1_offset_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", hacky_v0_offset[2]); + return sprintf(buf, "%d\n", hacky_v1_offset[2]); } -static ssize_t blue_v0_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +static ssize_t blue_v1_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int value; if (sscanf(buf, "%d", &value) == 1) { - hacky_v0_offset[2] = value; + hacky_v1_offset[2] = value; update_brightness(lcd_); } return size; @@ -1050,9 +1050,9 @@ static DEVICE_ATTR(green_multiplier, S_IRUGO | S_IWUGO, green_multiplier_show, g static DEVICE_ATTR(green_multiplier_original, S_IRUGO, green_multiplier_original_show, NULL); static DEVICE_ATTR(blue_multiplier, S_IRUGO | S_IWUGO, blue_multiplier_show, blue_multiplier_store); static DEVICE_ATTR(blue_multiplier_original, S_IRUGO, blue_multiplier_original_show, NULL); -static DEVICE_ATTR(red_v0_offset, S_IRUGO | S_IWUGO, red_v0_offset_show, red_v0_offset_store); -static DEVICE_ATTR(green_v0_offset, S_IRUGO | S_IWUGO, green_v0_offset_show, green_v0_offset_store); -static DEVICE_ATTR(blue_v0_offset, S_IRUGO | S_IWUGO, blue_v0_offset_show, blue_v0_offset_store); +static DEVICE_ATTR(red_v1_offset, S_IRUGO | S_IWUGO, red_v1_offset_show, red_v1_offset_store); +static DEVICE_ATTR(green_v1_offset, S_IRUGO | S_IWUGO, green_v1_offset_show, green_v1_offset_store); +static DEVICE_ATTR(blue_v1_offset, S_IRUGO | S_IWUGO, blue_v1_offset_show, blue_v1_offset_store); static DEVICE_ATTR(version, S_IRUGO, voodoo_color_version, NULL); @@ -1066,9 +1066,9 @@ static struct attribute *voodoo_color_attributes[] = { &dev_attr_green_multiplier_original.attr, &dev_attr_blue_multiplier.attr, &dev_attr_blue_multiplier_original.attr, - &dev_attr_red_v0_offset.attr, - &dev_attr_green_v0_offset.attr, - &dev_attr_blue_v0_offset.attr, + &dev_attr_red_v1_offset.attr, + &dev_attr_green_v1_offset.attr, + &dev_attr_blue_v1_offset.attr, &dev_attr_version.attr, NULL }; From b29527f97c21f5e3d1085d6758855059ed915491 Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Mon, 19 Dec 2011 02:53:21 +0100 Subject: [PATCH 0448/4025] Voodoo sound: driver v4 for Nexus S. Microphone presets feature deactivated: needs some fine adjustement for the code & hardware --- sound/soc/Kconfig | 2 + sound/soc/codecs/Kconfig.voodoo | 46 +++ sound/soc/codecs/Makefile | 7 +- sound/soc/codecs/wm8994_herring.c | 5 + sound/soc/codecs/wm8994_samsung.c | 8 + sound/soc/codecs/wm8994_voodoo.c | 649 ++++++++++++++++++++++++++++++ sound/soc/codecs/wm8994_voodoo.h | 22 + 7 files changed, 738 insertions(+), 1 deletion(-) create mode 100644 sound/soc/codecs/Kconfig.voodoo create mode 100644 sound/soc/codecs/wm8994_voodoo.c create mode 100644 sound/soc/codecs/wm8994_voodoo.h diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 8224db5f043..fbcd4f97bcc 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -58,6 +58,8 @@ source "sound/soc/sh/Kconfig" source "sound/soc/tegra/Kconfig" source "sound/soc/txx9/Kconfig" +source "sound/soc/codecs/Kconfig.voodoo" + # Supported codecs source "sound/soc/codecs/Kconfig" diff --git a/sound/soc/codecs/Kconfig.voodoo b/sound/soc/codecs/Kconfig.voodoo new file mode 100644 index 00000000000..7f07e6d273f --- /dev/null +++ b/sound/soc/codecs/Kconfig.voodoo @@ -0,0 +1,46 @@ +menuconfig SND_VOODOO + bool "Voodoo sound driver" + depends on SND_S3C24XX_SOC + default y + help + With this option enabled, the kernel compile an additionnal driver + that extend the existing sound driver + +config SND_VOODOO_HP_LEVEL_CONTROL + bool "Add headphone amplifier level control" + depends on SND_VOODOO + default y + help + Adds a control allowing to adjust the analog gain of the headphone + amplifier + +config SND_VOODOO_HP_LEVEL + int "default level at boot 0-62" + depends on SND_VOODOO_HP_LEVEL_CONTROL + default 54 + range 0 62 + help + Default headphone amplifier level. Take care not setting it to high, + it would introduce hiss for people not using the control app + +config SND_VOODOO_FM + bool "FM radio: restore a normal frequency response" + depends on SND_VOODOO && SND_ARIES_SOC_WM8994 + default y + help + Adds a control to enable or disable the high-pass filter on FM radio + +config SND_VOODOO_DEBUG + bool "Codec development tools (unsafe and introduce sound skipping)" + depends on SND_VOODOO + default n + help + Allow to codec dump registers and load register-address/value batchs + Powerful but also dangerous tool + +config SND_VOODOO_DEBUG_LOG + bool "Log every wm8994_write" + depends on SND_VOODOO_DEBUG + default n + help + Log codec writes diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 98bc006cee2..7f456c77273 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -73,9 +73,14 @@ snd-soc-wm8988-objs := wm8988.o snd-soc-wm8990-objs := wm8990.o snd-soc-wm8991-objs := wm8991.o snd-soc-wm8993-objs := wm8993.o +snd-soc-wm8995-objs := wm8995.o +ifeq ($(CONFIG_SND_VOODOO),y) +snd-soc-wm8994-objs := wm8994_samsung.o wm8994_herring.o wm8994_voodoo.o +snd-soc-wm8994-samsung-objs := wm8994_samsung.o wm8994_herring.o wm8994_voodoo.o +else snd-soc-wm8994-objs := wm8994.o wm8994-tables.o wm8958-dsp2.o snd-soc-wm8994-samsung-objs := wm8994_samsung.o wm8994_herring.o -snd-soc-wm8995-objs := wm8995.o +endif snd-soc-wm9081-objs := wm9081.o snd-soc-wm9705-objs := wm9705.o snd-soc-wm9712-objs := wm9712.o diff --git a/sound/soc/codecs/wm8994_herring.c b/sound/soc/codecs/wm8994_herring.c index 56cb39d68ee..c5bbdf2817d 100755 --- a/sound/soc/codecs/wm8994_herring.c +++ b/sound/soc/codecs/wm8994_herring.c @@ -21,6 +21,7 @@ #include #include "wm8994_samsung.h" #include "../../../arch/arm/mach-s5pv210/herring.h" +#include "wm8994_voodoo.h" /* * Debug Feature @@ -2591,6 +2592,10 @@ void wm8994_set_voicecall_common_setting(struct snd_soc_codec *codec) wm8994_set_cdma_voicecall_common_setting(codec); else wm8994_set_gsm_voicecall_common_setting(codec); + +#ifdef CONFIG_SND_VOODOO_RECORD_PRESETS + voodoo_hook_record_main_mic(); +#endif } static void wm8994_set_cdma_voicecall_receiver(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/wm8994_samsung.c b/sound/soc/codecs/wm8994_samsung.c index c1f2bf26915..ea4736a67be 100755 --- a/sound/soc/codecs/wm8994_samsung.c +++ b/sound/soc/codecs/wm8994_samsung.c @@ -41,6 +41,7 @@ #include #include "wm8994_samsung.h" #include "../../../arch/arm/mach-s5pv210/herring.h" +#include "wm8994_voodoo.h" #define WM8994_VERSION "0.1" #define SUBJECT "wm8994_samsung.c" @@ -177,6 +178,10 @@ int wm8994_write(struct snd_soc_codec *codec, unsigned int reg, u8 data[4]; int ret; +#ifdef CONFIG_SND_VOODOO + value = voodoo_hook_wm8994_write(codec, reg, value); +#endif + /* data is * D15..D9 WM8993 register offset * D8...D0 register data @@ -3026,6 +3031,9 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) //codec->dev = &i2c->dev; ret = wm8994_init(wm8994_priv, pdata); +#ifdef CONFIG_SND_VOODOO + voodoo_hook_wm8994_pcm_probe(codec); +#endif if (ret) { dev_err(codec->dev, "failed to initialize WM8994\n"); goto err_init; diff --git a/sound/soc/codecs/wm8994_voodoo.c b/sound/soc/codecs/wm8994_voodoo.c new file mode 100644 index 00000000000..7065df1de01 --- /dev/null +++ b/sound/soc/codecs/wm8994_voodoo.c @@ -0,0 +1,649 @@ +/* + * voodoo_sound.c -- WM8994 ALSA Soc Audio driver related + * + * Copyright (C) 2010 François SIMOND / twitter & XDA-developers @supercurio + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wm8994_samsung.h" +#include "wm8994_voodoo.h" + +#define SUBJECT "wm8994_voodoo.c" +#define VOODOO_SOUND_VERSION 4 + +bool bypass_write_hook = false; + +#ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL +unsigned short hplvol = CONFIG_SND_VOODOO_HP_LEVEL; +unsigned short hprvol = CONFIG_SND_VOODOO_HP_LEVEL; +#endif + +#ifdef CONFIG_SND_VOODOO_FM +bool fm_radio_headset_restore_bass = true; +bool fm_radio_headset_restore_highs = true; +bool fm_radio_headset_normalize_gain = true; +#endif + +#ifdef CONFIG_SND_VOODOO_RECORD_PRESETS +unsigned short recording_preset = 1; +#endif + +bool dac_osr128 = true; +bool adc_osr128 = false; +bool fll_tuning = false; +bool mono_downmix = false; + +// keep here a pointer to the codec structure +struct snd_soc_codec *codec_; + + +#ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL +void update_hpvol() +{ + unsigned short val; + + bypass_write_hook = true; + // hard limit to 62 because 63 introduces distortions + if (hplvol > 62) + hplvol = 62; + if (hprvol > 62) + hprvol = 62; + + // we don't need the Volume Update flag when sending the first volume + val = (WM8994_HPOUT1L_MUTE_N | hplvol); + val |= WM8994_HPOUT1L_ZC; + wm8994_write(codec_, WM8994_LEFT_OUTPUT_VOLUME, val); + + // this time we write the right volume plus the Volume Update flag. This way, both + // volume are set at the same time + val = (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | hprvol); + val |= WM8994_HPOUT1L_ZC; + wm8994_write(codec_, WM8994_RIGHT_OUTPUT_VOLUME, val); + bypass_write_hook = false; +} +#endif + +#ifdef CONFIG_SND_VOODOO_FM +void update_fm_radio_headset_restore_freqs(bool with_mute) +{ + unsigned short val; + + if (with_mute) + { + wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, 0x236); + msleep(180); + } + + if (fm_radio_headset_restore_bass) + { + // disable Sidetone high-pass filter designed for voice and not FM radio + // Sidetone(621H): 0000 ST_HPF_CUT=000, ST_HPF=0, ST2_SEL=0, ST1_SEL=0 + wm8994_write(codec_, WM8994_SIDETONE, 0x0000); + // disable 4FS ultrasonic mode and restore the hi-fi <4Hz hi pass filter + // AIF2 ADC Filters(510H): 1800 AIF2ADC_4FS=0, AIF2ADC_HPF_CUT=00, AIF2ADCL_HPF=1, AIF2ADCR_HPF=1 + wm8994_write(codec_, WM8994_AIF2_ADC_FILTERS, 0x1800); + } + else + { + // default settings in GT-I9000 Froyo XXJPX kernel sources + wm8994_write(codec_, WM8994_SIDETONE, 0x01c0); + wm8994_write(codec_, WM8994_AIF2_ADC_FILTERS, 0xF800); + } + + if (fm_radio_headset_restore_highs) + { + val = wm8994_read(codec_, WM8994_AIF2_DAC_FILTERS_1); + val &= ~(WM8994_AIF2DAC_DEEMP_MASK); + wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, val); + } + else + wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, 0x0036); + + // un-mute + if (with_mute) + { + val = wm8994_read(codec_, WM8994_AIF2_DAC_FILTERS_1); + val &= ~(WM8994_AIF2DAC_MUTE_MASK); + wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, val); + } +} + +void update_fm_radio_headset_normalize_gain() +{ + if (fm_radio_headset_normalize_gain) + { + // Bumped volume, change with Zero Cross + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_3_4_VOLUME, 0x52); + wm8994_write(codec_, WM8994_RIGHT_LINE_INPUT_3_4_VOLUME, 0x152); + wm8994_write(codec_, WM8994_AIF2_DRC_2, 0x0840); + wm8994_write(codec_, WM8994_AIF2_DRC_3, 0x2408); + wm8994_write(codec_, WM8994_AIF2_DRC_4, 0x0082); + wm8994_write(codec_, WM8994_AIF2_DRC_5, 0x0100); + wm8994_write(codec_, WM8994_AIF2_DRC_1, 0x019C); + } + else + { + // Original volume, change with Zero Cross + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_3_4_VOLUME, 0x4B); + wm8994_write(codec_, WM8994_RIGHT_LINE_INPUT_3_4_VOLUME, 0x14B); + wm8994_write(codec_, WM8994_AIF2_DRC_2, 0x0840); + wm8994_write(codec_, WM8994_AIF2_DRC_3, 0x2400); + wm8994_write(codec_, WM8994_AIF2_DRC_4, 0x0000); + wm8994_write(codec_, WM8994_AIF2_DRC_5, 0x0000); + wm8994_write(codec_, WM8994_AIF2_DRC_1, 0x019C); + } +} +#endif + + +#ifdef CONFIG_SND_VOODOO_RECORD_PRESETS +void update_recording_preset() +{ + switch (recording_preset) + { + case 0: + { + // Original: + // IN1L_VOL1=11000 (+19.5 dB) + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0118); + // DRC disabled + wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x0080); + break; + } + case 2: + { + // High sensitivy: Original - 4.5 dB, IN1L_VOL1=10101 (+15 dB) + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0115); + // DRC Input: -6dB, Ouptut -3.75dB + // Above knee 1/8, Below knee 1/2 + // Max gain 24 / Min gain -12 + wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0426); + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0019); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x0105); + break; + } + case 3: + { + // Concert: Original - 36 dB IN1L_VOL1=00000 (-16.5 dB) + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0100); + // DRC Input: -4.5dB, Ouptut -6.75dB + // Above knee 1/4, Below knee 1/2 + // Max gain 18 / Min gain -12 + wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0845); + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0011); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x00C9); + break; + } + default: + { + // make sure recording_preset is the default: 4 + recording_preset = 1; + // Balanced: Original - 16.5 dB, IN1L_VOL1=01101 (+3 dB) + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x054D); + // DRC Input: -13.5dB, Ouptut -9dB + // Above knee 1/8, Below knee 1/2 + // Max gain 12 / Min gain -12 + wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0844); + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0019); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x024C); + break; + } + } +} +#endif + + +unsigned short osr128_get_value(unsigned short val) +{ + if (dac_osr128 == 1) + val |= WM8994_DAC_OSR128; + else + val &= ~WM8994_DAC_OSR128; + + if (adc_osr128 == 1) + val |= WM8994_ADC_OSR128; + else + val &= ~WM8994_ADC_OSR128; + return val; +} + +void update_osr128() +{ + unsigned short val; + val = osr128_get_value(wm8994_read(codec_, WM8994_OVERSAMPLING)); + bypass_write_hook = true; + wm8994_write(codec_, WM8994_OVERSAMPLING, val); + bypass_write_hook = false; +} + +unsigned short fll_tuning_get_value(unsigned short val) +{ + val = (val >> WM8994_FLL1_GAIN_WIDTH << WM8994_FLL1_GAIN_WIDTH); + if (fll_tuning == 1) + val |= 5; + return val; +} + +void update_fll_tuning() +{ + unsigned short val; + val = fll_tuning_get_value(wm8994_read(codec_, WM8994_FLL1_CONTROL_4)); + bypass_write_hook = true; + wm8994_write(codec_, WM8994_FLL1_CONTROL_4, val); + bypass_write_hook = false; +} + + +unsigned short mono_downmix_get_value(unsigned short val) +{ + if (mono_downmix) + val |= WM8994_AIF1DAC1_MONO; + else + val &= ~WM8994_AIF1DAC1_MONO; + return val; +} + + +void update_mono_downmix() +{ + unsigned short val1, val2, val3; + val1 = mono_downmix_get_value(wm8994_read(codec_, WM8994_AIF1_DAC1_FILTERS_1)); + val2 = mono_downmix_get_value(wm8994_read(codec_, WM8994_AIF1_DAC2_FILTERS_1)); + val3 = mono_downmix_get_value(wm8994_read(codec_, WM8994_AIF2_DAC_FILTERS_1)); + + bypass_write_hook = true; + wm8994_write(codec_, WM8994_AIF1_DAC1_FILTERS_1, val1); + wm8994_write(codec_, WM8994_AIF1_DAC2_FILTERS_1, val2); + wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, val3); + bypass_write_hook = false; +} + +/* + * + * Declaring the controling misc devices + * + */ +#ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL +static ssize_t headphone_amplifier_level_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + // output median of left and right headphone amplifier volumes + return sprintf(buf,"%u\n", (hplvol + hprvol) / 2 ); +} + +static ssize_t headphone_amplifier_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned short vol; + if (sscanf(buf, "%hu", &vol) == 1) + { + // left and right are set to the same volumes + hplvol = hprvol = vol; + update_hpvol(); + } + return size; +} +#endif + + +#ifdef CONFIG_SND_VOODOO_FM +static ssize_t fm_radio_headset_restore_bass_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%u\n",(fm_radio_headset_restore_bass ? 1 : 0)); +} + +static ssize_t fm_radio_headset_restore_bass_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned short state; + if (sscanf(buf, "%hu", &state) == 1) + { + fm_radio_headset_restore_bass = state == 0 ? false : true; + update_fm_radio_headset_restore_freqs(true); + } + return size; +} + +static ssize_t fm_radio_headset_restore_highs_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%u\n",(fm_radio_headset_restore_highs ? 1 : 0)); +} + +static ssize_t fm_radio_headset_restore_highs_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned short state; + if (sscanf(buf, "%hu", &state) == 1) + { + fm_radio_headset_restore_highs = state == 0 ? false : true; + update_fm_radio_headset_restore_freqs(true); + } + return size; +} + +static ssize_t fm_radio_headset_normalize_gain_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%u\n",(fm_radio_headset_restore_highs ? 1 : 0)); +} + +static ssize_t fm_radio_headset_normalize_gain_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned short state; + if (sscanf(buf, "%hu", &state) == 1) + { + fm_radio_headset_normalize_gain = state == 0 ? false : true; + update_fm_radio_headset_normalize_gain(); + } + return size; +} +#endif + + +#ifdef CONFIG_SND_VOODOO_RECORD_PRESETS +static ssize_t recording_preset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%d\n", recording_preset); +} + +static ssize_t recording_preset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned short preset_number; + if (sscanf(buf, "%hu", &preset_number) == 1) + { + recording_preset = preset_number; + update_recording_preset(); + } + return size; +} +#endif + + +static ssize_t dac_osr128_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%u\n",(dac_osr128 ? 1 : 0)); +} + +static ssize_t dac_osr128_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned short state; + if (sscanf(buf, "%hu", &state) == 1) + { + dac_osr128 = state == 0 ? false : true; + update_osr128(); + } + return size; +} + +static ssize_t adc_osr128_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%u\n",(adc_osr128 ? 1 : 0)); +} + +static ssize_t adc_osr128_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned short state; + if (sscanf(buf, "%hu", &state) == 1) + { + adc_osr128 = state == 0 ? false : true; + update_osr128(); + } + return size; +} + +static ssize_t fll_tuning_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%u\n",(fll_tuning ? 1 : 0)); +} + +static ssize_t fll_tuning_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned short state; + if (sscanf(buf, "%hu", &state) == 1) + { + fll_tuning = state == 0 ? false : true; + update_fll_tuning(); + } + return size; +} + +static ssize_t mono_downmix_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%u\n",(mono_downmix ? 1 : 0)); +} + +static ssize_t mono_downmix_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned short state; + if (sscanf(buf, "%hu", &state) == 1) + { + mono_downmix = state == 0 ? false : true; + update_mono_downmix(); + } + return size; +} + + +#ifdef CONFIG_SND_VOODOO_DEBUG +static ssize_t show_wm8994_register_dump(struct device *dev, struct device_attribute *attr, char *buf) +{ + // modified version of wm8994_register_dump from wm8994_aries.c + int wm8994_register; + + for(wm8994_register = 0; wm8994_register <= 0x6; wm8994_register++) + sprintf(buf, "0x%X 0x%X\n", wm8994_register, wm8994_read(codec_, wm8994_register)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x15, wm8994_read(codec_, 0x15)); + for(wm8994_register = 0x18; wm8994_register <= 0x3C; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x4C, wm8994_read(codec_, 0x4C)); + for(wm8994_register = 0x51; wm8994_register <= 0x5C; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x60, wm8994_read(codec_, 0x60)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x101, wm8994_read(codec_, 0x101)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x110, wm8994_read(codec_, 0x110)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x111, wm8994_read(codec_, 0x111)); + for(wm8994_register = 0x200; wm8994_register <= 0x212; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + for(wm8994_register = 0x220; wm8994_register <= 0x224; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + for(wm8994_register = 0x240; wm8994_register <= 0x244; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + for(wm8994_register = 0x300; wm8994_register <= 0x317; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + for(wm8994_register = 0x400; wm8994_register <= 0x411; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + for(wm8994_register = 0x420; wm8994_register <= 0x423; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + for(wm8994_register = 0x440; wm8994_register <= 0x444; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + for(wm8994_register = 0x450; wm8994_register <= 0x454; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + for(wm8994_register = 0x480; wm8994_register <= 0x493; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + for(wm8994_register = 0x4A0; wm8994_register <= 0x4B3; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + for(wm8994_register = 0x500; wm8994_register <= 0x503; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x510, wm8994_read(codec_, 0x510)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x520, wm8994_read(codec_, 0x520)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x521, wm8994_read(codec_, 0x521)); + for(wm8994_register = 0x540; wm8994_register <= 0x544; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + for(wm8994_register = 0x580; wm8994_register <= 0x593; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + for(wm8994_register = 0x600; wm8994_register <= 0x614; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x620, wm8994_read(codec_, 0x620)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x621, wm8994_read(codec_, 0x621)); + for(wm8994_register = 0x700; wm8994_register <= 0x70A; wm8994_register++) + sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + + return sprintf(buf, "%s", buf); +} + + +static ssize_t store_wm8994_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + short unsigned int reg = 0; + short unsigned int val = 0; + int unsigned bytes_read = 0; + + while (sscanf(buf, "%hx %hx%n", ®, &val, &bytes_read) == 2) + { + buf += bytes_read; + wm8994_write(codec_, reg, val); + } + return size; +} +#endif + + +static ssize_t voodoo_sound_version(struct device *dev, struct device_attribute *attr, char *buf) { + return sprintf(buf, "%u\n", VOODOO_SOUND_VERSION); +} + +#ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL +static DEVICE_ATTR(headphone_amplifier_level, S_IRUGO | S_IWUGO , headphone_amplifier_level_show, headphone_amplifier_level_store); +#endif +#ifdef CONFIG_SND_VOODOO_FM +static DEVICE_ATTR(fm_radio_headset_restore_bass, S_IRUGO | S_IWUGO , fm_radio_headset_restore_bass_show, fm_radio_headset_restore_bass_store); +static DEVICE_ATTR(fm_radio_headset_restore_highs, S_IRUGO | S_IWUGO , fm_radio_headset_restore_highs_show, fm_radio_headset_restore_highs_store); +static DEVICE_ATTR(fm_radio_headset_normalize_gain, S_IRUGO | S_IWUGO , fm_radio_headset_normalize_gain_show, fm_radio_headset_normalize_gain_store); +#endif +#ifdef CONFIG_SND_VOODOO_RECORD_PRESETS +static DEVICE_ATTR(recording_preset, S_IRUGO | S_IWUGO , recording_preset_show, recording_preset_store); +#endif +static DEVICE_ATTR(dac_osr128, S_IRUGO | S_IWUGO , dac_osr128_show, dac_osr128_store); +static DEVICE_ATTR(adc_osr128, S_IRUGO | S_IWUGO , adc_osr128_show, adc_osr128_store); +static DEVICE_ATTR(fll_tuning, S_IRUGO | S_IWUGO , fll_tuning_show, fll_tuning_store); +static DEVICE_ATTR(mono_downmix, S_IRUGO | S_IWUGO , mono_downmix_show, mono_downmix_store); +#ifdef CONFIG_SND_VOODOO_DEBUG +static DEVICE_ATTR(wm8994_register_dump, S_IRUGO , show_wm8994_register_dump, NULL); +static DEVICE_ATTR(wm8994_write, S_IWUSR , NULL, store_wm8994_write); +#endif +static DEVICE_ATTR(version, S_IRUGO , voodoo_sound_version, NULL); + +static struct attribute *voodoo_sound_attributes[] = { +#ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL + &dev_attr_headphone_amplifier_level.attr, +#endif +#ifdef CONFIG_SND_VOODOO_FM + &dev_attr_fm_radio_headset_restore_bass.attr, + &dev_attr_fm_radio_headset_restore_highs.attr, + &dev_attr_fm_radio_headset_normalize_gain.attr, +#endif +#ifdef CONFIG_SND_VOODOO_RECORD_PRESETS + &dev_attr_recording_preset.attr, +#endif + &dev_attr_dac_osr128.attr, + &dev_attr_adc_osr128.attr, + &dev_attr_fll_tuning.attr, + &dev_attr_mono_downmix.attr, +#ifdef CONFIG_SND_VOODOO_DEBUG + &dev_attr_wm8994_register_dump.attr, + &dev_attr_wm8994_write.attr, +#endif + &dev_attr_version.attr, + NULL +}; + +static struct attribute_group voodoo_sound_group = { + .attrs = voodoo_sound_attributes, +}; + +static struct miscdevice voodoo_sound_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "voodoo_sound", +}; + + +/* + * + * Driver Hooks + * + */ + +#ifdef CONFIG_SND_VOODOO_FM +void voodoo_hook_fmradio_headset() +{ + if (! fm_radio_headset_restore_bass && ! fm_radio_headset_restore_highs && !fm_radio_headset_normalize_gain) + return; + + update_fm_radio_headset_restore_freqs(false); + update_fm_radio_headset_normalize_gain(); +} +#endif + + +#ifdef CONFIG_SND_VOODOO_RECORD_PRESETS +void voodoo_hook_record_main_mic() +{ + update_recording_preset(); +} +#endif + +void voodoo_hook_playback_headset() +{ +} + + +unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) +{ + struct wm8994_priv *wm8994 = codec->drvdata; + // modify some registers before those being written to the codec + + if (! bypass_write_hook) + { +#ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL + if (wm8994->cur_path == HP || wm8994->cur_path == HP_NO_MIC) + { + if (reg == WM8994_LEFT_OUTPUT_VOLUME) + value = (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | hplvol); + if (reg == WM8994_RIGHT_OUTPUT_VOLUME) + value = (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | hprvol); + } +#endif + if (reg == WM8994_OVERSAMPLING) + value = osr128_get_value(value); + if (reg == WM8994_FLL1_CONTROL_4) + value = fll_tuning_get_value(value); + if (reg == WM8994_AIF1_DAC1_FILTERS_1 || reg == WM8994_AIF1_DAC2_FILTERS_1 || reg == WM8994_AIF2_DAC_FILTERS_1) + value = mono_downmix_get_value(value); + } + +#ifdef CONFIG_SND_VOODOO_DEBUG_LOG + // log every write to dmesg + printk("Voodoo sound: wm8994_write register= [%X] value= [%X]\n", reg, value); + printk("Voodoo sound: cur_path=%i, rec_path=%i, power_state=%i\n", + wm8994->cur_path, wm8994->rec_path, wm8994->power_state); +#endif + return value; +} + + +void voodoo_hook_wm8994_pcm_probe(struct snd_soc_codec *codec) +{ + printk("Voodoo sound: driver v%d\n", VOODOO_SOUND_VERSION); + misc_register(&voodoo_sound_device); + if (sysfs_create_group(&voodoo_sound_device.this_device->kobj, &voodoo_sound_group) < 0) + { + printk("%s sysfs_create_group fail\n", __FUNCTION__); + pr_err("Failed to create sysfs group for device (%s)!\n", voodoo_sound_device.name); + } + + // make a copy of the codec pointer + codec_ = codec; +} diff --git a/sound/soc/codecs/wm8994_voodoo.h b/sound/soc/codecs/wm8994_voodoo.h new file mode 100644 index 00000000000..0b8e63e47be --- /dev/null +++ b/sound/soc/codecs/wm8994_voodoo.h @@ -0,0 +1,22 @@ +/* + * wm8994.h -- WM8994 Soc Audio driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +void voodoo_hook_fmradio_headset(void); +unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value); +void voodoo_hook_wm8994_pcm_probe(struct snd_soc_codec *codec); +void voodoo_hook_record_main_mic(void); +void voodoo_hook_playback_headset(void); +void update_hpvol(void); +void update_fm_radio_headset_restore_freqs(bool with_mute); +void update_fm_radio_headset_normalize_gain(void); +void update_recording_preset(void); +void update_full_bitwidth(bool with_mute); +void update_osr128(void); +void update_fll_tuning(void); +unsigned short tune_fll_value(unsigned short val); +void update_mono_downmix(void); From dbaf5858c22315a61fc4cd9c02fe5c1a55295231 Mon Sep 17 00:00:00 2001 From: supercurio Date: Wed, 23 Nov 2011 22:26:41 +0100 Subject: [PATCH 0449/4025] Voodoo sound: update to driver v5 - New speaker tuning mode for music using different hardware EQ settings than stock ones - Microphone presets now supported on Nexus S. - Microphone presets balanced and loud reworked with lower background noise and higher dynamic range for balanced: -2dB noise, +6dB dynamic range. - New DAC direct option: reduces distortion and improves SNR by a small margin (bypass usless analog channel mixer) - Anti-jitter mode on by default. - Same exact source is now used on each device supported (still: only useful code is compiled in via ifdefs) - ability to fully disable/re-enable the driver and its sysfs interface: 0 or 1 in /sys/class/misc/voodoo_sound_control/enable - refactored source code --- sound/soc/codecs/Kconfig.voodoo | 18 +- sound/soc/codecs/wm8994_herring.c | 6 + sound/soc/codecs/wm8994_samsung.c | 2 + sound/soc/codecs/wm8994_voodoo.c | 599 +++++++++++++++++++++--------- sound/soc/codecs/wm8994_voodoo.h | 30 +- 5 files changed, 463 insertions(+), 192 deletions(-) diff --git a/sound/soc/codecs/Kconfig.voodoo b/sound/soc/codecs/Kconfig.voodoo index 7f07e6d273f..af418fbc20f 100644 --- a/sound/soc/codecs/Kconfig.voodoo +++ b/sound/soc/codecs/Kconfig.voodoo @@ -1,6 +1,6 @@ menuconfig SND_VOODOO bool "Voodoo sound driver" - depends on SND_S3C24XX_SOC + depends on SND_UNIVERSAL_WM8994 || SND_S3C24XX_SOC default y help With this option enabled, the kernel compile an additionnal driver @@ -17,15 +17,29 @@ config SND_VOODOO_HP_LEVEL_CONTROL config SND_VOODOO_HP_LEVEL int "default level at boot 0-62" depends on SND_VOODOO_HP_LEVEL_CONTROL - default 54 + default 54 if MACH_HERRING=y || M110S=y + default 47 range 0 62 help Default headphone amplifier level. Take care not setting it to high, it would introduce hiss for people not using the control app +config SND_VOODOO_RECORD_PRESETS + bool "Microphone recording presets" + depends on SND_VOODOO + default y + help + Recording presets with Dynamic Range Compression auto-gain + on microphone: + - Original + - High sensitivity + - Balanced (recommanded, default) + - Loud environment - concert + config SND_VOODOO_FM bool "FM radio: restore a normal frequency response" depends on SND_VOODOO && SND_ARIES_SOC_WM8994 + default n if S5PC110_T959_BOARD=y || S5PC110_KEPLER_BOARD=y || S5PV210_VICTORY=y || M110S=y default y help Adds a control to enable or disable the high-pass filter on FM radio diff --git a/sound/soc/codecs/wm8994_herring.c b/sound/soc/codecs/wm8994_herring.c index c5bbdf2817d..28e2320d338 100755 --- a/sound/soc/codecs/wm8994_herring.c +++ b/sound/soc/codecs/wm8994_herring.c @@ -21,7 +21,9 @@ #include #include "wm8994_samsung.h" #include "../../../arch/arm/mach-s5pv210/herring.h" +#ifdef CONFIG_SND_VOODOO #include "wm8994_voodoo.h" +#endif /* * Debug Feature @@ -2168,6 +2170,10 @@ void wm8994_set_playback_speaker(struct snd_soc_codec *codec) val |= WM8994_AIF1DAC1L_TO_DAC1L; wm8994_write(codec, WM8994_DAC1_LEFT_MIXER_ROUTING, val); +#ifdef CONFIG_SND_VOODOO + voodoo_hook_playback_speaker(); +#endif + /* Enbale bias,vmid and Left speaker */ val = wm8994_read(codec, WM8994_POWER_MANAGEMENT_1); val &= ~(WM8994_BIAS_ENA_MASK | WM8994_VMID_SEL_MASK | diff --git a/sound/soc/codecs/wm8994_samsung.c b/sound/soc/codecs/wm8994_samsung.c index ea4736a67be..4b646e09098 100755 --- a/sound/soc/codecs/wm8994_samsung.c +++ b/sound/soc/codecs/wm8994_samsung.c @@ -41,7 +41,9 @@ #include #include "wm8994_samsung.h" #include "../../../arch/arm/mach-s5pv210/herring.h" +#ifdef CONFIG_SND_VOODOO #include "wm8994_voodoo.h" +#endif #define WM8994_VERSION "0.1" #define SUBJECT "wm8994_samsung.c" diff --git a/sound/soc/codecs/wm8994_voodoo.c b/sound/soc/codecs/wm8994_voodoo.c index 7065df1de01..8d0f117b679 100644 --- a/sound/soc/codecs/wm8994_voodoo.c +++ b/sound/soc/codecs/wm8994_voodoo.c @@ -1,7 +1,7 @@ /* * voodoo_sound.c -- WM8994 ALSA Soc Audio driver related * - * Copyright (C) 2010 François SIMOND / twitter & XDA-developers @supercurio + * Copyright (C) 2010/11 François SIMOND / twitter & XDA-developers @supercurio * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -11,20 +11,17 @@ */ #include -#include #include -#include -#include -#include -#include -#include -#include #include -#include "wm8994_samsung.h" #include "wm8994_voodoo.h" +#ifdef NEXUS_S +#include "wm8994_samsung.h" +#else +#include "wm8994.h" +#endif #define SUBJECT "wm8994_voodoo.c" -#define VOODOO_SOUND_VERSION 4 +#define VOODOO_SOUND_VERSION 5 bool bypass_write_hook = false; @@ -41,17 +38,53 @@ bool fm_radio_headset_normalize_gain = true; #ifdef CONFIG_SND_VOODOO_RECORD_PRESETS unsigned short recording_preset = 1; +unsigned short original_record_gain; +unsigned short original_record_gain_input_mixer; #endif +#ifdef NEXUS_S +bool speaker_tuning = false; +#endif + +// global active or kill switch +bool enable = false; + bool dac_osr128 = true; bool adc_osr128 = false; -bool fll_tuning = false; +bool fll_tuning = true; +bool dac_direct = true; bool mono_downmix = false; // keep here a pointer to the codec structure struct snd_soc_codec *codec_; +#define DECLARE_BOOL_SHOW(name) \ +static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf) \ +{ \ + return sprintf(buf,"%u\n",(name ? 1 : 0)); \ +} + +#define DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(name, updater, with_mute) \ +static ssize_t name##_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) \ +{ \ + unsigned short state; \ + if (sscanf(buf, "%hu", &state) == 1) \ + { \ + name = state == 0 ? false : true; \ + updater(with_mute); \ + } \ + return size; \ +} + + +#ifdef NEXUS_S +#define DECLARE_WM8994(codec) struct wm8994_priv *wm8994 = codec->drvdata; +#else +#define DECLARE_WM8994(codec) struct wm8994_priv *wm8994 = codec->private_data; +#endif + + #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL void update_hpvol() { @@ -83,6 +116,11 @@ void update_fm_radio_headset_restore_freqs(bool with_mute) { unsigned short val; + // apply only when FM radio is active + DECLARE_WM8994(codec_) + if (wm8994->fmradio_path == FMR_OFF) + return; + if (with_mute) { wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, 0x236); @@ -123,8 +161,13 @@ void update_fm_radio_headset_restore_freqs(bool with_mute) } } -void update_fm_radio_headset_normalize_gain() +void update_fm_radio_headset_normalize_gain(bool with_mute) { + // apply only when FM radio is active + DECLARE_WM8994(codec_) + if (wm8994->fmradio_path == FMR_OFF) + return; + if (fm_radio_headset_normalize_gain) { // Bumped volume, change with Zero Cross @@ -152,64 +195,202 @@ void update_fm_radio_headset_normalize_gain() #ifdef CONFIG_SND_VOODOO_RECORD_PRESETS -void update_recording_preset() +void update_recording_preset(bool with_mute) { - switch (recording_preset) + if (is_path(MAIN_MICROPHONE)) { - case 0: - { - // Original: - // IN1L_VOL1=11000 (+19.5 dB) - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0118); - // DRC disabled - wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x0080); - break; - } - case 2: - { - // High sensitivy: Original - 4.5 dB, IN1L_VOL1=10101 (+15 dB) - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0115); - // DRC Input: -6dB, Ouptut -3.75dB - // Above knee 1/8, Below knee 1/2 - // Max gain 24 / Min gain -12 - wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); - wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0426); - wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0019); - wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x0105); - break; - } - case 3: - { - // Concert: Original - 36 dB IN1L_VOL1=00000 (-16.5 dB) - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0100); - // DRC Input: -4.5dB, Ouptut -6.75dB - // Above knee 1/4, Below knee 1/2 - // Max gain 18 / Min gain -12 - wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); - wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0845); - wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0011); - wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x00C9); - break; - } - default: + switch (recording_preset) { - // make sure recording_preset is the default: 4 - recording_preset = 1; - // Balanced: Original - 16.5 dB, IN1L_VOL1=01101 (+3 dB) - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x054D); - // DRC Input: -13.5dB, Ouptut -9dB - // Above knee 1/8, Below knee 1/2 - // Max gain 12 / Min gain -12 - wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); - wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0844); - wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0019); - wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x024C); - break; + case 0: + { +#ifdef NEXUS_S + printk("Voodoo sound: Nexus S original microphone gain & input mixer: 0x%X, 0x%X\n", + original_record_gain, original_record_gain_input_mixer); +#endif + // Original: + // On Galaxy S: IN1L_VOL1=11000 (+19.5 dB) + // On Nexus S: variable value + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, WM8994_IN1L_VU | original_record_gain ); + wm8994_write(codec_, WM8994_INPUT_MIXER_3, original_record_gain_input_mixer); + // DRC disabled + wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x0080); + break; + } + case 2: + { + // High sensitivy: Original - 4.5 dB, IN1L_VOL1=10101 (+15 dB) + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0115); + wm8994_write(codec_, WM8994_INPUT_MIXER_3, 0x30); + // DRC Input: -6dB, Ouptut -3.75dB + // Above knee 1/8, Below knee 1/2 + // Max gain 24 / Min gain -12 + wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0426); + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0019); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x0105); + break; + } + case 3: + { + // Concert new: IN1L_VOL1=10110 (+4.5 dB) + // +30dB input mixer gain deactivated + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x010F); + wm8994_write(codec_, WM8994_INPUT_MIXER_3, 0x20); + // DRC Input: -4.5dB, Ouptut -6.75dB + // Above knee 1/4, Below knee 1/2 + // Max gain 24 / Min gain -12 + wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0846); + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0011); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x00C9); + break; + } + case 4: + { + // ULTRA LOUD: Original - 36 dB - 30 dB IN1L_VOL1=00000 (-16.5 dB) + // +30dB input mixer gain deactivated + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0100); + wm8994_write(codec_, WM8994_INPUT_MIXER_3, 0x20); + // DRC Input: -7.5dB, Ouptut -6dB + // Above knee 1/8, Below knee 1/4 + // Max gain 36 / Min gain -12 + wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0847); + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x001A); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x00C9); + break; + } + default: + { + // make sure recording_preset is the default + recording_preset = 1; + // New Balanced: Original - 16.5 dB + // IN1L_VOL1=01101 (+27 dB) + // +30dB input mixer gain deactivated + wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x055D); + wm8994_write(codec_, WM8994_INPUT_MIXER_3, 0x20); + // DRC Input: -18.5dB, Ouptut -9dB + // Above knee 1/8, Below knee 1/2 + // Max gain 18 / Min gain -12 + wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0845); + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0019); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x030C); + break; + } } } } #endif +bool is_path(int unified_path) +{ + DECLARE_WM8994(codec_) + + switch(unified_path) + { + // speaker + case SPEAKER: +#ifdef GALAXY_TAB + if (wm8994->cur_path != SPK && wm8994->cur_path != RING_SPK && + wm8994->fmradio_path != FMR_SPK && wm8994->fmradio_path != FMR_SPK_MIX) +#else + if (wm8994->cur_path != SPK && wm8994->cur_path != RING_SPK) +#endif + return true; + + // headphones + // FIXME: be sure dac_direct doesn't break phone calls on TAB + // with these spath detection settings (HP4P) + case HEADPHONES: +#ifdef NEXUS_S + if (wm8994->cur_path == HP || wm8994->cur_path == HP_NO_MIC) +#else +#ifdef GALAXY_TAB + if (wm8994->cur_path == HP3P || wm8994->cur_path == HP4P || wm8994->fmradio_path == FMR_HP) +#else +#ifdef M110S + if (wm8994->cur_path == HP) +#else + if (wm8994->cur_path == HP || wm8994->fmradio_path == FMR_HP) +#endif +#endif +#endif + return true; + + + // headphones + // FIXME: be sure dac_direct doesn't break phone calls on TAB + // with these spath detection settings (HP4P) + case MAIN_MICROPHONE: + if (wm8994->rec_path == MAIN) + return true; + + } + return false; +} + +#ifdef NEXUS_S +void update_speaker_tuning(bool with_mute) +{ + if (speaker_tuning) + { + // DRC settings + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0010); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x00EB); + + // hardware EQ + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_1, 0x041D); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_2, 0x4C00); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_A, 0x0FE3); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_B, 0x0403); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_PG, 0x0074); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_A, 0x1F03); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_B, 0xF0F9); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_PG, 0x03DA); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_A, 0x1ED2); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_B, 0xF11A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_PG, 0x045D); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_A, 0x0E76); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_B, 0xFCE4); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_PG, 0x330D); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_A, 0xFC8F); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_B, 0x0400); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_PG, 0x323C); + + // Speaker Boost tuning + wm8994_write(codec_, WM8994_CLASSD, 0x0170); + } + else + { + // DRC settings + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0028); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x0186); + + // hardware EQ + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_1, 0x0019); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_2, 0x6280); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_A, 0x0FC3); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_B, 0x03FD); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_PG, 0x00F4); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_A, 0x1F30); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_B, 0xF0CD); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_PG, 0x032C); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_A, 0x1C52); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_B, 0xF379); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_PG, 0x0DC1); + wm8994_write(codec_, WM8994_CLASSD, 0x0170); + + // Speaker Boost tuning + wm8994_write(codec_, WM8994_CLASSD, 0x0168); + } +} +#endif unsigned short osr128_get_value(unsigned short val) { @@ -225,7 +406,7 @@ unsigned short osr128_get_value(unsigned short val) return val; } -void update_osr128() +void update_osr128(bool with_mute) { unsigned short val; val = osr128_get_value(wm8994_read(codec_, WM8994_OVERSAMPLING)); @@ -242,7 +423,7 @@ unsigned short fll_tuning_get_value(unsigned short val) return val; } -void update_fll_tuning() +void update_fll_tuning(bool with_mute) { unsigned short val; val = fll_tuning_get_value(wm8994_read(codec_, WM8994_FLL1_CONTROL_4)); @@ -254,15 +435,19 @@ void update_fll_tuning() unsigned short mono_downmix_get_value(unsigned short val) { - if (mono_downmix) - val |= WM8994_AIF1DAC1_MONO; - else - val &= ~WM8994_AIF1DAC1_MONO; + // depends on the output path in order to preserve mono downmixing + // on speaker + if (is_path(SPEAKER)) + { + if (mono_downmix) + val |= WM8994_AIF1DAC1_MONO; + else + val &= ~WM8994_AIF1DAC1_MONO; + } return val; } - -void update_mono_downmix() +void update_mono_downmix(bool with_mute) { unsigned short val1, val2, val3; val1 = mono_downmix_get_value(wm8994_read(codec_, WM8994_AIF1_DAC1_FILTERS_1)); @@ -276,6 +461,32 @@ void update_mono_downmix() bypass_write_hook = false; } +unsigned short dac_direct_get_value(unsigned short val) +{ + if (is_path(HEADPHONES)) + { + if (dac_direct) + val = (val == WM8994_DAC1L_TO_MIXOUTL) ? WM8994_DAC1L_TO_HPOUT1L : val; + else + val = (val == WM8994_DAC1L_TO_HPOUT1L) ? WM8994_DAC1L_TO_MIXOUTL : val; + } + + return val; +} + +void update_dac_direct(bool with_mute) +{ + unsigned short val1, val2; + val1 = dac_direct_get_value(wm8994_read(codec_, WM8994_OUTPUT_MIXER_1)); + val2 = dac_direct_get_value(wm8994_read(codec_, WM8994_OUTPUT_MIXER_2)); + + bypass_write_hook = true; + wm8994_write(codec_, WM8994_OUTPUT_MIXER_1, val1); + wm8994_write(codec_, WM8994_OUTPUT_MIXER_2, val2); + bypass_write_hook = false; +} + + /* * * Declaring the controling misc devices @@ -301,55 +512,20 @@ static ssize_t headphone_amplifier_level_store(struct device *dev, struct device } #endif +#ifdef NEXUS_S +DECLARE_BOOL_SHOW(speaker_tuning) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(speaker_tuning, update_speaker_tuning, false) +#endif #ifdef CONFIG_SND_VOODOO_FM -static ssize_t fm_radio_headset_restore_bass_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n",(fm_radio_headset_restore_bass ? 1 : 0)); -} - -static ssize_t fm_radio_headset_restore_bass_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned short state; - if (sscanf(buf, "%hu", &state) == 1) - { - fm_radio_headset_restore_bass = state == 0 ? false : true; - update_fm_radio_headset_restore_freqs(true); - } - return size; -} +DECLARE_BOOL_SHOW(fm_radio_headset_restore_bass) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fm_radio_headset_restore_bass, update_fm_radio_headset_restore_freqs, true) -static ssize_t fm_radio_headset_restore_highs_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n",(fm_radio_headset_restore_highs ? 1 : 0)); -} +DECLARE_BOOL_SHOW(fm_radio_headset_restore_highs) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fm_radio_headset_restore_highs, update_fm_radio_headset_restore_freqs, true) -static ssize_t fm_radio_headset_restore_highs_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned short state; - if (sscanf(buf, "%hu", &state) == 1) - { - fm_radio_headset_restore_highs = state == 0 ? false : true; - update_fm_radio_headset_restore_freqs(true); - } - return size; -} - -static ssize_t fm_radio_headset_normalize_gain_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n",(fm_radio_headset_restore_highs ? 1 : 0)); -} - -static ssize_t fm_radio_headset_normalize_gain_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned short state; - if (sscanf(buf, "%hu", &state) == 1) - { - fm_radio_headset_normalize_gain = state == 0 ? false : true; - update_fm_radio_headset_normalize_gain(); - } - return size; -} +DECLARE_BOOL_SHOW(fm_radio_headset_normalize_gain) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fm_radio_headset_normalize_gain, update_fm_radio_headset_normalize_gain, false) #endif @@ -365,76 +541,27 @@ static ssize_t recording_preset_store(struct device *dev, struct device_attribut if (sscanf(buf, "%hu", &preset_number) == 1) { recording_preset = preset_number; - update_recording_preset(); + update_recording_preset(false); } return size; } #endif -static ssize_t dac_osr128_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n",(dac_osr128 ? 1 : 0)); -} - -static ssize_t dac_osr128_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned short state; - if (sscanf(buf, "%hu", &state) == 1) - { - dac_osr128 = state == 0 ? false : true; - update_osr128(); - } - return size; -} - -static ssize_t adc_osr128_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n",(adc_osr128 ? 1 : 0)); -} - -static ssize_t adc_osr128_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned short state; - if (sscanf(buf, "%hu", &state) == 1) - { - adc_osr128 = state == 0 ? false : true; - update_osr128(); - } - return size; -} +DECLARE_BOOL_SHOW(dac_osr128) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(dac_osr128, update_osr128, false) -static ssize_t fll_tuning_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n",(fll_tuning ? 1 : 0)); -} +DECLARE_BOOL_SHOW(adc_osr128) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(adc_osr128, update_osr128, false) -static ssize_t fll_tuning_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned short state; - if (sscanf(buf, "%hu", &state) == 1) - { - fll_tuning = state == 0 ? false : true; - update_fll_tuning(); - } - return size; -} +DECLARE_BOOL_SHOW(fll_tuning) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fll_tuning, update_fll_tuning, false) -static ssize_t mono_downmix_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n",(mono_downmix ? 1 : 0)); -} +DECLARE_BOOL_SHOW(mono_downmix) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(mono_downmix, update_mono_downmix, false) -static ssize_t mono_downmix_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned short state; - if (sscanf(buf, "%hu", &state) == 1) - { - mono_downmix = state == 0 ? false : true; - update_mono_downmix(); - } - return size; -} +DECLARE_BOOL_SHOW(dac_direct) +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(dac_direct, update_dac_direct, false) #ifdef CONFIG_SND_VOODOO_DEBUG @@ -515,9 +642,31 @@ static ssize_t voodoo_sound_version(struct device *dev, struct device_attribute return sprintf(buf, "%u\n", VOODOO_SOUND_VERSION); } + +DECLARE_BOOL_SHOW(enable) +static ssize_t enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned short state; + bool bool_state; + if (sscanf(buf, "%hu", &state) == 1) + { + bool_state = state == 0 ? false : true; + if (state != enable) + { + enable = bool_state; + update_enable(); + } + } + return size; +} + + #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL static DEVICE_ATTR(headphone_amplifier_level, S_IRUGO | S_IWUGO , headphone_amplifier_level_show, headphone_amplifier_level_store); #endif +#ifdef NEXUS_S +static DEVICE_ATTR(speaker_tuning, S_IRUGO | S_IWUGO , speaker_tuning_show, speaker_tuning_store); +#endif #ifdef CONFIG_SND_VOODOO_FM static DEVICE_ATTR(fm_radio_headset_restore_bass, S_IRUGO | S_IWUGO , fm_radio_headset_restore_bass_show, fm_radio_headset_restore_bass_store); static DEVICE_ATTR(fm_radio_headset_restore_highs, S_IRUGO | S_IWUGO , fm_radio_headset_restore_highs_show, fm_radio_headset_restore_highs_store); @@ -529,6 +678,7 @@ static DEVICE_ATTR(recording_preset, S_IRUGO | S_IWUGO , recording_preset_show, static DEVICE_ATTR(dac_osr128, S_IRUGO | S_IWUGO , dac_osr128_show, dac_osr128_store); static DEVICE_ATTR(adc_osr128, S_IRUGO | S_IWUGO , adc_osr128_show, adc_osr128_store); static DEVICE_ATTR(fll_tuning, S_IRUGO | S_IWUGO , fll_tuning_show, fll_tuning_store); +static DEVICE_ATTR(dac_direct, S_IRUGO | S_IWUGO , dac_direct_show, dac_direct_store); static DEVICE_ATTR(mono_downmix, S_IRUGO | S_IWUGO , mono_downmix_show, mono_downmix_store); #ifdef CONFIG_SND_VOODOO_DEBUG static DEVICE_ATTR(wm8994_register_dump, S_IRUGO , show_wm8994_register_dump, NULL); @@ -536,10 +686,15 @@ static DEVICE_ATTR(wm8994_write, S_IWUSR , NULL, store_wm8994_write); #endif static DEVICE_ATTR(version, S_IRUGO , voodoo_sound_version, NULL); +static DEVICE_ATTR(enable, S_IRUGO | S_IWUGO , enable_show, enable_store); + static struct attribute *voodoo_sound_attributes[] = { #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL &dev_attr_headphone_amplifier_level.attr, #endif +#ifdef NEXUS_S + &dev_attr_speaker_tuning.attr, +#endif #ifdef CONFIG_SND_VOODOO_FM &dev_attr_fm_radio_headset_restore_bass.attr, &dev_attr_fm_radio_headset_restore_highs.attr, @@ -551,6 +706,7 @@ static struct attribute *voodoo_sound_attributes[] = { &dev_attr_dac_osr128.attr, &dev_attr_adc_osr128.attr, &dev_attr_fll_tuning.attr, + &dev_attr_dac_direct.attr, &dev_attr_mono_downmix.attr, #ifdef CONFIG_SND_VOODOO_DEBUG &dev_attr_wm8994_register_dump.attr, @@ -560,15 +716,53 @@ static struct attribute *voodoo_sound_attributes[] = { NULL }; +static struct attribute *voodoo_sound_control_attributes[] = { + &dev_attr_enable.attr, + NULL +}; + static struct attribute_group voodoo_sound_group = { .attrs = voodoo_sound_attributes, }; +static struct attribute_group voodoo_sound_control_group = { + .attrs = voodoo_sound_control_attributes, +}; + static struct miscdevice voodoo_sound_device = { .minor = MISC_DYNAMIC_MINOR, .name = "voodoo_sound", }; +static struct miscdevice voodoo_sound_control_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "voodoo_sound_control", +}; + + +void voodoo_hook_wm8994_pcm_remove() { + printk("Voodoo sound: removing driver v%d\n", VOODOO_SOUND_VERSION); + sysfs_remove_group(&voodoo_sound_device.this_device->kobj, &voodoo_sound_group); + misc_deregister(&voodoo_sound_device); +} + + +void update_enable() +{ + if (enable) + { + printk("Voodoo sound: initializing driver v%d\n", VOODOO_SOUND_VERSION); + misc_register(&voodoo_sound_device); + if (sysfs_create_group(&voodoo_sound_device.this_device->kobj, &voodoo_sound_group) < 0) + { + printk("%s sysfs_create_group fail\n", __FUNCTION__); + pr_err("Failed to create sysfs group for device (%s)!\n", voodoo_sound_device.name); + } + } + else + voodoo_hook_wm8994_pcm_remove(); +} + /* * @@ -579,11 +773,15 @@ static struct miscdevice voodoo_sound_device = { #ifdef CONFIG_SND_VOODOO_FM void voodoo_hook_fmradio_headset() { + // global kill switch + if (! enable) + return; + if (! fm_radio_headset_restore_bass && ! fm_radio_headset_restore_highs && !fm_radio_headset_normalize_gain) return; update_fm_radio_headset_restore_freqs(false); - update_fm_radio_headset_normalize_gain(); + update_fm_radio_headset_normalize_gain(false); } #endif @@ -591,24 +789,48 @@ void voodoo_hook_fmradio_headset() #ifdef CONFIG_SND_VOODOO_RECORD_PRESETS void voodoo_hook_record_main_mic() { - update_recording_preset(); + // global kill switch + if (! enable) + return; + + if (recording_preset == 0) + return; + + original_record_gain = wm8994_read(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME); + original_record_gain_input_mixer = wm8994_read(codec_, WM8994_INPUT_MIXER_3); + update_recording_preset(false); } #endif -void voodoo_hook_playback_headset() + +void voodoo_hook_playback_speaker() { + // global kill switch + if (! enable) + return; +#ifdef NEXUS_S + if (! speaker_tuning) + return; + + update_speaker_tuning(false); +#endif } unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { - struct wm8994_priv *wm8994 = codec->drvdata; + // global kill switch + if (! enable) + return value; + // modify some registers before those being written to the codec + // be sure our pointer to codec is up to date + codec_ = codec; if (! bypass_write_hook) { #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL - if (wm8994->cur_path == HP || wm8994->cur_path == HP_NO_MIC) + if (is_path(HEADPHONES)) { if (reg == WM8994_LEFT_OUTPUT_VOLUME) value = (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | hplvol); @@ -622,13 +844,20 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int value = fll_tuning_get_value(value); if (reg == WM8994_AIF1_DAC1_FILTERS_1 || reg == WM8994_AIF1_DAC2_FILTERS_1 || reg == WM8994_AIF2_DAC_FILTERS_1) value = mono_downmix_get_value(value); + if (reg == WM8994_OUTPUT_MIXER_1 || reg == WM8994_OUTPUT_MIXER_2) + value = dac_direct_get_value(value); } #ifdef CONFIG_SND_VOODOO_DEBUG_LOG // log every write to dmesg printk("Voodoo sound: wm8994_write register= [%X] value= [%X]\n", reg, value); +#ifdef NEXUS_S printk("Voodoo sound: cur_path=%i, rec_path=%i, power_state=%i\n", wm8994->cur_path, wm8994->rec_path, wm8994->power_state); +#else + printk("Voodoo sound: cur_path=%i, rec_path=%i, fmradio_path=%i, fmr_mix_path=%i, power_state=%i, recognition_active=%i, ringtone_active=%i\n", + wm8994->cur_path, wm8994->rec_path, wm8994->fmradio_path, wm8994->fmr_mix_path, wm8994->power_state, wm8994->recognition_active, wm8994->ringtone_active); +#endif #endif return value; } @@ -636,12 +865,14 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int void voodoo_hook_wm8994_pcm_probe(struct snd_soc_codec *codec) { - printk("Voodoo sound: driver v%d\n", VOODOO_SOUND_VERSION); - misc_register(&voodoo_sound_device); - if (sysfs_create_group(&voodoo_sound_device.this_device->kobj, &voodoo_sound_group) < 0) + enable = true; + update_enable(); + + misc_register(&voodoo_sound_control_device); + if (sysfs_create_group(&voodoo_sound_control_device.this_device->kobj, &voodoo_sound_control_group) < 0) { printk("%s sysfs_create_group fail\n", __FUNCTION__); - pr_err("Failed to create sysfs group for device (%s)!\n", voodoo_sound_device.name); + pr_err("Failed to create sysfs group for device (%s)!\n", voodoo_sound_control_device.name); } // make a copy of the codec pointer diff --git a/sound/soc/codecs/wm8994_voodoo.h b/sound/soc/codecs/wm8994_voodoo.h index 0b8e63e47be..e7a31b033a4 100644 --- a/sound/soc/codecs/wm8994_voodoo.h +++ b/sound/soc/codecs/wm8994_voodoo.h @@ -6,17 +6,35 @@ * published by the Free Software Foundation. */ +bool is_path(int unified_path); void voodoo_hook_fmradio_headset(void); unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value); void voodoo_hook_wm8994_pcm_probe(struct snd_soc_codec *codec); +void voodoo_hook_wm8994_pcm_remove(void); void voodoo_hook_record_main_mic(void); -void voodoo_hook_playback_headset(void); +void voodoo_hook_playback_speaker(void); void update_hpvol(void); void update_fm_radio_headset_restore_freqs(bool with_mute); -void update_fm_radio_headset_normalize_gain(void); -void update_recording_preset(void); +void update_fm_radio_headset_normalize_gain(bool with_mute); +void update_recording_preset(bool with_mute); void update_full_bitwidth(bool with_mute); -void update_osr128(void); -void update_fll_tuning(void); +void update_osr128(bool with_mute); +void update_fll_tuning(bool with_mute); +void update_mono_downmix(bool with_mute); +void update_dac_direct(bool with_mute); +void update_enable(void); unsigned short tune_fll_value(unsigned short val); -void update_mono_downmix(void); + +#ifdef CONFIG_MACH_HERRING +#define NEXUS_S +#endif + +#ifdef CONFIG_FB_S3C_AMS701KA +#define GALAXY_TAB +#endif + +#ifdef CONFIG_M110S +#define M110S +#endif + +enum unified_path { HEADPHONES, SPEAKER, MAIN_MICROPHONE }; From 8ce30184f50c3f3cf54cda32cffb8b9c3f235112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Fri, 18 Mar 2011 02:39:58 +0100 Subject: [PATCH 0450/4025] Voodoo sound: apply speaker tuning control only when active path is speaker, fix reversed is_path(SPEAKER) logic --- sound/soc/codecs/wm8994_voodoo.c | 133 ++++++++++++++++--------------- 1 file changed, 67 insertions(+), 66 deletions(-) diff --git a/sound/soc/codecs/wm8994_voodoo.c b/sound/soc/codecs/wm8994_voodoo.c index 8d0f117b679..9aa53bc9d11 100644 --- a/sound/soc/codecs/wm8994_voodoo.c +++ b/sound/soc/codecs/wm8994_voodoo.c @@ -292,39 +292,36 @@ bool is_path(int unified_path) // speaker case SPEAKER: #ifdef GALAXY_TAB - if (wm8994->cur_path != SPK && wm8994->cur_path != RING_SPK && - wm8994->fmradio_path != FMR_SPK && wm8994->fmradio_path != FMR_SPK_MIX) + return (wm8994->cur_path == SPK || wm8994->cur_path == RING_SPK || + wm8994->fmradio_path == FMR_SPK || wm8994->fmradio_path == FMR_SPK_MIX); #else - if (wm8994->cur_path != SPK && wm8994->cur_path != RING_SPK) + return (wm8994->cur_path == SPK || wm8994->cur_path == RING_SPK); #endif - return true; // headphones // FIXME: be sure dac_direct doesn't break phone calls on TAB // with these spath detection settings (HP4P) case HEADPHONES: #ifdef NEXUS_S - if (wm8994->cur_path == HP || wm8994->cur_path == HP_NO_MIC) + return (wm8994->cur_path == HP || wm8994->cur_path == HP_NO_MIC); #else #ifdef GALAXY_TAB - if (wm8994->cur_path == HP3P || wm8994->cur_path == HP4P || wm8994->fmradio_path == FMR_HP) + return (wm8994->cur_path == HP3P || wm8994->cur_path == HP4P || wm8994->fmradio_path == FMR_HP); #else #ifdef M110S - if (wm8994->cur_path == HP) + return (wm8994->cur_path == HP); #else - if (wm8994->cur_path == HP || wm8994->fmradio_path == FMR_HP) + return (wm8994->cur_path == HP || wm8994->fmradio_path == FMR_HP); #endif #endif #endif - return true; // headphones // FIXME: be sure dac_direct doesn't break phone calls on TAB // with these spath detection settings (HP4P) case MAIN_MICROPHONE: - if (wm8994->rec_path == MAIN) - return true; + return (wm8994->rec_path == MAIN); } return false; @@ -333,61 +330,65 @@ bool is_path(int unified_path) #ifdef NEXUS_S void update_speaker_tuning(bool with_mute) { - if (speaker_tuning) - { - // DRC settings - wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0010); - wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x00EB); - - // hardware EQ - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_1, 0x041D); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_2, 0x4C00); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_A, 0x0FE3); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_B, 0x0403); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_PG, 0x0074); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_A, 0x1F03); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_B, 0xF0F9); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_C, 0x040A); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_PG, 0x03DA); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_A, 0x1ED2); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_B, 0xF11A); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_C, 0x040A); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_PG, 0x045D); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_A, 0x0E76); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_B, 0xFCE4); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_C, 0x040A); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_PG, 0x330D); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_A, 0xFC8F); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_B, 0x0400); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_PG, 0x323C); - - // Speaker Boost tuning - wm8994_write(codec_, WM8994_CLASSD, 0x0170); - } - else + if (is_path(SPEAKER)) { - // DRC settings - wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0028); - wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x0186); - - // hardware EQ - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_1, 0x0019); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_2, 0x6280); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_A, 0x0FC3); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_B, 0x03FD); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_PG, 0x00F4); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_A, 0x1F30); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_B, 0xF0CD); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_C, 0x040A); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_PG, 0x032C); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_A, 0x1C52); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_B, 0xF379); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_C, 0x040A); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_PG, 0x0DC1); - wm8994_write(codec_, WM8994_CLASSD, 0x0170); - - // Speaker Boost tuning - wm8994_write(codec_, WM8994_CLASSD, 0x0168); + printk("We are on speaker!\n"); + if (speaker_tuning) + { + // DRC settings + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0010); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x00EB); + + // hardware EQ + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_1, 0x041D); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_2, 0x4C00); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_A, 0x0FE3); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_B, 0x0403); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_PG, 0x0074); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_A, 0x1F03); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_B, 0xF0F9); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_PG, 0x03DA); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_A, 0x1ED2); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_B, 0xF11A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_PG, 0x045D); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_A, 0x0E76); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_B, 0xFCE4); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_PG, 0x330D); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_A, 0xFC8F); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_B, 0x0400); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_PG, 0x323C); + + // Speaker Boost tuning + wm8994_write(codec_, WM8994_CLASSD, 0x0170); + } + else + { + // DRC settings + wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0028); + wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x0186); + + // hardware EQ + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_1, 0x0019); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_2, 0x6280); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_A, 0x0FC3); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_B, 0x03FD); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_PG, 0x00F4); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_A, 0x1F30); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_B, 0xF0CD); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_PG, 0x032C); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_A, 0x1C52); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_B, 0xF379); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_C, 0x040A); + wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_PG, 0x0DC1); + wm8994_write(codec_, WM8994_CLASSD, 0x0170); + + // Speaker Boost tuning + wm8994_write(codec_, WM8994_CLASSD, 0x0168); + } } } #endif @@ -437,7 +438,7 @@ unsigned short mono_downmix_get_value(unsigned short val) { // depends on the output path in order to preserve mono downmixing // on speaker - if (is_path(SPEAKER)) + if (! is_path(SPEAKER)) { if (mono_downmix) val |= WM8994_AIF1DAC1_MONO; From 0b428f20378355340e9ad4bc74bf70b3fe0d138c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Mon, 21 Mar 2011 06:25:43 +0100 Subject: [PATCH 0451/4025] Voodoo sound: bump version to v6 --- sound/soc/codecs/wm8994_voodoo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8994_voodoo.c b/sound/soc/codecs/wm8994_voodoo.c index 9aa53bc9d11..d9bcb90d39f 100644 --- a/sound/soc/codecs/wm8994_voodoo.c +++ b/sound/soc/codecs/wm8994_voodoo.c @@ -21,7 +21,7 @@ #endif #define SUBJECT "wm8994_voodoo.c" -#define VOODOO_SOUND_VERSION 5 +#define VOODOO_SOUND_VERSION 6 bool bypass_write_hook = false; From 78f73e2b57f548b72f1042547c2c89b937a3ac64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Thu, 24 Mar 2011 09:10:43 +0100 Subject: [PATCH 0452/4025] Voodoo sound: modularization-related change and path management improvements --- sound/soc/codecs/Kconfig.voodoo | 8 +++ sound/soc/codecs/Makefile | 4 ++ sound/soc/codecs/wm8994_voodoo.c | 95 ++++++++++++++++++++++++++++---- sound/soc/codecs/wm8994_voodoo.h | 2 +- 4 files changed, 96 insertions(+), 13 deletions(-) diff --git a/sound/soc/codecs/Kconfig.voodoo b/sound/soc/codecs/Kconfig.voodoo index af418fbc20f..5f8514858d0 100644 --- a/sound/soc/codecs/Kconfig.voodoo +++ b/sound/soc/codecs/Kconfig.voodoo @@ -44,6 +44,14 @@ config SND_VOODOO_FM help Adds a control to enable or disable the high-pass filter on FM radio + +config SND_VOODOO_MODULE + tristate "Build also as module (incomplete)" + depends on SND_VOODOO && m + default n + help + requires additionnal source + config SND_VOODOO_DEBUG bool "Codec development tools (unsafe and introduce sound skipping)" depends on SND_VOODOO diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 7f456c77273..fa6ba22c1c7 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -186,3 +186,7 @@ obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o obj-$(CONFIG_SND_SOC_WM9090) += snd-soc-wm9090.o + +ifeq ($(CONFIG_SND_VOODOO_MODULE),m) +obj-$(CONFIG_SND_VOODOO_MODULE) += voodoo-sound-tegrak-module/ +endif diff --git a/sound/soc/codecs/wm8994_voodoo.c b/sound/soc/codecs/wm8994_voodoo.c index d9bcb90d39f..9ead3868c3f 100644 --- a/sound/soc/codecs/wm8994_voodoo.c +++ b/sound/soc/codecs/wm8994_voodoo.c @@ -23,6 +23,24 @@ #define SUBJECT "wm8994_voodoo.c" #define VOODOO_SOUND_VERSION 6 + +#ifdef MODULE +#include "tegrak_voodoo_sound.h" + +// wm8994_write -> tegrak_wm8994_write for dynamic link +#ifdef wm8994_write +#undef wm8994_write +#endif + +// wm8994_read -> tegrak_wm8994_read for dynamic link +#ifdef wm8994_read +#undef wm8994_read +#endif +#define wm8994_write(codec, reg, value) tegrak_wm8994_write(codec, reg, value) +#define wm8994_read(codec, reg) tegrak_wm8994_read(codec, reg) +#endif + + bool bypass_write_hook = false; #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL @@ -115,9 +133,10 @@ void update_hpvol() void update_fm_radio_headset_restore_freqs(bool with_mute) { unsigned short val; + DECLARE_WM8994(codec_) + bypass_write_hook = true; // apply only when FM radio is active - DECLARE_WM8994(codec_) if (wm8994->fmradio_path == FMR_OFF) return; @@ -159,12 +178,15 @@ void update_fm_radio_headset_restore_freqs(bool with_mute) val &= ~(WM8994_AIF2DAC_MUTE_MASK); wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, val); } + bypass_write_hook = false; } void update_fm_radio_headset_normalize_gain(bool with_mute) { - // apply only when FM radio is active DECLARE_WM8994(codec_) + + bypass_write_hook = true; + // apply only when FM radio is active if (wm8994->fmradio_path == FMR_OFF) return; @@ -190,6 +212,7 @@ void update_fm_radio_headset_normalize_gain(bool with_mute) wm8994_write(codec_, WM8994_AIF2_DRC_5, 0x0000); wm8994_write(codec_, WM8994_AIF2_DRC_1, 0x019C); } + bypass_write_hook = false; } #endif @@ -316,12 +339,28 @@ bool is_path(int unified_path) #endif #endif + // FM Radio on headphones + case RADIO_HEADPHONES: +#ifdef NEXUS_S + return false; +#else +#ifdef M110S + return false; +#else +#ifdef GALAXY_TAB + return (wm8994->codec_state & FMRADIO_ACTIVE) && (wm8994->fmradio_path == FMR_HP); +#else + return (wm8994->codec_state & FMRADIO_ACTIVE) && (wm8994->fmradio_path == FMR_HP); +#endif +#endif +#endif + // headphones // FIXME: be sure dac_direct doesn't break phone calls on TAB // with these spath detection settings (HP4P) case MAIN_MICROPHONE: - return (wm8994->rec_path == MAIN); + return (wm8994->codec_state & CAPTURE_ACTIVE) && (wm8994->rec_path == MAIN); } return false; @@ -330,7 +369,8 @@ bool is_path(int unified_path) #ifdef NEXUS_S void update_speaker_tuning(bool with_mute) { - if (is_path(SPEAKER)) + DECLARE_WM8994(codec_) + if (is_path(SPEAKER) && !(wm8994->codec_state & CALL_ACTIVE)) { printk("We are on speaker!\n"); if (speaker_tuning) @@ -464,7 +504,12 @@ void update_mono_downmix(bool with_mute) unsigned short dac_direct_get_value(unsigned short val) { - if (is_path(HEADPHONES)) + DECLARE_WM8994(codec_) + + if (is_path(HEADPHONES) && + (wm8994->codec_state & PLAYBACK_ACTIVE) && + !(wm8994->codec_state & CALL_ACTIVE) && + !(wm8994->stream_state & PCM_STREAM_PLAYBACK)) { if (dac_direct) val = (val == WM8994_DAC1L_TO_MIXOUTL) ? WM8994_DAC1L_TO_HPOUT1L : val; @@ -644,6 +689,7 @@ static ssize_t voodoo_sound_version(struct device *dev, struct device_attribute } +#ifndef MODULE DECLARE_BOOL_SHOW(enable) static ssize_t enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { @@ -660,7 +706,7 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr, c } return size; } - +#endif #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL static DEVICE_ATTR(headphone_amplifier_level, S_IRUGO | S_IWUGO , headphone_amplifier_level_show, headphone_amplifier_level_store); @@ -687,7 +733,9 @@ static DEVICE_ATTR(wm8994_write, S_IWUSR , NULL, store_wm8994_write); #endif static DEVICE_ATTR(version, S_IRUGO , voodoo_sound_version, NULL); +#ifndef MODULE static DEVICE_ATTR(enable, S_IRUGO | S_IWUGO , enable_show, enable_store); +#endif static struct attribute *voodoo_sound_attributes[] = { #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL @@ -717,29 +765,34 @@ static struct attribute *voodoo_sound_attributes[] = { NULL }; +#ifndef MODULE static struct attribute *voodoo_sound_control_attributes[] = { &dev_attr_enable.attr, NULL }; +#endif static struct attribute_group voodoo_sound_group = { .attrs = voodoo_sound_attributes, }; +#ifndef MODULE static struct attribute_group voodoo_sound_control_group = { .attrs = voodoo_sound_control_attributes, }; +#endif static struct miscdevice voodoo_sound_device = { .minor = MISC_DYNAMIC_MINOR, .name = "voodoo_sound", }; +#ifndef MODULE static struct miscdevice voodoo_sound_control_device = { .minor = MISC_DYNAMIC_MINOR, .name = "voodoo_sound_control", }; - +#endif void voodoo_hook_wm8994_pcm_remove() { printk("Voodoo sound: removing driver v%d\n", VOODOO_SOUND_VERSION); @@ -764,7 +817,6 @@ void update_enable() voodoo_hook_wm8994_pcm_remove(); } - /* * * Driver Hooks @@ -820,6 +872,8 @@ void voodoo_hook_playback_speaker() unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { + DECLARE_WM8994(codec) + // global kill switch if (! enable) return value; @@ -830,8 +884,9 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int if (! bypass_write_hook) { + #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL - if (is_path(HEADPHONES)) + if (is_path(HEADPHONES) && !(wm8994->codec_state & CALL_ACTIVE)) { if (reg == WM8994_LEFT_OUTPUT_VOLUME) value = (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | hplvol); @@ -839,6 +894,15 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int value = (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | hprvol); } #endif + +#ifdef CONFIG_SND_VOODOO_FM + if (is_path(RADIO_HEADPHONES)) + { + if (reg == WM8994_INPUT_MIXER_2 || reg == WM8994_AIF2_DRC_1 || reg == WM8994_ANALOGUE_HP_1) + voodoo_hook_fmradio_headset(); + } +#endif + if (reg == WM8994_OVERSAMPLING) value = osr128_get_value(value); if (reg == WM8994_FLL1_CONTROL_4) @@ -853,11 +917,16 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int // log every write to dmesg printk("Voodoo sound: wm8994_write register= [%X] value= [%X]\n", reg, value); #ifdef NEXUS_S - printk("Voodoo sound: cur_path=%i, rec_path=%i, power_state=%i\n", + printk("Voodoo sound: codec_state=%u, stream_state=%u, cur_path=%i, rec_path=%i, power_state=%i\n", + wm8994->codec_state, wm8994->stream_state, wm8994->cur_path, wm8994->rec_path, wm8994->power_state); #else - printk("Voodoo sound: cur_path=%i, rec_path=%i, fmradio_path=%i, fmr_mix_path=%i, power_state=%i, recognition_active=%i, ringtone_active=%i\n", - wm8994->cur_path, wm8994->rec_path, wm8994->fmradio_path, wm8994->fmr_mix_path, wm8994->power_state, wm8994->recognition_active, wm8994->ringtone_active); + printk("Voodoo sound: codec_state=%u, stream_state=%u, cur_path=%i, rec_path=%i, fmradio_path=%i, fmr_mix_path=%i, power_state=%i, recognition_active=%i, ringtone_active=%i\n", + wm8994->codec_state, wm8994->stream_state, + wm8994->cur_path, wm8994->rec_path, + wm8994->fmradio_path, wm8994->fmr_mix_path, + wm8994->power_state, + wm8994->recognition_active, wm8994->ringtone_active); #endif #endif return value; @@ -869,12 +938,14 @@ void voodoo_hook_wm8994_pcm_probe(struct snd_soc_codec *codec) enable = true; update_enable(); +#ifndef MODULE misc_register(&voodoo_sound_control_device); if (sysfs_create_group(&voodoo_sound_control_device.this_device->kobj, &voodoo_sound_control_group) < 0) { printk("%s sysfs_create_group fail\n", __FUNCTION__); pr_err("Failed to create sysfs group for device (%s)!\n", voodoo_sound_control_device.name); } +#endif // make a copy of the codec pointer codec_ = codec; diff --git a/sound/soc/codecs/wm8994_voodoo.h b/sound/soc/codecs/wm8994_voodoo.h index e7a31b033a4..bb87c68f6ed 100644 --- a/sound/soc/codecs/wm8994_voodoo.h +++ b/sound/soc/codecs/wm8994_voodoo.h @@ -37,4 +37,4 @@ unsigned short tune_fll_value(unsigned short val); #define M110S #endif -enum unified_path { HEADPHONES, SPEAKER, MAIN_MICROPHONE }; +enum unified_path { HEADPHONES, RADIO_HEADPHONES, SPEAKER, MAIN_MICROPHONE }; From 1b10ba19971bdc681faceb2187060d5a8371dd6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Mon, 28 Mar 2011 07:05:04 +0200 Subject: [PATCH 0453/4025] Voodoo sound: update to driver v7 - definite fix for DAC direct call issue - reshaped source code (Linux Coding Style!) - less hooks in pre-existing driver --- sound/soc/codecs/wm8994_voodoo.c | 995 +++++++++++++++++-------------- sound/soc/codecs/wm8994_voodoo.h | 6 +- 2 files changed, 555 insertions(+), 446 deletions(-) diff --git a/sound/soc/codecs/wm8994_voodoo.c b/sound/soc/codecs/wm8994_voodoo.c index 9ead3868c3f..82709d43f4c 100644 --- a/sound/soc/codecs/wm8994_voodoo.c +++ b/sound/soc/codecs/wm8994_voodoo.c @@ -14,15 +14,23 @@ #include #include #include "wm8994_voodoo.h" + +#ifndef MODULE #ifdef NEXUS_S #include "wm8994_samsung.h" #else #include "wm8994.h" #endif +#else +#ifdef NEXUS_S +#include "../wm8994_samsung.h" +#else +#include "../wm8994.h" +#endif +#endif #define SUBJECT "wm8994_voodoo.c" -#define VOODOO_SOUND_VERSION 6 - +#define VOODOO_SOUND_VERSION 7 #ifdef MODULE #include "tegrak_voodoo_sound.h" @@ -36,11 +44,11 @@ #ifdef wm8994_read #undef wm8994_read #endif + #define wm8994_write(codec, reg, value) tegrak_wm8994_write(codec, reg, value) #define wm8994_read(codec, reg) tegrak_wm8994_read(codec, reg) #endif - bool bypass_write_hook = false; #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL @@ -56,8 +64,8 @@ bool fm_radio_headset_normalize_gain = true; #ifdef CONFIG_SND_VOODOO_RECORD_PRESETS unsigned short recording_preset = 1; -unsigned short original_record_gain; -unsigned short original_record_gain_input_mixer; +unsigned short origin_recgain; +unsigned short origin_recgain_mixer; #endif #ifdef NEXUS_S @@ -74,35 +82,33 @@ bool dac_direct = true; bool mono_downmix = false; // keep here a pointer to the codec structure -struct snd_soc_codec *codec_; - +struct snd_soc_codec *codec; #define DECLARE_BOOL_SHOW(name) \ -static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf) \ +static ssize_t name##_show(struct device *dev, \ +struct device_attribute *attr, char *buf) \ { \ return sprintf(buf,"%u\n",(name ? 1 : 0)); \ } #define DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(name, updater, with_mute) \ -static ssize_t name##_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) \ +static ssize_t name##_store(struct device *dev, struct device_attribute *attr, \ + const char *buf, size_t size) \ { \ unsigned short state; \ - if (sscanf(buf, "%hu", &state) == 1) \ - { \ + if (sscanf(buf, "%hu", &state) == 1) { \ name = state == 0 ? false : true; \ updater(with_mute); \ } \ return size; \ } - #ifdef NEXUS_S #define DECLARE_WM8994(codec) struct wm8994_priv *wm8994 = codec->drvdata; #else #define DECLARE_WM8994(codec) struct wm8994_priv *wm8994 = codec->private_data; #endif - #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL void update_hpvol() { @@ -118,13 +124,13 @@ void update_hpvol() // we don't need the Volume Update flag when sending the first volume val = (WM8994_HPOUT1L_MUTE_N | hplvol); val |= WM8994_HPOUT1L_ZC; - wm8994_write(codec_, WM8994_LEFT_OUTPUT_VOLUME, val); + wm8994_write(codec, WM8994_LEFT_OUTPUT_VOLUME, val); - // this time we write the right volume plus the Volume Update flag. This way, both - // volume are set at the same time + // this time we write the right volume plus the Volume Update flag. + //This way, both volume are set at the same time val = (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | hprvol); val |= WM8994_HPOUT1L_ZC; - wm8994_write(codec_, WM8994_RIGHT_OUTPUT_VOLUME, val); + wm8994_write(codec, WM8994_RIGHT_OUTPUT_VOLUME, val); bypass_write_hook = false; } #endif @@ -133,234 +139,220 @@ void update_hpvol() void update_fm_radio_headset_restore_freqs(bool with_mute) { unsigned short val; - DECLARE_WM8994(codec_) + DECLARE_WM8994(codec); bypass_write_hook = true; // apply only when FM radio is active if (wm8994->fmradio_path == FMR_OFF) return; - if (with_mute) - { - wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, 0x236); + if (with_mute) { + wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, 0x236); msleep(180); } - if (fm_radio_headset_restore_bass) - { - // disable Sidetone high-pass filter designed for voice and not FM radio - // Sidetone(621H): 0000 ST_HPF_CUT=000, ST_HPF=0, ST2_SEL=0, ST1_SEL=0 - wm8994_write(codec_, WM8994_SIDETONE, 0x0000); - // disable 4FS ultrasonic mode and restore the hi-fi <4Hz hi pass filter - // AIF2 ADC Filters(510H): 1800 AIF2ADC_4FS=0, AIF2ADC_HPF_CUT=00, AIF2ADCL_HPF=1, AIF2ADCR_HPF=1 - wm8994_write(codec_, WM8994_AIF2_ADC_FILTERS, 0x1800); - } - else - { + if (fm_radio_headset_restore_bass) { + // disable Sidetone high-pass filter + // was designed for voice and not FM radio + wm8994_write(codec, WM8994_SIDETONE, 0x0000); + // disable 4FS ultrasonic mode and + // restore the hi-fi <4Hz hi pass filter + wm8994_write(codec, WM8994_AIF2_ADC_FILTERS, 0x1800); + } else { // default settings in GT-I9000 Froyo XXJPX kernel sources - wm8994_write(codec_, WM8994_SIDETONE, 0x01c0); - wm8994_write(codec_, WM8994_AIF2_ADC_FILTERS, 0xF800); + wm8994_write(codec, WM8994_SIDETONE, 0x01c0); + wm8994_write(codec, WM8994_AIF2_ADC_FILTERS, 0xF800); } - if (fm_radio_headset_restore_highs) - { - val = wm8994_read(codec_, WM8994_AIF2_DAC_FILTERS_1); + if (fm_radio_headset_restore_highs) { + val = wm8994_read(codec, WM8994_AIF2_DAC_FILTERS_1); val &= ~(WM8994_AIF2DAC_DEEMP_MASK); - wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, val); + wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, val); + } else { + wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, 0x0036); } - else - wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, 0x0036); // un-mute - if (with_mute) - { - val = wm8994_read(codec_, WM8994_AIF2_DAC_FILTERS_1); + if (with_mute) { + val = wm8994_read(codec, WM8994_AIF2_DAC_FILTERS_1); val &= ~(WM8994_AIF2DAC_MUTE_MASK); - wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, val); + wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, val); } bypass_write_hook = false; } void update_fm_radio_headset_normalize_gain(bool with_mute) { - DECLARE_WM8994(codec_) + DECLARE_WM8994(codec); bypass_write_hook = true; // apply only when FM radio is active if (wm8994->fmradio_path == FMR_OFF) return; - if (fm_radio_headset_normalize_gain) - { + if (fm_radio_headset_normalize_gain) { // Bumped volume, change with Zero Cross - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_3_4_VOLUME, 0x52); - wm8994_write(codec_, WM8994_RIGHT_LINE_INPUT_3_4_VOLUME, 0x152); - wm8994_write(codec_, WM8994_AIF2_DRC_2, 0x0840); - wm8994_write(codec_, WM8994_AIF2_DRC_3, 0x2408); - wm8994_write(codec_, WM8994_AIF2_DRC_4, 0x0082); - wm8994_write(codec_, WM8994_AIF2_DRC_5, 0x0100); - wm8994_write(codec_, WM8994_AIF2_DRC_1, 0x019C); - } - else - { + wm8994_write(codec, WM8994_LEFT_LINE_INPUT_3_4_VOLUME, 0x52); + wm8994_write(codec, WM8994_RIGHT_LINE_INPUT_3_4_VOLUME, 0x152); + wm8994_write(codec, WM8994_AIF2_DRC_2, 0x0840); + wm8994_write(codec, WM8994_AIF2_DRC_3, 0x2408); + wm8994_write(codec, WM8994_AIF2_DRC_4, 0x0082); + wm8994_write(codec, WM8994_AIF2_DRC_5, 0x0100); + wm8994_write(codec, WM8994_AIF2_DRC_1, 0x019C); + } else { // Original volume, change with Zero Cross - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_3_4_VOLUME, 0x4B); - wm8994_write(codec_, WM8994_RIGHT_LINE_INPUT_3_4_VOLUME, 0x14B); - wm8994_write(codec_, WM8994_AIF2_DRC_2, 0x0840); - wm8994_write(codec_, WM8994_AIF2_DRC_3, 0x2400); - wm8994_write(codec_, WM8994_AIF2_DRC_4, 0x0000); - wm8994_write(codec_, WM8994_AIF2_DRC_5, 0x0000); - wm8994_write(codec_, WM8994_AIF2_DRC_1, 0x019C); + wm8994_write(codec, WM8994_LEFT_LINE_INPUT_3_4_VOLUME, 0x4B); + wm8994_write(codec, WM8994_RIGHT_LINE_INPUT_3_4_VOLUME, 0x14B); + wm8994_write(codec, WM8994_AIF2_DRC_2, 0x0840); + wm8994_write(codec, WM8994_AIF2_DRC_3, 0x2400); + wm8994_write(codec, WM8994_AIF2_DRC_4, 0x0000); + wm8994_write(codec, WM8994_AIF2_DRC_5, 0x0000); + wm8994_write(codec, WM8994_AIF2_DRC_1, 0x019C); } bypass_write_hook = false; } #endif - #ifdef CONFIG_SND_VOODOO_RECORD_PRESETS void update_recording_preset(bool with_mute) { - if (is_path(MAIN_MICROPHONE)) - { - switch (recording_preset) - { - case 0: - { -#ifdef NEXUS_S - printk("Voodoo sound: Nexus S original microphone gain & input mixer: 0x%X, 0x%X\n", - original_record_gain, original_record_gain_input_mixer); -#endif - // Original: - // On Galaxy S: IN1L_VOL1=11000 (+19.5 dB) - // On Nexus S: variable value - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, WM8994_IN1L_VU | original_record_gain ); - wm8994_write(codec_, WM8994_INPUT_MIXER_3, original_record_gain_input_mixer); - // DRC disabled - wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x0080); - break; - } - case 2: - { - // High sensitivy: Original - 4.5 dB, IN1L_VOL1=10101 (+15 dB) - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0115); - wm8994_write(codec_, WM8994_INPUT_MIXER_3, 0x30); - // DRC Input: -6dB, Ouptut -3.75dB - // Above knee 1/8, Below knee 1/2 - // Max gain 24 / Min gain -12 - wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); - wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0426); - wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0019); - wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x0105); - break; - } - case 3: - { - // Concert new: IN1L_VOL1=10110 (+4.5 dB) - // +30dB input mixer gain deactivated - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x010F); - wm8994_write(codec_, WM8994_INPUT_MIXER_3, 0x20); - // DRC Input: -4.5dB, Ouptut -6.75dB - // Above knee 1/4, Below knee 1/2 - // Max gain 24 / Min gain -12 - wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); - wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0846); - wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0011); - wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x00C9); - break; - } - case 4: - { - // ULTRA LOUD: Original - 36 dB - 30 dB IN1L_VOL1=00000 (-16.5 dB) - // +30dB input mixer gain deactivated - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0100); - wm8994_write(codec_, WM8994_INPUT_MIXER_3, 0x20); - // DRC Input: -7.5dB, Ouptut -6dB - // Above knee 1/8, Below knee 1/4 - // Max gain 36 / Min gain -12 - wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); - wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0847); - wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x001A); - wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x00C9); - break; - } - default: - { - // make sure recording_preset is the default - recording_preset = 1; - // New Balanced: Original - 16.5 dB - // IN1L_VOL1=01101 (+27 dB) - // +30dB input mixer gain deactivated - wm8994_write(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x055D); - wm8994_write(codec_, WM8994_INPUT_MIXER_3, 0x20); - // DRC Input: -18.5dB, Ouptut -9dB - // Above knee 1/8, Below knee 1/2 - // Max gain 18 / Min gain -12 - wm8994_write(codec_, WM8994_AIF1_DRC1_1, 0x009A); - wm8994_write(codec_, WM8994_AIF1_DRC1_2, 0x0845); - wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0019); - wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x030C); - break; - } - } + if (!is_path(MAIN_MICROPHONE)) + return; + + switch (recording_preset) { + case 0: + // Original: + // On Galaxy S: IN1L_VOL1=11000 (+19.5 dB) + // On Nexus S: variable value + wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, + WM8994_IN1L_VU | origin_recgain); + wm8994_write(codec, WM8994_INPUT_MIXER_3, origin_recgain_mixer); + // DRC disabled + wm8994_write(codec, WM8994_AIF1_DRC1_1, 0x0080); + break; + case 2: + // High sensitivy: + // Original - 4.5 dB, IN1L_VOL1=10101 (+15 dB) + wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0115); + wm8994_write(codec, WM8994_INPUT_MIXER_3, 0x30); + // DRC Input: -6dB, Ouptut -3.75dB + // Above knee 1/8, Below knee 1/2 + // Max gain 24 / Min gain -12 + wm8994_write(codec, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec, WM8994_AIF1_DRC1_2, 0x0426); + wm8994_write(codec, WM8994_AIF1_DRC1_3, 0x0019); + wm8994_write(codec, WM8994_AIF1_DRC1_4, 0x0105); + break; + case 3: + // Concert new: IN1L_VOL1=10110 (+4.5 dB) + // +30dB input mixer gain deactivated + wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x010F); + wm8994_write(codec, WM8994_INPUT_MIXER_3, 0x20); + // DRC Input: -4.5dB, Ouptut -6.75dB + // Above knee 1/4, Below knee 1/2 + // Max gain 24 / Min gain -12 + wm8994_write(codec, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec, WM8994_AIF1_DRC1_2, 0x0846); + wm8994_write(codec, WM8994_AIF1_DRC1_3, 0x0011); + wm8994_write(codec, WM8994_AIF1_DRC1_4, 0x00C9); + break; + case 4: + // ULTRA LOUD: + // Original - 36 dB - 30 dB IN1L_VOL1=00000 (-16.5 dB) + // +30dB input mixer gain deactivated + wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0100); + wm8994_write(codec, WM8994_INPUT_MIXER_3, 0x20); + // DRC Input: -7.5dB, Ouptut -6dB + // Above knee 1/8, Below knee 1/4 + // Max gain 36 / Min gain -12 + wm8994_write(codec, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec, WM8994_AIF1_DRC1_2, 0x0847); + wm8994_write(codec, WM8994_AIF1_DRC1_3, 0x001A); + wm8994_write(codec, WM8994_AIF1_DRC1_4, 0x00C9); + break; + default: + // make sure recording_preset is the default + recording_preset = 1; + // New Balanced: Original - 16.5 dB + // IN1L_VOL1=01101 (+27 dB) + // +30dB input mixer gain deactivated + wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x055D); + wm8994_write(codec, WM8994_INPUT_MIXER_3, 0x20); + // DRC Input: -18.5dB, Ouptut -9dB + // Above knee 1/8, Below knee 1/2 + // Max gain 18 / Min gain -12 + wm8994_write(codec, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec, WM8994_AIF1_DRC1_2, 0x0845); + wm8994_write(codec, WM8994_AIF1_DRC1_3, 0x0019); + wm8994_write(codec, WM8994_AIF1_DRC1_4, 0x030C); + break; } } #endif bool is_path(int unified_path) { - DECLARE_WM8994(codec_) + DECLARE_WM8994(codec); - switch(unified_path) - { + switch (unified_path) { // speaker - case SPEAKER: + case SPEAKER: #ifdef GALAXY_TAB - return (wm8994->cur_path == SPK || wm8994->cur_path == RING_SPK || - wm8994->fmradio_path == FMR_SPK || wm8994->fmradio_path == FMR_SPK_MIX); + return (wm8994->cur_path == SPK + || wm8994->cur_path == RING_SPK + || wm8994->fmradio_path == FMR_SPK + || wm8994->fmradio_path == FMR_SPK_MIX); #else - return (wm8994->cur_path == SPK || wm8994->cur_path == RING_SPK); + return (wm8994->cur_path == SPK + || wm8994->cur_path == RING_SPK); #endif // headphones // FIXME: be sure dac_direct doesn't break phone calls on TAB // with these spath detection settings (HP4P) - case HEADPHONES: + case HEADPHONES: #ifdef NEXUS_S - return (wm8994->cur_path == HP || wm8994->cur_path == HP_NO_MIC); + return (wm8994->cur_path == HP + || wm8994->cur_path == HP_NO_MIC); #else #ifdef GALAXY_TAB - return (wm8994->cur_path == HP3P || wm8994->cur_path == HP4P || wm8994->fmradio_path == FMR_HP); + return (wm8994->cur_path == HP3P + || wm8994->cur_path == HP4P + || wm8994->fmradio_path == FMR_HP); #else #ifdef M110S - return (wm8994->cur_path == HP); + return (wm8994->cur_path == HP); #else - return (wm8994->cur_path == HP || wm8994->fmradio_path == FMR_HP); + return (wm8994->cur_path == HP + || wm8994->fmradio_path == FMR_HP); #endif #endif #endif // FM Radio on headphones - case RADIO_HEADPHONES: + case RADIO_HEADPHONES: #ifdef NEXUS_S - return false; + return false; #else #ifdef M110S - return false; + return false; #else #ifdef GALAXY_TAB - return (wm8994->codec_state & FMRADIO_ACTIVE) && (wm8994->fmradio_path == FMR_HP); + return (wm8994->codec_state & FMRADIO_ACTIVE) + && (wm8994->fmradio_path == FMR_HP); #else - return (wm8994->codec_state & FMRADIO_ACTIVE) && (wm8994->fmradio_path == FMR_HP); + return (wm8994->codec_state & FMRADIO_ACTIVE) + && (wm8994->fmradio_path == FMR_HP); #endif #endif #endif - // headphones // FIXME: be sure dac_direct doesn't break phone calls on TAB // with these spath detection settings (HP4P) - case MAIN_MICROPHONE: - return (wm8994->codec_state & CAPTURE_ACTIVE) && (wm8994->rec_path == MAIN); + case MAIN_MICROPHONE: + return (wm8994->codec_state & CAPTURE_ACTIVE) + && (wm8994->rec_path == MAIN); } return false; @@ -369,66 +361,64 @@ bool is_path(int unified_path) #ifdef NEXUS_S void update_speaker_tuning(bool with_mute) { - DECLARE_WM8994(codec_) - if (is_path(SPEAKER) && !(wm8994->codec_state & CALL_ACTIVE)) - { - printk("We are on speaker!\n"); - if (speaker_tuning) - { - // DRC settings - wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0010); - wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x00EB); - - // hardware EQ - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_1, 0x041D); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_2, 0x4C00); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_A, 0x0FE3); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_B, 0x0403); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_PG, 0x0074); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_A, 0x1F03); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_B, 0xF0F9); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_C, 0x040A); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_PG, 0x03DA); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_A, 0x1ED2); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_B, 0xF11A); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_C, 0x040A); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_PG, 0x045D); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_A, 0x0E76); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_B, 0xFCE4); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_C, 0x040A); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_4_PG, 0x330D); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_A, 0xFC8F); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_B, 0x0400); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_5_PG, 0x323C); - - // Speaker Boost tuning - wm8994_write(codec_, WM8994_CLASSD, 0x0170); - } - else - { - // DRC settings - wm8994_write(codec_, WM8994_AIF1_DRC1_3, 0x0028); - wm8994_write(codec_, WM8994_AIF1_DRC1_4, 0x0186); - - // hardware EQ - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_1, 0x0019); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_GAINS_2, 0x6280); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_A, 0x0FC3); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_B, 0x03FD); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_1_PG, 0x00F4); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_A, 0x1F30); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_B, 0xF0CD); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_C, 0x040A); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_2_PG, 0x032C); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_A, 0x1C52); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_B, 0xF379); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_C, 0x040A); - wm8994_write(codec_, WM8994_AIF1_DAC1_EQ_BAND_3_PG, 0x0DC1); - wm8994_write(codec_, WM8994_CLASSD, 0x0170); - - // Speaker Boost tuning - wm8994_write(codec_, WM8994_CLASSD, 0x0168); - } + DECLARE_WM8994(codec); + + if (!(is_path(SPEAKER) || (wm8994->codec_state & CALL_ACTIVE))) + return; + + printk("We are on speaker!\n"); + if (speaker_tuning) { + // DRC settings + wm8994_write(codec, WM8994_AIF1_DRC1_3, 0x0010); + wm8994_write(codec, WM8994_AIF1_DRC1_4, 0x00EB); + + // hardware EQ + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_GAINS_1, 0x041D); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_GAINS_2, 0x4C00); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_1_A, 0x0FE3); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_1_B, 0x0403); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_1_PG, 0x0074); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_2_A, 0x1F03); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_2_B, 0xF0F9); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_2_C, 0x040A); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_2_PG, 0x03DA); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_3_A, 0x1ED2); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_3_B, 0xF11A); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_3_C, 0x040A); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_3_PG, 0x045D); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_4_A, 0x0E76); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_4_B, 0xFCE4); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_4_C, 0x040A); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_4_PG, 0x330D); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_5_A, 0xFC8F); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_5_B, 0x0400); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_5_PG, 0x323C); + + // Speaker Boost tuning + wm8994_write(codec, WM8994_CLASSD, 0x0170); + } else { + // DRC settings + wm8994_write(codec, WM8994_AIF1_DRC1_3, 0x0028); + wm8994_write(codec, WM8994_AIF1_DRC1_4, 0x0186); + + // hardware EQ + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_GAINS_1, 0x0019); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_GAINS_2, 0x6280); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_1_A, 0x0FC3); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_1_B, 0x03FD); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_1_PG, 0x00F4); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_2_A, 0x1F30); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_2_B, 0xF0CD); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_2_C, 0x040A); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_2_PG, 0x032C); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_3_A, 0x1C52); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_3_B, 0xF379); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_3_C, 0x040A); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_BAND_3_PG, 0x0DC1); + wm8994_write(codec, WM8994_CLASSD, 0x0170); + + // Speaker Boost tuning + wm8994_write(codec, WM8994_CLASSD, 0x0168); } } #endif @@ -444,15 +434,16 @@ unsigned short osr128_get_value(unsigned short val) val |= WM8994_ADC_OSR128; else val &= ~WM8994_ADC_OSR128; + return val; } void update_osr128(bool with_mute) { unsigned short val; - val = osr128_get_value(wm8994_read(codec_, WM8994_OVERSAMPLING)); + val = osr128_get_value(wm8994_read(codec, WM8994_OVERSAMPLING)); bypass_write_hook = true; - wm8994_write(codec_, WM8994_OVERSAMPLING, val); + wm8994_write(codec, WM8994_OVERSAMPLING, val); bypass_write_hook = false; } @@ -461,60 +452,65 @@ unsigned short fll_tuning_get_value(unsigned short val) val = (val >> WM8994_FLL1_GAIN_WIDTH << WM8994_FLL1_GAIN_WIDTH); if (fll_tuning == 1) val |= 5; + return val; } void update_fll_tuning(bool with_mute) { unsigned short val; - val = fll_tuning_get_value(wm8994_read(codec_, WM8994_FLL1_CONTROL_4)); + val = fll_tuning_get_value(wm8994_read(codec, WM8994_FLL1_CONTROL_4)); bypass_write_hook = true; - wm8994_write(codec_, WM8994_FLL1_CONTROL_4, val); + wm8994_write(codec, WM8994_FLL1_CONTROL_4, val); bypass_write_hook = false; } - unsigned short mono_downmix_get_value(unsigned short val) { // depends on the output path in order to preserve mono downmixing // on speaker - if (! is_path(SPEAKER)) - { + if (!is_path(SPEAKER)) { if (mono_downmix) val |= WM8994_AIF1DAC1_MONO; else val &= ~WM8994_AIF1DAC1_MONO; } + return val; } void update_mono_downmix(bool with_mute) { unsigned short val1, val2, val3; - val1 = mono_downmix_get_value(wm8994_read(codec_, WM8994_AIF1_DAC1_FILTERS_1)); - val2 = mono_downmix_get_value(wm8994_read(codec_, WM8994_AIF1_DAC2_FILTERS_1)); - val3 = mono_downmix_get_value(wm8994_read(codec_, WM8994_AIF2_DAC_FILTERS_1)); + val1 = mono_downmix_get_value(wm8994_read + (codec, WM8994_AIF1_DAC1_FILTERS_1)); + val2 = mono_downmix_get_value(wm8994_read + (codec, WM8994_AIF1_DAC2_FILTERS_1)); + val3 = mono_downmix_get_value(wm8994_read + (codec, WM8994_AIF2_DAC_FILTERS_1)); bypass_write_hook = true; - wm8994_write(codec_, WM8994_AIF1_DAC1_FILTERS_1, val1); - wm8994_write(codec_, WM8994_AIF1_DAC2_FILTERS_1, val2); - wm8994_write(codec_, WM8994_AIF2_DAC_FILTERS_1, val3); + wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, val1); + wm8994_write(codec, WM8994_AIF1_DAC2_FILTERS_1, val2); + wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, val3); bypass_write_hook = false; } unsigned short dac_direct_get_value(unsigned short val) { - DECLARE_WM8994(codec_) - - if (is_path(HEADPHONES) && - (wm8994->codec_state & PLAYBACK_ACTIVE) && - !(wm8994->codec_state & CALL_ACTIVE) && - !(wm8994->stream_state & PCM_STREAM_PLAYBACK)) - { - if (dac_direct) - val = (val == WM8994_DAC1L_TO_MIXOUTL) ? WM8994_DAC1L_TO_HPOUT1L : val; - else - val = (val == WM8994_DAC1L_TO_HPOUT1L) ? WM8994_DAC1L_TO_MIXOUTL : val; + DECLARE_WM8994(codec); + + if (is_path(HEADPHONES) + && (wm8994->codec_state & PLAYBACK_ACTIVE) + && !(wm8994->codec_state & CALL_ACTIVE) + && !(wm8994->stream_state & PCM_STREAM_PLAYBACK)) { + + if (dac_direct) { + if (val == WM8994_DAC1L_TO_MIXOUTL) + return WM8994_DAC1L_TO_HPOUT1L; + else if (val == WM8994_DAC1L_TO_HPOUT1L) + return WM8994_DAC1L_TO_MIXOUTL; + } } return val; @@ -523,33 +519,35 @@ unsigned short dac_direct_get_value(unsigned short val) void update_dac_direct(bool with_mute) { unsigned short val1, val2; - val1 = dac_direct_get_value(wm8994_read(codec_, WM8994_OUTPUT_MIXER_1)); - val2 = dac_direct_get_value(wm8994_read(codec_, WM8994_OUTPUT_MIXER_2)); + val1 = dac_direct_get_value(wm8994_read(codec, WM8994_OUTPUT_MIXER_1)); + val2 = dac_direct_get_value(wm8994_read(codec, WM8994_OUTPUT_MIXER_2)); bypass_write_hook = true; - wm8994_write(codec_, WM8994_OUTPUT_MIXER_1, val1); - wm8994_write(codec_, WM8994_OUTPUT_MIXER_2, val2); + wm8994_write(codec, WM8994_OUTPUT_MIXER_1, val1); + wm8994_write(codec, WM8994_OUTPUT_MIXER_2, val2); bypass_write_hook = false; } - /* * * Declaring the controling misc devices * */ #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL -static ssize_t headphone_amplifier_level_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t headphone_amplifier_level_show(struct device *dev, + struct device_attribute *attr, + char *buf) { // output median of left and right headphone amplifier volumes - return sprintf(buf,"%u\n", (hplvol + hprvol) / 2 ); + return sprintf(buf, "%u\n", (hplvol + hprvol) / 2); } -static ssize_t headphone_amplifier_level_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +static ssize_t headphone_amplifier_level_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) { unsigned short vol; - if (sscanf(buf, "%hu", &vol) == 1) - { + if (sscanf(buf, "%hu", &vol) == 1) { // left and right are set to the same volumes hplvol = hprvol = vol; update_hpvol(); @@ -559,33 +557,42 @@ static ssize_t headphone_amplifier_level_store(struct device *dev, struct device #endif #ifdef NEXUS_S -DECLARE_BOOL_SHOW(speaker_tuning) -DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(speaker_tuning, update_speaker_tuning, false) +DECLARE_BOOL_SHOW(speaker_tuning); +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(speaker_tuning, + update_speaker_tuning, + false); #endif #ifdef CONFIG_SND_VOODOO_FM -DECLARE_BOOL_SHOW(fm_radio_headset_restore_bass) -DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fm_radio_headset_restore_bass, update_fm_radio_headset_restore_freqs, true) - -DECLARE_BOOL_SHOW(fm_radio_headset_restore_highs) -DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fm_radio_headset_restore_highs, update_fm_radio_headset_restore_freqs, true) - -DECLARE_BOOL_SHOW(fm_radio_headset_normalize_gain) -DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fm_radio_headset_normalize_gain, update_fm_radio_headset_normalize_gain, false) +DECLARE_BOOL_SHOW(fm_radio_headset_restore_bass); +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fm_radio_headset_restore_bass, + update_fm_radio_headset_restore_freqs, + true); + +DECLARE_BOOL_SHOW(fm_radio_headset_restore_highs); +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fm_radio_headset_restore_highs, + update_fm_radio_headset_restore_freqs, + true); + +DECLARE_BOOL_SHOW(fm_radio_headset_normalize_gain); +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fm_radio_headset_normalize_gain, + update_fm_radio_headset_normalize_gain, + false); #endif - #ifdef CONFIG_SND_VOODOO_RECORD_PRESETS -static ssize_t recording_preset_show(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t recording_preset_show(struct device *dev, + struct device_attribute *attr, char *buf) { - return sprintf(buf,"%d\n", recording_preset); + return sprintf(buf, "%d\n", recording_preset); } -static ssize_t recording_preset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +static ssize_t recording_preset_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) { unsigned short preset_number; - if (sscanf(buf, "%hu", &preset_number) == 1) - { + if (sscanf(buf, "%hu", &preset_number) == 1) { recording_preset = preset_number; update_recording_preset(false); } @@ -593,113 +600,146 @@ static ssize_t recording_preset_store(struct device *dev, struct device_attribut } #endif +DECLARE_BOOL_SHOW(dac_osr128); +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(dac_osr128, + update_osr128, + false); -DECLARE_BOOL_SHOW(dac_osr128) -DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(dac_osr128, update_osr128, false) +DECLARE_BOOL_SHOW(adc_osr128); +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(adc_osr128, + update_osr128, + false); -DECLARE_BOOL_SHOW(adc_osr128) -DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(adc_osr128, update_osr128, false) +DECLARE_BOOL_SHOW(fll_tuning); +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fll_tuning, + update_fll_tuning, + false); -DECLARE_BOOL_SHOW(fll_tuning) -DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fll_tuning, update_fll_tuning, false) - -DECLARE_BOOL_SHOW(mono_downmix) -DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(mono_downmix, update_mono_downmix, false) - -DECLARE_BOOL_SHOW(dac_direct) -DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(dac_direct, update_dac_direct, false) +DECLARE_BOOL_SHOW(mono_downmix); +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(mono_downmix, + update_mono_downmix, + false); +DECLARE_BOOL_SHOW(dac_direct); +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(dac_direct, + update_dac_direct, + false); #ifdef CONFIG_SND_VOODOO_DEBUG -static ssize_t show_wm8994_register_dump(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_wm8994_register_dump(struct device *dev, + struct device_attribute *attr, + char *buf) { - // modified version of wm8994_register_dump from wm8994_aries.c - int wm8994_register; - - for(wm8994_register = 0; wm8994_register <= 0x6; wm8994_register++) - sprintf(buf, "0x%X 0x%X\n", wm8994_register, wm8994_read(codec_, wm8994_register)); - sprintf(buf, "%s0x%X 0x%X\n", buf, 0x15, wm8994_read(codec_, 0x15)); - for(wm8994_register = 0x18; wm8994_register <= 0x3C; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - sprintf(buf, "%s0x%X 0x%X\n", buf, 0x4C, wm8994_read(codec_, 0x4C)); - for(wm8994_register = 0x51; wm8994_register <= 0x5C; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - sprintf(buf, "%s0x%X 0x%X\n", buf, 0x60, wm8994_read(codec_, 0x60)); - sprintf(buf, "%s0x%X 0x%X\n", buf, 0x101, wm8994_read(codec_, 0x101)); - sprintf(buf, "%s0x%X 0x%X\n", buf, 0x110, wm8994_read(codec_, 0x110)); - sprintf(buf, "%s0x%X 0x%X\n", buf, 0x111, wm8994_read(codec_, 0x111)); - for(wm8994_register = 0x200; wm8994_register <= 0x212; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - for(wm8994_register = 0x220; wm8994_register <= 0x224; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - for(wm8994_register = 0x240; wm8994_register <= 0x244; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - for(wm8994_register = 0x300; wm8994_register <= 0x317; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - for(wm8994_register = 0x400; wm8994_register <= 0x411; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - for(wm8994_register = 0x420; wm8994_register <= 0x423; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - for(wm8994_register = 0x440; wm8994_register <= 0x444; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - for(wm8994_register = 0x450; wm8994_register <= 0x454; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - for(wm8994_register = 0x480; wm8994_register <= 0x493; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - for(wm8994_register = 0x4A0; wm8994_register <= 0x4B3; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - for(wm8994_register = 0x500; wm8994_register <= 0x503; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - sprintf(buf, "%s0x%X 0x%X\n", buf, 0x510, wm8994_read(codec_, 0x510)); - sprintf(buf, "%s0x%X 0x%X\n", buf, 0x520, wm8994_read(codec_, 0x520)); - sprintf(buf, "%s0x%X 0x%X\n", buf, 0x521, wm8994_read(codec_, 0x521)); - for(wm8994_register = 0x540; wm8994_register <= 0x544; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - for(wm8994_register = 0x580; wm8994_register <= 0x593; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - for(wm8994_register = 0x600; wm8994_register <= 0x614; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); - sprintf(buf, "%s0x%X 0x%X\n", buf, 0x620, wm8994_read(codec_, 0x620)); - sprintf(buf, "%s0x%X 0x%X\n", buf, 0x621, wm8994_read(codec_, 0x621)); - for(wm8994_register = 0x700; wm8994_register <= 0x70A; wm8994_register++) - sprintf(buf, "%s0x%X 0x%X\n", buf, wm8994_register, wm8994_read(codec_, wm8994_register)); + // modified version of register_dump from wm8994_aries.c + // r = wm8994 register + int r; + + for (r = 0; r <= 0x6; r++) + sprintf(buf, "0x%X 0x%X\n", r, wm8994_read(codec, r)); + + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x15, wm8994_read(codec, 0x15)); + + for (r = 0x18; r <= 0x3C; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x4C, wm8994_read(codec, 0x4C)); + + for (r = 0x51; r <= 0x5C; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x60, wm8994_read(codec, 0x60)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x101, wm8994_read(codec, 0x101)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x110, wm8994_read(codec, 0x110)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x111, wm8994_read(codec, 0x111)); + + for (r = 0x200; r <= 0x212; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + for (r = 0x220; r <= 0x224; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + for (r = 0x240; r <= 0x244; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + for (r = 0x300; r <= 0x317; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + for (r = 0x400; r <= 0x411; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + for (r = 0x420; r <= 0x423; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + for (r = 0x440; r <= 0x444; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + for (r = 0x450; r <= 0x454; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + for (r = 0x480; r <= 0x493; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + for (r = 0x4A0; r <= 0x4B3; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + for (r = 0x500; r <= 0x503; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x510, wm8994_read(codec, 0x510)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x520, wm8994_read(codec, 0x520)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x521, wm8994_read(codec, 0x521)); + + for (r = 0x540; r <= 0x544; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + for (r = 0x580; r <= 0x593; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + for (r = 0x600; r <= 0x614; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); + + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x620, wm8994_read(codec, 0x620)); + sprintf(buf, "%s0x%X 0x%X\n", buf, 0x621, wm8994_read(codec, 0x621)); + + for (r = 0x700; r <= 0x70A; r++) + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); return sprintf(buf, "%s", buf); } - -static ssize_t store_wm8994_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +static ssize_t store_wm8994_write(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) { short unsigned int reg = 0; short unsigned int val = 0; int unsigned bytes_read = 0; - while (sscanf(buf, "%hx %hx%n", ®, &val, &bytes_read) == 2) - { + while (sscanf(buf, "%hx %hx%n", ®, &val, &bytes_read) == 2) { buf += bytes_read; - wm8994_write(codec_, reg, val); + wm8994_write(codec, reg, val); } return size; } #endif - -static ssize_t voodoo_sound_version(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t voodoo_sound_version(struct device *dev, + struct device_attribute *attr, char *buf) +{ return sprintf(buf, "%u\n", VOODOO_SOUND_VERSION); } - #ifndef MODULE -DECLARE_BOOL_SHOW(enable) -static ssize_t enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) +DECLARE_BOOL_SHOW(enable); +static ssize_t enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t size) { unsigned short state; bool bool_state; - if (sscanf(buf, "%hu", &state) == 1) - { + if (sscanf(buf, "%hu", &state) == 1) { bool_state = state == 0 ? false : true; - if (state != enable) - { + if (state != enable) { enable = bool_state; update_enable(); } @@ -709,111 +749,156 @@ static ssize_t enable_store(struct device *dev, struct device_attribute *attr, c #endif #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL -static DEVICE_ATTR(headphone_amplifier_level, S_IRUGO | S_IWUGO , headphone_amplifier_level_show, headphone_amplifier_level_store); +static DEVICE_ATTR(headphone_amplifier_level, S_IRUGO | S_IWUGO, + headphone_amplifier_level_show, + headphone_amplifier_level_store); #endif + #ifdef NEXUS_S -static DEVICE_ATTR(speaker_tuning, S_IRUGO | S_IWUGO , speaker_tuning_show, speaker_tuning_store); +static DEVICE_ATTR(speaker_tuning, S_IRUGO | S_IWUGO, + speaker_tuning_show, + speaker_tuning_store); #endif + #ifdef CONFIG_SND_VOODOO_FM -static DEVICE_ATTR(fm_radio_headset_restore_bass, S_IRUGO | S_IWUGO , fm_radio_headset_restore_bass_show, fm_radio_headset_restore_bass_store); -static DEVICE_ATTR(fm_radio_headset_restore_highs, S_IRUGO | S_IWUGO , fm_radio_headset_restore_highs_show, fm_radio_headset_restore_highs_store); -static DEVICE_ATTR(fm_radio_headset_normalize_gain, S_IRUGO | S_IWUGO , fm_radio_headset_normalize_gain_show, fm_radio_headset_normalize_gain_store); +static DEVICE_ATTR(fm_radio_headset_restore_bass, S_IRUGO | S_IWUGO, + fm_radio_headset_restore_bass_show, + fm_radio_headset_restore_bass_store); + +static DEVICE_ATTR(fm_radio_headset_restore_highs, S_IRUGO | S_IWUGO, + fm_radio_headset_restore_highs_show, + fm_radio_headset_restore_highs_store); + +static DEVICE_ATTR(fm_radio_headset_normalize_gain, S_IRUGO | S_IWUGO, + fm_radio_headset_normalize_gain_show, + fm_radio_headset_normalize_gain_store); #endif + #ifdef CONFIG_SND_VOODOO_RECORD_PRESETS -static DEVICE_ATTR(recording_preset, S_IRUGO | S_IWUGO , recording_preset_show, recording_preset_store); +static DEVICE_ATTR(recording_preset, S_IRUGO | S_IWUGO, + recording_preset_show, + recording_preset_store); #endif -static DEVICE_ATTR(dac_osr128, S_IRUGO | S_IWUGO , dac_osr128_show, dac_osr128_store); -static DEVICE_ATTR(adc_osr128, S_IRUGO | S_IWUGO , adc_osr128_show, adc_osr128_store); -static DEVICE_ATTR(fll_tuning, S_IRUGO | S_IWUGO , fll_tuning_show, fll_tuning_store); -static DEVICE_ATTR(dac_direct, S_IRUGO | S_IWUGO , dac_direct_show, dac_direct_store); -static DEVICE_ATTR(mono_downmix, S_IRUGO | S_IWUGO , mono_downmix_show, mono_downmix_store); + +static DEVICE_ATTR(dac_osr128, S_IRUGO | S_IWUGO, + dac_osr128_show, + dac_osr128_store); + +static DEVICE_ATTR(adc_osr128, S_IRUGO | S_IWUGO, + adc_osr128_show, + adc_osr128_store); + +static DEVICE_ATTR(fll_tuning, S_IRUGO | S_IWUGO, + fll_tuning_show, + fll_tuning_store); + +static DEVICE_ATTR(dac_direct, S_IRUGO | S_IWUGO, + dac_direct_show, + dac_direct_store); + +static DEVICE_ATTR(mono_downmix, S_IRUGO | S_IWUGO, + mono_downmix_show, + mono_downmix_store); + #ifdef CONFIG_SND_VOODOO_DEBUG -static DEVICE_ATTR(wm8994_register_dump, S_IRUGO , show_wm8994_register_dump, NULL); -static DEVICE_ATTR(wm8994_write, S_IWUSR , NULL, store_wm8994_write); +static DEVICE_ATTR(wm8994_register_dump, S_IRUGO, + show_wm8994_register_dump, + NULL); + +static DEVICE_ATTR(wm8994_write, S_IWUSR, + NULL, + store_wm8994_write); #endif -static DEVICE_ATTR(version, S_IRUGO , voodoo_sound_version, NULL); + +static DEVICE_ATTR(version, S_IRUGO, + voodoo_sound_version, + NULL); #ifndef MODULE -static DEVICE_ATTR(enable, S_IRUGO | S_IWUGO , enable_show, enable_store); +static DEVICE_ATTR(enable, S_IRUGO | S_IWUGO, + enable_show, + enable_store); #endif static struct attribute *voodoo_sound_attributes[] = { #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL - &dev_attr_headphone_amplifier_level.attr, + &dev_attr_headphone_amplifier_level.attr, #endif #ifdef NEXUS_S - &dev_attr_speaker_tuning.attr, + &dev_attr_speaker_tuning.attr, #endif #ifdef CONFIG_SND_VOODOO_FM - &dev_attr_fm_radio_headset_restore_bass.attr, - &dev_attr_fm_radio_headset_restore_highs.attr, - &dev_attr_fm_radio_headset_normalize_gain.attr, + &dev_attr_fm_radio_headset_restore_bass.attr, + &dev_attr_fm_radio_headset_restore_highs.attr, + &dev_attr_fm_radio_headset_normalize_gain.attr, #endif #ifdef CONFIG_SND_VOODOO_RECORD_PRESETS - &dev_attr_recording_preset.attr, + &dev_attr_recording_preset.attr, #endif - &dev_attr_dac_osr128.attr, - &dev_attr_adc_osr128.attr, - &dev_attr_fll_tuning.attr, - &dev_attr_dac_direct.attr, - &dev_attr_mono_downmix.attr, + &dev_attr_dac_osr128.attr, + &dev_attr_adc_osr128.attr, + &dev_attr_fll_tuning.attr, + &dev_attr_dac_direct.attr, + &dev_attr_mono_downmix.attr, #ifdef CONFIG_SND_VOODOO_DEBUG - &dev_attr_wm8994_register_dump.attr, - &dev_attr_wm8994_write.attr, + &dev_attr_wm8994_register_dump.attr, + &dev_attr_wm8994_write.attr, #endif - &dev_attr_version.attr, - NULL + &dev_attr_version.attr, + NULL }; #ifndef MODULE static struct attribute *voodoo_sound_control_attributes[] = { - &dev_attr_enable.attr, - NULL + &dev_attr_enable.attr, + NULL }; #endif static struct attribute_group voodoo_sound_group = { - .attrs = voodoo_sound_attributes, + .attrs = voodoo_sound_attributes, }; #ifndef MODULE static struct attribute_group voodoo_sound_control_group = { - .attrs = voodoo_sound_control_attributes, + .attrs = voodoo_sound_control_attributes, }; #endif static struct miscdevice voodoo_sound_device = { - .minor = MISC_DYNAMIC_MINOR, - .name = "voodoo_sound", + .minor = MISC_DYNAMIC_MINOR, + .name = "voodoo_sound", }; #ifndef MODULE static struct miscdevice voodoo_sound_control_device = { - .minor = MISC_DYNAMIC_MINOR, - .name = "voodoo_sound_control", + .minor = MISC_DYNAMIC_MINOR, + .name = "voodoo_sound_control", }; #endif -void voodoo_hook_wm8994_pcm_remove() { +void voodoo_hook_wm8994_pcm_remove() +{ printk("Voodoo sound: removing driver v%d\n", VOODOO_SOUND_VERSION); - sysfs_remove_group(&voodoo_sound_device.this_device->kobj, &voodoo_sound_group); + sysfs_remove_group(&voodoo_sound_device.this_device->kobj, + &voodoo_sound_group); misc_deregister(&voodoo_sound_device); } - void update_enable() { - if (enable) - { - printk("Voodoo sound: initializing driver v%d\n", VOODOO_SOUND_VERSION); + if (enable) { + printk("Voodoo sound: initializing driver v%d\n", + VOODOO_SOUND_VERSION); + misc_register(&voodoo_sound_device); - if (sysfs_create_group(&voodoo_sound_device.this_device->kobj, &voodoo_sound_group) < 0) - { + if (sysfs_create_group(&voodoo_sound_device.this_device->kobj, + &voodoo_sound_group) < 0) { printk("%s sysfs_create_group fail\n", __FUNCTION__); - pr_err("Failed to create sysfs group for device (%s)!\n", voodoo_sound_device.name); + pr_err("Failed to create sysfs group for (%s)!\n", + voodoo_sound_device.name); } - } - else + } else voodoo_hook_wm8994_pcm_remove(); } @@ -827,10 +912,12 @@ void update_enable() void voodoo_hook_fmradio_headset() { // global kill switch - if (! enable) + if (!enable) return; - if (! fm_radio_headset_restore_bass && ! fm_radio_headset_restore_highs && !fm_radio_headset_normalize_gain) + if (!fm_radio_headset_restore_bass + && !fm_radio_headset_restore_highs + && !fm_radio_headset_normalize_gain) return; update_fm_radio_headset_restore_freqs(false); @@ -838,115 +925,133 @@ void voodoo_hook_fmradio_headset() } #endif - #ifdef CONFIG_SND_VOODOO_RECORD_PRESETS void voodoo_hook_record_main_mic() { // global kill switch - if (! enable) + if (!enable) return; if (recording_preset == 0) return; - original_record_gain = wm8994_read(codec_, WM8994_LEFT_LINE_INPUT_1_2_VOLUME); - original_record_gain_input_mixer = wm8994_read(codec_, WM8994_INPUT_MIXER_3); + origin_recgain = wm8994_read(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME); + origin_recgain_mixer = wm8994_read(codec, WM8994_INPUT_MIXER_3); update_recording_preset(false); } #endif - void voodoo_hook_playback_speaker() { // global kill switch - if (! enable) + if (!enable) return; #ifdef NEXUS_S - if (! speaker_tuning) + if (!speaker_tuning) return; update_speaker_tuning(false); #endif } - -unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) +unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec_, + unsigned int reg, unsigned int value) { - DECLARE_WM8994(codec) + DECLARE_WM8994(codec_); // global kill switch - if (! enable) + if (!enable) return value; // modify some registers before those being written to the codec // be sure our pointer to codec is up to date - codec_ = codec; + codec = codec_; - if (! bypass_write_hook) - { + if (!bypass_write_hook) { #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL - if (is_path(HEADPHONES) && !(wm8994->codec_state & CALL_ACTIVE)) - { + if (is_path(HEADPHONES) + && !(wm8994->codec_state & CALL_ACTIVE)) { + if (reg == WM8994_LEFT_OUTPUT_VOLUME) - value = (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | hplvol); + value = + (WM8994_HPOUT1_VU | + WM8994_HPOUT1L_MUTE_N | + hplvol); + if (reg == WM8994_RIGHT_OUTPUT_VOLUME) - value = (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | hprvol); + value = + (WM8994_HPOUT1_VU | + WM8994_HPOUT1R_MUTE_N | + hprvol); } #endif #ifdef CONFIG_SND_VOODOO_FM - if (is_path(RADIO_HEADPHONES)) - { - if (reg == WM8994_INPUT_MIXER_2 || reg == WM8994_AIF2_DRC_1 || reg == WM8994_ANALOGUE_HP_1) + if (is_path(RADIO_HEADPHONES)) { + if (reg == WM8994_INPUT_MIXER_2 + || reg == WM8994_AIF2_DRC_1 + || reg == WM8994_ANALOGUE_HP_1) voodoo_hook_fmradio_headset(); } #endif if (reg == WM8994_OVERSAMPLING) value = osr128_get_value(value); + if (reg == WM8994_FLL1_CONTROL_4) value = fll_tuning_get_value(value); - if (reg == WM8994_AIF1_DAC1_FILTERS_1 || reg == WM8994_AIF1_DAC2_FILTERS_1 || reg == WM8994_AIF2_DAC_FILTERS_1) + + if (reg == WM8994_AIF1_DAC1_FILTERS_1 + || reg == WM8994_AIF1_DAC2_FILTERS_1 + || reg == WM8994_AIF2_DAC_FILTERS_1) value = mono_downmix_get_value(value); - if (reg == WM8994_OUTPUT_MIXER_1 || reg == WM8994_OUTPUT_MIXER_2) + + if (reg == WM8994_OUTPUT_MIXER_1 + || reg == WM8994_OUTPUT_MIXER_2) value = dac_direct_get_value(value); } - #ifdef CONFIG_SND_VOODOO_DEBUG_LOG // log every write to dmesg - printk("Voodoo sound: wm8994_write register= [%X] value= [%X]\n", reg, value); + printk("Voodoo sound: wm8994_write register= [%X] value= [%X]\n", + reg, value); #ifdef NEXUS_S - printk("Voodoo sound: codec_state=%u, stream_state=%u, cur_path=%i, rec_path=%i, power_state=%i\n", - wm8994->codec_state, wm8994->stream_state, - wm8994->cur_path, wm8994->rec_path, wm8994->power_state); + printk("Voodoo sound: codec_state=%u, stream_state=%u, " + "cur_path=%i, rec_path=%i, " + "power_state=%i\n", + wm8994->codec_state, wm8994->stream_state, + wm8994->cur_path, wm8994->rec_path, wm8994->power_state); #else - printk("Voodoo sound: codec_state=%u, stream_state=%u, cur_path=%i, rec_path=%i, fmradio_path=%i, fmr_mix_path=%i, power_state=%i, recognition_active=%i, ringtone_active=%i\n", - wm8994->codec_state, wm8994->stream_state, - wm8994->cur_path, wm8994->rec_path, - wm8994->fmradio_path, wm8994->fmr_mix_path, - wm8994->power_state, - wm8994->recognition_active, wm8994->ringtone_active); + printk("Voodoo sound: codec_state=%u, stream_state=%u, " + "cur_path=%i, rec_path=%i, " + "fmradio_path=%i, fmr_mix_path=%i, " + "power_state=%i, " + "recognition_active=%i, ringtone_active=%i\n", + wm8994->codec_state, wm8994->stream_state, + wm8994->cur_path, wm8994->rec_path, + wm8994->fmradio_path, wm8994->fmr_mix_path, + wm8994->power_state, + wm8994->recognition_active, wm8994->ringtone_active); #endif #endif return value; } - -void voodoo_hook_wm8994_pcm_probe(struct snd_soc_codec *codec) +void voodoo_hook_wm8994_pcm_probe(struct snd_soc_codec *codec_) { enable = true; update_enable(); #ifndef MODULE misc_register(&voodoo_sound_control_device); - if (sysfs_create_group(&voodoo_sound_control_device.this_device->kobj, &voodoo_sound_control_group) < 0) - { + if (sysfs_create_group(&voodoo_sound_control_device.this_device->kobj, + &voodoo_sound_control_group) < 0) { printk("%s sysfs_create_group fail\n", __FUNCTION__); - pr_err("Failed to create sysfs group for device (%s)!\n", voodoo_sound_control_device.name); + pr_err("Failed to create sysfs group for device (%s)!\n", + voodoo_sound_control_device.name); } #endif // make a copy of the codec pointer - codec_ = codec; + codec = codec_; } diff --git a/sound/soc/codecs/wm8994_voodoo.h b/sound/soc/codecs/wm8994_voodoo.h index bb87c68f6ed..3cd7d4afd67 100644 --- a/sound/soc/codecs/wm8994_voodoo.h +++ b/sound/soc/codecs/wm8994_voodoo.h @@ -7,12 +7,15 @@ */ bool is_path(int unified_path); + +unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value); void voodoo_hook_fmradio_headset(void); -unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value); void voodoo_hook_wm8994_pcm_probe(struct snd_soc_codec *codec); void voodoo_hook_wm8994_pcm_remove(void); void voodoo_hook_record_main_mic(void); void voodoo_hook_playback_speaker(void); + void update_hpvol(void); void update_fm_radio_headset_restore_freqs(bool with_mute); void update_fm_radio_headset_normalize_gain(bool with_mute); @@ -23,6 +26,7 @@ void update_fll_tuning(bool with_mute); void update_mono_downmix(bool with_mute); void update_dac_direct(bool with_mute); void update_enable(void); + unsigned short tune_fll_value(unsigned short val); #ifdef CONFIG_MACH_HERRING From c66fbe8305d97ed8b4d0bff029d38ab57e09b05b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Mon, 25 Apr 2011 06:49:14 +0200 Subject: [PATCH 0454/4025] Voodoo sound: driver v8 - Fixes DAC direct not being applied in several situations - Fixes 1 channel only on Captivate headphone+mic calls - Add full support for Samsung Gingerbread kernels including complete FM radio tunings --- sound/soc/codecs/Kconfig.voodoo | 8 +- sound/soc/codecs/wm8994_voodoo.c | 201 +++++++++++++++++++++++-------- sound/soc/codecs/wm8994_voodoo.h | 37 +++--- 3 files changed, 177 insertions(+), 69 deletions(-) diff --git a/sound/soc/codecs/Kconfig.voodoo b/sound/soc/codecs/Kconfig.voodoo index 5f8514858d0..dfb3250e391 100644 --- a/sound/soc/codecs/Kconfig.voodoo +++ b/sound/soc/codecs/Kconfig.voodoo @@ -37,14 +37,12 @@ config SND_VOODOO_RECORD_PRESETS - Loud environment - concert config SND_VOODOO_FM - bool "FM radio: restore a normal frequency response" - depends on SND_VOODOO && SND_ARIES_SOC_WM8994 - default n if S5PC110_T959_BOARD=y || S5PC110_KEPLER_BOARD=y || S5PV210_VICTORY=y || M110S=y - default y + bool "FM radio: frequency response and levels optimizations" + depends on SND_VOODOO && ARIES_EUR + default n help Adds a control to enable or disable the high-pass filter on FM radio - config SND_VOODOO_MODULE tristate "Build also as module (incomplete)" depends on SND_VOODOO && m diff --git a/sound/soc/codecs/wm8994_voodoo.c b/sound/soc/codecs/wm8994_voodoo.c index 82709d43f4c..b10dd0be17c 100644 --- a/sound/soc/codecs/wm8994_voodoo.c +++ b/sound/soc/codecs/wm8994_voodoo.c @@ -13,16 +13,17 @@ #include #include #include +#include #include "wm8994_voodoo.h" #ifndef MODULE -#ifdef NEXUS_S +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) #include "wm8994_samsung.h" #else #include "wm8994.h" #endif #else -#ifdef NEXUS_S +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) #include "../wm8994_samsung.h" #else #include "../wm8994.h" @@ -30,7 +31,7 @@ #endif #define SUBJECT "wm8994_voodoo.c" -#define VOODOO_SOUND_VERSION 7 +#define VOODOO_SOUND_VERSION 8 #ifdef MODULE #include "tegrak_voodoo_sound.h" @@ -103,7 +104,7 @@ static ssize_t name##_store(struct device *dev, struct device_attribute *attr, \ return size; \ } -#ifdef NEXUS_S +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) #define DECLARE_WM8994(codec) struct wm8994_priv *wm8994 = codec->drvdata; #else #define DECLARE_WM8994(codec) struct wm8994_priv *wm8994 = codec->private_data; @@ -113,13 +114,15 @@ static ssize_t name##_store(struct device *dev, struct device_attribute *attr, \ void update_hpvol() { unsigned short val; + DECLARE_WM8994(codec); + + // don't affect headphone amplifier volume + // when not on heapdhones or if call is active + if (!is_path(HEADPHONES) + || (wm8994->codec_state & CALL_ACTIVE)) + return; bypass_write_hook = true; - // hard limit to 62 because 63 introduces distortions - if (hplvol > 62) - hplvol = 62; - if (hprvol > 62) - hprvol = 62; // we don't need the Volume Update flag when sending the first volume val = (WM8994_HPOUT1L_MUTE_N | hplvol); @@ -147,7 +150,11 @@ void update_fm_radio_headset_restore_freqs(bool with_mute) return; if (with_mute) { - wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, 0x236); + wm8994_write(codec, WM8994_AIF2_DAC_FILTERS_1, + WM8994_AIF2DAC_MUTE | + WM8994_AIF2DAC_MUTERATE | + WM8994_AIF2DAC_UNMUTE_RAMP | + WM8994_AIF2DAC_DEEMP_MASK); msleep(180); } @@ -157,7 +164,9 @@ void update_fm_radio_headset_restore_freqs(bool with_mute) wm8994_write(codec, WM8994_SIDETONE, 0x0000); // disable 4FS ultrasonic mode and // restore the hi-fi <4Hz hi pass filter - wm8994_write(codec, WM8994_AIF2_ADC_FILTERS, 0x1800); + wm8994_write(codec, WM8994_AIF2_ADC_FILTERS, + WM8994_AIF2ADCL_HPF | + WM8994_AIF2ADCR_HPF); } else { // default settings in GT-I9000 Froyo XXJPX kernel sources wm8994_write(codec, WM8994_SIDETONE, 0x01c0); @@ -234,11 +243,17 @@ void update_recording_preset(bool with_mute) // High sensitivy: // Original - 4.5 dB, IN1L_VOL1=10101 (+15 dB) wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0115); - wm8994_write(codec, WM8994_INPUT_MIXER_3, 0x30); + wm8994_write(codec, WM8994_INPUT_MIXER_3, + WM8994_IN1L_TO_MIXINL | + WM8994_IN1L_MIXINL_VOL); // DRC Input: -6dB, Ouptut -3.75dB // Above knee 1/8, Below knee 1/2 // Max gain 24 / Min gain -12 - wm8994_write(codec, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec, WM8994_AIF1_DRC1_1, + WM8994_AIF1DRC1_SIG_DET_MODE | + WM8994_AIF1DRC1_QR | + WM8994_AIF1DRC1_ANTICLIP | + WM8994_AIF1ADC1L_DRC_ENA); wm8994_write(codec, WM8994_AIF1_DRC1_2, 0x0426); wm8994_write(codec, WM8994_AIF1_DRC1_3, 0x0019); wm8994_write(codec, WM8994_AIF1_DRC1_4, 0x0105); @@ -247,11 +262,16 @@ void update_recording_preset(bool with_mute) // Concert new: IN1L_VOL1=10110 (+4.5 dB) // +30dB input mixer gain deactivated wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x010F); - wm8994_write(codec, WM8994_INPUT_MIXER_3, 0x20); + wm8994_write(codec, WM8994_INPUT_MIXER_3, + WM8994_IN1L_TO_MIXINL); // DRC Input: -4.5dB, Ouptut -6.75dB // Above knee 1/4, Below knee 1/2 // Max gain 24 / Min gain -12 - wm8994_write(codec, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec, WM8994_AIF1_DRC1_1, + WM8994_AIF1DRC1_SIG_DET_MODE | + WM8994_AIF1DRC1_QR | + WM8994_AIF1DRC1_ANTICLIP | + WM8994_AIF1ADC1L_DRC_ENA); wm8994_write(codec, WM8994_AIF1_DRC1_2, 0x0846); wm8994_write(codec, WM8994_AIF1_DRC1_3, 0x0011); wm8994_write(codec, WM8994_AIF1_DRC1_4, 0x00C9); @@ -261,11 +281,16 @@ void update_recording_preset(bool with_mute) // Original - 36 dB - 30 dB IN1L_VOL1=00000 (-16.5 dB) // +30dB input mixer gain deactivated wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x0100); - wm8994_write(codec, WM8994_INPUT_MIXER_3, 0x20); + wm8994_write(codec, WM8994_INPUT_MIXER_3, + WM8994_IN1L_TO_MIXINL); // DRC Input: -7.5dB, Ouptut -6dB // Above knee 1/8, Below knee 1/4 // Max gain 36 / Min gain -12 - wm8994_write(codec, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec, WM8994_AIF1_DRC1_1, + WM8994_AIF1DRC1_SIG_DET_MODE | + WM8994_AIF1DRC1_QR | + WM8994_AIF1DRC1_ANTICLIP | + WM8994_AIF1ADC1L_DRC_ENA); wm8994_write(codec, WM8994_AIF1_DRC1_2, 0x0847); wm8994_write(codec, WM8994_AIF1_DRC1_3, 0x001A); wm8994_write(codec, WM8994_AIF1_DRC1_4, 0x00C9); @@ -277,11 +302,16 @@ void update_recording_preset(bool with_mute) // IN1L_VOL1=01101 (+27 dB) // +30dB input mixer gain deactivated wm8994_write(codec, WM8994_LEFT_LINE_INPUT_1_2_VOLUME, 0x055D); - wm8994_write(codec, WM8994_INPUT_MIXER_3, 0x20); + wm8994_write(codec, WM8994_INPUT_MIXER_3, + WM8994_IN1L_TO_MIXINL); // DRC Input: -18.5dB, Ouptut -9dB // Above knee 1/8, Below knee 1/2 // Max gain 18 / Min gain -12 - wm8994_write(codec, WM8994_AIF1_DRC1_1, 0x009A); + wm8994_write(codec, WM8994_AIF1_DRC1_1, + WM8994_AIF1DRC1_SIG_DET_MODE | + WM8994_AIF1DRC1_QR | + WM8994_AIF1DRC1_ANTICLIP | + WM8994_AIF1ADC1L_DRC_ENA); wm8994_write(codec, WM8994_AIF1_DRC1_2, 0x0845); wm8994_write(codec, WM8994_AIF1_DRC1_3, 0x0019); wm8994_write(codec, WM8994_AIF1_DRC1_4, 0x030C); @@ -302,15 +332,21 @@ bool is_path(int unified_path) || wm8994->cur_path == RING_SPK || wm8994->fmradio_path == FMR_SPK || wm8994->fmradio_path == FMR_SPK_MIX); +#else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + return (wm8994->cur_path == SPK + || wm8994->cur_path == SPK_HP); #else return (wm8994->cur_path == SPK || wm8994->cur_path == RING_SPK); +#endif #endif // headphones // FIXME: be sure dac_direct doesn't break phone calls on TAB // with these spath detection settings (HP4P) case HEADPHONES: + #ifdef NEXUS_S return (wm8994->cur_path == HP || wm8994->cur_path == HP_NO_MIC); @@ -322,11 +358,17 @@ bool is_path(int unified_path) #else #ifdef M110S return (wm8994->cur_path == HP); +#else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + return (wm8994->cur_path == HP + || wm8994->cur_path == HP_NO_MIC + || wm8994->fmradio_path == FMR_HP); #else return (wm8994->cur_path == HP || wm8994->fmradio_path == FMR_HP); #endif #endif +#endif #endif // FM Radio on headphones @@ -366,7 +408,6 @@ void update_speaker_tuning(bool with_mute) if (!(is_path(SPEAKER) || (wm8994->codec_state & CALL_ACTIVE))) return; - printk("We are on speaker!\n"); if (speaker_tuning) { // DRC settings wm8994_write(codec, WM8994_AIF1_DRC1_3, 0x0010); @@ -465,15 +506,18 @@ void update_fll_tuning(bool with_mute) bypass_write_hook = false; } -unsigned short mono_downmix_get_value(unsigned short val) +unsigned short mono_downmix_get_value(unsigned short val, bool can_reverse) { - // depends on the output path in order to preserve mono downmixing - // on speaker - if (!is_path(SPEAKER)) { - if (mono_downmix) + DECLARE_WM8994(codec); + + // Takes care not switching to Stereo on speaker or during a call + if (!is_path(SPEAKER) && !(wm8994->codec_state & CALL_ACTIVE)) { + if (mono_downmix) { val |= WM8994_AIF1DAC1_MONO; - else - val &= ~WM8994_AIF1DAC1_MONO; + } else { + if (can_reverse) + val &= ~WM8994_AIF1DAC1_MONO; + } } return val; @@ -483,11 +527,14 @@ void update_mono_downmix(bool with_mute) { unsigned short val1, val2, val3; val1 = mono_downmix_get_value(wm8994_read - (codec, WM8994_AIF1_DAC1_FILTERS_1)); + (codec, WM8994_AIF1_DAC1_FILTERS_1), + true); val2 = mono_downmix_get_value(wm8994_read - (codec, WM8994_AIF1_DAC2_FILTERS_1)); + (codec, WM8994_AIF1_DAC2_FILTERS_1), + true); val3 = mono_downmix_get_value(wm8994_read - (codec, WM8994_AIF2_DAC_FILTERS_1)); + (codec, WM8994_AIF2_DAC_FILTERS_1), + true); bypass_write_hook = true; wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_1, val1); @@ -496,19 +543,22 @@ void update_mono_downmix(bool with_mute) bypass_write_hook = false; } -unsigned short dac_direct_get_value(unsigned short val) +unsigned short dac_direct_get_value(unsigned short val, bool can_reverse) { DECLARE_WM8994(codec); - if (is_path(HEADPHONES) - && (wm8994->codec_state & PLAYBACK_ACTIVE) - && !(wm8994->codec_state & CALL_ACTIVE) - && !(wm8994->stream_state & PCM_STREAM_PLAYBACK)) { + if ((is_path(HEADPHONES) + && (wm8994->codec_state & PLAYBACK_ACTIVE) + && (wm8994->stream_state & PCM_STREAM_PLAYBACK) + && !(wm8994->codec_state & CALL_ACTIVE)) + || is_path(RADIO_HEADPHONES)) { if (dac_direct) { if (val == WM8994_DAC1L_TO_MIXOUTL) return WM8994_DAC1L_TO_HPOUT1L; - else if (val == WM8994_DAC1L_TO_HPOUT1L) + } else { + if (val == WM8994_DAC1L_TO_HPOUT1L + && can_reverse) return WM8994_DAC1L_TO_MIXOUTL; } } @@ -519,8 +569,10 @@ unsigned short dac_direct_get_value(unsigned short val) void update_dac_direct(bool with_mute) { unsigned short val1, val2; - val1 = dac_direct_get_value(wm8994_read(codec, WM8994_OUTPUT_MIXER_1)); - val2 = dac_direct_get_value(wm8994_read(codec, WM8994_OUTPUT_MIXER_2)); + val1 = dac_direct_get_value(wm8994_read(codec, + WM8994_OUTPUT_MIXER_1), true); + val2 = dac_direct_get_value(wm8994_read(codec, + WM8994_OUTPUT_MIXER_2), true); bypass_write_hook = true; wm8994_write(codec, WM8994_OUTPUT_MIXER_1, val1); @@ -550,6 +602,12 @@ static ssize_t headphone_amplifier_level_store(struct device *dev, if (sscanf(buf, "%hu", &vol) == 1) { // left and right are set to the same volumes hplvol = hprvol = vol; + // hard limit to 62 because 63 introduces distortions + if (hplvol > 62) + hplvol = 62; + if (hprvol > 62) + hprvol = 62; + update_hpvol(); } return size; @@ -820,6 +878,12 @@ static DEVICE_ATTR(enable, S_IRUGO | S_IWUGO, enable_store); #endif +#ifdef MODULE +static DEVICE_ATTR(module, 0, + NULL, + NULL); +#endif + static struct attribute *voodoo_sound_attributes[] = { #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL &dev_attr_headphone_amplifier_level.attr, @@ -843,6 +907,9 @@ static struct attribute *voodoo_sound_attributes[] = { #ifdef CONFIG_SND_VOODOO_DEBUG &dev_attr_wm8994_register_dump.attr, &dev_attr_wm8994_write.attr, +#endif +#ifdef MODULE + &dev_attr_module.attr, #endif &dev_attr_version.attr, NULL @@ -941,18 +1008,18 @@ void voodoo_hook_record_main_mic() } #endif +#ifdef NEXUS_S void voodoo_hook_playback_speaker() { // global kill switch if (!enable) return; -#ifdef NEXUS_S if (!speaker_tuning) return; update_speaker_tuning(false); -#endif } +#endif unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec_, unsigned int reg, unsigned int value) @@ -988,6 +1055,15 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec_, #endif #ifdef CONFIG_SND_VOODOO_FM +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + // FM tuning virtual hook for Gingerbread + if (is_path(RADIO_HEADPHONES)) { + if (reg == WM8994_AIF2_DRC_1 + || reg == WM8994_AIF2_DAC_FILTERS_1) + voodoo_hook_fmradio_headset(); + } +#else + // FM tuning virtual hook for Froyo if (is_path(RADIO_HEADPHONES)) { if (reg == WM8994_INPUT_MIXER_2 || reg == WM8994_AIF2_DRC_1 @@ -995,44 +1071,75 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec_, voodoo_hook_fmradio_headset(); } #endif - +#endif + // global Oversampling tuning if (reg == WM8994_OVERSAMPLING) value = osr128_get_value(value); + // global Anti-Jitter tuning if (reg == WM8994_FLL1_CONTROL_4) value = fll_tuning_get_value(value); + // global Mono downmix tuning if (reg == WM8994_AIF1_DAC1_FILTERS_1 || reg == WM8994_AIF1_DAC2_FILTERS_1 || reg == WM8994_AIF2_DAC_FILTERS_1) - value = mono_downmix_get_value(value); + value = mono_downmix_get_value(value, false); + // DAC direct tuning virtual hook if (reg == WM8994_OUTPUT_MIXER_1 || reg == WM8994_OUTPUT_MIXER_2) - value = dac_direct_get_value(value); + value = dac_direct_get_value(value, false); + } #ifdef CONFIG_SND_VOODOO_DEBUG_LOG // log every write to dmesg - printk("Voodoo sound: wm8994_write register= [%X] value= [%X]\n", - reg, value); #ifdef NEXUS_S printk("Voodoo sound: codec_state=%u, stream_state=%u, " "cur_path=%i, rec_path=%i, " "power_state=%i\n", wm8994->codec_state, wm8994->stream_state, - wm8994->cur_path, wm8994->rec_path, wm8994->power_state); + wm8994->cur_path, wm8994->rec_path, + wm8994->power_state); #else - printk("Voodoo sound: codec_state=%u, stream_state=%u, " +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + printk("Voodoo sound: wm8994_write 0x%03X 0x%04X " + "codec_state=%u, stream_state=%u, " "cur_path=%i, rec_path=%i, " "fmradio_path=%i, fmr_mix_path=%i, " + "input_source=%i, output_source=%i, " + "power_state=%i\n", + reg, value, + wm8994->codec_state, wm8994->stream_state, + wm8994->fmradio_path, wm8994->fmr_mix_path, + wm8994->cur_path, wm8994->rec_path, + wm8994->input_source, wm8994->output_source, + wm8994->power_state); +#else + printk("Voodoo sound: wm8994_write 0x%03X 0x%04X " + "codec_state=%u, stream_state=%u, " + "cur_path=%i, rec_path=%i, " + "fmradio_path=%i, fmr_mix_path=%i, " +#ifdef CONFIG_S5PC110_KEPLER_BOARD + "call_record_path=%i, call_record_ch=%i, " + "AUDIENCE_state=%i, " + "Fac_SUB_MIC_state=%i, TTY_state=%i, " +#endif "power_state=%i, " "recognition_active=%i, ringtone_active=%i\n", + reg, value, wm8994->codec_state, wm8994->stream_state, wm8994->cur_path, wm8994->rec_path, wm8994->fmradio_path, wm8994->fmr_mix_path, +#ifdef CONFIG_S5PC110_KEPLER_BOARD + wm8994->call_record_path, wm8994->call_record_ch, + wm8994->AUDIENCE_state, + wm8994->Fac_SUB_MIC_state, wm8994->TTY_state, +#endif wm8994->power_state, wm8994->recognition_active, wm8994->ringtone_active); #endif +#endif #endif return value; } diff --git a/sound/soc/codecs/wm8994_voodoo.h b/sound/soc/codecs/wm8994_voodoo.h index 3cd7d4afd67..6e7d23ff581 100644 --- a/sound/soc/codecs/wm8994_voodoo.h +++ b/sound/soc/codecs/wm8994_voodoo.h @@ -6,8 +6,27 @@ * published by the Free Software Foundation. */ -bool is_path(int unified_path); +#if defined(CONFIG_MACH_HERRING) || defined (CONFIG_SAMSUNG_GALAXYS) \ + || defined (CONFIG_SAMSUNG_GALAXYSB) \ + || defined (CONFIG_SAMSUNG_CAPTIVATE) \ + || defined (CONFIG_SAMSUNG_VIBRANT) \ + || defined (CONFIG_SAMSUNG_FASCINATE) \ + || defined (CONFIG_SAMSUNG_EPIC) +#define NEXUS_S +#endif + +#ifdef CONFIG_FB_S3C_AMS701KA +#define GALAXY_TAB +#endif +#ifdef CONFIG_M110S +#define M110S +#endif + +enum unified_path { HEADPHONES, RADIO_HEADPHONES, SPEAKER, MAIN_MICROPHONE }; + +bool is_path(int unified_path); +unsigned short tune_fll_value(unsigned short val); unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value); void voodoo_hook_fmradio_headset(void); @@ -26,19 +45,3 @@ void update_fll_tuning(bool with_mute); void update_mono_downmix(bool with_mute); void update_dac_direct(bool with_mute); void update_enable(void); - -unsigned short tune_fll_value(unsigned short val); - -#ifdef CONFIG_MACH_HERRING -#define NEXUS_S -#endif - -#ifdef CONFIG_FB_S3C_AMS701KA -#define GALAXY_TAB -#endif - -#ifdef CONFIG_M110S -#define M110S -#endif - -enum unified_path { HEADPHONES, RADIO_HEADPHONES, SPEAKER, MAIN_MICROPHONE }; From c389bc2f675449785536543daabda9d5e0bcb305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Fri, 20 May 2011 08:43:01 +0200 Subject: [PATCH 0455/4025] Voodoo sound: driver v9 New features - advanced logging controllable via debug_log infos: 1, verbose: 2 - implements hardware EQ - implements hardware stereo expansion effect - new concept: digital_gain: makes room for effects with negative gains avoid saturation using hardware DRC as limiter act as compresser+limiter with positive gains (gain unit is mili-decibels, min -71625, max 36000) negative digital_gain are analog compensated if possible - super smooth headphone amp volume changes New supported device - Compatible with M110S Gingerbread kernel sources --- sound/soc/codecs/Kconfig.voodoo | 12 +- sound/soc/codecs/wm8994_voodoo.c | 790 +++++++++++++++++++++++++++---- sound/soc/codecs/wm8994_voodoo.h | 19 +- 3 files changed, 714 insertions(+), 107 deletions(-) diff --git a/sound/soc/codecs/Kconfig.voodoo b/sound/soc/codecs/Kconfig.voodoo index dfb3250e391..9d6882dc8b7 100644 --- a/sound/soc/codecs/Kconfig.voodoo +++ b/sound/soc/codecs/Kconfig.voodoo @@ -45,22 +45,16 @@ config SND_VOODOO_FM config SND_VOODOO_MODULE tristate "Build also as module (incomplete)" - depends on SND_VOODOO && m + depends on SND_VOODOO && m && n default n help requires additionnal source -config SND_VOODOO_DEBUG - bool "Codec development tools (unsafe and introduce sound skipping)" +config SND_VOODOO_DEVELOPMENT + bool "Codec development tools (unsafe)" depends on SND_VOODOO default n help Allow to codec dump registers and load register-address/value batchs Powerful but also dangerous tool -config SND_VOODOO_DEBUG_LOG - bool "Log every wm8994_write" - depends on SND_VOODOO_DEBUG - default n - help - Log codec writes diff --git a/sound/soc/codecs/wm8994_voodoo.c b/sound/soc/codecs/wm8994_voodoo.c index b10dd0be17c..1334a8944af 100644 --- a/sound/soc/codecs/wm8994_voodoo.c +++ b/sound/soc/codecs/wm8994_voodoo.c @@ -31,7 +31,6 @@ #endif #define SUBJECT "wm8994_voodoo.c" -#define VOODOO_SOUND_VERSION 8 #ifdef MODULE #include "tegrak_voodoo_sound.h" @@ -52,9 +51,11 @@ bool bypass_write_hook = false; +short unsigned int debug_log_level = LOG_OFF; + #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL -unsigned short hplvol = CONFIG_SND_VOODOO_HP_LEVEL; -unsigned short hprvol = CONFIG_SND_VOODOO_HP_LEVEL; +unsigned short hp_level[2] = { CONFIG_SND_VOODOO_HP_LEVEL, + CONFIG_SND_VOODOO_HP_LEVEL };; #endif #ifdef CONFIG_SND_VOODOO_FM @@ -82,26 +83,73 @@ bool fll_tuning = true; bool dac_direct = true; bool mono_downmix = false; +// equalizer + +// digital gain value in mili dB +int digital_gain = 0; + +bool headphone_eq = false; +short eq_gains[5] = { 0, 0, 0, 0, 0 }; +short eq_bands[5] = { 3, 4, 4, 4, 3 }; +char eq_band_coef_names[][2] = { "A", "B", "C", "PG" }; + +unsigned int eq_band_values[5][4] = { + {0x0FCA, 0x0400, 0x00D8}, + {0x1EB5, 0xF145, 0x0B75, 0x01C5}, + {0x1C58, 0xF373, 0x0A54, 0x0558}, + {0x168E, 0xF829, 0x07AD, 0x1103}, + {0x0564, 0x0559, 0x4000} +}; + +// 3D effect +bool stereo_expansion = false; +short unsigned int stereo_expansion_gain = 16; + // keep here a pointer to the codec structure struct snd_soc_codec *codec; -#define DECLARE_BOOL_SHOW(name) \ -static ssize_t name##_show(struct device *dev, \ -struct device_attribute *attr, char *buf) \ -{ \ - return sprintf(buf,"%u\n",(name ? 1 : 0)); \ +#define DECLARE_BOOL_SHOW(name) \ +static ssize_t name##_show(struct device *dev, \ +struct device_attribute *attr, char *buf) \ +{ \ + return sprintf(buf,"%u\n",(name ? 1 : 0)); \ } -#define DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(name, updater, with_mute) \ +#define DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(name, updater, with_mute) \ static ssize_t name##_store(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t size) \ -{ \ - unsigned short state; \ - if (sscanf(buf, "%hu", &state) == 1) { \ - name = state == 0 ? false : true; \ - updater(with_mute); \ - } \ - return size; \ + const char *buf, size_t size) \ +{ \ + unsigned short state; \ + if (sscanf(buf, "%hu", &state) == 1) { \ + name = state == 0 ? false : true; \ + if (debug_log(LOG_INFOS)) \ + printk("Voodoo sound: %s: %u\n", #updater, state); \ + updater(with_mute); \ + } \ + return size; \ +} + +#define DECLARE_EQ_GAIN_SHOW(band) \ +static ssize_t headphone_eq_b##band##_gain_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return sprintf(buf, "%d\n", eq_gains[band-1]); \ +} + +#define DECLARE_EQ_GAIN_STORE(band) \ +static ssize_t headphone_eq_b##band##_gain_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t size) \ +{ \ + short new_gain; \ + if (sscanf(buf, "%hd", &new_gain) == 1) { \ + if (new_gain >= -12 && new_gain <= 12) { \ + eq_gains[band-1] = new_gain; \ + update_headphone_eq(false); \ + } \ + } \ + return size; \ } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) @@ -110,30 +158,112 @@ static ssize_t name##_store(struct device *dev, struct device_attribute *attr, \ #define DECLARE_WM8994(codec) struct wm8994_priv *wm8994 = codec->private_data; #endif +bool debug_log(short unsigned int level) +{ + if (debug_log_level >= level) + return true; + + return false; +} + #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL -void update_hpvol() +int hpvol(int channel) +{ + int vol; + + vol = hp_level[channel]; + + if (is_path_media_or_fm_no_call_no_record()) { + // negative digital gain compensation + if (digital_gain < 0) + vol = (vol - ((digital_gain / 100) + 5) / 10); + + if (vol > 62) + return 62; + } + + return vol; +} + +void write_hpvol(unsigned short l, unsigned short r) +{ + unsigned short val; + + // we don't need the Volume Update flag when sending the first volume + val = (WM8994_HPOUT1L_MUTE_N | l); + val |= WM8994_HPOUT1L_ZC; + wm8994_write(codec, WM8994_LEFT_OUTPUT_VOLUME, val); + + // this time we write the right volume plus the Volume Update flag. + // This way, both volume are set at the same time + val = (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | r); + val |= WM8994_HPOUT1L_ZC; + wm8994_write(codec, WM8994_RIGHT_OUTPUT_VOLUME, val); +} + +void update_hpvol(bool with_fade) { unsigned short val; + unsigned short i; + short steps; + unsigned short hp_level_old[2]; + unsigned short hp_level_registers[2] = { WM8994_LEFT_OUTPUT_VOLUME, + WM8994_RIGHT_OUTPUT_VOLUME }; + DECLARE_WM8994(codec); // don't affect headphone amplifier volume // when not on heapdhones or if call is active if (!is_path(HEADPHONES) || (wm8994->codec_state & CALL_ACTIVE)) - return; + return; bypass_write_hook = true; - // we don't need the Volume Update flag when sending the first volume - val = (WM8994_HPOUT1L_MUTE_N | hplvol); - val |= WM8994_HPOUT1L_ZC; - wm8994_write(codec, WM8994_LEFT_OUTPUT_VOLUME, val); + if (!with_fade) { + write_hpvol(hpvol(0), hpvol(1)); + bypass_write_hook = false; + return; + } + + // read previous levels + for (i = 0; i < 2; i++) { + val = wm8994_read(codec, hp_level_registers[i]); + val &= ~(WM8994_HPOUT1_VU_MASK); + val &= ~(WM8994_HPOUT1L_ZC_MASK); + val &= ~(WM8994_HPOUT1L_MUTE_N_MASK); + hp_level_old[i] = val + (digital_gain / 1000); + + if (debug_log(LOG_INFOS)) + printk("Voodoo sound: previous hp_level[%hu]: %hu\n", + i, val); + } + + // calculate number of steps for volume fade + steps = hp_level[0] - hp_level_old[0]; + if (debug_log(LOG_INFOS)) + printk("Voodoo sound: volume change steps: %hd " + "start: %hu, end: %hu\n", + steps, + hp_level_old[0], + hp_level[0]); + + while (steps != 0) { + if (hp_level[0] < hp_level_old[0]) + steps++; + else + steps--; + + if (debug_log(LOG_INFOS)) + printk("Voodoo sound: volume: %hu\n", + (hpvol(0) - steps)); + + write_hpvol(hpvol(0) - steps, hpvol(1) - steps); + + if (steps != 0) + udelay(1000); + } - // this time we write the right volume plus the Volume Update flag. - //This way, both volume are set at the same time - val = (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | hprvol); - val |= WM8994_HPOUT1L_ZC; - wm8994_write(codec, WM8994_RIGHT_OUTPUT_VOLUME, val); bypass_write_hook = false; } #endif @@ -325,7 +455,7 @@ bool is_path(int unified_path) DECLARE_WM8994(codec); switch (unified_path) { - // speaker + // speaker case SPEAKER: #ifdef GALAXY_TAB return (wm8994->cur_path == SPK @@ -342,9 +472,7 @@ bool is_path(int unified_path) #endif #endif - // headphones - // FIXME: be sure dac_direct doesn't break phone calls on TAB - // with these spath detection settings (HP4P) + // headphones case HEADPHONES: #ifdef NEXUS_S @@ -362,7 +490,10 @@ bool is_path(int unified_path) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) return (wm8994->cur_path == HP || wm8994->cur_path == HP_NO_MIC - || wm8994->fmradio_path == FMR_HP); +#ifndef M110S + || wm8994->fmradio_path == FMR_HP +#endif + ); #else return (wm8994->cur_path == HP || wm8994->fmradio_path == FMR_HP); @@ -371,7 +502,7 @@ bool is_path(int unified_path) #endif #endif - // FM Radio on headphones + // FM Radio on headphones case RADIO_HEADPHONES: #ifdef NEXUS_S return false; @@ -389,17 +520,32 @@ bool is_path(int unified_path) #endif #endif - // headphones - // FIXME: be sure dac_direct doesn't break phone calls on TAB - // with these spath detection settings (HP4P) + // Standard recording presets + // for M110S Gingerbread: added check non call case MAIN_MICROPHONE: return (wm8994->codec_state & CAPTURE_ACTIVE) - && (wm8994->rec_path == MAIN); + && (wm8994->rec_path == MAIN) + && !(wm8994->codec_state & CALL_ACTIVE); } return false; } +bool is_path_media_or_fm_no_call_no_record() { + + DECLARE_WM8994(codec); + + if ((is_path(HEADPHONES) + && (wm8994->codec_state & PLAYBACK_ACTIVE) + && (wm8994->stream_state & PCM_STREAM_PLAYBACK) + && !(wm8994->codec_state & CALL_ACTIVE) + && (wm8994->rec_path == MIC_OFF) + ) || is_path(RADIO_HEADPHONES)) + return true; + + return false; +} + #ifdef NEXUS_S void update_speaker_tuning(bool with_mute) { @@ -545,13 +691,7 @@ void update_mono_downmix(bool with_mute) unsigned short dac_direct_get_value(unsigned short val, bool can_reverse) { - DECLARE_WM8994(codec); - - if ((is_path(HEADPHONES) - && (wm8994->codec_state & PLAYBACK_ACTIVE) - && (wm8994->stream_state & PCM_STREAM_PLAYBACK) - && !(wm8994->codec_state & CALL_ACTIVE)) - || is_path(RADIO_HEADPHONES)) { + if (is_path_media_or_fm_no_call_no_record()) { if (dac_direct) { if (val == WM8994_DAC1L_TO_MIXOUTL) @@ -580,18 +720,225 @@ void update_dac_direct(bool with_mute) bypass_write_hook = false; } +unsigned short digital_gain_get_value(unsigned short val) +{ + // AIF gain to 0dB + int aif_gain = 0xC0; + int i; + int step = -375; + + if (is_path_media_or_fm_no_call_no_record()) { + + if (digital_gain <= 0) { + // clear the actual DAC volume for this value + val &= ~(WM8994_DAC1R_VOL_MASK); + + // calculation with round + i = ((digital_gain * 10 / step) + 5) / 10; + aif_gain -= i; + val |= aif_gain; + + if (debug_log(LOG_INFOS)) + printk("Voodoo sound: digital gain: %d mdB, " + "steps: %d, real AIF gain: %d mdB\n", + digital_gain, i, i * step); + } + } + + return val; +} + +void update_digital_gain(bool with_mute) +{ + unsigned short val1, val2; + val1 = digital_gain_get_value(wm8994_read(codec, + WM8994_AIF1_DAC1_LEFT_VOLUME)); + val2 = digital_gain_get_value(wm8994_read(codec, + WM8994_AIF1_DAC1_RIGHT_VOLUME)); + + bypass_write_hook = true; + wm8994_write(codec, WM8994_AIF1_DAC1_LEFT_VOLUME, + WM8994_DAC1_VU | val1); + wm8994_write(codec, WM8994_AIF1_DAC1_RIGHT_VOLUME, + WM8994_DAC1_VU | val2); + bypass_write_hook = false; +} + +void update_headphone_eq(bool with_mute) +{ + int gains_1; + int gains_2; + int i; + int j; + int k = 0; + int first_reg = WM8994_AIF1_DAC1_EQ_BAND_1_A; + + if (!is_path_media_or_fm_no_call_no_record()) { + // don't apply the EQ + return; + } + + if (debug_log(LOG_INFOS)) + printk("Voodoo sound: EQ gains (dB): %hd, %hd, %hd, %hd, %hd\n", + eq_gains[0], eq_gains[1], eq_gains[2], + eq_gains[3], eq_gains[4]); + + gains_1 = + ((eq_gains[0] + 12) << WM8994_AIF1DAC1_EQ_B1_GAIN_SHIFT) | + ((eq_gains[1] + 12) << WM8994_AIF1DAC1_EQ_B2_GAIN_SHIFT) | + ((eq_gains[2] + 12) << WM8994_AIF1DAC1_EQ_B3_GAIN_SHIFT) | + headphone_eq; + + gains_2 = + ((eq_gains[3] + 12) << WM8994_AIF1DAC1_EQ_B4_GAIN_SHIFT) | + ((eq_gains[4] + 12) << WM8994_AIF1DAC1_EQ_B5_GAIN_SHIFT); + + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_GAINS_1, gains_1); + wm8994_write(codec, WM8994_AIF1_DAC1_EQ_GAINS_2, gains_2); + + // don't send EQ configuration if its not enabled + if (!headphone_eq) + return; + + for (i = 0; i < ARRAY_SIZE(eq_band_values); i++) { + if (debug_log(LOG_INFOS)) + printk("Voodoo sound: send EQ Band %d\n", i + 1); + + for (j = 0; j < eq_bands[i]; j++) { + wm8994_write(codec, + first_reg + k, eq_band_values[i][j]); + k++; + } + } +} + +void update_stereo_expansion(bool with_mute) +{ + short unsigned int val; + + val = wm8994_read(codec, WM8994_AIF1_DAC1_FILTERS_2); + if (stereo_expansion) { + val &= ~(WM8994_AIF1DAC1_3D_GAIN_MASK); + val |= (stereo_expansion_gain << WM8994_AIF1DAC1_3D_GAIN_SHIFT); + } + val &= ~(WM8994_AIF1DAC1_3D_ENA_MASK); + val |= (stereo_expansion << WM8994_AIF1DAC1_3D_ENA_SHIFT); + + wm8994_write(codec, WM8994_AIF1_DAC1_FILTERS_2, val); +} + +void load_current_eq_values() +{ + int i; + int j; + int k = 0; + int first_reg = WM8994_AIF1_DAC1_EQ_BAND_1_A; + + for (i = 0; i < ARRAY_SIZE(eq_band_values); i++) + for (j = 0; j < eq_bands[i]; j++) { + eq_band_values[i][j] = + wm8994_read(codec, first_reg + k); + k++; + } +} + +void apply_saturation_prevention_drc() +{ + unsigned short val; + unsigned short drc_gain = 0; + int i; + int step = 750; + + // don't apply the limiter if not playing media + // (exclude FM radio, it has its own DRC settings) + if (!is_path_media_or_fm_no_call_no_record() + || is_path(RADIO_HEADPHONES)) + return; + + // don't apply the limiter without stereo_expansion or headphone_eq + // or a positive digital gain + if (!(stereo_expansion + || headphone_eq + || digital_gain >= 0)) + return; + + // configure the DRC to avoid saturation: not actually compress signal + // gain is unmodified. Should affect only what's higher than 0 dBFS + + // tune Attack & Decacy values + val = wm8994_read(codec, WM8994_AIF1_DRC1_2); + val &= ~(WM8994_AIF1DRC1_ATK_MASK); + val &= ~(WM8994_AIF1DRC1_DCY_MASK); + val |= (0x1 << WM8994_AIF1DRC1_ATK_SHIFT); + val |= (0x4 << WM8994_AIF1DRC1_DCY_SHIFT); + + // set DRC maximum gain to 36 dB + val &= ~(WM8994_AIF1DRC1_MAXGAIN_MASK); + val |= (0x3 << WM8994_AIF1DRC1_MAXGAIN_SHIFT); + + wm8994_write(codec, WM8994_AIF1_DRC1_2, val); + + // Above knee: flat (what really avoid the saturation) + val = wm8994_read(codec, WM8994_AIF1_DRC1_3); + val |= (0x5 << WM8994_AIF1DRC1_HI_COMP_SHIFT); + wm8994_write(codec, WM8994_AIF1_DRC1_3, val); + + val = wm8994_read(codec, WM8994_AIF1_DRC1_1); + // disable Quick Release and Anti Clip + // both do do more harm than good for this particular usage + val &= ~(WM8994_AIF1DRC1_QR_MASK); + val &= ~(WM8994_AIF1DRC1_ANTICLIP_MASK); + + // enable DRC + val &= ~(WM8994_AIF1DAC1_DRC_ENA_MASK); + val |= WM8994_AIF1DAC1_DRC_ENA; + wm8994_write(codec, WM8994_AIF1_DRC1_1, val); + + val = wm8994_read(codec, WM8994_AIF1_DRC1_4); + val &= ~(WM8994_AIF1DRC1_KNEE_IP_MASK); + + if (digital_gain >= 0) { + // deal with positive digital gains + i = ((digital_gain * 10 / step) + 5) / 10; + drc_gain += i; + val |= (drc_gain << WM8994_AIF1DRC1_KNEE_IP_SHIFT); + + if (debug_log(LOG_INFOS)) + printk("Voodoo sound: digital gain: %d mdB, " + "steps: %d, real DRC gain: %d mdB\n", + digital_gain, i, i * step); + + } + wm8994_write(codec, WM8994_AIF1_DRC1_4, val); +} + /* * * Declaring the controling misc devices * */ +static ssize_t debug_log_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", debug_log_level); +} + +static ssize_t debug_log_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + sscanf(buf, "%hu", &debug_log_level); + return size; +} + #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL static ssize_t headphone_amplifier_level_show(struct device *dev, struct device_attribute *attr, char *buf) { // output median of left and right headphone amplifier volumes - return sprintf(buf, "%u\n", (hplvol + hprvol) / 2); + return sprintf(buf, "%u\n", (hp_level[0] + hp_level[1]) / 2); } static ssize_t headphone_amplifier_level_store(struct device *dev, @@ -600,15 +947,16 @@ static ssize_t headphone_amplifier_level_store(struct device *dev, { unsigned short vol; if (sscanf(buf, "%hu", &vol) == 1) { - // left and right are set to the same volumes - hplvol = hprvol = vol; + // hard limit to 62 because 63 introduces distortions - if (hplvol > 62) - hplvol = 62; - if (hprvol > 62) - hprvol = 62; + if (vol > 62) + vol = 62; + + // left and right are set to the same volumes by this control + hp_level[0] = hp_level[1] = vol; - update_hpvol(); + update_digital_gain(false); + update_hpvol(true); } return size; } @@ -683,7 +1031,153 @@ DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(dac_direct, update_dac_direct, false); -#ifdef CONFIG_SND_VOODOO_DEBUG +static ssize_t digital_gain_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", digital_gain); +} + +static ssize_t digital_gain_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int new_digital_gain; + if (sscanf(buf, "%d", &new_digital_gain) == 1) { + if (new_digital_gain <= 36000 && new_digital_gain >= -71625) { + if (new_digital_gain > digital_gain) { + // reduce analog volume first + digital_gain = new_digital_gain; +#ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL + update_hpvol(false); +#endif + update_digital_gain(false); + } else { + // reduce digital volume first + digital_gain = new_digital_gain; + update_digital_gain(false); +#ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL + update_hpvol(false); +#endif + } + } + apply_saturation_prevention_drc(); + } + return size; +} + +DECLARE_BOOL_SHOW(headphone_eq); +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(headphone_eq, + update_headphone_eq, + false); + +DECLARE_EQ_GAIN_SHOW(1); +DECLARE_EQ_GAIN_STORE(1); +DECLARE_EQ_GAIN_SHOW(2); +DECLARE_EQ_GAIN_STORE(2); +DECLARE_EQ_GAIN_SHOW(3); +DECLARE_EQ_GAIN_STORE(3); +DECLARE_EQ_GAIN_SHOW(4); +DECLARE_EQ_GAIN_STORE(4); +DECLARE_EQ_GAIN_SHOW(5); +DECLARE_EQ_GAIN_STORE(5); + +static ssize_t headphone_eq_bands_values_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int i; + int j; + int k = 0; + int first_reg = WM8994_AIF1_DAC1_EQ_BAND_1_A; + int bands_size = ARRAY_SIZE(eq_bands); + char *name; + + for (i = 0; i < bands_size; i++) + for (j = 0; j < eq_bands[i]; j++) { + + // display 3-coef bands properly (hi & lo shelf) + if (j + 1 == eq_bands[i]) + name = eq_band_coef_names[3]; + else + name = eq_band_coef_names[j]; + + sprintf(buf, "%s%d %s 0x%04X\n", buf, + i + 1, name, + wm8994_read(codec, first_reg + k)); + k++; + } + + return sprintf(buf, "%s", buf); +} + +static ssize_t headphone_eq_bands_values_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int i; + short unsigned int val; + short unsigned int band; + char coef_name[2]; + unsigned int bytes_read = 0; + + while (sscanf(buf, "%hu %s %hx%n", + &band, coef_name, &val, &bytes_read) == 3) { + + buf += bytes_read; + + if (band < 1 || band > 5) + continue; + + for (i = 0; i < ARRAY_SIZE(eq_band_coef_names); i++) { + // loop through band coefficient letters + if (strncmp(eq_band_coef_names[i], coef_name, 2) == 0) { + if (eq_bands[band-1] == 3 && i == 3) + // deal with high and low shelves + eq_band_values[band-1][2] = val; + else + // parametric bands + eq_band_values[band-1][i] = val; + + if (debug_log(LOG_INFOS)) + printk("Voodoo sound: read EQ from " + "sysfs: EQ Band %hd %s: 0x%04X\n" + , band, coef_name, val); + break; + } + } + } + + return size; +} + +DECLARE_BOOL_SHOW(stereo_expansion); +DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(stereo_expansion, + update_stereo_expansion, + false); + +static ssize_t stereo_expansion_gain_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%u\n", stereo_expansion_gain); +} + +static ssize_t stereo_expansion_gain_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + short unsigned val; + + if (sscanf(buf, "%hu", &val) == 1) + if (val >= 0 && val < 32) { + stereo_expansion_gain = val; + update_stereo_expansion(false); + } + + return size; +} + +#ifdef CONFIG_SND_VOODOO_DEVELOPMENT static ssize_t show_wm8994_register_dump(struct device *dev, struct device_attribute *attr, char *buf) @@ -775,7 +1269,13 @@ static ssize_t store_wm8994_write(struct device *dev, while (sscanf(buf, "%hx %hx%n", ®, &val, &bytes_read) == 2) { buf += bytes_read; + if (debug_log(LOG_INFOS)); + printk("Voodoo sound: read from sysfs: %X, %X\n", + reg, val); + + bypass_write_hook = true; wm8994_write(codec, reg, val); + bypass_write_hook = false; } return size; } @@ -806,6 +1306,10 @@ static ssize_t enable_store(struct device *dev, } #endif +static DEVICE_ATTR(debug_log, S_IRUGO | S_IWUGO, + debug_log_show, + debug_log_store); + #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL static DEVICE_ATTR(headphone_amplifier_level, S_IRUGO | S_IWUGO, headphone_amplifier_level_show, @@ -854,11 +1358,51 @@ static DEVICE_ATTR(dac_direct, S_IRUGO | S_IWUGO, dac_direct_show, dac_direct_store); +static DEVICE_ATTR(digital_gain, S_IRUGO | S_IWUGO, + digital_gain_show, + digital_gain_store); + +static DEVICE_ATTR(headphone_eq, S_IRUGO | S_IWUGO, + headphone_eq_show, + headphone_eq_store); + +static DEVICE_ATTR(headphone_eq_b1_gain, S_IRUGO | S_IWUGO, + headphone_eq_b1_gain_show, + headphone_eq_b1_gain_store); + +static DEVICE_ATTR(headphone_eq_b2_gain, S_IRUGO | S_IWUGO, + headphone_eq_b2_gain_show, + headphone_eq_b2_gain_store); + +static DEVICE_ATTR(headphone_eq_b3_gain, S_IRUGO | S_IWUGO, + headphone_eq_b3_gain_show, + headphone_eq_b3_gain_store); + +static DEVICE_ATTR(headphone_eq_b4_gain, S_IRUGO | S_IWUGO, + headphone_eq_b4_gain_show, + headphone_eq_b4_gain_store); + +static DEVICE_ATTR(headphone_eq_b5_gain, S_IRUGO | S_IWUGO, + headphone_eq_b5_gain_show, + headphone_eq_b5_gain_store); + +static DEVICE_ATTR(headphone_eq_bands_values, S_IRUGO | S_IWUGO, + headphone_eq_bands_values_show, + headphone_eq_bands_values_store); + +static DEVICE_ATTR(stereo_expansion, S_IRUGO | S_IWUGO, + stereo_expansion_show, + stereo_expansion_store); + +static DEVICE_ATTR(stereo_expansion_gain, S_IRUGO | S_IWUGO, + stereo_expansion_gain_show, + stereo_expansion_gain_store); + static DEVICE_ATTR(mono_downmix, S_IRUGO | S_IWUGO, mono_downmix_show, mono_downmix_store); -#ifdef CONFIG_SND_VOODOO_DEBUG +#ifdef CONFIG_SND_VOODOO_DEVELOPMENT static DEVICE_ATTR(wm8994_register_dump, S_IRUGO, show_wm8994_register_dump, NULL); @@ -885,6 +1429,7 @@ static DEVICE_ATTR(module, 0, #endif static struct attribute *voodoo_sound_attributes[] = { + &dev_attr_debug_log.attr, #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL &dev_attr_headphone_amplifier_level.attr, #endif @@ -903,8 +1448,18 @@ static struct attribute *voodoo_sound_attributes[] = { &dev_attr_adc_osr128.attr, &dev_attr_fll_tuning.attr, &dev_attr_dac_direct.attr, + &dev_attr_digital_gain.attr, + &dev_attr_headphone_eq.attr, + &dev_attr_headphone_eq_b1_gain.attr, + &dev_attr_headphone_eq_b2_gain.attr, + &dev_attr_headphone_eq_b3_gain.attr, + &dev_attr_headphone_eq_b4_gain.attr, + &dev_attr_headphone_eq_b5_gain.attr, + &dev_attr_headphone_eq_bands_values.attr, + &dev_attr_stereo_expansion.attr, + &dev_attr_stereo_expansion_gain.attr, &dev_attr_mono_downmix.attr, -#ifdef CONFIG_SND_VOODOO_DEBUG +#ifdef CONFIG_SND_VOODOO_DEVELOPMENT &dev_attr_wm8994_register_dump.attr, &dev_attr_wm8994_write.attr, #endif @@ -958,6 +1513,10 @@ void update_enable() printk("Voodoo sound: initializing driver v%d\n", VOODOO_SOUND_VERSION); +#ifdef CONFIG_SND_VOODOO_DEVELOPMENT + printk("Voodoo sound: codec development tools enabled\n"); +#endif + misc_register(&voodoo_sound_device); if (sysfs_create_group(&voodoo_sound_device.this_device->kobj, &voodoo_sound_group) < 0) { @@ -1044,13 +1603,13 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec_, value = (WM8994_HPOUT1_VU | WM8994_HPOUT1L_MUTE_N | - hplvol); + hpvol(0)); if (reg == WM8994_RIGHT_OUTPUT_VOLUME) value = (WM8994_HPOUT1_VU | WM8994_HPOUT1R_MUTE_N | - hprvol); + hpvol(1)); } #endif @@ -1091,54 +1650,90 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec_, || reg == WM8994_OUTPUT_MIXER_2) value = dac_direct_get_value(value, false); + // Digital Headroom virtual hook + if (reg == WM8994_AIF1_DAC1_LEFT_VOLUME + || reg == WM8994_AIF1_DAC1_RIGHT_VOLUME) + value = digital_gain_get_value(value); + + // Headphones EQ & 3D virtual hook + if (reg == WM8994_AIF1_DAC1_FILTERS_1 + || reg == WM8994_AIF1_DAC2_FILTERS_1 + || reg == WM8994_AIF2_DAC_FILTERS_1) { + bypass_write_hook = true; + apply_saturation_prevention_drc(); + update_headphone_eq(false); + update_stereo_expansion(false); + bypass_write_hook = false; + } + } -#ifdef CONFIG_SND_VOODOO_DEBUG_LOG + if (debug_log(LOG_VERBOSE)) // log every write to dmesg #ifdef NEXUS_S - printk("Voodoo sound: codec_state=%u, stream_state=%u, " - "cur_path=%i, rec_path=%i, " - "power_state=%i\n", - wm8994->codec_state, wm8994->stream_state, - wm8994->cur_path, wm8994->rec_path, - wm8994->power_state); + printk("Voodoo sound: codec_state=%u, stream_state=%u, " + "cur_path=%i, rec_path=%i, " + "power_state=%i\n", + wm8994->codec_state, wm8994->stream_state, + wm8994->cur_path, wm8994->rec_path, + wm8994->power_state); #else #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) - printk("Voodoo sound: wm8994_write 0x%03X 0x%04X " - "codec_state=%u, stream_state=%u, " - "cur_path=%i, rec_path=%i, " - "fmradio_path=%i, fmr_mix_path=%i, " - "input_source=%i, output_source=%i, " - "power_state=%i\n", - reg, value, - wm8994->codec_state, wm8994->stream_state, - wm8994->fmradio_path, wm8994->fmr_mix_path, - wm8994->cur_path, wm8994->rec_path, - wm8994->input_source, wm8994->output_source, - wm8994->power_state); + printk("Voodoo sound: wm8994_write 0x%03X 0x%04X " + "codec_state=%u, stream_state=%u, " + "cur_path=%i, rec_path=%i, " +#ifndef M110S + "fmradio_path=%i, fmr_mix_path=%i, " +#endif + "input_source=%i, " +#ifndef M110S + "output_source=%i, " +#endif + "power_state=%i\n", + reg, value, + wm8994->codec_state, wm8994->stream_state, +#ifndef M110S + wm8994->fmradio_path, wm8994->fmr_mix_path, +#endif + wm8994->cur_path, wm8994->rec_path, + wm8994->input_source, +#ifndef M110S + wm8994->output_source, +#endif + wm8994->power_state); #else - printk("Voodoo sound: wm8994_write 0x%03X 0x%04X " - "codec_state=%u, stream_state=%u, " - "cur_path=%i, rec_path=%i, " - "fmradio_path=%i, fmr_mix_path=%i, " + printk("Voodoo sound: wm8994_write 0x%03X 0x%04X " + "codec_state=%u, stream_state=%u, " + "cur_path=%i, rec_path=%i, " +#ifndef M110S + "fmradio_path=%i, fmr_mix_path=%i, " +#endif #ifdef CONFIG_S5PC110_KEPLER_BOARD - "call_record_path=%i, call_record_ch=%i, " - "AUDIENCE_state=%i, " - "Fac_SUB_MIC_state=%i, TTY_state=%i, " -#endif - "power_state=%i, " - "recognition_active=%i, ringtone_active=%i\n", - reg, value, - wm8994->codec_state, wm8994->stream_state, - wm8994->cur_path, wm8994->rec_path, - wm8994->fmradio_path, wm8994->fmr_mix_path, + "call_record_path=%i, call_record_ch=%i, " + "AUDIENCE_state=%i, " + "Fac_SUB_MIC_state=%i, TTY_state=%i, " +#endif + "power_state=%i, " +#ifndef M110S + "recognition_active=%i, ringtone_active=%i" +#endif + "\n", + reg, value, + wm8994->codec_state, wm8994->stream_state, + wm8994->cur_path, wm8994->rec_path, +#ifndef M110S + wm8994->fmradio_path, wm8994->fmr_mix_path, +#endif #ifdef CONFIG_S5PC110_KEPLER_BOARD - wm8994->call_record_path, wm8994->call_record_ch, - wm8994->AUDIENCE_state, - wm8994->Fac_SUB_MIC_state, wm8994->TTY_state, + wm8994->call_record_path, wm8994->call_record_ch, + wm8994->AUDIENCE_state, + wm8994->Fac_SUB_MIC_state, wm8994->TTY_state, #endif - wm8994->power_state, - wm8994->recognition_active, wm8994->ringtone_active); + wm8994->power_state +#ifndef M110S + ,wm8994->recognition_active, + wm8994->ringtone_active #endif + ); #endif #endif return value; @@ -1161,4 +1756,7 @@ void voodoo_hook_wm8994_pcm_probe(struct snd_soc_codec *codec_) // make a copy of the codec pointer codec = codec_; + + // initialize eq_band_values[] from default codec EQ values + load_current_eq_values(); } diff --git a/sound/soc/codecs/wm8994_voodoo.h b/sound/soc/codecs/wm8994_voodoo.h index 6e7d23ff581..ef73e28038d 100644 --- a/sound/soc/codecs/wm8994_voodoo.h +++ b/sound/soc/codecs/wm8994_voodoo.h @@ -6,6 +6,8 @@ * published by the Free Software Foundation. */ +#define VOODOO_SOUND_VERSION 9 + #if defined(CONFIG_MACH_HERRING) || defined (CONFIG_SAMSUNG_GALAXYS) \ || defined (CONFIG_SAMSUNG_GALAXYSB) \ || defined (CONFIG_SAMSUNG_CAPTIVATE) \ @@ -23,10 +25,17 @@ #define M110S #endif +#ifdef CONFIG_TDMB_T3700 +#define M110S +#endif + +enum debug_log { LOG_OFF, LOG_INFOS, LOG_VERBOSE }; +bool debug_log(short unsigned int level); + enum unified_path { HEADPHONES, RADIO_HEADPHONES, SPEAKER, MAIN_MICROPHONE }; bool is_path(int unified_path); -unsigned short tune_fll_value(unsigned short val); +bool is_path_media_or_fm_no_call_no_record(void); unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value); void voodoo_hook_fmradio_headset(void); @@ -35,7 +44,10 @@ void voodoo_hook_wm8994_pcm_remove(void); void voodoo_hook_record_main_mic(void); void voodoo_hook_playback_speaker(void); -void update_hpvol(void); +void load_current_eq_values(void); +void apply_saturation_prevention_drc(void); + +void update_hpvol(bool with_fade); void update_fm_radio_headset_restore_freqs(bool with_mute); void update_fm_radio_headset_normalize_gain(bool with_mute); void update_recording_preset(bool with_mute); @@ -44,4 +56,7 @@ void update_osr128(bool with_mute); void update_fll_tuning(bool with_mute); void update_mono_downmix(bool with_mute); void update_dac_direct(bool with_mute); +void update_digital_gain(bool with_mute); +void update_stereo_expansion(bool with_mute); +void update_headphone_eq(bool with_mute); void update_enable(void); From b1d3398cc9d4562119bf3c198c1803fc172526ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Wed, 15 Jun 2011 16:30:14 +0200 Subject: [PATCH 0456/4025] Voodoo sound: fix wm8994_write logging routine missing register/value for Nexus S-based kernels --- sound/soc/codecs/wm8994_voodoo.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/wm8994_voodoo.c b/sound/soc/codecs/wm8994_voodoo.c index 1334a8944af..c38e7be0fd4 100644 --- a/sound/soc/codecs/wm8994_voodoo.c +++ b/sound/soc/codecs/wm8994_voodoo.c @@ -485,15 +485,17 @@ bool is_path(int unified_path) || wm8994->fmradio_path == FMR_HP); #else #ifdef M110S +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + return (wm8994->cur_path == HP + || wm8994->cur_path == HP_NO_MIC); +#else return (wm8994->cur_path == HP); +#endif #else #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) return (wm8994->cur_path == HP || wm8994->cur_path == HP_NO_MIC -#ifndef M110S - || wm8994->fmradio_path == FMR_HP -#endif - ); + || wm8994->fmradio_path == FMR_HP); #else return (wm8994->cur_path == HP || wm8994->fmradio_path == FMR_HP); @@ -1669,16 +1671,17 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec_, } if (debug_log(LOG_VERBOSE)) // log every write to dmesg + printk("Voodoo sound: wm8994_write 0x%03X 0x%04X " #ifdef NEXUS_S - printk("Voodoo sound: codec_state=%u, stream_state=%u, " + "codec_state=%u, stream_state=%u, " "cur_path=%i, rec_path=%i, " "power_state=%i\n", + reg, value, wm8994->codec_state, wm8994->stream_state, wm8994->cur_path, wm8994->rec_path, wm8994->power_state); #else #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) - printk("Voodoo sound: wm8994_write 0x%03X 0x%04X " "codec_state=%u, stream_state=%u, " "cur_path=%i, rec_path=%i, " #ifndef M110S @@ -1701,7 +1704,6 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec_, #endif wm8994->power_state); #else - printk("Voodoo sound: wm8994_write 0x%03X 0x%04X " "codec_state=%u, stream_state=%u, " "cur_path=%i, rec_path=%i, " #ifndef M110S From 9706706582cd73ecbae2f267f5a22c17865a9f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Fri, 8 Jul 2011 16:51:42 +0200 Subject: [PATCH 0457/4025] Voodoo sound: driver v10 Improvement: - HW EQ support: smooth activation/deactivation and gain changes Bugfixes: - HP volume smoothing loop on low levels with negative digital offsets - wm8994_write logging on Nexus S New supported devices: - Galaxy Tab 7" Gingerbread Kernels support (based on M180S) - Galaxy Tab 10.1 - beta --- sound/soc/codecs/Kconfig.voodoo | 2 +- sound/soc/codecs/wm8994_voodoo.c | 195 ++++++++++++++++++++++++------- sound/soc/codecs/wm8994_voodoo.h | 11 +- 3 files changed, 160 insertions(+), 48 deletions(-) diff --git a/sound/soc/codecs/Kconfig.voodoo b/sound/soc/codecs/Kconfig.voodoo index 9d6882dc8b7..23ca597a183 100644 --- a/sound/soc/codecs/Kconfig.voodoo +++ b/sound/soc/codecs/Kconfig.voodoo @@ -1,6 +1,6 @@ menuconfig SND_VOODOO bool "Voodoo sound driver" - depends on SND_UNIVERSAL_WM8994 || SND_S3C24XX_SOC + depends on SND_UNIVERSAL_WM8994 || SND_S3C24XX_SOC || SND_SOC_WM8994_P3 default y help With this option enabled, the kernel compile an additionnal driver diff --git a/sound/soc/codecs/wm8994_voodoo.c b/sound/soc/codecs/wm8994_voodoo.c index c38e7be0fd4..d877d783c8d 100644 --- a/sound/soc/codecs/wm8994_voodoo.c +++ b/sound/soc/codecs/wm8994_voodoo.c @@ -17,13 +17,13 @@ #include "wm8994_voodoo.h" #ifndef MODULE -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) && !defined(GALAXY_TAB) #include "wm8994_samsung.h" #else #include "wm8994.h" #endif #else -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) && !defined(GALAXY_TAB) #include "../wm8994_samsung.h" #else #include "../wm8994.h" @@ -55,7 +55,7 @@ short unsigned int debug_log_level = LOG_OFF; #ifdef CONFIG_SND_VOODOO_HP_LEVEL_CONTROL unsigned short hp_level[2] = { CONFIG_SND_VOODOO_HP_LEVEL, - CONFIG_SND_VOODOO_HP_LEVEL };; + CONFIG_SND_VOODOO_HP_LEVEL }; #endif #ifdef CONFIG_SND_VOODOO_FM @@ -79,7 +79,9 @@ bool enable = false; bool dac_osr128 = true; bool adc_osr128 = false; +#ifndef GALAXY_TAB_TEGRA bool fll_tuning = true; +#endif bool dac_direct = true; bool mono_downmix = false; @@ -134,7 +136,7 @@ static ssize_t headphone_eq_b##band##_gain_show(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ - return sprintf(buf, "%d\n", eq_gains[band-1]); \ + return sprintf(buf, "%d\n", eq_gains[band - 1]); \ } #define DECLARE_EQ_GAIN_STORE(band) \ @@ -145,8 +147,11 @@ static ssize_t headphone_eq_b##band##_gain_store(struct device *dev, \ short new_gain; \ if (sscanf(buf, "%hd", &new_gain) == 1) { \ if (new_gain >= -12 && new_gain <= 12) { \ - eq_gains[band-1] = new_gain; \ - update_headphone_eq(false); \ + smooth_apply_eq_band_gain(band - 1, \ + eq_gains[band - 1], \ + new_gain, \ + headphone_eq); \ + eq_gains[band - 1] = new_gain; \ } \ } \ return size; \ @@ -206,7 +211,7 @@ void update_hpvol(bool with_fade) unsigned short val; unsigned short i; short steps; - unsigned short hp_level_old[2]; + int hp_level_old[2]; unsigned short hp_level_registers[2] = { WM8994_LEFT_OUTPUT_VOLUME, WM8994_RIGHT_OUTPUT_VOLUME }; @@ -218,9 +223,9 @@ void update_hpvol(bool with_fade) || (wm8994->codec_state & CALL_ACTIVE)) return; - bypass_write_hook = true; if (!with_fade) { + bypass_write_hook = true; write_hpvol(hpvol(0), hpvol(1)); bypass_write_hook = false; return; @@ -234,9 +239,12 @@ void update_hpvol(bool with_fade) val &= ~(WM8994_HPOUT1L_MUTE_N_MASK); hp_level_old[i] = val + (digital_gain / 1000); + if (hp_level_old[i] < 0) + hp_level_old[i] = 0; + if (debug_log(LOG_INFOS)) - printk("Voodoo sound: previous hp_level[%hu]: %hu\n", - i, val); + printk("Voodoo sound: previous hp_level[%hu]: %d\n", + i, hp_level_old[i]); } // calculate number of steps for volume fade @@ -258,13 +266,14 @@ void update_hpvol(bool with_fade) printk("Voodoo sound: volume: %hu\n", (hpvol(0) - steps)); + bypass_write_hook = true; write_hpvol(hpvol(0) - steps, hpvol(1) - steps); + bypass_write_hook = false; if (steps != 0) udelay(1000); } - bypass_write_hook = false; } #endif @@ -480,9 +489,14 @@ bool is_path(int unified_path) || wm8994->cur_path == HP_NO_MIC); #else #ifdef GALAXY_TAB +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) + return (wm8994->cur_path == HP + || wm8994->cur_path == HP_NO_MIC); +#else return (wm8994->cur_path == HP3P || wm8994->cur_path == HP4P || wm8994->fmradio_path == FMR_HP); +#endif #else #ifdef M110S #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) @@ -492,6 +506,10 @@ bool is_path(int unified_path) return (wm8994->cur_path == HP); #endif #else +#ifdef GALAXY_TAB_TEGRA + return (wm8994->cur_path == HP + || wm8994->cur_path == HP_NO_MIC); +#else #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) return (wm8994->cur_path == HP || wm8994->cur_path == HP_NO_MIC @@ -502,6 +520,7 @@ bool is_path(int unified_path) #endif #endif #endif +#endif #endif // FM Radio on headphones @@ -512,14 +531,17 @@ bool is_path(int unified_path) #ifdef M110S return false; #else +#ifdef GALAXY_TAB_TEGRA + return false; +#else #ifdef GALAXY_TAB - return (wm8994->codec_state & FMRADIO_ACTIVE) - && (wm8994->fmradio_path == FMR_HP); + return false; #else return (wm8994->codec_state & FMRADIO_ACTIVE) && (wm8994->fmradio_path == FMR_HP); #endif #endif +#endif #endif // Standard recording presets @@ -533,7 +555,8 @@ bool is_path(int unified_path) return false; } -bool is_path_media_or_fm_no_call_no_record() { +bool is_path_media_or_fm_no_call_no_record() +{ DECLARE_WM8994(codec); @@ -636,6 +659,7 @@ void update_osr128(bool with_mute) bypass_write_hook = false; } +#ifndef GALAXY_TAB_TEGRA unsigned short fll_tuning_get_value(unsigned short val) { val = (val >> WM8994_FLL1_GAIN_WIDTH << WM8994_FLL1_GAIN_WIDTH); @@ -653,6 +677,7 @@ void update_fll_tuning(bool with_mute) wm8994_write(codec, WM8994_FLL1_CONTROL_4, val); bypass_write_hook = false; } +#endif unsigned short mono_downmix_get_value(unsigned short val, bool can_reverse) { @@ -699,8 +724,7 @@ unsigned short dac_direct_get_value(unsigned short val, bool can_reverse) if (val == WM8994_DAC1L_TO_MIXOUTL) return WM8994_DAC1L_TO_HPOUT1L; } else { - if (val == WM8994_DAC1L_TO_HPOUT1L - && can_reverse) + if (val == WM8994_DAC1L_TO_HPOUT1L && can_reverse) return WM8994_DAC1L_TO_MIXOUTL; } } @@ -742,8 +766,9 @@ unsigned short digital_gain_get_value(unsigned short val) if (debug_log(LOG_INFOS)) printk("Voodoo sound: digital gain: %d mdB, " - "steps: %d, real AIF gain: %d mdB\n", - digital_gain, i, i * step); + "%d mdB steps: %d, " + "real AIF gain: %d mdB\n", + digital_gain, step, i, i * step); } } @@ -766,14 +791,10 @@ void update_digital_gain(bool with_mute) bypass_write_hook = false; } -void update_headphone_eq(bool with_mute) +void update_headphone_eq(bool update_bands) { int gains_1; int gains_2; - int i; - int j; - int k = 0; - int first_reg = WM8994_AIF1_DAC1_EQ_BAND_1_A; if (!is_path_media_or_fm_no_call_no_record()) { // don't apply the EQ @@ -782,8 +803,8 @@ void update_headphone_eq(bool with_mute) if (debug_log(LOG_INFOS)) printk("Voodoo sound: EQ gains (dB): %hd, %hd, %hd, %hd, %hd\n", - eq_gains[0], eq_gains[1], eq_gains[2], - eq_gains[3], eq_gains[4]); + eq_gains[0], eq_gains[1], eq_gains[2], + eq_gains[3], eq_gains[4]); gains_1 = ((eq_gains[0] + 12) << WM8994_AIF1DAC1_EQ_B1_GAIN_SHIFT) | @@ -802,6 +823,17 @@ void update_headphone_eq(bool with_mute) if (!headphone_eq) return; + if (update_bands) + update_headphone_eq_bands(); +} + +void update_headphone_eq_bands() +{ + int i; + int j; + int k = 0; + int first_reg = WM8994_AIF1_DAC1_EQ_BAND_1_A; + for (i = 0; i < ARRAY_SIZE(eq_band_values); i++) { if (debug_log(LOG_INFOS)) printk("Voodoo sound: send EQ Band %d\n", i + 1); @@ -814,6 +846,34 @@ void update_headphone_eq(bool with_mute) } } +void smooth_apply_eq_band_gain(int band, int start, int end, bool current_state) +{ + if (debug_log(LOG_INFOS)) + printk("Voodoo sound: EQ smooth transition for Band %d " + "from %d to %d\n", band + 1, start, end); + + if (start == end) { + if (end != 0) + update_headphone_eq(true); + else + update_headphone_eq(false); + return; + } + + if (current_state) + update_headphone_eq_bands(); + + while (start != end) { + if (start < end) + start++; + else + start--; + + eq_gains[band] = start; + update_headphone_eq(false); + } +} + void update_stereo_expansion(bool with_mute) { short unsigned int val; @@ -864,6 +924,9 @@ void apply_saturation_prevention_drc() || digital_gain >= 0)) return; + if (debug_log(LOG_INFOS)) + printk("Voodoo sound: apply saturation prevention DRC\n"); + // configure the DRC to avoid saturation: not actually compress signal // gain is unmodified. Should affect only what's higher than 0 dBFS @@ -907,8 +970,8 @@ void apply_saturation_prevention_drc() if (debug_log(LOG_INFOS)) printk("Voodoo sound: digital gain: %d mdB, " - "steps: %d, real DRC gain: %d mdB\n", - digital_gain, i, i * step); + "%d mdB steps: %d, real DRC gain: %d mdB\n", + digital_gain, step, i, i * step); } wm8994_write(codec, WM8994_AIF1_DRC1_4, val); @@ -1018,10 +1081,12 @@ DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(adc_osr128, update_osr128, false); +#ifndef GALAXY_TAB_TEGRA DECLARE_BOOL_SHOW(fll_tuning); DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(fll_tuning, update_fll_tuning, false); +#endif DECLARE_BOOL_SHOW(mono_downmix); DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(mono_downmix, @@ -1068,9 +1133,41 @@ static ssize_t digital_gain_store(struct device *dev, } DECLARE_BOOL_SHOW(headphone_eq); -DECLARE_BOOL_STORE_UPDATE_WITH_MUTE(headphone_eq, - update_headphone_eq, - false); +static ssize_t headphone_eq_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + unsigned short state; + bool current_state; + int i; + short eq_gains_copy[ARRAY_SIZE(eq_gains)]; + + if (sscanf(buf, "%hu", &state) == 1) { + current_state = state == 0 ? false : true; + if (debug_log(LOG_INFOS)) + printk("Voodoo sound: EQ activation: %u\n", state); + + if (current_state) { + // fade from 0dB each EQ band + headphone_eq = current_state; + for (i = 0; i < ARRAY_SIZE(eq_bands); i++) + smooth_apply_eq_band_gain(i, 0, eq_gains[i], + current_state); + } else { + // fade to 0dB each EQ band + for (i = 0; i < ARRAY_SIZE(eq_bands); i++) { + eq_gains_copy[i] = eq_gains[i]; + smooth_apply_eq_band_gain(i, eq_gains[i], 0, + current_state); + } + // restore original gains in driver memory not codec + for (i = 0; i < ARRAY_SIZE(eq_bands); i++) + eq_gains[i] = eq_gains_copy[i]; + headphone_eq = current_state; + } + } + return size; +} DECLARE_EQ_GAIN_SHOW(1); DECLARE_EQ_GAIN_STORE(1); @@ -1133,12 +1230,12 @@ static ssize_t headphone_eq_bands_values_store(struct device *dev, for (i = 0; i < ARRAY_SIZE(eq_band_coef_names); i++) { // loop through band coefficient letters if (strncmp(eq_band_coef_names[i], coef_name, 2) == 0) { - if (eq_bands[band-1] == 3 && i == 3) + if (eq_bands[band - 1] == 3 && i == 3) // deal with high and low shelves - eq_band_values[band-1][2] = val; + eq_band_values[band - 1][2] = val; else // parametric bands - eq_band_values[band-1][i] = val; + eq_band_values[band - 1][i] = val; if (debug_log(LOG_INFOS)) printk("Voodoo sound: read EQ from " @@ -1271,7 +1368,7 @@ static ssize_t store_wm8994_write(struct device *dev, while (sscanf(buf, "%hx %hx%n", ®, &val, &bytes_read) == 2) { buf += bytes_read; - if (debug_log(LOG_INFOS)); + if (debug_log(LOG_INFOS)) printk("Voodoo sound: read from sysfs: %X, %X\n", reg, val); @@ -1352,9 +1449,11 @@ static DEVICE_ATTR(adc_osr128, S_IRUGO | S_IWUGO, adc_osr128_show, adc_osr128_store); +#ifndef GALAXY_TAB_TEGRA static DEVICE_ATTR(fll_tuning, S_IRUGO | S_IWUGO, fll_tuning_show, fll_tuning_store); +#endif static DEVICE_ATTR(dac_direct, S_IRUGO | S_IWUGO, dac_direct_show, @@ -1448,7 +1547,9 @@ static struct attribute *voodoo_sound_attributes[] = { #endif &dev_attr_dac_osr128.attr, &dev_attr_adc_osr128.attr, +#ifndef GALAXY_TAB_TEGRA &dev_attr_fll_tuning.attr, +#endif &dev_attr_dac_direct.attr, &dev_attr_digital_gain.attr, &dev_attr_headphone_eq.attr, @@ -1637,9 +1738,11 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec_, if (reg == WM8994_OVERSAMPLING) value = osr128_get_value(value); +#ifndef GALAXY_TAB_TEGRA // global Anti-Jitter tuning if (reg == WM8994_FLL1_CONTROL_4) value = fll_tuning_get_value(value); +#endif // global Mono downmix tuning if (reg == WM8994_AIF1_DAC1_FILTERS_1 @@ -1663,7 +1766,7 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec_, || reg == WM8994_AIF2_DAC_FILTERS_1) { bypass_write_hook = true; apply_saturation_prevention_drc(); - update_headphone_eq(false); + update_headphone_eq(true); update_stereo_expansion(false); bypass_write_hook = false; } @@ -1684,29 +1787,33 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec_, #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) "codec_state=%u, stream_state=%u, " "cur_path=%i, rec_path=%i, " -#ifndef M110S +#if !defined(M110S) && !defined(GALAXY_TAB_TEGRA) "fmradio_path=%i, fmr_mix_path=%i, " #endif +#ifndef GALAXY_TAB "input_source=%i, " -#ifndef M110S +#endif +#if !defined(M110S) && !defined(GALAXY_TAB_TEGRA) && !defined(GALAXY_TAB) "output_source=%i, " #endif "power_state=%i\n", reg, value, wm8994->codec_state, wm8994->stream_state, -#ifndef M110S +#if !defined(M110S) && !defined(GALAXY_TAB_TEGRA) wm8994->fmradio_path, wm8994->fmr_mix_path, #endif wm8994->cur_path, wm8994->rec_path, +#ifndef GALAXY_TAB wm8994->input_source, -#ifndef M110S +#endif +#if !defined(M110S) && !defined(GALAXY_TAB_TEGRA) && !defined(GALAXY_TAB) wm8994->output_source, #endif wm8994->power_state); #else "codec_state=%u, stream_state=%u, " "cur_path=%i, rec_path=%i, " -#ifndef M110S +#if !defined(M110S) && !defined(GALAXY_TAB_TEGRA) "fmradio_path=%i, fmr_mix_path=%i, " #endif #ifdef CONFIG_S5PC110_KEPLER_BOARD @@ -1715,14 +1822,14 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec_, "Fac_SUB_MIC_state=%i, TTY_state=%i, " #endif "power_state=%i, " -#ifndef M110S +#if !defined(M110S) && !defined(GALAXY_TAB_TEGRA) "recognition_active=%i, ringtone_active=%i" #endif "\n", reg, value, wm8994->codec_state, wm8994->stream_state, wm8994->cur_path, wm8994->rec_path, -#ifndef M110S +#if !defined(M110S) && !defined(GALAXY_TAB_TEGRA) wm8994->fmradio_path, wm8994->fmr_mix_path, #endif #ifdef CONFIG_S5PC110_KEPLER_BOARD @@ -1731,11 +1838,11 @@ unsigned int voodoo_hook_wm8994_write(struct snd_soc_codec *codec_, wm8994->Fac_SUB_MIC_state, wm8994->TTY_state, #endif wm8994->power_state -#ifndef M110S +#if !defined(M110S) && !defined(GALAXY_TAB_TEGRA) ,wm8994->recognition_active, wm8994->ringtone_active #endif - ); + ); #endif #endif return value; diff --git a/sound/soc/codecs/wm8994_voodoo.h b/sound/soc/codecs/wm8994_voodoo.h index ef73e28038d..578f8e8f3e0 100644 --- a/sound/soc/codecs/wm8994_voodoo.h +++ b/sound/soc/codecs/wm8994_voodoo.h @@ -6,7 +6,7 @@ * published by the Free Software Foundation. */ -#define VOODOO_SOUND_VERSION 9 +#define VOODOO_SOUND_VERSION 10 #if defined(CONFIG_MACH_HERRING) || defined (CONFIG_SAMSUNG_GALAXYS) \ || defined (CONFIG_SAMSUNG_GALAXYSB) \ @@ -17,7 +17,7 @@ #define NEXUS_S #endif -#ifdef CONFIG_FB_S3C_AMS701KA +#if defined(CONFIG_FB_S3C_AMS701KA) || defined(CONFIG_KOR_MODEL_M180S) #define GALAXY_TAB #endif @@ -25,6 +25,10 @@ #define M110S #endif +#ifdef CONFIG_MACH_SAMSUNG_VARIATION_TEGRA +#define GALAXY_TAB_TEGRA +#endif + #ifdef CONFIG_TDMB_T3700 #define M110S #endif @@ -58,5 +62,6 @@ void update_mono_downmix(bool with_mute); void update_dac_direct(bool with_mute); void update_digital_gain(bool with_mute); void update_stereo_expansion(bool with_mute); -void update_headphone_eq(bool with_mute); +void update_headphone_eq(bool update_bands); +void update_headphone_eq_bands(void); void update_enable(void); From d6668d3a5e2e72ecf9fd949cdbf65f40407b45ea Mon Sep 17 00:00:00 2001 From: Thomas Ryu Date: Fri, 29 Apr 2011 20:51:10 +0900 Subject: [PATCH 0458/4025] ARM: S5PC11X: sleep current reduction of cdma/wimax. change the sleep gpio configurations of cdma/wimax table to reduce sleep current. Signed-off-by: Thomas Ryu --- arch/arm/mach-s5pv210/mach-herring.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c index a1f157c852e..9d3edf8f714 100755 --- a/arch/arm/mach-s5pv210/mach-herring.c +++ b/arch/arm/mach-s5pv210/mach-herring.c @@ -4842,20 +4842,20 @@ static unsigned int herring_cdma_wimax_sleep_gpio_table[][3] = { { S5PV210_GPG0(0), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, - { S5PV210_GPG0(1), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, + { S5PV210_GPG0(1), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, { S5PV210_GPG0(2), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, - { S5PV210_GPG0(3), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, - { S5PV210_GPG0(4), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, - { S5PV210_GPG0(5), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, - { S5PV210_GPG0(6), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, + { S5PV210_GPG0(3), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, + { S5PV210_GPG0(4), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, + { S5PV210_GPG0(5), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, + { S5PV210_GPG0(6), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, { S5PV210_GPG1(0), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, { S5PV210_GPG1(1), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, { S5PV210_GPG1(2), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, - { S5PV210_GPG1(3), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, - { S5PV210_GPG1(4), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, - { S5PV210_GPG1(5), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, - { S5PV210_GPG1(6), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, + { S5PV210_GPG1(3), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, + { S5PV210_GPG1(4), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, + { S5PV210_GPG1(5), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, + { S5PV210_GPG1(6), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, /*wimax SDIO pins*/ { S5PV210_GPG2(0), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, @@ -4904,7 +4904,7 @@ static unsigned int herring_cdma_wimax_sleep_gpio_table[][3] = { { S5PV210_GPJ1(1), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, { S5PV210_GPJ1(2), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, { S5PV210_GPJ1(3), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, - { S5PV210_GPJ1(4), S3C_GPIO_SLP_PREV, S3C_GPIO_PULL_NONE}, + { S5PV210_GPJ1(4), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, { S5PV210_GPJ1(5), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, { S5PV210_GPJ2(0), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, @@ -4915,7 +4915,7 @@ static unsigned int herring_cdma_wimax_sleep_gpio_table[][3] = { { S5PV210_GPJ2(5), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, { S5PV210_GPJ2(6), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, - { S5PV210_GPJ2(7), S3C_GPIO_SLP_OUT1, S3C_GPIO_PULL_NONE}, + { S5PV210_GPJ2(7), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, { S5PV210_GPJ3(0), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, { S5PV210_GPJ3(1), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, From 5cfdd8a3db2dc2abbd17b10f01f5fd82da406343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SIMOND=20Fran=C3=A7ois?= Date: Mon, 19 Dec 2011 12:55:33 +0100 Subject: [PATCH 0459/4025] Voodoo Sound: update source code for ICS kernel sources --- sound/soc/codecs/Kconfig.voodoo | 2 +- sound/soc/codecs/wm8994_voodoo.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/Kconfig.voodoo b/sound/soc/codecs/Kconfig.voodoo index 23ca597a183..6672bedc806 100644 --- a/sound/soc/codecs/Kconfig.voodoo +++ b/sound/soc/codecs/Kconfig.voodoo @@ -1,6 +1,6 @@ menuconfig SND_VOODOO bool "Voodoo sound driver" - depends on SND_UNIVERSAL_WM8994 || SND_S3C24XX_SOC || SND_SOC_WM8994_P3 + depends on SND_UNIVERSAL_WM8994 || SND_S3C24XX_SOC || SND_SOC_WM8994_P3 || SND_SOC_SAMSUNG_HERRING_WM8994 default y help With this option enabled, the kernel compile an additionnal driver diff --git a/sound/soc/codecs/wm8994_voodoo.c b/sound/soc/codecs/wm8994_voodoo.c index d877d783c8d..750702f950a 100644 --- a/sound/soc/codecs/wm8994_voodoo.c +++ b/sound/soc/codecs/wm8994_voodoo.c @@ -108,7 +108,7 @@ bool stereo_expansion = false; short unsigned int stereo_expansion_gain = 16; // keep here a pointer to the codec structure -struct snd_soc_codec *codec; +static struct snd_soc_codec *codec; #define DECLARE_BOOL_SHOW(name) \ static ssize_t name##_show(struct device *dev, \ @@ -158,7 +158,8 @@ static ssize_t headphone_eq_b##band##_gain_store(struct device *dev, \ } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) -#define DECLARE_WM8994(codec) struct wm8994_priv *wm8994 = codec->drvdata; +#define DECLARE_WM8994(codec) struct wm8994_priv *wm8994 = \ + snd_soc_codec_get_drvdata(codec); #else #define DECLARE_WM8994(codec) struct wm8994_priv *wm8994 = codec->private_data; #endif @@ -1286,7 +1287,7 @@ static ssize_t show_wm8994_register_dump(struct device *dev, int r; for (r = 0; r <= 0x6; r++) - sprintf(buf, "0x%X 0x%X\n", r, wm8994_read(codec, r)); + sprintf(buf, "%s0x%X 0x%X\n", buf, r, wm8994_read(codec, r)); sprintf(buf, "%s0x%X 0x%X\n", buf, 0x15, wm8994_read(codec, 0x15)); From ea693bf7f87603b072f4ceea6684221fa0b8e863 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Fri, 16 Dec 2011 17:52:18 -0800 Subject: [PATCH 0460/4025] mmc: Set suspend/resume bus operations if CONFIG_PM_RUNTIME is used Signed-off-by: Dmitry Shmidt --- drivers/mmc/core/bus.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 393d817ed04..e07d6c90cae 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -120,18 +120,19 @@ static int mmc_bus_remove(struct device *dev) return 0; } -static int mmc_bus_suspend(struct device *dev, pm_message_t state) +static int mmc_bus_pm_suspend(struct device *dev) { struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); int ret = 0; + pm_message_t state = { PM_EVENT_SUSPEND }; if (dev->driver && drv->suspend) ret = drv->suspend(card, state); return ret; } -static int mmc_bus_resume(struct device *dev) +static int mmc_bus_pm_resume(struct device *dev) { struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); @@ -143,7 +144,6 @@ static int mmc_bus_resume(struct device *dev) } #ifdef CONFIG_PM_RUNTIME - static int mmc_runtime_suspend(struct device *dev) { struct mmc_card *card = mmc_dev_to_card(dev); @@ -162,21 +162,13 @@ static int mmc_runtime_idle(struct device *dev) { return pm_runtime_suspend(dev); } +#endif /* CONFIG_PM_RUNTIME */ static const struct dev_pm_ops mmc_bus_pm_ops = { - .runtime_suspend = mmc_runtime_suspend, - .runtime_resume = mmc_runtime_resume, - .runtime_idle = mmc_runtime_idle, + SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_pm_suspend, mmc_bus_pm_resume) + SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, mmc_runtime_idle) }; -#define MMC_PM_OPS_PTR (&mmc_bus_pm_ops) - -#else /* !CONFIG_PM_RUNTIME */ - -#define MMC_PM_OPS_PTR NULL - -#endif /* !CONFIG_PM_RUNTIME */ - static struct bus_type mmc_bus_type = { .name = "mmc", .dev_attrs = mmc_dev_attrs, @@ -184,9 +176,7 @@ static struct bus_type mmc_bus_type = { .uevent = mmc_bus_uevent, .probe = mmc_bus_probe, .remove = mmc_bus_remove, - .suspend = mmc_bus_suspend, - .resume = mmc_bus_resume, - .pm = MMC_PM_OPS_PTR, + .pm = &mmc_bus_pm_ops, }; int mmc_register_bus(void) From 35047200c401cdd1bb43b5574270d1ac86a47937 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 19 Dec 2011 12:32:21 -0800 Subject: [PATCH 0461/4025] wireless: Protect regdomain change by mutex Signed-off-by: Dmitry Shmidt --- net/wireless/reg.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 379574c30ad..7b0add2bada 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -1759,6 +1759,7 @@ static void restore_alpha2(char *alpha2, bool reset_user) static void restore_regulatory_settings(bool reset_user) { char alpha2[2]; + char world_alpha2[2]; struct reg_beacon *reg_beacon, *btmp; struct regulatory_request *reg_request, *tmp; LIST_HEAD(tmp_reg_req_list); @@ -1809,11 +1810,13 @@ static void restore_regulatory_settings(bool reset_user) /* First restore to the basic regulatory settings */ cfg80211_regdomain = cfg80211_world_regdom; + world_alpha2[0] = cfg80211_regdomain->alpha2[0]; + world_alpha2[1] = cfg80211_regdomain->alpha2[1]; mutex_unlock(®_mutex); mutex_unlock(&cfg80211_mutex); - regulatory_hint_core(cfg80211_regdomain->alpha2); + regulatory_hint_core(world_alpha2); /* * This restores the ieee80211_regdom module parameter From 8d71d882e7062dfbcdb2f790470f803cc536b8ae Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Fri, 11 Nov 2011 16:04:12 -0800 Subject: [PATCH 0462/4025] net: wireless: bcmdhd: Use CONFIG_DHD_USE_STATIC_BUF for preallocated memory Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/Kconfig | 7 +++ drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c | 16 +++--- drivers/net/wireless/bcmdhd/dhd.h | 4 +- drivers/net/wireless/bcmdhd/dhd_cdc.c | 4 +- drivers/net/wireless/bcmdhd/dhd_linux.c | 4 +- drivers/net/wireless/bcmdhd/dhd_sdio.c | 4 +- .../net/wireless/bcmdhd/include/linux_osl.h | 2 +- drivers/net/wireless/bcmdhd/linux_osl.c | 52 +++++++++++-------- drivers/net/wireless/bcmdhd/wl_android.c | 7 +-- 9 files changed, 57 insertions(+), 43 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/Kconfig b/drivers/net/wireless/bcmdhd/Kconfig index db434ab04cd..205c813681a 100644 --- a/drivers/net/wireless/bcmdhd/Kconfig +++ b/drivers/net/wireless/bcmdhd/Kconfig @@ -31,3 +31,10 @@ config BCMDHD_WEXT select WEXT_PRIV help Enables WEXT support + +config DHD_USE_STATIC_BUF + bool "Enable memory preallocation" + depends on BCMDHD + default n + ---help--- + Use memory preallocated in platform \ No newline at end of file diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c index 70bacbd3793..aedb508c594 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c @@ -1002,11 +1002,11 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u if (pkt == NULL) { sd_data(("%s: Creating new %s Packet, len=%d\n", __FUNCTION__, write ? "TX" : "RX", buflen_u)); -#ifdef DHD_USE_STATIC_BUF +#ifdef CONFIG_DHD_USE_STATIC_BUF if (!(mypkt = PKTGET_STATIC(sd->osh, buflen_u, write ? TRUE : FALSE))) { #else if (!(mypkt = PKTGET(sd->osh, buflen_u, write ? TRUE : FALSE))) { -#endif /* DHD_USE_STATIC_BUF */ +#endif /* CONFIG_DHD_USE_STATIC_BUF */ sd_err(("%s: PKTGET failed: len %d\n", __FUNCTION__, buflen_u)); return SDIOH_API_RC_FAIL; @@ -1023,11 +1023,11 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u if (!write) { bcopy(PKTDATA(sd->osh, mypkt), buffer, buflen_u); } -#ifdef DHD_USE_STATIC_BUF +#ifdef CONFIG_DHD_USE_STATIC_BUF PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE); #else PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); -#endif /* DHD_USE_STATIC_BUF */ +#endif /* CONFIG_DHD_USE_STATIC_BUF */ } else if (((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) != 0) { /* Case 2: We have a packet, but it is unaligned. */ @@ -1036,11 +1036,11 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u sd_data(("%s: Creating aligned %s Packet, len=%d\n", __FUNCTION__, write ? "TX" : "RX", PKTLEN(sd->osh, pkt))); -#ifdef DHD_USE_STATIC_BUF +#ifdef CONFIG_DHD_USE_STATIC_BUF if (!(mypkt = PKTGET_STATIC(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) { #else if (!(mypkt = PKTGET(sd->osh, PKTLEN(sd->osh, pkt), write ? TRUE : FALSE))) { -#endif /* DHD_USE_STATIC_BUF */ +#endif /* CONFIG_DHD_USE_STATIC_BUF */ sd_err(("%s: PKTGET failed: len %d\n", __FUNCTION__, PKTLEN(sd->osh, pkt))); return SDIOH_API_RC_FAIL; @@ -1061,11 +1061,11 @@ sdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint write, u PKTDATA(sd->osh, pkt), PKTLEN(sd->osh, mypkt)); } -#ifdef DHD_USE_STATIC_BUF +#ifdef CONFIG_DHD_USE_STATIC_BUF PKTFREE_STATIC(sd->osh, mypkt, write ? TRUE : FALSE); #else PKTFREE(sd->osh, mypkt, write ? TRUE : FALSE); -#endif /* DHD_USE_STATIC_BUF */ +#endif /* CONFIG_DHD_USE_STATIC_BUF */ } else { /* case 3: We have a packet and it is aligned. */ sd_data(("%s: Aligned %s Packet, direct DMA\n", __FUNCTION__, write ? "Tx" : "Rx")); diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index c87f6cf37d9..bbb53888144 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -116,7 +116,7 @@ typedef enum { } dhd_if_state_t; -#if defined(DHD_USE_STATIC_BUF) +#if defined(CONFIG_DHD_USE_STATIC_BUF) uint8* dhd_os_prealloc(void *osh, int section, uint size); void dhd_os_prefree(void *osh, void *addr, uint size); @@ -128,7 +128,7 @@ void dhd_os_prefree(void *osh, void *addr, uint size); #define DHD_OS_PREALLOC(osh, section, size) MALLOC(osh, size) #define DHD_OS_PREFREE(osh, addr, size) MFREE(osh, addr, size) -#endif /* defined(DHD_USE_STATIC_BUF) */ +#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ /* Packet alignment for most efficient SDIO (can change based on platform) */ #ifndef DHD_SDALIGN diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c index 3a4de96c002..84609920603 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cdc.c +++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c @@ -2460,7 +2460,7 @@ dhd_prot_attach(dhd_pub_t *dhd) return 0; fail: -#ifndef DHD_USE_STATIC_BUF +#ifndef CONFIG_DHD_USE_STATIC_BUF if (cdc != NULL) MFREE(dhd->osh, cdc, sizeof(dhd_prot_t)); #endif @@ -2474,7 +2474,7 @@ dhd_prot_detach(dhd_pub_t *dhd) #ifdef PROP_TXSTATUS dhd_wlfc_deinit(dhd); #endif -#ifndef DHD_USE_STATIC_BUF +#ifndef CONFIG_DHD_USE_STATIC_BUF MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t)); #endif dhd->prot = NULL; diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 92cdc9b1a4b..32238ee0e12 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -3915,7 +3915,7 @@ dhd_os_sdtxunlock(dhd_pub_t *pub) dhd_os_sdunlock(pub); } -#if defined(DHD_USE_STATIC_BUF) +#if defined(CONFIG_DHD_USE_STATIC_BUF) uint8* dhd_os_prealloc(void *osh, int section, uint size) { return (uint8*)wl_android_prealloc(section, size); @@ -3924,7 +3924,7 @@ uint8* dhd_os_prealloc(void *osh, int section, uint size) void dhd_os_prefree(void *osh, void *addr, uint size) { } -#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ +#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ #if defined(CONFIG_WIRELESS_EXT) struct iw_statistics * diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 29301159cbd..760e2beb7a5 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -5736,7 +5736,7 @@ dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) return; if (bus->rxbuf) { -#ifndef DHD_USE_STATIC_BUF +#ifndef CONFIG_DHD_USE_STATIC_BUF MFREE(osh, bus->rxbuf, bus->rxblen); #endif bus->rxctl = bus->rxbuf = NULL; @@ -5744,7 +5744,7 @@ dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) } if (bus->databuf) { -#ifndef DHD_USE_STATIC_BUF +#ifndef CONFIG_DHD_USE_STATIC_BUF MFREE(osh, bus->databuf, MAX_DATA_BUF); #endif bus->databuf = NULL; diff --git a/drivers/net/wireless/bcmdhd/include/linux_osl.h b/drivers/net/wireless/bcmdhd/include/linux_osl.h index 1ec136eb70d..38de2982f13 100644 --- a/drivers/net/wireless/bcmdhd/include/linux_osl.h +++ b/drivers/net/wireless/bcmdhd/include/linux_osl.h @@ -268,7 +268,7 @@ extern int osl_error(int bcmerror); #define PKTLIST_DUMP(osh, buf) #define PKTDBG_TRACE(osh, pkt, bit) #define PKTFREE(osh, skb, send) osl_pktfree((osh), (skb), (send)) -#ifdef DHD_USE_STATIC_BUF +#ifdef CONFIG_DHD_USE_STATIC_BUF #define PKTGET_STATIC(osh, len, send) osl_pktget_static((osh), (len)) #define PKTFREE_STATIC(osh, skb, send) osl_pktfree_static((osh), (skb), (send)) #endif diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c index 1a544378c1e..b3fcdd2f1ad 100644 --- a/drivers/net/wireless/bcmdhd/linux_osl.c +++ b/drivers/net/wireless/bcmdhd/linux_osl.c @@ -47,7 +47,7 @@ #define OS_HANDLE_MAGIC 0x1234abcd #define BCM_MEM_FILENAME_LEN 24 -#ifdef DHD_USE_STATIC_BUF +#ifdef CONFIG_DHD_USE_STATIC_BUF #define STATIC_BUF_MAX_NUM 16 #define STATIC_BUF_SIZE (PAGE_SIZE * 2) #define STATIC_BUF_TOTAL_LEN (STATIC_BUF_MAX_NUM * STATIC_BUF_SIZE) @@ -70,7 +70,7 @@ typedef struct bcm_static_pkt { } bcm_static_pkt_t; static bcm_static_pkt_t *bcm_static_skb = 0; -#endif +#endif typedef struct bcm_mem_link { struct bcm_mem_link *prev; @@ -211,7 +211,7 @@ osl_attach(void *pdev, uint bustype, bool pkttag) break; } -#if defined(DHD_USE_STATIC_BUF) +#if defined(CONFIG_DHD_USE_STATIC_BUF) if (!bcm_static_buf) { if (!(bcm_static_buf = (bcm_static_buf_t *)dhd_os_prealloc(osh, 3, STATIC_BUF_SIZE+ STATIC_BUF_TOTAL_LEN))) { @@ -220,25 +220,25 @@ osl_attach(void *pdev, uint bustype, bool pkttag) else printk("alloc static buf at %x!\n", (unsigned int)bcm_static_buf); - sema_init(&bcm_static_buf->static_sem, 1); bcm_static_buf->buf_ptr = (unsigned char *)bcm_static_buf + STATIC_BUF_SIZE; } if (!bcm_static_skb) { - int i; - void *skb_buff_ptr = 0; - bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); - skb_buff_ptr = dhd_os_prealloc(osh, 4, 0); - - bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * 16); - for (i = 0; i < STATIC_PKT_MAX_NUM * 2; i++) - bcm_static_skb->pkt_use[i] = 0; - - sema_init(&bcm_static_skb->osl_pkt_sem, 1); + void *skb_buff_ptr = dhd_os_prealloc(osh, 4, 0); + + if (skb_buff_ptr) { + bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); + bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * 16); + for (i = 0; i < STATIC_PKT_MAX_NUM * 2; i++) + bcm_static_skb->pkt_use[i] = 0; + sema_init(&bcm_static_skb->osl_pkt_sem, 1); + } else { + printk("can not alloc static skb buffers\n"); + } } -#endif +#endif return osh; } @@ -388,7 +388,7 @@ osl_ctfpool_stats(osl_t *osh, void *b) if ((osh == NULL) || (osh->ctfpool == NULL)) return; -#ifdef DHD_USE_STATIC_BUF +#ifdef CONFIG_DHD_USE_STATIC_BUF if (bcm_static_buf) { bcm_static_buf = 0; } @@ -548,14 +548,14 @@ osl_pktfree(osl_t *osh, void *p, bool send) } } -#ifdef DHD_USE_STATIC_BUF +#ifdef CONFIG_DHD_USE_STATIC_BUF void * osl_pktget_static(osl_t *osh, uint len) { int i; struct sk_buff *skb; - if (len > (PAGE_SIZE * 2)) { + if (!bcm_static_skb || (len > (PAGE_SIZE * 2))) { printk("%s: attempt to allocate huge packet (0x%x)\n", __FUNCTION__, len); return osl_pktget(osh, len); } @@ -570,10 +570,10 @@ osl_pktget_static(osl_t *osh, uint len) if (i != STATIC_PKT_MAX_NUM) { bcm_static_skb->pkt_use[i] = 1; - up(&bcm_static_skb->osl_pkt_sem); skb = bcm_static_skb->skb_4k[i]; skb->tail = skb->data + len; skb->len = len; + up(&bcm_static_skb->osl_pkt_sem); return skb; } } @@ -586,10 +586,10 @@ osl_pktget_static(osl_t *osh, uint len) if (i != STATIC_PKT_MAX_NUM) { bcm_static_skb->pkt_use[i+STATIC_PKT_MAX_NUM] = 1; - up(&bcm_static_skb->osl_pkt_sem); skb = bcm_static_skb->skb_8k[i]; skb->tail = skb->data + len; skb->len = len; + up(&bcm_static_skb->osl_pkt_sem); return skb; } @@ -603,9 +603,14 @@ osl_pktfree_static(osl_t *osh, void *p, bool send) { int i; + if (!bcm_static_skb) { + osl_pktfree(osh, p, send); + return; + } + + down(&bcm_static_skb->osl_pkt_sem); for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { if (p == bcm_static_skb->skb_4k[i]) { - down(&bcm_static_skb->osl_pkt_sem); bcm_static_skb->pkt_use[i] = 0; up(&bcm_static_skb->osl_pkt_sem); return; @@ -614,14 +619,15 @@ osl_pktfree_static(osl_t *osh, void *p, bool send) for (i = 0; i < STATIC_PKT_MAX_NUM; i++) { if (p == bcm_static_skb->skb_8k[i]) { - down(&bcm_static_skb->osl_pkt_sem); bcm_static_skb->pkt_use[i + STATIC_PKT_MAX_NUM] = 0; up(&bcm_static_skb->osl_pkt_sem); return; } } + up(&bcm_static_skb->osl_pkt_sem); - return osl_pktfree(osh, p, send); + osl_pktfree(osh, p, send); + return; } #endif diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index 9ca3d602023..67f7d9fca53 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -675,20 +675,21 @@ void wl_android_wifictrl_func_del(void) } } -void* wl_android_prealloc(int section, unsigned long size) +void *wl_android_prealloc(int section, unsigned long size) { void *alloc_ptr = NULL; if (wifi_control_data && wifi_control_data->mem_prealloc) { alloc_ptr = wifi_control_data->mem_prealloc(section, size); if (alloc_ptr) { DHD_INFO(("success alloc section %d\n", section)); - bzero(alloc_ptr, size); + if (size != 0L) + bzero(alloc_ptr, size); return alloc_ptr; } } DHD_ERROR(("can't alloc section %d\n", section)); - return 0; + return NULL; } int wifi_get_irq_number(unsigned long *irq_flags_ptr) From 7caeacd6ed135e2ee4fbbc26aa0fc0aea4cb166d Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Wed, 30 Nov 2011 12:49:02 -0800 Subject: [PATCH 0463/4025] net: wireless: bcmdhd: Update to Version 5.90.125.94.1 - Return zeroed private command buffer - Fix memory leak in wl_inform_single_bss() Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_common.c | 5 +++-- drivers/net/wireless/bcmdhd/dhd_linux_mon.c | 10 ++++++---- drivers/net/wireless/bcmdhd/include/epivers.h | 2 +- drivers/net/wireless/bcmdhd/wl_android.c | 9 ++++++--- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 9 ++++++--- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index a29c2fab28c..c90bb1676a2 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -1902,6 +1902,7 @@ dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, if ((!dhd) && (!ssids_local)) { DHD_ERROR(("%s error exit\n", __FUNCTION__)); err = -1; + return err; } if (dhd_check_ap_wfd_mode_set(dhd) == TRUE) @@ -2155,14 +2156,14 @@ wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left) { - char* str = *list_str; + char* str; int idx = 0; if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { DHD_ERROR(("%s error paramters\n", __FUNCTION__)); return -1; } - + str = *list_str; while (*bytes_left > 0) { if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c index dd9c71f75be..ce94ff9993d 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c @@ -225,9 +225,10 @@ static void dhd_mon_if_set_multicast_list(struct net_device *ndev) mon_if = ndev_to_monif(ndev); if (mon_if == NULL || mon_if->real_ndev == NULL) { MON_PRINT(" cannot find matched net dev, skip the packet\n"); + } else { + MON_PRINT("enter, if name: %s, matched if name %s\n", + ndev->name, mon_if->real_ndev->name); } - - MON_PRINT("enter, if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name); } static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr) @@ -238,9 +239,10 @@ static int dhd_mon_if_change_mac(struct net_device *ndev, void *addr) mon_if = ndev_to_monif(ndev); if (mon_if == NULL || mon_if->real_ndev == NULL) { MON_PRINT(" cannot find matched net dev, skip the packet\n"); + } else { + MON_PRINT("enter, if name: %s, matched if name %s\n", + ndev->name, mon_if->real_ndev->name); } - - MON_PRINT("enter, if name: %s, matched if name %s\n", ndev->name, mon_if->real_ndev->name); return ret; } diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index ae1f975bdb6..fe71e166a7d 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -44,6 +44,6 @@ #define EPI_VERSION_DEV 5.90.125 -#define EPI_VERSION_STR "5.90.125.94" +#define EPI_VERSION_STR "5.90.125.94.1" #endif diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index 67f7d9fca53..b6804817240 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -559,8 +559,10 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) bytes_written = strlen("OK"); } - if (bytes_written > 0) { - if (bytes_written > priv_cmd.total_len) { + if (bytes_written >= 0) { + if ((bytes_written == 0) && (priv_cmd.total_len > 0)) + command[0] = '\0'; + if (bytes_written >= priv_cmd.total_len) { DHD_ERROR(("%s: bytes_written = %d\n", __FUNCTION__, bytes_written)); bytes_written = priv_cmd.total_len; } else { @@ -571,7 +573,8 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) DHD_ERROR(("%s: failed to copy data to user buffer\n", __FUNCTION__)); ret = -EFAULT; } - } else { + } + else { ret = bytes_written; } diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index daa7d2605aa..9c2533028df 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -4155,6 +4155,7 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) struct wl_cfg80211_bss_info *notif_bss_info; struct wl_scan_req *sr = wl_to_sr(wl); struct beacon_proberesp *beacon_proberesp; + struct cfg80211_bss *cbss = NULL; s32 mgmt_type; s32 signal; u32 freq; @@ -4213,13 +4214,15 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) signal = notif_bss_info->rssi * 100; - if (unlikely(!cfg80211_inform_bss_frame(wiphy, channel, mgmt, - le16_to_cpu(notif_bss_info->frame_len), - signal, GFP_KERNEL))) { + cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt, + le16_to_cpu(notif_bss_info->frame_len), signal, GFP_KERNEL); + if (unlikely(!cbss)) { WL_ERR(("cfg80211_inform_bss_frame error\n")); kfree(notif_bss_info); return -EINVAL; } + + cfg80211_put_bss(cbss); kfree(notif_bss_info); return err; From af16732d4c98078988755337fb5e197fc31ca77e Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Fri, 2 Dec 2011 13:10:47 -0800 Subject: [PATCH 0464/4025] net: wireless: bcmdhd: Add FW reloading in case of FW hang Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_linux.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 32238ee0e12..4a3365f5d24 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -2296,7 +2296,6 @@ dhd_stop(struct net_device *net) if (ifidx == 0 && !dhd_download_fw_on_driverload) wl_android_wifi_off(net); #endif - dhd->pub.hang_was_sent = 0; dhd->pub.rxcnt_timeout = 0; dhd->pub.txcnt_timeout = 0; OLD_MOD_DEC_USE_COUNT; @@ -2325,6 +2324,8 @@ dhd_open(struct net_device *net) firmware_path[0] = '\0'; } + dhd->pub.hang_was_sent = 0; + #if !defined(WL_CFG80211) /* * Force start if ifconfig_up gets called before START command @@ -4282,6 +4283,8 @@ int net_os_send_hang_message(struct net_device *dev) #endif #if defined(WL_CFG80211) ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); + dev_close(dev); + dev_open(dev); #endif } } From 4f36cb88d6e7e5afcdef42f6d2d70cbffbd2c541 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Fri, 2 Dec 2011 13:24:01 -0800 Subject: [PATCH 0465/4025] net: wireless: bcmdhd: Fix scan crash in ibss mode Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 9c2533028df..7bf42055aaa 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -1461,7 +1461,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, (int)wl->status)); return -EAGAIN; } - if (request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) { + if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) { WL_ERR(("n_ssids > WL_SCAN_PARAMS_SSID_MAX\n")); return -EOPNOTSUPP; } From c561cedf2b6c9d6e7c26ee69dd17c97c0a852a17 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 6 Dec 2011 16:27:37 -0800 Subject: [PATCH 0466/4025] net: wireless: bcmdhd: Allow to push more packets to FW for Tx Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_sdio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 760e2beb7a5..1bdc7d50f1f 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -382,7 +382,7 @@ static bool dhd_readahead; /* To check if there's window offered */ #define DATAOK(bus) \ - (((uint8)(bus->tx_max - bus->tx_seq) > 2) && \ + (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) /* To check if there's window offered for ctrl frame */ From ed3f35608786481035165a3b0321ab0b04768b5d Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 12 Dec 2011 15:40:33 -0800 Subject: [PATCH 0467/4025] net: wireless: bcmdhd: Fix getting arp_hostip table Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index c90bb1676a2..9df70a00dbf 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -1489,7 +1489,7 @@ dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen) return -1; iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen); - retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, TRUE, 0); + retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, 0); if (retcode) { DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n", From f227b88c89e84371e3897207ddab3877f6af6113 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 13 Dec 2011 12:27:49 -0800 Subject: [PATCH 0468/4025] net: wireless: bcmdhd: Decrease event wake_lock timeout to 1500 ms Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd.h | 4 ++-- drivers/net/wireless/bcmdhd/dhd_linux.c | 8 ++++---- drivers/net/wireless/bcmdhd/wl_iw.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index bbb53888144..84d1761a906 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -314,8 +314,8 @@ inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) #define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub) #define DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(pub, val) dhd_os_wake_lock_timeout_enable(pub, val) -#define DHD_PACKET_TIMEOUT 1 -#define DHD_EVENT_TIMEOUT 2 +#define DHD_PACKET_TIMEOUT_MS 1000 +#define DHD_EVENT_TIMEOUT_MS 1500 /* interface operations (register, remove) should be atomic, use this lock to prevent race * condition among wifi on/off and interface operation functions diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 4a3365f5d24..37caa105496 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -1397,7 +1397,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) int i; dhd_if_t *ifp; wl_event_msg_t event; - int tout = DHD_PACKET_TIMEOUT; + int tout = DHD_PACKET_TIMEOUT_MS; DHD_TRACE(("%s: Enter\n", __FUNCTION__)); @@ -1501,7 +1501,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) if (event.event_type == WLC_E_BTA_HCI_EVENT) { dhd_bta_doevt(dhdp, data, event.datalen); } - tout = DHD_EVENT_TIMEOUT; + tout = DHD_EVENT_TIMEOUT_MS; } ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); @@ -2029,7 +2029,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) /* send to dongle only if we are not waiting for reload already */ if (dhd->pub.hang_was_sent) { DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__)); - DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT); + DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); DHD_OS_WAKE_UNLOCK(&dhd->pub); return OSL_ERROR(BCME_DONGLE_DOWN); } @@ -4424,7 +4424,7 @@ int dhd_os_wake_lock_timeout(dhd_pub_t *pub) #ifdef CONFIG_HAS_WAKELOCK if (dhd->wakelock_timeout_enable) wake_lock_timeout(&dhd->wl_rxwake, - dhd->wakelock_timeout_enable * HZ); + msecs_to_jiffies(dhd->wakelock_timeout_enable)); #endif dhd->wakelock_timeout_enable = 0; spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c index ba3cc6c876c..32f7b57d2d4 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/bcmdhd/wl_iw.c @@ -1626,7 +1626,7 @@ wl_iw_send_priv_event( strcpy(extra, flag); wrqu.data.length = strlen(extra); wireless_send_event(dev, cmd, &wrqu, extra); - net_os_wake_lock_timeout_enable(dev, DHD_EVENT_TIMEOUT); + net_os_wake_lock_timeout_enable(dev, DHD_EVENT_TIMEOUT_MS); WL_TRACE(("Send IWEVCUSTOM Event as %s\n", extra)); return 0; From 599c8566fa1f34f297df6c683c23a213ff748d02 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 13 Dec 2011 17:39:48 -0800 Subject: [PATCH 0469/4025] net: wireless: bcmdhd: Fix proper scan command even if request is NULL Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 7bf42055aaa..3ca4df7faed 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -1130,8 +1130,8 @@ wl_cfg80211_notify_ifchange(void) static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_request *request) { - u32 n_ssids = request->n_ssids; - u32 n_channels = request->n_channels; + u32 n_ssids; + u32 n_channels; u16 channel; chanspec_t chanspec; s32 i, offset; @@ -1160,6 +1160,12 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req params->passive_time = htod32(params->passive_time); params->home_time = htod32(params->home_time); + if (!request) + return; + + n_ssids = request->n_ssids; + n_channels = request->n_channels; + /* Copy channel array if applicable */ WL_SCAN(("### List of channelspecs to scan ###\n")); if (n_channels > 0) { @@ -1248,8 +1254,7 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, return -ENOMEM; } - if (request != NULL) - wl_scan_prep(¶ms->params, request); + wl_scan_prep(¶ms->params, request); params->version = htod32(ISCAN_REQ_VERSION); params->action = htod16(action); @@ -1340,8 +1345,7 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, goto exit; } - if (request != NULL) - wl_scan_prep(¶ms->params, request); + wl_scan_prep(¶ms->params, request); params->version = htod32(ESCAN_REQ_VERSION); params->action = htod16(action); params->sync_id = htod16(0x1234); From 37ff4411a5f5ce21feb3825296308f2a767e3662 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Thu, 15 Dec 2011 12:12:20 -0800 Subject: [PATCH 0470/4025] net: wireless: bcm4329: Fix pno_enable if disassociated Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcm4329/dhd_common.c | 43 +++++++++++++++++++---- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/bcm4329/dhd_common.c b/drivers/net/wireless/bcm4329/dhd_common.c index f7cd372d68c..8b89e390a40 100644 --- a/drivers/net/wireless/bcm4329/dhd_common.c +++ b/drivers/net/wireless/bcm4329/dhd_common.c @@ -1896,6 +1896,41 @@ dhd_iscan_get_partial_result(void *dhdp, uint *scan_count) #endif +/* + * returns = TRUE if associated, FALSE if not associated + */ +bool is_associated(dhd_pub_t *dhd, void *bss_buf) +{ + char bssid[ETHER_ADDR_LEN], zbuf[ETHER_ADDR_LEN]; + int ret = -1; + + bzero(bssid, ETHER_ADDR_LEN); + bzero(zbuf, ETHER_ADDR_LEN); + + ret = dhdcdc_set_ioctl(dhd, 0, WLC_GET_BSSID, (char *)bssid, ETHER_ADDR_LEN); + DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret)); + + if (ret == BCME_NOTASSOCIATED) { + DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret)); + } + + if (ret < 0) + return FALSE; + + if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) { + /* STA is assocoated BSSID is non zero */ + + if (bss_buf) { + /* return bss if caller provided buf */ + memcpy(bss_buf, bssid, ETHER_ADDR_LEN); + } + return TRUE; + } else { + DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__)); + return FALSE; + } +} + /* Function to estimate possible DTIM_SKIP value */ int dhd_get_dtim_skip(dhd_pub_t *dhd) { @@ -1979,7 +2014,6 @@ int dhd_pno_clean(dhd_pub_t *dhd) int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) { char iovbuf[128]; - uint8 bssid[6]; int ret = -1; if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) { @@ -1990,12 +2024,7 @@ int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) memset(iovbuf, 0, sizeof(iovbuf)); /* Check if disassoc to enable pno */ - if ((pfn_enabled) && \ - ((ret = dhdcdc_set_ioctl(dhd, 0, WLC_GET_BSSID, \ - (char *)&bssid, ETHER_ADDR_LEN)) == BCME_NOTASSOCIATED)) { - DHD_TRACE(("%s pno enable called in disassoc mode\n", __FUNCTION__)); - } - else if (pfn_enabled) { + if (pfn_enabled && (is_associated(dhd, NULL) == TRUE)) { DHD_ERROR(("%s pno enable called in assoc mode ret=%d\n", \ __FUNCTION__, ret)); return ret; From bbd08c6e95880dfc3bf1fe9b07486beb33a9cdd1 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Fri, 16 Dec 2011 12:54:51 -0800 Subject: [PATCH 0471/4025] net: wireless: bcmdhd: Fix P2P interface removal Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_linux.c | 3 ++ drivers/net/wireless/bcmdhd/wl_cfg80211.c | 43 +++++++++++++++++------ drivers/net/wireless/bcmdhd/wl_cfg80211.h | 9 +++-- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 37caa105496..d4cc56f4043 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -1032,6 +1032,9 @@ dhd_op_if(dhd_if_t *ifp) if (ret < 0) { ifp->set_multicast = FALSE; if (ifp->net) { +#ifdef WL_CFG80211 + wl_cfg80211_post_del((void*)(ifp->net)); +#endif free_netdev(ifp->net); } dhd->iflist[ifp->idx] = NULL; diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 3ca4df7faed..32241d52add 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -16,7 +16,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -589,7 +589,7 @@ static const u32 __wl_cipher_suites[] = { WLAN_CIPHER_SUITE_WEP104, WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, - WLAN_CIPHER_SUITE_AES_CMAC, + WLAN_CIPHER_SUITE_AES_CMAC }; /* There isn't a lot of sense in it, but you can transmit anything you like */ @@ -844,8 +844,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, wl_set_p2p_status(wl, IF_ADD); err = wl_cfgp2p_ifadd(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec); - if (unlikely(err)) + if (unlikely(err)) { + WL_ERR((" virtual iface add failed (%d) \n", err)); return ERR_PTR(-ENOMEM); + } timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, (wl_get_p2p_status(wl, IF_ADD) == false), @@ -860,7 +862,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, } vwdev->wiphy = wl->wdev->wiphy; WL_INFO((" virtual interface(%s) is created memalloc done \n", - wl->p2p->vir_ifname)); + wl->p2p->vir_ifname)); index = alloc_idx_vwdev(wl); wl->vwdev[index] = vwdev; vwdev->iftype = @@ -873,6 +875,8 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, wl_set_drv_status(wl, READY); wl->p2p->vif_created = true; set_mode_by_netdev(wl, _ndev, mode); + WL_DBG((" virtual interface(%s) wl->wdev %p wl->wdev->netdev %p vwdev %p vwdev->netdev %p\n", + wl->p2p->vir_ifname, wl->wdev, wl->wdev->netdev, vwdev, vwdev->netdev)); net_attach = wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION); if (rtnl_is_locked()) { rtnl_unlock(); @@ -927,10 +931,14 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) * ifconfig down and up sequnce, which will reload the fw * however we should cleanup the linux network virtual interfaces */ - dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); - WL_ERR(("Firmware returned an error from p2p_ifdel\n")); - WL_ERR(("try to remove linux virtual interface %s\n", dev->name)); - dhd_del_if(dhd->info, dhd_net2idx(dhd->info, dev)); + /* Request framework to RESET and clean up */ + struct net_device *ndev = wl_to_prmry_ndev(wl); + WL_ERR(("Firmware returned an error (%d) from p2p_ifdel" + "HANG Notification sent to %s dev %p wdev %p ndev %p\n", ret, ndev->name, dev, wl->wdev, wl_to_prmry_ndev(wl))); + wl_cfg80211_hang(ndev, WLAN_REASON_UNSPECIFIED); + } + else { + WL_ERR(("Firmware success from p2p_ifdel dev %p wdev %p ndev %p", dev, wl->wdev, wl_to_prmry_ndev(wl))); } /* Wait for any pending scan req to get aborted from the sysioc context */ @@ -1035,7 +1043,7 @@ int (*_net_attach)(dhd_pub_t *dhdp, int ifidx)) WL_ERR(("net is NULL\n")); return 0; } - if (wl->p2p_supported) { + if (wl->p2p_supported && wl_get_p2p_status(wl, IF_ADD)) { WL_DBG(("IF_ADD event called from dongle, old interface name: %s," "new name: %s\n", ndev->name, wl->p2p->vir_ifname)); /* Assign the net device to CONNECT BSSCFG */ @@ -1047,6 +1055,8 @@ int (*_net_attach)(dhd_pub_t *dhdp, int ifidx)) wl_clr_p2p_status(wl, IF_ADD); wake_up_interruptible(&wl->dongle_event_wait); + } else { + ret = BCME_NOTREADY; } return ret; } @@ -1063,7 +1073,8 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev) return 0; } - if (p2p_is_on(wl) && wl->p2p->vif_created) { + if (p2p_is_on(wl) && wl->p2p->vif_created && + wl_get_p2p_status(wl, IF_DELETING)) { if (wl->scan_request) { /* Abort any pending scan requests */ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; @@ -1096,6 +1107,18 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev) return 0; } +s32 wl_cfg80211_post_del(void* ndev) +{ + int index; + struct wl_priv *wl = wlcfg_drv_priv; + index = get_idx_vwdev_by_netdev(wl, (struct net_device *)ndev); + WL_DBG(("index : %d\n", index)); + if (index >= 0) { + free_vwdev_by_index(wl, index); + } + return 0; +} + s32 wl_cfg80211_is_progress_ifadd(void) { diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index 262335ef99c..232db1b1f83 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -2,13 +2,13 @@ * Linux cfg80211 driver * * Copyright (C) 1999-2011, Broadcom Corporation - * + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,7 +16,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -452,6 +452,7 @@ static inline s32 alloc_idx_vwdev(struct wl_priv *wl) if (wl->vwdev[i] == NULL) return i; } + WL_ERR((" *********alloc_idx_vwdev failed (%d) \n", -1)); return -1; } @@ -462,6 +463,7 @@ static inline s32 get_idx_vwdev_by_netdev(struct wl_priv *wl, struct net_device if ((wl->vwdev[i] != NULL) && (wl->vwdev[i]->netdev == ndev)) return i; } + WL_ERR((" *********get_idx_vwdev_by_netdev failed (%d) \n", -1)); return -1; } @@ -531,6 +533,7 @@ extern s32 wl_cfg80211_down(void); /* dongle down */ extern s32 wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx, int (*_net_attach)(dhd_pub_t *dhdp, int ifidx)); extern s32 wl_cfg80211_notify_ifdel(struct net_device *ndev); +extern s32 wl_cfg80211_post_del(void *ndev); extern s32 wl_cfg80211_is_progress_ifadd(void); extern s32 wl_cfg80211_is_progress_ifchange(void); extern s32 wl_cfg80211_is_progress_ifadd(void); From e1493f1544e804f228efd4a48a843bb1d81d2d2c Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 19 Dec 2011 10:24:09 -0800 Subject: [PATCH 0472/4025] net: wireless: bcmdhd: Enable wlan access on resume for all sdio functions Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c index 726b6391353..0fa2329e2ae 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c @@ -181,11 +181,9 @@ static int bcmsdh_sdmmc_resume(struct device *pdev) { struct sdio_func *func = dev_to_sdio_func(pdev); - if (func->num != 2) - return 0; dhd_mmc_suspend = FALSE; #if defined(OOB_INTR_ONLY) - if (dhd_os_check_if_up(bcmsdh_get_drvdata())) + if ((func->num == 2) && dhd_os_check_if_up(bcmsdh_get_drvdata())) bcmsdh_oob_intr_set(1); #endif smp_mb(); From f16e6fb3e3bbbc279579b3c3def7951787c88a0a Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Thu, 15 Dec 2011 18:40:37 -0800 Subject: [PATCH 0473/4025] Revert "usb: gadget: rndis: don't use dev_get_stats" This reverts commit ffdab0c0c40bab6de78b1952bb07aed221994b73. Not needed anymore in 2.6.39 and 3.0, dev_get_stats has been fixed and may be called from atomic context. See: 1ac9ad1 net: remove dev_txq_stats_fold() --- drivers/usb/gadget/rndis.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 6cea2e17b32..d3cdffea9c8 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -159,25 +159,6 @@ static const u32 oid_supported_list[] = #endif /* RNDIS_PM */ }; -/* HACK: copied from net/core/dev.c to replace dev_get_stats since - * dev_get_stats cannot be called from atomic context */ -static void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64, - const struct net_device_stats *netdev_stats) -{ -#if BITS_PER_LONG == 64 - BUILD_BUG_ON(sizeof(*stats64) != sizeof(*netdev_stats)); - memcpy(stats64, netdev_stats, sizeof(*stats64)); -#else - size_t i, n = sizeof(*stats64) / sizeof(u64); - const unsigned long *src = (const unsigned long *)netdev_stats; - u64 *dst = (u64 *)stats64; - - BUILD_BUG_ON(sizeof(*netdev_stats) / sizeof(unsigned long) != - sizeof(*stats64) / sizeof(u64)); - for (i = 0; i < n; i++) - dst[i] = src[i]; -#endif -} /* NDIS Functions */ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, @@ -190,7 +171,7 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, rndis_query_cmplt_type *resp; struct net_device *net; struct rtnl_link_stats64 temp; - struct rtnl_link_stats64 *stats = &temp; + const struct rtnl_link_stats64 *stats; if (!r) return -ENOMEM; resp = (rndis_query_cmplt_type *)r->buf; @@ -213,7 +194,7 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, resp->InformationBufferOffset = cpu_to_le32(16); net = rndis_per_dev_params[configNr].dev; - netdev_stats_to_stats64(stats, &net->stats); + stats = dev_get_stats(net, &temp); switch (OID) { From 70df35a3564820865db8ddb1b21ef9f92b5ca95c Mon Sep 17 00:00:00 2001 From: David Dillow Date: Thu, 1 Dec 2011 23:26:53 -0500 Subject: [PATCH 0474/4025] ALSA: sis7019 - give slow codecs more time to reset commit fc084e0b930d546872ab23667052499f7daf0fed upstream. There are some AC97 codec and board combinations that have been observed to take a very long time to respond after the cold reset has completed. In one case, more than 350 ms was required. To allow users to have sound on those platforms, we'll wait up to 500ms for the codec to become ready. As a board may have multiple codecs, with some faster than others to reset, we add a module parameter to inform the driver which codecs should be present. Reported-by: KotCzarny Signed-off-by: David Dillow Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/sis7019.c | 64 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 2b5c7a95ae1..5fe840b3666 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -41,6 +41,7 @@ MODULE_SUPPORTED_DEVICE("{{SiS,SiS7019 Audio Accelerator}}"); static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ static int enable = 1; +static int codecs = 1; module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for SiS7019 Audio Accelerator."); @@ -48,6 +49,8 @@ module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator."); module_param(enable, bool, 0444); MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator."); +module_param(codecs, int, 0444); +MODULE_PARM_DESC(codecs, "Set bit to indicate that codec number is expected to be present (default 1)"); static DEFINE_PCI_DEVICE_TABLE(snd_sis7019_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) }, @@ -140,6 +143,9 @@ struct sis7019 { dma_addr_t silence_dma_addr; }; +/* These values are also used by the module param 'codecs' to indicate + * which codecs should be present. + */ #define SIS_PRIMARY_CODEC_PRESENT 0x0001 #define SIS_SECONDARY_CODEC_PRESENT 0x0002 #define SIS_TERTIARY_CODEC_PRESENT 0x0004 @@ -1078,6 +1084,7 @@ static int sis_chip_init(struct sis7019 *sis) { unsigned long io = sis->ioport; void __iomem *ioaddr = sis->ioaddr; + unsigned long timeout; u16 status; int count; int i; @@ -1104,21 +1111,45 @@ static int sis_chip_init(struct sis7019 *sis) while ((inw(io + SIS_AC97_STATUS) & SIS_AC97_STATUS_BUSY) && --count) udelay(1); + /* Command complete, we can let go of the semaphore now. + */ + outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA); + if (!count) + return -EIO; + /* Now that we've finished the reset, find out what's attached. + * There are some codec/board combinations that take an extremely + * long time to come up. 350+ ms has been observed in the field, + * so we'll give them up to 500ms. */ - status = inl(io + SIS_AC97_STATUS); - if (status & SIS_AC97_STATUS_CODEC_READY) - sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT; - if (status & SIS_AC97_STATUS_CODEC2_READY) - sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT; - if (status & SIS_AC97_STATUS_CODEC3_READY) - sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT; - - /* All done, let go of the semaphore, and check for errors + sis->codecs_present = 0; + timeout = msecs_to_jiffies(500) + jiffies; + while (time_before_eq(jiffies, timeout)) { + status = inl(io + SIS_AC97_STATUS); + if (status & SIS_AC97_STATUS_CODEC_READY) + sis->codecs_present |= SIS_PRIMARY_CODEC_PRESENT; + if (status & SIS_AC97_STATUS_CODEC2_READY) + sis->codecs_present |= SIS_SECONDARY_CODEC_PRESENT; + if (status & SIS_AC97_STATUS_CODEC3_READY) + sis->codecs_present |= SIS_TERTIARY_CODEC_PRESENT; + + if (sis->codecs_present == codecs) + break; + + msleep(1); + } + + /* All done, check for errors. */ - outl(SIS_AC97_SEMA_RELEASE, io + SIS_AC97_SEMA); - if (!sis->codecs_present || !count) + if (!sis->codecs_present) { + printk(KERN_ERR "sis7019: could not find any codecs\n"); return -EIO; + } + + if (sis->codecs_present != codecs) { + printk(KERN_WARNING "sis7019: missing codecs, found %0x, expected %0x\n", + sis->codecs_present, codecs); + } /* Let the hardware know that the audio driver is alive, * and enable PCM slots on the AC-link for L/R playback (3 & 4) and @@ -1390,6 +1421,17 @@ static int __devinit snd_sis7019_probe(struct pci_dev *pci, if (!enable) goto error_out; + /* The user can specify which codecs should be present so that we + * can wait for them to show up if they are slow to recover from + * the AC97 cold reset. We default to a single codec, the primary. + * + * We assume that SIS_PRIMARY_*_PRESENT matches bits 0-2. + */ + codecs &= SIS_PRIMARY_CODEC_PRESENT | SIS_SECONDARY_CODEC_PRESENT | + SIS_TERTIARY_CODEC_PRESENT; + if (!codecs) + codecs = SIS_PRIMARY_CODEC_PRESENT; + rc = snd_card_create(index, id, THIS_MODULE, sizeof(*sis), &card); if (rc < 0) goto error_out; From 2a72a47b80bf4dfbdec91889d1d2c4702f134da5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 2 Dec 2011 15:29:12 +0100 Subject: [PATCH 0475/4025] ALSA: hda/realtek - Fix Oops in alc_mux_select() commit cce4aa378a049f4275416ee6302dd24f37b289df upstream. When no imux is available (e.g. a single capture source), alc_auto_init_input_src() may trigger an Oops due to the access to -1. Add a proper zero-check to avoid it. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e7dc0340da6..eb0a141966a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -509,6 +509,8 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, imux = &spec->input_mux[mux_idx]; if (!imux->num_items && mux_idx > 0) imux = &spec->input_mux[0]; + if (!imux->num_items) + return 0; type = get_wcaps_type(get_wcaps(codec, nid)); if (type == AC_WID_AUD_MIX) { From 612e5dbc550f30c787e40b958d351720e72091c6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 5 Dec 2011 21:20:23 +0100 Subject: [PATCH 0476/4025] alarmtimers: Fix time comparison commit c9c024b3f3e07d087974db4c0dc46217fff3a6c0 upstream. The expiry function compares the timer against current time and does not expire the timer when the expiry time is >= now. That's wrong. If the timer is set for now, then it must expire. Make the condition expiry > now for breaking out the loop. Signed-off-by: Thomas Gleixner Acked-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- kernel/time/alarmtimer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c index ea5e1a928d5..8b70c76910a 100644 --- a/kernel/time/alarmtimer.c +++ b/kernel/time/alarmtimer.c @@ -181,7 +181,7 @@ static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer) struct alarm *alarm; ktime_t expired = next->expires; - if (expired.tv64 >= now.tv64) + if (expired.tv64 > now.tv64) break; alarm = container_of(next, struct alarm, node); From ff40cdaf4ca551c43c94da75ab99719781de123a Mon Sep 17 00:00:00 2001 From: "Manjunathappa, Prakash" Date: Thu, 10 Nov 2011 11:43:21 +0530 Subject: [PATCH 0477/4025] ARM: davinci: da850 evm: change audio edma event queue to EVENTQ_0 commit f1b21c525693b0159aed83b5871f2d0f077f208e upstream. On OMAP-L138 platform, EDMA event queue 0 should be used for audio transfers so that they are not starved by video data moving on event queue 1. Commit 48519f0ae03bc7e86b3dc93e56f1334d53803770 (ASoC: davinci: let platform data define edma queue numbers) had a side-effect of changing this behavior by making the driver actually honor the platform data passed. Fix this now by passing event queue 0 as the queue to be used for audio transfers. Signed-off-by: Manjunathappa, Prakash Signed-off-by: Sekhar Nori Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-davinci/board-da850-evm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c index e83cc860c87..f8936174ce8 100644 --- a/arch/arm/mach-davinci/board-da850-evm.c +++ b/arch/arm/mach-davinci/board-da850-evm.c @@ -748,7 +748,7 @@ static struct snd_platform_data da850_evm_snd_data = { .num_serializer = ARRAY_SIZE(da850_iis_serializer_direction), .tdm_slots = 2, .serial_dir = da850_iis_serializer_direction, - .asp_chan_q = EVENTQ_1, + .asp_chan_q = EVENTQ_0, .version = MCASP_VERSION_2, .txnumevt = 1, .rxnumevt = 1, From 5f29f2e19e7c6231559992be25acb2bfb0fa37d9 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 26 Nov 2011 11:39:14 +0100 Subject: [PATCH 0478/4025] arm: mx23: recognise stmp378x as mx23 commit 11357be9246c7d1acf9b37ad54a18b29bbb734be upstream. Adding the machine_is_* line was forgotten when converting mach-stmp378x to mach-mxs. Signed-off-by: Wolfram Sang Signed-off-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-mxs/include/mach/mxs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-mxs/include/mach/mxs.h b/arch/arm/mach-mxs/include/mach/mxs.h index 35a89dd2724..1332f73c9ad 100644 --- a/arch/arm/mach-mxs/include/mach/mxs.h +++ b/arch/arm/mach-mxs/include/mach/mxs.h @@ -30,6 +30,7 @@ */ #define cpu_is_mx23() ( \ machine_is_mx23evk() || \ + machine_is_stmp378x() || \ 0) #define cpu_is_mx28() ( \ machine_is_mx28evk() || \ From ac565b516b8e9b4e8989642f0c41e9d7d230e0da Mon Sep 17 00:00:00 2001 From: Jean-Christophe PLAGNIOL-VILLARD Date: Mon, 28 Nov 2011 12:53:08 +0100 Subject: [PATCH 0479/4025] ARM: at91: fix clock conid for atmel_tcb.1 on 9260/9g20 commit 1808958d27b1250295f01dff4997d8a8814adaab upstream. The conid is supposed to be t0/t1/t2_clk. Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD Acked-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-at91/at91sam9260.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index 7d606b04d31..eeb94785885 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -237,9 +237,9 @@ static struct clk_lookup periph_clocks_lookups[] = { CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk), CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk), CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk), - CLKDEV_CON_DEV_ID("t3_clk", "atmel_tcb.1", &tc3_clk), - CLKDEV_CON_DEV_ID("t4_clk", "atmel_tcb.1", &tc4_clk), - CLKDEV_CON_DEV_ID("t5_clk", "atmel_tcb.1", &tc5_clk), + CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk), + CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk), + CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk), CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk), }; From a43cc03a3c0c1f1eb783b4493ecbf15c7638b7f7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 14 Nov 2011 19:20:49 +0100 Subject: [PATCH 0480/4025] ARM: davinci: dm646x evm: wrong register used in setup_vpif_input_channel_mode commit 83713fc9373be2e943f82e9d36213708c6b0050e upstream. The function setup_vpif_input_channel_mode() used the VSCLKDIS register instead of VIDCLKCTL. This meant that when in HD mode videoport channel 0 used a different clock from channel 1. Clearly a copy-and-paste error. Signed-off-by: Hans Verkuil Acked-by: Manjunath Hadli Signed-off-by: Sekhar Nori Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-davinci/board-dm646x-evm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c index f6ac9ba7487..3cdd23787bd 100644 --- a/arch/arm/mach-davinci/board-dm646x-evm.c +++ b/arch/arm/mach-davinci/board-dm646x-evm.c @@ -563,7 +563,7 @@ static int setup_vpif_input_channel_mode(int mux_mode) int val; u32 value; - if (!vpif_vsclkdis_reg || !cpld_client) + if (!vpif_vidclkctl_reg || !cpld_client) return -ENXIO; val = i2c_smbus_read_byte(cpld_client); @@ -571,7 +571,7 @@ static int setup_vpif_input_channel_mode(int mux_mode) return val; spin_lock_irqsave(&vpif_reg_lock, flags); - value = __raw_readl(vpif_vsclkdis_reg); + value = __raw_readl(vpif_vidclkctl_reg); if (mux_mode) { val &= VPIF_INPUT_TWO_CHANNEL; value |= VIDCH1CLK; @@ -579,7 +579,7 @@ static int setup_vpif_input_channel_mode(int mux_mode) val |= VPIF_INPUT_ONE_CHANNEL; value &= ~VIDCH1CLK; } - __raw_writel(value, vpif_vsclkdis_reg); + __raw_writel(value, vpif_vidclkctl_reg); spin_unlock_irqrestore(&vpif_reg_lock, flags); err = i2c_smbus_write_byte(cpld_client, val); From 4957ef02313c54e372b54fbc9ec6478f791a87cb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 5 Dec 2011 20:50:45 +0000 Subject: [PATCH 0481/4025] ASoC: Provide a more complete DMA driver stub commit cefcc03ffc9527dde56807339edb1719c8dbae5f upstream. Allow userspace applications to do more parameter setting by providing a more complete stub DMA driver specifying a wildcard set of formats and channels and essentially random values for the DMA parameters. This is required for useful runtime operation of the dummy DMA driver until we are able to figure out how to power up links and do hw_params() from DAPM. Sending to stable as without this the dummy driver is not terribly useful. Reported-by: Kyung-Kwee Ryu Tested-by: Kyung-Kwee Ryu Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/soc-utils.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index ec921ec99c2..cd987de341f 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -57,7 +57,36 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) } EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); -static struct snd_soc_platform_driver dummy_platform; +static const struct snd_pcm_hardware dummy_dma_hardware = { + .formats = 0xffffffff, + .channels_min = 1, + .channels_max = UINT_MAX, + + /* Random values to keep userspace happy when checking constraints */ + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, + .buffer_bytes_max = 128*1024, + .period_bytes_min = PAGE_SIZE, + .period_bytes_max = PAGE_SIZE*2, + .periods_min = 2, + .periods_max = 128, +}; + +static int dummy_dma_open(struct snd_pcm_substream *substream) +{ + snd_soc_set_runtime_hwparams(substream, &dummy_dma_hardware); + + return 0; +} + +static struct snd_pcm_ops dummy_dma_ops = { + .open = dummy_dma_open, + .ioctl = snd_pcm_lib_ioctl, +}; + +static struct snd_soc_platform_driver dummy_platform = { + .ops = &dummy_dma_ops, +}; static __devinit int snd_soc_dummy_probe(struct platform_device *pdev) { From 0c5a975756c0c111294d728c683d083a9649b541 Mon Sep 17 00:00:00 2001 From: Claudio Scordino Date: Thu, 8 Dec 2011 14:33:56 -0800 Subject: [PATCH 0482/4025] fs/proc/meminfo.c: fix compilation error commit b53fc7c2974a50913f49e1d800fe904a28c338e3 upstream. Fix the error message "directives may not be used inside a macro argument" which appears when the kernel is compiled for the cris architecture. Signed-off-by: Claudio Scordino Cc: Andrea Arcangeli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/proc/meminfo.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c index ed257d14156..a96282781f9 100644 --- a/fs/proc/meminfo.c +++ b/fs/proc/meminfo.c @@ -131,12 +131,13 @@ static int meminfo_proc_show(struct seq_file *m, void *v) K(i.freeswap), K(global_page_state(NR_FILE_DIRTY)), K(global_page_state(NR_WRITEBACK)), - K(global_page_state(NR_ANON_PAGES) #ifdef CONFIG_TRANSPARENT_HUGEPAGE + K(global_page_state(NR_ANON_PAGES) + global_page_state(NR_ANON_TRANSPARENT_HUGEPAGES) * - HPAGE_PMD_NR + HPAGE_PMD_NR), +#else + K(global_page_state(NR_ANON_PAGES)), #endif - ), K(global_page_state(NR_FILE_MAPPED)), K(global_page_state(NR_SHMEM)), K(global_page_state(NR_SLAB_RECLAIMABLE) + From cd989fe1fe5da572e45468c6dcb361a7d3c63e5c Mon Sep 17 00:00:00 2001 From: Youquan Song Date: Thu, 8 Dec 2011 14:34:16 -0800 Subject: [PATCH 0483/4025] thp: add compound tail page _mapcount when mapped commit b6999b19120931ede364fa3b685e698a61fed31d upstream. With the 3.2-rc kernel, IOMMU 2M pages in KVM works. But when I tried to use IOMMU 1GB pages in KVM, I encountered an oops and the 1GB page failed to be used. The root cause is that 1GB page allocation calls gup_huge_pud() while 2M page calls gup_huge_pmd. If compound pages are used and the page is a tail page, gup_huge_pmd() increases _mapcount to record tail page are mapped while gup_huge_pud does not do that. So when the mapped page is relesed, it will result in kernel oops because the page is not marked mapped. This patch add tail process for compound page in 1GB huge page which keeps the same process as 2M page. Reproduce like: 1. Add grub boot option: hugepagesz=1G hugepages=8 2. mount -t hugetlbfs -o pagesize=1G hugetlbfs /dev/hugepages 3. qemu-kvm -m 2048 -hda os-kvm.img -cpu kvm64 -smp 4 -mem-path /dev/hugepages -net none -device pci-assign,host=07:00.1 kernel BUG at mm/swap.c:114! invalid opcode: 0000 [#1] SMP Call Trace: put_page+0x15/0x37 kvm_release_pfn_clean+0x31/0x36 kvm_iommu_put_pages+0x94/0xb1 kvm_iommu_unmap_memslots+0x80/0xb6 kvm_assign_device+0xba/0x117 kvm_vm_ioctl_assigned_device+0x301/0xa47 kvm_vm_ioctl+0x36c/0x3a2 do_vfs_ioctl+0x49e/0x4e4 sys_ioctl+0x5a/0x7c system_call_fastpath+0x16/0x1b RIP put_compound_page+0xd4/0x168 Signed-off-by: Youquan Song Reviewed-by: Andrea Arcangeli Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/gup.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c index ea305856151..dd74e46828c 100644 --- a/arch/x86/mm/gup.c +++ b/arch/x86/mm/gup.c @@ -201,6 +201,8 @@ static noinline int gup_huge_pud(pud_t pud, unsigned long addr, do { VM_BUG_ON(compound_head(page) != head); pages[*nr] = page; + if (PageTail(page)) + get_huge_page_tail(page); (*nr)++; page++; refs++; From b492a377ac1507a67091c5232afd5ebd1c7c6e25 Mon Sep 17 00:00:00 2001 From: Youquan Song Date: Thu, 8 Dec 2011 14:34:18 -0800 Subject: [PATCH 0484/4025] thp: set compound tail page _count to zero commit 58a84aa92723d1ac3e1cc4e3b0ff49291663f7e1 upstream. Commit 70b50f94f1644 ("mm: thp: tail page refcounting fix") keeps all page_tail->_count zero at all times. But the current kernel does not set page_tail->_count to zero if a 1GB page is utilized. So when an IOMMU 1GB page is used by KVM, it wil result in a kernel oops because a tail page's _count does not equal zero. kernel BUG at include/linux/mm.h:386! invalid opcode: 0000 [#1] SMP Call Trace: gup_pud_range+0xb8/0x19d get_user_pages_fast+0xcb/0x192 ? trace_hardirqs_off+0xd/0xf hva_to_pfn+0x119/0x2f2 gfn_to_pfn_memslot+0x2c/0x2e kvm_iommu_map_pages+0xfd/0x1c1 kvm_iommu_map_memslots+0x7c/0xbd kvm_iommu_map_guest+0xaa/0xbf kvm_vm_ioctl_assigned_device+0x2ef/0xa47 kvm_vm_ioctl+0x36c/0x3a2 do_vfs_ioctl+0x49e/0x4e4 sys_ioctl+0x5a/0x7c system_call_fastpath+0x16/0x1b RIP gup_huge_pud+0xf2/0x159 Signed-off-by: Youquan Song Reviewed-by: Andrea Arcangeli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/hugetlb.c | 1 + mm/page_alloc.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 2b57cd96dd5..80936a118c3 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -575,6 +575,7 @@ static void prep_compound_gigantic_page(struct page *page, unsigned long order) __SetPageHead(page); for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) { __SetPageTail(p); + set_page_count(p, 0); p->first_page = page; } } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 0f50cdb98aa..f3ef1e9ee82 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -355,8 +355,8 @@ void prep_compound_page(struct page *page, unsigned long order) __SetPageHead(page); for (i = 1; i < nr_pages; i++) { struct page *p = page + i; - __SetPageTail(p); + set_page_count(p, 0); p->first_page = page; } } From 5b4993336fe6b14627ab85efde17aea094d333e8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 5 Dec 2011 21:16:06 +0100 Subject: [PATCH 0485/4025] ptp: Fix clock_getres() implementation commit d68fb11c3dae75c8331538dcf083a65e697cc034 upstream. The clock_getres() function must return the resolution in the timespec argument and return 0 for success. Signed-off-by: Thomas Gleixner Acked-by: John Stultz Cc: Richard Cochran Signed-off-by: Greg Kroah-Hartman --- drivers/ptp/ptp_clock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index cf3f9997546..10451a15e82 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -101,7 +101,9 @@ static s32 scaled_ppm_to_ppb(long ppm) static int ptp_clock_getres(struct posix_clock *pc, struct timespec *tp) { - return 1; /* always round timer functions to one nanosecond */ + tp->tv_sec = 0; + tp->tv_nsec = 1; + return 0; } static int ptp_clock_settime(struct posix_clock *pc, const struct timespec *tp) From 21830d75b1b3752a6418157c0abae8a11938d356 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Thu, 8 Dec 2011 14:34:27 -0800 Subject: [PATCH 0486/4025] mm: Ensure that pfn_valid() is called once per pageblock when reserving pageblocks commit d021563888312018ca65681096f62e36c20e63cc upstream. setup_zone_migrate_reserve() expects that zone->start_pfn starts at pageblock_nr_pages aligned pfn otherwise we could access beyond an existing memblock resulting in the following panic if CONFIG_HOLES_IN_ZONE is not configured and we do not check pfn_valid: IP: [] setup_zone_migrate_reserve+0xcd/0x180 *pdpt = 0000000000000000 *pde = f000ff53f000ff53 Oops: 0000 [#1] SMP Pid: 1, comm: swapper Not tainted 3.0.7-0.7-pae #1 VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform EIP: 0060:[] EFLAGS: 00010006 CPU: 0 EIP is at setup_zone_migrate_reserve+0xcd/0x180 EAX: 000c0000 EBX: f5801fc0 ECX: 000c0000 EDX: 00000000 ESI: 000c01fe EDI: 000c01fe EBP: 00140000 ESP: f2475f58 DS: 007b ES: 007b FS: 00d8 GS: 0000 SS: 0068 Process swapper (pid: 1, ti=f2474000 task=f2472cd0 task.ti=f2474000) Call Trace: [] __setup_per_zone_wmarks+0xec/0x160 [] setup_per_zone_wmarks+0xf/0x20 [] init_per_zone_wmark_min+0x27/0x86 [] do_one_initcall+0x2b/0x160 [] kernel_init+0xbe/0x157 [] kernel_thread_helper+0x6/0xd Code: a5 39 f5 89 f7 0f 46 fd 39 cf 76 40 8b 03 f6 c4 08 74 32 eb 91 90 89 c8 c1 e8 0e 0f be 80 80 2f 86 c0 8b 14 85 60 2f 86 c0 89 c8 <2b> 82 b4 12 00 00 c1 e0 05 03 82 ac 12 00 00 8b 00 f6 c4 08 0f EIP: [] setup_zone_migrate_reserve+0xcd/0x180 SS:ESP 0068:f2475f58 CR2: 00000000000012b4 We crashed in pageblock_is_reserved() when accessing pfn 0xc0000 because highstart_pfn = 0x36ffe. The issue was introduced in 3.0-rc1 by 6d3163ce ("mm: check if any page in a pageblock is reserved before marking it MIGRATE_RESERVE"). Make sure that start_pfn is always aligned to pageblock_nr_pages to ensure that pfn_valid s always called at the start of each pageblock. Architectures with holes in pageblocks will be correctly handled by pfn_valid_within in pageblock_is_reserved. Signed-off-by: Michal Hocko Signed-off-by: Mel Gorman Tested-by: Dang Bo Reviewed-by: KAMEZAWA Hiroyuki Cc: Andrea Arcangeli Cc: David Rientjes Cc: Arve Hjnnevg Cc: KOSAKI Motohiro Cc: John Stultz Cc: Dave Hansen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/page_alloc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index f3ef1e9ee82..8439d2a04f2 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -3388,9 +3388,15 @@ static void setup_zone_migrate_reserve(struct zone *zone) unsigned long block_migratetype; int reserve; - /* Get the start pfn, end pfn and the number of blocks to reserve */ + /* + * Get the start pfn, end pfn and the number of blocks to reserve + * We have to be careful to be aligned to pageblock_nr_pages to + * make sure that we always check pfn_valid for the first page in + * the block. + */ start_pfn = zone->zone_start_pfn; end_pfn = start_pfn + zone->spanned_pages; + start_pfn = roundup(start_pfn, pageblock_nr_pages); reserve = roundup(min_wmark_pages(zone), pageblock_nr_pages) >> pageblock_order; From 3a15d7377faf8b10d04febc6c265ecf5f52c2558 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Thu, 8 Dec 2011 14:34:30 -0800 Subject: [PATCH 0487/4025] mm: vmalloc: check for page allocation failure before vmlist insertion commit 1368edf0647ac112d8cfa6ce47257dc950c50f5c upstream. Commit f5252e00 ("mm: avoid null pointer access in vm_struct via /proc/vmallocinfo") adds newly allocated vm_structs to the vmlist after it is fully initialised. Unfortunately, it did not check that __vmalloc_area_node() successfully populated the area. In the event of allocation failure, the vmalloc area is freed but the pointer to freed memory is inserted into the vmlist leading to a a crash later in get_vmalloc_info(). This patch adds a check for ____vmalloc_area_node() failure within __vmalloc_node_range. It does not use "goto fail" as in the previous error path as a warning was already displayed by __vmalloc_area_node() before it called vfree in its failure path. Credit goes to Luciano Chavez for doing all the real work of identifying exactly where the problem was. Signed-off-by: Mel Gorman Reported-by: Luciano Chavez Tested-by: Luciano Chavez Reviewed-by: Rik van Riel Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/vmalloc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/vmalloc.c b/mm/vmalloc.c index 65d5fd2453e..43b44dbadda 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -1648,6 +1648,8 @@ void *__vmalloc_node_range(unsigned long size, unsigned long align, return NULL; addr = __vmalloc_area_node(area, gfp_mask, prot, node, caller); + if (!addr) + return NULL; /* * In this function, newly allocated vm_struct is not added From 58a48c4b50249df1bebcedca479f6faa7091bd0e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 5 Dec 2011 08:43:34 -0500 Subject: [PATCH 0488/4025] fix apparmor dereferencing potentially freed dentry, sanitize __d_path() API commit 02125a826459a6ad142f8d91c5b6357562f96615 upstream. __d_path() API is asking for trouble and in case of apparmor d_namespace_path() getting just that. The root cause is that when __d_path() misses the root it had been told to look for, it stores the location of the most remote ancestor in *root. Without grabbing references. Sure, at the moment of call it had been pinned down by what we have in *path. And if we raced with umount -l, we could have very well stopped at vfsmount/dentry that got freed as soon as prepend_path() dropped vfsmount_lock. It is safe to compare these pointers with pre-existing (and known to be still alive) vfsmount and dentry, as long as all we are asking is "is it the same address?". Dereferencing is not safe and apparmor ended up stepping into that. d_namespace_path() really wants to examine the place where we stopped, even if it's not connected to our namespace. As the result, it looked at ->d_sb->s_magic of a dentry that might've been already freed by that point. All other callers had been careful enough to avoid that, but it's really a bad interface - it invites that kind of trouble. The fix is fairly straightforward, even though it's bigger than I'd like: * prepend_path() root argument becomes const. * __d_path() is never called with NULL/NULL root. It was a kludge to start with. Instead, we have an explicit function - d_absolute_root(). Same as __d_path(), except that it doesn't get root passed and stops where it stops. apparmor and tomoyo are using it. * __d_path() returns NULL on path outside of root. The main caller is show_mountinfo() and that's precisely what we pass root for - to skip those outside chroot jail. Those who don't want that can (and do) use d_path(). * __d_path() root argument becomes const. Everyone agrees, I hope. * apparmor does *NOT* try to use __d_path() or any of its variants when it sees that path->mnt is an internal vfsmount. In that case it's definitely not mounted anywhere and dentry_path() is exactly what we want there. Handling of sysctl()-triggered weirdness is moved to that place. * if apparmor is asked to do pathname relative to chroot jail and __d_path() tells it we it's not in that jail, the sucker just calls d_absolute_path() instead. That's the other remaining caller of __d_path(), BTW. * seq_path_root() does _NOT_ return -ENAMETOOLONG (it's stupid anyway - the normal seq_file logics will take care of growing the buffer and redoing the call of ->show() just fine). However, if it gets path not reachable from root, it returns SEQ_SKIP. The only caller adjusted (i.e. stopped ignoring the return value as it used to do). Reviewed-by: John Johansen ACKed-by: John Johansen Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/dcache.c | 71 +++++++++++++++++++++++--------------- fs/namespace.c | 20 ++++++----- fs/seq_file.c | 6 ++-- include/linux/dcache.h | 3 +- include/linux/fs.h | 1 + security/apparmor/path.c | 65 +++++++++++++++++++--------------- security/tomoyo/realpath.c | 9 +++-- 7 files changed, 105 insertions(+), 70 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index fbdcbca4072..d2f8feb75da 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2487,16 +2487,14 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name) /** * prepend_path - Prepend path string to a buffer * @path: the dentry/vfsmount to report - * @root: root vfsmnt/dentry (may be modified by this function) + * @root: root vfsmnt/dentry * @buffer: pointer to the end of the buffer * @buflen: pointer to buffer length * * Caller holds the rename_lock. - * - * If path is not reachable from the supplied root, then the value of - * root is changed (without modifying refcounts). */ -static int prepend_path(const struct path *path, struct path *root, +static int prepend_path(const struct path *path, + const struct path *root, char **buffer, int *buflen) { struct dentry *dentry = path->dentry; @@ -2531,10 +2529,10 @@ static int prepend_path(const struct path *path, struct path *root, dentry = parent; } -out: if (!error && !slash) error = prepend(buffer, buflen, "/", 1); +out: br_read_unlock(vfsmount_lock); return error; @@ -2548,15 +2546,17 @@ static int prepend_path(const struct path *path, struct path *root, WARN(1, "Root dentry has weird name <%.*s>\n", (int) dentry->d_name.len, dentry->d_name.name); } - root->mnt = vfsmnt; - root->dentry = dentry; + if (!slash) + error = prepend(buffer, buflen, "/", 1); + if (!error) + error = vfsmnt->mnt_ns ? 1 : 2; goto out; } /** * __d_path - return the path of a dentry * @path: the dentry/vfsmount to report - * @root: root vfsmnt/dentry (may be modified by this function) + * @root: root vfsmnt/dentry * @buf: buffer to return value in * @buflen: buffer length * @@ -2567,10 +2567,10 @@ static int prepend_path(const struct path *path, struct path *root, * * "buflen" should be positive. * - * If path is not reachable from the supplied root, then the value of - * root is changed (without modifying refcounts). + * If the path is not reachable from the supplied root, return %NULL. */ -char *__d_path(const struct path *path, struct path *root, +char *__d_path(const struct path *path, + const struct path *root, char *buf, int buflen) { char *res = buf + buflen; @@ -2581,7 +2581,28 @@ char *__d_path(const struct path *path, struct path *root, error = prepend_path(path, root, &res, &buflen); write_sequnlock(&rename_lock); - if (error) + if (error < 0) + return ERR_PTR(error); + if (error > 0) + return NULL; + return res; +} + +char *d_absolute_path(const struct path *path, + char *buf, int buflen) +{ + struct path root = {}; + char *res = buf + buflen; + int error; + + prepend(&res, &buflen, "\0", 1); + write_seqlock(&rename_lock); + error = prepend_path(path, &root, &res, &buflen); + write_sequnlock(&rename_lock); + + if (error > 1) + error = -EINVAL; + if (error < 0) return ERR_PTR(error); return res; } @@ -2589,8 +2610,9 @@ char *__d_path(const struct path *path, struct path *root, /* * same as __d_path but appends "(deleted)" for unlinked files. */ -static int path_with_deleted(const struct path *path, struct path *root, - char **buf, int *buflen) +static int path_with_deleted(const struct path *path, + const struct path *root, + char **buf, int *buflen) { prepend(buf, buflen, "\0", 1); if (d_unlinked(path->dentry)) { @@ -2627,7 +2649,6 @@ char *d_path(const struct path *path, char *buf, int buflen) { char *res = buf + buflen; struct path root; - struct path tmp; int error; /* @@ -2642,9 +2663,8 @@ char *d_path(const struct path *path, char *buf, int buflen) get_fs_root(current->fs, &root); write_seqlock(&rename_lock); - tmp = root; - error = path_with_deleted(path, &tmp, &res, &buflen); - if (error) + error = path_with_deleted(path, &root, &res, &buflen); + if (error < 0) res = ERR_PTR(error); write_sequnlock(&rename_lock); path_put(&root); @@ -2665,7 +2685,6 @@ char *d_path_with_unreachable(const struct path *path, char *buf, int buflen) { char *res = buf + buflen; struct path root; - struct path tmp; int error; if (path->dentry->d_op && path->dentry->d_op->d_dname) @@ -2673,9 +2692,8 @@ char *d_path_with_unreachable(const struct path *path, char *buf, int buflen) get_fs_root(current->fs, &root); write_seqlock(&rename_lock); - tmp = root; - error = path_with_deleted(path, &tmp, &res, &buflen); - if (!error && !path_equal(&tmp, &root)) + error = path_with_deleted(path, &root, &res, &buflen); + if (error > 0) error = prepend_unreachable(&res, &buflen); write_sequnlock(&rename_lock); path_put(&root); @@ -2806,19 +2824,18 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) write_seqlock(&rename_lock); if (!d_unlinked(pwd.dentry)) { unsigned long len; - struct path tmp = root; char *cwd = page + PAGE_SIZE; int buflen = PAGE_SIZE; prepend(&cwd, &buflen, "\0", 1); - error = prepend_path(&pwd, &tmp, &cwd, &buflen); + error = prepend_path(&pwd, &root, &cwd, &buflen); write_sequnlock(&rename_lock); - if (error) + if (error < 0) goto out; /* Unreachable from current root */ - if (!path_equal(&tmp, &root)) { + if (error > 0) { error = prepend_unreachable(&cwd, &buflen); if (error) goto out; diff --git a/fs/namespace.c b/fs/namespace.c index 537dd96bea0..edc1c4aef75 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1048,15 +1048,12 @@ static int show_mountinfo(struct seq_file *m, void *v) if (err) goto out; seq_putc(m, ' '); - seq_path_root(m, &mnt_path, &root, " \t\n\\"); - if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) { - /* - * Mountpoint is outside root, discard that one. Ugly, - * but less so than trying to do that in iterator in a - * race-free way (due to renames). - */ - return SEQ_SKIP; - } + + /* mountpoints outside of chroot jail will give SEQ_SKIP on this */ + err = seq_path_root(m, &mnt_path, &root, " \t\n\\"); + if (err) + goto out; + seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw"); show_mnt_opts(m, mnt); @@ -2725,3 +2722,8 @@ struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data); } EXPORT_SYMBOL_GPL(kern_mount_data); + +bool our_mnt(struct vfsmount *mnt) +{ + return check_mnt(mnt); +} diff --git a/fs/seq_file.c b/fs/seq_file.c index 05d6b0e78c9..dba43c3ea3a 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -449,8 +449,6 @@ EXPORT_SYMBOL(seq_path); /* * Same as seq_path, but relative to supplied root. - * - * root may be changed, see __d_path(). */ int seq_path_root(struct seq_file *m, struct path *path, struct path *root, char *esc) @@ -463,6 +461,8 @@ int seq_path_root(struct seq_file *m, struct path *path, struct path *root, char *p; p = __d_path(path, root, buf, size); + if (!p) + return SEQ_SKIP; res = PTR_ERR(p); if (!IS_ERR(p)) { char *end = mangle_path(buf, p, esc); @@ -474,7 +474,7 @@ int seq_path_root(struct seq_file *m, struct path *path, struct path *root, } seq_commit(m, res); - return res < 0 ? res : 0; + return res < 0 && res != -ENAMETOOLONG ? res : 0; } /* diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 19d90a55541..8f848e462b2 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -340,7 +340,8 @@ extern int d_validate(struct dentry *, struct dentry *); */ extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...); -extern char *__d_path(const struct path *path, struct path *root, char *, int); +extern char *__d_path(const struct path *, const struct path *, char *, int); +extern char *d_absolute_path(const struct path *, char *, int); extern char *d_path(const struct path *, char *, int); extern char *d_path_with_unreachable(const struct path *, char *, int); extern char *dentry_path_raw(struct dentry *, char *, int); diff --git a/include/linux/fs.h b/include/linux/fs.h index b5b97924786..7b17db7c5a6 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1882,6 +1882,7 @@ extern int fd_statfs(int, struct kstatfs *); extern int statfs_by_dentry(struct dentry *, struct kstatfs *); extern int freeze_super(struct super_block *super); extern int thaw_super(struct super_block *super); +extern bool our_mnt(struct vfsmount *mnt); extern int current_umask(void); diff --git a/security/apparmor/path.c b/security/apparmor/path.c index 36cc0cc39e7..b566eba4a65 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c @@ -57,23 +57,44 @@ static int prepend(char **buffer, int buflen, const char *str, int namelen) static int d_namespace_path(struct path *path, char *buf, int buflen, char **name, int flags) { - struct path root, tmp; char *res; - int connected, error = 0; + int error = 0; + int connected = 1; + + if (path->mnt->mnt_flags & MNT_INTERNAL) { + /* it's not mounted anywhere */ + res = dentry_path(path->dentry, buf, buflen); + *name = res; + if (IS_ERR(res)) { + *name = buf; + return PTR_ERR(res); + } + if (path->dentry->d_sb->s_magic == PROC_SUPER_MAGIC && + strncmp(*name, "/sys/", 5) == 0) { + /* TODO: convert over to using a per namespace + * control instead of hard coded /proc + */ + return prepend(name, *name - buf, "/proc", 5); + } + return 0; + } - /* Get the root we want to resolve too, released below */ + /* resolve paths relative to chroot?*/ if (flags & PATH_CHROOT_REL) { - /* resolve paths relative to chroot */ + struct path root; get_fs_root(current->fs, &root); - } else { - /* resolve paths relative to namespace */ - root.mnt = current->nsproxy->mnt_ns->root; - root.dentry = root.mnt->mnt_root; - path_get(&root); + res = __d_path(path, &root, buf, buflen); + if (res && !IS_ERR(res)) { + /* everything's fine */ + *name = res; + path_put(&root); + goto ok; + } + path_put(&root); + connected = 0; } - tmp = root; - res = __d_path(path, &tmp, buf, buflen); + res = d_absolute_path(path, buf, buflen); *name = res; /* handle error conditions - and still allow a partial path to @@ -84,7 +105,10 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, *name = buf; goto out; } + if (!our_mnt(path->mnt)) + connected = 0; +ok: /* Handle two cases: * 1. A deleted dentry && profile is not allowing mediation of deleted * 2. On some filesystems, newly allocated dentries appear to the @@ -97,10 +121,7 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, goto out; } - /* Determine if the path is connected to the expected root */ - connected = tmp.dentry == root.dentry && tmp.mnt == root.mnt; - - /* If the path is not connected, + /* If the path is not connected to the expected root, * check if it is a sysctl and handle specially else remove any * leading / that __d_path may have returned. * Unless @@ -112,17 +133,9 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, * namespace root. */ if (!connected) { - /* is the disconnect path a sysctl? */ - if (tmp.dentry->d_sb->s_magic == PROC_SUPER_MAGIC && - strncmp(*name, "/sys/", 5) == 0) { - /* TODO: convert over to using a per namespace - * control instead of hard coded /proc - */ - error = prepend(name, *name - buf, "/proc", 5); - } else if (!(flags & PATH_CONNECT_PATH) && + if (!(flags & PATH_CONNECT_PATH) && !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) && - (tmp.mnt == current->nsproxy->mnt_ns->root && - tmp.dentry == tmp.mnt->mnt_root))) { + our_mnt(path->mnt))) { /* disconnected path, don't return pathname starting * with '/' */ @@ -133,8 +146,6 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, } out: - path_put(&root); - return error; } diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c index d1e05b04771..a339187cad7 100644 --- a/security/tomoyo/realpath.c +++ b/security/tomoyo/realpath.c @@ -95,7 +95,6 @@ char *tomoyo_realpath_from_path(struct path *path) return NULL; is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode); while (1) { - struct path ns_root = { .mnt = NULL, .dentry = NULL }; char *pos; buf_len <<= 1; kfree(buf); @@ -128,8 +127,12 @@ char *tomoyo_realpath_from_path(struct path *path) /* If we don't have a vfsmount, we can't calculate. */ if (!path->mnt) break; - /* go to whatever namespace root we are under */ - pos = __d_path(path, &ns_root, buf, buf_len); + pos = d_absolute_path(path, buf, buf_len - 1); + /* If path is disconnected, use "[unknown]" instead. */ + if (pos == ERR_PTR(-EINVAL)) { + name = tomoyo_encode("[unknown]"); + break; + } /* Prepend "/proc" prefix if using internal proc vfs mount. */ if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) && (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) { From 2afc2fbeaafb4c9a5ab0f92efa0fa739c95c26e4 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 22 Nov 2011 13:51:33 -0800 Subject: [PATCH 0489/4025] target: Handle 0 correctly in transport_get_sectors_6() commit 9b5cd7f37e1e018432111333e2a67f78ba41edfe upstream. SBC-3 says: A TRANSFER LENGTH field set to zero specifies that 256 logical blocks shall be written. Any other value specifies the number of logical blocks that shall be written. The old code was always just returning the value in the TRANSFER LENGTH byte. Fix this to return 256 if the byte is 0. Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_transport.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 4b9b7169bdd..1340ffd7648 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2777,10 +2777,15 @@ static inline u32 transport_get_sectors_6( /* * Everything else assume TYPE_DISK Sector CDB location. - * Use 8-bit sector value. + * Use 8-bit sector value. SBC-3 says: + * + * A TRANSFER LENGTH field set to zero specifies that 256 + * logical blocks shall be written. Any other value + * specifies the number of logical blocks that shall be + * written. */ type_disk: - return (u32)cdb[4]; + return cdb[4] ? : 256; } static inline u32 transport_get_sectors_10( From b0db8ad8ad0cb8f2980c3bd742f4f95eb24818b4 Mon Sep 17 00:00:00 2001 From: Allen Kay Date: Fri, 14 Oct 2011 12:31:54 -0700 Subject: [PATCH 0490/4025] intel-iommu: fix return value of iommu_unmap() API commit 292827cb164ad00cc7689a21283b1261c0b6daed upstream. iommu_unmap() API expects IOMMU drivers to return the actual page order of the address being unmapped. Previous code was just returning page order passed in from the caller. This patch fixes this problem. Signed-off-by: Allen Kay Signed-off-by: David Woodhouse Signed-off-by: Youquan Song Signed-off-by: Greg Kroah-Hartman --- drivers/pci/intel-iommu.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index f02c34d26d1..4f255c865df 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -817,13 +817,14 @@ static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain, } /* clear last level pte, a tlb flush should be followed */ -static void dma_pte_clear_range(struct dmar_domain *domain, +static int dma_pte_clear_range(struct dmar_domain *domain, unsigned long start_pfn, unsigned long last_pfn) { int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT; unsigned int large_page = 1; struct dma_pte *first_pte, *pte; + int order; BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width); BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width); @@ -847,6 +848,9 @@ static void dma_pte_clear_range(struct dmar_domain *domain, (void *)pte - (void *)first_pte); } while (start_pfn && start_pfn <= last_pfn); + + order = (large_page - 1) * 9; + return order; } /* free page table pages. last level pte should already be cleared */ @@ -3865,14 +3869,15 @@ static int intel_iommu_unmap(struct iommu_domain *domain, { struct dmar_domain *dmar_domain = domain->priv; size_t size = PAGE_SIZE << gfp_order; + int order; - dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT, + order = dma_pte_clear_range(dmar_domain, iova >> VTD_PAGE_SHIFT, (iova + size - 1) >> VTD_PAGE_SHIFT); if (dmar_domain->max_addr == iova + size) dmar_domain->max_addr = iova; - return gfp_order; + return order; } static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain, From c46f906e93c81844de1c41e2e6fc1a6a36131c4f Mon Sep 17 00:00:00 2001 From: Allen Kay Date: Fri, 14 Oct 2011 12:32:17 -0700 Subject: [PATCH 0491/4025] intel-iommu: set iommu_superpage on VM domains to lowest common denominator commit 8140a95d228efbcd64d84150e794761a32463947 upstream. set dmar->iommu_superpage field to the smallest common denominator of super page sizes supported by all active VT-d engines. Initialize this field in intel_iommu_domain_init() API so intel_iommu_map() API will be able to use iommu_superpage field to determine the appropriate super page size to use. Signed-off-by: Allen Kay Signed-off-by: David Woodhouse Signed-off-by: Youquan Song Signed-off-by: Greg Kroah-Hartman --- drivers/pci/intel-iommu.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 4f255c865df..46fa9eb135c 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -578,17 +578,18 @@ static void domain_update_iommu_snooping(struct dmar_domain *domain) static void domain_update_iommu_superpage(struct dmar_domain *domain) { - int i, mask = 0xf; + struct dmar_drhd_unit *drhd; + struct intel_iommu *iommu = NULL; + int mask = 0xf; if (!intel_iommu_superpage) { domain->iommu_superpage = 0; return; } - domain->iommu_superpage = 4; /* 1TiB */ - - for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) { - mask |= cap_super_page_val(g_iommus[i]->cap); + /* set iommu_superpage to the smallest common denominator */ + for_each_active_iommu(iommu, drhd) { + mask &= cap_super_page_val(iommu->cap); if (!mask) { break; } @@ -3744,6 +3745,7 @@ static int intel_iommu_domain_init(struct iommu_domain *domain) vm_domain_exit(dmar_domain); return -ENOMEM; } + domain_update_iommu_cap(dmar_domain); domain->priv = dmar_domain; return 0; From 5341e68f9b6c25c0a062de6d730034640988a605 Mon Sep 17 00:00:00 2001 From: Allen Kay Date: Fri, 14 Oct 2011 12:32:46 -0700 Subject: [PATCH 0492/4025] intel-iommu: fix superpage support in pfn_to_dma_pte() commit 4399c8bf2b9093696fa8160d79712e7346989c46 upstream. If target_level == 0, current code breaks out of the while-loop if SUPERPAGE bit is set. We should also break out if PTE is not present. If we don't do this, KVM calls to iommu_iova_to_phys() will cause pfn_to_dma_pte() to create mapping for 4KiB pages. Signed-off-by: Allen Kay Signed-off-by: David Woodhouse Signed-off-by: Youquan Song Signed-off-by: Greg Kroah-Hartman --- drivers/pci/intel-iommu.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 46fa9eb135c..0ec8930f31b 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -307,6 +307,11 @@ static inline bool dma_pte_present(struct dma_pte *pte) return (pte->val & 3) != 0; } +static inline bool dma_pte_superpage(struct dma_pte *pte) +{ + return (pte->val & (1 << 7)); +} + static inline int first_pte_in_page(struct dma_pte *pte) { return !((unsigned long)pte & ~VTD_PAGE_MASK); @@ -732,29 +737,23 @@ static void free_context_table(struct intel_iommu *iommu) } static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain, - unsigned long pfn, int large_level) + unsigned long pfn, int target_level) { int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT; struct dma_pte *parent, *pte = NULL; int level = agaw_to_level(domain->agaw); - int offset, target_level; + int offset; BUG_ON(!domain->pgd); BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width); parent = domain->pgd; - /* Search pte */ - if (!large_level) - target_level = 1; - else - target_level = large_level; - while (level > 0) { void *tmp_page; offset = pfn_level_offset(pfn, level); pte = &parent[offset]; - if (!large_level && (pte->val & DMA_PTE_LARGE_PAGE)) + if (!target_level && (dma_pte_superpage(pte) || !dma_pte_present(pte))) break; if (level == target_level) break; From 6400c8a382ded237df5dc1605f0d06e7939ff4da Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 18 Nov 2011 10:55:35 -0800 Subject: [PATCH 0493/4025] percpu: fix chunk range calculation commit a855b84c3d8c73220d4d3cd392a7bee7c83de70e upstream. Percpu allocator recorded the cpus which map to the first and last units in pcpu_first/last_unit_cpu respectively and used them to determine the address range of a chunk - e.g. it assumed that the first unit has the lowest address in a chunk while the last unit has the highest address. This simply isn't true. Groups in a chunk can have arbitrary positive or negative offsets from the previous one and there is no guarantee that the first unit occupies the lowest offset while the last one the highest. Fix it by actually comparing unit offsets to determine cpus occupying the lowest and highest offsets. Also, rename pcu_first/last_unit_cpu to pcpu_low/high_unit_cpu to avoid confusion. The chunk address range is used to flush cache on vmalloc area map/unmap and decide whether a given address is in the first chunk by per_cpu_ptr_to_phys() and the bug was discovered by invalid per_cpu_ptr_to_phys() translation for crash_note. Kudos to Dave Young for tracking down the problem. Signed-off-by: Tejun Heo Reported-by: WANG Cong Reported-by: Dave Young Tested-by: Dave Young LKML-Reference: <4EC21F67.10905@redhat.com> Signed-off-by: Thomas Renninger Signed-off-by: Greg Kroah-Hartman --- mm/percpu-vm.c | 12 ++++++------ mm/percpu.c | 34 ++++++++++++++++++++-------------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/mm/percpu-vm.c b/mm/percpu-vm.c index ea534960a04..bfad7246665 100644 --- a/mm/percpu-vm.c +++ b/mm/percpu-vm.c @@ -143,8 +143,8 @@ static void pcpu_pre_unmap_flush(struct pcpu_chunk *chunk, int page_start, int page_end) { flush_cache_vunmap( - pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start), - pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end)); + pcpu_chunk_addr(chunk, pcpu_low_unit_cpu, page_start), + pcpu_chunk_addr(chunk, pcpu_high_unit_cpu, page_end)); } static void __pcpu_unmap_pages(unsigned long addr, int nr_pages) @@ -206,8 +206,8 @@ static void pcpu_post_unmap_tlb_flush(struct pcpu_chunk *chunk, int page_start, int page_end) { flush_tlb_kernel_range( - pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start), - pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end)); + pcpu_chunk_addr(chunk, pcpu_low_unit_cpu, page_start), + pcpu_chunk_addr(chunk, pcpu_high_unit_cpu, page_end)); } static int __pcpu_map_pages(unsigned long addr, struct page **pages, @@ -284,8 +284,8 @@ static void pcpu_post_map_flush(struct pcpu_chunk *chunk, int page_start, int page_end) { flush_cache_vmap( - pcpu_chunk_addr(chunk, pcpu_first_unit_cpu, page_start), - pcpu_chunk_addr(chunk, pcpu_last_unit_cpu, page_end)); + pcpu_chunk_addr(chunk, pcpu_low_unit_cpu, page_start), + pcpu_chunk_addr(chunk, pcpu_high_unit_cpu, page_end)); } /** diff --git a/mm/percpu.c b/mm/percpu.c index bf80e55dbed..93b5a7c96a7 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -116,9 +116,9 @@ static int pcpu_atom_size __read_mostly; static int pcpu_nr_slots __read_mostly; static size_t pcpu_chunk_struct_size __read_mostly; -/* cpus with the lowest and highest unit numbers */ -static unsigned int pcpu_first_unit_cpu __read_mostly; -static unsigned int pcpu_last_unit_cpu __read_mostly; +/* cpus with the lowest and highest unit addresses */ +static unsigned int pcpu_low_unit_cpu __read_mostly; +static unsigned int pcpu_high_unit_cpu __read_mostly; /* the address of the first chunk which starts with the kernel static area */ void *pcpu_base_addr __read_mostly; @@ -984,19 +984,19 @@ phys_addr_t per_cpu_ptr_to_phys(void *addr) { void __percpu *base = __addr_to_pcpu_ptr(pcpu_base_addr); bool in_first_chunk = false; - unsigned long first_start, first_end; + unsigned long first_low, first_high; unsigned int cpu; /* - * The following test on first_start/end isn't strictly + * The following test on unit_low/high isn't strictly * necessary but will speed up lookups of addresses which * aren't in the first chunk. */ - first_start = pcpu_chunk_addr(pcpu_first_chunk, pcpu_first_unit_cpu, 0); - first_end = pcpu_chunk_addr(pcpu_first_chunk, pcpu_last_unit_cpu, - pcpu_unit_pages); - if ((unsigned long)addr >= first_start && - (unsigned long)addr < first_end) { + first_low = pcpu_chunk_addr(pcpu_first_chunk, pcpu_low_unit_cpu, 0); + first_high = pcpu_chunk_addr(pcpu_first_chunk, pcpu_high_unit_cpu, + pcpu_unit_pages); + if ((unsigned long)addr >= first_low && + (unsigned long)addr < first_high) { for_each_possible_cpu(cpu) { void *start = per_cpu_ptr(base, cpu); @@ -1233,7 +1233,9 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, for (cpu = 0; cpu < nr_cpu_ids; cpu++) unit_map[cpu] = UINT_MAX; - pcpu_first_unit_cpu = NR_CPUS; + + pcpu_low_unit_cpu = NR_CPUS; + pcpu_high_unit_cpu = NR_CPUS; for (group = 0, unit = 0; group < ai->nr_groups; group++, unit += i) { const struct pcpu_group_info *gi = &ai->groups[group]; @@ -1253,9 +1255,13 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, unit_map[cpu] = unit + i; unit_off[cpu] = gi->base_offset + i * ai->unit_size; - if (pcpu_first_unit_cpu == NR_CPUS) - pcpu_first_unit_cpu = cpu; - pcpu_last_unit_cpu = cpu; + /* determine low/high unit_cpu */ + if (pcpu_low_unit_cpu == NR_CPUS || + unit_off[cpu] < unit_off[pcpu_low_unit_cpu]) + pcpu_low_unit_cpu = cpu; + if (pcpu_high_unit_cpu == NR_CPUS || + unit_off[cpu] > unit_off[pcpu_high_unit_cpu]) + pcpu_high_unit_cpu = cpu; } } pcpu_nr_units = unit; From 0ea3edaf9ae2cede6f76b08a09981b3e71439e2e Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Fri, 2 Dec 2011 08:19:18 -0800 Subject: [PATCH 0494/4025] iwlwifi: do not re-configure HT40 after associated commit 34a5b4b6af104cf18eb50748509528b9bdbc4036 upstream. The ht40 setting should not change after association unless channel switch This fix a problem we are seeing which cause uCode assert because driver sending invalid information and make uCode confuse Here is the firmware assert message: kernel: iwlagn 0000:03:00.0: Microcode SW error detected. Restarting 0x82000000. kernel: iwlagn 0000:03:00.0: Loaded firmware version: 17.168.5.3 build 42301 kernel: iwlagn 0000:03:00.0: Start IWL Error Log Dump: kernel: iwlagn 0000:03:00.0: Status: 0x000512E4, count: 6 kernel: iwlagn 0000:03:00.0: 0x00002078 | ADVANCED_SYSASSERT kernel: iwlagn 0000:03:00.0: 0x00009514 | uPc kernel: iwlagn 0000:03:00.0: 0x00009496 | branchlink1 kernel: iwlagn 0000:03:00.0: 0x00009496 | branchlink2 kernel: iwlagn 0000:03:00.0: 0x0000D1F2 | interruptlink1 kernel: iwlagn 0000:03:00.0: 0x00000000 | interruptlink2 kernel: iwlagn 0000:03:00.0: 0x01008035 | data1 kernel: iwlagn 0000:03:00.0: 0x0000C90F | data2 kernel: iwlagn 0000:03:00.0: 0x000005A7 | line kernel: iwlagn 0000:03:00.0: 0x5080B520 | beacon time kernel: iwlagn 0000:03:00.0: 0xCC515AE0 | tsf low kernel: iwlagn 0000:03:00.0: 0x00000003 | tsf hi kernel: iwlagn 0000:03:00.0: 0x00000000 | time gp1 kernel: iwlagn 0000:03:00.0: 0x29703BF0 | time gp2 kernel: iwlagn 0000:03:00.0: 0x00000000 | time gp3 kernel: iwlagn 0000:03:00.0: 0x000111A8 | uCode version kernel: iwlagn 0000:03:00.0: 0x000000B0 | hw version kernel: iwlagn 0000:03:00.0: 0x00480303 | board version kernel: iwlagn 0000:03:00.0: 0x09E8004E | hcmd kernel: iwlagn 0000:03:00.0: CSR values: kernel: iwlagn 0000:03:00.0: (2nd byte of CSR_INT_COALESCING is CSR_INT_PERIODIC_REG) kernel: iwlagn 0000:03:00.0: CSR_HW_IF_CONFIG_REG: 0X00480303 kernel: iwlagn 0000:03:00.0: CSR_INT_COALESCING: 0X0000ff40 kernel: iwlagn 0000:03:00.0: CSR_INT: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_INT_MASK: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_FH_INT_STATUS: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_GPIO_IN: 0X00000030 kernel: iwlagn 0000:03:00.0: CSR_RESET: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_GP_CNTRL: 0X080403c5 kernel: iwlagn 0000:03:00.0: CSR_HW_REV: 0X000000b0 kernel: iwlagn 0000:03:00.0: CSR_EEPROM_REG: 0X07d60ffd kernel: iwlagn 0000:03:00.0: CSR_EEPROM_GP: 0X90000001 kernel: iwlagn 0000:03:00.0: CSR_OTP_GP_REG: 0X00030001 kernel: iwlagn 0000:03:00.0: CSR_GIO_REG: 0X00080044 kernel: iwlagn 0000:03:00.0: CSR_GP_UCODE_REG: 0X000093bb kernel: iwlagn 0000:03:00.0: CSR_GP_DRIVER_REG: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_UCODE_DRV_GP1: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_UCODE_DRV_GP2: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_LED_REG: 0X00000078 kernel: iwlagn 0000:03:00.0: CSR_DRAM_INT_TBL_REG: 0X88214dd2 kernel: iwlagn 0000:03:00.0: CSR_GIO_CHICKEN_BITS: 0X27800200 kernel: iwlagn 0000:03:00.0: CSR_ANA_PLL_CFG: 0X00000000 kernel: iwlagn 0000:03:00.0: CSR_HW_REV_WA_REG: 0X0001001a kernel: iwlagn 0000:03:00.0: CSR_DBG_HPET_MEM_REG: 0Xffff0010 kernel: iwlagn 0000:03:00.0: FH register values: kernel: iwlagn 0000:03:00.0: FH_RSCSR_CHNL0_STTS_WPTR_REG: 0X21316d00 kernel: iwlagn 0000:03:00.0: FH_RSCSR_CHNL0_RBDCB_BASE_REG: 0X021479c0 kernel: iwlagn 0000:03:00.0: FH_RSCSR_CHNL0_WPTR: 0X00000060 kernel: iwlagn 0000:03:00.0: FH_MEM_RCSR_CHNL0_CONFIG_REG: 0X80819104 kernel: iwlagn 0000:03:00.0: FH_MEM_RSSR_SHARED_CTRL_REG: 0X000000fc kernel: iwlagn 0000:03:00.0: FH_MEM_RSSR_RX_STATUS_REG: 0X07030000 kernel: iwlagn 0000:03:00.0: FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV: 0X00000000 kernel: iwlagn 0000:03:00.0: FH_TSSR_TX_STATUS_REG: 0X07ff0001 kernel: iwlagn 0000:03:00.0: FH_TSSR_TX_ERROR_REG: 0X00000000 kernel: iwlagn 0000:03:00.0: Start IWL Event Log Dump: display last 20 entries kernel: ------------[ cut here ]------------ WARNING: at net/mac80211/util.c:1208 ieee80211_reconfig+0x1f1/0x407() kernel: Hardware name: 4290W4H kernel: Pid: 1896, comm: kworker/0:0 Not tainted 3.1.0 #2 kernel: Call Trace: kernel: [] ? warn_slowpath_common+0x73/0x87 kernel: [] ? ieee80211_reconfig+0x1f1/0x407 kernel: [] ? ieee80211_recalc_smps_work+0x32/0x32 kernel: [] ? ieee80211_restart_work+0x7e/0x87 kernel: [] ? process_one_work+0x1c8/0x2e3 kernel: [] ? worker_thread+0x17a/0x23a kernel: [] ? manage_workers.clone.18+0x15b/0x15b kernel: [] ? manage_workers.clone.18+0x15b/0x15b kernel: [] ? kthread+0x7a/0x82 kernel: [] ? kernel_thread_helper+0x4/0x10 kernel: [] ? kthread_flush_work_fn+0x11/0x11 kernel: [] ? gs_change+0xb/0xb Reported-by: Udo Steinberg Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 36 +++++++++++++-------- drivers/net/wireless/iwlwifi/iwl-agn.c | 18 ++--------- drivers/net/wireless/iwlwifi/iwl-agn.h | 2 ++ 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 09f679d6046..b849ad79e14 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -411,6 +411,24 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return 0; } +void iwlagn_config_ht40(struct ieee80211_conf *conf, + struct iwl_rxon_context *ctx) +{ + if (conf_is_ht40_minus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_BELOW; + ctx->ht.is_40mhz = true; + } else if (conf_is_ht40_plus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + ctx->ht.is_40mhz = true; + } else { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_NONE; + ctx->ht.is_40mhz = false; + } +} + int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl_priv *priv = hw->priv; @@ -470,19 +488,11 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) ctx->ht.enabled = conf_is_ht(conf); if (ctx->ht.enabled) { - if (conf_is_ht40_minus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_BELOW; - ctx->ht.is_40mhz = true; - } else if (conf_is_ht40_plus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - ctx->ht.is_40mhz = true; - } else { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_NONE; - ctx->ht.is_40mhz = false; - } + /* if HT40 is used, it should not change + * after associated except channel switch */ + if (iwl_is_associated_ctx(ctx) && + !ctx->ht.is_40mhz) + iwlagn_config_ht40(conf, ctx); } else ctx->ht.is_40mhz = false; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index baec52d191b..67d4c2d948d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2872,21 +2872,9 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, /* Configure HT40 channels */ ctx->ht.enabled = conf_is_ht(conf); - if (ctx->ht.enabled) { - if (conf_is_ht40_minus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_BELOW; - ctx->ht.is_40mhz = true; - } else if (conf_is_ht40_plus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - ctx->ht.is_40mhz = true; - } else { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_NONE; - ctx->ht.is_40mhz = false; - } - } else + if (ctx->ht.enabled) + iwlagn_config_ht40(conf, ctx); + else ctx->ht.is_40mhz = false; if ((le16_to_cpu(ctx->staging.channel) != ch)) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index d1716844002..5a0acab0bbc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -152,6 +152,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes); +void iwlagn_config_ht40(struct ieee80211_conf *conf, + struct iwl_rxon_context *ctx); /* uCode */ void iwlagn_rx_calib_result(struct iwl_priv *priv, From 5009514a0967db0060656c70de812b8643417da7 Mon Sep 17 00:00:00 2001 From: Nikolay Martynov Date: Sat, 10 Dec 2011 17:31:23 +0100 Subject: [PATCH 0495/4025] mac80211: fix race condition caused by late addBA response Upstream commit d305a6557b2c4dca0110f05ffe745b1ef94adb80. If addBA responses comes in just after addba_resp_timer has expired mac80211 will still accept it and try to open the aggregation session. This causes drivers to be confused and in some cases even crash. This patch fixes the race condition and makes sure that if addba_resp_timer has expired addBA response is not longer accepted and we do not try to open half-closed session. Signed-off-by: Nikolay Martynov [some adjustments] Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/agg-tx.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 42a59c260e8..db7db43ccf4 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -792,12 +792,27 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, goto out; } - del_timer(&tid_tx->addba_resp_timer); + del_timer_sync(&tid_tx->addba_resp_timer); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "switched off addBA timer for tid %d\n", tid); #endif + /* + * addba_resp_timer may have fired before we got here, and + * caused WANT_STOP to be set. If the stop then was already + * processed further, STOPPING might be set. + */ + if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) || + test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG + "got addBA resp for tid %d but we already gave up\n", + tid); +#endif + goto out; + } + if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) == WLAN_STATUS_SUCCESS) { /* From c1f95ce58fb4257de087ab89343adea9a47c2144 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 12 Dec 2011 22:06:55 -0800 Subject: [PATCH 0496/4025] linux/log2.h: Fix rounddown_pow_of_two(1) commit 13c07b0286d340275f2d97adf085cecda37ede37 upstream. Exactly like roundup_pow_of_two(1), the rounddown version was buggy for the case of a compile-time constant '1' argument. Probably because it originated from the same code, sharing history with the roundup version from before the bugfix (for that one, see commit 1a06a52ee1b0: "Fix roundup_pow_of_two(1)"). However, unlike the roundup version, the fix for rounddown is to just remove the broken special case entirely. It's simply not needed - the generic code 1UL << ilog2(n) does the right thing for the constant '1' argment too. The only reason roundup needed that special case was because rounding up does so by subtracting one from the argument (and then adding one to the result) causing the obvious problems with "ilog2(0)". But rounddown doesn't do any of that, since ilog2() naturally truncates (ie "rounds down") to the right rounded down value. And without the ilog2(0) case, there's no reason for the special case that had the wrong value. tl;dr: rounddown_pow_of_two(1) should be 1, not 0. Acked-by: Dmitry Torokhov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/log2.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/linux/log2.h b/include/linux/log2.h index 25b808631cd..fd7ff3d91e6 100644 --- a/include/linux/log2.h +++ b/include/linux/log2.h @@ -185,7 +185,6 @@ unsigned long __rounddown_pow_of_two(unsigned long n) #define rounddown_pow_of_two(n) \ ( \ __builtin_constant_p(n) ? ( \ - (n == 1) ? 0 : \ (1UL << ilog2(n))) : \ __rounddown_pow_of_two(n) \ ) From cadacbdef368bb32b8da3e9b46fc2a4b2ba751c7 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 8 Dec 2011 08:04:12 -0500 Subject: [PATCH 0497/4025] hwmon: (jz4740) fix signedness bug commit 0b57d7602b68f7b2786b2f0e22da39cbd4139a95 upstream. wait_for_completion_interruptible_timeout() may return negative value. In this case, checking if (t > 0) will return true if t is unsigned. Signed-off-by: Axel Lin Acked-by: Lars-Peter Clausen Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/jz4740-hwmon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c index fea292d4340..b65a4dae3f5 100644 --- a/drivers/hwmon/jz4740-hwmon.c +++ b/drivers/hwmon/jz4740-hwmon.c @@ -59,7 +59,7 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev, { struct jz4740_hwmon *hwmon = dev_get_drvdata(dev); struct completion *completion = &hwmon->read_completion; - unsigned long t; + long t; unsigned long val; int ret; From 53824693961bf513fe152d35c887e83eb016eaea Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 11 Nov 2011 16:28:05 +0100 Subject: [PATCH 0498/4025] mmc: mxcmmc: fix falling back to PIO commit e58f516ff4730c4047c3f104b061f7a03e9a263c upstream. When we can't configure the dma channel we want to fall back to PIO. We do this by setting host->do_dma to zero. This does not work as do_dma is used to see whether dma can be used for the current transfer. Instead, we have to set host->dma to NULL. Signed-off-by: Sascha Hauer Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/mxcmmc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index cc20e025932..e12fbc510bb 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -731,6 +731,7 @@ static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) "failed to config DMA channel. Falling back to PIO\n"); dma_release_channel(host->dma); host->do_dma = 0; + host->dma = NULL; } } From f4347eb6d2aae437d9552a26704bcb07f4626d6c Mon Sep 17 00:00:00 2001 From: Mark Langsdorf Date: Fri, 18 Nov 2011 16:33:06 +0100 Subject: [PATCH 0499/4025] x86, hpet: Immediately disable HPET timer 1 if rtc irq is masked commit 2ded6e6a94c98ea453a156748cb7fabaf39a76b9 upstream. When HPET is operating in RTC mode, the TN_ENABLE bit on timer1 controls whether the HPET or the RTC delivers interrupts to irq8. When the system goes into suspend, the RTC driver sends a signal to the HPET driver so that the HPET releases control of irq8, allowing the RTC to wake the system from suspend. The switchover is accomplished by a write to the HPET configuration registers which currently only occurs while servicing the HPET interrupt. On some systems, I have seen the system suspend before an HPET interrupt occurs, preventing the write to the HPET configuration register and leaving the HPET in control of the irq8. As the HPET is not active during suspend, it does not generate a wake signal and RTC alarms do not work. This patch forces the HPET driver to immediately transfer control of the irq8 channel to the RTC instead of waiting until the next interrupt event. Signed-off-by: Mark Langsdorf Link: http://lkml.kernel.org/r/20111118153306.GB16319@alberich.amd.com Tested-by: Andreas Herrmann Signed-off-by: Andreas Herrmann Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/hpet.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 6781765b3a0..aa083d35074 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c @@ -1054,6 +1054,14 @@ int hpet_rtc_timer_init(void) } EXPORT_SYMBOL_GPL(hpet_rtc_timer_init); +static void hpet_disable_rtc_channel(void) +{ + unsigned long cfg; + cfg = hpet_readl(HPET_T1_CFG); + cfg &= ~HPET_TN_ENABLE; + hpet_writel(cfg, HPET_T1_CFG); +} + /* * The functions below are called from rtc driver. * Return 0 if HPET is not being used. @@ -1065,6 +1073,9 @@ int hpet_mask_rtc_irq_bit(unsigned long bit_mask) return 0; hpet_rtc_flags &= ~bit_mask; + if (unlikely(!hpet_rtc_flags)) + hpet_disable_rtc_channel(); + return 1; } EXPORT_SYMBOL_GPL(hpet_mask_rtc_irq_bit); @@ -1130,15 +1141,11 @@ EXPORT_SYMBOL_GPL(hpet_rtc_dropped_irq); static void hpet_rtc_timer_reinit(void) { - unsigned int cfg, delta; + unsigned int delta; int lost_ints = -1; - if (unlikely(!hpet_rtc_flags)) { - cfg = hpet_readl(HPET_T1_CFG); - cfg &= ~HPET_TN_ENABLE; - hpet_writel(cfg, HPET_T1_CFG); - return; - } + if (unlikely(!hpet_rtc_flags)) + hpet_disable_rtc_channel(); if (!(hpet_rtc_flags & RTC_PIE) || hpet_pie_limit) delta = hpet_default_delta; From b98eb43012d8679aa6c9e5527a7cc5706ee192f6 Mon Sep 17 00:00:00 2001 From: Eryu Guan Date: Tue, 1 Nov 2011 19:04:59 -0400 Subject: [PATCH 0500/4025] jbd/jbd2: validate sb->s_first in journal_get_superblock() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 8762202dd0d6e46854f786bdb6fb3780a1625efe upstream. I hit a J_ASSERT(blocknr != 0) failure in cleanup_journal_tail() when mounting a fsfuzzed ext3 image. It turns out that the corrupted ext3 image has s_first = 0 in journal superblock, and the 0 is passed to journal->j_head in journal_reset(), then to blocknr in cleanup_journal_tail(), in the end the J_ASSERT failed. So validate s_first after reading journal superblock from disk in journal_get_superblock() to ensure s_first is valid. The following script could reproduce it: fstype=ext3 blocksize=1024 img=$fstype.img offset=0 found=0 magic="c0 3b 39 98" dd if=/dev/zero of=$img bs=1M count=8 mkfs -t $fstype -b $blocksize -F $img filesize=`stat -c %s $img` while [ $offset -lt $filesize ] do if od -j $offset -N 4 -t x1 $img | grep -i "$magic";then echo "Found journal: $offset" found=1 break fi offset=`echo "$offset+$blocksize" | bc` done if [ $found -ne 1 ];then echo "Magic \"$magic\" not found" exit 1 fi dd if=/dev/zero of=$img seek=$(($offset+23)) conv=notrunc bs=1 count=1 mkdir -p ./mnt mount -o loop $img ./mnt Cc: Jan Kara Signed-off-by: Eryu Guan Signed-off-by: "Theodore Ts'o" Cc: Moritz Mühlenhoff Signed-off-by: Greg Kroah-Hartman --- fs/jbd/journal.c | 8 ++++++++ fs/jbd2/journal.c | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index e2d4285fbe9..9f36384e2e8 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -1131,6 +1131,14 @@ static int journal_get_superblock(journal_t *journal) goto out; } + if (be32_to_cpu(sb->s_first) == 0 || + be32_to_cpu(sb->s_first) >= journal->j_maxlen) { + printk(KERN_WARNING + "JBD: Invalid start block of journal: %u\n", + be32_to_cpu(sb->s_first)); + goto out; + } + return 0; out: diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 0dfa5b598e6..40c5fb73e9c 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1251,6 +1251,14 @@ static int journal_get_superblock(journal_t *journal) goto out; } + if (be32_to_cpu(sb->s_first) == 0 || + be32_to_cpu(sb->s_first) >= journal->j_maxlen) { + printk(KERN_WARNING + "JBD2: Invalid start block of journal: %u\n", + be32_to_cpu(sb->s_first)); + goto out; + } + return 0; out: From b2c51348a4e6b08bb493b2b33d06df89d1a9a0bc Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 19 Sep 2011 17:04:37 -0700 Subject: [PATCH 0501/4025] Make TASKSTATS require root access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 1a51410abe7d0ee4b1d112780f46df87d3621043 upstream. Ok, this isn't optimal, since it means that 'iotop' needs admin capabilities, and we may have to work on this some more. But at the same time it is very much not acceptable to let anybody just read anybody elses IO statistics quite at this level. Use of the GENL_ADMIN_PERM suggested by Johannes Berg as an alternative to checking the capabilities by hand. Reported-by: Vasiliy Kulikov Cc: Johannes Berg Acked-by: Balbir Singh Signed-off-by: Linus Torvalds Cc: Moritz Mühlenhoff Signed-off-by: Greg Kroah-Hartman --- kernel/taskstats.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/taskstats.c b/kernel/taskstats.c index fc0f2200541..8d597b19f13 100644 --- a/kernel/taskstats.c +++ b/kernel/taskstats.c @@ -657,6 +657,7 @@ static struct genl_ops taskstats_ops = { .cmd = TASKSTATS_CMD_GET, .doit = taskstats_user_cmd, .policy = taskstats_cmd_get_policy, + .flags = GENL_ADMIN_PERM, }; static struct genl_ops cgroupstats_ops = { From 70f2545d9e75f9d8ed4bfe0a6efa232abd88806e Mon Sep 17 00:00:00 2001 From: Phillip Lougher Date: Wed, 2 Nov 2011 13:38:01 -0700 Subject: [PATCH 0502/4025] hfs: fix hfs_find_init() sb->ext_tree NULL ptr oops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 434a964daa14b9db083ce20404a4a2add54d037a upstream. Clement Lecigne reports a filesystem which causes a kernel oops in hfs_find_init() trying to dereference sb->ext_tree which is NULL. This proves to be because the filesystem has a corrupted MDB extent record, where the extents file does not fit into the first three extents in the file record (the first blocks). In hfs_get_block() when looking up the blocks for the extent file (HFS_EXT_CNID), it fails the first blocks special case, and falls through to the extent code (which ultimately calls hfs_find_init()) which is in the process of being initialised. Hfs avoids this scenario by always having the extents b-tree fitting into the first blocks (the extents B-tree can't have overflow extents). The fix is to check at mount time that the B-tree fits into first blocks, i.e. fail if HFS_I(inode)->alloc_blocks >= HFS_I(inode)->first_blocks Note, the existing commit 47f365eb57573 ("hfs: fix oops on mount with corrupted btree extent records") becomes subsumed into this as a special case, but only for the extents B-tree (HFS_EXT_CNID), it is perfectly acceptable for the catalog B-Tree file to grow beyond three extents, with the remaining extent descriptors in the extents overfow. This fixes CVE-2011-2203 Reported-by: Clement LECIGNE Signed-off-by: Phillip Lougher Cc: Jeff Mahoney Cc: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Moritz Mühlenhoff Signed-off-by: Greg Kroah-Hartman --- fs/hfs/btree.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c index 3ebc437736f..1cbdeea1db4 100644 --- a/fs/hfs/btree.c +++ b/fs/hfs/btree.c @@ -46,11 +46,26 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke case HFS_EXT_CNID: hfs_inode_read_fork(tree->inode, mdb->drXTExtRec, mdb->drXTFlSize, mdb->drXTFlSize, be32_to_cpu(mdb->drXTClpSiz)); + if (HFS_I(tree->inode)->alloc_blocks > + HFS_I(tree->inode)->first_blocks) { + printk(KERN_ERR "hfs: invalid btree extent records\n"); + unlock_new_inode(tree->inode); + goto free_inode; + } + tree->inode->i_mapping->a_ops = &hfs_btree_aops; break; case HFS_CAT_CNID: hfs_inode_read_fork(tree->inode, mdb->drCTExtRec, mdb->drCTFlSize, mdb->drCTFlSize, be32_to_cpu(mdb->drCTClpSiz)); + + if (!HFS_I(tree->inode)->first_blocks) { + printk(KERN_ERR "hfs: invalid btree extent records " + "(0 size).\n"); + unlock_new_inode(tree->inode); + goto free_inode; + } + tree->inode->i_mapping->a_ops = &hfs_btree_aops; break; default: @@ -59,11 +74,6 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke } unlock_new_inode(tree->inode); - if (!HFS_I(tree->inode)->first_blocks) { - printk(KERN_ERR "hfs: invalid btree extent records (0 size).\n"); - goto free_inode; - } - mapping = tree->inode->i_mapping; page = read_mapping_page(mapping, 0, NULL); if (IS_ERR(page)) From ccd5790e5f7fdc113f50a3d10c97446243d7e2fb Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 13 Dec 2011 10:45:55 +0100 Subject: [PATCH 0503/4025] hwmon: (coretemp) Fix oops on CPU offlining This is for stable kernel branch 3.0 only. Previous and later versions have different code paths and are not affected by this bug. This is the same fix as "hwmon: (coretemp) Fix oops on driver load" but for the CPU offlining case. Sorry for missing it at first. Signed-off-by: Jean Delvare Cc: Durgadoss R Acked-by: Guenter Roeck Cc: Fenghua Yu Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/coretemp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 835ae427d85..6163cfa95c3 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -747,6 +747,8 @@ static void __cpuinit put_core_offline(unsigned int cpu) return; pdata = platform_get_drvdata(pdev); + if (!pdata) + return; indx = TO_ATTR_NO(cpu); From 898726cbefbc1726a759874345b44f046e198d03 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 12 Dec 2011 17:22:29 -0500 Subject: [PATCH 0504/4025] xfs: fix nfs export of 64-bit inodes numbers on 32-bit kernels commit c29f7d457ac63311feb11928a866efd2fe153d74 upstream. The i_ino field in the VFS inode is of type unsigned long and thus can't hold the full 64-bit inode number on 32-bit kernels. We have the full inode number in the XFS inode, so use that one for nfs exports. Note that I've also switched the 32-bit file handles types to it, just to make the code more consistent and copy & paste errors less likely to happen. Reported-by: Guoquan Yang Reported-by: Hank Peng Signed-off-by: Christoph Hellwig Signed-off-by: Ben Myers Signed-off-by: Greg Kroah-Hartman --- fs/xfs/linux-2.6/xfs_export.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c index f4f878fc008..fed3f3c878c 100644 --- a/fs/xfs/linux-2.6/xfs_export.c +++ b/fs/xfs/linux-2.6/xfs_export.c @@ -98,22 +98,22 @@ xfs_fs_encode_fh( switch (fileid_type) { case FILEID_INO32_GEN_PARENT: spin_lock(&dentry->d_lock); - fid->i32.parent_ino = dentry->d_parent->d_inode->i_ino; + fid->i32.parent_ino = XFS_I(dentry->d_parent->d_inode)->i_ino; fid->i32.parent_gen = dentry->d_parent->d_inode->i_generation; spin_unlock(&dentry->d_lock); /*FALLTHRU*/ case FILEID_INO32_GEN: - fid->i32.ino = inode->i_ino; + fid->i32.ino = XFS_I(inode)->i_ino; fid->i32.gen = inode->i_generation; break; case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG: spin_lock(&dentry->d_lock); - fid64->parent_ino = dentry->d_parent->d_inode->i_ino; + fid64->parent_ino = XFS_I(dentry->d_parent->d_inode)->i_ino; fid64->parent_gen = dentry->d_parent->d_inode->i_generation; spin_unlock(&dentry->d_lock); /*FALLTHRU*/ case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG: - fid64->ino = inode->i_ino; + fid64->ino = XFS_I(inode)->i_ino; fid64->gen = inode->i_generation; break; } From bf3673c5e33ba214af62e1cd9d4a333eb61e650f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 12 Dec 2011 17:22:46 -0500 Subject: [PATCH 0505/4025] xfs: avoid synchronous transactions when deleting attr blocks commit 859f57ca00805e6c482eef1a7ab073097d02c8ca upstream. [slightly different from the upstream version because of a previous cleanup] Currently xfs_attr_inactive causes a synchronous transactions if we are removing a file that has any extents allocated to the attribute fork, and thus makes XFS extremely slow at removing files with out of line extended attributes. The code looks a like a relict from the days before the busy extent list, but with the busy extent list we avoid reusing data and attr extents that have been freed but not commited yet, so this code is just as superflous as the synchronous transactions for data blocks. Signed-off-by: Christoph Hellwig Reported-by: Bernd Schubert Reviewed-by: Dave Chinner Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_attr.c | 14 +++----------- fs/xfs/xfs_bmap.c | 10 +--------- fs/xfs/xfs_inode.c | 8 -------- 3 files changed, 4 insertions(+), 28 deletions(-) diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index 01d2072fb6d..99d4011602e 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c @@ -822,17 +822,9 @@ xfs_attr_inactive(xfs_inode_t *dp) error = xfs_attr_root_inactive(&trans, dp); if (error) goto out; - /* - * signal synchronous inactive transactions unless this - * is a synchronous mount filesystem in which case we - * know that we're here because we've been called out of - * xfs_inactive which means that the last reference is gone - * and the unlink transaction has already hit the disk so - * async inactive transactions are safe. - */ - if ((error = xfs_itruncate_finish(&trans, dp, 0LL, XFS_ATTR_FORK, - (!(mp->m_flags & XFS_MOUNT_WSYNC) - ? 1 : 0)))) + + error = xfs_itruncate_finish(&trans, dp, 0LL, XFS_ATTR_FORK, 0); + if (error) goto out; /* diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index e546a33214c..a175933a7f4 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -3785,19 +3785,11 @@ xfs_bmap_compute_maxlevels( * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi * caller. Frees all the extents that need freeing, which must be done * last due to locking considerations. We never free any extents in - * the first transaction. This is to allow the caller to make the first - * transaction a synchronous one so that the pointers to the data being - * broken in this transaction will be permanent before the data is actually - * freed. This is necessary to prevent blocks from being reallocated - * and written to before the free and reallocation are actually permanent. - * We do not just make the first transaction synchronous here, because - * there are more efficient ways to gain the same protection in some cases - * (see the file truncation code). + * the first transaction. * * Return 1 if the given transaction was committed and a new one * started, and 0 otherwise in the committed parameter. */ -/*ARGSUSED*/ int /* error */ xfs_bmap_finish( xfs_trans_t **tp, /* transaction pointer addr */ diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index c6888a420c5..5715279975c 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1528,15 +1528,7 @@ xfs_itruncate_finish( xfs_trans_log_inode(ntp, ip, XFS_ILOG_CORE); } } - } else if (sync) { - ASSERT(!(mp->m_flags & XFS_MOUNT_WSYNC)); - if (ip->i_d.di_anextents > 0) - xfs_trans_set_sync(ntp); } - ASSERT(fork == XFS_DATA_FORK || - (fork == XFS_ATTR_FORK && - ((sync && !(mp->m_flags & XFS_MOUNT_WSYNC)) || - (sync == 0 && (mp->m_flags & XFS_MOUNT_WSYNC))))); /* * Since it is possible for space to become allocated beyond From d8091fda7895ed0624d1641089f4080164e75a35 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 15 Dec 2011 10:54:39 +1100 Subject: [PATCH 0506/4025] md/raid5: fix bug that could result in reads from a failed device. commit 355840e7a7e56bb2834fd3b0da64da5465f8aeaa upstream. commit a847627709b3402163d99f7c6fda4a77bcd6b51b in linux-3.0.9 attempted to backport this to 3.0 but only made one change were two were necessary. This add the second change. This bug was introduced in 415e72d034c50520ddb7ff79e7d1792c1306f0c9 which was in 2.6.36. There is a small window of time between when a device fails and when it is removed from the array. During this time we might still read from it, but we won't write to it - so it is possible that we could read stale data. We didn't need the test of 'Faulty' before because the test on In_sync is sufficient. Since we started allowing reads from the early part of non-In_sync devices we need a test on Faulty too. This is suitable for any kernel from 2.6.36 onwards, though the patch might need a bit of tweaking in 3.0 and earlier. Signed-off-by: NeilBrown Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index cbb50d3883a..1f6c68df6f3 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3078,7 +3078,7 @@ static void handle_stripe5(struct stripe_head *sh) /* Not in-sync */; else if (test_bit(In_sync, &rdev->flags)) set_bit(R5_Insync, &dev->flags); - else { + else if (!test_bit(Faulty, &rdev->flags)) { /* could be in-sync depending on recovery/reshape status */ if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset) set_bit(R5_Insync, &dev->flags); From 37e8c2c97ab911f99cb75c0b5596150a34e06023 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 14 Dec 2011 12:16:08 +0000 Subject: [PATCH 0507/4025] xen: only limit memory map to maximum reservation for domain 0. commit d3db728125c4470a2d061ac10fa7395e18237263 upstream. d312ae878b6a "xen: use maximum reservation to limit amount of usable RAM" clamped the total amount of RAM to the current maximum reservation. This is correct for dom0 but is not correct for guest domains. In order to boot a guest "pre-ballooned" (e.g. with memory=1G but maxmem=2G) in order to allow for future memory expansion the guest must derive max_pfn from the e820 provided by the toolstack and not the current maximum reservation (which can reflect only the current maximum, not the guest lifetime max). The existing algorithm already behaves this correctly if we do not artificially limit the maximum number of pages for the guest case. For a guest booted with maxmem=512, memory=128 this results in: [ 0.000000] BIOS-provided physical RAM map: [ 0.000000] Xen: 0000000000000000 - 00000000000a0000 (usable) [ 0.000000] Xen: 00000000000a0000 - 0000000000100000 (reserved) -[ 0.000000] Xen: 0000000000100000 - 0000000008100000 (usable) -[ 0.000000] Xen: 0000000008100000 - 0000000020800000 (unusable) +[ 0.000000] Xen: 0000000000100000 - 0000000020800000 (usable) ... [ 0.000000] NX (Execute Disable) protection: active [ 0.000000] DMI not present or invalid. [ 0.000000] e820 update range: 0000000000000000 - 0000000000010000 (usable) ==> (reserved) [ 0.000000] e820 remove range: 00000000000a0000 - 0000000000100000 (usable) -[ 0.000000] last_pfn = 0x8100 max_arch_pfn = 0x1000000 +[ 0.000000] last_pfn = 0x20800 max_arch_pfn = 0x1000000 [ 0.000000] initial memory mapped : 0 - 027ff000 [ 0.000000] Base memory trampoline at [c009f000] 9f000 size 4096 -[ 0.000000] init_memory_mapping: 0000000000000000-0000000008100000 -[ 0.000000] 0000000000 - 0008100000 page 4k -[ 0.000000] kernel direct mapping tables up to 8100000 @ 27bb000-27ff000 +[ 0.000000] init_memory_mapping: 0000000000000000-0000000020800000 +[ 0.000000] 0000000000 - 0020800000 page 4k +[ 0.000000] kernel direct mapping tables up to 20800000 @ 26f8000-27ff000 [ 0.000000] xen: setting RW the range 27e8000 - 27ff000 [ 0.000000] 0MB HIGHMEM available. -[ 0.000000] 129MB LOWMEM available. -[ 0.000000] mapped low ram: 0 - 08100000 -[ 0.000000] low ram: 0 - 08100000 +[ 0.000000] 520MB LOWMEM available. +[ 0.000000] mapped low ram: 0 - 20800000 +[ 0.000000] low ram: 0 - 20800000 With this change "xl mem-set 512M" will successfully increase the guest RAM (by reducing the balloon). There is no change for dom0. Reported-and-Tested-by: George Shuklin Signed-off-by: Ian Campbell Reviewed-by: David Vrabel Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/setup.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index acea42ee4ee..f8dcda49314 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -192,9 +192,21 @@ static unsigned long __init xen_get_max_pages(void) domid_t domid = DOMID_SELF; int ret; - ret = HYPERVISOR_memory_op(XENMEM_maximum_reservation, &domid); - if (ret > 0) - max_pages = ret; + /* + * For the initial domain we use the maximum reservation as + * the maximum page. + * + * For guest domains the current maximum reservation reflects + * the current maximum rather than the static maximum. In this + * case the e820 map provided to us will cover the static + * maximum region. + */ + if (xen_initial_domain()) { + ret = HYPERVISOR_memory_op(XENMEM_maximum_reservation, &domid); + if (ret > 0) + max_pages = ret; + } + return min(max_pages, MAX_DOMAIN_PAGES); } From ef91e16945125c199f1e126091bc25a5835dd2bf Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 12 Dec 2011 22:06:18 -0500 Subject: [PATCH 0508/4025] ext4: display the correct mount option in /proc/mounts for [no]init_itable commit fc6cb1cda5db7b2d24bf32890826214b857c728e upstream. /proc/mounts was showing the mount option [no]init_inode_table when the correct mount option that will be accepted by parse_options() is [no]init_itable. Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 111ed9d3c54..7aa77f04917 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1113,9 +1113,9 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) seq_puts(seq, ",block_validity"); if (!test_opt(sb, INIT_INODE_TABLE)) - seq_puts(seq, ",noinit_inode_table"); + seq_puts(seq, ",noinit_itable"); else if (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT) - seq_printf(seq, ",init_inode_table=%u", + seq_printf(seq, ",init_itable=%u", (unsigned) sbi->s_li_wait_mult); ext4_show_quota_options(seq, sb); @@ -1291,8 +1291,7 @@ enum { Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity, Opt_inode_readahead_blks, Opt_journal_ioprio, Opt_dioread_nolock, Opt_dioread_lock, - Opt_discard, Opt_nodiscard, - Opt_init_inode_table, Opt_noinit_inode_table, + Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, }; static const match_table_t tokens = { @@ -1365,9 +1364,9 @@ static const match_table_t tokens = { {Opt_dioread_lock, "dioread_lock"}, {Opt_discard, "discard"}, {Opt_nodiscard, "nodiscard"}, - {Opt_init_inode_table, "init_itable=%u"}, - {Opt_init_inode_table, "init_itable"}, - {Opt_noinit_inode_table, "noinit_itable"}, + {Opt_init_itable, "init_itable=%u"}, + {Opt_init_itable, "init_itable"}, + {Opt_noinit_itable, "noinit_itable"}, {Opt_err, NULL}, }; @@ -1844,7 +1843,7 @@ static int parse_options(char *options, struct super_block *sb, case Opt_dioread_lock: clear_opt(sb, DIOREAD_NOLOCK); break; - case Opt_init_inode_table: + case Opt_init_itable: set_opt(sb, INIT_INODE_TABLE); if (args[0].from) { if (match_int(&args[0], &option)) @@ -1855,7 +1854,7 @@ static int parse_options(char *options, struct super_block *sb, return 0; sbi->s_li_wait_mult = option; break; - case Opt_noinit_inode_table: + case Opt_noinit_itable: clear_opt(sb, INIT_INODE_TABLE); break; default: From dda54df863232231ce851045834f475f02a7e565 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Tue, 13 Dec 2011 21:41:15 -0500 Subject: [PATCH 0509/4025] ext4: avoid hangs in ext4_da_should_update_i_disksize() commit ea51d132dbf9b00063169c1159bee253d9649224 upstream. If the pte mapping in generic_perform_write() is unmapped between iov_iter_fault_in_readable() and iov_iter_copy_from_user_atomic(), the "copied" parameter to ->end_write can be zero. ext4 couldn't cope with it with delayed allocations enabled. This skips the i_disksize enlargement logic if copied is zero and no new data was appeneded to the inode. gdb> bt #0 0xffffffff811afe80 in ext4_da_should_update_i_disksize (file=0xffff88003f606a80, mapping=0xffff88001d3824e0, pos=0x1\ 08000, len=0x1000, copied=0x0, page=0xffffea0000d792e8, fsdata=0x0) at fs/ext4/inode.c:2467 #1 ext4_da_write_end (file=0xffff88003f606a80, mapping=0xffff88001d3824e0, pos=0x108000, len=0x1000, copied=0x0, page=0\ xffffea0000d792e8, fsdata=0x0) at fs/ext4/inode.c:2512 #2 0xffffffff810d97f1 in generic_perform_write (iocb=, iov=, nr_segs=, pos=0x108000, ppos=0xffff88001e26be40, count=, written=0x0) at mm/filemap.c:2440 #3 generic_file_buffered_write (iocb=, iov=, nr_segs=, p\ os=0x108000, ppos=0xffff88001e26be40, count=, written=0x0) at mm/filemap.c:2482 #4 0xffffffff810db5d1 in __generic_file_aio_write (iocb=0xffff88001e26bde8, iov=0xffff88001e26bec8, nr_segs=0x1, ppos=0\ xffff88001e26be40) at mm/filemap.c:2600 #5 0xffffffff810db853 in generic_file_aio_write (iocb=0xffff88001e26bde8, iov=0xffff88001e26bec8, nr_segs=, pos=) at mm/filemap.c:2632 #6 0xffffffff811a71aa in ext4_file_write (iocb=0xffff88001e26bde8, iov=0xffff88001e26bec8, nr_segs=0x1, pos=0x108000) a\ t fs/ext4/file.c:136 #7 0xffffffff811375aa in do_sync_write (filp=0xffff88003f606a80, buf=, len=, \ ppos=0xffff88001e26bf48) at fs/read_write.c:406 #8 0xffffffff81137e56 in vfs_write (file=0xffff88003f606a80, buf=0x1ec2960
, count=0x4\ 000, pos=0xffff88001e26bf48) at fs/read_write.c:435 #9 0xffffffff8113816c in sys_write (fd=, buf=0x1ec2960
, count=0x\ 4000) at fs/read_write.c:487 #10 #11 0x00007f120077a390 in __brk_reservation_fn_dmi_alloc__ () #12 0x0000000000000000 in ?? () gdb> print offset $22 = 0xffffffffffffffff gdb> print idx $23 = 0xffffffff gdb> print inode->i_blkbits $24 = 0xc gdb> up #1 ext4_da_write_end (file=0xffff88003f606a80, mapping=0xffff88001d3824e0, pos=0x108000, len=0x1000, copied=0x0, page=0\ xffffea0000d792e8, fsdata=0x0) at fs/ext4/inode.c:2512 2512 if (ext4_da_should_update_i_disksize(page, end)) { gdb> print start $25 = 0x0 gdb> print end $26 = 0xffffffffffffffff gdb> print pos $27 = 0x108000 gdb> print new_i_size $28 = 0x108000 gdb> print ((struct ext4_inode_info *)((char *)inode-((int)(&((struct ext4_inode_info *)0)->vfs_inode))))->i_disksize $29 = 0xd9000 gdb> down 2467 for (i = 0; i < idx; i++) gdb> print i $30 = 0xd44acbee This is 100% reproducible with some autonuma development code tuned in a very aggressive manner (not normal way even for knumad) which does "exotic" changes to the ptes. It wouldn't normally trigger but I don't see why it can't happen normally if the page is added to swap cache in between the two faults leading to "copied" being zero (which then hangs in ext4). So it should be fixed. Especially possible with lumpy reclaim (albeit disabled if compaction is enabled) as that would ignore the young bits in the ptes. Signed-off-by: Andrea Arcangeli Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 1265904a239..ea9076b8d91 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3231,7 +3231,7 @@ static int ext4_da_write_end(struct file *file, */ new_i_size = pos + copied; - if (new_i_size > EXT4_I(inode)->i_disksize) { + if (copied && new_i_size > EXT4_I(inode)->i_disksize) { if (ext4_da_should_update_i_disksize(page, end)) { down_write(&EXT4_I(inode)->i_data_sem); if (new_i_size > EXT4_I(inode)->i_disksize) { From 8fe5e8ff93473129957c6d4a7df80046186b9c7b Mon Sep 17 00:00:00 2001 From: Yongqiang Yang Date: Tue, 13 Dec 2011 21:51:55 -0500 Subject: [PATCH 0510/4025] ext4: avoid potential hang in mpage_submit_io() when blocksize < pagesize commit 13a79a4741d37fda2fbafb953f0f301dc007928f upstream. If there is an unwritten but clean buffer in a page and there is a dirty buffer after the buffer, then mpage_submit_io does not write the dirty buffer out. As a result, da_writepages loops forever. This patch fixes the problem by checking dirty flag. Signed-off-by: Yongqiang Yang Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index ea9076b8d91..af0906080fd 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -2126,8 +2126,11 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd, clear_buffer_unwritten(bh); } - /* skip page if block allocation undone */ - if (buffer_delay(bh) || buffer_unwritten(bh)) + /* + * skip page if block allocation undone and + * block is dirty + */ + if (ext4_bh_delay_or_unwritten(NULL, bh)) skip_page = 1; bh = bh->b_this_page; block_start += bh->b_size; From 5da4b53abb4424f4b502a37425ffe4e46a7df5b5 Mon Sep 17 00:00:00 2001 From: Yongqiang Yang Date: Tue, 13 Dec 2011 22:29:12 -0500 Subject: [PATCH 0511/4025] ext4: handle EOF correctly in ext4_bio_write_page() commit 5a0dc7365c240795bf190766eba7a27600be3b3e upstream. We need to zero out part of a page which beyond EOF before setting uptodate, otherwise, mapread or write will see non-zero data beyond EOF. Signed-off-by: Yongqiang Yang Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/page-io.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index bd6a85e33c9..d99d74aca8a 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -405,6 +405,18 @@ int ext4_bio_write_page(struct ext4_io_submit *io, block_end = block_start + blocksize; if (block_start >= len) { + /* + * Comments copied from block_write_full_page_endio: + * + * The page straddles i_size. It must be zeroed out on + * each and every writepage invocation because it may + * be mmapped. "A file is mapped in multiples of the + * page size. For a file that is not a multiple of + * the page size, the remaining memory is zeroed when + * mapped, and writes to that region are not written + * out to the file." + */ + zero_user_segment(page, block_start, block_end); clear_buffer_dirty(bh); set_buffer_uptodate(bh); continue; From 60923f67e3a0ed74d3f0c6c25a0a3e5e41795644 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 13 Dec 2011 10:36:59 +0100 Subject: [PATCH 0512/4025] fuse: fix fuse_retrieve commit 48706d0a91583d08c56e7ef2a7602d99c8d4133f upstream. Fix two bugs in fuse_retrieve(): - retrieving more than one page would yield repeated instances of the first page - if more than FUSE_MAX_PAGES_PER_REQ pages were requested than the request page array would overflow fuse_retrieve() was added in 2.6.36 and these bugs had been there since the beginning. Signed-off-by: Miklos Szeredi Signed-off-by: Greg Kroah-Hartman --- fs/fuse/dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 5cb8614508c..2aaf3eaaf13 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1512,7 +1512,7 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode, else if (outarg->offset + num > file_size) num = file_size - outarg->offset; - while (num) { + while (num && req->num_pages < FUSE_MAX_PAGES_PER_REQ) { struct page *page; unsigned int this_num; @@ -1526,6 +1526,7 @@ static int fuse_retrieve(struct fuse_conn *fc, struct inode *inode, num -= this_num; total_len += this_num; + index++; } req->misc.retrieve_in.offset = outarg->offset; req->misc.retrieve_in.size = total_len; From fa0bd1d27724944e5c8a93ebfdf70af50bec9972 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sun, 11 Dec 2011 10:27:54 -0600 Subject: [PATCH 0513/4025] staging: r8712u: Add new USB ID commit c7caf4d4c56aee40b995f5858ccf1c814f3d2da2 upstream. Add USB ID for Sitecom WLA-2000 v1.001 WLAN. Reported-and-tested-by: Roland Gruber Signed-off-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/usb_intf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index 21ce2af447b..6cb7e28c99a 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -86,6 +86,7 @@ static struct usb_device_id rtl871x_usb_id_tbl[] = { {USB_DEVICE(0x0DF6, 0x0045)}, {USB_DEVICE(0x0DF6, 0x0059)}, /* 11n mode disable */ {USB_DEVICE(0x0DF6, 0x004B)}, + {USB_DEVICE(0x0DF6, 0x005D)}, {USB_DEVICE(0x0DF6, 0x0063)}, /* Sweex */ {USB_DEVICE(0x177F, 0x0154)}, From 8cce5e94c35994eab76780648ee8788b0a7a7728 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 12 Dec 2011 09:23:48 -0500 Subject: [PATCH 0514/4025] drm/radeon/kms: add some new pci ids commit cd5cfce856684e13b9b57d46b78bb827e9c4da3c upstream. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=43739 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- include/drm/drm_pciids.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h index 4e4fbb820e2..14b6cd02228 100644 --- a/include/drm/drm_pciids.h +++ b/include/drm/drm_pciids.h @@ -182,8 +182,11 @@ {0x1002, 0x6748, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6749, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6758, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6759, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x675B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x675D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x675F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6761, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ @@ -195,8 +198,10 @@ {0x1002, 0x6767, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6768, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6770, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x6772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6778, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6779, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x677B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CAICOS|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6841, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x6842, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_TURKS|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ @@ -246,6 +251,7 @@ {0x1002, 0x68f2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ {0x1002, 0x68f8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ {0x1002, 0x68f9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ + {0x1002, 0x68fa, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ {0x1002, 0x68fe, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_CEDAR|RADEON_NEW_MEMMAP}, \ {0x1002, 0x7100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_NEW_MEMMAP}, \ {0x1002, 0x7101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R520|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ @@ -488,6 +494,8 @@ {0x1002, 0x9647, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ {0x1002, 0x9648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ {0x1002, 0x964a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x964b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x964c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x964e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ {0x1002, 0x964f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_SUMO|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP},\ {0x1002, 0x9710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ @@ -502,6 +510,8 @@ {0x1002, 0x9805, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9806, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0x1002, 0x9807, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ + {0x1002, 0x9809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ {0, 0, 0} #define r128_PCI_IDS \ From 02ca05666d485710afaf604cf06fc4551d34e90d Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 12 Dec 2011 12:39:14 -0800 Subject: [PATCH 0515/4025] ibft: Fix finding IBFT ACPI table on UEFI commit 935a9fee51c945b8942be2d7b4bae069167b4886 upstream. Found one system with UEFI/iBFT, kernel does not detect the iBFT during iscsi_ibft module loading. Root cause: on x86 (UEFI), we are calling of find_ibft_region() much earlier - specifically in setup_arch() before ACPI is enabled. Try to split acpi checking code out and call that later At that time ACPI iBFT already get permanent mapped with ioremap. So isa_virt_to_bus() will get wrong phys from right virt address. We could just skip that phys address printing. For legacy one, print the found address early. -v2: update comments and description according to Konrad. -v3: fix problem about module use case that is found by Konrad. -v4: use acpi_get_table() instead of acpi_table_parse() to handle module use case that is found by Konrad again.. Signed-off-by: Yinghai Lu Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/iscsi_ibft.c | 42 ++++++++++++++++++++++++++++-- drivers/firmware/iscsi_ibft_find.c | 26 ++---------------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c index ce33f462695..2763643089c 100644 --- a/drivers/firmware/iscsi_ibft.c +++ b/drivers/firmware/iscsi_ibft.c @@ -738,6 +738,37 @@ static void __exit ibft_exit(void) ibft_cleanup(); } +#ifdef CONFIG_ACPI +static const struct { + char *sign; +} ibft_signs[] = { + /* + * One spec says "IBFT", the other says "iBFT". We have to check + * for both. + */ + { ACPI_SIG_IBFT }, + { "iBFT" }, +}; + +static void __init acpi_find_ibft_region(void) +{ + int i; + struct acpi_table_header *table = NULL; + + if (acpi_disabled) + return; + + for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++) { + acpi_get_table(ibft_signs[i].sign, 0, &table); + ibft_addr = (struct acpi_table_ibft *)table; + } +} +#else +static void __init acpi_find_ibft_region(void) +{ +} +#endif + /* * ibft_init() - creates sysfs tree entries for the iBFT data. */ @@ -745,9 +776,16 @@ static int __init ibft_init(void) { int rc = 0; + /* + As on UEFI systems the setup_arch()/find_ibft_region() + is called before ACPI tables are parsed and it only does + legacy finding. + */ + if (!ibft_addr) + acpi_find_ibft_region(); + if (ibft_addr) { - printk(KERN_INFO "iBFT detected at 0x%llx.\n", - (u64)isa_virt_to_bus(ibft_addr)); + pr_info("iBFT detected.\n"); rc = ibft_check_device(); if (rc) diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index bfe723266fd..4da4eb9ae92 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c @@ -45,13 +45,6 @@ EXPORT_SYMBOL_GPL(ibft_addr); static const struct { char *sign; } ibft_signs[] = { -#ifdef CONFIG_ACPI - /* - * One spec says "IBFT", the other says "iBFT". We have to check - * for both. - */ - { ACPI_SIG_IBFT }, -#endif { "iBFT" }, { "BIFT" }, /* Broadcom iSCSI Offload */ }; @@ -62,14 +55,6 @@ static const struct { #define VGA_MEM 0xA0000 /* VGA buffer */ #define VGA_SIZE 0x20000 /* 128kB */ -#ifdef CONFIG_ACPI -static int __init acpi_find_ibft(struct acpi_table_header *header) -{ - ibft_addr = (struct acpi_table_ibft *)header; - return 0; -} -#endif /* CONFIG_ACPI */ - static int __init find_ibft_in_mem(void) { unsigned long pos; @@ -94,6 +79,7 @@ static int __init find_ibft_in_mem(void) * the table cannot be valid. */ if (pos + len <= (IBFT_END-1)) { ibft_addr = (struct acpi_table_ibft *)virt; + pr_info("iBFT found at 0x%lx.\n", pos); goto done; } } @@ -108,20 +94,12 @@ static int __init find_ibft_in_mem(void) */ unsigned long __init find_ibft_region(unsigned long *sizep) { -#ifdef CONFIG_ACPI - int i; -#endif ibft_addr = NULL; -#ifdef CONFIG_ACPI - for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++) - acpi_table_parse(ibft_signs[i].sign, acpi_find_ibft); -#endif /* CONFIG_ACPI */ - /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will * only use ACPI for this */ - if (!ibft_addr && !efi_enabled) + if (!efi_enabled) find_ibft_in_mem(); if (ibft_addr) { From d23d19302ad80a9d5f013b74aa5e1e7328d4ba9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Ha=C5=82asa?= Date: Mon, 12 Dec 2011 14:51:00 +0100 Subject: [PATCH 0516/4025] USB: cdc-acm: add IDs for Motorola H24 HSPA USB module. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 6abff5dc4d5a2c90e597137ce8987e7fd439259b upstream. Add USB IDs for Motorola H24 HSPA USB module. Signed-off-by: Krzysztof Hałasa Acked-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 2ffcaa0b0b7..8faa23cd74f 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1458,6 +1458,16 @@ static const struct usb_device_id acm_ids[] = { }, { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */ }, + /* Motorola H24 HSPA module: */ + { USB_DEVICE(0x22b8, 0x2d91) }, /* modem */ + { USB_DEVICE(0x22b8, 0x2d92) }, /* modem + diagnostics */ + { USB_DEVICE(0x22b8, 0x2d93) }, /* modem + AT port */ + { USB_DEVICE(0x22b8, 0x2d95) }, /* modem + AT port + diagnostics */ + { USB_DEVICE(0x22b8, 0x2d96) }, /* modem + NMEA */ + { USB_DEVICE(0x22b8, 0x2d97) }, /* modem + diagnostics + NMEA */ + { USB_DEVICE(0x22b8, 0x2d99) }, /* modem + AT port + NMEA */ + { USB_DEVICE(0x22b8, 0x2d9a) }, /* modem + AT port + diagnostics + NMEA */ + { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */ .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on data interface instead of From 4c3f5007ad3aec88567774b5bbf933145ee42df8 Mon Sep 17 00:00:00 2001 From: Alex Hermann Date: Mon, 12 Dec 2011 21:42:23 +0100 Subject: [PATCH 0517/4025] usb: option: Add Huawei E398 controlling interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 414b591fd16655871e9f5592a55368b10a3ccc30 upstream. This patch adds the controlling interfaces for the Huawei E398. Thanks to Bjørn Mork for extracting the interface numbers from the windows driver. Signed-off-by: Alex Hermann Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index e98a1e1e508..d4682ee5977 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -660,6 +660,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x02) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x03) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x08) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x01) }, /* E398 3G Modem */ + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x02) }, /* E398 3G PC UI Interface */ + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x03) }, /* E398 3G Application Interface */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) }, From 5dfcd4d5e36784b14071bbe5e42947d3e8bf1c69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Tue, 13 Dec 2011 05:33:02 +0100 Subject: [PATCH 0518/4025] USB: option: Removing one bogus and adding some new Huawei combinations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 02a551c9755b799579e0a093bcc99b80b4dc1453 upstream. Huawei use the product code HUAWEI_PRODUCT_E353 (0x1506) for a number of different devices, which each can appear with a number of different descriptor sets. Different types of interfaces can be identified by looking at the subclass and protocol fields Subclass 1 protocol 8 is actually the data interface of a CDC ECM set, with subclass 1 protocol 9 as the control interface. Neither support serial data communcation, and cannot therefore be supported by this driver. At the same time, add a few other sets which appear if the device is configured in "Windows mode" using this modeswitch message: 55534243000000000000000000000011060000000100000000000000000000 Signed-off-by: Bjørn Mork Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index d4682ee5977..d2becb9eb60 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -659,7 +659,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x02) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x03) }, - { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x08) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x10) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x12) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x13) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x01) }, /* E398 3G Modem */ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x02) }, /* E398 3G PC UI Interface */ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x03) }, /* E398 3G Application Interface */ From c4e133f4e253b57e5d4409964a3b51f2d887e94b Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 25 May 2011 14:06:41 -0600 Subject: [PATCH 0519/4025] ASoC: core: Don't schedule deferred_resume_work twice commit 82e14e8bdd88b69018fe757192b01dd98582905e upstream. For cards that have two or more DAIs, snd_soc_resume's loop over all DAIs ends up calling schedule_work(deferred_resume_work) once per DAI. Since this is the same work item each time, the 2nd and subsequent calls return 0 (work item already queued), and trigger the dev_err message below stating that a work item may have been lost. Solve this by adjusting the loop to simply calculate whether to run the resume work immediately or defer it, and then call schedule work (or not) one time based on that. Note: This has not been tested in mainline, but only in chromeos-2.6.38; mainline doesn't support suspend/resume on Tegra, nor does the mainline Tegra ASoC driver contain multiple DAIs. It has been compile-checked in mainline. Signed-off-by: Stephen Warren Acked-by: Liam Girdwood Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/soc-core.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 59abd842c2c..493ae7c4c04 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1257,7 +1257,7 @@ static void soc_resume_deferred(struct work_struct *work) int snd_soc_resume(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); - int i; + int i, ac97_control = 0; /* AC97 devices might have other drivers hanging off them so * need to resume immediately. Other drivers don't have that @@ -1266,14 +1266,15 @@ int snd_soc_resume(struct device *dev) */ for (i = 0; i < card->num_rtd; i++) { struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; - if (cpu_dai->driver->ac97_control) { - dev_dbg(dev, "Resuming AC97 immediately\n"); - soc_resume_deferred(&card->deferred_resume_work); - } else { - dev_dbg(dev, "Scheduling resume work\n"); - if (!schedule_work(&card->deferred_resume_work)) - dev_err(dev, "resume work item may be lost\n"); - } + ac97_control |= cpu_dai->driver->ac97_control; + } + if (ac97_control) { + dev_dbg(dev, "Resuming AC97 immediately\n"); + soc_resume_deferred(&card->deferred_resume_work); + } else { + dev_dbg(dev, "Scheduling resume work\n"); + if (!schedule_work(&card->deferred_resume_work)) + dev_err(dev, "resume work item may be lost\n"); } return 0; From 6636552f1dd0d2e2be2f87605ea2cd3aa4d2e5b6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 21 Dec 2011 12:59:52 -0800 Subject: [PATCH 0520/4025] Linux 3.0.14 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5ccc9620617..f4f577b2970 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 13 +SUBLEVEL = 14 EXTRAVERSION = NAME = Sneaky Weasel From ef7386b5de11f6269eaf072c5ef522d2a43172c2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 30 Dec 2011 13:24:40 -0800 Subject: [PATCH 0521/4025] Revert "clockevents: Set noop handler in clockevents_exchange_device()" commit 3b87487ac5008072f138953b07505a7e3493327f upstream. This reverts commit de28f25e8244c7353abed8de0c7792f5f883588c. It results in resume problems for various people. See for example http://thread.gmane.org/gmane.linux.kernel/1233033 http://thread.gmane.org/gmane.linux.kernel/1233389 http://thread.gmane.org/gmane.linux.kernel/1233159 http://thread.gmane.org/gmane.linux.kernel/1227868/focus=1230877 and the fedora and ubuntu bug reports https://bugzilla.redhat.com/show_bug.cgi?id=767248 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/904569 which got bisected down to the stable version of this commit. Reported-by: Jonathan Nieder Reported-by: Phil Miller Reported-by: Philip Langdale Reported-by: Tim Gardner Cc: Thomas Gleixner Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/time/clockevents.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index 13dfaaba406..e4c699dfa4e 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -286,7 +286,6 @@ void clockevents_exchange_device(struct clock_event_device *old, * released list and do a notify add later. */ if (old) { - old->event_handler = clockevents_handle_noop; clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED); list_del(&old->list); list_add(&old->list, &clockevents_released); From c6d7c4dbff353eac7919342ae6b3299a378160a6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 3 Jan 2012 10:50:13 -0800 Subject: [PATCH 0522/4025] Linux 3.0.15 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f4f577b2970..5b8c185be2e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 14 +SUBLEVEL = 15 EXTRAVERSION = NAME = Sneaky Weasel From 1071cf4b06c8ed46e57a32b037524ac7202e14bb Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 3 Jan 2012 14:12:54 -0800 Subject: [PATCH 0523/4025] ARM: s5pv210: herring: Add wlan locale translation table Signed-off-by: Dmitry Shmidt --- arch/arm/mach-s5pv210/mach-herring.c | 71 ++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c index 9d3edf8f714..fe578c4ed3e 100755 --- a/arch/arm/mach-s5pv210/mach-herring.c +++ b/arch/arm/mach-s5pv210/mach-herring.c @@ -5343,11 +5343,82 @@ int __init herring_init_wifi_mem(void) return -ENOMEM; } + +/* Customized Locale table : OPTIONAL feature */ +#define WLC_CNTRY_BUF_SZ 4 +typedef struct cntry_locales_custom { + char iso_abbrev[WLC_CNTRY_BUF_SZ]; + char custom_locale[WLC_CNTRY_BUF_SZ]; + int custom_locale_rev; +} cntry_locales_custom_t; + +static cntry_locales_custom_t herring_wlan_translate_custom_table[] = { +/* Table should be filled out based on custom platform regulatory requirement */ + {"", "XY", 4}, /* universal */ + {"US", "US", 69}, /* input ISO "US" to : US regrev 69 */ + {"CA", "US", 69}, /* input ISO "CA" to : US regrev 69 */ + {"EU", "EU", 5}, /* European union countries */ + {"AT", "EU", 5}, + {"BE", "EU", 5}, + {"BG", "EU", 5}, + {"CY", "EU", 5}, + {"CZ", "EU", 5}, + {"DK", "EU", 5}, + {"EE", "EU", 5}, + {"FI", "EU", 5}, + {"FR", "EU", 5}, + {"DE", "EU", 5}, + {"GR", "EU", 5}, + {"HU", "EU", 5}, + {"IE", "EU", 5}, + {"IT", "EU", 5}, + {"LV", "EU", 5}, + {"LI", "EU", 5}, + {"LT", "EU", 5}, + {"LU", "EU", 5}, + {"MT", "EU", 5}, + {"NL", "EU", 5}, + {"PL", "EU", 5}, + {"PT", "EU", 5}, + {"RO", "EU", 5}, + {"SK", "EU", 5}, + {"SI", "EU", 5}, + {"ES", "EU", 5}, + {"SE", "EU", 5}, + {"GB", "EU", 5}, /* input ISO "GB" to : EU regrev 05 */ + {"IL", "IL", 0}, + {"CH", "CH", 0}, + {"TR", "TR", 0}, + {"NO", "NO", 0}, + {"KR", "XY", 3}, + {"AU", "XY", 3}, + {"CN", "XY", 3}, /* input ISO "CN" to : XY regrev 03 */ + {"TW", "XY", 3}, + {"AR", "XY", 3}, + {"MX", "XY", 3} +}; + +static void *herring_wlan_get_country_code(char *ccode) +{ + int size = ARRAY_SIZE(herring_wlan_translate_custom_table); + int i; + + if (!ccode) + return NULL; + + for (i = 0; i < size; i++) + if (strcmp(ccode, herring_wlan_translate_custom_table[i].iso_abbrev) == 0) + return &herring_wlan_translate_custom_table[i]; + return &herring_wlan_translate_custom_table[0]; +} + + static struct wifi_platform_data wifi_pdata = { .set_power = wlan_power_en, .set_reset = wlan_reset_en, .set_carddetect = wlan_carddetect_en, .mem_prealloc = herring_mem_prealloc, + .get_country_code = herring_wlan_get_country_code, }; static struct platform_device sec_device_wifi = { From 9ce53d23da31815c0d0ae0380f898da4b5aa7af6 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Thu, 8 Dec 2011 22:23:00 +0200 Subject: [PATCH 0524/4025] ARM: OMAP: rx51: fix USB commit e5fe29c7198a1f6616286dfc8602a69da165cb3f upstream. Commit 10299e2e4e3ed3b16503d4e04edd48b33083f4e2 (ARM: RX-51: Enable isp1704 power on/off) added power management for isp1704. However, the transceiver should be powered on by default, otherwise USB doesn't work at all for networking during boot. All kernels after v3.0 are affected. Signed-off-by: Felipe Contreras Reviewed-by: Sebastian Reichel [tony@atomide.com: updated comments] Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/board-rx51-peripherals.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index 88bd6f7705f..c56597172bf 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c @@ -133,7 +133,7 @@ static struct platform_device rx51_charger_device = { static void __init rx51_charger_init(void) { WARN_ON(gpio_request_one(RX51_USB_TRANSCEIVER_RST_GPIO, - GPIOF_OUT_INIT_LOW, "isp1704_reset")); + GPIOF_OUT_INIT_HIGH, "isp1704_reset")); platform_device_register(&rx51_charger_device); } From 919130981e72465867038ac1dec823dbd7a87eb5 Mon Sep 17 00:00:00 2001 From: Ted Feng Date: Thu, 8 Dec 2011 00:46:21 +0000 Subject: [PATCH 0525/4025] ipip, sit: copy parms.name after register_netdevice commit 72b36015ba43a3cca5303f5534d2c3e1899eae29 upstream. Same fix as 731abb9cb2 for ipip and sit tunnel. Commit 1c5cae815d removed an explicit call to dev_alloc_name in ipip_tunnel_locate and ipip6_tunnel_locate, because register_netdevice will now create a valid name, however the tunnel keeps a copy of the name in the private parms structure. Fix this by copying the name back after register_netdevice has successfully returned. This shows up if you do a simple tunnel add, followed by a tunnel show: $ sudo ip tunnel add mode ipip remote 10.2.20.211 $ ip tunnel tunl0: ip/ip remote any local any ttl inherit nopmtudisc tunl%d: ip/ip remote 10.2.20.211 local any ttl inherit $ sudo ip tunnel add mode sit remote 10.2.20.212 $ ip tunnel sit0: ipv6/ip remote any local any ttl 64 nopmtudisc 6rd-prefix 2002::/16 sit%d: ioctl 89f8 failed: No such device sit%d: ipv6/ip remote 10.2.20.212 local any ttl inherit Signed-off-by: Ted Feng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ipip.c | 7 ++++++- net/ipv6/sit.c | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 378b20b7ca6..6f06f7f39ea 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -285,6 +285,8 @@ static struct ip_tunnel * ipip_tunnel_locate(struct net *net, if (register_netdevice(dev) < 0) goto failed_free; + strcpy(nt->parms.name, dev->name); + dev_hold(dev); ipip_tunnel_link(ipn, nt); return nt; @@ -759,7 +761,6 @@ static int ipip_tunnel_init(struct net_device *dev) struct ip_tunnel *tunnel = netdev_priv(dev); tunnel->dev = dev; - strcpy(tunnel->parms.name, dev->name); memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); @@ -825,6 +826,7 @@ static void ipip_destroy_tunnels(struct ipip_net *ipn, struct list_head *head) static int __net_init ipip_init_net(struct net *net) { struct ipip_net *ipn = net_generic(net, ipip_net_id); + struct ip_tunnel *t; int err; ipn->tunnels[0] = ipn->tunnels_wc; @@ -848,6 +850,9 @@ static int __net_init ipip_init_net(struct net *net) if ((err = register_netdev(ipn->fb_tunnel_dev))) goto err_reg_dev; + t = netdev_priv(ipn->fb_tunnel_dev); + + strcpy(t->parms.name, ipn->fb_tunnel_dev->name); return 0; err_reg_dev: diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 1cca5761aea..38490d5c7e1 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -263,6 +263,8 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, if (register_netdevice(dev) < 0) goto failed_free; + strcpy(nt->parms.name, dev->name); + dev_hold(dev); ipip6_tunnel_link(sitn, nt); @@ -1141,7 +1143,6 @@ static int ipip6_tunnel_init(struct net_device *dev) struct ip_tunnel *tunnel = netdev_priv(dev); tunnel->dev = dev; - strcpy(tunnel->parms.name, dev->name); memcpy(dev->dev_addr, &tunnel->parms.iph.saddr, 4); memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); @@ -1204,6 +1205,7 @@ static void __net_exit sit_destroy_tunnels(struct sit_net *sitn, struct list_hea static int __net_init sit_init_net(struct net *net) { struct sit_net *sitn = net_generic(net, sit_net_id); + struct ip_tunnel *t; int err; sitn->tunnels[0] = sitn->tunnels_wc; @@ -1228,6 +1230,9 @@ static int __net_init sit_init_net(struct net *net) if ((err = register_netdev(sitn->fb_tunnel_dev))) goto err_reg_dev; + t = netdev_priv(sitn->fb_tunnel_dev); + + strcpy(t->parms.name, sitn->fb_tunnel_dev->name); return 0; err_reg_dev: From bd43f8f08f6645690724869150df18ef0dc6a7dd Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 12 Dec 2011 13:57:52 -0800 Subject: [PATCH 0526/4025] rtc: m41t80: Workaround broken alarm functionality commit c3b79770e51ab1fd4201f3b54edf30113b9ce74f upstream. The m41t80 driver can read and set the alarm, but it doesn't seem to have a functional alarm irq. This causes failures when the generic core sees alarm functions, but then cannot use them properly for things like UIE mode. Disabling the alarm functions allows proper error reporting, and possible fallback to emulated modes. Once someone fixes the alarm irq functionality, this can be restored. CC: Matt Turner CC: Nico Macrionitis CC: Atsushi Nemoto Reported-by: Matt Turner Reported-by: Nico Macrionitis Tested-by: Nico Macrionitis Signed-off-by: John Stultz Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-m41t80.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index eda128fc1d3..64aedd8cc09 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -357,10 +357,19 @@ static int m41t80_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t) static struct rtc_class_ops m41t80_rtc_ops = { .read_time = m41t80_rtc_read_time, .set_time = m41t80_rtc_set_time, + /* + * XXX - m41t80 alarm functionality is reported broken. + * until it is fixed, don't register alarm functions. + * .read_alarm = m41t80_rtc_read_alarm, .set_alarm = m41t80_rtc_set_alarm, + */ .proc = m41t80_rtc_proc, + /* + * See above comment on broken alarm + * .alarm_irq_enable = m41t80_rtc_alarm_irq_enable, + */ }; #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE) From 183647b865aea1411c87f9b76b8c74511e34807d Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Thu, 10 Nov 2011 13:55:15 -0200 Subject: [PATCH 0527/4025] drm/i915: prevent division by zero when asking for chipset power commit 4ed0b577457eb6aeb7cdc7e7316576e63d15abb2 upstream. This prevents an in-kernel division by zero which happens when we are asking for i915_chipset_val too quickly, or within a race condition between the power monitoring thread and userspace accesses via debugfs. The issue can be reproduced easily via the following command: while ``; do cat /sys/kernel/debug/dri/0/i915_emon_status; done This is particularly dangerous because it can be triggered by a non-privileged user by just reading the debugfs entry. This issue was also found independently by Konstantin Belousov , who proposed a similar patch. Reported-by: Konstantin Belousov Acked-by: Jesse Barnes Acked-by: Keith Packard Reviewed-by: Chris Wilson Signed-off-by: Eugeni Dodonov Signed-off-by: Keith Packard Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_dma.c | 10 ++++++++++ drivers/gpu/drm/i915/i915_drv.h | 1 + 2 files changed, 11 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 7eef6e11d9a..ef164432ba6 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1451,6 +1451,14 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) diff1 = now - dev_priv->last_time1; + /* Prevent division-by-zero if we are asking too fast. + * Also, we don't get interesting results if we are polling + * faster than once in 10ms, so just return the saved value + * in such cases. + */ + if (diff1 <= 10) + return dev_priv->chipset_power; + count1 = I915_READ(DMIEC); count2 = I915_READ(DDREC); count3 = I915_READ(CSIEC); @@ -1481,6 +1489,8 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) dev_priv->last_count1 = total_count; dev_priv->last_time1 = now; + dev_priv->chipset_power = ret; + return ret; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e0d0e278f62..335564e35c3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -702,6 +702,7 @@ typedef struct drm_i915_private { u64 last_count1; unsigned long last_time1; + unsigned long chipset_power; u64 last_count2; struct timespec last_time2; unsigned long gfx_power; From 8f8a594251e5260f53d746887890d0d2185ceebb Mon Sep 17 00:00:00 2001 From: majianpeng Date: Wed, 30 Nov 2011 15:47:48 +0100 Subject: [PATCH 0528/4025] cfq-iosched: free cic_index if blkio_alloc_blkg_stats fails commit 2984ff38ccf6cbc02a7a996a36c7d6f69f3c6146 upstream. If we fail allocating the blkpg stats, we free cfqd and cfgq. But we need to free the IDA cfqd->cic_index as well. Signed-off-by: majianpeng Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/cfq-iosched.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index ae21919f15e..aae94473b58 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -4015,6 +4015,11 @@ static void *cfq_init_queue(struct request_queue *q) if (blkio_alloc_blkg_stats(&cfqg->blkg)) { kfree(cfqg); + + spin_lock(&cic_index_lock); + ida_remove(&cic_index_ida, cfqd->cic_index); + spin_unlock(&cic_index_lock); + kfree(cfqd); return NULL; } From cec3c159f674367def095745a72ac6150f889243 Mon Sep 17 00:00:00 2001 From: Yasuaki Ishimatsu Date: Fri, 2 Dec 2011 10:07:07 +0100 Subject: [PATCH 0529/4025] cfq-iosched: fix cfq_cic_link() race confition commit 5eb46851de3904cd1be9192fdacb8d34deadc1fc upstream. cfq_cic_link() has race condition. When some processes which shared ioc issue I/O to same block device simultaneously, cfq_cic_link() returns -EEXIST sometimes. The race condition might stop I/O by following steps: step 1: Process A: Issue an I/O to /dev/sda step 2: Process A: Get an ioc (iocA here) in get_io_context() which does not linked with a cic for the device step 3: Process A: Get a new cic for the device (cicA here) in cfq_alloc_io_context() step 4: Process B: Issue an I/O to /dev/sda step 5: Process B: Get iocA in get_io_context() since process A and B share the same ioc step 6: Process B: Get a new cic for the device (cicB here) in cfq_alloc_io_context() since iocA has not been linked with a cic for the device yet step 7: Process A: Link cicA to iocA in cfq_cic_link() step 8: Process A: Dispatch I/O to driver and finish it step 9: Process B: Try to link cicB to iocA in cfq_cic_link() But it fails with showing "cfq: cic link failed!" kernel message, since iocA has already linked with cicA at step 7. step 10: Process B: Wait for finishig I/O in get_request_wait() The function does not wake up, when there is no I/O to the device. When cfq_cic_link() returns -EEXIST, it means ioc has already linked with cic. So when cfq_cic_link() return -EEXIST, retry cfq_cic_lookup(). Signed-off-by: Yasuaki Ishimatsu Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/cfq-iosched.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index aae94473b58..23500ac7f0f 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -3169,7 +3169,7 @@ static int cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc, } } - if (ret) + if (ret && ret != -EEXIST) printk(KERN_ERR "cfq: cic link failed!\n"); return ret; @@ -3185,6 +3185,7 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) { struct io_context *ioc = NULL; struct cfq_io_context *cic; + int ret; might_sleep_if(gfp_mask & __GFP_WAIT); @@ -3192,6 +3193,7 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) if (!ioc) return NULL; +retry: cic = cfq_cic_lookup(cfqd, ioc); if (cic) goto out; @@ -3200,7 +3202,12 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) if (cic == NULL) goto err; - if (cfq_cic_link(cfqd, ioc, cic, gfp_mask)) + ret = cfq_cic_link(cfqd, ioc, cic, gfp_mask); + if (ret == -EEXIST) { + /* someone has linked cic to ioc already */ + cfq_cic_free(cic); + goto retry; + } else if (ret) goto err_free; out: From 3b538a7aaf6468c40a1faa559417e6165456b8e3 Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Fri, 18 Nov 2011 20:00:40 +0100 Subject: [PATCH 0530/4025] SCSI: zfcp: return early from slave_destroy if slave_alloc returned early commit 44f747fff6e9f027a4866c1a6864e26ae7c510c8 upstream. zfcp_scsi_slave_destroy erroneously always tried to finish its task even if the corresponding previous zfcp_scsi_slave_alloc returned early. This can lead to kernel page faults on accessing uninitialized fields of struct zfcp_scsi_dev in zfcp_erp_lun_shutdown_wait. Take the port field of the struct to determine if slave_alloc returned early. This zfcp bug is exposed by 4e6c82b (in turn fixing f7c9c6b to be compatible with 21208ae) which can call slave_destroy for a corresponding previous slave_alloc that did not finish. This patch is based on James Bottomley's fix suggestion in http://www.spinics.net/lists/linux-scsi/msg55449.html. Signed-off-by: Steffen Maier Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/s390/scsi/zfcp_scsi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 2a4991d6d4d..3a417dff1b8 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -57,6 +57,10 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdev) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + /* if previous slave_alloc returned early, there is nothing to do */ + if (!zfcp_sdev->port) + return; + zfcp_erp_lun_shutdown_wait(sdev, "scssd_1"); put_device(&zfcp_sdev->port->dev); } From e57a4c768c03a91334759def503b2d7616028a35 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 7 Nov 2011 22:05:21 +1100 Subject: [PATCH 0531/4025] SCSI: mpt2sas: _scsih_smart_predicted_fault uses GFP_KERNEL in interrupt context commit f6a290b419a2675c4b77a6b0731cd2a64332365e upstream. _scsih_smart_predicted_fault is called in an interrupt and therefore must allocate memory using GFP_ATOMIC. Signed-off-by: Anton Blanchard Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 5690f09e010..f88e52a1a39 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -4145,7 +4145,7 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) /* insert into event log */ sz = offsetof(Mpi2EventNotificationReply_t, EventData) + sizeof(Mpi2EventDataSasDeviceStatusChange_t); - event_reply = kzalloc(sz, GFP_KERNEL); + event_reply = kzalloc(sz, GFP_ATOMIC); if (!event_reply) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); From d27020f6c090faf3688324af9a8b496435285039 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 11 Nov 2011 20:52:01 +0100 Subject: [PATCH 0532/4025] SCSI: fcoe: Fix preempt count leak in fcoe_filter_frames() commit 7e1e7ead88dff75b11b86ee0d5232c4591be1326 upstream. The error exit path leaks preempt count. Add the missing put_cpu(). Signed-off-by: Thomas Gleixner Reviewed-by: Yi Zou Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/fcoe/fcoe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 8885b3ef369..f829adcb3b7 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1561,6 +1561,7 @@ static inline int fcoe_filter_frames(struct fc_lport *lport, stats->InvalidCRCCount++; if (stats->InvalidCRCCount < 5) printk(KERN_WARNING "fcoe: dropping frame with CRC error\n"); + put_cpu(); return -EINVAL; } From afa2450ce311b3182c737c3fda59bb557da93409 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 7 Dec 2011 09:02:21 +0100 Subject: [PATCH 0533/4025] mac80211: fix another race in aggregation start commit 15062e6a8524f5977f2cbdf6e3eb2f144262f74e upstream. Emmanuel noticed that when mac80211 stops the queues for aggregation that can leave a packet pending. This packet will be given to the driver after the AMPDU callback, but as a non-aggregated packet which messes up the sequence number etc. I also noticed by looking at the code that if packets are being processed while we clear the WANT_START bit, they might see it cleared already and queue up on tid_tx->pending. If the driver then rejects the new aggregation session we leak the packet. Fix both of these issues by changing this code to not stop the queues at all. Instead, let packets queue up on the tid_tx->pending queue instead of letting them get to the driver, and add code to recover properly in case the driver rejects the session. (The patch looks large because it has to move two functions to before their new use.) Reported-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/agg-tx.c | 86 +++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index db7db43ccf4..b7f4f5c1f69 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -304,6 +304,38 @@ ieee80211_wake_queue_agg(struct ieee80211_local *local, int tid) __release(agg_queue); } +/* + * splice packets from the STA's pending to the local pending, + * requires a call to ieee80211_agg_splice_finish later + */ +static void __acquires(agg_queue) +ieee80211_agg_splice_packets(struct ieee80211_local *local, + struct tid_ampdu_tx *tid_tx, u16 tid) +{ + int queue = ieee80211_ac_from_tid(tid); + unsigned long flags; + + ieee80211_stop_queue_agg(local, tid); + + if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates" + " from the pending queue\n", tid)) + return; + + if (!skb_queue_empty(&tid_tx->pending)) { + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + /* copy over remaining packets */ + skb_queue_splice_tail_init(&tid_tx->pending, + &local->pending[queue]); + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + } +} + +static void __releases(agg_queue) +ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) +{ + ieee80211_wake_queue_agg(local, tid); +} + void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) { struct tid_ampdu_tx *tid_tx; @@ -315,19 +347,17 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) tid_tx = rcu_dereference_protected_tid_tx(sta, tid); /* - * While we're asking the driver about the aggregation, - * stop the AC queue so that we don't have to worry - * about frames that came in while we were doing that, - * which would require us to put them to the AC pending - * afterwards which just makes the code more complex. + * Start queuing up packets for this aggregation session. + * We're going to release them once the driver is OK with + * that. */ - ieee80211_stop_queue_agg(local, tid); - clear_bit(HT_AGG_STATE_WANT_START, &tid_tx->state); /* - * make sure no packets are being processed to get - * valid starting sequence number + * Make sure no packets are being processed. This ensures that + * we have a valid starting sequence number and that in-flight + * packets have been flushed out and no packets for this TID + * will go into the driver during the ampdu_action call. */ synchronize_net(); @@ -341,17 +371,15 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) " tid %d\n", tid); #endif spin_lock_bh(&sta->lock); + ieee80211_agg_splice_packets(local, tid_tx, tid); ieee80211_assign_tid_tx(sta, tid, NULL); + ieee80211_agg_splice_finish(local, tid); spin_unlock_bh(&sta->lock); - ieee80211_wake_queue_agg(local, tid); kfree_rcu(tid_tx, rcu_head); return; } - /* we can take packets again now */ - ieee80211_wake_queue_agg(local, tid); - /* activate the timer for the recipient's addBA response */ mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); #ifdef CONFIG_MAC80211_HT_DEBUG @@ -471,38 +499,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, } EXPORT_SYMBOL(ieee80211_start_tx_ba_session); -/* - * splice packets from the STA's pending to the local pending, - * requires a call to ieee80211_agg_splice_finish later - */ -static void __acquires(agg_queue) -ieee80211_agg_splice_packets(struct ieee80211_local *local, - struct tid_ampdu_tx *tid_tx, u16 tid) -{ - int queue = ieee80211_ac_from_tid(tid); - unsigned long flags; - - ieee80211_stop_queue_agg(local, tid); - - if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates" - " from the pending queue\n", tid)) - return; - - if (!skb_queue_empty(&tid_tx->pending)) { - spin_lock_irqsave(&local->queue_stop_reason_lock, flags); - /* copy over remaining packets */ - skb_queue_splice_tail_init(&tid_tx->pending, - &local->pending[queue]); - spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); - } -} - -static void __releases(agg_queue) -ieee80211_agg_splice_finish(struct ieee80211_local *local, u16 tid) -{ - ieee80211_wake_queue_agg(local, tid); -} - static void ieee80211_agg_tx_operational(struct ieee80211_local *local, struct sta_info *sta, u16 tid) { From d27bf91d1a9ea58a32bf9dd949e93bb1dc1fc9bf Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Wed, 23 Nov 2011 10:59:13 +0100 Subject: [PATCH 0534/4025] block: initialize request_queue's numa node during commit 5151412dd4338b273afdb107c3772528e9e67d92 upstream. struct request_queue is allocated with __GFP_ZERO so its "node" field is zero before initialization. This causes an oops if node 0 is offline in the page allocator because its zonelists are not initialized. From Dave Young's dmesg: SRAT: Node 1 PXM 2 0-d0000000 SRAT: Node 1 PXM 2 100000000-330000000 SRAT: Node 0 PXM 1 330000000-630000000 Initmem setup node 1 0000000000000000-000000000affb000 ... Built 1 zonelists in Node order, mobility grouping on. ... BUG: unable to handle kernel paging request at 0000000000001c08 IP: [] __alloc_pages_nodemask+0xb5/0x870 and __alloc_pages_nodemask+0xb5 translates to a NULL pointer on zonelist->_zonerefs. The fix is to initialize q->node at the time of allocation so the correct node is passed to the slab allocator later. Since blk_init_allocated_queue_node() is no longer needed, merge it with blk_init_allocated_queue(). [rientjes@google.com: changelog, initializing q->node] Reported-by: Dave Young Signed-off-by: Mike Snitzer Signed-off-by: David Rientjes Tested-by: Dave Young Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/blk-core.c | 14 +++----------- include/linux/blkdev.h | 3 --- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/block/blk-core.c b/block/blk-core.c index 847d04ef9f1..35ae52df6b6 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -418,6 +418,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) q->backing_dev_info.state = 0; q->backing_dev_info.capabilities = BDI_CAP_MAP_COPY; q->backing_dev_info.name = "block"; + q->node = node_id; err = bdi_init(&q->backing_dev_info); if (err) { @@ -502,7 +503,7 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id) if (!uninit_q) return NULL; - q = blk_init_allocated_queue_node(uninit_q, rfn, lock, node_id); + q = blk_init_allocated_queue(uninit_q, rfn, lock); if (!q) blk_cleanup_queue(uninit_q); @@ -513,19 +514,10 @@ EXPORT_SYMBOL(blk_init_queue_node); struct request_queue * blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn, spinlock_t *lock) -{ - return blk_init_allocated_queue_node(q, rfn, lock, -1); -} -EXPORT_SYMBOL(blk_init_allocated_queue); - -struct request_queue * -blk_init_allocated_queue_node(struct request_queue *q, request_fn_proc *rfn, - spinlock_t *lock, int node_id) { if (!q) return NULL; - q->node = node_id; if (blk_init_free_list(q)) return NULL; @@ -555,7 +547,7 @@ blk_init_allocated_queue_node(struct request_queue *q, request_fn_proc *rfn, return NULL; } -EXPORT_SYMBOL(blk_init_allocated_queue_node); +EXPORT_SYMBOL(blk_init_allocated_queue); int blk_get_queue(struct request_queue *q) { diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 1a23722e887..cd93f9994ad 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -798,9 +798,6 @@ extern void blk_unprep_request(struct request *); */ extern struct request_queue *blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id); -extern struct request_queue *blk_init_allocated_queue_node(struct request_queue *, - request_fn_proc *, - spinlock_t *, int node_id); extern struct request_queue *blk_init_queue(request_fn_proc *, spinlock_t *); extern struct request_queue *blk_init_allocated_queue(struct request_queue *, request_fn_proc *, spinlock_t *); From fcd02ab513c07dfc792fff5baa7ba7e930eba4b0 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Mon, 5 Dec 2011 23:19:51 +0100 Subject: [PATCH 0535/4025] ssb: fix init regression with SoCs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 329456d1ffb416c220813725b7363cda9975c9aa upstream. This fixes a Data bus error on some SoCs. The first fix for this problem did not solve it on all devices. commit 6ae8ec27868bfdbb815287bee8146acbefaee867 Author: Rafał Miłecki Date: Tue Jul 5 17:25:32 2011 +0200 ssb: fix init regression of hostmode PCI core In ssb_pcicore_fix_sprom_core_index() the sprom on the PCI core is accessed, but the sprom only exists when the ssb bus is connected over a PCI bus to the rest of the system and not when the SSB Bus is the main system bus. SoCs sometimes have a PCI host controller and there this code will not be executed, but there are some old SoCs with an PCI controller in client mode around and ssb_pcicore_fix_sprom_core_index() should not be called on these devices too. The PCI controller on these devices are unused, but without this fix it results in an Data bus error when it gets initialized. Cc: Michael Buesch Cc: Rafał Miłecki Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/ssb/driver_pcicore.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index d6620ad309c..c828151c419 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -516,10 +516,14 @@ static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc) static void ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) { - ssb_pcicore_fix_sprom_core_index(pc); + struct ssb_device *pdev = pc->dev; + struct ssb_bus *bus = pdev->bus; + + if (bus->bustype == SSB_BUSTYPE_PCI) + ssb_pcicore_fix_sprom_core_index(pc); /* Disable PCI interrupts. */ - ssb_write32(pc->dev, SSB_INTVEC, 0); + ssb_write32(pdev, SSB_INTVEC, 0); /* Additional PCIe always once-executed workarounds */ if (pc->dev->id.coreid == SSB_DEV_PCIE) { From 43579d76bdd733c9baf131bbc29719c2a2821569 Mon Sep 17 00:00:00 2001 From: Jason Chen Date: Wed, 30 Nov 2011 11:34:27 +0800 Subject: [PATCH 0536/4025] MXC PWM: should active during DOZE/WAIT/DBG mode commit c0d96aed8c6dd925afe9ea35491a0cd458642a86 upstream. Signed-off-by: Jason Chen Signed-off-by: Sascha Hauer Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-mxc/pwm.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c index 7a61ef8f471..7bf2a00034f 100644 --- a/arch/arm/plat-mxc/pwm.c +++ b/arch/arm/plat-mxc/pwm.c @@ -32,6 +32,9 @@ #define MX3_PWMSAR 0x0C /* PWM Sample Register */ #define MX3_PWMPR 0x10 /* PWM Period Register */ #define MX3_PWMCR_PRESCALER(x) (((x - 1) & 0xFFF) << 4) +#define MX3_PWMCR_DOZEEN (1 << 24) +#define MX3_PWMCR_WAITEN (1 << 23) +#define MX3_PWMCR_DBGEN (1 << 22) #define MX3_PWMCR_CLKSRC_IPG_HIGH (2 << 16) #define MX3_PWMCR_CLKSRC_IPG (1 << 16) #define MX3_PWMCR_EN (1 << 0) @@ -77,7 +80,9 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR); writel(period_cycles, pwm->mmio_base + MX3_PWMPR); - cr = MX3_PWMCR_PRESCALER(prescale) | MX3_PWMCR_EN; + cr = MX3_PWMCR_PRESCALER(prescale) | + MX3_PWMCR_DOZEEN | MX3_PWMCR_WAITEN | + MX3_PWMCR_DBGEN | MX3_PWMCR_EN; if (cpu_is_mx25()) cr |= MX3_PWMCR_CLKSRC_IPG; From 5cb6d2895e510f77514ef15c8f061621f09e4d78 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 12 Dec 2011 00:05:53 -0800 Subject: [PATCH 0537/4025] Input: synaptics - fix touchpad not working after S2R on Vostro V13 commit 8521478f67e95ada4e87970c7b41e504c724b2cf upstream. Synaptics touchpads on several Dell laptops, particularly Vostro V13 systems, may not respond properly to PS/2 commands and queries immediately after resuming from suspend to RAM. This leads to unresponsive touchpad after suspend/resume cycle. Adding a 1-second delay after resetting the device allows touchpad to finish initializing (calibrating?) and start reacting properly. Reported-by: Daniel Manrique Tested-by: Daniel Manrique Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/synaptics.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index e06e045bf90..6ad728f0e28 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -760,6 +761,16 @@ static int synaptics_reconnect(struct psmouse *psmouse) do { psmouse_reset(psmouse); + if (retry) { + /* + * On some boxes, right after resuming, the touchpad + * needs some time to finish initializing (I assume + * it needs time to calibrate) and start responding + * to Synaptics-specific queries, so let's wait a + * bit. + */ + ssleep(1); + } error = synaptics_detect(psmouse, 0); } while (error && ++retry < 3); From d051424f29eac6b4c173365a3ba5b9bb76870ce6 Mon Sep 17 00:00:00 2001 From: Eugene Surovegin Date: Thu, 15 Dec 2011 11:25:59 -0800 Subject: [PATCH 0538/4025] percpu: fix per_cpu_ptr_to_phys() handling of non-page-aligned addresses commit 9f57bd4d6dc69a4e3bf43044fa00fcd24dd363e3 upstream. per_cpu_ptr_to_phys() incorrectly rounds up its result for non-kmalloc case to the page boundary, which is bogus for any non-page-aligned address. This affects the only in-tree user of this function - sysfs handler for per-cpu 'crash_notes' physical address. The trouble is that the crash_notes per-cpu variable is not page-aligned: crash_notes = 0xc08e8ed4 PER-CPU OFFSET VALUES: CPU 0: 3711f000 CPU 1: 37129000 CPU 2: 37133000 CPU 3: 3713d000 So, the per-cpu addresses are: crash_notes on CPU 0: f7a07ed4 => phys 36b57ed4 crash_notes on CPU 1: f7a11ed4 => phys 36b4ded4 crash_notes on CPU 2: f7a1bed4 => phys 36b43ed4 crash_notes on CPU 3: f7a25ed4 => phys 36b39ed4 However, /sys/devices/system/cpu/cpu*/crash_notes says: /sys/devices/system/cpu/cpu0/crash_notes: 36b57000 /sys/devices/system/cpu/cpu1/crash_notes: 36b4d000 /sys/devices/system/cpu/cpu2/crash_notes: 36b43000 /sys/devices/system/cpu/cpu3/crash_notes: 36b39000 As you can see, all values are rounded down to a page boundary. Consequently, this is where kexec sets up the NOTE segments, and thus where the secondary kernel is looking for them. However, when the first kernel crashes, it saves the notes to the unaligned addresses, where they are not found. Fix it by adding offset_in_page() to the translated page address. -tj: Combined Eugene's and Petr's commit messages. Signed-off-by: Eugene Surovegin Signed-off-by: Tejun Heo Reported-by: Petr Tesarik Signed-off-by: Greg Kroah-Hartman --- mm/percpu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mm/percpu.c b/mm/percpu.c index 93b5a7c96a7..0ae7a09141e 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -1011,9 +1011,11 @@ phys_addr_t per_cpu_ptr_to_phys(void *addr) if (!is_vmalloc_addr(addr)) return __pa(addr); else - return page_to_phys(vmalloc_to_page(addr)); + return page_to_phys(vmalloc_to_page(addr)) + + offset_in_page(addr); } else - return page_to_phys(pcpu_addr_to_page(addr)); + return page_to_phys(pcpu_addr_to_page(addr)) + + offset_in_page(addr); } /** From 5b8befdb785856462ee5eafc8a52ceb78e720f77 Mon Sep 17 00:00:00 2001 From: Michel Lespinasse Date: Mon, 19 Dec 2011 17:12:06 -0800 Subject: [PATCH 0539/4025] binary_sysctl(): fix memory leak commit 3d3c8f93a237b64580c5c5e138edeb1377e98230 upstream. binary_sysctl() calls sysctl_getname() which allocates from names_cache slab usin __getname() The matching function to free the name is __putname(), and not putname() which should be used only to match getname() allocations. This is because when auditing is enabled, putname() calls audit_putname *instead* (not in addition) to __putname(). Then, if a syscall is in progress, audit_putname does not release the name - instead, it expects the name to get released when the syscall completes, but that will happen only if audit_getname() was called previously, i.e. if the name was allocated with getname() rather than the naked __getname(). So, __getname() followed by putname() ends up leaking memory. Signed-off-by: Michel Lespinasse Acked-by: Al Viro Cc: Christoph Hellwig Cc: Eric Paris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/sysctl_binary.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c index 3b8e028b960..e055e8b533c 100644 --- a/kernel/sysctl_binary.c +++ b/kernel/sysctl_binary.c @@ -1354,7 +1354,7 @@ static ssize_t binary_sysctl(const int *name, int nlen, fput(file); out_putname: - putname(pathname); + __putname(pathname); out: return result; } From 724c6ae2912dbfc5c6a9e309f92b786fbc141462 Mon Sep 17 00:00:00 2001 From: Frantisek Hrbata Date: Mon, 19 Dec 2011 17:11:59 -0800 Subject: [PATCH 0540/4025] oom: fix integer overflow of points in oom_badness commit ff05b6f7ae762b6eb464183eec994b28ea09f6dd upstream. An integer overflow will happen on 64bit archs if task's sum of rss, swapents and nr_ptes exceeds (2^31)/1000 value. This was introduced by commit f755a04 oom: use pte pages in OOM score where the oom score computation was divided into several steps and it's no longer computed as one expression in unsigned long(rss, swapents, nr_pte are unsigned long), where the result value assigned to points(int) is in range(1..1000). So there could be an int overflow while computing 176 points *= 1000; and points may have negative value. Meaning the oom score for a mem hog task will be one. 196 if (points <= 0) 197 return 1; For example: [ 3366] 0 3366 35390480 24303939 5 0 0 oom01 Out of memory: Kill process 3366 (oom01) score 1 or sacrifice child Here the oom1 process consumes more than 24303939(rss)*4096~=92GB physical memory, but it's oom score is one. In this situation the mem hog task is skipped and oom killer kills another and most probably innocent task with oom score greater than one. The points variable should be of type long instead of int to prevent the int overflow. Signed-off-by: Frantisek Hrbata Acked-by: KOSAKI Motohiro Acked-by: Oleg Nesterov Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/oom_kill.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 8093fc766d1..7c72487ca45 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -162,7 +162,7 @@ static bool oom_unkillable_task(struct task_struct *p, unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem, const nodemask_t *nodemask, unsigned long totalpages) { - int points; + long points; if (oom_unkillable_task(p, mem, nodemask)) return 0; From 3c681ec96dcc0acd6d5386773b44e6c129919394 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 19 Dec 2011 16:38:30 +0100 Subject: [PATCH 0541/4025] oprofile: Fix uninitialized memory access when writing to writing to oprofilefs commit 913050b91eb94f194392dd797b1ff3779f606ac0 upstream. If oprofilefs_ulong_from_user() is called with count equals zero, *val remains unchanged. Depending on the implementation it might be uninitialized. Change oprofilefs_ulong_from_user()'s interface to return count on success. Thus, we are able to return early if count equals zero which avoids using *val uninitialized. Fixing all users of oprofilefs_ulong_ from_user(). This follows write syscall implementation when count is zero: "If count is zero ... [and if] no errors are detected, 0 will be returned without causing any other effect." (man 2 write) Reported-By: Mike Waychison Signed-off-by: Robert Richter Cc: Andrew Morton Cc: oprofile-list Link: http://lkml.kernel.org/r/20111219153830.GH16765@erda.amd.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/s390/oprofile/init.c | 2 +- drivers/oprofile/oprofile_files.c | 7 ++++--- drivers/oprofile/oprofilefs.c | 11 +++++++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/arch/s390/oprofile/init.c b/arch/s390/oprofile/init.c index 0e358c2cffe..422110a4385 100644 --- a/arch/s390/oprofile/init.c +++ b/arch/s390/oprofile/init.c @@ -90,7 +90,7 @@ static ssize_t hwsampler_write(struct file *file, char const __user *buf, return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; if (oprofile_started) diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 89f63456646..84a208dbed9 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -45,7 +45,7 @@ static ssize_t timeout_write(struct file *file, char const __user *buf, return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; retval = oprofile_set_timeout(val); @@ -84,7 +84,7 @@ static ssize_t depth_write(struct file *file, char const __user *buf, size_t cou return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; retval = oprofile_set_ulong(&oprofile_backtrace_depth, val); @@ -141,9 +141,10 @@ static ssize_t enable_write(struct file *file, char const __user *buf, size_t co return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; + retval = 0; if (val) retval = oprofile_start(); else diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index e9ff6f7770b..1c0b799b30b 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -60,6 +60,13 @@ ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user *buf, size_t cou } +/* + * Note: If oprofilefs_ulong_from_user() returns 0, then *val remains + * unchanged and might be uninitialized. This follows write syscall + * implementation when count is zero: "If count is zero ... [and if] + * no errors are detected, 0 will be returned without causing any + * other effect." (man 2 write) + */ int oprofilefs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count) { char tmpbuf[TMPBUFSIZE]; @@ -79,7 +86,7 @@ int oprofilefs_ulong_from_user(unsigned long *val, char const __user *buf, size_ spin_lock_irqsave(&oprofilefs_lock, flags); *val = simple_strtoul(tmpbuf, NULL, 0); spin_unlock_irqrestore(&oprofilefs_lock, flags); - return 0; + return count; } @@ -99,7 +106,7 @@ static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_ return -EINVAL; retval = oprofilefs_ulong_from_user(&value, buf, count); - if (retval) + if (retval <= 0) return retval; retval = oprofile_set_ulong(file->private_data, value); From 746b9ba6177ef65cd2e5b674b9b8b61b09c74421 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 1 Dec 2011 16:37:42 -0500 Subject: [PATCH 0542/4025] NFSv4.1: Ensure that we handle _all_ SEQUENCE status bits. commit 111d489f0fb431f4ae85d96851fbf8d3248c09d8 upstream. Currently, the code assumes that the SEQUENCE status bits are mutually exclusive. They are not... Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4state.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index e97dd219f84..87822a32709 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1519,16 +1519,16 @@ void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags) { if (!flags) return; - else if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED) + if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED) nfs41_handle_server_reboot(clp); - else if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED | + if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED | SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED | SEQ4_STATUS_ADMIN_STATE_REVOKED | SEQ4_STATUS_LEASE_MOVED)) nfs41_handle_state_revoked(clp); - else if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED) + if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED) nfs41_handle_recallable_state_revoked(clp); - else if (flags & (SEQ4_STATUS_CB_PATH_DOWN | + if (flags & (SEQ4_STATUS_CB_PATH_DOWN | SEQ4_STATUS_BACKCHANNEL_FAULT | SEQ4_STATUS_CB_PATH_DOWN_SESSION)) nfs41_handle_cb_path_down(clp); From 52367e4731f577370011910c06cb428df55d054b Mon Sep 17 00:00:00 2001 From: David Howells Date: Tue, 13 Dec 2011 14:49:04 +0000 Subject: [PATCH 0543/4025] SELinux: Fix RCU deref check warning in sel_netport_insert() commit 50345f1ea9cda4618d9c26e590a97ecd4bc7ac75 upstream. Fix the following bug in sel_netport_insert() where rcu_dereference() should be rcu_dereference_protected() as sel_netport_lock is held. =================================================== [ INFO: suspicious rcu_dereference_check() usage. ] --------------------------------------------------- security/selinux/netport.c:127 invoked rcu_dereference_check() without protection! other info that might help us debug this: rcu_scheduler_active = 1, debug_locks = 0 1 lock held by ossec-rootcheck/3323: #0: (sel_netport_lock){+.....}, at: [] sel_netport_sid+0xbb/0x226 stack backtrace: Pid: 3323, comm: ossec-rootcheck Not tainted 3.1.0-rc8-fsdevel+ #1095 Call Trace: [] lockdep_rcu_dereference+0xa7/0xb0 [] sel_netport_sid+0x1b7/0x226 [] ? sel_netport_avc_callback+0xbc/0xbc [] selinux_socket_bind+0x115/0x230 [] ? might_fault+0x4e/0x9e [] ? might_fault+0x97/0x9e [] security_socket_bind+0x11/0x13 [] sys_bind+0x56/0x95 [] ? sysret_check+0x27/0x62 [] ? trace_hardirqs_on_caller+0x11e/0x155 [] ? audit_syscall_entry+0x17b/0x1ae [] ? trace_hardirqs_on_thunk+0x3a/0x3f [] system_call_fastpath+0x16/0x1b Signed-off-by: David Howells Acked-by: Paul Moore Acked-by: Eric Dumazet Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman --- security/selinux/netport.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/security/selinux/netport.c b/security/selinux/netport.c index cfe2d72d3fb..e2b74ebdc38 100644 --- a/security/selinux/netport.c +++ b/security/selinux/netport.c @@ -139,7 +139,9 @@ static void sel_netport_insert(struct sel_netport *port) if (sel_netport_hash[idx].size == SEL_NETPORT_HASH_BKT_LIMIT) { struct sel_netport *tail; tail = list_entry( - rcu_dereference(sel_netport_hash[idx].list.prev), + rcu_dereference_protected( + sel_netport_hash[idx].list.prev, + lockdep_is_held(&sel_netport_lock)), struct sel_netport, list); list_del_rcu(&tail->list); call_rcu(&tail->rcu, sel_netport_free); From 2e23cd501a9c6a0bfbe2b44781b4a35b0f0d4f29 Mon Sep 17 00:00:00 2001 From: Thomas Meyer Date: Mon, 19 Dec 2011 17:11:55 -0800 Subject: [PATCH 0544/4025] nilfs2: unbreak compat ioctl commit 695c60f21c69e525a89279a5f35bae4ff237afbc upstream. commit 828b1c50ae ("nilfs2: add compat ioctl") incidentally broke all other NILFS compat ioctls. Make them work again. Signed-off-by: Thomas Meyer Signed-off-by: Ryusuke Konishi Tested-by: Ryusuke Konishi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/nilfs2/ioctl.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 41d6743d303..3e654273cfc 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -842,6 +842,19 @@ long nilfs_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case FS_IOC32_GETVERSION: cmd = FS_IOC_GETVERSION; break; + case NILFS_IOCTL_CHANGE_CPMODE: + case NILFS_IOCTL_DELETE_CHECKPOINT: + case NILFS_IOCTL_GET_CPINFO: + case NILFS_IOCTL_GET_CPSTAT: + case NILFS_IOCTL_GET_SUINFO: + case NILFS_IOCTL_GET_SUSTAT: + case NILFS_IOCTL_GET_VINFO: + case NILFS_IOCTL_GET_BDESCS: + case NILFS_IOCTL_CLEAN_SEGMENTS: + case NILFS_IOCTL_SYNC: + case NILFS_IOCTL_RESIZE: + case NILFS_IOCTL_SET_ALLOC_RANGE: + break; default: return -ENOIOCTLCMD; } From 2aad1ca4711a46ca4540c924ffb84e7673a4738c Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 15 Dec 2011 13:34:50 +1030 Subject: [PATCH 0545/4025] mmc: vub300: fix type of firmware_rom_wait_states module parameter commit 61074287c2965edf0fc75b54ae8f4ce99f182669 upstream. You didn't mean this to be a bool. Signed-off-by: Rusty Russell Acked-by: Tony Olech Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/vub300.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index d4455ffbefd..52f4b644766 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -259,7 +259,7 @@ static int firmware_rom_wait_states = 0x04; static int firmware_rom_wait_states = 0x1C; #endif -module_param(firmware_rom_wait_states, bool, 0644); +module_param(firmware_rom_wait_states, int, 0644); MODULE_PARM_DESC(firmware_rom_wait_states, "ROM wait states byte=RRRIIEEE (Reserved Internal External)"); From b05727c7f8e3b30309d013a7d3bbc6d1e6f860ba Mon Sep 17 00:00:00 2001 From: Mandeep Singh Baines Date: Thu, 15 Dec 2011 11:36:43 -0800 Subject: [PATCH 0546/4025] cgroups: fix a css_set not found bug in cgroup_attach_proc commit e0197aae59e55c06db172bfbe1a1cdb8c0e1cab3 upstream. There is a BUG when migrating a PF_EXITING proc. Since css_set_prefetch() is not called for the PF_EXITING case, find_existing_css_set() will return NULL inside cgroup_task_migrate() causing a BUG. This bug is easy to reproduce. Create a zombie and echo its pid to cgroup.procs. $ cat zombie.c \#include int main() { if (fork()) pause(); return 0; } $ We are hitting this bug pretty regularly on ChromeOS. This bug is already fixed by Tejun Heo's cgroup patchset which is targetted for the next merge window: https://lkml.org/lkml/2011/11/1/356 I've create a smaller patch here which just fixes this bug so that a fix can be merged into the current release and stable. Signed-off-by: Mandeep Singh Baines Downstream-Bug-Report: http://crosbug.com/23953 Reviewed-by: Li Zefan Signed-off-by: Tejun Heo Cc: containers@lists.linux-foundation.org Cc: cgroups@vger.kernel.org Cc: KAMEZAWA Hiroyuki Cc: Frederic Weisbecker Cc: Oleg Nesterov Cc: Andrew Morton Cc: Paul Menage Cc: Olof Johansson Signed-off-by: Greg Kroah-Hartman --- kernel/cgroup.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 2731d115d72..575a5e78263 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2095,11 +2095,6 @@ int cgroup_attach_proc(struct cgroup *cgrp, struct task_struct *leader) continue; /* get old css_set pointer */ task_lock(tsk); - if (tsk->flags & PF_EXITING) { - /* ignore this task if it's going away */ - task_unlock(tsk); - continue; - } oldcg = tsk->cgroups; get_css_set(oldcg); task_unlock(tsk); From 20e725bc08091c303a469d8e1e295bf3b360c778 Mon Sep 17 00:00:00 2001 From: Ilya Yanok Date: Mon, 1 Aug 2011 23:00:28 +0200 Subject: [PATCH 0547/4025] mfd: Fix twl-core oops while calling twl_i2c_* for unbound driver commit 8653be1afd60d6e8c36139b487e375b70357d9ef upstream. Check inuse variable before trying to access twl_map to prevent dereferencing of uninitialized variable. Signed-off-by: Ilya Yanok Signed-off-by: Samuel Ortiz Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/twl-core.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index b8f2a4e7f6e..f82413a9889 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -362,13 +362,13 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); return -EPERM; } - sid = twl_map[mod_no].sid; - twl = &twl_modules[sid]; - if (unlikely(!inuse)) { - pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); + pr_err("%s: not initialized\n", DRIVER_NAME); return -EPERM; } + sid = twl_map[mod_no].sid; + twl = &twl_modules[sid]; + mutex_lock(&twl->xfer_lock); /* * [MSG1]: fill the register address data @@ -419,13 +419,13 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); return -EPERM; } - sid = twl_map[mod_no].sid; - twl = &twl_modules[sid]; - if (unlikely(!inuse)) { - pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); + pr_err("%s: not initialized\n", DRIVER_NAME); return -EPERM; } + sid = twl_map[mod_no].sid; + twl = &twl_modules[sid]; + mutex_lock(&twl->xfer_lock); /* [MSG1] fill the register address data */ msg = &twl->xfer_msg[0]; From 2f79eddd49d391aded0b0c20f7eef3bec6d5e096 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 21 Dec 2011 11:05:48 -0600 Subject: [PATCH 0548/4025] vfs: __read_cache_page should use gfp argument rather than GFP_KERNEL commit e6f67b8c05f5e129e126f4409ddac6f25f58ffcb upstream. lockdep reports a deadlock in jfs because a special inode's rw semaphore is taken recursively. The mapping's gfp mask is GFP_NOFS, but is not used when __read_cache_page() calls add_to_page_cache_lru(). Signed-off-by: Dave Kleikamp Acked-by: Hugh Dickins Acked-by: Al Viro Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/filemap.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/mm/filemap.c b/mm/filemap.c index a8251a8d345..dd828ea59dc 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1807,7 +1807,7 @@ static struct page *__read_cache_page(struct address_space *mapping, page = __page_cache_alloc(gfp | __GFP_COLD); if (!page) return ERR_PTR(-ENOMEM); - err = add_to_page_cache_lru(page, mapping, index, GFP_KERNEL); + err = add_to_page_cache_lru(page, mapping, index, gfp); if (unlikely(err)) { page_cache_release(page); if (err == -EEXIST) @@ -1904,10 +1904,7 @@ static struct page *wait_on_page_read(struct page *page) * @gfp: the page allocator flags to use if allocating * * This is the same as "read_mapping_page(mapping, index, NULL)", but with - * any new page allocations done using the specified allocation flags. Note - * that the Radix tree operations will still use GFP_KERNEL, so you can't - * expect to do this atomically or anything like that - but you can pass in - * other page requirements. + * any new page allocations done using the specified allocation flags. * * If the page does not get brought uptodate, return -EIO. */ From 2daac55a9ada99404e67f4f8182a66c4ee8b3969 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 4 Nov 2011 10:07:06 -0300 Subject: [PATCH 0549/4025] media: s5p-fimc: Use correct fourcc for RGB565 colour format commit f83f71fda27650ae43558633be93652577dbc38c upstream. With 16-bit RGB565 colour format pixels are stored by the device in memory in the following order: | b3 | b2 | b1 | b0 | ~+-----+-----+-----+-----+ | R5 G6 B5 | R5 G6 B5 | This corresponds to V4L2_PIX_FMT_RGB565 fourcc, not V4L2_PIX_FMT_RGB565X. This change is required to avoid trouble when setting up video pipeline with the s5p-tv devices, so the colour formats at both devices can be properly matched. Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/s5p-fimc/fimc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index bdf19ada917..e9babcb0887 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -36,7 +36,7 @@ static char *fimc_clocks[MAX_FIMC_CLOCKS] = { static struct fimc_fmt fimc_formats[] = { { .name = "RGB565", - .fourcc = V4L2_PIX_FMT_RGB565X, + .fourcc = V4L2_PIX_FMT_RGB565, .depth = { 16 }, .color = S5P_FIMC_RGB565, .memplanes = 1, From 3c00ff7bd542942ff7f3e473d1372b4ae892318f Mon Sep 17 00:00:00 2001 From: Rajkumar Manoharan Date: Sat, 10 Dec 2011 18:59:43 +0530 Subject: [PATCH 0550/4025] ath9k: fix max phy rate at rate control init commit 10636bc2d60942254bda149827b922c41f4cb4af upstream. The stations always chooses 1Mbps for all trasmitting frames, whenever the AP is configured to lock the supported rates. As the max phy rate is always set with the 4th from highest phy rate, this assumption might be wrong if we have less than that. Fix that. Cc: Paul Stewart Reported-by: Ajay Gummalla Signed-off-by: Rajkumar Manoharan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/rc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index ba7f36ab0a7..ea35843dd38 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1252,7 +1252,9 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->max_valid_rate = k; ath_rc_sort_validrates(rate_table, ath_rc_priv); - ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; + ath_rc_priv->rate_max_phy = (k > 4) ? + ath_rc_priv->valid_rate_index[k-4] : + ath_rc_priv->valid_rate_index[k-1]; ath_rc_priv->rate_table = rate_table; ath_dbg(common, ATH_DBG_CONFIG, From 3ed4fae4b9ff076b6a88b341491dc8dee2977f88 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 8 Dec 2011 15:52:00 -0800 Subject: [PATCH 0551/4025] iwlwifi: do not set the sequence control bit is not needed commit 123877b80ed62c3b897c53357b622574c023b642 upstream. Check the IEEE80211_TX_CTL_ASSIGN_SEQ flag from mac80211, then decide how to set the TX_CMD_FLG_SEQ_CTL_MSK bit. Setting the wrong bit in BAR frame whill make the firmware to increment the sequence number which is incorrect and cause unknown behavior. Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 4974cd7837c..1ab1ef15c5a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -385,7 +385,10 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, tx_cmd->tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; } else { - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + else + tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; } priv->cfg->ops->utils->tx_cmd_protection(priv, info, fc, &tx_flags); From a37fd0740a9d2b261dc3d7781e3f3923f9076bb1 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Wed, 14 Dec 2011 08:22:36 -0800 Subject: [PATCH 0552/4025] iwlwifi: allow to switch to HT40 if not associated commit 78feb35b8161acd95c33a703ed6ab6f554d29387 upstream. My previous patch 34a5b4b6af104cf18eb50748509528b9bdbc4036 iwlwifi: do not re-configure HT40 after associated Fix the case of HT40 after association on specified AP, but it break the association for some APs and cause not able to establish connection. We need to address HT40 before and after addociation. Reported-by: Andrej Gelenberg Signed-off-by: Wey-Yi Guy Tested-by: Andrej Gelenberg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index b849ad79e14..39a3c9c235f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -490,8 +490,8 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) if (ctx->ht.enabled) { /* if HT40 is used, it should not change * after associated except channel switch */ - if (iwl_is_associated_ctx(ctx) && - !ctx->ht.is_40mhz) + if (!ctx->ht.is_40mhz || + !iwl_is_associated_ctx(ctx)) iwlagn_config_ht40(conf, ctx); } else ctx->ht.is_40mhz = false; From 4875f39a0548a1fa5f55b4a90dca0f4a7ad8f237 Mon Sep 17 00:00:00 2001 From: Hillf Danton Date: Mon, 19 Dec 2011 17:11:57 -0800 Subject: [PATCH 0553/4025] memcg: keep root group unchanged if creation fails commit a41c58a6665cc995e237303b05db42100b71b65e upstream. If the request is to create non-root group and we fail to meet it, we should leave the root unchanged. Signed-off-by: Hillf Danton Signed-off-by: Hugh Dickins Acked-by: KAMEZAWA Hiroyuki Acked-by: Michal Hocko Cc: Balbir Singh Cc: David Rientjes Cc: Andrea Arcangeli Cc: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/memcontrol.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 59ac5d6de47..d99217b322a 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -4963,9 +4963,9 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont) int cpu; enable_swap_cgroup(); parent = NULL; - root_mem_cgroup = mem; if (mem_cgroup_soft_limit_tree_init()) goto free_out; + root_mem_cgroup = mem; for_each_possible_cpu(cpu) { struct memcg_stock_pcp *stock = &per_cpu(memcg_stock, cpu); @@ -5004,7 +5004,6 @@ mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont) return &mem->css; free_out: __mem_cgroup_free(mem); - root_mem_cgroup = NULL; return ERR_PTR(error); } From f3545737cf06d342d34483b7a8421d0bb90b9c1b Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Thu, 22 Dec 2011 02:45:29 +0530 Subject: [PATCH 0554/4025] VFS: Fix race between CPU hotplug and lglocks commit e30e2fdfe56288576ee9e04dbb06b4bd5f282203 upstream. Currently, the *_global_[un]lock_online() routines are not at all synchronized with CPU hotplug. Soft-lockups detected as a consequence of this race was reported earlier at https://lkml.org/lkml/2011/8/24/185. (Thanks to Cong Meng for finding out that the root-cause of this issue is the race condition between br_write_[un]lock() and CPU hotplug, which results in the lock states getting messed up). Fixing this race by just adding {get,put}_online_cpus() at appropriate places in *_global_[un]lock_online() is not a good option, because, then suddenly br_write_[un]lock() would become blocking, whereas they have been kept as non-blocking all this time, and we would want to keep them that way. So, overall, we want to ensure 3 things: 1. br_write_lock() and br_write_unlock() must remain as non-blocking. 2. The corresponding lock and unlock of the per-cpu spinlocks must not happen for different sets of CPUs. 3. Either prevent any new CPU online operation in between this lock-unlock, or ensure that the newly onlined CPU does not proceed with its corresponding per-cpu spinlock unlocked. To achieve all this: (a) We introduce a new spinlock that is taken by the *_global_lock_online() routine and released by the *_global_unlock_online() routine. (b) We register a callback for CPU hotplug notifications, and this callback takes the same spinlock as above. (c) We maintain a bitmap which is close to the cpu_online_mask, and once it is initialized in the lock_init() code, all future updates to it are done in the callback, under the above spinlock. (d) The above bitmap is used (instead of cpu_online_mask) while locking and unlocking the per-cpu locks. The callback takes the spinlock upon the CPU_UP_PREPARE event. So, if the br_write_lock-unlock sequence is in progress, the callback keeps spinning, thus preventing the CPU online operation till the lock-unlock sequence is complete. This takes care of requirement (3). The bitmap that we maintain remains unmodified throughout the lock-unlock sequence, since all updates to it are managed by the callback, which takes the same spinlock as the one taken by the lock code and released only by the unlock routine. Combining this with (d) above, satisfies requirement (2). Overall, since we use a spinlock (mentioned in (a)) to prevent CPU hotplug operations from racing with br_write_lock-unlock, requirement (1) is also taken care of. By the way, it is to be noted that a CPU offline operation can actually run in parallel with our lock-unlock sequence, because our callback doesn't react to notifications earlier than CPU_DEAD (in order to maintain our bitmap properly). And this means, since we use our own bitmap (which is stale, on purpose) during the lock-unlock sequence, we could end up unlocking the per-cpu lock of an offline CPU (because we had locked it earlier, when the CPU was online), in order to satisfy requirement (2). But this is harmless, though it looks a bit awkward. Debugged-by: Cong Meng Signed-off-by: Srivatsa S. Bhat Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- include/linux/lglock.h | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/include/linux/lglock.h b/include/linux/lglock.h index f549056fb20..87f402ccec5 100644 --- a/include/linux/lglock.h +++ b/include/linux/lglock.h @@ -22,6 +22,7 @@ #include #include #include +#include /* can make br locks by using local lock for read side, global lock for write */ #define br_lock_init(name) name##_lock_init() @@ -72,9 +73,31 @@ #define DEFINE_LGLOCK(name) \ \ + DEFINE_SPINLOCK(name##_cpu_lock); \ + cpumask_t name##_cpus __read_mostly; \ DEFINE_PER_CPU(arch_spinlock_t, name##_lock); \ DEFINE_LGLOCK_LOCKDEP(name); \ \ + static int \ + name##_lg_cpu_callback(struct notifier_block *nb, \ + unsigned long action, void *hcpu) \ + { \ + switch (action & ~CPU_TASKS_FROZEN) { \ + case CPU_UP_PREPARE: \ + spin_lock(&name##_cpu_lock); \ + cpu_set((unsigned long)hcpu, name##_cpus); \ + spin_unlock(&name##_cpu_lock); \ + break; \ + case CPU_UP_CANCELED: case CPU_DEAD: \ + spin_lock(&name##_cpu_lock); \ + cpu_clear((unsigned long)hcpu, name##_cpus); \ + spin_unlock(&name##_cpu_lock); \ + } \ + return NOTIFY_OK; \ + } \ + static struct notifier_block name##_lg_cpu_notifier = { \ + .notifier_call = name##_lg_cpu_callback, \ + }; \ void name##_lock_init(void) { \ int i; \ LOCKDEP_INIT_MAP(&name##_lock_dep_map, #name, &name##_lock_key, 0); \ @@ -83,6 +106,11 @@ lock = &per_cpu(name##_lock, i); \ *lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; \ } \ + register_hotcpu_notifier(&name##_lg_cpu_notifier); \ + get_online_cpus(); \ + for_each_online_cpu(i) \ + cpu_set(i, name##_cpus); \ + put_online_cpus(); \ } \ EXPORT_SYMBOL(name##_lock_init); \ \ @@ -124,9 +152,9 @@ \ void name##_global_lock_online(void) { \ int i; \ - preempt_disable(); \ + spin_lock(&name##_cpu_lock); \ rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_); \ - for_each_online_cpu(i) { \ + for_each_cpu(i, &name##_cpus) { \ arch_spinlock_t *lock; \ lock = &per_cpu(name##_lock, i); \ arch_spin_lock(lock); \ @@ -137,12 +165,12 @@ void name##_global_unlock_online(void) { \ int i; \ rwlock_release(&name##_lock_dep_map, 1, _RET_IP_); \ - for_each_online_cpu(i) { \ + for_each_cpu(i, &name##_cpus) { \ arch_spinlock_t *lock; \ lock = &per_cpu(name##_lock, i); \ arch_spin_unlock(lock); \ } \ - preempt_enable(); \ + spin_unlock(&name##_cpu_lock); \ } \ EXPORT_SYMBOL(name##_global_unlock_online); \ \ From 8048ac75378918eab0f68ba175915e72ef73e0da Mon Sep 17 00:00:00 2001 From: Jason Chen Date: Mon, 19 Dec 2011 11:23:28 +0800 Subject: [PATCH 0555/4025] ARM:imx:fix pwm period value commit 5776ac2eb33164c77cdb4d2b48feee15616eaba3 upstream. According to imx pwm RM, the real period value should be PERIOD value in PWMPR plus 2. PWMO (Hz) = PCLK(Hz) / (period +2) Signed-off-by: Jason Chen Signed-off-by: Sascha Hauer Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-mxc/pwm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c index 7bf2a00034f..f4b68beddbb 100644 --- a/arch/arm/plat-mxc/pwm.c +++ b/arch/arm/plat-mxc/pwm.c @@ -77,6 +77,15 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns) do_div(c, period_ns); duty_cycles = c; + /* + * according to imx pwm RM, the real period value should be + * PERIOD value in PWMPR plus 2. + */ + if (period_cycles > 2) + period_cycles -= 2; + else + period_cycles = 0; + writel(duty_cycles, pwm->mmio_base + MX3_PWMSAR); writel(period_cycles, pwm->mmio_base + MX3_PWMPR); From bc23ab0861a252bdbdf3bd982c37a6a96c2ceba6 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 13 Dec 2011 16:51:04 +0100 Subject: [PATCH 0556/4025] ARM: 7214/1: mmc: mmci: Fixup handling of MCI_STARTBITERR commit b63038d6f4ca5d1849ce01d9fc5bb9cb426dec73 upstream. The interrupt was previously enabled and then correctly cleared. Now we also handle it correctly. Tested-by: Linus Walleij Signed-off-by: Ulf Hansson Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/mmci.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index fe140724a02..03a05fd803e 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -557,7 +557,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status) { /* First check for errors */ - if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { + if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR| + MCI_TXUNDERRUN|MCI_RXOVERRUN)) { u32 remain, success; /* Terminate the DMA transfer */ @@ -837,8 +838,9 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status); data = host->data; - if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN| - MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data) + if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR| + MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_DATAEND| + MCI_DATABLOCKEND) && data) mmci_data_irq(host, data, status); cmd = host->cmd; From 9267a9e850bf6c52dd7c95f3978dc78a1d3ad1a1 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 13 Dec 2011 16:58:43 +0100 Subject: [PATCH 0557/4025] ARM: 7220/1: mmc: mmci: Fixup error handling for dma commit 3b6e3c73851a9a4b0e6ed9d378206341dd65e8a5 upstream. When getting a cmd irq during an ongoing data transfer with dma, the dma job were never terminated. This is now corrected. Tested-by: Linus Walleij Signed-off-by: Per Forlin Signed-off-by: Ulf Hansson Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/mmci.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 03a05fd803e..9394d0b77ec 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -637,8 +637,12 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, } if (!cmd->data || cmd->error) { - if (host->data) + if (host->data) { + /* Terminate the DMA transfer */ + if (dma_inprogress(host)) + mmci_dma_data_error(host); mmci_stop_data(host); + } mmci_request_end(host, cmd->mrq); } else if (!(cmd->data->flags & MMC_DATA_READ)) { mmci_start_data(host, cmd->data); From 4347b837ab999865063649cf801ba4f8d7e8748e Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Thu, 22 Dec 2011 16:15:40 +0100 Subject: [PATCH 0558/4025] oprofile, arm/sh: Fix oprofile_arch_exit() linkage issue commit 55205c916e179e09773d98d290334d319f45ac6b upstream. This change fixes a linking problem, which happens if oprofile is selected to be compiled as built-in: `oprofile_arch_exit' referenced in section `.init.text' of arch/arm/oprofile/built-in.o: defined in discarded section `.exit.text' of arch/arm/oprofile/built-in.o The problem is appeared after commit 87121ca504, which introduced oprofile_arch_exit() calls from __init function. Note that the aforementioned commit has been backported to stable branches, and the problem is known to be reproduced at least with 3.0.13 and 3.1.5 kernels. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Robert Richter Cc: Will Deacon Cc: oprofile-list Link: http://lkml.kernel.org/r/20111222151540.GB16765@erda.amd.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/arm/oprofile/common.c | 2 +- arch/sh/oprofile/common.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c index c074e66ad22..4e0a371630b 100644 --- a/arch/arm/oprofile/common.c +++ b/arch/arm/oprofile/common.c @@ -116,7 +116,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) return oprofile_perf_init(ops); } -void __exit oprofile_arch_exit(void) +void oprofile_arch_exit(void) { oprofile_perf_exit(); } diff --git a/arch/sh/oprofile/common.c b/arch/sh/oprofile/common.c index b4c2d2b946d..e4dd5d5a111 100644 --- a/arch/sh/oprofile/common.c +++ b/arch/sh/oprofile/common.c @@ -49,7 +49,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) return oprofile_perf_init(ops); } -void __exit oprofile_arch_exit(void) +void oprofile_arch_exit(void) { oprofile_perf_exit(); kfree(sh_pmu_op_name); @@ -60,5 +60,5 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) ops->backtrace = sh_backtrace; return -ENODEV; } -void __exit oprofile_arch_exit(void) {} +void oprofile_arch_exit(void) {} #endif /* CONFIG_HW_PERF_EVENTS */ From 3ce696d12b26c9c1cfedeb194a02606bef2854a4 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Sat, 31 Dec 2011 11:44:01 -0800 Subject: [PATCH 0559/4025] futex: Fix uninterruptible loop due to gate_area commit e6780f7243eddb133cc20ec37fa69317c218b709 upstream. It was found (by Sasha) that if you use a futex located in the gate area we get stuck in an uninterruptible infinite loop, much like the ZERO_PAGE issue. While looking at this problem, PeterZ realized you'll get into similar trouble when hitting any install_special_pages() mapping. And are there still drivers setting up their own special mmaps without page->mapping, and without special VM or pte flags to make get_user_pages fail? In most cases, if page->mapping is NULL, we do not need to retry at all: Linus points out that even /proc/sys/vm/drop_caches poses no problem, because it ends up using remove_mapping(), which takes care not to interfere when the page reference count is raised. But there is still one case which does need a retry: if memory pressure called shmem_writepage in between get_user_pages_fast dropping page table lock and our acquiring page lock, then the page gets switched from filecache to swapcache (and ->mapping set to NULL) whatever the refcount. Fault it back in to get the page->mapping needed for key->shared.inode. Reported-by: Sasha Levin Signed-off-by: Hugh Dickins Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/futex.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index 8b6da250723..6487e4cb993 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -314,17 +314,29 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) #endif lock_page(page_head); + + /* + * If page_head->mapping is NULL, then it cannot be a PageAnon + * page; but it might be the ZERO_PAGE or in the gate area or + * in a special mapping (all cases which we are happy to fail); + * or it may have been a good file page when get_user_pages_fast + * found it, but truncated or holepunched or subjected to + * invalidate_complete_page2 before we got the page lock (also + * cases which we are happy to fail). And we hold a reference, + * so refcount care in invalidate_complete_page's remove_mapping + * prevents drop_caches from setting mapping to NULL beneath us. + * + * The case we do have to guard against is when memory pressure made + * shmem_writepage move it from filecache to swapcache beneath us: + * an unlikely race, but we do need to retry for page_head->mapping. + */ if (!page_head->mapping) { + int shmem_swizzled = PageSwapCache(page_head); unlock_page(page_head); put_page(page_head); - /* - * ZERO_PAGE pages don't have a mapping. Avoid a busy loop - * trying to find one. RW mapping would have COW'd (and thus - * have a mapping) so this page is RO and won't ever change. - */ - if ((page_head == ZERO_PAGE(address))) - return -EFAULT; - goto again; + if (shmem_swizzled) + goto again; + return -EFAULT; } /* From 33c118d42de2ce4c0dbc60b72b2fdf124a54b19d Mon Sep 17 00:00:00 2001 From: "Mingarelli, Thomas" Date: Mon, 7 Nov 2011 10:59:00 +0100 Subject: [PATCH 0560/4025] watchdog: hpwdt: Changes to handle NX secure bit in 32bit path commit e67d668e147c3b4fec638c9e0ace04319f5ceccd upstream. This patch makes use of the set_memory_x() kernel API in order to make necessary BIOS calls to source NMIs. This is needed for SLES11 SP2 and the latest upstream kernel as it appears the NX Execute Disable has grown in its control. Signed-off by: Thomas Mingarelli Signed-off by: Wim Van Sebroeck Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/hpwdt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 8cb26855bfe..9cb60dfbb59 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -216,6 +216,7 @@ static int __devinit cru_detect(unsigned long map_entry, cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE; + set_memory_x((unsigned long)bios32_entrypoint, (2 * PAGE_SIZE)); asminline_call(&cmn_regs, bios32_entrypoint); if (cmn_regs.u1.ral != 0) { @@ -233,8 +234,10 @@ static int __devinit cru_detect(unsigned long map_entry, if ((physical_bios_base + physical_bios_offset)) { cru_rom_addr = ioremap(cru_physical_address, cru_length); - if (cru_rom_addr) + if (cru_rom_addr) { + set_memory_x((unsigned long)cru_rom_addr, cru_length); retval = 0; + } } printk(KERN_DEBUG "hpwdt: CRU Base Address: 0x%lx\n", From 6f4214ef6a0e3c8319880eb5570ba2ae787bb577 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 21 Dec 2011 11:58:17 -0500 Subject: [PATCH 0561/4025] drm/radeon/kms: bail on BTC parts if MC ucode is missing commit 77e00f2ea94abee1ad13bdfde19cf7aa25992b0e upstream. We already do this for cayman, need to also do it for BTC parts. The default memory and voltage setup is not adequate for advanced operation. Continuing will result in an unusable display. Signed-off-by: Alex Deucher Cc: Jean Delvare Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/evergreen.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 21c5aa070b9..fe052c618ae 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -3257,6 +3257,18 @@ int evergreen_init(struct radeon_device *rdev) rdev->accel_working = false; } } + + /* Don't start up if the MC ucode is missing on BTC parts. + * The default clocks and voltages before the MC ucode + * is loaded are not suffient for advanced operations. + */ + if (ASIC_IS_DCE5(rdev)) { + if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) { + DRM_ERROR("radeon: MC ucode required for NI+.\n"); + return -EINVAL; + } + } + return 0; } From 7204bf5ef7295b6041047d581153990164b58988 Mon Sep 17 00:00:00 2001 From: Hillf Danton Date: Wed, 28 Dec 2011 15:57:16 -0800 Subject: [PATCH 0562/4025] mm: hugetlb: fix non-atomic enqueue of huge page commit b0365c8d0cb6e79eb5f21418ae61ab511f31b575 upstream. If a huge page is enqueued under the protection of hugetlb_lock, then the operation is atomic and safe. Signed-off-by: Hillf Danton Reviewed-by: Michal Hocko Acked-by: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/hugetlb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 80936a118c3..f9c584943d8 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -901,7 +901,6 @@ static int gather_surplus_pages(struct hstate *h, int delta) h->resv_huge_pages += delta; ret = 0; - spin_unlock(&hugetlb_lock); /* Free the needed pages to the hugetlb pool */ list_for_each_entry_safe(page, tmp, &surplus_list, lru) { if ((--needed) < 0) @@ -915,6 +914,7 @@ static int gather_surplus_pages(struct hstate *h, int delta) VM_BUG_ON(page_count(page)); enqueue_huge_page(h, page); } + spin_unlock(&hugetlb_lock); /* Free unnecessary surplus pages to the buddy allocator */ free: From fca54d03a85e883b813255c63bbf11049d2eeb7a Mon Sep 17 00:00:00 2001 From: Nagalakshmi Nandigama Date: Wed, 4 Jan 2012 09:25:13 -0600 Subject: [PATCH 0563/4025] mpt2sas: fix non-x86 crash on shutdown Upstrem commit: 911ae9434f83e7355d343f6c2be3ef5b00ea7aed There's a bug in the MSIX backup and restore routines that cause a crash on non-x86 (direct access to PCI space not via read/write). These routines are unnecessary and were removed by the above commit, so also remove them from stable to fix the crash. Signed-off-by: Nagalakshmi Nandigama Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mpt2sas/mpt2sas_base.c | 59 +---------------------------- drivers/scsi/mpt2sas/mpt2sas_base.h | 4 -- 2 files changed, 2 insertions(+), 61 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 83035bd1c48..39e81cd567a 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -1081,41 +1081,6 @@ _base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev) return 0; } -/** - * _base_save_msix_table - backup msix vector table - * @ioc: per adapter object - * - * This address an errata where diag reset clears out the table - */ -static void -_base_save_msix_table(struct MPT2SAS_ADAPTER *ioc) -{ - int i; - - if (!ioc->msix_enable || ioc->msix_table_backup == NULL) - return; - - for (i = 0; i < ioc->msix_vector_count; i++) - ioc->msix_table_backup[i] = ioc->msix_table[i]; -} - -/** - * _base_restore_msix_table - this restores the msix vector table - * @ioc: per adapter object - * - */ -static void -_base_restore_msix_table(struct MPT2SAS_ADAPTER *ioc) -{ - int i; - - if (!ioc->msix_enable || ioc->msix_table_backup == NULL) - return; - - for (i = 0; i < ioc->msix_vector_count; i++) - ioc->msix_table[i] = ioc->msix_table_backup[i]; -} - /** * _base_check_enable_msix - checks MSIX capabable. * @ioc: per adapter object @@ -1128,7 +1093,7 @@ _base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc) { int base; u16 message_control; - u32 msix_table_offset; + base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); if (!base) { @@ -1141,14 +1106,8 @@ _base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc) pci_read_config_word(ioc->pdev, base + 2, &message_control); ioc->msix_vector_count = (message_control & 0x3FF) + 1; - /* get msix table */ - pci_read_config_dword(ioc->pdev, base + 4, &msix_table_offset); - msix_table_offset &= 0xFFFFFFF8; - ioc->msix_table = (u32 *)((void *)ioc->chip + msix_table_offset); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, " - "vector_count(%d), table_offset(0x%08x), table(%p)\n", ioc->name, - ioc->msix_vector_count, msix_table_offset, ioc->msix_table)); + "vector_count(%d)\n", ioc->name, ioc->msix_vector_count)); return 0; } @@ -1162,8 +1121,6 @@ _base_disable_msix(struct MPT2SAS_ADAPTER *ioc) { if (ioc->msix_enable) { pci_disable_msix(ioc->pdev); - kfree(ioc->msix_table_backup); - ioc->msix_table_backup = NULL; ioc->msix_enable = 0; } } @@ -1189,14 +1146,6 @@ _base_enable_msix(struct MPT2SAS_ADAPTER *ioc) if (_base_check_enable_msix(ioc) != 0) goto try_ioapic; - ioc->msix_table_backup = kcalloc(ioc->msix_vector_count, - sizeof(u32), GFP_KERNEL); - if (!ioc->msix_table_backup) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for " - "msix_table_backup failed!!!\n", ioc->name)); - goto try_ioapic; - } - memset(&entries, 0, sizeof(struct msix_entry)); r = pci_enable_msix(ioc->pdev, &entries, 1); if (r) { @@ -3513,9 +3462,6 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) u32 hcb_size; printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name); - - _base_save_msix_table(ioc); - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n", ioc->name)); @@ -3611,7 +3557,6 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) goto out; } - _base_restore_msix_table(ioc); printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name); return 0; diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 41a57a7a5b3..e1735f99f23 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -626,8 +626,6 @@ struct mpt2sas_port_facts { * @wait_for_port_enable_to_complete: * @msix_enable: flag indicating msix is enabled * @msix_vector_count: number msix vectors - * @msix_table: virt address to the msix table - * @msix_table_backup: backup msix table * @scsi_io_cb_idx: shost generated commands * @tm_cb_idx: task management commands * @scsih_cb_idx: scsih internal commands @@ -768,8 +766,6 @@ struct MPT2SAS_ADAPTER { u8 msix_enable; u16 msix_vector_count; - u32 *msix_table; - u32 *msix_table_backup; u32 ioc_reset_count; /* internal commands, callback index */ From 747b409502fe765784cda1135d806042beddaa89 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 22 Dec 2011 13:23:59 -0800 Subject: [PATCH 0564/4025] sparc64: Fix MSIQ HV call ordering in pci_sun4v_msiq_build_irq(). [ Upstream commit 7cc8583372a21d98a23b703ad96cab03180b5030 ] This silently was working for many years and stopped working on Niagara-T3 machines. We need to set the MSIQ to VALID before we can set it's state to IDLE. On Niagara-T3, setting the state to IDLE first was causing HV_EINVAL errors. The hypervisor documentation says, rather ambiguously, that the MSIQ must be "initialized" before one can set the state. I previously understood this to mean merely that a successful setconf() operation has been performed on the MSIQ, which we have done at this point. But it seems to also mean that it has been set VALID too. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/sparc/kernel/pci_sun4v.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/sparc/kernel/pci_sun4v.c b/arch/sparc/kernel/pci_sun4v.c index b01a06e9ae4..9e73c4a37ae 100644 --- a/arch/sparc/kernel/pci_sun4v.c +++ b/arch/sparc/kernel/pci_sun4v.c @@ -848,10 +848,10 @@ static int pci_sun4v_msiq_build_irq(struct pci_pbm_info *pbm, if (!irq) return -ENOMEM; - if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE)) - return -EINVAL; if (pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_VALID)) return -EINVAL; + if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE)) + return -EINVAL; return irq; } From fde939495571ffd22458e94745b0c2e6af33478d Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 14 Dec 2011 10:05:22 -0800 Subject: [PATCH 0565/4025] sparc32: Be less strict in matching %lo part of relocation. [ Upstream commit b1f44e13a525d2ffb7d5afe2273b7169d6f2222e ] The "(insn & 0x01800000) != 0x01800000" test matches 'restore' but that is a legitimate place to see the %lo() part of a 32-bit symbol relocation, particularly in tail calls. Signed-off-by: David S. Miller Tested-by: Sergei Trofimovich Signed-off-by: Greg Kroah-Hartman --- arch/sparc/mm/btfixup.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/sparc/mm/btfixup.c b/arch/sparc/mm/btfixup.c index 5175ac2f482..8a7f81743c1 100644 --- a/arch/sparc/mm/btfixup.c +++ b/arch/sparc/mm/btfixup.c @@ -302,8 +302,7 @@ void __init btfixup(void) case 'i': /* INT */ if ((insn & 0xc1c00000) == 0x01000000) /* %HI */ set_addr(addr, q[1], fmangled, (insn & 0xffc00000) | (p[1] >> 10)); - else if ((insn & 0x80002000) == 0x80002000 && - (insn & 0x01800000) != 0x01800000) /* %LO */ + else if ((insn & 0x80002000) == 0x80002000) /* %LO */ set_addr(addr, q[1], fmangled, (insn & 0xffffe000) | (p[1] & 0x3ff)); else { prom_printf(insn_i, p, addr, insn); From cff6d2096e9a57c2497dd5ee4aed3c97149bfc9e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 17 Nov 2011 22:44:58 -0800 Subject: [PATCH 0566/4025] sparc64: Patch sun4v code sequences properly on module load. [ Upstream commit 0b64120cceb86e93cb1bda0dc055f13016646907 ] Some of the sun4v code patching occurs in inline functions visible to, and usable by, modules. Therefore we have to patch them up during module load. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/sparc/kernel/entry.h | 7 ++++++ arch/sparc/kernel/module.c | 27 ++++++++++++++++++++ arch/sparc/kernel/setup_64.c | 48 ++++++++++++++++++++++-------------- 3 files changed, 63 insertions(+), 19 deletions(-) diff --git a/arch/sparc/kernel/entry.h b/arch/sparc/kernel/entry.h index e27f8ea8656..0c218e4c088 100644 --- a/arch/sparc/kernel/entry.h +++ b/arch/sparc/kernel/entry.h @@ -42,6 +42,9 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr, extern void fpload(unsigned long *fpregs, unsigned long *fsr); #else /* CONFIG_SPARC32 */ + +#include + struct popc_3insn_patch_entry { unsigned int addr; unsigned int insns[3]; @@ -57,6 +60,10 @@ extern struct popc_6insn_patch_entry __popc_6insn_patch, __popc_6insn_patch_end; extern void __init per_cpu_patch(void); +extern void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *, + struct sun4v_1insn_patch_entry *); +extern void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *, + struct sun4v_2insn_patch_entry *); extern void __init sun4v_patch(void); extern void __init boot_cpu_id_too_large(int cpu); extern unsigned int dcache_parity_tl1_occurred; diff --git a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c index 99ba5baa949..8172c18d844 100644 --- a/arch/sparc/kernel/module.c +++ b/arch/sparc/kernel/module.c @@ -17,6 +17,8 @@ #include #include +#include "entry.h" + #ifdef CONFIG_SPARC64 #include @@ -220,6 +222,29 @@ int apply_relocate_add(Elf_Shdr *sechdrs, } #ifdef CONFIG_SPARC64 +static void do_patch_sections(const Elf_Ehdr *hdr, + const Elf_Shdr *sechdrs) +{ + const Elf_Shdr *s, *sun4v_1insn = NULL, *sun4v_2insn = NULL; + char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + + for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { + if (!strcmp(".sun4v_1insn_patch", secstrings + s->sh_name)) + sun4v_1insn = s; + if (!strcmp(".sun4v_2insn_patch", secstrings + s->sh_name)) + sun4v_2insn = s; + } + + if (sun4v_1insn && tlb_type == hypervisor) { + void *p = (void *) sun4v_1insn->sh_addr; + sun4v_patch_1insn_range(p, p + sun4v_1insn->sh_size); + } + if (sun4v_2insn && tlb_type == hypervisor) { + void *p = (void *) sun4v_2insn->sh_addr; + sun4v_patch_2insn_range(p, p + sun4v_2insn->sh_size); + } +} + int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, struct module *me) @@ -227,6 +252,8 @@ int module_finalize(const Elf_Ehdr *hdr, /* make jump label nops */ jump_label_apply_nops(me); + do_patch_sections(hdr, sechdrs); + /* Cheetah's I-cache is fully coherent. */ if (tlb_type == spitfire) { unsigned long va; diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c index 3c5bb784214..4e7d3ff0ccb 100644 --- a/arch/sparc/kernel/setup_64.c +++ b/arch/sparc/kernel/setup_64.c @@ -234,40 +234,50 @@ void __init per_cpu_patch(void) } } -void __init sun4v_patch(void) +void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *start, + struct sun4v_1insn_patch_entry *end) { - extern void sun4v_hvapi_init(void); - struct sun4v_1insn_patch_entry *p1; - struct sun4v_2insn_patch_entry *p2; - - if (tlb_type != hypervisor) - return; + while (start < end) { + unsigned long addr = start->addr; - p1 = &__sun4v_1insn_patch; - while (p1 < &__sun4v_1insn_patch_end) { - unsigned long addr = p1->addr; - - *(unsigned int *) (addr + 0) = p1->insn; + *(unsigned int *) (addr + 0) = start->insn; wmb(); __asm__ __volatile__("flush %0" : : "r" (addr + 0)); - p1++; + start++; } +} - p2 = &__sun4v_2insn_patch; - while (p2 < &__sun4v_2insn_patch_end) { - unsigned long addr = p2->addr; +void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *start, + struct sun4v_2insn_patch_entry *end) +{ + while (start < end) { + unsigned long addr = start->addr; - *(unsigned int *) (addr + 0) = p2->insns[0]; + *(unsigned int *) (addr + 0) = start->insns[0]; wmb(); __asm__ __volatile__("flush %0" : : "r" (addr + 0)); - *(unsigned int *) (addr + 4) = p2->insns[1]; + *(unsigned int *) (addr + 4) = start->insns[1]; wmb(); __asm__ __volatile__("flush %0" : : "r" (addr + 4)); - p2++; + start++; } +} + +void __init sun4v_patch(void) +{ + extern void sun4v_hvapi_init(void); + + if (tlb_type != hypervisor) + return; + + sun4v_patch_1insn_range(&__sun4v_1insn_patch, + &__sun4v_1insn_patch_end); + + sun4v_patch_2insn_range(&__sun4v_2insn_patch, + &__sun4v_2insn_patch_end); sun4v_hvapi_init(); } From 2d2eb1d284257cbb7ebb29bd75a3cbbc9275e4f7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 17 Nov 2011 18:17:59 -0800 Subject: [PATCH 0567/4025] sparc: Kill custom io_remap_pfn_range(). [ Upstream commit 3e37fd3153ac95088a74f5e7c569f7567e9f993a ] To handle the large physical addresses, just make a simple wrapper around remap_pfn_range() like MIPS does. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/sparc/include/asm/pgtable_32.h | 20 +++- arch/sparc/include/asm/pgtable_64.h | 20 +++- arch/sparc/mm/Makefile | 1 - arch/sparc/mm/generic_32.c | 98 ----------------- arch/sparc/mm/generic_64.c | 164 ---------------------------- 5 files changed, 32 insertions(+), 271 deletions(-) delete mode 100644 arch/sparc/mm/generic_32.c delete mode 100644 arch/sparc/mm/generic_64.c diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h index 5b31a8e8982..a790cc65747 100644 --- a/arch/sparc/include/asm/pgtable_32.h +++ b/arch/sparc/include/asm/pgtable_32.h @@ -431,10 +431,6 @@ extern unsigned long *sparc_valid_addr_bitmap; #define kern_addr_valid(addr) \ (test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap)) -extern int io_remap_pfn_range(struct vm_area_struct *vma, - unsigned long from, unsigned long pfn, - unsigned long size, pgprot_t prot); - /* * For sparc32&64, the pfn in io_remap_pfn_range() carries in * its high 4 bits. These macros/functions put it there or get it from there. @@ -443,6 +439,22 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma, #define GET_IOSPACE(pfn) (pfn >> (BITS_PER_LONG - 4)) #define GET_PFN(pfn) (pfn & 0x0fffffffUL) +extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long, + unsigned long, pgprot_t); + +static inline int io_remap_pfn_range(struct vm_area_struct *vma, + unsigned long from, unsigned long pfn, + unsigned long size, pgprot_t prot) +{ + unsigned long long offset, space, phys_base; + + offset = ((unsigned long long) GET_PFN(pfn)) << PAGE_SHIFT; + space = GET_IOSPACE(pfn); + phys_base = offset | (space << 32ULL); + + return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot); +} + #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \ ({ \ diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h index 1e03c5a6b4f..98226280423 100644 --- a/arch/sparc/include/asm/pgtable_64.h +++ b/arch/sparc/include/asm/pgtable_64.h @@ -750,10 +750,6 @@ static inline bool kern_addr_valid(unsigned long addr) extern int page_in_phys_avail(unsigned long paddr); -extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, - unsigned long pfn, - unsigned long size, pgprot_t prot); - /* * For sparc32&64, the pfn in io_remap_pfn_range() carries in * its high 4 bits. These macros/functions put it there or get it from there. @@ -762,6 +758,22 @@ extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, #define GET_IOSPACE(pfn) (pfn >> (BITS_PER_LONG - 4)) #define GET_PFN(pfn) (pfn & 0x0fffffffffffffffUL) +extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long, + unsigned long, pgprot_t); + +static inline int io_remap_pfn_range(struct vm_area_struct *vma, + unsigned long from, unsigned long pfn, + unsigned long size, pgprot_t prot) +{ + unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT; + int space = GET_IOSPACE(pfn); + unsigned long phys_base; + + phys_base = offset | (((unsigned long) space) << 32UL); + + return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot); +} + #include /* We provide our own get_unmapped_area to cope with VA holes and diff --git a/arch/sparc/mm/Makefile b/arch/sparc/mm/Makefile index 79836a7dd00..3b6e248650d 100644 --- a/arch/sparc/mm/Makefile +++ b/arch/sparc/mm/Makefile @@ -8,7 +8,6 @@ obj-$(CONFIG_SPARC64) += ultra.o tlb.o tsb.o obj-y += fault_$(BITS).o obj-y += init_$(BITS).o obj-$(CONFIG_SPARC32) += loadmmu.o -obj-y += generic_$(BITS).o obj-$(CONFIG_SPARC32) += extable.o btfixup.o srmmu.o iommu.o io-unit.o obj-$(CONFIG_SPARC32) += hypersparc.o viking.o tsunami.o swift.o obj-$(CONFIG_SPARC_LEON)+= leon_mm.o diff --git a/arch/sparc/mm/generic_32.c b/arch/sparc/mm/generic_32.c deleted file mode 100644 index e6067b75f11..00000000000 --- a/arch/sparc/mm/generic_32.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * generic.c: Generic Sparc mm routines that are not dependent upon - * MMU type but are Sparc specific. - * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* Remap IO memory, the same way as remap_pfn_range(), but use - * the obio memory space. - * - * They use a pgprot that sets PAGE_IO and does not check the - * mem_map table as this is independent of normal memory. - */ -static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte, unsigned long address, unsigned long size, - unsigned long offset, pgprot_t prot, int space) -{ - unsigned long end; - - address &= ~PMD_MASK; - end = address + size; - if (end > PMD_SIZE) - end = PMD_SIZE; - do { - set_pte_at(mm, address, pte, mk_pte_io(offset, prot, space)); - address += PAGE_SIZE; - offset += PAGE_SIZE; - pte++; - } while (address < end); -} - -static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size, - unsigned long offset, pgprot_t prot, int space) -{ - unsigned long end; - - address &= ~PGDIR_MASK; - end = address + size; - if (end > PGDIR_SIZE) - end = PGDIR_SIZE; - offset -= address; - do { - pte_t *pte = pte_alloc_map(mm, NULL, pmd, address); - if (!pte) - return -ENOMEM; - io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space); - address = (address + PMD_SIZE) & PMD_MASK; - pmd++; - } while (address < end); - return 0; -} - -int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, - unsigned long pfn, unsigned long size, pgprot_t prot) -{ - int error = 0; - pgd_t * dir; - unsigned long beg = from; - unsigned long end = from + size; - struct mm_struct *mm = vma->vm_mm; - int space = GET_IOSPACE(pfn); - unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT; - - /* See comment in mm/memory.c remap_pfn_range */ - vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP; - vma->vm_pgoff = (offset >> PAGE_SHIFT) | - ((unsigned long)space << 28UL); - - offset -= from; - dir = pgd_offset(mm, from); - flush_cache_range(vma, beg, end); - - while (from < end) { - pmd_t *pmd = pmd_alloc(mm, dir, from); - error = -ENOMEM; - if (!pmd) - break; - error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, prot, space); - if (error) - break; - from = (from + PGDIR_SIZE) & PGDIR_MASK; - dir++; - } - - flush_tlb_range(vma, beg, end); - return error; -} -EXPORT_SYMBOL(io_remap_pfn_range); diff --git a/arch/sparc/mm/generic_64.c b/arch/sparc/mm/generic_64.c deleted file mode 100644 index 3cb00dfd4bd..00000000000 --- a/arch/sparc/mm/generic_64.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * generic.c: Generic Sparc mm routines that are not dependent upon - * MMU type but are Sparc specific. - * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -/* Remap IO memory, the same way as remap_pfn_range(), but use - * the obio memory space. - * - * They use a pgprot that sets PAGE_IO and does not check the - * mem_map table as this is independent of normal memory. - */ -static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte, - unsigned long address, - unsigned long size, - unsigned long offset, pgprot_t prot, - int space) -{ - unsigned long end; - - /* clear hack bit that was used as a write_combine side-effect flag */ - offset &= ~0x1UL; - address &= ~PMD_MASK; - end = address + size; - if (end > PMD_SIZE) - end = PMD_SIZE; - do { - pte_t entry; - unsigned long curend = address + PAGE_SIZE; - - entry = mk_pte_io(offset, prot, space, PAGE_SIZE); - if (!(address & 0xffff)) { - if (PAGE_SIZE < (4 * 1024 * 1024) && - !(address & 0x3fffff) && - !(offset & 0x3ffffe) && - end >= address + 0x400000) { - entry = mk_pte_io(offset, prot, space, - 4 * 1024 * 1024); - curend = address + 0x400000; - offset += 0x400000; - } else if (PAGE_SIZE < (512 * 1024) && - !(address & 0x7ffff) && - !(offset & 0x7fffe) && - end >= address + 0x80000) { - entry = mk_pte_io(offset, prot, space, - 512 * 1024 * 1024); - curend = address + 0x80000; - offset += 0x80000; - } else if (PAGE_SIZE < (64 * 1024) && - !(offset & 0xfffe) && - end >= address + 0x10000) { - entry = mk_pte_io(offset, prot, space, - 64 * 1024); - curend = address + 0x10000; - offset += 0x10000; - } else - offset += PAGE_SIZE; - } else - offset += PAGE_SIZE; - - if (pte_write(entry)) - entry = pte_mkdirty(entry); - do { - BUG_ON(!pte_none(*pte)); - set_pte_at(mm, address, pte, entry); - address += PAGE_SIZE; - pte_val(entry) += PAGE_SIZE; - pte++; - } while (address < curend); - } while (address < end); -} - -static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size, - unsigned long offset, pgprot_t prot, int space) -{ - unsigned long end; - - address &= ~PGDIR_MASK; - end = address + size; - if (end > PGDIR_SIZE) - end = PGDIR_SIZE; - offset -= address; - do { - pte_t *pte = pte_alloc_map(mm, NULL, pmd, address); - if (!pte) - return -ENOMEM; - io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space); - pte_unmap(pte); - address = (address + PMD_SIZE) & PMD_MASK; - pmd++; - } while (address < end); - return 0; -} - -static inline int io_remap_pud_range(struct mm_struct *mm, pud_t * pud, unsigned long address, unsigned long size, - unsigned long offset, pgprot_t prot, int space) -{ - unsigned long end; - - address &= ~PUD_MASK; - end = address + size; - if (end > PUD_SIZE) - end = PUD_SIZE; - offset -= address; - do { - pmd_t *pmd = pmd_alloc(mm, pud, address); - if (!pud) - return -ENOMEM; - io_remap_pmd_range(mm, pmd, address, end - address, address + offset, prot, space); - address = (address + PUD_SIZE) & PUD_MASK; - pud++; - } while (address < end); - return 0; -} - -int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from, - unsigned long pfn, unsigned long size, pgprot_t prot) -{ - int error = 0; - pgd_t * dir; - unsigned long beg = from; - unsigned long end = from + size; - struct mm_struct *mm = vma->vm_mm; - int space = GET_IOSPACE(pfn); - unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT; - unsigned long phys_base; - - phys_base = offset | (((unsigned long) space) << 32UL); - - /* See comment in mm/memory.c remap_pfn_range */ - vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP; - vma->vm_pgoff = phys_base >> PAGE_SHIFT; - - offset -= from; - dir = pgd_offset(mm, from); - flush_cache_range(vma, beg, end); - - while (from < end) { - pud_t *pud = pud_alloc(mm, dir, from); - error = -ENOMEM; - if (!pud) - break; - error = io_remap_pud_range(mm, pud, from, end - from, offset + from, prot, space); - if (error) - break; - from = (from + PGDIR_SIZE) & PGDIR_MASK; - dir++; - } - - flush_tlb_range(vma, beg, end); - return error; -} -EXPORT_SYMBOL(io_remap_pfn_range); From 9dd04b12d0588de337ff615f6991862956dd40de Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 19 Oct 2011 15:15:58 -0700 Subject: [PATCH 0568/4025] sparc32: Remove non-kernel code from memcpy implementation. [ Upstream commit 045b7de9ca0cf09f1adc3efa467f668b89238390 ] Signed-off-by: David S. Miller Tested-by: Kjetil Oftedal Signed-off-by: Greg Kroah-Hartman --- arch/sparc/lib/memcpy.S | 607 +--------------------------------------- 1 file changed, 2 insertions(+), 605 deletions(-) diff --git a/arch/sparc/lib/memcpy.S b/arch/sparc/lib/memcpy.S index 34fe6575173..6a8ef5d8daf 100644 --- a/arch/sparc/lib/memcpy.S +++ b/arch/sparc/lib/memcpy.S @@ -7,17 +7,12 @@ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ -#ifdef __KERNEL__ - -#define FUNC(x) \ +#define FUNC(x) \ .globl x; \ .type x,@function; \ - .align 4; \ + .align 4; \ x: -#undef FASTER_REVERSE -#undef FASTER_NONALIGNED -#define FASTER_ALIGNED /* In kernel these functions don't return a value. * One should use macros in asm/string.h for that purpose. @@ -26,21 +21,6 @@ x: #define SETUP_RETL #define RETL_INSN clr %o0 -#else - -/* libc */ - -#include "DEFS.h" - -#define FASTER_REVERSE -#define FASTER_NONALIGNED -#define FASTER_ALIGNED - -#define SETUP_RETL mov %o0, %g6 -#define RETL_INSN mov %g6, %o0 - -#endif - /* Both these macros have to start with exactly the same insn */ #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ ldd [%src + (offset) + 0x00], %t0; \ @@ -164,30 +144,6 @@ x: .text .align 4 -#ifdef FASTER_REVERSE - -70: /* rdword_align */ - - andcc %o1, 1, %g0 - be 4f - andcc %o1, 2, %g0 - - ldub [%o1 - 1], %g2 - sub %o1, 1, %o1 - stb %g2, [%o0 - 1] - sub %o2, 1, %o2 - be 3f - sub %o0, 1, %o0 -4: - lduh [%o1 - 2], %g2 - sub %o1, 2, %o1 - sth %g2, [%o0 - 2] - sub %o2, 2, %o2 - b 3f - sub %o0, 2, %o0 - -#endif /* FASTER_REVERSE */ - 0: retl nop ! Only bcopy returns here and it retuns void... @@ -207,8 +163,6 @@ FUNC(memmove) bleu 0f andcc %o4, 3, %o5 -#ifndef FASTER_REVERSE - add %o1, %o2, %o1 add %o0, %o2, %o0 sub %o1, 1, %o1 @@ -226,294 +180,6 @@ FUNC(memmove) retl RETL_INSN -#else /* FASTER_REVERSE */ - - add %o1, %o2, %o1 - add %o0, %o2, %o0 - bne 77f - cmp %o2, 15 - bleu 91f - andcc %o1, 3, %g0 - bne 70b -3: - andcc %o1, 4, %g0 - - be 2f - mov %o2, %g1 - - ld [%o1 - 4], %o4 - sub %g1, 4, %g1 - st %o4, [%o0 - 4] - sub %o1, 4, %o1 - sub %o0, 4, %o0 -2: - andcc %g1, 0xffffff80, %g7 - be 3f - andcc %o0, 4, %g0 - - be 74f + 4 -5: - RMOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5) - RMOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5) - RMOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5) - RMOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5) - subcc %g7, 128, %g7 - sub %o1, 128, %o1 - bne 5b - sub %o0, 128, %o0 -3: - andcc %g1, 0x70, %g7 - be 72f - andcc %g1, 8, %g0 - - sethi %hi(72f), %o5 - srl %g7, 1, %o4 - add %g7, %o4, %o4 - sub %o1, %g7, %o1 - sub %o5, %o4, %o5 - jmpl %o5 + %lo(72f), %g0 - sub %o0, %g7, %o0 - -71: /* rmemcpy_table */ - RMOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5) - RMOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5) - RMOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5) - RMOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5) - RMOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5) - RMOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5) - RMOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5) - -72: /* rmemcpy_table_end */ - - be 73f - andcc %g1, 4, %g0 - - ldd [%o1 - 0x08], %g2 - sub %o0, 8, %o0 - sub %o1, 8, %o1 - st %g2, [%o0] - st %g3, [%o0 + 0x04] - -73: /* rmemcpy_last7 */ - - be 1f - andcc %g1, 2, %g0 - - ld [%o1 - 4], %g2 - sub %o1, 4, %o1 - st %g2, [%o0 - 4] - sub %o0, 4, %o0 -1: - be 1f - andcc %g1, 1, %g0 - - lduh [%o1 - 2], %g2 - sub %o1, 2, %o1 - sth %g2, [%o0 - 2] - sub %o0, 2, %o0 -1: - be 1f - nop - - ldub [%o1 - 1], %g2 - stb %g2, [%o0 - 1] -1: - retl - RETL_INSN - -74: /* rldd_std */ - RMOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5) - RMOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5) - RMOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5) - RMOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5) - subcc %g7, 128, %g7 - sub %o1, 128, %o1 - bne 74b - sub %o0, 128, %o0 - - andcc %g1, 0x70, %g7 - be 72b - andcc %g1, 8, %g0 - - sethi %hi(72b), %o5 - srl %g7, 1, %o4 - add %g7, %o4, %o4 - sub %o1, %g7, %o1 - sub %o5, %o4, %o5 - jmpl %o5 + %lo(72b), %g0 - sub %o0, %g7, %o0 - -75: /* rshort_end */ - - and %o2, 0xe, %o3 -2: - sethi %hi(76f), %o5 - sll %o3, 3, %o4 - sub %o0, %o3, %o0 - sub %o5, %o4, %o5 - sub %o1, %o3, %o1 - jmpl %o5 + %lo(76f), %g0 - andcc %o2, 1, %g0 - - RMOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3) - RMOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3) - RMOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3) - RMOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3) - RMOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3) - RMOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3) - RMOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3) - -76: /* rshort_table_end */ - - be 1f - nop - ldub [%o1 - 1], %g2 - stb %g2, [%o0 - 1] -1: - retl - RETL_INSN - -91: /* rshort_aligned_end */ - - bne 75b - andcc %o2, 8, %g0 - - be 1f - andcc %o2, 4, %g0 - - ld [%o1 - 0x08], %g2 - ld [%o1 - 0x04], %g3 - sub %o1, 8, %o1 - st %g2, [%o0 - 0x08] - st %g3, [%o0 - 0x04] - sub %o0, 8, %o0 -1: - b 73b - mov %o2, %g1 - -77: /* rnon_aligned */ - cmp %o2, 15 - bleu 75b - andcc %o0, 3, %g0 - be 64f - andcc %o0, 1, %g0 - be 63f - andcc %o0, 2, %g0 - ldub [%o1 - 1], %g5 - sub %o1, 1, %o1 - stb %g5, [%o0 - 1] - sub %o0, 1, %o0 - be 64f - sub %o2, 1, %o2 -63: - ldub [%o1 - 1], %g5 - sub %o1, 2, %o1 - stb %g5, [%o0 - 1] - sub %o0, 2, %o0 - ldub [%o1], %g5 - sub %o2, 2, %o2 - stb %g5, [%o0] -64: - and %o1, 3, %g2 - and %o1, -4, %o1 - and %o2, 0xc, %g3 - add %o1, 4, %o1 - cmp %g3, 4 - sll %g2, 3, %g4 - mov 32, %g2 - be 4f - sub %g2, %g4, %g7 - - blu 3f - cmp %g3, 8 - - be 2f - srl %o2, 2, %g3 - - ld [%o1 - 4], %o3 - add %o0, -8, %o0 - ld [%o1 - 8], %o4 - add %o1, -16, %o1 - b 7f - add %g3, 1, %g3 -2: - ld [%o1 - 4], %o4 - add %o0, -4, %o0 - ld [%o1 - 8], %g1 - add %o1, -12, %o1 - b 8f - add %g3, 2, %g3 -3: - ld [%o1 - 4], %o5 - add %o0, -12, %o0 - ld [%o1 - 8], %o3 - add %o1, -20, %o1 - b 6f - srl %o2, 2, %g3 -4: - ld [%o1 - 4], %g1 - srl %o2, 2, %g3 - ld [%o1 - 8], %o5 - add %o1, -24, %o1 - add %o0, -16, %o0 - add %g3, -1, %g3 - - ld [%o1 + 12], %o3 -5: - sll %o5, %g4, %g2 - srl %g1, %g7, %g5 - or %g2, %g5, %g2 - st %g2, [%o0 + 12] -6: - ld [%o1 + 8], %o4 - sll %o3, %g4, %g2 - srl %o5, %g7, %g5 - or %g2, %g5, %g2 - st %g2, [%o0 + 8] -7: - ld [%o1 + 4], %g1 - sll %o4, %g4, %g2 - srl %o3, %g7, %g5 - or %g2, %g5, %g2 - st %g2, [%o0 + 4] -8: - ld [%o1], %o5 - sll %g1, %g4, %g2 - srl %o4, %g7, %g5 - addcc %g3, -4, %g3 - or %g2, %g5, %g2 - add %o1, -16, %o1 - st %g2, [%o0] - add %o0, -16, %o0 - bne,a 5b - ld [%o1 + 12], %o3 - sll %o5, %g4, %g2 - srl %g1, %g7, %g5 - srl %g4, 3, %g3 - or %g2, %g5, %g2 - add %o1, %g3, %o1 - andcc %o2, 2, %g0 - st %g2, [%o0 + 12] - be 1f - andcc %o2, 1, %g0 - - ldub [%o1 + 15], %g5 - add %o1, -2, %o1 - stb %g5, [%o0 + 11] - add %o0, -2, %o0 - ldub [%o1 + 16], %g5 - stb %g5, [%o0 + 12] -1: - be 1f - nop - ldub [%o1 + 15], %g5 - stb %g5, [%o0 + 11] -1: - retl - RETL_INSN - -#endif /* FASTER_REVERSE */ - /* NOTE: This code is executed just for the cases, where %src (=%o1) & 3 is != 0. We need to align it to 4. So, for (%src & 3) @@ -653,22 +319,6 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ bne 82b add %o0, 128, %o0 -#ifndef FASTER_ALIGNED - - andcc %g1, 0x70, %g7 - be 80b - andcc %g1, 8, %g0 - - sethi %hi(80b), %o5 - srl %g7, 1, %o4 - add %g7, %o4, %o4 - add %o1, %g7, %o1 - sub %o5, %o4, %o5 - jmpl %o5 + %lo(80b), %g0 - add %o0, %g7, %o0 - -#else /* FASTER_ALIGNED */ - andcc %g1, 0x70, %g7 be 84f andcc %g1, 8, %g0 @@ -723,19 +373,9 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ retl RETL_INSN -#endif /* FASTER_ALIGNED */ - 86: /* non_aligned */ cmp %o2, 6 bleu 88f - -#ifdef FASTER_NONALIGNED - - cmp %o2, 256 - bcc 87f - -#endif /* FASTER_NONALIGNED */ - andcc %o0, 3, %g0 be 61f andcc %o0, 1, %g0 @@ -855,249 +495,6 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ retl RETL_INSN -#ifdef FASTER_NONALIGNED - -87: /* faster_nonaligned */ - - andcc %o1, 3, %g0 - be 3f - andcc %o1, 1, %g0 - - be 4f - andcc %o1, 2, %g0 - - ldub [%o1], %g2 - add %o1, 1, %o1 - stb %g2, [%o0] - sub %o2, 1, %o2 - bne 3f - add %o0, 1, %o0 -4: - lduh [%o1], %g2 - add %o1, 2, %o1 - srl %g2, 8, %g3 - sub %o2, 2, %o2 - stb %g3, [%o0] - add %o0, 2, %o0 - stb %g2, [%o0 - 1] -3: - andcc %o1, 4, %g0 - - bne 2f - cmp %o5, 1 - - ld [%o1], %o4 - srl %o4, 24, %g2 - stb %g2, [%o0] - srl %o4, 16, %g3 - stb %g3, [%o0 + 1] - srl %o4, 8, %g2 - stb %g2, [%o0 + 2] - sub %o2, 4, %o2 - stb %o4, [%o0 + 3] - add %o1, 4, %o1 - add %o0, 4, %o0 -2: - be 33f - cmp %o5, 2 - be 32f - sub %o2, 4, %o2 -31: - ld [%o1], %g2 - add %o1, 4, %o1 - srl %g2, 24, %g3 - and %o0, 7, %g5 - stb %g3, [%o0] - cmp %g5, 7 - sll %g2, 8, %g1 - add %o0, 4, %o0 - be 41f - and %o2, 0xffffffc0, %o3 - ld [%o0 - 7], %o4 -4: - SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) - SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) - SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) - SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) - subcc %o3, 64, %o3 - add %o1, 64, %o1 - bne 4b - add %o0, 64, %o0 - - andcc %o2, 0x30, %o3 - be,a 1f - srl %g1, 16, %g2 -4: - SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) - subcc %o3, 16, %o3 - add %o1, 16, %o1 - bne 4b - add %o0, 16, %o0 - - srl %g1, 16, %g2 -1: - st %o4, [%o0 - 7] - sth %g2, [%o0 - 3] - srl %g1, 8, %g4 - b 88f - stb %g4, [%o0 - 1] -32: - ld [%o1], %g2 - add %o1, 4, %o1 - srl %g2, 16, %g3 - and %o0, 7, %g5 - sth %g3, [%o0] - cmp %g5, 6 - sll %g2, 16, %g1 - add %o0, 4, %o0 - be 42f - and %o2, 0xffffffc0, %o3 - ld [%o0 - 6], %o4 -4: - SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) - SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) - SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) - SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) - subcc %o3, 64, %o3 - add %o1, 64, %o1 - bne 4b - add %o0, 64, %o0 - - andcc %o2, 0x30, %o3 - be,a 1f - srl %g1, 16, %g2 -4: - SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) - subcc %o3, 16, %o3 - add %o1, 16, %o1 - bne 4b - add %o0, 16, %o0 - - srl %g1, 16, %g2 -1: - st %o4, [%o0 - 6] - b 88f - sth %g2, [%o0 - 2] -33: - ld [%o1], %g2 - sub %o2, 4, %o2 - srl %g2, 24, %g3 - and %o0, 7, %g5 - stb %g3, [%o0] - cmp %g5, 5 - srl %g2, 8, %g4 - sll %g2, 24, %g1 - sth %g4, [%o0 + 1] - add %o1, 4, %o1 - be 43f - and %o2, 0xffffffc0, %o3 - - ld [%o0 - 1], %o4 - add %o0, 4, %o0 -4: - SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1) - SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1) - SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1) - SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1) - subcc %o3, 64, %o3 - add %o1, 64, %o1 - bne 4b - add %o0, 64, %o0 - - andcc %o2, 0x30, %o3 - be,a 1f - srl %g1, 24, %g2 -4: - SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1) - subcc %o3, 16, %o3 - add %o1, 16, %o1 - bne 4b - add %o0, 16, %o0 - - srl %g1, 24, %g2 -1: - st %o4, [%o0 - 5] - b 88f - stb %g2, [%o0 - 1] -41: - SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) - SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) - SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) - SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) - subcc %o3, 64, %o3 - add %o1, 64, %o1 - bne 41b - add %o0, 64, %o0 - - andcc %o2, 0x30, %o3 - be,a 1f - srl %g1, 16, %g2 -4: - SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3) - subcc %o3, 16, %o3 - add %o1, 16, %o1 - bne 4b - add %o0, 16, %o0 - - srl %g1, 16, %g2 -1: - sth %g2, [%o0 - 3] - srl %g1, 8, %g4 - b 88f - stb %g4, [%o0 - 1] -43: - SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3) - SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3) - SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3) - SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3) - subcc %o3, 64, %o3 - add %o1, 64, %o1 - bne 43b - add %o0, 64, %o0 - - andcc %o2, 0x30, %o3 - be,a 1f - srl %g1, 24, %g2 -4: - SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3) - subcc %o3, 16, %o3 - add %o1, 16, %o1 - bne 4b - add %o0, 16, %o0 - - srl %g1, 24, %g2 -1: - stb %g2, [%o0 + 3] - b 88f - add %o0, 4, %o0 -42: - SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) - SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) - SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) - SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) - subcc %o3, 64, %o3 - add %o1, 64, %o1 - bne 42b - add %o0, 64, %o0 - - andcc %o2, 0x30, %o3 - be,a 1f - srl %g1, 16, %g2 -4: - SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2) - subcc %o3, 16, %o3 - add %o1, 16, %o1 - bne 4b - add %o0, 16, %o0 - - srl %g1, 16, %g2 -1: - sth %g2, [%o0 - 2] - - /* Fall through */ - -#endif /* FASTER_NONALIGNED */ - 88: /* short_end */ and %o2, 0xe, %o3 From 2588f7f219ab1e93be648ecf8bcb1599b1ecba09 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 19 Oct 2011 15:30:14 -0700 Subject: [PATCH 0569/4025] sparc32: Remove uses of %g7 in memcpy implementation. [ Upstream commit 21f74d361dfd6a7d0e47574e315f780d8172084a ] This is setting things up so that we can correct the return value, so that it properly returns the original destination buffer pointer. Signed-off-by: David S. Miller Tested-by: Kjetil Oftedal Signed-off-by: Greg Kroah-Hartman --- arch/sparc/lib/memcpy.S | 179 +++++++++++++++++++++------------------- 1 file changed, 92 insertions(+), 87 deletions(-) diff --git a/arch/sparc/lib/memcpy.S b/arch/sparc/lib/memcpy.S index 6a8ef5d8daf..90a598846ba 100644 --- a/arch/sparc/lib/memcpy.S +++ b/arch/sparc/lib/memcpy.S @@ -235,7 +235,7 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ add %o1, 4, %o1 add %o0, 4, %o0 2: - andcc %g1, 0xffffff80, %g7 + andcc %g1, 0xffffff80, %g0 be 3f andcc %o0, 4, %g0 @@ -245,22 +245,23 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5) MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5) MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5) - subcc %g7, 128, %g7 + sub %g1, 128, %g1 add %o1, 128, %o1 - bne 5b + cmp %g1, 128 + bge 5b add %o0, 128, %o0 3: - andcc %g1, 0x70, %g7 + andcc %g1, 0x70, %g4 be 80f andcc %g1, 8, %g0 sethi %hi(80f), %o5 - srl %g7, 1, %o4 - add %g7, %o4, %o4 - add %o1, %g7, %o1 + srl %g4, 1, %o4 + add %g4, %o4, %o4 + add %o1, %g4, %o1 sub %o5, %o4, %o5 jmpl %o5 + %lo(80f), %g0 - add %o0, %g7, %o0 + add %o0, %g4, %o0 79: /* memcpy_table */ @@ -314,20 +315,21 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5) MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5) MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5) - subcc %g7, 128, %g7 + subcc %g1, 128, %g1 add %o1, 128, %o1 - bne 82b + cmp %g1, 128 + bge 82b add %o0, 128, %o0 - andcc %g1, 0x70, %g7 + andcc %g1, 0x70, %g4 be 84f andcc %g1, 8, %g0 sethi %hi(84f), %o5 - add %o1, %g7, %o1 - sub %o5, %g7, %o5 + add %o1, %g4, %o1 + sub %o5, %g4, %o5 jmpl %o5 + %lo(84f), %g0 - add %o0, %g7, %o0 + add %o0, %g4, %o0 83: /* amemcpy_table */ @@ -376,124 +378,127 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ 86: /* non_aligned */ cmp %o2, 6 bleu 88f - andcc %o0, 3, %g0 + nop + + save %sp, -96, %sp + andcc %i0, 3, %g0 be 61f - andcc %o0, 1, %g0 + andcc %i0, 1, %g0 be 60f - andcc %o0, 2, %g0 + andcc %i0, 2, %g0 - ldub [%o1], %g5 - add %o1, 1, %o1 - stb %g5, [%o0] - sub %o2, 1, %o2 + ldub [%i1], %g5 + add %i1, 1, %i1 + stb %g5, [%i0] + sub %i2, 1, %i2 bne 61f - add %o0, 1, %o0 + add %i0, 1, %i0 60: - ldub [%o1], %g3 - add %o1, 2, %o1 - stb %g3, [%o0] - sub %o2, 2, %o2 - ldub [%o1 - 1], %g3 - add %o0, 2, %o0 - stb %g3, [%o0 - 1] + ldub [%i1], %g3 + add %i1, 2, %i1 + stb %g3, [%i0] + sub %i2, 2, %i2 + ldub [%i1 - 1], %g3 + add %i0, 2, %i0 + stb %g3, [%i0 - 1] 61: - and %o1, 3, %g2 - and %o2, 0xc, %g3 - and %o1, -4, %o1 + and %i1, 3, %g2 + and %i2, 0xc, %g3 + and %i1, -4, %i1 cmp %g3, 4 sll %g2, 3, %g4 mov 32, %g2 be 4f - sub %g2, %g4, %g7 + sub %g2, %g4, %l0 blu 3f cmp %g3, 0x8 be 2f - srl %o2, 2, %g3 + srl %i2, 2, %g3 - ld [%o1], %o3 - add %o0, -8, %o0 - ld [%o1 + 4], %o4 + ld [%i1], %i3 + add %i0, -8, %i0 + ld [%i1 + 4], %i4 b 8f add %g3, 1, %g3 2: - ld [%o1], %o4 - add %o0, -12, %o0 - ld [%o1 + 4], %o5 + ld [%i1], %i4 + add %i0, -12, %i0 + ld [%i1 + 4], %i5 add %g3, 2, %g3 b 9f - add %o1, -4, %o1 + add %i1, -4, %i1 3: - ld [%o1], %g1 - add %o0, -4, %o0 - ld [%o1 + 4], %o3 - srl %o2, 2, %g3 + ld [%i1], %g1 + add %i0, -4, %i0 + ld [%i1 + 4], %i3 + srl %i2, 2, %g3 b 7f - add %o1, 4, %o1 + add %i1, 4, %i1 4: - ld [%o1], %o5 - cmp %o2, 7 - ld [%o1 + 4], %g1 - srl %o2, 2, %g3 + ld [%i1], %i5 + cmp %i2, 7 + ld [%i1 + 4], %g1 + srl %i2, 2, %g3 bleu 10f - add %o1, 8, %o1 + add %i1, 8, %i1 - ld [%o1], %o3 + ld [%i1], %i3 add %g3, -1, %g3 5: - sll %o5, %g4, %g2 - srl %g1, %g7, %g5 + sll %i5, %g4, %g2 + srl %g1, %l0, %g5 or %g2, %g5, %g2 - st %g2, [%o0] + st %g2, [%i0] 7: - ld [%o1 + 4], %o4 + ld [%i1 + 4], %i4 sll %g1, %g4, %g2 - srl %o3, %g7, %g5 + srl %i3, %l0, %g5 or %g2, %g5, %g2 - st %g2, [%o0 + 4] + st %g2, [%i0 + 4] 8: - ld [%o1 + 8], %o5 - sll %o3, %g4, %g2 - srl %o4, %g7, %g5 + ld [%i1 + 8], %i5 + sll %i3, %g4, %g2 + srl %i4, %l0, %g5 or %g2, %g5, %g2 - st %g2, [%o0 + 8] + st %g2, [%i0 + 8] 9: - ld [%o1 + 12], %g1 - sll %o4, %g4, %g2 - srl %o5, %g7, %g5 + ld [%i1 + 12], %g1 + sll %i4, %g4, %g2 + srl %i5, %l0, %g5 addcc %g3, -4, %g3 or %g2, %g5, %g2 - add %o1, 16, %o1 - st %g2, [%o0 + 12] - add %o0, 16, %o0 + add %i1, 16, %i1 + st %g2, [%i0 + 12] + add %i0, 16, %i0 bne,a 5b - ld [%o1], %o3 + ld [%i1], %i3 10: - sll %o5, %g4, %g2 - srl %g1, %g7, %g5 - srl %g7, 3, %g3 + sll %i5, %g4, %g2 + srl %g1, %l0, %g5 + srl %l0, 3, %g3 or %g2, %g5, %g2 - sub %o1, %g3, %o1 - andcc %o2, 2, %g0 - st %g2, [%o0] + sub %i1, %g3, %i1 + andcc %i2, 2, %g0 + st %g2, [%i0] be 1f - andcc %o2, 1, %g0 - - ldub [%o1], %g2 - add %o1, 2, %o1 - stb %g2, [%o0 + 4] - add %o0, 2, %o0 - ldub [%o1 - 1], %g2 - stb %g2, [%o0 + 3] + andcc %i2, 1, %g0 + + ldub [%i1], %g2 + add %i1, 2, %i1 + stb %g2, [%i0 + 4] + add %i0, 2, %i0 + ldub [%i1 - 1], %g2 + stb %g2, [%i0 + 3] 1: be 1f nop - ldub [%o1], %g2 - stb %g2, [%o0 + 4] + ldub [%i1], %g2 + stb %g2, [%i0 + 4] 1: - retl - RETL_INSN + ret + restore %g0, %g0, %o0 88: /* short_end */ From 23a652b45554faf08ac5a7a86c176a95cce8ca83 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 19 Oct 2011 15:31:55 -0700 Subject: [PATCH 0570/4025] sparc32: Correct the return value of memcpy. [ Upstream commit a52312b88c8103e965979a79a07f6b34af82ca4b ] Properly return the original destination buffer pointer. Signed-off-by: David S. Miller Tested-by: Kjetil Oftedal Signed-off-by: Greg Kroah-Hartman --- arch/sparc/lib/memcpy.S | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/arch/sparc/lib/memcpy.S b/arch/sparc/lib/memcpy.S index 90a598846ba..4d8c497517b 100644 --- a/arch/sparc/lib/memcpy.S +++ b/arch/sparc/lib/memcpy.S @@ -13,14 +13,6 @@ .align 4; \ x: - -/* In kernel these functions don't return a value. - * One should use macros in asm/string.h for that purpose. - * We return 0, so that bugs are more apparent. - */ -#define SETUP_RETL -#define RETL_INSN clr %o0 - /* Both these macros have to start with exactly the same insn */ #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ ldd [%src + (offset) + 0x00], %t0; \ @@ -154,7 +146,7 @@ FUNC(__memmove) #endif FUNC(memmove) cmp %o0, %o1 - SETUP_RETL + mov %o0, %g7 bleu 9f sub %o0, %o1, %o4 @@ -178,7 +170,7 @@ FUNC(memmove) sub %o0, 1, %o0 retl - RETL_INSN + mov %g7, %o0 /* NOTE: This code is executed just for the cases, where %src (=%o1) & 3 is != 0. @@ -212,7 +204,7 @@ FUNC(memmove) FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ sub %o0, %o1, %o4 - SETUP_RETL + mov %o0, %g7 9: andcc %o4, 3, %o5 0: @@ -308,7 +300,7 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ stb %g2, [%o0] 1: retl - RETL_INSN + mov %g7, %o0 82: /* ldd_std */ MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5) @@ -373,7 +365,7 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ stb %g2, [%o0] 1: retl - RETL_INSN + mov %g7, %o0 86: /* non_aligned */ cmp %o2, 6 @@ -498,7 +490,7 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ stb %g2, [%i0 + 4] 1: ret - restore %g0, %g0, %o0 + restore %g7, %g0, %o0 88: /* short_end */ @@ -529,7 +521,7 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len */ stb %g2, [%o0] 1: retl - RETL_INSN + mov %g7, %o0 90: /* short_aligned_end */ bne 88b From d4afed4d20e91a12de7cd1c64bb3451ee2236d19 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 31 Oct 2011 01:05:49 -0700 Subject: [PATCH 0571/4025] sparc64: Fix masking and shifting in VIS fpcmp emulation. [ Upstream commit 2e8ecdc008a16b9a6c4b9628bb64d0d1c05f9f92 ] Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/sparc/kernel/visemul.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/arch/sparc/kernel/visemul.c b/arch/sparc/kernel/visemul.c index 36357717d69..9384a0cbeba 100644 --- a/arch/sparc/kernel/visemul.c +++ b/arch/sparc/kernel/visemul.c @@ -713,17 +713,17 @@ static void pcmp(struct pt_regs *regs, unsigned int insn, unsigned int opf) s16 b = (rs2 >> (i * 16)) & 0xffff; if (a > b) - rd_val |= 1 << i; + rd_val |= 8 >> i; } break; case FCMPGT32_OPF: for (i = 0; i < 2; i++) { - s32 a = (rs1 >> (i * 32)) & 0xffff; - s32 b = (rs2 >> (i * 32)) & 0xffff; + s32 a = (rs1 >> (i * 32)) & 0xffffffff; + s32 b = (rs2 >> (i * 32)) & 0xffffffff; if (a > b) - rd_val |= 1 << i; + rd_val |= 2 >> i; } break; @@ -733,17 +733,17 @@ static void pcmp(struct pt_regs *regs, unsigned int insn, unsigned int opf) s16 b = (rs2 >> (i * 16)) & 0xffff; if (a <= b) - rd_val |= 1 << i; + rd_val |= 8 >> i; } break; case FCMPLE32_OPF: for (i = 0; i < 2; i++) { - s32 a = (rs1 >> (i * 32)) & 0xffff; - s32 b = (rs2 >> (i * 32)) & 0xffff; + s32 a = (rs1 >> (i * 32)) & 0xffffffff; + s32 b = (rs2 >> (i * 32)) & 0xffffffff; if (a <= b) - rd_val |= 1 << i; + rd_val |= 2 >> i; } break; @@ -753,17 +753,17 @@ static void pcmp(struct pt_regs *regs, unsigned int insn, unsigned int opf) s16 b = (rs2 >> (i * 16)) & 0xffff; if (a != b) - rd_val |= 1 << i; + rd_val |= 8 >> i; } break; case FCMPNE32_OPF: for (i = 0; i < 2; i++) { - s32 a = (rs1 >> (i * 32)) & 0xffff; - s32 b = (rs2 >> (i * 32)) & 0xffff; + s32 a = (rs1 >> (i * 32)) & 0xffffffff; + s32 b = (rs2 >> (i * 32)) & 0xffffffff; if (a != b) - rd_val |= 1 << i; + rd_val |= 2 >> i; } break; @@ -773,17 +773,17 @@ static void pcmp(struct pt_regs *regs, unsigned int insn, unsigned int opf) s16 b = (rs2 >> (i * 16)) & 0xffff; if (a == b) - rd_val |= 1 << i; + rd_val |= 8 >> i; } break; case FCMPEQ32_OPF: for (i = 0; i < 2; i++) { - s32 a = (rs1 >> (i * 32)) & 0xffff; - s32 b = (rs2 >> (i * 32)) & 0xffff; + s32 a = (rs1 >> (i * 32)) & 0xffffffff; + s32 b = (rs2 >> (i * 32)) & 0xffffffff; if (a == b) - rd_val |= 1 << i; + rd_val |= 2 >> i; } break; } From 2a89fc8b91abf1ba56daa23b05e6572b30331837 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 26 Dec 2011 12:30:13 -0500 Subject: [PATCH 0572/4025] sparc: Fix handling of orig_i0 wrt. debugging when restarting syscalls. [ A combination of upstream commits 1d299bc7732c34d85bd43ac1a8745f5a2fed2078 and e88d2468718b0789b4c33da2f7e1cef2a1eee279 ] Although we provide a proper way for a debugger to control whether syscall restart occurs, we run into problems because orig_i0 is not saved and restored properly. Luckily we can solve this problem without having to make debuggers aware of the issue. Across system calls, several registers are considered volatile and can be safely clobbered. Therefore we use the pt_regs save area of one of those registers, %g6, as a place to save and restore orig_i0. Debuggers transparently will do the right thing because they save and restore this register already. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/sparc/kernel/signal32.c | 18 ++++++++------- arch/sparc/kernel/signal_32.c | 30 ++++++++++++++++++++----- arch/sparc/kernel/signal_64.c | 42 +++++++++++++++++++++++------------ 3 files changed, 63 insertions(+), 27 deletions(-) diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 5d92488fc16..2e58328c30e 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -829,21 +829,23 @@ static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -void do_signal32(sigset_t *oldset, struct pt_regs * regs, - int restart_syscall, unsigned long orig_i0) +void do_signal32(sigset_t *oldset, struct pt_regs * regs) { struct k_sigaction ka; + unsigned long orig_i0; + int restart_syscall; siginfo_t info; int signr; signr = get_signal_to_deliver(&info, &ka, regs, NULL); - /* If the debugger messes with the program counter, it clears - * the "in syscall" bit, directing us to not perform a syscall - * restart. - */ - if (restart_syscall && !pt_regs_is_syscall(regs)) - restart_syscall = 0; + restart_syscall = 0; + orig_i0 = 0; + if (pt_regs_is_syscall(regs) && + (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { + restart_syscall = 1; + orig_i0 = regs->u_regs[UREG_G6]; + } if (signr > 0) { if (restart_syscall) diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 04ede8f04ad..2302567578b 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -525,10 +525,26 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) siginfo_t info; int signr; + /* It's a lot of work and synchronization to add a new ptrace + * register for GDB to save and restore in order to get + * orig_i0 correct for syscall restarts when debugging. + * + * Although it should be the case that most of the global + * registers are volatile across a system call, glibc already + * depends upon that fact that we preserve them. So we can't + * just use any global register to save away the orig_i0 value. + * + * In particular %g2, %g3, %g4, and %g5 are all assumed to be + * preserved across a system call trap by various pieces of + * code in glibc. + * + * %g7 is used as the "thread register". %g6 is not used in + * any fixed manner. %g6 is used as a scratch register and + * a compiler temporary, but it's value is never used across + * a system call. Therefore %g6 is usable for orig_i0 storage. + */ if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) - restart_syscall = 1; - else - restart_syscall = 0; + regs->u_regs[UREG_G6] = orig_i0; if (test_thread_flag(TIF_RESTORE_SIGMASK)) oldset = ¤t->saved_sigmask; @@ -541,8 +557,12 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) * the software "in syscall" bit, directing us to not perform * a syscall restart. */ - if (restart_syscall && !pt_regs_is_syscall(regs)) - restart_syscall = 0; + restart_syscall = 0; + if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) { + restart_syscall = 1; + orig_i0 = regs->u_regs[UREG_G6]; + } + if (signr > 0) { if (restart_syscall) diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index 47509df3b89..d58260bff2d 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -535,11 +535,27 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) siginfo_t info; int signr; + /* It's a lot of work and synchronization to add a new ptrace + * register for GDB to save and restore in order to get + * orig_i0 correct for syscall restarts when debugging. + * + * Although it should be the case that most of the global + * registers are volatile across a system call, glibc already + * depends upon that fact that we preserve them. So we can't + * just use any global register to save away the orig_i0 value. + * + * In particular %g2, %g3, %g4, and %g5 are all assumed to be + * preserved across a system call trap by various pieces of + * code in glibc. + * + * %g7 is used as the "thread register". %g6 is not used in + * any fixed manner. %g6 is used as a scratch register and + * a compiler temporary, but it's value is never used across + * a system call. Therefore %g6 is usable for orig_i0 storage. + */ if (pt_regs_is_syscall(regs) && - (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { - restart_syscall = 1; - } else - restart_syscall = 0; + (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) + regs->u_regs[UREG_G6] = orig_i0; if (current_thread_info()->status & TS_RESTORE_SIGMASK) oldset = ¤t->saved_sigmask; @@ -548,22 +564,20 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) #ifdef CONFIG_COMPAT if (test_thread_flag(TIF_32BIT)) { - extern void do_signal32(sigset_t *, struct pt_regs *, - int restart_syscall, - unsigned long orig_i0); - do_signal32(oldset, regs, restart_syscall, orig_i0); + extern void do_signal32(sigset_t *, struct pt_regs *); + do_signal32(oldset, regs); return; } #endif signr = get_signal_to_deliver(&info, &ka, regs, NULL); - /* If the debugger messes with the program counter, it clears - * the software "in syscall" bit, directing us to not perform - * a syscall restart. - */ - if (restart_syscall && !pt_regs_is_syscall(regs)) - restart_syscall = 0; + restart_syscall = 0; + if (pt_regs_is_syscall(regs) && + (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) { + restart_syscall = 1; + orig_i0 = regs->u_regs[UREG_G6]; + } if (signr > 0) { if (restart_syscall) From b3c5fb8252b04ec02654f80988e68852f1a14cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20K=C3=B6tter?= Date: Sat, 17 Dec 2011 11:39:08 +0000 Subject: [PATCH 0573/4025] net: bpf_jit: fix an off-one bug in x86_64 cond jump target MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit a03ffcf873fe0f2565386ca8ef832144c42e67fa ] x86 jump instruction size is 2 or 5 bytes (near/long jump), not 2 or 6 bytes. In case a conditional jump is followed by a long jump, conditional jump target is one byte past the start of target instruction. Signed-off-by: Markus Kötter Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/x86/net/bpf_jit_comp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index bfab3fa10ed..7b65f752c5f 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -568,8 +568,8 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i]; break; } if (filter[i].jt != 0) { - if (filter[i].jf) - t_offset += is_near(f_offset) ? 2 : 6; + if (filter[i].jf && f_offset) + t_offset += is_near(f_offset) ? 2 : 5; EMIT_COND_JMP(t_op, t_offset); if (filter[i].jf) EMIT_JMP(f_offset); From e2f377870311c6e2ecf77e1ed6bbcb175ce0dde9 Mon Sep 17 00:00:00 2001 From: Djalal Harouni Date: Tue, 6 Dec 2011 15:47:12 +0000 Subject: [PATCH 0574/4025] ppp: fix pptp double release_sock in pptp_bind() [ Upstream commit a454daceb78844a09c08b6e2d8badcb76a5d73b9 ] Signed-off-by: Djalal Harouni Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/pptp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/pptp.c b/drivers/net/pptp.c index 1286fe212dc..4b3a68b69a6 100644 --- a/drivers/net/pptp.c +++ b/drivers/net/pptp.c @@ -418,10 +418,8 @@ static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr, lock_sock(sk); opt->src_addr = sp->sa_addr.pptp; - if (add_chan(po)) { - release_sock(sk); + if (add_chan(po)) error = -EBUSY; - } release_sock(sk); return error; From 7eac8f9de24674cc55ee9797d05447bbfbdf1a96 Mon Sep 17 00:00:00 2001 From: Alex Juncu Date: Thu, 15 Dec 2011 23:01:25 +0000 Subject: [PATCH 0575/4025] llc: llc_cmsg_rcv was getting called after sk_eat_skb. [ Upstream commit 9cef310fcdee12b49b8b4c96fd8f611c8873d284 ] Received non stream protocol packets were calling llc_cmsg_rcv that used a skb after that skb was released by sk_eat_skb. This caused received STP packets to generate kernel panics. Signed-off-by: Alexandru Juncu Signed-off-by: Kunjan Naik Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/llc/af_llc.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index dfd3a648a55..a18e6c3d36e 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -833,15 +833,15 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, copied += used; len -= used; + /* For non stream protcols we get one packet per recvmsg call */ + if (sk->sk_type != SOCK_STREAM) + goto copy_uaddr; + if (!(flags & MSG_PEEK)) { sk_eat_skb(sk, skb, 0); *seq = 0; } - /* For non stream protcols we get one packet per recvmsg call */ - if (sk->sk_type != SOCK_STREAM) - goto copy_uaddr; - /* Partial read */ if (used + offset < skb->len) continue; @@ -857,6 +857,12 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock, } if (llc_sk(sk)->cmsg_flags) llc_cmsg_rcv(msg, skb); + + if (!(flags & MSG_PEEK)) { + sk_eat_skb(sk, skb, 0); + *seq = 0; + } + goto out; } From 477a897533f9ab9a6ebb6eedfa9ca3760caa94b2 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 22 Dec 2011 02:05:07 +0000 Subject: [PATCH 0576/4025] mqprio: Avoid panic if no options are provided [ Upstream commit 7838f2ce36b6ab5c13ef20b1857e3bbd567f1759 ] Userspace may not provide TCA_OPTIONS, in fact tc currently does so not do so if no arguments are specified on the command line. Return EINVAL instead of panicing. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_mqprio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c index ea17cbed29e..59b26b8ff4b 100644 --- a/net/sched/sch_mqprio.c +++ b/net/sched/sch_mqprio.c @@ -106,7 +106,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt) if (!netif_is_multiqueue(dev)) return -EOPNOTSUPP; - if (nla_len(opt) < sizeof(*qopt)) + if (!opt || nla_len(opt) < sizeof(*qopt)) return -EINVAL; qopt = nla_data(opt); From 9ec14c04ec6be93ff397adf250bc91ee77742bfb Mon Sep 17 00:00:00 2001 From: Gerlando Falauto Date: Mon, 19 Dec 2011 22:58:04 +0000 Subject: [PATCH 0577/4025] net: have ipconfig not wait if no dev is available [ Upstream commit cd7816d14953c8af910af5bb92f488b0b277e29d ] previous commit 3fb72f1e6e6165c5f495e8dc11c5bbd14c73385c makes IP-Config wait for carrier on at least one network device. Before waiting (predefined value 120s), check that at least one device was successfully brought up. Otherwise (e.g. buggy bootloader which does not set the MAC address) there is no point in waiting for carrier. Cc: Micha Nelissen Cc: Holger Brunck Signed-off-by: Gerlando Falauto Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ipconfig.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index ab7e5542c1c..7fbcabafa29 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -252,6 +252,10 @@ static int __init ic_open_devs(void) } } + /* no point in waiting if we could not bring up at least one device */ + if (!ic_first_dev) + goto have_carrier; + /* wait for a carrier on at least one device */ start = jiffies; while (jiffies - start < msecs_to_jiffies(CONF_CARRIER_TIMEOUT)) { From 01d6bbab3834409c220083f25810be9f1a553054 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 11 Dec 2011 23:42:53 +0000 Subject: [PATCH 0578/4025] sch_gred: should not use GFP_KERNEL while holding a spinlock [ Upstream commit 3f1e6d3fd37bd4f25e5b19f1c7ca21850426c33f ] gred_change_vq() is called under sch_tree_lock(sch). This means a spinlock is held, and we are not allowed to sleep in this context. We might pre-allocate memory using GFP_KERNEL before taking spinlock, but this is not suitable for stable material. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_gred.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index b9493a09a87..6cd8ddfb512 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -385,7 +385,7 @@ static inline int gred_change_vq(struct Qdisc *sch, int dp, struct gred_sched_data *q; if (table->tab[dp] == NULL) { - table->tab[dp] = kzalloc(sizeof(*q), GFP_KERNEL); + table->tab[dp] = kzalloc(sizeof(*q), GFP_ATOMIC); if (table->tab[dp] == NULL) return -ENOMEM; } From f6e4c89e089ae671a677242edb9e8b08c369c415 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Fri, 16 Dec 2011 12:44:15 +0000 Subject: [PATCH 0579/4025] sctp: fix incorrect overflow check on autoclose [ Upstream commit 2692ba61a82203404abd7dd2a027bda962861f74 ] Commit 8ffd3208 voids the previous patches f6778aab and 810c0719 for limiting the autoclose value. If userspace passes in -1 on 32-bit platform, the overflow check didn't work and autoclose would be set to 0xffffffff. This patch defines a max_autoclose (in seconds) for limiting the value and exposes it through sysctl, with the following intentions. 1) Avoid overflowing autoclose * HZ. 2) Keep the default autoclose bound consistent across 32- and 64-bit platforms (INT_MAX / HZ in this patch). 3) Keep the autoclose value consistent between setsockopt() and getsockopt() calls. Suggested-by: Vlad Yasevich Signed-off-by: Xi Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/sctp/structs.h | 4 ++++ net/sctp/associola.c | 2 +- net/sctp/protocol.c | 3 +++ net/sctp/socket.c | 2 -- net/sctp/sysctl.c | 13 +++++++++++++ 5 files changed, 21 insertions(+), 3 deletions(-) diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 7df327a6d56..c3884214c60 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -236,6 +236,9 @@ extern struct sctp_globals { * bits is an indicator of when to send and window update SACK. */ int rwnd_update_shift; + + /* Threshold for autoclose timeout, in seconds. */ + unsigned long max_autoclose; } sctp_globals; #define sctp_rto_initial (sctp_globals.rto_initial) @@ -271,6 +274,7 @@ extern struct sctp_globals { #define sctp_auth_enable (sctp_globals.auth_enable) #define sctp_checksum_disable (sctp_globals.checksum_disable) #define sctp_rwnd_upd_shift (sctp_globals.rwnd_update_shift) +#define sctp_max_autoclose (sctp_globals.max_autoclose) /* SCTP Socket type: UDP or TCP style. */ typedef enum { diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 4a62888f2e4..17a6e658a4c 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -173,7 +173,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a asoc->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0; asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay; asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = - (unsigned long)sp->autoclose * HZ; + min_t(unsigned long, sp->autoclose, sctp_max_autoclose) * HZ; /* Initializes the timers */ for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 207175b2f40..946afd6045c 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -1144,6 +1144,9 @@ SCTP_STATIC __init int sctp_init(void) sctp_max_instreams = SCTP_DEFAULT_INSTREAMS; sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS; + /* Initialize maximum autoclose timeout. */ + sctp_max_autoclose = INT_MAX / HZ; + /* Initialize handle used for association ids. */ idr_init(&sctp_assocs_id); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d3ccf7973c5..fa9b5c7739a 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -2129,8 +2129,6 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char __user *optval, return -EINVAL; if (copy_from_user(&sp->autoclose, optval, optlen)) return -EFAULT; - /* make sure it won't exceed MAX_SCHEDULE_TIMEOUT */ - sp->autoclose = min_t(long, sp->autoclose, MAX_SCHEDULE_TIMEOUT / HZ); return 0; } diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 50cb57f0919..6752f489feb 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -53,6 +53,10 @@ static int sack_timer_min = 1; static int sack_timer_max = 500; static int addr_scope_max = 3; /* check sctp_scope_policy_t in include/net/sctp/constants.h for max entries */ static int rwnd_scale_max = 16; +static unsigned long max_autoclose_min = 0; +static unsigned long max_autoclose_max = + (MAX_SCHEDULE_TIMEOUT / HZ > UINT_MAX) + ? UINT_MAX : MAX_SCHEDULE_TIMEOUT / HZ; extern long sysctl_sctp_mem[3]; extern int sysctl_sctp_rmem[3]; @@ -251,6 +255,15 @@ static ctl_table sctp_table[] = { .extra1 = &one, .extra2 = &rwnd_scale_max, }, + { + .procname = "max_autoclose", + .data = &sctp_max_autoclose, + .maxlen = sizeof(unsigned long), + .mode = 0644, + .proc_handler = &proc_doulongvec_minmax, + .extra1 = &max_autoclose_min, + .extra2 = &max_autoclose_max, + }, { /* sentinel */ } }; From 0e5fe3ed8d751c7be333fa193882e91dcc289158 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Mon, 19 Dec 2011 04:11:40 +0000 Subject: [PATCH 0580/4025] sctp: Do not account for sizeof(struct sk_buff) in estimated rwnd [ Upstream commit a76c0adf60f6ca5ff3481992e4ea0383776b24d2 ] When checking whether a DATA chunk fits into the estimated rwnd a full sizeof(struct sk_buff) is added to the needed chunk size. This quickly exhausts the available rwnd space and leads to packets being sent which are much below the PMTU limit. This can lead to much worse performance. The reason for this behaviour was to avoid putting too much memory pressure on the receiver. The concept is not completely irational because a Linux receiver does in fact clone an skb for each DATA chunk delivered. However, Linux also reserves half the available socket buffer space for data structures therefore usage of it is already accounted for. When proposing to change this the last time it was noted that this behaviour was introduced to solve a performance issue caused by rwnd overusage in combination with small DATA chunks. Trying to reproduce this I found that with the sk_buff overhead removed, the performance would improve significantly unless socket buffer limits are increased. The following numbers have been gathered using a patched iperf supporting SCTP over a live 1 Gbit ethernet network. The -l option was used to limit DATA chunk sizes. The numbers listed are based on the average of 3 test runs each. Default values have been used for sk_(r|w)mem. Chunk Size Unpatched No Overhead ------------------------------------- 4 15.2 Kbit [!] 12.2 Mbit [!] 8 35.8 Kbit [!] 26.0 Mbit [!] 16 95.5 Kbit [!] 54.4 Mbit [!] 32 106.7 Mbit 102.3 Mbit 64 189.2 Mbit 188.3 Mbit 128 331.2 Mbit 334.8 Mbit 256 537.7 Mbit 536.0 Mbit 512 766.9 Mbit 766.6 Mbit 1024 810.1 Mbit 808.6 Mbit Signed-off-by: Thomas Graf Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/output.c | 8 +------- net/sctp/outqueue.c | 6 ++---- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/net/sctp/output.c b/net/sctp/output.c index 08b3cead650..817174eb5f4 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -697,13 +697,7 @@ static void sctp_packet_append_data(struct sctp_packet *packet, /* Keep track of how many bytes are in flight to the receiver. */ asoc->outqueue.outstanding_bytes += datasize; - /* Update our view of the receiver's rwnd. Include sk_buff overhead - * while updating peer.rwnd so that it reduces the chances of a - * receiver running out of receive buffer space even when receive - * window is still open. This can happen when a sender is sending - * sending small messages. - */ - datasize += sizeof(struct sk_buff); + /* Update our view of the receiver's rwnd. */ if (datasize < rwnd) rwnd -= datasize; else diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index d03682109b7..1f2938fbf9b 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -411,8 +411,7 @@ void sctp_retransmit_mark(struct sctp_outq *q, chunk->transport->flight_size -= sctp_data_size(chunk); q->outstanding_bytes -= sctp_data_size(chunk); - q->asoc->peer.rwnd += (sctp_data_size(chunk) + - sizeof(struct sk_buff)); + q->asoc->peer.rwnd += sctp_data_size(chunk); } continue; } @@ -432,8 +431,7 @@ void sctp_retransmit_mark(struct sctp_outq *q, * (Section 7.2.4)), add the data size of those * chunks to the rwnd. */ - q->asoc->peer.rwnd += (sctp_data_size(chunk) + - sizeof(struct sk_buff)); + q->asoc->peer.rwnd += sctp_data_size(chunk); q->outstanding_bytes -= sctp_data_size(chunk); if (chunk->transport) transport->flight_size -= sctp_data_size(chunk); From 6c3efb1526c3fcdab3e5bbc9c77710b306493507 Mon Sep 17 00:00:00 2001 From: Weiping Pan Date: Thu, 1 Dec 2011 15:47:06 +0000 Subject: [PATCH 0581/4025] ipv4: flush route cache after change accept_local [ Upstream commit d01ff0a049f749e0bf10a35bb23edd012718c8c2 ] After reset ipv4_devconf->data[IPV4_DEVCONF_ACCEPT_LOCAL] to 0, we should flush route cache, or it will continue receive packets with local source address, which should be dropped. Signed-off-by: Weiping Pan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/devinet.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 4155abca261..7d7fb20b0a1 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1490,7 +1490,9 @@ static int devinet_conf_proc(ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { + int old_value = *(int *)ctl->data; int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); + int new_value = *(int *)ctl->data; if (write) { struct ipv4_devconf *cnf = ctl->extra1; @@ -1501,6 +1503,9 @@ static int devinet_conf_proc(ctl_table *ctl, int write, if (cnf == net->ipv4.devconf_dflt) devinet_copy_dflt_conf(net, i); + if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1) + if ((new_value == 0) && (old_value != 0)) + rt_cache_flush(net, 0); } return ret; From ad5dd5dc45d80c397dfe314934e91d0ead793928 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 21 Dec 2011 15:47:16 -0500 Subject: [PATCH 0582/4025] ipv4: reintroduce route cache garbage collector [ Upstream commit 9f28a2fc0bd77511f649c0a788c7bf9a5fd04edb ] Commit 2c8cec5c10b (ipv4: Cache learned PMTU information in inetpeer) removed IP route cache garbage collector a bit too soon, as this gc was responsible for expired routes cleanup, releasing their neighbour reference. As pointed out by Robert Gladewitz, recent kernels can fill and exhaust their neighbour cache. Reintroduce the garbage collection, since we'll have to wait our neighbour lookups become refcount-less to not depend on this stuff. Reported-by: Robert Gladewitz Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/route.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 75ef66f3183..b01f569cfb1 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -132,6 +132,9 @@ static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; static int ip_rt_min_advmss __read_mostly = 256; static int rt_chain_length_max __read_mostly = 20; +static struct delayed_work expires_work; +static unsigned long expires_ljiffies; + /* * Interface to generic destination cache. */ @@ -821,6 +824,97 @@ static int has_noalias(const struct rtable *head, const struct rtable *rth) return ONE; } +static void rt_check_expire(void) +{ + static unsigned int rover; + unsigned int i = rover, goal; + struct rtable *rth; + struct rtable __rcu **rthp; + unsigned long samples = 0; + unsigned long sum = 0, sum2 = 0; + unsigned long delta; + u64 mult; + + delta = jiffies - expires_ljiffies; + expires_ljiffies = jiffies; + mult = ((u64)delta) << rt_hash_log; + if (ip_rt_gc_timeout > 1) + do_div(mult, ip_rt_gc_timeout); + goal = (unsigned int)mult; + if (goal > rt_hash_mask) + goal = rt_hash_mask + 1; + for (; goal > 0; goal--) { + unsigned long tmo = ip_rt_gc_timeout; + unsigned long length; + + i = (i + 1) & rt_hash_mask; + rthp = &rt_hash_table[i].chain; + + if (need_resched()) + cond_resched(); + + samples++; + + if (rcu_dereference_raw(*rthp) == NULL) + continue; + length = 0; + spin_lock_bh(rt_hash_lock_addr(i)); + while ((rth = rcu_dereference_protected(*rthp, + lockdep_is_held(rt_hash_lock_addr(i)))) != NULL) { + prefetch(rth->dst.rt_next); + if (rt_is_expired(rth)) { + *rthp = rth->dst.rt_next; + rt_free(rth); + continue; + } + if (rth->dst.expires) { + /* Entry is expired even if it is in use */ + if (time_before_eq(jiffies, rth->dst.expires)) { +nofree: + tmo >>= 1; + rthp = &rth->dst.rt_next; + /* + * We only count entries on + * a chain with equal hash inputs once + * so that entries for different QOS + * levels, and other non-hash input + * attributes don't unfairly skew + * the length computation + */ + length += has_noalias(rt_hash_table[i].chain, rth); + continue; + } + } else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout)) + goto nofree; + + /* Cleanup aged off entries. */ + *rthp = rth->dst.rt_next; + rt_free(rth); + } + spin_unlock_bh(rt_hash_lock_addr(i)); + sum += length; + sum2 += length*length; + } + if (samples) { + unsigned long avg = sum / samples; + unsigned long sd = int_sqrt(sum2 / samples - avg*avg); + rt_chain_length_max = max_t(unsigned long, + ip_rt_gc_elasticity, + (avg + 4*sd) >> FRACT_BITS); + } + rover = i; +} + +/* + * rt_worker_func() is run in process context. + * we call rt_check_expire() to scan part of the hash table + */ +static void rt_worker_func(struct work_struct *work) +{ + rt_check_expire(); + schedule_delayed_work(&expires_work, ip_rt_gc_interval); +} + /* * Perturbation of rt_genid by a small quantity [1..256] * Using 8 bits of shuffling ensure we can call rt_cache_invalidate() @@ -3087,6 +3181,13 @@ static ctl_table ipv4_route_table[] = { .mode = 0644, .proc_handler = proc_dointvec_jiffies, }, + { + .procname = "gc_interval", + .data = &ip_rt_gc_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, { .procname = "redirect_load", .data = &ip_rt_redirect_load, @@ -3297,6 +3398,11 @@ int __init ip_rt_init(void) devinet_init(); ip_fib_init(); + INIT_DELAYED_WORK_DEFERRABLE(&expires_work, rt_worker_func); + expires_ljiffies = jiffies; + schedule_delayed_work(&expires_work, + net_random() % ip_rt_gc_interval + ip_rt_gc_interval); + if (ip_rt_proc_init()) printk(KERN_ERR "Unable to create route proc files\n"); #ifdef CONFIG_XFRM From 732e81a7579eb0adb26aeadb209e919ee984d01e Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Thu, 22 Dec 2011 17:03:29 +1100 Subject: [PATCH 0583/4025] ipv4: using prefetch requires including prefetch.h [ Upstream commit b9eda06f80b0db61a73bd87c6b0eb67d8aca55ad ] Signed-off-by: Stephen Rothwell Acked-by: Eric Dumazet Acked-by: David Miller Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- net/ipv4/route.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index b01f569cfb1..4845bfe02d2 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include From 244e209cbfb8fef744f47f4a9fe0b8c036772d8f Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 26 Dec 2011 08:47:33 +0200 Subject: [PATCH 0584/4025] iwlwifi: update SCD BC table for all SCD queues commit 96f1f05af76b601ab21a7dc603ae0a1cea4efc3d upstream. Since we configure all the queues as CHAINABLE, we need to update the byte count for all the queues, not only the AGGREGATABLE ones. Not doing so can confuse the SCD and make the fw assert. Signed-off-by: Emmanuel Grumbach Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 1ab1ef15c5a..67cd2e3b6b6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -778,10 +778,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd)); iwl_print_hex_dump(priv, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); - /* Set up entry for this TFD in Tx byte-count array */ - if (info->flags & IEEE80211_TX_CTL_AMPDU) - iwlagn_txq_update_byte_cnt_tbl(priv, txq, - le16_to_cpu(tx_cmd->len)); + iwlagn_txq_update_byte_cnt_tbl(priv, txq, le16_to_cpu(tx_cmd->len)); pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys, firstlen, PCI_DMA_BIDIRECTIONAL); From 4838b7e04451e425895c77f462ae1a70d6d3ff62 Mon Sep 17 00:00:00 2001 From: Sanjeev Premi Date: Mon, 11 Jul 2011 20:50:31 +0530 Subject: [PATCH 0585/4025] mfd: Fix mismatch in twl4030 mutex lock-unlock commit e178ccb33569da17dc897a08a3865441b813bdfb upstream. A mutex is locked on entry into twl4030_madc_conversion(). Immediate return on some error conditions leaves the mutex locked. This patch ensures that mutex is always unlocked before leaving the function. Signed-off-by: Sanjeev Premi Cc: Keerthy Signed-off-by: Samuel Ortiz Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/twl4030-madc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 3941ddcf15f..b5d598c3aa7 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -530,13 +530,13 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) if (ret) { dev_err(twl4030_madc->dev, "unable to write sel register 0x%X\n", method->sel + 1); - return ret; + goto out; } ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel); if (ret) { dev_err(twl4030_madc->dev, "unable to write sel register 0x%X\n", method->sel + 1); - return ret; + goto out; } /* Select averaging for all channels if do_avg is set */ if (req->do_avg) { @@ -546,7 +546,7 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) dev_err(twl4030_madc->dev, "unable to write avg register 0x%X\n", method->avg + 1); - return ret; + goto out; } ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->avg); @@ -554,7 +554,7 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) dev_err(twl4030_madc->dev, "unable to write sel reg 0x%X\n", method->sel + 1); - return ret; + goto out; } } if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) { From 3ad5a4fbba0c5c863b0a42e2a6a5007de76d3102 Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Thu, 11 Aug 2011 22:33:12 -0500 Subject: [PATCH 0586/4025] mfd: Copy the device pointer to the twl4030-madc structure commit 66cc5b8e50af87b0bbd0f179d76d2826f4549c13 upstream. Worst case this fixes the following error: [ 72.086212] (NULL device *): conversion timeout! Best case it prevents a crash Signed-off-by: Kyle Manna Signed-off-by: Samuel Ortiz --- drivers/mfd/twl4030-madc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index b5d598c3aa7..cb44b53dee3 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -706,6 +706,8 @@ static int __devinit twl4030_madc_probe(struct platform_device *pdev) if (!madc) return -ENOMEM; + madc->dev = &pdev->dev; + /* * Phoenix provides 2 interrupt lines. The first one is connected to * the OMAP. The other one can be connected to the other processor such From b5e0e13b29aa292a2ece89a78757a55e85e9e626 Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Thu, 11 Aug 2011 22:33:14 -0500 Subject: [PATCH 0587/4025] mfd: Check for twl4030-madc NULL pointer commit d0e84caeb4cd535923884735906e5730329505b4 upstream. If the twl4030-madc device wasn't registered, and another device, such as twl4030-madc-hwmon, calls twl4030_madc_conversion() a NULL pointer is dereferenced. Signed-off-by: Kyle Manna Signed-off-by: Samuel Ortiz Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/twl4030-madc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index cb44b53dee3..7cbf2aa9e64 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -510,8 +510,9 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req) u8 ch_msb, ch_lsb; int ret; - if (!req) + if (!req || !twl4030_madc) return -EINVAL; + mutex_lock(&twl4030_madc->lock); if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) { ret = -EINVAL; From cb3b250af580752ed54642e37640daf714b30ad3 Mon Sep 17 00:00:00 2001 From: Kyle Manna Date: Thu, 11 Aug 2011 22:33:13 -0500 Subject: [PATCH 0588/4025] mfd: Turn on the twl4030-madc MADC clock commit 3d6271f92e98094584fd1e609a9969cd33e61122 upstream. Without turning the MADC clock on, no MADC conversions occur. $ cat /sys/class/hwmon/hwmon0/device/in8_input [ 53.428436] twl4030_madc twl4030_madc: conversion timeout! cat: read error: Resource temporarily unavailable Signed-off-by: Kyle Manna Signed-off-by: Samuel Ortiz Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/twl4030-madc.c | 22 ++++++++++++++++++++++ include/linux/i2c/twl4030-madc.h | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 7cbf2aa9e64..834f824d3c1 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c @@ -740,6 +740,28 @@ static int __devinit twl4030_madc_probe(struct platform_device *pdev) TWL4030_BCI_BCICTL1); goto err_i2c; } + + /* Check that MADC clock is on */ + ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, ®val, TWL4030_REG_GPBR1); + if (ret) { + dev_err(&pdev->dev, "unable to read reg GPBR1 0x%X\n", + TWL4030_REG_GPBR1); + goto err_i2c; + } + + /* If MADC clk is not on, turn it on */ + if (!(regval & TWL4030_GPBR1_MADC_HFCLK_EN)) { + dev_info(&pdev->dev, "clk disabled, enabling\n"); + regval |= TWL4030_GPBR1_MADC_HFCLK_EN; + ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, regval, + TWL4030_REG_GPBR1); + if (ret) { + dev_err(&pdev->dev, "unable to write reg GPBR1 0x%X\n", + TWL4030_REG_GPBR1); + goto err_i2c; + } + } + platform_set_drvdata(pdev, madc); mutex_init(&madc->lock); ret = request_threaded_irq(platform_get_irq(pdev, 0), NULL, diff --git a/include/linux/i2c/twl4030-madc.h b/include/linux/i2c/twl4030-madc.h index 6427d298fbf..530e11ba073 100644 --- a/include/linux/i2c/twl4030-madc.h +++ b/include/linux/i2c/twl4030-madc.h @@ -129,6 +129,10 @@ enum sample_type { #define REG_BCICTL2 0x024 #define TWL4030_BCI_ITHSENS 0x007 +/* Register and bits for GPBR1 register */ +#define TWL4030_REG_GPBR1 0x0c +#define TWL4030_GPBR1_MADC_HFCLK_EN (1 << 7) + struct twl4030_madc_user_parms { int channel; int average; From 3b26fd897af35e9d48cfbadef1e7f24287d6f1ba Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Thu, 15 Dec 2011 11:28:46 -0500 Subject: [PATCH 0589/4025] xen/swiotlb: Use page alignment for early buffer allocation. commit 63a741757d15320a25ebf5778f8651cce2ed0611 upstream. This fixes an odd bug found on a Dell PowerEdge 1850/0RC130 (BIOS A05 01/09/2006) where all of the modules doing pci_set_dma_mask would fail with: ata_piix 0000:00:1f.1: enabling device (0005 -> 0007) ata_piix 0000:00:1f.1: can't derive routing for PCI INT A ata_piix 0000:00:1f.1: BMDMA: failed to set dma mask, falling back to PIO The issue was the Xen-SWIOTLB was allocated such as that the end of buffer was stradling a page (and also above 4GB). The fix was spotted by Kalev Leonid which was to piggyback on git commit e79f86b2ef9c0a8c47225217c1018b7d3d90101c "swiotlb: Use page alignment for early buffer allocation" which: We could call free_bootmem_late() if swiotlb is not used, and it will shrink to page alignment. So alloc them with page alignment at first, to avoid lose two pages And doing that fixes the outstanding issue. Suggested-by: "Kalev, Leonid" Reported-and-Tested-by: "Taylor, Neal E" Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/xen/swiotlb-xen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 84f317e0cc2..fd60dffeb0f 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -162,7 +162,7 @@ void __init xen_swiotlb_init(int verbose) /* * Get IO TLB memory from any location. */ - xen_io_tlb_start = alloc_bootmem(bytes); + xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes)); if (!xen_io_tlb_start) panic("Cannot allocate SWIOTLB buffer"); From b32a7304bea14c51fe279281db1ff02eefad2e3a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 4 Jan 2012 09:48:35 -0500 Subject: [PATCH 0590/4025] xfs: log the inode in ->write_inode calls for kupdate Commit 0b8fd3033c308e4088760aa1d38ce77197b4e074 upstream. If the writeback code writes back an inode because it has expired we currently use the non-blockin ->write_inode path. This means any inode that is pinned is skipped. With delayed logging and a workload that has very little log traffic otherwise it is very likely that an inode that gets constantly written to is always pinned, and thus we keep refusing to write it. The VM writeback code at that point redirties it and doesn't try to write it again for another 30 seconds. This means under certain scenarious time based metadata writeback never happens. Fix this by calling into xfs_log_inode for kupdate in addition to data integrity syncs, and thus transfer the inode to the log ASAP. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Tested-by: Mark Tinguely Reviewed-by: Mark Tinguely Signed-off-by: Ben Myers Signed-off-by: Greg Kroah-Hartman --- fs/xfs/linux-2.6/xfs_super.c | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 28de70b9122..e6ac98c112e 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -870,27 +870,6 @@ xfs_fs_dirty_inode( XFS_I(inode)->i_update_core = 1; } -STATIC int -xfs_log_inode( - struct xfs_inode *ip) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp; - int error; - - tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS); - error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0); - if (error) { - xfs_trans_cancel(tp, 0); - return error; - } - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL); - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - return xfs_trans_commit(tp, 0); -} - STATIC int xfs_fs_write_inode( struct inode *inode, @@ -904,10 +883,8 @@ xfs_fs_write_inode( if (XFS_FORCED_SHUTDOWN(mp)) return -XFS_ERROR(EIO); - if (!ip->i_update_core) - return 0; - if (wbc->sync_mode == WB_SYNC_ALL) { + if (wbc->sync_mode == WB_SYNC_ALL || wbc->for_kupdate) { /* * Make sure the inode has made it it into the log. Instead * of forcing it all the way to stable storage using a @@ -916,11 +893,14 @@ xfs_fs_write_inode( * of synchronous log foces dramatically. */ xfs_ioend_wait(ip); - error = xfs_log_inode(ip); + error = xfs_log_dirty_inode(ip, NULL, 0); if (error) goto out; return 0; } else { + if (!ip->i_update_core) + return 0; + /* * We make this non-blocking if the inode is contended, return * EAGAIN to indicate to the caller that they did not succeed. From 6826d3e80d143ca7411fd2dca05bc57c7ed3e620 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 4 Jan 2012 09:48:36 -0500 Subject: [PATCH 0591/4025] xfs: log all dirty inodes in xfs_fs_sync_fs Commit be4f1ac828776bbc7868a68b465cd8eedb733cfd upstream. Since Linux 2.6.36 the writeback code has introduces various measures for live lock prevention during sync(). Unfortunately some of these are actively harmful for the XFS model, where the inode gets marked dirty for metadata from the data I/O handler. The older_than_this checks that are now more strictly enforced since writeback: avoid livelocking WB_SYNC_ALL writeback by only calling into __writeback_inodes_sb and thus only sampling the current cut off time once. But on a slow enough devices the previous asynchronous sync pass might not have fully completed yet, and thus XFS might mark metadata dirty only after that sampling of the cut off time for the blocking pass already happened. I have not myself reproduced this myself on a real system, but by introducing artificial delay into the XFS I/O completion workqueues it can be reproduced easily. Fix this by iterating over all XFS inodes in ->sync_fs and log all that are dirty. This might log inode that only got redirtied after the previous pass, but given how cheap delayed logging of inodes is it isn't a major concern for performance. Signed-off-by: Christoph Hellwig Reviewed-by: Dave Chinner Tested-by: Mark Tinguely Reviewed-by: Mark Tinguely Signed-off-by: Ben Myers Signed-off-by: Greg Kroah-Hartman --- fs/xfs/linux-2.6/xfs_sync.c | 37 +++++++++++++++++++++++++++++++++++++ fs/xfs/linux-2.6/xfs_sync.h | 2 ++ 2 files changed, 39 insertions(+) diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c index b69688d0776..2f277a04d67 100644 --- a/fs/xfs/linux-2.6/xfs_sync.c +++ b/fs/xfs/linux-2.6/xfs_sync.c @@ -336,6 +336,32 @@ xfs_sync_fsdata( return xfs_bwrite(mp, bp); } +int +xfs_log_dirty_inode( + struct xfs_inode *ip, + struct xfs_perag *pag, + int flags) +{ + struct xfs_mount *mp = ip->i_mount; + struct xfs_trans *tp; + int error; + + if (!ip->i_update_core) + return 0; + + tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS); + error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0); + if (error) { + xfs_trans_cancel(tp, 0); + return error; + } + + xfs_ilock(ip, XFS_ILOCK_EXCL); + xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL); + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + return xfs_trans_commit(tp, 0); +} + /* * When remounting a filesystem read-only or freezing the filesystem, we have * two phases to execute. This first phase is syncing the data before we @@ -365,6 +391,17 @@ xfs_quiesce_data( /* push and block till complete */ xfs_sync_data(mp, SYNC_WAIT); + + /* + * Log all pending size and timestamp updates. The vfs writeback + * code is supposed to do this, but due to its overagressive + * livelock detection it will skip inodes where appending writes + * were written out in the first non-blocking sync phase if their + * completion took long enough that it happened after taking the + * timestamp for the cut-off in the blocking phase. + */ + xfs_inode_ag_iterator(mp, xfs_log_dirty_inode, 0); + xfs_qm_sync(mp, SYNC_WAIT); /* write superblock and hoover up shutdown errors */ diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h index e3a6ad27415..ef5b2ce4298 100644 --- a/fs/xfs/linux-2.6/xfs_sync.h +++ b/fs/xfs/linux-2.6/xfs_sync.h @@ -42,6 +42,8 @@ void xfs_quiesce_attr(struct xfs_mount *mp); void xfs_flush_inodes(struct xfs_inode *ip); +int xfs_log_dirty_inode(struct xfs_inode *ip, struct xfs_perag *pag, int flags); + int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); void xfs_inode_set_reclaim_tag(struct xfs_inode *ip); From e343400d67fa390709d8147972eb4b700018811b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20M=C3=BCller?= Date: Fri, 30 Dec 2011 12:55:48 -0500 Subject: [PATCH 0592/4025] drm/radeon/kms/atom: fix possible segfault in pm setup commit 4376eee92e5a8332b470040e672ea99cd44c826a upstream. If we end up with no power states, don't look up current vddc. fixes: https://bugs.freedesktop.org/show_bug.cgi?id=44130 agd5f: fix patch formatting Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_atombios.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 285acc4f1e1..a098edcf662 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -2568,7 +2568,11 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; rdev->pm.current_clock_mode_index = 0; - rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; + if (rdev->pm.default_power_state_index >= 0) + rdev->pm.current_vddc = + rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; + else + rdev->pm.current_vddc = 0; } void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) From c61e023d2b6ca9d0aaf766659a81ad5d017e5b53 Mon Sep 17 00:00:00 2001 From: Mandeep Singh Baines Date: Tue, 3 Jan 2012 14:41:13 -0800 Subject: [PATCH 0593/4025] hung_task: fix false positive during vfork commit f9fab10bbd768b0e5254e53a4a8477a94bfc4b96 upstream. vfork parent uninterruptibly and unkillably waits for its child to exec/exit. This wait is of unbounded length. Ignore such waits in the hung_task detector. Signed-off-by: Mandeep Singh Baines Reported-by: Sasha Levin LKML-Reference: <1325344394.28904.43.camel@lappy> Cc: Linus Torvalds Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Andrew Morton Cc: John Kacur Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/hung_task.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/kernel/hung_task.c b/kernel/hung_task.c index ea640120ab8..e972276f12f 100644 --- a/kernel/hung_task.c +++ b/kernel/hung_task.c @@ -74,11 +74,17 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout) /* * Ensure the task is not frozen. - * Also, when a freshly created task is scheduled once, changes - * its state to TASK_UNINTERRUPTIBLE without having ever been - * switched out once, it musn't be checked. + * Also, skip vfork and any other user process that freezer should skip. */ - if (unlikely(t->flags & PF_FROZEN || !switch_count)) + if (unlikely(t->flags & (PF_FROZEN | PF_FREEZER_SKIP))) + return; + + /* + * When a freshly created task is scheduled once, changes its state to + * TASK_UNINTERRUPTIBLE without having ever been switched out once, it + * musn't be checked. + */ + if (unlikely(!switch_count)) return; if (switch_count != t->last_switch_count) { From b47f3ad598247071dcab661f94655bbe8074467a Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 3 Jan 2012 17:32:13 -0800 Subject: [PATCH 0594/4025] Revert "rtc: Disable the alarm in the hardware" commit 157e8bf8b4823bfcdefa6c1548002374b61f61df upstream. This reverts commit c0afabd3d553c521e003779c127143ffde55a16f. It causes failures on Toshiba laptops - instead of disabling the alarm, it actually seems to enable it on the affected laptops, resulting in (for example) the laptop powering on automatically five minutes after shutdown. There's a patch for it that appears to work for at least some people, but it's too late to play around with this, so revert for now and try again in the next merge window. See for example http://bugs.debian.org/652869 Reported-and-bisected-by: Andreas Friedrich (Toshiba Tecra) Reported-by: Antonio-M. Corbi Bellot (Toshiba Portege R500) Reported-by: Marco Santos (Toshiba Portege Z830) Reported-by: Christophe Vu-Brugier (Toshiba Portege R830) Cc: Jonathan Nieder Requested-by: John Stultz Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/interface.c | 44 ++++++++++------------------------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index bbb6f852c5a..eb4c88316a1 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -318,20 +318,6 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) } EXPORT_SYMBOL_GPL(rtc_read_alarm); -static int ___rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) -{ - int err; - - if (!rtc->ops) - err = -ENODEV; - else if (!rtc->ops->set_alarm) - err = -EINVAL; - else - err = rtc->ops->set_alarm(rtc->dev.parent, alarm); - - return err; -} - static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { struct rtc_time tm; @@ -355,7 +341,14 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) * over right here, before we set the alarm. */ - return ___rtc_set_alarm(rtc, alarm); + if (!rtc->ops) + err = -ENODEV; + else if (!rtc->ops->set_alarm) + err = -EINVAL; + else + err = rtc->ops->set_alarm(rtc->dev.parent, alarm); + + return err; } int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) @@ -769,20 +762,6 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) return 0; } -static void rtc_alarm_disable(struct rtc_device *rtc) -{ - struct rtc_wkalrm alarm; - struct rtc_time tm; - - __rtc_read_time(rtc, &tm); - - alarm.time = rtc_ktime_to_tm(ktime_add(rtc_tm_to_ktime(tm), - ktime_set(300, 0))); - alarm.enabled = 0; - - ___rtc_set_alarm(rtc, &alarm); -} - /** * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue * @rtc rtc device @@ -804,10 +783,8 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) struct rtc_wkalrm alarm; int err; next = timerqueue_getnext(&rtc->timerqueue); - if (!next) { - rtc_alarm_disable(rtc); + if (!next) return; - } alarm.time = rtc_ktime_to_tm(next->expires); alarm.enabled = 1; err = __rtc_set_alarm(rtc, &alarm); @@ -869,8 +846,7 @@ void rtc_timer_do_work(struct work_struct *work) err = __rtc_set_alarm(rtc, &alarm); if (err == -ETIME) goto again; - } else - rtc_alarm_disable(rtc); + } mutex_unlock(&rtc->ops_lock); } From ef50d8d96fa350c1f602f8c3bae65eb21ddb28e3 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 4 Jan 2012 17:29:02 +0100 Subject: [PATCH 0595/4025] ptrace: partially fix the do_wait(WEXITED) vs EXIT_DEAD->EXIT_ZOMBIE race commit 50b8d257486a45cba7b65ca978986ed216bbcc10 upstream. Test-case: int main(void) { int pid, status; pid = fork(); if (!pid) { for (;;) { if (!fork()) return 0; if (waitpid(-1, &status, 0) < 0) { printf("ERR!! wait: %m\n"); return 0; } } } assert(ptrace(PTRACE_ATTACH, pid, 0,0) == 0); assert(waitpid(-1, NULL, 0) == pid); assert(ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACEFORK) == 0); do { ptrace(PTRACE_CONT, pid, 0, 0); pid = waitpid(-1, NULL, 0); } while (pid > 0); return 1; } It fails because ->real_parent sees its child in EXIT_DEAD state while the tracer is going to change the state back to EXIT_ZOMBIE in wait_task_zombie(). The offending commit is 823b018e which moved the EXIT_DEAD check, but in fact we should not blame it. The original code was not correct as well because it didn't take ptrace_reparented() into account and because we can't really trust ->ptrace. This patch adds the additional check to close this particular race but it doesn't solve the whole problem. We simply can't rely on ->ptrace in this case, it can be cleared if the tracer is multithreaded by the exiting ->parent. I think we should kill EXIT_DEAD altogether, we should always remove the soon-to-be-reaped child from ->children or at least we should never do the DEAD->ZOMBIE transition. But this is too complex for 3.2. Reported-and-tested-by: Denys Vlasenko Tested-by: Lukasz Michalik Acked-by: Tejun Heo Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/exit.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/kernel/exit.c b/kernel/exit.c index f2b321bae44..303bed2966b 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1553,8 +1553,15 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace, } /* dead body doesn't have much to contribute */ - if (p->exit_state == EXIT_DEAD) + if (unlikely(p->exit_state == EXIT_DEAD)) { + /* + * But do not ignore this task until the tracer does + * wait_task_zombie()->do_notify_parent(). + */ + if (likely(!ptrace) && unlikely(ptrace_reparented(p))) + wo->notask_error = 0; return 0; + } /* slay zombie? */ if (p->exit_state == EXIT_ZOMBIE) { From eb1f526d4bfda44e94ccdf34950911eaff74b092 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 26 Dec 2011 10:42:15 +0530 Subject: [PATCH 0596/4025] ath9k: Fix kernel panic in AR2427 in AP mode commit b25bfda38236f349cde0d1b28952f4eea2148d3f upstream. don't do aggregation related stuff for 'AP mode client power save handling' if aggregation is not enabled in the driver, otherwise it will lead to panic because those data structures won't be never intialized in 'ath_tx_node_init' if aggregation is disabled EIP is at ath_tx_aggr_wakeup+0x37/0x80 [ath9k] EAX: e8c09a20 EBX: f2a304e8 ECX: 00000001 EDX: 00000000 ESI: e8c085e0 EDI: f2a304ac EBP: f40e1ca4 ESP: f40e1c8c DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 Process swapper/1 (pid: 0, ti=f40e0000 task=f408e860 task.ti=f40dc000) Stack: 0001e966 e8c09a20 00000000 f2a304ac e8c085e0 f2a304ac f40e1cb0 f8186741 f8186700 f40e1d2c f922988d f2a304ac 00000202 00000001 c0b4ba43 00000000 0000000f e8eb75c0 e8c085e0 205b0001 34383220 f2a304ac f2a30000 00010020 Call Trace: [] ath9k_sta_notify+0x41/0x50 [ath9k] [] ? ath9k_get_survey+0x110/0x110 [ath9k] [] ieee80211_sta_ps_deliver_wakeup+0x9d/0x350 [mac80211] [] ? __module_address+0x95/0xb0 [] ap_sta_ps_end+0x63/0xa0 [mac80211] [] ieee80211_rx_h_sta_process+0x156/0x2b0 [mac80211] [] ieee80211_rx_handlers+0xce/0x510 [mac80211] [] ? trace_hardirqs_on+0xb/0x10 [] ? skb_queue_tail+0x3e/0x50 [] ieee80211_prepare_and_rx_handle+0x111/0x750 [mac80211] [] ieee80211_rx+0x349/0xb20 [mac80211] [] ? ieee80211_rx+0x99/0xb20 [mac80211] [] ath_rx_tasklet+0x818/0x1d00 [ath9k] [] ? ath9k_tasklet+0x35/0x1c0 [ath9k] [] ? ath9k_tasklet+0x35/0x1c0 [ath9k] [] ath9k_tasklet+0xf3/0x1c0 [ath9k] [] tasklet_action+0xbe/0x180 Cc: Senthil Balasubramanian Cc: Rajkumar Manoharan Reported-by: Ashwin Mendonca Tested-by: Ashwin Mendonca Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 5362306d403..a126a3e238f 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1828,6 +1828,9 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_node *an = (struct ath_node *) sta->drv_priv; + if (!(sc->sc_flags & SC_OP_TXAGGR)) + return; + switch (cmd) { case STA_NOTIFY_SLEEP: an->sleeping = true; From d58331bd6a2881cd265277e4b3b263fecbdf7217 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 6 Jan 2012 14:15:47 -0800 Subject: [PATCH 0597/4025] Linux 3.0.16 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5b8c185be2e..7f0d8e27bf3 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 15 +SUBLEVEL = 16 EXTRAVERSION = NAME = Sneaky Weasel From 744c6bb548d54cc4688a727b251b25d7fbe510cf Mon Sep 17 00:00:00 2001 From: Kisoo Yu Date: Fri, 23 Dec 2011 16:04:03 +0900 Subject: [PATCH 0598/4025] S5PC11X: PD: Add spinlock in power domain control All power domain controls use one NORMAL_CFG register. So, enable and disable procedure needs a protection from simultaneous access. Change-Id: I1f726faa7b546d111bc286e60de8189ebc0ea975 Signed-off-by: Kisoo Yu --- arch/arm/mach-s5pv210/power-domain.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-s5pv210/power-domain.c b/arch/arm/mach-s5pv210/power-domain.c index 338387840f2..59a1a98dd56 100644 --- a/arch/arm/mach-s5pv210/power-domain.c +++ b/arch/arm/mach-s5pv210/power-domain.c @@ -38,6 +38,7 @@ struct clk_should_be_running { const char *clk_name; struct device *dev; }; +static spinlock_t pd_lock; static struct regulator_consumer_supply s5pv210_pd_audio_supply[] = { REGULATOR_SUPPLY("pd", "samsung-i2s.0"), @@ -332,18 +333,25 @@ static int s5pv210_pd_pwr_off(int ctrl) static int s5pv210_pd_ctrl(int ctrlbit, int enable) { - u32 pd_reg = __raw_readl(S5P_NORMAL_CFG); + u32 pd_reg; + spin_lock(&pd_lock); + pd_reg = __raw_readl(S5P_NORMAL_CFG); if (enable) { __raw_writel((pd_reg | ctrlbit), S5P_NORMAL_CFG); if (s5pv210_pd_pwr_done(ctrlbit)) - return -ETIME; + goto out; } else { __raw_writel((pd_reg & ~(ctrlbit)), S5P_NORMAL_CFG); if (s5pv210_pd_pwr_off(ctrlbit)) - return -ETIME; + goto out; } + spin_unlock(&pd_lock); return 0; +out: + spin_unlock(&pd_lock); + return -ETIME; + } static int s5pv210_pd_clk_enable(struct clk_should_be_running *clk_run) @@ -497,6 +505,7 @@ static int __devinit reg_s5pv210_pd_probe(struct platform_device *pdev) drvdata->clk_run = config->clk_run; drvdata->ctrlbit = config->ctrlbit; + spin_lock_init(&pd_lock); drvdata->dev = regulator_register(&drvdata->desc, &pdev->dev, config->init_data, drvdata); From b5c9e41dc5bef0b74fa47ef90e1f9f28a58a84ff Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Wed, 11 Jan 2012 15:52:33 -0800 Subject: [PATCH 0599/4025] video: s3cfb_nt35580: initialize brightness. blank/unblank would leave the brightness set to 0. Also let tl2796 initialize using the actual lcd->bl default. Change-Id: I0ad1709443cf6415900768e934d0d28213d088ec Signed-off-by: JP Abgrall --- drivers/video/samsung/s3cfb_nt35580.c | 1 + drivers/video/samsung/s3cfb_tl2796.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/video/samsung/s3cfb_nt35580.c b/drivers/video/samsung/s3cfb_nt35580.c index 2779ce7075d..3a76083cb9d 100755 --- a/drivers/video/samsung/s3cfb_nt35580.c +++ b/drivers/video/samsung/s3cfb_nt35580.c @@ -214,6 +214,7 @@ static int __devinit nt35580_probe(struct spi_device *spi) } lcd->bl_dev->props.max_brightness = 255; + lcd->bl_dev->props.brightness = lcd->bl; spi_set_drvdata(spi, lcd); lcd->ldi_enable = 1; diff --git a/drivers/video/samsung/s3cfb_tl2796.c b/drivers/video/samsung/s3cfb_tl2796.c index 682997059a4..9c6db88fafb 100755 --- a/drivers/video/samsung/s3cfb_tl2796.c +++ b/drivers/video/samsung/s3cfb_tl2796.c @@ -633,7 +633,7 @@ static int __devinit tl2796_probe(struct spi_device *spi) } lcd->bl_dev->props.max_brightness = 255; - lcd->bl_dev->props.brightness = 255; + lcd->bl_dev->props.brightness = lcd->bl; tl2796_ldi_enable(lcd); #ifdef CONFIG_HAS_EARLYSUSPEND From c8c609f0d82e86be9827faf1980b97dea15c529f Mon Sep 17 00:00:00 2001 From: sangamanatha Date: Wed, 21 Dec 2011 14:21:40 +0900 Subject: [PATCH 0600/4025] ARM: S5PC11X: wimax pins sleep current reduction ARM: S5PC11X: wimax sleep gpio configuration changes to reduce the sleep current. Signed-off-by: sangamanatha --- arch/arm/mach-s5pv210/mach-herring.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c index fe578c4ed3e..f605dcf2b46 100755 --- a/arch/arm/mach-s5pv210/mach-herring.c +++ b/arch/arm/mach-s5pv210/mach-herring.c @@ -4770,8 +4770,8 @@ static unsigned int herring_cdma_wimax_sleep_gpio_table[][3] = { { S5PV210_GPC1(2), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, /*WIMAX EEPROM I2C LINES*/ - { S5PV210_GPC1(3), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, - { S5PV210_GPC1(4), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, + { S5PV210_GPC1(3), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, + { S5PV210_GPC1(4), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, /*WIMAX DBGEN*/ { S5PV210_GPD0(0), S3C_GPIO_SLP_PREV, S3C_GPIO_PULL_NONE}, @@ -4780,7 +4780,7 @@ static unsigned int herring_cdma_wimax_sleep_gpio_table[][3] = { { S5PV210_GPD0(2), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, /*WIMAX RESET_N*/ - { S5PV210_GPD0(3), S3C_GPIO_SLP_PREV, S3C_GPIO_PULL_NONE}, + { S5PV210_GPD0(3), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_UP}, { S5PV210_GPD1(0), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, { S5PV210_GPD1(1), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_NONE}, @@ -4911,7 +4911,7 @@ static unsigned int herring_cdma_wimax_sleep_gpio_table[][3] = { { S5PV210_GPJ2(1), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, { S5PV210_GPJ2(2), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, { S5PV210_GPJ2(3), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, - { S5PV210_GPJ2(4), S3C_GPIO_SLP_PREV, S3C_GPIO_PULL_DOWN}, + { S5PV210_GPJ2(4), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, { S5PV210_GPJ2(5), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, { S5PV210_GPJ2(6), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, From 9345ff5c125a0597bc9deb76ec784b883f616107 Mon Sep 17 00:00:00 2001 From: Thomas Ryu Date: Tue, 13 Dec 2011 20:47:30 +0900 Subject: [PATCH 0601/4025] ARM: S5PC11X: improve USB signal quality Tunning of PHY0 Tune Register to improve physical characteristics. This improves the margin of USB eye diagram, which means the quality of USB signal is also improved. Signed-off-by: Thomas Ryu --- arch/arm/mach-s5pv210/mach-herring.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c index f605dcf2b46..be33104846f 100755 --- a/arch/arm/mach-s5pv210/mach-herring.c +++ b/arch/arm/mach-s5pv210/mach-herring.c @@ -5977,9 +5977,8 @@ void otg_phy_init(void) writel(readl(S3C_USBOTG_PHYTUNE) | (0x1<<20), S3C_USBOTG_PHYTUNE); - /* set DC level as 6 (6%) */ - writel((readl(S3C_USBOTG_PHYTUNE) & ~(0xf)) | (0x1<<2) | (0x1<<1), - S3C_USBOTG_PHYTUNE); + /* set DC level as 0xf (24%) */ + writel(readl(S3C_USBOTG_PHYTUNE) | 0xf, S3C_USBOTG_PHYTUNE); } EXPORT_SYMBOL(otg_phy_init); From 0a356c00cd87453a7c45ab0b2e49410b17802d71 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 9 Dec 2011 13:54:34 -0800 Subject: [PATCH 0602/4025] MAINTAINERS: stable: Update address commit bc7a2f3abc636d7cab84258a48e77b08fb5fd3d6 upstream. The old address hasn't worked since the great intrusion of August 2011. Signed-off-by: Joe Perches Signed-off-by: Greg Kroah-Hartman --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 34e24186584..de85391c021 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6039,7 +6039,7 @@ F: arch/alpha/kernel/srm_env.c STABLE BRANCH M: Greg Kroah-Hartman -L: stable@kernel.org +L: stable@vger.kernel.org S: Maintained STAGING SUBSYSTEM From e559e564fbf46caf1d2c5a531ffe8b745b117c3f Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 9 Dec 2011 14:12:00 -0800 Subject: [PATCH 0603/4025] Documentation: Update stable address commit 2eb7f204db51969ea558802a6601d79c2fb273b9 upstream. The Japanese/Korean/Chinese versions still need updating. Also, the stable kernel 2.6.x.y descriptions are out of date and should be updated as well. Signed-off-by: Joe Perches Signed-off-by: Greg Kroah-Hartman --- Documentation/HOWTO | 4 ++-- Documentation/development-process/5.Posting | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Documentation/HOWTO b/Documentation/HOWTO index 81bc1a9ab9d..f7ade3b3b40 100644 --- a/Documentation/HOWTO +++ b/Documentation/HOWTO @@ -275,8 +275,8 @@ versions. If no 2.6.x.y kernel is available, then the highest numbered 2.6.x kernel is the current stable kernel. -2.6.x.y are maintained by the "stable" team , and are -released as needs dictate. The normal release period is approximately +2.6.x.y are maintained by the "stable" team , and +are released as needs dictate. The normal release period is approximately two weeks, but it can be longer if there are no pressing problems. A security-related problem, instead, can cause a release to happen almost instantly. diff --git a/Documentation/development-process/5.Posting b/Documentation/development-process/5.Posting index 903a2546f13..8a48c9b6286 100644 --- a/Documentation/development-process/5.Posting +++ b/Documentation/development-process/5.Posting @@ -271,10 +271,10 @@ copies should go to: the linux-kernel list. - If you are fixing a bug, think about whether the fix should go into the - next stable update. If so, stable@kernel.org should get a copy of the - patch. Also add a "Cc: stable@kernel.org" to the tags within the patch - itself; that will cause the stable team to get a notification when your - fix goes into the mainline. + next stable update. If so, stable@vger.kernel.org should get a copy of + the patch. Also add a "Cc: stable@vger.kernel.org" to the tags within + the patch itself; that will cause the stable team to get a notification + when your fix goes into the mainline. When selecting recipients for a patch, it is good to have an idea of who you think will eventually accept the patch and get it merged. While it From d4560a886a6ddd150cb5489d2b9491f96349aa7f Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Mon, 2 Jan 2012 15:31:23 -0500 Subject: [PATCH 0604/4025] firmware: Fix an oops on reading fw_priv->fw in sysfs loading file commit eea915bb0d1358755f151eaefb8208a2d5f3e10c upstream. This oops was reported recently: firmware_loading_store+0xf9/0x17b dev_attr_store+0x20/0x22 sysfs_write_file+0x101/0x134 vfs_write+0xac/0xf3 sys_write+0x4a/0x6e system_call_fastpath+0x16/0x1b The complete backtrace was unfortunately not captured, but details can be found here: https://bugzilla.redhat.com/show_bug.cgi?id=769920 The cause is fairly clear. Its caused by the fact that firmware_loading_store has a case 0 in its switch statement that reads and writes the fw_priv->fw poniter without the protection of the fw_lock mutex. since there is a window between the time that _request_firmware sets fw_priv->fw to NULL and the time the corresponding sysfs file is unregistered, its possible for a user space application to race in, and write a zero to the loading file, causing a NULL dereference in firmware_loading_store. Fix it by extending the protection of the fw_lock mutex to cover all of the firware_loading_store function. Signed-off-by: Neil Horman Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_class.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 06ed6b4e7df..3719c94be19 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -226,13 +226,13 @@ static ssize_t firmware_loading_store(struct device *dev, int loading = simple_strtol(buf, NULL, 10); int i; + mutex_lock(&fw_lock); + + if (!fw_priv->fw) + goto out; + switch (loading) { case 1: - mutex_lock(&fw_lock); - if (!fw_priv->fw) { - mutex_unlock(&fw_lock); - break; - } firmware_free_data(fw_priv->fw); memset(fw_priv->fw, 0, sizeof(struct firmware)); /* If the pages are not owned by 'struct firmware' */ @@ -243,7 +243,6 @@ static ssize_t firmware_loading_store(struct device *dev, fw_priv->page_array_size = 0; fw_priv->nr_pages = 0; set_bit(FW_STATUS_LOADING, &fw_priv->status); - mutex_unlock(&fw_lock); break; case 0: if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) { @@ -274,7 +273,8 @@ static ssize_t firmware_loading_store(struct device *dev, fw_load_abort(fw_priv); break; } - +out: + mutex_unlock(&fw_lock); return count; } From 081fa89b1a6e7ed3a05459b88ad974a6f3795a90 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 27 Dec 2011 12:22:51 -0600 Subject: [PATCH 0605/4025] rt2800usb: Move ID out of unknown commit 3f81f8f1524ccca24df1029b0cf825ecef5e5cdc upstream. Testing on the openSUSE wireless forum has shown that a Linksys WUSB54GC v3 with USB ID 1737:0077 works with rt2800usb when the ID is written to /sys/.../new_id. This ID can therefore be moved out of UNKNOWN. Signed-off-by: Larry Finger Acked-by: Gertjan van Wingerde Acked-by: Ivo van Doorn Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2800usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 6e7fe941b95..d4e9eac5815 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -878,6 +878,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x13b1, 0x0031) }, { USB_DEVICE(0x1737, 0x0070) }, { USB_DEVICE(0x1737, 0x0071) }, + { USB_DEVICE(0x1737, 0x0077) }, /* Logitec */ { USB_DEVICE(0x0789, 0x0162) }, { USB_DEVICE(0x0789, 0x0163) }, @@ -1069,7 +1070,6 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x1740, 0x0605) }, { USB_DEVICE(0x1740, 0x0615) }, /* Linksys */ - { USB_DEVICE(0x1737, 0x0077) }, { USB_DEVICE(0x1737, 0x0078) }, /* Logitec */ { USB_DEVICE(0x0789, 0x0168) }, From 51a32a1a373e071aec24ffa765d198d591b3d6dd Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 28 Dec 2011 00:10:16 +0000 Subject: [PATCH 0606/4025] offb: Fix setting of the pseudo-palette for >8bpp commit 1bb0b7d21584b3f878e2bc880db62351ddee5185 upstream. When using a >8bpp framebuffer, offb advertises truecolor, not directcolor, and doesn't touch the color map even if it has a corresponding access method for the real hardware. Thus it needs to set the pseudo-palette with all 3 components of the color, like other truecolor framebuffers, not with copies of the color index like a directcolor framebuffer would do. This went unnoticed for a long time because it's pretty hard to get offb to kick in with anything but 8bpp (old BootX under MacOS will do that and qemu does it). Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- drivers/video/offb.c | 50 ++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/drivers/video/offb.c b/drivers/video/offb.c index cb163a5397b..24e1fc6b565 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -100,36 +100,32 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int transp, struct fb_info *info) { struct offb_par *par = (struct offb_par *) info->par; - int i, depth; - u32 *pal = info->pseudo_palette; - - depth = info->var.bits_per_pixel; - if (depth == 16) - depth = (info->var.green.length == 5) ? 15 : 16; - - if (regno > 255 || - (depth == 16 && regno > 63) || - (depth == 15 && regno > 31)) - return 1; - - if (regno < 16) { - switch (depth) { - case 15: - pal[regno] = (regno << 10) | (regno << 5) | regno; - break; - case 16: - pal[regno] = (regno << 11) | (regno << 5) | regno; - break; - case 24: - pal[regno] = (regno << 16) | (regno << 8) | regno; - break; - case 32: - i = (regno << 8) | regno; - pal[regno] = (i << 16) | i; - break; + + if (info->fix.visual == FB_VISUAL_TRUECOLOR) { + u32 *pal = info->pseudo_palette; + u32 cr = red >> (16 - info->var.red.length); + u32 cg = green >> (16 - info->var.green.length); + u32 cb = blue >> (16 - info->var.blue.length); + u32 value; + + if (regno >= 16) + return -EINVAL; + + value = (cr << info->var.red.offset) | + (cg << info->var.green.offset) | + (cb << info->var.blue.offset); + if (info->var.transp.length > 0) { + u32 mask = (1 << info->var.transp.length) - 1; + mask <<= info->var.transp.offset; + value |= mask; } + pal[regno] = value; + return 0; } + if (regno > 255) + return -EINVAL; + red >>= 8; green >>= 8; blue >>= 8; From 68530d7210025a1e395819b774fcffaf943dd8f3 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 3 Jan 2012 12:09:15 +1100 Subject: [PATCH 0607/4025] offb: Fix bug in calculating requested vram size commit c055fe0797b7bd8f6f21a13598a55a16d5c13ae7 upstream. We used to try to request 8 times more vram than needed, which would fail if the card has a too small BAR (observed with qemu & kvm). Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- drivers/video/offb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/offb.c b/drivers/video/offb.c index 24e1fc6b565..3251a0236d5 100644 --- a/drivers/video/offb.c +++ b/drivers/video/offb.c @@ -377,7 +377,7 @@ static void __init offb_init_fb(const char *name, const char *full_name, int pitch, unsigned long address, int foreign_endian, struct device_node *dp) { - unsigned long res_size = pitch * height * (depth + 7) / 8; + unsigned long res_size = pitch * height; struct offb_par *par = &default_par; unsigned long res_start = address; struct fb_fix_screeninfo *fix; From 4b2bb3c98c134fb26332afd5ad54078c53a30c44 Mon Sep 17 00:00:00 2001 From: Pontus Fuchs Date: Tue, 18 Oct 2011 09:23:41 +0200 Subject: [PATCH 0608/4025] wl12xx: Validate FEM index from ini file and FW commit 2131d3c2f99b081806fdae7662c92fe6acda52af upstream. Check for out of bound FEM index to prevent reading beyond ini memory end. Signed-off-by: Pontus Fuchs Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/wl12xx/cmd.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c index 42935ac7266..b8ec8cd69b0 100644 --- a/drivers/net/wireless/wl12xx/cmd.c +++ b/drivers/net/wireless/wl12xx/cmd.c @@ -121,6 +121,11 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) if (!wl->nvs) return -ENODEV; + if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { + wl1271_warning("FEM index from INI out of bounds"); + return -EINVAL; + } + gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); if (!gen_parms) return -ENOMEM; @@ -144,6 +149,12 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) gp->tx_bip_fem_manufacturer = gen_parms->general_params.tx_bip_fem_manufacturer; + if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { + wl1271_warning("FEM index from FW out of bounds"); + ret = -EINVAL; + goto out; + } + wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); @@ -163,6 +174,11 @@ int wl128x_cmd_general_parms(struct wl1271 *wl) if (!wl->nvs) return -ENODEV; + if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { + wl1271_warning("FEM index from ini out of bounds"); + return -EINVAL; + } + gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL); if (!gen_parms) return -ENOMEM; @@ -187,6 +203,12 @@ int wl128x_cmd_general_parms(struct wl1271 *wl) gp->tx_bip_fem_manufacturer = gen_parms->general_params.tx_bip_fem_manufacturer; + if (gp->tx_bip_fem_manufacturer >= WL1271_INI_FEM_MODULE_COUNT) { + wl1271_warning("FEM index from FW out of bounds"); + ret = -EINVAL; + goto out; + } + wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); From a7b8c32b67b60fe9e8b53bb86bb7a04631e6e262 Mon Sep 17 00:00:00 2001 From: Pontus Fuchs Date: Tue, 18 Oct 2011 09:23:42 +0200 Subject: [PATCH 0609/4025] wl12xx: Check buffer bound when processing nvs data commit f6efe96edd9c41c624c8f4ddbc4930c1a2d8f1e1 upstream. An nvs with malformed contents could cause the processing of the calibration data to read beyond the end of the buffer. Prevent this from happening by adding bound checking. Signed-off-by: Pontus Fuchs Reviewed-by: Luciano Coelho Signed-off-by: Luciano Coelho Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/wl12xx/boot.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c index b07f8b7e5f1..e0e16888fe8 100644 --- a/drivers/net/wireless/wl12xx/boot.c +++ b/drivers/net/wireless/wl12xx/boot.c @@ -328,6 +328,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) nvs_ptr += 3; for (i = 0; i < burst_len; i++) { + if (nvs_ptr + 3 >= (u8 *) wl->nvs + nvs_len) + goto out_badnvs; + val = (nvs_ptr[0] | (nvs_ptr[1] << 8) | (nvs_ptr[2] << 16) | (nvs_ptr[3] << 24)); @@ -339,6 +342,9 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) nvs_ptr += 4; dest_addr += 4; } + + if (nvs_ptr >= (u8 *) wl->nvs + nvs_len) + goto out_badnvs; } /* @@ -350,6 +356,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) */ nvs_ptr = (u8 *)wl->nvs + ALIGN(nvs_ptr - (u8 *)wl->nvs + 7, 4); + + if (nvs_ptr >= (u8 *) wl->nvs + nvs_len) + goto out_badnvs; + nvs_len -= nvs_ptr - (u8 *)wl->nvs; /* Now we must set the partition correctly */ @@ -365,6 +375,10 @@ static int wl1271_boot_upload_nvs(struct wl1271 *wl) kfree(nvs_aligned); return 0; + +out_badnvs: + wl1271_error("nvs data is malformed"); + return -EILSEQ; } static void wl1271_boot_enable_interrupts(struct wl1271 *wl) From bfaebb8af017d443937022cf3d5735d726e4f711 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 23 Nov 2011 20:07:17 +0000 Subject: [PATCH 0610/4025] powerpc/time: Handle wrapping of decrementer commit 37fb9a0231ee43d42d069863bdfd567fca2b61af upstream. When re-enabling interrupts we have code to handle edge sensitive decrementers by resetting the decrementer to 1 whenever it is negative. If interrupts were disabled long enough that the decrementer wrapped to positive we do nothing. This means interrupts can be delayed for a long time until it finally goes negative again. While we hope interrupts are never be disabled long enough for the decrementer to go positive, we have a very good test team that can drive any kernel into the ground. The softlockup data we get back from these fails could be seconds in the future, completely missing the cause of the lockup. We already keep track of the timebase of the next event so use that to work out if we should trigger a decrementer exception. Signed-off-by: Anton Blanchard Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/time.h | 2 ++ arch/powerpc/kernel/irq.c | 15 ++++++--------- arch/powerpc/kernel/time.c | 9 +++++++++ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h index fe6f7c2c9c6..bc3c745cb90 100644 --- a/arch/powerpc/include/asm/time.h +++ b/arch/powerpc/include/asm/time.h @@ -219,5 +219,7 @@ DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array); extern void secondary_cpu_time_init(void); extern void iSeries_time_init_early(void); +extern void decrementer_check_overflow(void); + #endif /* __KERNEL__ */ #endif /* __POWERPC_TIME_H */ diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 5b428e30866..ca2987d939f 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -170,16 +170,13 @@ notrace void arch_local_irq_restore(unsigned long en) */ local_paca->hard_enabled = en; -#ifndef CONFIG_BOOKE - /* On server, re-trigger the decrementer if it went negative since - * some processors only trigger on edge transitions of the sign bit. - * - * BookE has a level sensitive decrementer (latches in TSR) so we - * don't need that + /* + * Trigger the decrementer if we have a pending event. Some processors + * only trigger on edge transitions of the sign bit. We might also + * have disabled interrupts long enough that the decrementer wrapped + * to positive. */ - if ((int)mfspr(SPRN_DEC) < 0) - mtspr(SPRN_DEC, 1); -#endif /* CONFIG_BOOKE */ + decrementer_check_overflow(); /* * Force the delivery of pending soft-disabled interrupts on PS3. diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 03b29a6759a..2de304af07a 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -889,6 +889,15 @@ static void __init clocksource_init(void) clock->name, clock->mult, clock->shift); } +void decrementer_check_overflow(void) +{ + u64 now = get_tb_or_rtc(); + struct decrementer_clock *decrementer = &__get_cpu_var(decrementers); + + if (now >= decrementer->next_tb) + set_dec(1); +} + static int decrementer_set_next_event(unsigned long evt, struct clock_event_device *dev) { From ec0d3233562d591c892841fcfa73edd3700a6ca6 Mon Sep 17 00:00:00 2001 From: Li Zhong Date: Sun, 18 Dec 2011 16:03:04 +0000 Subject: [PATCH 0611/4025] powerpc: Fix unpaired probe_hcall_entry and probe_hcall_exit commit e4f387d8db3ba3c2dae4d8bdfe7bb5f4fe1bcb0d upstream. Unpaired calling of probe_hcall_entry and probe_hcall_exit might happen as following, which could cause incorrect preempt count. __trace_hcall_entry => trace_hcall_entry -> probe_hcall_entry => get_cpu_var => preempt_disable __trace_hcall_exit => trace_hcall_exit -> probe_hcall_exit => put_cpu_var => preempt_enable where: A => B and A -> B means A calls B, but => means A will call B through function name, and B will definitely be called. -> means A will call B through function pointer, so B might not be called if the function pointer is not set. So error happens when only one of probe_hcall_entry and probe_hcall_exit get called during a hcall. This patch tries to move the preempt count operations from probe_hcall_entry and probe_hcall_exit to its callers. Reported-by: Paul E. McKenney Signed-off-by: Li Zhong Tested-by: Paul E. McKenney Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/pseries/hvCall_inst.c | 4 +--- arch/powerpc/platforms/pseries/lpar.c | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c index f106662f438..c9311cfdfca 100644 --- a/arch/powerpc/platforms/pseries/hvCall_inst.c +++ b/arch/powerpc/platforms/pseries/hvCall_inst.c @@ -109,7 +109,7 @@ static void probe_hcall_entry(void *ignored, unsigned long opcode, unsigned long if (opcode > MAX_HCALL_OPCODE) return; - h = &get_cpu_var(hcall_stats)[opcode / 4]; + h = &__get_cpu_var(hcall_stats)[opcode / 4]; h->tb_start = mftb(); h->purr_start = mfspr(SPRN_PURR); } @@ -126,8 +126,6 @@ static void probe_hcall_exit(void *ignored, unsigned long opcode, unsigned long h->num_calls++; h->tb_total += mftb() - h->tb_start; h->purr_total += mfspr(SPRN_PURR) - h->purr_start; - - put_cpu_var(hcall_stats); } static int __init hcall_inst_init(void) diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index ed96b376537..81e30d96f83 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -745,6 +745,7 @@ void __trace_hcall_entry(unsigned long opcode, unsigned long *args) goto out; (*depth)++; + preempt_disable(); trace_hcall_entry(opcode, args); (*depth)--; @@ -767,6 +768,7 @@ void __trace_hcall_exit(long opcode, unsigned long retval, (*depth)++; trace_hcall_exit(opcode, retval, retbuf); + preempt_enable(); (*depth)--; out: From e50262ea574d1daf62529e2b282b8551790f7f38 Mon Sep 17 00:00:00 2001 From: Aurelien Jacobs Date: Fri, 16 Dec 2011 10:49:22 +0000 Subject: [PATCH 0612/4025] asix: new device id commit e8303a3b2196272c3eb994d0fd1a189a958a2bdd upstream. Adds the device id needed for the USB Ethernet Adapter delivered by ASUS with their Zenbook. Signed-off-by: Aurelien Jacobs Acked-by: Grant Grundler Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/asix.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index c5c4b4def7f..c50632e8658 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -1560,6 +1560,10 @@ static const struct usb_device_id products [] = { // ASIX 88772a USB_DEVICE(0x0db0, 0xa877), .driver_info = (unsigned long) &ax88772_info, +}, { + // Asus USB Ethernet Adapter + USB_DEVICE (0x0b95, 0x7e2b), + .driver_info = (unsigned long) &ax88772_info, }, { }, // END }; From 0853141b9eff15c72dde6868ee5351db3f7d12f1 Mon Sep 17 00:00:00 2001 From: Ram Vepa Date: Fri, 23 Dec 2011 08:01:43 -0500 Subject: [PATCH 0613/4025] IB/qib: Fix a possible data corruption when receiving packets commit eddfb675256f49d14e8c5763098afe3eb2c93701 upstream. Prevent a receive data corruption by ensuring that the write to update the rcvhdrheadn register to generate an interrupt is at the very end of the receive processing. Signed-off-by: Ramkrishna Vepa Signed-off-by: Mike Marciniszyn Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/qib/qib_iba6120.c | 4 +++- drivers/infiniband/hw/qib/qib_iba7220.c | 4 +++- drivers/infiniband/hw/qib/qib_iba7322.c | 6 ++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index d8ca0a0b970..65df26ce538 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -2076,9 +2076,11 @@ static void qib_6120_config_ctxts(struct qib_devdata *dd) static void qib_update_6120_usrhead(struct qib_ctxtdata *rcd, u64 hd, u32 updegr, u32 egrhd, u32 npkts) { - qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt); if (updegr) qib_write_ureg(rcd->dd, ur_rcvegrindexhead, egrhd, rcd->ctxt); + mmiowb(); + qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt); + mmiowb(); } static u32 qib_6120_hdrqempty(struct qib_ctxtdata *rcd) diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index c765a2eb04c..759bb63bb3b 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -2704,9 +2704,11 @@ static int qib_7220_set_loopback(struct qib_pportdata *ppd, const char *what) static void qib_update_7220_usrhead(struct qib_ctxtdata *rcd, u64 hd, u32 updegr, u32 egrhd, u32 npkts) { - qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt); if (updegr) qib_write_ureg(rcd->dd, ur_rcvegrindexhead, egrhd, rcd->ctxt); + mmiowb(); + qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt); + mmiowb(); } static u32 qib_7220_hdrqempty(struct qib_ctxtdata *rcd) diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 8ec5237031a..49e4a589479 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -4060,10 +4060,12 @@ static void qib_update_7322_usrhead(struct qib_ctxtdata *rcd, u64 hd, */ if (hd >> IBA7322_HDRHEAD_PKTINT_SHIFT) adjust_rcv_timeout(rcd, npkts); - qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt); - qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt); if (updegr) qib_write_ureg(rcd->dd, ur_rcvegrindexhead, egrhd, rcd->ctxt); + mmiowb(); + qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt); + qib_write_ureg(rcd->dd, ur_rcvhdrhead, hd, rcd->ctxt); + mmiowb(); } static u32 qib_7322_hdrqempty(struct qib_ctxtdata *rcd) From 2431496fbdd142ccc83138d94f3f510a36ce9270 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 4 Nov 2011 16:32:25 -0400 Subject: [PATCH 0614/4025] perf: Fix parsing of __print_flags() in TP_printk() commit 49908a1b25d448d68fd26faca260e1850201575f upstream. A update is made to the sched:sched_switch event that adds some logic to the first parameter of the __print_flags() that shows the state of tasks. This change cause perf to fail parsing the flags. A simple fix is needed to have the parser be able to process ops within the argument. Reported-by: Andrew Vagin Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/trace-event-parse.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c index 6c164dc9ee9..bf54c48871d 100644 --- a/tools/perf/util/trace-event-parse.c +++ b/tools/perf/util/trace-event-parse.c @@ -1582,6 +1582,8 @@ process_symbols(struct event *event, struct print_arg *arg, char **tok) field = malloc_or_die(sizeof(*field)); type = process_arg(event, field, &token); + while (type == EVENT_OP) + type = process_op(event, field, &token); if (test_type_token(type, token, EVENT_DELIM, ",")) goto out_free; From dcc4f0ce22c88840b2c490e962dfbd84cb003941 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 21 Dec 2011 17:35:34 +0100 Subject: [PATCH 0615/4025] reiserfs: Fix quota mount option parsing commit a06d789b424190e9f59da391681f908486db2554 upstream. When jqfmt mount option is not specified on remount, we mistakenly clear s_jquota_fmt value stored in superblock. Fix the problem. CC: reiserfs-devel@vger.kernel.org Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/reiserfs/super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index aa91089162c..a19a9f5b55e 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -1164,7 +1164,8 @@ static void handle_quota_files(struct super_block *s, char **qf_names, kfree(REISERFS_SB(s)->s_qf_names[i]); REISERFS_SB(s)->s_qf_names[i] = qf_names[i]; } - REISERFS_SB(s)->s_jquota_fmt = *qfmt; + if (*qfmt) + REISERFS_SB(s)->s_jquota_fmt = *qfmt; } #endif From d8bbed420a3f1a3c7290a7bb9f3b424fd24c0b04 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Wed, 21 Dec 2011 21:18:43 +0100 Subject: [PATCH 0616/4025] reiserfs: Force inode evictions before umount to avoid crash commit a9e36da655e54545c3289b2a0700b5c443de0edd upstream. This patch fixes a crash in reiserfs_delete_xattrs during umount. When shrink_dcache_for_umount clears the dcache from generic_shutdown_super, delayed evictions are forced to disk. If an evicted inode has extended attributes associated with it, it will need to walk the xattr tree to locate and remove them. But since shrink_dcache_for_umount will BUG if it encounters active dentries, the xattr tree must be released before it's called or it will crash during every umount. This patch forces the evictions to occur before generic_shutdown_super by calling shrink_dcache_sb first. The additional evictions caused by the removal of each associated xattr file and dir will be automatically handled as they're added to the LRU list. CC: reiserfs-devel@vger.kernel.org Signed-off-by: Jeff Mahoney Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/reiserfs/super.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index a19a9f5b55e..f19dfbf6000 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -453,16 +453,20 @@ int remove_save_link(struct inode *inode, int truncate) static void reiserfs_kill_sb(struct super_block *s) { if (REISERFS_SB(s)) { - if (REISERFS_SB(s)->xattr_root) { - d_invalidate(REISERFS_SB(s)->xattr_root); - dput(REISERFS_SB(s)->xattr_root); - REISERFS_SB(s)->xattr_root = NULL; - } - if (REISERFS_SB(s)->priv_root) { - d_invalidate(REISERFS_SB(s)->priv_root); - dput(REISERFS_SB(s)->priv_root); - REISERFS_SB(s)->priv_root = NULL; - } + /* + * Force any pending inode evictions to occur now. Any + * inodes to be removed that have extended attributes + * associated with them need to clean them up before + * we can release the extended attribute root dentries. + * shrink_dcache_for_umount will BUG if we don't release + * those before it's called so ->put_super is too late. + */ + shrink_dcache_sb(s); + + dput(REISERFS_SB(s)->xattr_root); + REISERFS_SB(s)->xattr_root = NULL; + dput(REISERFS_SB(s)->priv_root); + REISERFS_SB(s)->priv_root = NULL; } kill_block_super(s); From 42e857c955b65b25062e5af605c4164e5e32b144 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 22 Dec 2011 16:49:05 +0100 Subject: [PATCH 0617/4025] ext3: Don't warn from writepage when readonly inode is spotted after error commit 33c104d415e92a51aaf638dc3d93920cfa601e5c upstream. WARN_ON_ONCE(IS_RDONLY(inode)) tends to trip when filesystem hits error and is remounted read-only. This unnecessarily scares users (well, they should be scared because of filesystem error, but the stack trace distracts them from the right source of their fear ;-). We could as well just remove the WARN_ON but it's not hard to fix it to not trip on filesystem with errors and not use more cycles in the common case so that's what we do. Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/ext3/inode.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 3451d23c3ba..db9ba1a3f7f 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -1568,7 +1568,13 @@ static int ext3_ordered_writepage(struct page *page, int err; J_ASSERT(PageLocked(page)); - WARN_ON_ONCE(IS_RDONLY(inode)); + /* + * We don't want to warn for emergency remount. The condition is + * ordered to avoid dereferencing inode->i_sb in non-error case to + * avoid slow-downs. + */ + WARN_ON_ONCE(IS_RDONLY(inode) && + !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ERROR_FS)); /* * We give up here if we're reentered, because it might be for a @@ -1642,7 +1648,13 @@ static int ext3_writeback_writepage(struct page *page, int err; J_ASSERT(PageLocked(page)); - WARN_ON_ONCE(IS_RDONLY(inode)); + /* + * We don't want to warn for emergency remount. The condition is + * ordered to avoid dereferencing inode->i_sb in non-error case to + * avoid slow-downs. + */ + WARN_ON_ONCE(IS_RDONLY(inode) && + !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ERROR_FS)); if (ext3_journal_current_handle()) goto out_fail; @@ -1684,7 +1696,13 @@ static int ext3_journalled_writepage(struct page *page, int err; J_ASSERT(PageLocked(page)); - WARN_ON_ONCE(IS_RDONLY(inode)); + /* + * We don't want to warn for emergency remount. The condition is + * ordered to avoid dereferencing inode->i_sb in non-error case to + * avoid slow-downs. + */ + WARN_ON_ONCE(IS_RDONLY(inode) && + !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ERROR_FS)); if (ext3_journal_current_handle()) goto no_write; From 90a043b02598d19b6dccc677bbf9bb8e8ec94ab7 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 4 Jan 2012 16:36:35 -0500 Subject: [PATCH 0618/4025] USB: update documentation for usbmon commit d8cae98cddd286e38db1724dda1b0e7b467f9237 upstream. The documentation for usbmon is out of date; the usbfs "devices" file now exists in /sys/kernel/debug/usb rather than /proc/bus/usb. This patch (as1505) updates the documentation accordingly, and also mentions that the necessary information can be found by running lsusb. Signed-off-by: Alan Stern CC: Pete Zaitcev Signed-off-by: Greg Kroah-Hartman --- Documentation/usb/usbmon.txt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt index a4efa0462f0..5335fa8b06e 100644 --- a/Documentation/usb/usbmon.txt +++ b/Documentation/usb/usbmon.txt @@ -47,10 +47,11 @@ This allows to filter away annoying devices that talk continuously. 2. Find which bus connects to the desired device -Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to -the device. Usually you do it by looking for the vendor string. If you have -many similar devices, unplug one and compare two /proc/bus/usb/devices outputs. -The T-line will have a bus number. Example: +Run "cat /sys/kernel/debug/usb/devices", and find the T-line which corresponds +to the device. Usually you do it by looking for the vendor string. If you have +many similar devices, unplug one and compare the two +/sys/kernel/debug/usb/devices outputs. The T-line will have a bus number. +Example: T: Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 @@ -58,7 +59,10 @@ P: Vendor=0557 ProdID=2004 Rev= 1.00 S: Manufacturer=ATEN S: Product=UC100KM V2.00 -Bus=03 means it's bus 3. +"Bus=03" means it's bus 3. Alternatively, you can look at the output from +"lsusb" and get the bus number from the appropriate line. Example: + +Bus 003 Device 002: ID 0557:2004 ATEN UC100KM V2.00 3. Start 'cat' From 630fe244a944ebb950e8b2076177547266d255cf Mon Sep 17 00:00:00 2001 From: Claudio Scordino Date: Fri, 16 Dec 2011 15:08:49 +0100 Subject: [PATCH 0619/4025] atmel_serial: fix spinlock lockup in RS485 code commit dbf1115d3f8c7052788aa4e6e46abd27f3b3eeba upstream. Patch to fix a spinlock lockup in the driver that sometimes happens when the tasklet starts. Signed-off-by: Claudio Scordino Signed-off-by: Dave Bender Tested-by: Dave Bender Acked-by: Nicolas Ferre Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index af9b7814965..b989495c763 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -199,8 +199,9 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned int mode; + unsigned long flags; - spin_lock(&port->lock); + spin_lock_irqsave(&port->lock, flags); /* Disable interrupts */ UART_PUT_IDR(port, atmel_port->tx_done_mask); @@ -231,7 +232,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) /* Enable interrupts */ UART_PUT_IER(port, atmel_port->tx_done_mask); - spin_unlock(&port->lock); + spin_unlock_irqrestore(&port->lock, flags); } From 2481cbcad1ba76a928c74c2e8cab67d8c77823ab Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Tue, 27 Dec 2011 14:25:55 +0800 Subject: [PATCH 0620/4025] cgroup: fix to allow mounting a hierarchy by name commit 0d19ea866562e46989412a0676412fa0983c9ce7 upstream. If we mount a hierarchy with a specified name, the name is unique, and we can use it to mount the hierarchy without specifying its set of subsystem names. This feature is documented is Documentation/cgroups/cgroups.txt section 2.3 Here's an example: # mount -t cgroup -o cpuset,name=myhier xxx /cgroup1 # mount -t cgroup -o name=myhier xxx /cgroup2 But it was broken by commit 32a8cf235e2f192eb002755076994525cdbaa35a (cgroup: make the mount options parsing more accurate) This fixes the regression. Signed-off-by: Li Zefan Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- kernel/cgroup.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 575a5e78263..2efce77f649 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1173,10 +1173,10 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts) /* * If the 'all' option was specified select all the subsystems, - * otherwise 'all, 'none' and a subsystem name options were not - * specified, let's default to 'all' + * otherwise if 'none', 'name=' and a subsystem name options + * were not specified, let's default to 'all' */ - if (all_ss || (!all_ss && !one_ss && !opts->none)) { + if (all_ss || (!one_ss && !opts->none && !opts->name)) { for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { struct cgroup_subsys *ss = subsys[i]; if (ss == NULL) From 608620c3e7c26618bbef00ce070e7d0bbfb9cc37 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Sat, 10 Dec 2011 02:30:48 +0100 Subject: [PATCH 0621/4025] udf: Fix deadlock when converting file from in-ICB one to normal one commit d2eb8c359309ec45d6bf5b147303ab8e13be86ea upstream. During BKL removal in 2.6.38, conversion of files from in-ICB format to normal format got broken. We call ->writepage with i_data_sem held but udf_get_block() also acquires i_data_sem thus creating A-A deadlock. We fix the problem by dropping i_data_sem before calling ->writepage() which is safe since i_mutex still protects us against any changes in the file. Also fix pagelock - i_data_sem lock inversion in udf_expand_file_adinicb() by dropping i_data_sem before calling find_or_create_page(). Reported-by: Matthias Matiak Tested-by: Matthias Matiak Reviewed-by: Namjae Jeon Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/udf/file.c | 6 +++--- fs/udf/inode.c | 21 ++++++++++++++++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/fs/udf/file.c b/fs/udf/file.c index 2a346bb1d9f..0c0c9d33dbc 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -125,7 +125,6 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, err = udf_expand_file_adinicb(inode); if (err) { udf_debug("udf_expand_adinicb: err=%d\n", err); - up_write(&iinfo->i_data_sem); return err; } } else { @@ -133,9 +132,10 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, iinfo->i_lenAlloc = pos + count; else iinfo->i_lenAlloc = inode->i_size; + up_write(&iinfo->i_data_sem); } - } - up_write(&iinfo->i_data_sem); + } else + up_write(&iinfo->i_data_sem); retval = generic_file_aio_write(iocb, iov, nr_segs, ppos); if (retval > 0) diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 1d1358ed80c..262050f2eb6 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -145,6 +145,12 @@ const struct address_space_operations udf_aops = { .bmap = udf_bmap, }; +/* + * Expand file stored in ICB to a normal one-block-file + * + * This function requires i_data_sem for writing and releases it. + * This function requires i_mutex held + */ int udf_expand_file_adinicb(struct inode *inode) { struct page *page; @@ -163,9 +169,15 @@ int udf_expand_file_adinicb(struct inode *inode) iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; /* from now on we have normal address_space methods */ inode->i_data.a_ops = &udf_aops; + up_write(&iinfo->i_data_sem); mark_inode_dirty(inode); return 0; } + /* + * Release i_data_sem so that we can lock a page - page lock ranks + * above i_data_sem. i_mutex still protects us against file changes. + */ + up_write(&iinfo->i_data_sem); page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS); if (!page) @@ -181,6 +193,7 @@ int udf_expand_file_adinicb(struct inode *inode) SetPageUptodate(page); kunmap(page); } + down_write(&iinfo->i_data_sem); memset(iinfo->i_ext.i_data + iinfo->i_lenEAttr, 0x00, iinfo->i_lenAlloc); iinfo->i_lenAlloc = 0; @@ -190,17 +203,20 @@ int udf_expand_file_adinicb(struct inode *inode) iinfo->i_alloc_type = ICBTAG_FLAG_AD_LONG; /* from now on we have normal address_space methods */ inode->i_data.a_ops = &udf_aops; + up_write(&iinfo->i_data_sem); err = inode->i_data.a_ops->writepage(page, &udf_wbc); if (err) { /* Restore everything back so that we don't lose data... */ lock_page(page); kaddr = kmap(page); + down_write(&iinfo->i_data_sem); memcpy(iinfo->i_ext.i_data + iinfo->i_lenEAttr, kaddr, inode->i_size); kunmap(page); unlock_page(page); iinfo->i_alloc_type = ICBTAG_FLAG_AD_IN_ICB; inode->i_data.a_ops = &udf_adinicb_aops; + up_write(&iinfo->i_data_sem); } page_cache_release(page); mark_inode_dirty(inode); @@ -1105,10 +1121,9 @@ int udf_setsize(struct inode *inode, loff_t newsize) if (bsize < (udf_file_entry_alloc_offset(inode) + newsize)) { err = udf_expand_file_adinicb(inode); - if (err) { - up_write(&iinfo->i_data_sem); + if (err) return err; - } + down_write(&iinfo->i_data_sem); } else iinfo->i_lenAlloc = newsize; } From e60f83773e5a5757b765b30776bd1e7fe1188c1b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 23 Dec 2011 14:02:55 +0100 Subject: [PATCH 0622/4025] drivers/usb/class/cdc-acm.c: clear dangling pointer commit e7c8e8605d0bafc705ff27f9da98a1668427cc0f upstream. On some failures, the country_code field of an acm structure is freed without freeing the acm structure itself. Elsewhere, operations including memcpy and kfree are performed on the country_code field. The patch sets the country_code field to NULL when it is freed, and likewise sets the country_code_size field to 0. Signed-off-by: Julia Lawall Acked-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 8faa23cd74f..b632d4b5354 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1183,6 +1183,8 @@ static int acm_probe(struct usb_interface *intf, i = device_create_file(&intf->dev, &dev_attr_wCountryCodes); if (i < 0) { kfree(acm->country_codes); + acm->country_codes = NULL; + acm->country_code_size = 0; goto skip_countries; } @@ -1191,6 +1193,8 @@ static int acm_probe(struct usb_interface *intf, if (i < 0) { device_remove_file(&intf->dev, &dev_attr_wCountryCodes); kfree(acm->country_codes); + acm->country_codes = NULL; + acm->country_code_size = 0; goto skip_countries; } } From 41671fca58f3487f4dd4b148a0a3360b2f9ebb2a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 5 Dec 2011 14:02:59 -0800 Subject: [PATCH 0623/4025] USB: isight: fix kernel bug when loading firmware commit 59bf5cf94f0fa3b08fb1258b52649077b7d0914d upstream. We were sending data on the stack when uploading firmware, which causes some machines fits, and is not allowed. Fix this by using the buffer we already had around for this very purpose. Reported-by: Wouter M. Koolen Tested-by: Wouter M. Koolen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/isight_firmware.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/usb/misc/isight_firmware.c b/drivers/usb/misc/isight_firmware.c index fe1d44319d0..8f725f65191 100644 --- a/drivers/usb/misc/isight_firmware.c +++ b/drivers/usb/misc/isight_firmware.c @@ -55,8 +55,9 @@ static int isight_firmware_load(struct usb_interface *intf, ptr = firmware->data; + buf[0] = 0x01; if (usb_control_msg - (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\1", 1, + (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1, 300) != 1) { printk(KERN_ERR "Failed to initialise isight firmware loader\n"); @@ -100,8 +101,9 @@ static int isight_firmware_load(struct usb_interface *intf, } } + buf[0] = 0x00; if (usb_control_msg - (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\0", 1, + (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1, 300) != 1) { printk(KERN_ERR "isight firmware loading completion failed\n"); ret = -ENODEV; From 702d50dd4360c942a3b888c468843f2540a95e64 Mon Sep 17 00:00:00 2001 From: Huajun Li Date: Wed, 4 Jan 2012 19:25:33 +0800 Subject: [PATCH 0624/4025] usb: usb-storage doesn't support dynamic id currently, the patch disables the feature to fix an oops commit 1a3a026ba1b6bbfe0b7f79ab38cf991d691e7c9a upstream. Echo vendor and product number of a non usb-storage device to usb-storage driver's new_id, then plug in the device to host and you will find following oops msg, the root cause is usb_stor_probe1() refers invalid id entry if giving a dynamic id, so just disable the feature. [ 3105.018012] general protection fault: 0000 [#1] SMP DEBUG_PAGEALLOC [ 3105.018062] CPU 0 [ 3105.018075] Modules linked in: usb_storage usb_libusual bluetooth dm_crypt binfmt_misc snd_hda_codec_analog snd_hda_intel snd_hda_codec snd_hwdep hp_wmi ppdev sparse_keymap snd_pcm snd_seq_midi snd_rawmidi snd_seq_midi_event snd_seq snd_timer snd_seq_device psmouse snd serio_raw tpm_infineon soundcore i915 snd_page_alloc tpm_tis parport_pc tpm tpm_bios drm_kms_helper drm i2c_algo_bit video lp parport usbhid hid sg sr_mod sd_mod ehci_hcd uhci_hcd usbcore e1000e usb_common floppy [ 3105.018408] [ 3105.018419] Pid: 189, comm: khubd Tainted: G I 3.2.0-rc7+ #29 Hewlett-Packard HP Compaq dc7800p Convertible Minitower/0AACh [ 3105.018481] RIP: 0010:[] [] usb_stor_probe1+0x2fd/0xc20 [usb_storage] [ 3105.018536] RSP: 0018:ffff880056a3d830 EFLAGS: 00010286 [ 3105.018562] RAX: ffff880065f4e648 RBX: ffff88006bb28000 RCX: 0000000000000000 [ 3105.018597] RDX: ffff88006f23c7b0 RSI: 0000000000000001 RDI: 0000000000000206 [ 3105.018632] RBP: ffff880056a3d900 R08: 0000000000000000 R09: ffff880067365000 [ 3105.018665] R10: 00000000000002ac R11: 0000000000000010 R12: ffff6000b41a7340 [ 3105.018698] R13: ffff880065f4ef60 R14: ffff88006bb28b88 R15: ffff88006f23d270 [ 3105.018733] FS: 0000000000000000(0000) GS:ffff88007a200000(0000) knlGS:0000000000000000 [ 3105.018773] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 3105.018801] CR2: 00007fc99c8c4650 CR3: 0000000001e05000 CR4: 00000000000006f0 [ 3105.018835] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 3105.018870] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 3105.018906] Process khubd (pid: 189, threadinfo ffff880056a3c000, task ffff88005677a400) [ 3105.018945] Stack: [ 3105.018959] 0000000000000000 0000000000000000 ffff880056a3d8d0 0000000000000002 [ 3105.019011] 0000000000000000 ffff880056a3d918 ffff880000000000 0000000000000002 [ 3105.019058] ffff880056a3d8d0 0000000000000012 ffff880056a3d8d0 0000000000000006 [ 3105.019105] Call Trace: [ 3105.019128] [] storage_probe+0xa4/0xe0 [usb_storage] [ 3105.019173] [] usb_probe_interface+0x172/0x330 [usbcore] [ 3105.019211] [] driver_probe_device+0x257/0x3b0 [ 3105.019243] [] __device_attach+0x73/0x90 [ 3105.019272] [] ? __driver_attach+0x110/0x110 [ 3105.019303] [] bus_for_each_drv+0x9c/0xf0 [ 3105.019334] [] device_attach+0xf7/0x120 [ 3105.019364] [] bus_probe_device+0x45/0x80 [ 3105.019396] [] device_add+0x876/0x990 [ 3105.019434] [] usb_set_configuration+0x822/0x9e0 [usbcore] [ 3105.019479] [] generic_probe+0x62/0xf0 [usbcore] [ 3105.019518] [] usb_probe_device+0x66/0xb0 [usbcore] [ 3105.019555] [] driver_probe_device+0x257/0x3b0 [ 3105.019589] [] __device_attach+0x73/0x90 [ 3105.019617] [] ? __driver_attach+0x110/0x110 [ 3105.019648] [] bus_for_each_drv+0x9c/0xf0 [ 3105.019680] [] device_attach+0xf7/0x120 [ 3105.019709] [] bus_probe_device+0x45/0x80 [ 3105.021040] usb usb6: usb auto-resume [ 3105.021045] usb usb6: wakeup_rh [ 3105.024849] [] device_add+0x876/0x990 [ 3105.025086] [] usb_new_device+0x1e7/0x2b0 [usbcore] [ 3105.025086] [] hub_thread+0xb27/0x1ec0 [usbcore] [ 3105.025086] [] ? wake_up_bit+0x50/0x50 [ 3105.025086] [] ? usb_remote_wakeup+0xa0/0xa0 [usbcore] [ 3105.025086] [] kthread+0xd8/0xf0 [ 3105.025086] [] kernel_thread_helper+0x4/0x10 [ 3105.025086] [] ? _raw_spin_unlock_irq+0x50/0x80 [ 3105.025086] [] ? retint_restore_args+0x13/0x13 [ 3105.025086] [] ? __init_kthread_worker+0x80/0x80 [ 3105.025086] [] ? gs_change+0x13/0x13 [ 3105.025086] Code: 00 48 83 05 cd ad 00 00 01 48 83 05 cd ad 00 00 01 4c 8b ab 30 0c 00 00 48 8b 50 08 48 83 c0 30 48 89 45 a0 4c 89 a3 40 0c 00 00 <41> 0f b6 44 24 10 48 89 55 a8 3c ff 0f 84 b8 04 00 00 48 83 05 [ 3105.025086] RIP [] usb_stor_probe1+0x2fd/0xc20 [usb_storage] [ 3105.025086] RSP [ 3105.060037] hub 6-0:1.0: hub_resume [ 3105.062616] usb usb5: usb auto-resume [ 3105.064317] ehci_hcd 0000:00:1d.7: resume root hub [ 3105.094809] ---[ end trace a7919e7f17c0a727 ]--- [ 3105.130069] hub 5-0:1.0: hub_resume [ 3105.132131] usb usb4: usb auto-resume [ 3105.132136] usb usb4: wakeup_rh [ 3105.180059] hub 4-0:1.0: hub_resume [ 3106.290052] usb usb6: suspend_rh (auto-stop) [ 3106.290077] usb usb4: suspend_rh (auto-stop) Signed-off-by: Huajun Li Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index c325e69415a..9e069efeefe 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -1073,6 +1073,7 @@ static struct usb_driver usb_storage_driver = { .id_table = usb_storage_usb_ids, .supports_autosuspend = 1, .soft_unbind = 1, + .no_dynamic_id = 1, }; static int __init usb_stor_init(void) From d1a86326cb0aaa71ddef4ae5325e2387c1410380 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 3 Jan 2012 09:58:54 +0100 Subject: [PATCH 0625/4025] USB: add quirk for another camera commit 35284b3d2f68a8a3703745e629999469f78386b5 upstream. The Guillemot Webcam Hercules Dualpix Exchange camera has been reported with a second ID. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/quirks.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index ecf12e15a7e..4c65eb6a867 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -117,9 +117,12 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x06a3, 0x0006), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, - /* Guillemot Webcam Hercules Dualpix Exchange*/ + /* Guillemot Webcam Hercules Dualpix Exchange (2nd ID) */ { USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Guillemot Webcam Hercules Dualpix Exchange*/ + { USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME }, + /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, From a2cb6c3022494f6e43d284ed9159e15dd71f5937 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Mon, 19 Dec 2011 22:01:54 +0200 Subject: [PATCH 0626/4025] usb: musb: fix pm_runtime mismatch commit 772aed45b604c5ff171f0f12c12392d868333f79 upstream. In musb_init_controller() there's a pm_runtime_put(), but there's no pm_runtime_get(), which creates a mismatch that causes the driver to sleep when it shouldn't. This was introduced in 7acc619[1], but it wasn't triggered in my setup until 18a2689[2] was merged to Linus' branch at point df0914[3]. IOW; when PM is working as it was supposed to. However, it seems most of the time this is used in a way that keeps the counter above 0, so nobody noticed. Also, it seems to depend on the configuration used in versions before 3.1, but not later (or in it). I found the problem by loading isp1704_charger before any usb gadgets: http://article.gmane.org/gmane.linux.kernel/1226122 All versions after 2.6.39 are affected. [1] usb: musb: Idle path retention and offmode support for OMAP3 [2] OMAP2+: musb: hwmod adaptation for musb registration [3] Merge branch 'omap-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap-2.6 Cc: Hema HK Signed-off-by: Felipe Contreras Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_core.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index dce7182e1df..a0232a77c05 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2078,8 +2078,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) if (status < 0) goto fail3; - pm_runtime_put(musb->controller); - status = musb_init_debugfs(musb); if (status < 0) goto fail4; From 5ccce01507d92e98ca263b35aa263f43e24b272f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Sun, 6 Nov 2011 19:06:21 +0100 Subject: [PATCH 0627/4025] USB: omninet: fix write_room commit 694c6301e515bad574af74b6552134c4d9dcb334 upstream. Fix regression introduced by commit 507ca9bc047666 ([PATCH] USB: add ability for usb-serial drivers to determine if their write urb is currently being used.) which inverted the logic in write_room so that it returns zero when the write urb is actually free. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/omninet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 60f38d5e64f..0a8c1e64b24 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -315,7 +315,7 @@ static int omninet_write_room(struct tty_struct *tty) int room = 0; /* Default: no room */ /* FIXME: no consistent locking for write_urb_busy */ - if (wport->write_urb_busy) + if (!wport->write_urb_busy) room = wport->bulk_out_size - OMNINET_HEADERLEN; dbg("%s - returns %d", __func__, room); From 0d5b25f934978301b2a1385c72f3b6abe04db484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Schr=C3=B6der?= Date: Thu, 5 Jan 2012 20:34:40 +0100 Subject: [PATCH 0628/4025] USB: Add USB-ID for Multiplex RC serial adapter to cp210x.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 08e87d0d773dc9ca5faf4c3306e238ed0ea129b0 upstream. Hi, below patch adds the USB-ID of the serial adapters sold by Multiplex RC (www.multiplex-rc.de). Signed-off-by: Malte Schröder Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index fd67cc53545..a1a324b30d2 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -92,6 +92,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */ { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */ { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */ + { USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */ { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */ { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */ { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ From 766b8a7f7ee006dfd73dbc676addd80f7dbe86ef Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sat, 3 Dec 2011 23:41:31 +0100 Subject: [PATCH 0629/4025] usb: fix number of mapped SG DMA entries commit bc677d5b64644c399cd3db6a905453e611f402ab upstream. Add a new field num_mapped_sgs to struct urb so that we have a place to store the number of mapped entries and can also retain the original value of entries in num_sgs. Previously, usb_hcd_map_urb_for_dma() would overwrite this with the number of mapped entries, which would break dma_unmap_sg() because it requires the original number of entries. This fixes warnings like the following when using USB storage devices: ------------[ cut here ]------------ WARNING: at lib/dma-debug.c:902 check_unmap+0x4e4/0x695() ehci_hcd 0000:00:12.2: DMA-API: device driver frees DMA sg list with different entry count [map count=4] [unmap count=1] Modules linked in: ohci_hcd ehci_hcd Pid: 0, comm: kworker/0:1 Not tainted 3.2.0-rc2+ #319 Call Trace: [] warn_slowpath_common+0x80/0x98 [] warn_slowpath_fmt+0x41/0x43 [] check_unmap+0x4e4/0x695 [] ? trace_hardirqs_off+0xd/0xf [] ? _raw_spin_unlock_irqrestore+0x33/0x50 [] debug_dma_unmap_sg+0xeb/0x117 [] usb_hcd_unmap_urb_for_dma+0x71/0x188 [] unmap_urb_for_dma+0x20/0x22 [] usb_hcd_giveback_urb+0x5d/0xc0 [] ehci_urb_done+0xf7/0x10c [ehci_hcd] [] qh_completions+0x429/0x4bd [ehci_hcd] [] ehci_work+0x95/0x9c0 [ehci_hcd] ... ---[ end trace f29ac88a5a48c580 ]--- Mapped at: [] debug_dma_map_sg+0x45/0x139 [] usb_hcd_map_urb_for_dma+0x22e/0x478 [] usb_hcd_submit_urb+0x63f/0x6fa [] usb_submit_urb+0x2c7/0x2de [] usb_sg_wait+0x55/0x161 Signed-off-by: Clemens Ladisch Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 5 ++--- drivers/usb/host/ehci-q.c | 2 +- drivers/usb/host/uhci-q.c | 2 +- drivers/usb/host/whci/qset.c | 4 ++-- drivers/usb/host/xhci-ring.c | 4 ++-- include/linux/usb.h | 1 + 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 39ea00bfb9c..691d212cac4 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1387,11 +1387,10 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, ret = -EAGAIN; else urb->transfer_flags |= URB_DMA_MAP_SG; - if (n != urb->num_sgs) { - urb->num_sgs = n; + urb->num_mapped_sgs = n; + if (n != urb->num_sgs) urb->transfer_flags |= URB_DMA_SG_COMBINED; - } } else if (urb->sg) { struct scatterlist *sg = urb->sg; urb->transfer_dma = dma_map_page( diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 0917e3a3246..2499b3bce36 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -649,7 +649,7 @@ qh_urb_transaction ( /* * data transfer stage: buffer setup */ - i = urb->num_sgs; + i = urb->num_mapped_sgs; if (len > 0 && i > 0) { sg = urb->sg; buf = sg_dma_address(sg); diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 84ed28b34f9..82539913ad8 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -943,7 +943,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, if (usb_pipein(urb->pipe)) status |= TD_CTRL_SPD; - i = urb->num_sgs; + i = urb->num_mapped_sgs; if (len > 0 && i > 0) { sg = urb->sg; data = sg_dma_address(sg); diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index a403b53e86b..76083ae9213 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c @@ -443,7 +443,7 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u remaining = urb->transfer_buffer_length; - for_each_sg(urb->sg, sg, urb->num_sgs, i) { + for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) { dma_addr_t dma_addr; size_t dma_remaining; dma_addr_t sp, ep; @@ -561,7 +561,7 @@ static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset, remaining = urb->transfer_buffer_length; - for_each_sg(urb->sg, sg, urb->num_sgs, i) { + for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) { size_t len; size_t sg_remaining; void *orig; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index b4b06910f68..c0c5d6c7cb6 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -2570,7 +2570,7 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb) struct scatterlist *sg; sg = NULL; - num_sgs = urb->num_sgs; + num_sgs = urb->num_mapped_sgs; temp = urb->transfer_buffer_length; xhci_dbg(xhci, "count sg list trbs: \n"); @@ -2754,7 +2754,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, return -EINVAL; num_trbs = count_sg_trbs_needed(xhci, urb); - num_sgs = urb->num_sgs; + num_sgs = urb->num_mapped_sgs; total_packet_count = roundup(urb->transfer_buffer_length, le16_to_cpu(urb->ep->desc.wMaxPacketSize)); diff --git a/include/linux/usb.h b/include/linux/usb.h index 73c7df48960..b08e04cf202 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -1202,6 +1202,7 @@ struct urb { void *transfer_buffer; /* (in) associated data buffer */ dma_addr_t transfer_dma; /* (in) dma addr for transfer_buffer */ struct scatterlist *sg; /* (in) scatter gather buffer list */ + int num_mapped_sgs; /* (internal) mapped sg entries */ int num_sgs; /* (in) number of entries in the sg list */ u32 transfer_buffer_length; /* (in) data buffer length */ u32 actual_length; /* (return) actual transfer length */ From 35e81320ad9953dbcf3cea06d18828ebee3b0468 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 4 Jan 2012 23:29:18 +0100 Subject: [PATCH 0630/4025] xhci: Properly handle COMP_2ND_BW_ERR commit 71d85724bdd947a3b42a88d08af79f290a1a767b upstream. I encountered a result of COMP_2ND_BW_ERR while improving how the pwc webcam driver handles not having the full usb1 bandwidth available to itself. I created the following test setup, a NEC xhci controller with a single TT USB 2 hub plugged into it, with a usb keyboard and a pwc webcam plugged into the usb2 hub. This caused the following to show up in dmesg when trying to stream from the pwc camera at its highest alt setting: xhci_hcd 0000:01:00.0: ERROR: unexpected command completion code 0x23. usb 6-2.1: Not enough bandwidth for altsetting 9 And usb_set_interface returned -EINVAL, which caused my pwc code to not do the right thing as it expected -ENOSPC. This patch makes the xhci driver properly handle COMP_2ND_BW_ERR and makes usb_set_interface return -ENOSPC as expected. This should be backported to stable kernels as old as 2.6.32. Signed-off-by: Hans de Goede Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 1 + drivers/usb/host/xhci.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 221f14e1fdd..b880e546d88 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1568,6 +1568,7 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, /* FIXME: can we allocate more resources for the HC? */ break; case COMP_BW_ERR: + case COMP_2ND_BW_ERR: dev_warn(&udev->dev, "Not enough bandwidth " "for new device state.\n"); ret = -ENOSPC; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 49ce76c6b41..3e7c3a6c0fb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -900,7 +900,6 @@ struct xhci_transfer_event { /* Invalid Stream ID Error */ #define COMP_STRID_ERR 34 /* Secondary Bandwidth Error - may be returned by a Configure Endpoint cmd */ -/* FIXME - check for this */ #define COMP_2ND_BW_ERR 35 /* Split Transaction Error */ #define COMP_SPLIT_ERR 36 From cca4989bac1a29811a3be91c29a5648375016392 Mon Sep 17 00:00:00 2001 From: VU Tuan Duc Date: Tue, 15 Nov 2011 14:08:00 +0700 Subject: [PATCH 0631/4025] USB: option: add id for 3G dongle Model VT1000 of Viettel commit 5b061623355d8f69327a24838b0aa05e435ae5d5 upstream. Add VendorID/ProductID for USB 3G dongle Model VT1000 of Viettel. Signed-off-by: VU Tuan Duc Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index d2becb9eb60..6dd64534fad 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -472,6 +472,10 @@ static void option_instat_callback(struct urb *urb); #define YUGA_PRODUCT_CLU528 0x260D #define YUGA_PRODUCT_CLU526 0x260F +/* Viettel products */ +#define VIETTEL_VENDOR_ID 0x2262 +#define VIETTEL_PRODUCT_VT1000 0x0002 + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -1173,6 +1177,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU516) }, { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU528) }, { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) }, + { USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); From 9f1efce9d1265de3888ddb4a91cb6d5b14536ff2 Mon Sep 17 00:00:00 2001 From: Janne Snabb Date: Wed, 28 Dec 2011 19:36:00 +0000 Subject: [PATCH 0632/4025] usb: option: add ZD Incorporated HSPA modem commit 3c8c9316710b83e906e425024153bf0929887b59 upstream. Add support for Chinese Noname HSPA USB modem which is apparently manufactured by a company called ZD Incorporated (based on texts in the Windows drivers). This product is available at least from Dealextreme (SKU 80032) and possibly in India with name Olive V-MW250. It is based on Qualcomm MSM6280 chip. I needed to also add "options usb-storage quirks=0685:7000:i" in modprobe configuration because udevd or the kernel keeps poking the embedded fake-cd-rom which fails and causes the device to reset. There might be a better way to accomplish the same. usb_modeswitch is not needed with this device. Signed-off-by: Janne Snabb Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 6dd64534fad..c96b6b6509f 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -476,6 +476,10 @@ static void option_instat_callback(struct urb *urb); #define VIETTEL_VENDOR_ID 0x2262 #define VIETTEL_PRODUCT_VT1000 0x0002 +/* ZD Incorporated */ +#define ZD_VENDOR_ID 0x0685 +#define ZD_PRODUCT_7000 0x7000 + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -1178,6 +1182,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU528) }, { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) }, { USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZD_VENDOR_ID, ZD_PRODUCT_7000, 0xff, 0xff, 0xff) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); From 9f3657ac7841b871c5d2dc8ab51fb08080ae67b1 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 2 Jan 2012 13:35:41 +0200 Subject: [PATCH 0633/4025] usb: ch9: fix up MaxStreams helper commit 18b7ede5f7ee2092aedcb578d3ac30bd5d4fc23c upstream. [ removed the dwc3 portion of the patch as it didn't apply to older kernels - gregkh] According to USB 3.0 Specification Table 9-22, if bmAttributes [4:0] are set to zero, it means "no streams supported", but the way this helper was defined on Linux, we will *always* have one stream which might cause several problems. For example on DWC3, we would tell the controller endpoint has streams enabled and yet start transfers with Stream ID set to 0, which would goof up the host side. While doing that, convert the macro to an inline function due to the different checks we now need. Signed-off-by: Felipe Balbi Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci.c | 3 +-- include/linux/usb/ch9.h | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index b880e546d88..107438eca2b 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -2184,8 +2184,7 @@ static int xhci_calculate_streams_and_bitmask(struct xhci_hcd *xhci, if (ret < 0) return ret; - max_streams = USB_SS_MAX_STREAMS( - eps[i]->ss_ep_comp.bmAttributes); + max_streams = usb_ss_max_streams(&eps[i]->ss_ep_comp); if (max_streams < (*num_streams - 1)) { xhci_dbg(xhci, "Ep 0x%x only supports %u stream IDs.\n", eps[i]->desc.bEndpointAddress, diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index 0fd3fbdd828..cf65b5cff72 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -583,8 +583,26 @@ struct usb_ss_ep_comp_descriptor { } __attribute__ ((packed)); #define USB_DT_SS_EP_COMP_SIZE 6 + /* Bits 4:0 of bmAttributes if this is a bulk endpoint */ -#define USB_SS_MAX_STREAMS(p) (1 << ((p) & 0x1f)) +static inline int +usb_ss_max_streams(const struct usb_ss_ep_comp_descriptor *comp) +{ + int max_streams; + + if (!comp) + return 0; + + max_streams = comp->bmAttributes & 0x1f; + + if (!max_streams) + return 0; + + max_streams = 1 << max_streams; + + return max_streams; +} + /* Bits 1:0 of bmAttributes if this is an isoc endpoint */ #define USB_SS_MULT(p) (1 + ((p) & 0x3)) From 06752b6cc142845a2c21196fa86a0cba7d72d325 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Thu, 17 Nov 2011 16:41:45 -0500 Subject: [PATCH 0634/4025] OHCI: final fix for NVIDIA problems (I hope) commit c61875977458637226ab093a35d200f2d5789787 upstream. Problems with NVIDIA's OHCI host controllers persist. After looking carefully through the spec, I finally realized that when a controller is reset it then automatically goes into a SUSPEND state in which it is completely quiescent (no DMA and no IRQs) and from which it will not awaken until the system puts it into the OPERATIONAL state. Therefore there's no need to worry about controllers being in the RESET state for extended periods, or remaining in the OPERATIONAL state during system shutdown. The proper action for device initialization is to put the controller into the RESET state (if it's not there already) and then to issue a software reset. Similarly, the proper action for device shutdown is simply to do a software reset. This patch (as1499) implements such an approach. It simplifies initialization and shutdown, and allows the NVIDIA shutdown-quirk code to be removed. Signed-off-by: Alan Stern Tested-by: Andre "Osku" Schmidt Tested-by: Arno Augustin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 15 +++++------ drivers/usb/host/ohci-pci.c | 26 ------------------ drivers/usb/host/ohci.h | 1 - drivers/usb/host/pci-quirks.c | 50 +++++++++++++++-------------------- 4 files changed, 28 insertions(+), 64 deletions(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index f9cf3f04b74..23107e23053 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -389,17 +389,14 @@ ohci_shutdown (struct usb_hcd *hcd) struct ohci_hcd *ohci; ohci = hcd_to_ohci (hcd); - ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); + ohci_writel(ohci, (u32) ~0, &ohci->regs->intrdisable); - /* If the SHUTDOWN quirk is set, don't put the controller in RESET */ - ohci->hc_control &= (ohci->flags & OHCI_QUIRK_SHUTDOWN ? - OHCI_CTRL_RWC | OHCI_CTRL_HCFS : - OHCI_CTRL_RWC); - ohci_writel(ohci, ohci->hc_control, &ohci->regs->control); + /* Software reset, after which the controller goes into SUSPEND */ + ohci_writel(ohci, OHCI_HCR, &ohci->regs->cmdstatus); + ohci_readl(ohci, &ohci->regs->cmdstatus); /* flush the writes */ + udelay(10); - /* flush the writes */ - (void) ohci_readl (ohci, &ohci->regs->control); + ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval); } static int check_ed(struct ohci_hcd *ohci, struct ed *ed) diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index ad8166c681e..bc01b064585 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -175,28 +175,6 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd) return 0; } -/* nVidia controllers continue to drive Reset signalling on the bus - * even after system shutdown, wasting power. This flag tells the - * shutdown routine to leave the controller OPERATIONAL instead of RESET. - */ -static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd) -{ - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - /* Evidently nVidia fixed their later hardware; this is a guess at - * the changeover point. - */ -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB 0x026d - - if (pdev->device < PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB) { - ohci->flags |= OHCI_QUIRK_SHUTDOWN; - ohci_dbg(ohci, "enabled nVidia shutdown quirk\n"); - } - - return 0; -} - static void sb800_prefetch(struct ohci_hcd *ohci, int on) { struct pci_dev *pdev; @@ -260,10 +238,6 @@ static const struct pci_device_id ohci_pci_quirks[] = { PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399), .driver_data = (unsigned long)ohci_quirk_amd700, }, - { - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), - .driver_data = (unsigned long) ohci_quirk_nvidia_shutdown, - }, /* FIXME for some of the early AMD 760 southbridges, OHCI * won't work at all. blacklist them. diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 35e5fd640ce..0795b934d00 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -403,7 +403,6 @@ struct ohci_hcd { #define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */ #define OHCI_QUIRK_AMD_PLL 0x200 /* AMD PLL quirk*/ #define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */ -#define OHCI_QUIRK_SHUTDOWN 0x800 /* nVidia power bug */ // there are also chip quirks/bugs in init logic struct work_struct nec_work; /* Worker for NEC quirk */ diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index a495d489918..23e04fb038b 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -36,6 +36,7 @@ #define OHCI_INTRENABLE 0x10 #define OHCI_INTRDISABLE 0x14 #define OHCI_FMINTERVAL 0x34 +#define OHCI_HCFS (3 << 6) /* hc functional state */ #define OHCI_HCR (1 << 0) /* host controller reset */ #define OHCI_OCR (1 << 3) /* ownership change request */ #define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ @@ -465,6 +466,8 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) { void __iomem *base; u32 control; + u32 fminterval; + int cnt; if (!mmio_resource_enabled(pdev, 0)) return; @@ -497,41 +500,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) } #endif - /* reset controller, preserving RWC (and possibly IR) */ - writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); - readl(base + OHCI_CONTROL); + /* disable interrupts */ + writel((u32) ~0, base + OHCI_INTRDISABLE); - /* Some NVIDIA controllers stop working if kept in RESET for too long */ - if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { - u32 fminterval; - int cnt; + /* Reset the USB bus, if the controller isn't already in RESET */ + if (control & OHCI_HCFS) { + /* Go into RESET, preserving RWC (and possibly IR) */ + writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); + readl(base + OHCI_CONTROL); - /* drive reset for at least 50 ms (7.1.7.5) */ + /* drive bus reset for at least 50 ms (7.1.7.5) */ msleep(50); + } - /* software reset of the controller, preserving HcFmInterval */ - fminterval = readl(base + OHCI_FMINTERVAL); - writel(OHCI_HCR, base + OHCI_CMDSTATUS); + /* software reset of the controller, preserving HcFmInterval */ + fminterval = readl(base + OHCI_FMINTERVAL); + writel(OHCI_HCR, base + OHCI_CMDSTATUS); - /* reset requires max 10 us delay */ - for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ - if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) - break; - udelay(1); - } - writel(fminterval, base + OHCI_FMINTERVAL); - - /* Now we're in the SUSPEND state with all devices reset - * and wakeups and interrupts disabled - */ + /* reset requires max 10 us delay */ + for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ + if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) + break; + udelay(1); } + writel(fminterval, base + OHCI_FMINTERVAL); - /* - * disable interrupts - */ - writel(~(u32)0, base + OHCI_INTRDISABLE); - writel(~(u32)0, base + OHCI_INTRSTATUS); - + /* Now the controller is safely in SUSPEND and nothing can wake it up */ iounmap(base); } From 49ffa26eca87d3518ed88d3e6feebf1b80837a15 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 9 Jan 2012 14:06:46 -0800 Subject: [PATCH 0635/4025] igmp: Avoid zero delay when receiving odd mixture of IGMP queries commit a8c1f65c79cbbb2f7da782d4c9d15639a9b94b27 upstream. Commit 5b7c84066733c5dfb0e4016d939757b38de189e4 ('ipv4: correct IGMP behavior on v3 query during v2-compatibility mode') added yet another case for query parsing, which can result in max_delay = 0. Substitute a value of 1, as in the usual v3 case. Reported-by: Simon McVittie References: http://bugs.debian.org/654876 Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller --- net/ipv4/igmp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index d577199eabd..e0d42dbb33f 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -875,6 +875,8 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, * to be intended in a v3 query. */ max_delay = IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE); + if (!max_delay) + max_delay = 1; /* can't mod w/ 0 */ } else { /* v3 */ if (!pskb_may_pull(skb, sizeof(struct igmpv3_query))) return; From 2643bcef53a08c09975861ebbed6d687571a2751 Mon Sep 17 00:00:00 2001 From: Aurelien Jacobs Date: Sat, 7 Jan 2012 12:15:16 -0800 Subject: [PATCH 0636/4025] asix: fix infinite loop in rx_fixup() commit 6c15d74defd38e7e7f8805392578b7a1d508097e upstream. At this point if skb->len happens to be 2, the subsequant skb_pull(skb, 4) call won't work and the skb->len won't be decreased and won't ever reach 0, resulting in an infinite loop. With an ASIX 88772 under heavy load, without this patch, rx_fixup() reaches an infinite loop in less than a minute. With this patch applied, no infinite loop even after hours of heavy load. Signed-off-by: Aurelien Jacobs Cc: Jussi Kivilinna Signed-off-by: David S. Miller --- drivers/net/usb/asix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index c50632e8658..71055770009 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -371,7 +371,7 @@ static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb) skb_pull(skb, (size + 1) & 0xfffe); - if (skb->len == 0) + if (skb->len < sizeof(header)) break; head = (u8 *) skb->data; From 81aaa36dde03db855fb233382c7667f98ac12659 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Sat, 31 Dec 2011 13:26:46 +0000 Subject: [PATCH 0637/4025] bonding: fix error handling if slave is busy (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f7d9821a6a9c83450ac35e76d3709e32fd38b76f upstream. If slave device already has a receive handler registered, then the error unwind of bonding device enslave function is broken. The following will leave a pointer to freed memory in the slave device list, causing a later kernel panic. # modprobe dummy # ip li add dummy0-1 link dummy0 type macvlan # modprobe bonding # echo +dummy0 >/sys/class/net/bond0/bonding/slaves The fix is to detach the slave (which removes it from the list) in the unwind path. Signed-off-by: Stephen Hemminger Reviewed-by: Nicolas de Pesloüan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2065cb4002b..0b65c5fccc3 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1905,7 +1905,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) "but new slave device does not support netpoll.\n", bond_dev->name); res = -EBUSY; - goto err_close; + goto err_detach; } } #endif @@ -1914,7 +1914,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) res = bond_create_slave_symlinks(bond_dev, slave_dev); if (res) - goto err_close; + goto err_detach; res = netdev_rx_handler_register(slave_dev, bond_handle_frame, new_slave); @@ -1935,6 +1935,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) err_dest_symlinks: bond_destroy_slave_symlinks(bond_dev, slave_dev); +err_detach: + write_lock_bh(&bond->lock); + bond_detach_slave(bond, new_slave); + write_unlock_bh(&bond->lock); + err_close: dev_close(slave_dev); From 4ae84455f98af3b3c3a23f8b6458fcefc9ff62bf Mon Sep 17 00:00:00 2001 From: "Srivatsa S. Bhat" Date: Thu, 3 Nov 2011 00:59:25 +0100 Subject: [PATCH 0638/4025] PM / Sleep: Fix race between CPU hotplug and freezer commit 79cfbdfa87e84992d509e6c1648a18e1d7e68c20 upstream. The CPU hotplug notifications sent out by the _cpu_up() and _cpu_down() functions depend on the value of the 'tasks_frozen' argument passed to them (which indicates whether tasks have been frozen or not). (Examples for such CPU hotplug notifications: CPU_ONLINE, CPU_ONLINE_FROZEN, CPU_DEAD, CPU_DEAD_FROZEN). Thus, it is essential that while the callbacks for those notifications are running, the state of the system with respect to the tasks being frozen or not remains unchanged, *throughout that duration*. Hence there is a need for synchronizing the CPU hotplug code with the freezer subsystem. Since the freezer is involved only in the Suspend/Hibernate call paths, this patch hooks the CPU hotplug code to the suspend/hibernate notifiers PM_[SUSPEND|HIBERNATE]_PREPARE and PM_POST_[SUSPEND|HIBERNATE] to prevent the race between CPU hotplug and freezer, thus ensuring that CPU hotplug notifications will always be run with the state of the system really being what the notifications indicate, _throughout_ their execution time. Signed-off-by: Srivatsa S. Bhat Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- kernel/cpu.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/kernel/cpu.c b/kernel/cpu.c index 12b7458f23b..aa39dd7a384 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef CONFIG_SMP /* Serializes the updates to cpu_online_mask, cpu_present_mask */ @@ -476,6 +477,79 @@ static int alloc_frozen_cpus(void) return 0; } core_initcall(alloc_frozen_cpus); + +/* + * Prevent regular CPU hotplug from racing with the freezer, by disabling CPU + * hotplug when tasks are about to be frozen. Also, don't allow the freezer + * to continue until any currently running CPU hotplug operation gets + * completed. + * To modify the 'cpu_hotplug_disabled' flag, we need to acquire the + * 'cpu_add_remove_lock'. And this same lock is also taken by the regular + * CPU hotplug path and released only after it is complete. Thus, we + * (and hence the freezer) will block here until any currently running CPU + * hotplug operation gets completed. + */ +void cpu_hotplug_disable_before_freeze(void) +{ + cpu_maps_update_begin(); + cpu_hotplug_disabled = 1; + cpu_maps_update_done(); +} + + +/* + * When tasks have been thawed, re-enable regular CPU hotplug (which had been + * disabled while beginning to freeze tasks). + */ +void cpu_hotplug_enable_after_thaw(void) +{ + cpu_maps_update_begin(); + cpu_hotplug_disabled = 0; + cpu_maps_update_done(); +} + +/* + * When callbacks for CPU hotplug notifications are being executed, we must + * ensure that the state of the system with respect to the tasks being frozen + * or not, as reported by the notification, remains unchanged *throughout the + * duration* of the execution of the callbacks. + * Hence we need to prevent the freezer from racing with regular CPU hotplug. + * + * This synchronization is implemented by mutually excluding regular CPU + * hotplug and Suspend/Hibernate call paths by hooking onto the Suspend/ + * Hibernate notifications. + */ +static int +cpu_hotplug_pm_callback(struct notifier_block *nb, + unsigned long action, void *ptr) +{ + switch (action) { + + case PM_SUSPEND_PREPARE: + case PM_HIBERNATION_PREPARE: + cpu_hotplug_disable_before_freeze(); + break; + + case PM_POST_SUSPEND: + case PM_POST_HIBERNATION: + cpu_hotplug_enable_after_thaw(); + break; + + default: + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + + +int cpu_hotplug_pm_sync_init(void) +{ + pm_notifier(cpu_hotplug_pm_callback, 0); + return 0; +} +core_initcall(cpu_hotplug_pm_sync_init); + #endif /* CONFIG_PM_SLEEP_SMP */ /** From 18366c3fed0c372f9c123489e7061de11b640965 Mon Sep 17 00:00:00 2001 From: "kashyap.desai@lsi.com" Date: Thu, 4 Aug 2011 16:47:50 +0530 Subject: [PATCH 0639/4025] SCSI: mpt2sas: Added missing mpt2sas_base_detach call from scsih_remove context commit 9ae89b0296e275d5a556068b40b7c2557a556a85 upstream. mpt2sas_base_detach() call was removed from _scsih_remove() while doing some code shuffling. Mainly when we work on adding code for scsih_shutdown(). I have added back mpt2sas_base_detach() which will get callled from _scsih_remove(). Signed-off-by: Kashyap Desai Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index f88e52a1a39..c79857e439f 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -7211,6 +7211,7 @@ _scsih_remove(struct pci_dev *pdev) } sas_remove_host(shost); + mpt2sas_base_detach(ioc); list_del(&ioc->list); scsi_remove_host(shost); scsi_host_put(shost); From 68f760945cb704f4a9d0ae7c4abc9e41ca30aa91 Mon Sep 17 00:00:00 2001 From: Thilo-Alexander Ginkel Date: Sat, 17 Dec 2011 10:55:10 +0100 Subject: [PATCH 0640/4025] usb: cdc-acm: Fix acm_tty_hangup() vs. acm_tty_close() race [Not upstream as it was fixed differently for 3.3 with a much more "intrusive" rework of the driver - gregkh] There is a race condition involving acm_tty_hangup() and acm_tty_close() where hangup() would attempt to access tty->driver_data without proper locking and NULL checking after close() has potentially already set it to NULL. One possibility to (sporadically) trigger this behavior is to perform a suspend/resume cycle with a running WWAN data connection. This patch addresses the issue by introducing a NULL check for tty->driver_data in acm_tty_hangup() protected by open_mutex and exiting gracefully when hangup() is invoked on a device that has already been closed. Signed-off-by: Thilo-Alexander Ginkel Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index b632d4b5354..158f6312143 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -554,10 +554,18 @@ static void acm_port_down(struct acm *acm) static void acm_tty_hangup(struct tty_struct *tty) { - struct acm *acm = tty->driver_data; - tty_port_hangup(&acm->port); + struct acm *acm; + mutex_lock(&open_mutex); + acm = tty->driver_data; + + if (!acm) + goto out; + + tty_port_hangup(&acm->port); acm_port_down(acm); + +out: mutex_unlock(&open_mutex); } From 6e474bc4d5c0d94c070a18901e00ff33de0c1be1 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Mon, 12 Dec 2011 21:55:52 +0000 Subject: [PATCH 0641/4025] xfs: fix acl count validation in xfs_acl_from_disk() commit 093019cf1b18dd31b2c3b77acce4e000e2cbc9ce upstream. Commit fa8b18ed didn't prevent the integer overflow and possible memory corruption. "count" can go negative and bypass the check. Signed-off-by: Xi Wang Reviewed-by: Christoph Hellwig Signed-off-by: Ben Myers Signed-off-by: Greg Kroah-Hartman --- fs/xfs/linux-2.6/xfs_acl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/linux-2.6/xfs_acl.c b/fs/xfs/linux-2.6/xfs_acl.c index 4b9fb915d44..f86e0348786 100644 --- a/fs/xfs/linux-2.6/xfs_acl.c +++ b/fs/xfs/linux-2.6/xfs_acl.c @@ -39,7 +39,7 @@ xfs_acl_from_disk(struct xfs_acl *aclp) struct posix_acl_entry *acl_e; struct posix_acl *acl; struct xfs_acl_entry *ace; - int count, i; + unsigned int count, i; count = be32_to_cpu(aclp->acl_cnt); if (count > XFS_ACL_MAX_ENTRIES) From e9d23be2708477feeaec78e707c80441520c1ef6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 12 Jan 2012 11:54:29 -0800 Subject: [PATCH 0642/4025] Linux 3.0.17 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7f0d8e27bf3..295fbda0036 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 16 +SUBLEVEL = 17 EXTRAVERSION = NAME = Sneaky Weasel From a65e28a0149261776678977962cfa0f90973e1d4 Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Thu, 12 Jan 2012 15:55:25 -0800 Subject: [PATCH 0643/4025] ram_console: set CON_ANYTIME console flag We want to ensure that we get all the console messages, even ones that occur while the printing CPU is not yet online. Change-Id: I1d2694d05ac9415669a92f38efdd8e71c927705b Signed-off-by: Dima Zavin --- drivers/staging/android/ram_console.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c index cb42d899822..b278d62e4b8 100644 --- a/drivers/staging/android/ram_console.c +++ b/drivers/staging/android/ram_console.c @@ -143,7 +143,7 @@ ram_console_write(struct console *console, const char *s, unsigned int count) static struct console ram_console = { .name = "ram", .write = ram_console_write, - .flags = CON_PRINTBUFFER | CON_ENABLED, + .flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME, .index = -1, }; From 9e98b9dcd04a8d5ce0f77d32eedca133101d191e Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Fri, 13 Jan 2012 21:49:21 -0800 Subject: [PATCH 0644/4025] video: s3c fimd: Adjust pixclock to match hw settings * The pixclock used to report refresh rates to userspace did not reflect the actual frequency that the hardware was programmed with due to rounding. Now we recalculate the pixclock based on what is programmed in the VIDCON0 register. * The div bits in the control register where not being cleared before the new value was OR-ed in. Change-Id: Ic417b67a3324d94727ed82170d31015967bb1ce1 Signed-off-by: JP Abgrall --- drivers/video/samsung/s3cfb_fimd6x.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/video/samsung/s3cfb_fimd6x.c b/drivers/video/samsung/s3cfb_fimd6x.c index 360f1f6b4a8..b5b73a1b6b3 100644 --- a/drivers/video/samsung/s3cfb_fimd6x.c +++ b/drivers/video/samsung/s3cfb_fimd6x.c @@ -152,6 +152,19 @@ int s3cfb_frame_off(struct s3cfb_global *ctrl) return 0; } +void s3cfb_readjust_pixclock(struct s3cfb_global *ctrl, u32 src_clk, u32 div) +{ + struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev); + int i; + u32 pixclock; + + pixclock = KHZ2PICOS(src_clk / 1000) * div; + dev_info(ctrl->dev, "pixclock adjusted from %d to %d\n", + ctrl->fb[0]->var.pixclock, pixclock); + for (i = 0; i < pdata->nr_wins; i++) + ctrl->fb[i]->var.pixclock = pixclock; +} + int s3cfb_set_clock(struct s3cfb_global *ctrl) { struct s3c_platform_fb *pdata = to_fb_plat(ctrl->dev); @@ -162,7 +175,8 @@ int s3cfb_set_clock(struct s3cfb_global *ctrl) /* fixed clock source: hclk */ cfg = readl(ctrl->regs + S3C_VIDCON0); cfg &= ~(S3C_VIDCON0_CLKSEL_MASK | S3C_VIDCON0_CLKVALUP_MASK | - S3C_VIDCON0_VCLKEN_MASK | S3C_VIDCON0_CLKDIR_MASK); + S3C_VIDCON0_VCLKEN_MASK | S3C_VIDCON0_CLKDIR_MASK | + S3C_VIDCON0_CLKVAL_F(-1)); cfg |= (S3C_VIDCON0_CLKVALUP_ALWAYS | S3C_VIDCON0_VCLKEN_NORMAL | S3C_VIDCON0_CLKDIR_DIVIDED); @@ -199,6 +213,7 @@ int s3cfb_set_clock(struct s3cfb_global *ctrl) dev_dbg(ctrl->dev, "parent clock: %d, vclk: %d, vclk div: %d\n", src_clk, vclk, div); + s3cfb_readjust_pixclock(ctrl, src_clk, div); return 0; } From 352ba9d4699925f93706bbcaad07c044176c2a22 Mon Sep 17 00:00:00 2001 From: Simon Wilson Date: Tue, 10 Jan 2012 10:51:25 -0800 Subject: [PATCH 0645/4025] misc: fsa9480: make interrupt handling more robust - fsa9480 interrupt is actually triggered low, not falling - process any queued events and only handle the last Change-Id: Id7b99068b226346a609454f41d75f10a86259898 Signed-off-by: Simon Wilson --- drivers/misc/fsa9480.c | 43 ++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c index ca6b8e20344..8098f8263a8 100755 --- a/drivers/misc/fsa9480.c +++ b/drivers/misc/fsa9480.c @@ -30,6 +30,7 @@ #include #include #include +#include /* FSA9480 I2C registers */ #define FSA9480_REG_DEVID 0x01 @@ -397,18 +398,40 @@ static irqreturn_t fsa9480_irq_thread(int irq, void *data) struct fsa9480_usbsw *usbsw = data; struct i2c_client *client = usbsw->client; int intr; - - /* read and clear interrupt status bits */ - intr = i2c_smbus_read_word_data(client, FSA9480_REG_INT1); - if (intr < 0) { - dev_err(&client->dev, "%s: err %d\n", __func__, intr); - } else if (intr == 0) { - /* interrupt was fired, but no status bits were set, - so device was reset. In this case, the registers were - reset to defaults so they need to be reinitialised. */ + int max_events = 100; + int events_seen = 0; + + /* + * the fsa could have queued up a few events if we haven't processed + * them promptly + */ + while (max_events-- > 0) { + intr = i2c_smbus_read_word_data(client, FSA9480_REG_INT1); + if (intr < 0) + dev_err(&client->dev, "%s: err %d\n", __func__, intr); + else if (intr == 0) + break; + else if (intr > 0) + events_seen++; + } + if (!max_events) + dev_warn(&client->dev, "too many events. fsa hosed?\n"); + + if (!events_seen) { + /* + * interrupt was fired, but no status bits were set, + * so device was reset. In this case, the registers were + * reset to defaults so they need to be reinitialised. + */ fsa9480_reg_init(usbsw); } + /* + * fsa may take some time to update the dev_type reg after reading + * the int reg. + */ + usleep_range(200, 300); + /* device detection */ fsa9480_detect_dev(usbsw); @@ -422,7 +445,7 @@ static int fsa9480_irq_init(struct fsa9480_usbsw *usbsw) if (client->irq) { ret = request_threaded_irq(client->irq, NULL, - fsa9480_irq_thread, IRQF_TRIGGER_FALLING, + fsa9480_irq_thread, IRQF_TRIGGER_LOW | IRQF_ONESHOT, "fsa9480 micro USB", usbsw); if (ret) { dev_err(&client->dev, "failed to reqeust IRQ\n"); From 92935b6665f6606ea25571776f47f20a9a53229d Mon Sep 17 00:00:00 2001 From: "Kocharlakota.sridhar" Date: Tue, 20 Dec 2011 17:30:43 +0900 Subject: [PATCH 0646/4025] misc: samsung_modemctl: Add multipdp support UMTS models support 3 PDP sessions at same time. Modified the driver to support multipdp sessions. Change-Id: I739fa751290288885b163dd76f3879ab8639b683 Signed-off-by: Kocharlakota.sridhar --- drivers/misc/samsung_modemctl/modem_ctl.c | 4 + drivers/misc/samsung_modemctl/modem_ctl.h | 1 + drivers/misc/samsung_modemctl/modem_ctl_p.h | 3 +- drivers/misc/samsung_modemctl/modem_io.c | 90 +++++++++++++++------ 4 files changed, 71 insertions(+), 27 deletions(-) diff --git a/drivers/misc/samsung_modemctl/modem_ctl.c b/drivers/misc/samsung_modemctl/modem_ctl.c index e7504fd8469..f99f17c0b72 100755 --- a/drivers/misc/samsung_modemctl/modem_ctl.c +++ b/drivers/misc/samsung_modemctl/modem_ctl.c @@ -1092,6 +1092,10 @@ static int __devinit modemctl_probe(struct platform_device *pdev) mc->gpio_cp_reset = pdata->gpio_cp_reset; mc->gpio_phone_on = pdata->gpio_phone_on; mc->is_cdma_modem = pdata->is_cdma_modem; + if (pdata->num_pdp_contexts) + mc->num_pdp_contexts = pdata->num_pdp_contexts; + else + mc->num_pdp_contexts = 1; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) diff --git a/drivers/misc/samsung_modemctl/modem_ctl.h b/drivers/misc/samsung_modemctl/modem_ctl.h index 7c23165e776..b4ad920f1fe 100644 --- a/drivers/misc/samsung_modemctl/modem_ctl.h +++ b/drivers/misc/samsung_modemctl/modem_ctl.h @@ -39,6 +39,7 @@ struct modemctl_data { unsigned gpio_cp_reset; unsigned gpio_phone_on; bool is_cdma_modem; /* 1:CDMA Modem */ + int num_pdp_contexts; }; #endif diff --git a/drivers/misc/samsung_modemctl/modem_ctl_p.h b/drivers/misc/samsung_modemctl/modem_ctl_p.h index 3de2231550f..6223b2080ce 100644 --- a/drivers/misc/samsung_modemctl/modem_ctl_p.h +++ b/drivers/misc/samsung_modemctl/modem_ctl_p.h @@ -121,7 +121,7 @@ struct modemctl { struct wake_lock ip_tx_wakelock; struct wake_lock ip_rx_wakelock; - struct net_device *ndev; + struct net_device **ndev; int open_count; int status; @@ -137,6 +137,7 @@ struct modemctl { unsigned gpio_cp_reset; unsigned gpio_phone_on; bool is_cdma_modem; + int num_pdp_contexts; bool is_modem_delta_update; unsigned dpram_prev_phone_active; unsigned dpram_prev_status; diff --git a/drivers/misc/samsung_modemctl/modem_io.c b/drivers/misc/samsung_modemctl/modem_io.c index fe50da60dff..5c815efa10c 100644 --- a/drivers/misc/samsung_modemctl/modem_io.c +++ b/drivers/misc/samsung_modemctl/modem_io.c @@ -40,7 +40,8 @@ #include "modem_ctl_p.h" #define RAW_CH_VNET0 10 - +#define CHANNEL_TO_NETDEV_ID(id) (id - RAW_CH_VNET0) +#define NETDEV_TO_CHANNEL_ID(id) (id + RAW_CH_VNET0) /* general purpose fifo access routines */ @@ -309,6 +310,7 @@ struct raw_hdr { struct vnet { struct modemctl *mc; struct sk_buff_head txq; + int rmnet_ch_id; }; static void handle_raw_rx(struct modemctl *mc) @@ -319,17 +321,19 @@ static void handle_raw_rx(struct modemctl *mc) /* process inbound packets */ while (fifo_read(&mc->raw_rx, &raw, sizeof(raw)) == sizeof(raw)) { - struct net_device *dev = mc->ndev; + struct net_device *dev; unsigned sz = raw.len - (sizeof(raw) - 1); - if (unlikely(raw.channel != RAW_CH_VNET0)) { + if (unlikely(!(raw.channel >= RAW_CH_VNET0 && raw.channel < + NETDEV_TO_CHANNEL_ID(mc->num_pdp_contexts)))) { + MODEM_COUNT(mc, rx_unknown); pr_err("[VNET] unknown channel %d\n", raw.channel); if (fifo_skip(&mc->raw_rx, sz + 1) != (sz + 1)) goto purge_raw_fifo; continue; } - + dev = mc->ndev[CHANNEL_TO_NETDEV_ID(raw.channel)]; skb = dev_alloc_skb(sz + NET_IP_ALIGN); if (skb == NULL) { MODEM_COUNT(mc, rx_dropped); @@ -379,6 +383,9 @@ int handle_raw_tx(struct modemctl *mc, struct sk_buff *skb) struct raw_hdr raw; unsigned char ftr = 0x7e; unsigned sz; + int netdev_id; + struct vnet *vn = netdev_priv(skb->dev); + sz = skb->len + sizeof(raw) + 1; @@ -389,15 +396,16 @@ int handle_raw_tx(struct modemctl *mc, struct sk_buff *skb) raw.start = 0x7f; raw.len = 6 + skb->len; - raw.channel = RAW_CH_VNET0; + raw.channel = vn->rmnet_ch_id; raw.control = 0; fifo_write(&mc->raw_tx, &raw, sizeof(raw)); fifo_write(&mc->raw_tx, skb->data, skb->len); fifo_write(&mc->raw_tx, &ftr, 1); - mc->ndev->stats.tx_packets++; - mc->ndev->stats.tx_bytes += skb->len; + netdev_id = CHANNEL_TO_NETDEV_ID(vn->rmnet_ch_id); + mc->ndev[netdev_id]->stats.tx_packets++; + mc->ndev[netdev_id]->stats.tx_bytes += skb->len; mc->mmio_signal_bits |= MBD_SEND_RAW; @@ -408,17 +416,24 @@ int handle_raw_tx(struct modemctl *mc, struct sk_buff *skb) void modem_handle_io(struct modemctl *mc) { struct sk_buff *skb; - struct vnet *vn = netdev_priv(mc->ndev); + struct vnet *vn; + int i; + int cnt = 0; handle_raw_rx(mc); - while ((skb = skb_dequeue(&vn->txq))) - if (handle_raw_tx(mc, skb)) { - skb_queue_head(&vn->txq, skb); - break; - } - if (skb == NULL) - wake_unlock(&vn->mc->ip_tx_wakelock); + for (i = 0; i < mc->num_pdp_contexts; i++) { + vn = netdev_priv(mc->ndev[i]); + while ((skb = skb_dequeue(&vn->txq))) + if (handle_raw_tx(mc, skb)) { + skb_queue_head(&vn->txq, skb); + break; + } + if (skb == NULL) + cnt++; + } + if (cnt == mc->num_pdp_contexts) + wake_unlock(&mc->ip_tx_wakelock); } static int vnet_open(struct net_device *ndev) @@ -639,9 +654,10 @@ static int modem_pipe_register(struct m_pipe *pipe, const char *devname) int modem_io_init(struct modemctl *mc, void __iomem *mmio) { - struct net_device *ndev; struct vnet *vn; int r; + int i; + int ch_id; INIT_M_FIFO(mc->fmt_tx, FMT, TX, mmio); INIT_M_FIFO(mc->fmt_rx, FMT, RX, mmio); @@ -650,16 +666,30 @@ int modem_io_init(struct modemctl *mc, void __iomem *mmio) INIT_M_FIFO(mc->rfs_tx, RFS, TX, mmio); INIT_M_FIFO(mc->rfs_rx, RFS, RX, mmio); - ndev = alloc_netdev(0, "rmnet%d", vnet_setup); - if (ndev) { - vn = netdev_priv(ndev); - vn->mc = mc; - skb_queue_head_init(&vn->txq); - r = register_netdev(ndev); - if (r) - free_netdev(ndev); - else - mc->ndev = ndev; + mc->ndev = kmalloc(sizeof(struct net_device *) * mc->num_pdp_contexts, + GFP_KERNEL); + if (!mc->ndev) { + pr_err("memory allocation failed for netdev\n"); + return -ENOMEM; + } + for (i = 0, ch_id = RAW_CH_VNET0; i < mc->num_pdp_contexts; + i++, ch_id++) { + mc->ndev[i] = alloc_netdev(0, "rmnet%d", vnet_setup); + if (mc->ndev[i]) { + vn = netdev_priv(mc->ndev[i]); + vn->mc = mc; + vn->rmnet_ch_id = ch_id; + skb_queue_head_init(&vn->txq); + r = register_netdev(mc->ndev[i]); + if (r) { + free_netdev(mc->ndev[i]); + pr_err("failed to register rmnet%d\n", i); + goto free; + } + } else { + pr_err("failed to alloc rmnet%d\n", i); + goto free; + } } mc->cmd_pipe.tx = &mc->fmt_tx; @@ -683,4 +713,12 @@ int modem_io_init(struct modemctl *mc, void __iomem *mmio) pr_err("failed to register modem_rfs pipe\n"); return 0; + +free: + /* Unregister and free any alloced netdevs */ + while (--i >= 0) { + unregister_netdev(mc->ndev[i]); + free_netdev(mc->ndev[i]); + } + return -ENOMEM; } From 175bc21bc3afb6962613414c6c9bd33b895954af Mon Sep 17 00:00:00 2001 From: Simon Wilson Date: Wed, 18 Jan 2012 13:07:13 -0800 Subject: [PATCH 0647/4025] arm: herring: allow multiple pdp contexts for non-wimax devices Change-Id: Ib7fc84c64ba3cf1bad4662175683a8ac8c0a99ea Signed-off-by: Simon Wilson --- arch/arm/mach-s5pv210/dev-herring-phone.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-s5pv210/dev-herring-phone.c b/arch/arm/mach-s5pv210/dev-herring-phone.c index f8798b3dd51..b605e02b320 100755 --- a/arch/arm/mach-s5pv210/dev-herring-phone.c +++ b/arch/arm/mach-s5pv210/dev-herring-phone.c @@ -31,6 +31,7 @@ static struct modemctl_data mdmctl_data = { .gpio_cp_reset = GPIO_CP_RST, .gpio_phone_on = GPIO_PHONE_ON, .is_cdma_modem = 0, + .num_pdp_contexts = 3, }; static struct resource mdmctl_res[] = { @@ -67,8 +68,10 @@ static struct platform_device modemctl = { static int __init herring_init_phone_interface(void) { /* CDMA device */ - if (herring_is_cdma_wimax_dev()) + if (herring_is_cdma_wimax_dev()) { mdmctl_data.is_cdma_modem = 1; + mdmctl_data.num_pdp_contexts = 1; + } platform_device_register(&modemctl); return 0; From c96f99d7907853ffb7e29915954dfc38b912fa2c Mon Sep 17 00:00:00 2001 From: Ken Sumrall Date: Wed, 18 Jan 2012 14:56:06 -0800 Subject: [PATCH 0648/4025] Revert "mmc: Set suspend/resume bus operations if CONFIG_PM_RUNTIME is used" This reverts commit ea693bf7f87603b072f4ceea6684221fa0b8e863. We are reverting this change to see if it clears up some filesystem corruption we are seeing. --- drivers/mmc/core/bus.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index e07d6c90cae..393d817ed04 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -120,19 +120,18 @@ static int mmc_bus_remove(struct device *dev) return 0; } -static int mmc_bus_pm_suspend(struct device *dev) +static int mmc_bus_suspend(struct device *dev, pm_message_t state) { struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); int ret = 0; - pm_message_t state = { PM_EVENT_SUSPEND }; if (dev->driver && drv->suspend) ret = drv->suspend(card, state); return ret; } -static int mmc_bus_pm_resume(struct device *dev) +static int mmc_bus_resume(struct device *dev) { struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); @@ -144,6 +143,7 @@ static int mmc_bus_pm_resume(struct device *dev) } #ifdef CONFIG_PM_RUNTIME + static int mmc_runtime_suspend(struct device *dev) { struct mmc_card *card = mmc_dev_to_card(dev); @@ -162,13 +162,21 @@ static int mmc_runtime_idle(struct device *dev) { return pm_runtime_suspend(dev); } -#endif /* CONFIG_PM_RUNTIME */ static const struct dev_pm_ops mmc_bus_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_pm_suspend, mmc_bus_pm_resume) - SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, mmc_runtime_idle) + .runtime_suspend = mmc_runtime_suspend, + .runtime_resume = mmc_runtime_resume, + .runtime_idle = mmc_runtime_idle, }; +#define MMC_PM_OPS_PTR (&mmc_bus_pm_ops) + +#else /* !CONFIG_PM_RUNTIME */ + +#define MMC_PM_OPS_PTR NULL + +#endif /* !CONFIG_PM_RUNTIME */ + static struct bus_type mmc_bus_type = { .name = "mmc", .dev_attrs = mmc_dev_attrs, @@ -176,7 +184,9 @@ static struct bus_type mmc_bus_type = { .uevent = mmc_bus_uevent, .probe = mmc_bus_probe, .remove = mmc_bus_remove, - .pm = &mmc_bus_pm_ops, + .suspend = mmc_bus_suspend, + .resume = mmc_bus_resume, + .pm = MMC_PM_OPS_PTR, }; int mmc_register_bus(void) From dac306d896642f3dfcd878ab6a0a5b8c123722f3 Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Thu, 19 Jan 2012 09:51:07 -0800 Subject: [PATCH 0649/4025] Revert "proc: enable writing to /proc/pid/mem" This reverts commit 198214a7ee50375fa71a65e518341980cfd4b2f0. --- fs/proc/base.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/proc/base.c b/fs/proc/base.c index efb304854b7..1a8d756021f 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -891,6 +891,10 @@ static ssize_t mem_read(struct file * file, char __user * buf, return ret; } +#define mem_write NULL + +#ifndef mem_write +/* This is a security hazard */ static ssize_t mem_write(struct file * file, const char __user *buf, size_t count, loff_t *ppos) { @@ -949,6 +953,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf, out_no_task: return copied; } +#endif loff_t mem_lseek(struct file *file, loff_t offset, int orig) { From 21dcd21b0b2a5a787b0a794ee8a1a218a0a10c4a Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Thu, 19 Jan 2012 09:51:07 -0800 Subject: [PATCH 0650/4025] Revert "proc: enable writing to /proc/pid/mem" This reverts commit 198214a7ee50375fa71a65e518341980cfd4b2f0. --- fs/proc/base.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/proc/base.c b/fs/proc/base.c index efb304854b7..1a8d756021f 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -891,6 +891,10 @@ static ssize_t mem_read(struct file * file, char __user * buf, return ret; } +#define mem_write NULL + +#ifndef mem_write +/* This is a security hazard */ static ssize_t mem_write(struct file * file, const char __user *buf, size_t count, loff_t *ppos) { @@ -949,6 +953,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf, out_no_task: return copied; } +#endif loff_t mem_lseek(struct file *file, loff_t offset, int orig) { From d1e94136fc4fe8ea608f4e9d21befa00c86e1e29 Mon Sep 17 00:00:00 2001 From: Dima Zavin Date: Mon, 23 Jan 2012 10:39:02 -0800 Subject: [PATCH 0651/4025] misc: remove android pmem driver, it's obsolete. Change-Id: I48d9778007e1e9eed2bb34e33ceee818c23afaa5 Signed-off-by: Dima Zavin --- drivers/misc/Kconfig | 4 - drivers/misc/Makefile | 1 - drivers/misc/pmem.c | 1345 ---------------------------------- include/linux/android_pmem.h | 93 --- 4 files changed, 1443 deletions(-) delete mode 100644 drivers/misc/pmem.c delete mode 100644 include/linux/android_pmem.h diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 961b5295074..7ae6ec94e2c 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -61,10 +61,6 @@ config AD525X_DPOT_SPI To compile this driver as a module, choose M here: the module will be called ad525x_dpot-spi. -config ANDROID_PMEM - bool "Android pmem allocator" - default y - config ATMEL_PWM tristate "Atmel AT32/AT91 PWM support" depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 5d804587873..606b27f4cb2 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_PHANTOM) += phantom.o obj-$(CONFIG_SENSORS_BH1780) += bh1780gli.o obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o -obj-$(CONFIG_ANDROID_PMEM) += pmem.o obj-$(CONFIG_SGI_IOC4) += ioc4.o obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o obj-$(CONFIG_KGDB_TESTS) += kgdbts.o diff --git a/drivers/misc/pmem.c b/drivers/misc/pmem.c deleted file mode 100644 index abb73c14316..00000000000 --- a/drivers/misc/pmem.c +++ /dev/null @@ -1,1345 +0,0 @@ -/* drivers/android/pmem.c - * - * Copyright (C) 2007 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PMEM_MAX_DEVICES 10 -#define PMEM_MAX_ORDER 128 -#define PMEM_MIN_ALLOC PAGE_SIZE - -#define PMEM_DEBUG 1 - -/* indicates that a refernce to this file has been taken via get_pmem_file, - * the file should not be released until put_pmem_file is called */ -#define PMEM_FLAGS_BUSY 0x1 -/* indicates that this is a suballocation of a larger master range */ -#define PMEM_FLAGS_CONNECTED 0x1 << 1 -/* indicates this is a master and not a sub allocation and that it is mmaped */ -#define PMEM_FLAGS_MASTERMAP 0x1 << 2 -/* submap and unsubmap flags indicate: - * 00: subregion has never been mmaped - * 10: subregion has been mmaped, reference to the mm was taken - * 11: subretion has ben released, refernece to the mm still held - * 01: subretion has been released, reference to the mm has been released - */ -#define PMEM_FLAGS_SUBMAP 0x1 << 3 -#define PMEM_FLAGS_UNSUBMAP 0x1 << 4 - - -struct pmem_data { - /* in alloc mode: an index into the bitmap - * in no_alloc mode: the size of the allocation */ - int index; - /* see flags above for descriptions */ - unsigned int flags; - /* protects this data field, if the mm_mmap sem will be held at the - * same time as this sem, the mm sem must be taken first (as this is - * the order for vma_open and vma_close ops */ - struct rw_semaphore sem; - /* info about the mmaping process */ - struct vm_area_struct *vma; - /* task struct of the mapping process */ - struct task_struct *task; - /* process id of teh mapping process */ - pid_t pid; - /* file descriptor of the master */ - int master_fd; - /* file struct of the master */ - struct file *master_file; - /* a list of currently available regions if this is a suballocation */ - struct list_head region_list; - /* a linked list of data so we can access them for debugging */ - struct list_head list; -#if PMEM_DEBUG - int ref; -#endif -}; - -struct pmem_bits { - unsigned allocated:1; /* 1 if allocated, 0 if free */ - unsigned order:7; /* size of the region in pmem space */ -}; - -struct pmem_region_node { - struct pmem_region region; - struct list_head list; -}; - -#define PMEM_DEBUG_MSGS 0 -#if PMEM_DEBUG_MSGS -#define DLOG(fmt,args...) \ - do { printk(KERN_INFO "[%s:%s:%d] "fmt, __FILE__, __func__, __LINE__, \ - ##args); } \ - while (0) -#else -#define DLOG(x...) do {} while (0) -#endif - -struct pmem_info { - struct miscdevice dev; - /* physical start address of the remaped pmem space */ - unsigned long base; - /* vitual start address of the remaped pmem space */ - unsigned char __iomem *vbase; - /* total size of the pmem space */ - unsigned long size; - /* number of entries in the pmem space */ - unsigned long num_entries; - /* pfn of the garbage page in memory */ - unsigned long garbage_pfn; - /* index of the garbage page in the pmem space */ - int garbage_index; - /* the bitmap for the region indicating which entries are allocated - * and which are free */ - struct pmem_bits *bitmap; - /* indicates the region should not be managed with an allocator */ - unsigned no_allocator; - /* indicates maps of this region should be cached, if a mix of - * cached and uncached is desired, set this and open the device with - * O_SYNC to get an uncached region */ - unsigned cached; - unsigned buffered; - /* in no_allocator mode the first mapper gets the whole space and sets - * this flag */ - unsigned allocated; - /* for debugging, creates a list of pmem file structs, the - * data_list_lock should be taken before pmem_data->sem if both are - * needed */ - struct mutex data_list_lock; - struct list_head data_list; - /* pmem_sem protects the bitmap array - * a write lock should be held when modifying entries in bitmap - * a read lock should be held when reading data from bits or - * dereferencing a pointer into bitmap - * - * pmem_data->sem protects the pmem data of a particular file - * Many of the function that require the pmem_data->sem have a non- - * locking version for when the caller is already holding that sem. - * - * IF YOU TAKE BOTH LOCKS TAKE THEM IN THIS ORDER: - * down(pmem_data->sem) => down(bitmap_sem) - */ - struct rw_semaphore bitmap_sem; - - long (*ioctl)(struct file *, unsigned int, unsigned long); - int (*release)(struct inode *, struct file *); -}; - -static struct pmem_info pmem[PMEM_MAX_DEVICES]; -static int id_count; - -#define PMEM_IS_FREE(id, index) !(pmem[id].bitmap[index].allocated) -#define PMEM_ORDER(id, index) pmem[id].bitmap[index].order -#define PMEM_BUDDY_INDEX(id, index) (index ^ (1 << PMEM_ORDER(id, index))) -#define PMEM_NEXT_INDEX(id, index) (index + (1 << PMEM_ORDER(id, index))) -#define PMEM_OFFSET(index) (index * PMEM_MIN_ALLOC) -#define PMEM_START_ADDR(id, index) (PMEM_OFFSET(index) + pmem[id].base) -#define PMEM_LEN(id, index) ((1 << PMEM_ORDER(id, index)) * PMEM_MIN_ALLOC) -#define PMEM_END_ADDR(id, index) (PMEM_START_ADDR(id, index) + \ - PMEM_LEN(id, index)) -#define PMEM_START_VADDR(id, index) (PMEM_OFFSET(id, index) + pmem[id].vbase) -#define PMEM_END_VADDR(id, index) (PMEM_START_VADDR(id, index) + \ - PMEM_LEN(id, index)) -#define PMEM_REVOKED(data) (data->flags & PMEM_FLAGS_REVOKED) -#define PMEM_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK))) -#define PMEM_IS_SUBMAP(data) ((data->flags & PMEM_FLAGS_SUBMAP) && \ - (!(data->flags & PMEM_FLAGS_UNSUBMAP))) - -static int pmem_release(struct inode *, struct file *); -static int pmem_mmap(struct file *, struct vm_area_struct *); -static int pmem_open(struct inode *, struct file *); -static long pmem_ioctl(struct file *, unsigned int, unsigned long); - -struct file_operations pmem_fops = { - .release = pmem_release, - .mmap = pmem_mmap, - .open = pmem_open, - .unlocked_ioctl = pmem_ioctl, -}; - -static int get_id(struct file *file) -{ - return MINOR(file->f_dentry->d_inode->i_rdev); -} - -int is_pmem_file(struct file *file) -{ - int id; - - if (unlikely(!file || !file->f_dentry || !file->f_dentry->d_inode)) - return 0; - id = get_id(file); - if (unlikely(id >= PMEM_MAX_DEVICES)) - return 0; - if (unlikely(file->f_dentry->d_inode->i_rdev != - MKDEV(MISC_MAJOR, pmem[id].dev.minor))) - return 0; - return 1; -} - -static int has_allocation(struct file *file) -{ - struct pmem_data *data; - /* check is_pmem_file first if not accessed via pmem_file_ops */ - - if (unlikely(!file->private_data)) - return 0; - data = (struct pmem_data *)file->private_data; - if (unlikely(data->index < 0)) - return 0; - return 1; -} - -static int is_master_owner(struct file *file) -{ - struct file *master_file; - struct pmem_data *data; - int put_needed, ret = 0; - - if (!is_pmem_file(file) || !has_allocation(file)) - return 0; - data = (struct pmem_data *)file->private_data; - if (PMEM_FLAGS_MASTERMAP & data->flags) - return 1; - master_file = fget_light(data->master_fd, &put_needed); - if (master_file && data->master_file == master_file) - ret = 1; - fput_light(master_file, put_needed); - return ret; -} - -static int pmem_free(int id, int index) -{ - /* caller should hold the write lock on pmem_sem! */ - int buddy, curr = index; - DLOG("index %d\n", index); - - if (pmem[id].no_allocator) { - pmem[id].allocated = 0; - return 0; - } - /* clean up the bitmap, merging any buddies */ - pmem[id].bitmap[curr].allocated = 0; - /* find a slots buddy Buddy# = Slot# ^ (1 << order) - * if the buddy is also free merge them - * repeat until the buddy is not free or end of the bitmap is reached - */ - do { - buddy = PMEM_BUDDY_INDEX(id, curr); - if (PMEM_IS_FREE(id, buddy) && - PMEM_ORDER(id, buddy) == PMEM_ORDER(id, curr)) { - PMEM_ORDER(id, buddy)++; - PMEM_ORDER(id, curr)++; - curr = min(buddy, curr); - } else { - break; - } - } while (curr < pmem[id].num_entries); - - return 0; -} - -static void pmem_revoke(struct file *file, struct pmem_data *data); - -static int pmem_release(struct inode *inode, struct file *file) -{ - struct pmem_data *data = (struct pmem_data *)file->private_data; - struct pmem_region_node *region_node; - struct list_head *elt, *elt2; - int id = get_id(file), ret = 0; - - - mutex_lock(&pmem[id].data_list_lock); - /* if this file is a master, revoke all the memory in the connected - * files */ - if (PMEM_FLAGS_MASTERMAP & data->flags) { - struct pmem_data *sub_data; - list_for_each(elt, &pmem[id].data_list) { - sub_data = list_entry(elt, struct pmem_data, list); - down_read(&sub_data->sem); - if (PMEM_IS_SUBMAP(sub_data) && - file == sub_data->master_file) { - up_read(&sub_data->sem); - pmem_revoke(file, sub_data); - } else - up_read(&sub_data->sem); - } - } - list_del(&data->list); - mutex_unlock(&pmem[id].data_list_lock); - - - down_write(&data->sem); - - /* if its not a conencted file and it has an allocation, free it */ - if (!(PMEM_FLAGS_CONNECTED & data->flags) && has_allocation(file)) { - down_write(&pmem[id].bitmap_sem); - ret = pmem_free(id, data->index); - up_write(&pmem[id].bitmap_sem); - } - - /* if this file is a submap (mapped, connected file), downref the - * task struct */ - if (PMEM_FLAGS_SUBMAP & data->flags) - if (data->task) { - put_task_struct(data->task); - data->task = NULL; - } - - file->private_data = NULL; - - list_for_each_safe(elt, elt2, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, list); - list_del(elt); - kfree(region_node); - } - BUG_ON(!list_empty(&data->region_list)); - - up_write(&data->sem); - kfree(data); - if (pmem[id].release) - ret = pmem[id].release(inode, file); - - return ret; -} - -static int pmem_open(struct inode *inode, struct file *file) -{ - struct pmem_data *data; - int id = get_id(file); - int ret = 0; - - DLOG("current %u file %p(%d)\n", current->pid, file, file_count(file)); - /* setup file->private_data to indicate its unmapped */ - /* you can only open a pmem device one time */ - if (file->private_data != NULL) - return -1; - data = kmalloc(sizeof(struct pmem_data), GFP_KERNEL); - if (!data) { - printk("pmem: unable to allocate memory for pmem metadata."); - return -1; - } - data->flags = 0; - data->index = -1; - data->task = NULL; - data->vma = NULL; - data->pid = 0; - data->master_file = NULL; -#if PMEM_DEBUG - data->ref = 0; -#endif - INIT_LIST_HEAD(&data->region_list); - init_rwsem(&data->sem); - - file->private_data = data; - INIT_LIST_HEAD(&data->list); - - mutex_lock(&pmem[id].data_list_lock); - list_add(&data->list, &pmem[id].data_list); - mutex_unlock(&pmem[id].data_list_lock); - return ret; -} - -static unsigned long pmem_order(unsigned long len) -{ - int i; - - len = (len + PMEM_MIN_ALLOC - 1)/PMEM_MIN_ALLOC; - len--; - for (i = 0; i < sizeof(len)*8; i++) - if (len >> i == 0) - break; - return i; -} - -static int pmem_allocate(int id, unsigned long len) -{ - /* caller should hold the write lock on pmem_sem! */ - /* return the corresponding pdata[] entry */ - int curr = 0; - int end = pmem[id].num_entries; - int best_fit = -1; - unsigned long order = pmem_order(len); - - if (pmem[id].no_allocator) { - DLOG("no allocator"); - if ((len > pmem[id].size) || pmem[id].allocated) - return -1; - pmem[id].allocated = 1; - return len; - } - - if (order > PMEM_MAX_ORDER) - return -1; - DLOG("order %lx\n", order); - - /* look through the bitmap: - * if you find a free slot of the correct order use it - * otherwise, use the best fit (smallest with size > order) slot - */ - while (curr < end) { - if (PMEM_IS_FREE(id, curr)) { - if (PMEM_ORDER(id, curr) == (unsigned char)order) { - /* set the not free bit and clear others */ - best_fit = curr; - break; - } - if (PMEM_ORDER(id, curr) > (unsigned char)order && - (best_fit < 0 || - PMEM_ORDER(id, curr) < PMEM_ORDER(id, best_fit))) - best_fit = curr; - } - curr = PMEM_NEXT_INDEX(id, curr); - } - - /* if best_fit < 0, there are no suitable slots, - * return an error - */ - if (best_fit < 0) { - printk("pmem: no space left to allocate!\n"); - return -1; - } - - /* now partition the best fit: - * split the slot into 2 buddies of order - 1 - * repeat until the slot is of the correct order - */ - while (PMEM_ORDER(id, best_fit) > (unsigned char)order) { - int buddy; - PMEM_ORDER(id, best_fit) -= 1; - buddy = PMEM_BUDDY_INDEX(id, best_fit); - PMEM_ORDER(id, buddy) = PMEM_ORDER(id, best_fit); - } - pmem[id].bitmap[best_fit].allocated = 1; - return best_fit; -} - -static pgprot_t pmem_access_prot(struct file *file, pgprot_t vma_prot) -{ - int id = get_id(file); -#ifdef pgprot_noncached - if (pmem[id].cached == 0 || file->f_flags & O_SYNC) - return pgprot_noncached(vma_prot); -#endif -#ifdef pgprot_ext_buffered - else if (pmem[id].buffered) - return pgprot_ext_buffered(vma_prot); -#endif - return vma_prot; -} - -static unsigned long pmem_start_addr(int id, struct pmem_data *data) -{ - if (pmem[id].no_allocator) - return PMEM_START_ADDR(id, 0); - else - return PMEM_START_ADDR(id, data->index); - -} - -static void *pmem_start_vaddr(int id, struct pmem_data *data) -{ - return pmem_start_addr(id, data) - pmem[id].base + pmem[id].vbase; -} - -static unsigned long pmem_len(int id, struct pmem_data *data) -{ - if (pmem[id].no_allocator) - return data->index; - else - return PMEM_LEN(id, data->index); -} - -static int pmem_map_garbage(int id, struct vm_area_struct *vma, - struct pmem_data *data, unsigned long offset, - unsigned long len) -{ - int i, garbage_pages = len >> PAGE_SHIFT; - - vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP | VM_SHARED | VM_WRITE; - for (i = 0; i < garbage_pages; i++) { - if (vm_insert_pfn(vma, vma->vm_start + offset + (i * PAGE_SIZE), - pmem[id].garbage_pfn)) - return -EAGAIN; - } - return 0; -} - -static int pmem_unmap_pfn_range(int id, struct vm_area_struct *vma, - struct pmem_data *data, unsigned long offset, - unsigned long len) -{ - int garbage_pages; - DLOG("unmap offset %lx len %lx\n", offset, len); - - BUG_ON(!PMEM_IS_PAGE_ALIGNED(len)); - - garbage_pages = len >> PAGE_SHIFT; - zap_page_range(vma, vma->vm_start + offset, len, NULL); - pmem_map_garbage(id, vma, data, offset, len); - return 0; -} - -static int pmem_map_pfn_range(int id, struct vm_area_struct *vma, - struct pmem_data *data, unsigned long offset, - unsigned long len) -{ - DLOG("map offset %lx len %lx\n", offset, len); - BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_start)); - BUG_ON(!PMEM_IS_PAGE_ALIGNED(vma->vm_end)); - BUG_ON(!PMEM_IS_PAGE_ALIGNED(len)); - BUG_ON(!PMEM_IS_PAGE_ALIGNED(offset)); - - if (io_remap_pfn_range(vma, vma->vm_start + offset, - (pmem_start_addr(id, data) + offset) >> PAGE_SHIFT, - len, vma->vm_page_prot)) { - return -EAGAIN; - } - return 0; -} - -static int pmem_remap_pfn_range(int id, struct vm_area_struct *vma, - struct pmem_data *data, unsigned long offset, - unsigned long len) -{ - /* hold the mm semp for the vma you are modifying when you call this */ - BUG_ON(!vma); - zap_page_range(vma, vma->vm_start + offset, len, NULL); - return pmem_map_pfn_range(id, vma, data, offset, len); -} - -static void pmem_vma_open(struct vm_area_struct *vma) -{ - struct file *file = vma->vm_file; - struct pmem_data *data = file->private_data; - int id = get_id(file); - /* this should never be called as we don't support copying pmem - * ranges via fork */ - BUG_ON(!has_allocation(file)); - down_write(&data->sem); - /* remap the garbage pages, forkers don't get access to the data */ - pmem_unmap_pfn_range(id, vma, data, 0, vma->vm_start - vma->vm_end); - up_write(&data->sem); -} - -static void pmem_vma_close(struct vm_area_struct *vma) -{ - struct file *file = vma->vm_file; - struct pmem_data *data = file->private_data; - - DLOG("current %u ppid %u file %p count %d\n", current->pid, - current->parent->pid, file, file_count(file)); - if (unlikely(!is_pmem_file(file) || !has_allocation(file))) { - printk(KERN_WARNING "pmem: something is very wrong, you are " - "closing a vm backing an allocation that doesn't " - "exist!\n"); - return; - } - down_write(&data->sem); - if (data->vma == vma) { - data->vma = NULL; - if ((data->flags & PMEM_FLAGS_CONNECTED) && - (data->flags & PMEM_FLAGS_SUBMAP)) - data->flags |= PMEM_FLAGS_UNSUBMAP; - } - /* the kernel is going to free this vma now anyway */ - up_write(&data->sem); -} - -static struct vm_operations_struct vm_ops = { - .open = pmem_vma_open, - .close = pmem_vma_close, -}; - -static int pmem_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct pmem_data *data; - int index; - unsigned long vma_size = vma->vm_end - vma->vm_start; - int ret = 0, id = get_id(file); - - if (vma->vm_pgoff || !PMEM_IS_PAGE_ALIGNED(vma_size)) { -#if PMEM_DEBUG - printk(KERN_ERR "pmem: mmaps must be at offset zero, aligned" - " and a multiple of pages_size.\n"); -#endif - return -EINVAL; - } - - data = (struct pmem_data *)file->private_data; - down_write(&data->sem); - /* check this file isn't already mmaped, for submaps check this file - * has never been mmaped */ - if ((data->flags & PMEM_FLAGS_SUBMAP) || - (data->flags & PMEM_FLAGS_UNSUBMAP)) { -#if PMEM_DEBUG - printk(KERN_ERR "pmem: you can only mmap a pmem file once, " - "this file is already mmaped. %x\n", data->flags); -#endif - ret = -EINVAL; - goto error; - } - /* if file->private_data == unalloced, alloc*/ - if (data && data->index == -1) { - down_write(&pmem[id].bitmap_sem); - index = pmem_allocate(id, vma->vm_end - vma->vm_start); - up_write(&pmem[id].bitmap_sem); - data->index = index; - } - /* either no space was available or an error occured */ - if (!has_allocation(file)) { - ret = -EINVAL; - printk("pmem: could not find allocation for map.\n"); - goto error; - } - - if (pmem_len(id, data) < vma_size) { -#if PMEM_DEBUG - printk(KERN_WARNING "pmem: mmap size [%lu] does not match" - "size of backing region [%lu].\n", vma_size, - pmem_len(id, data)); -#endif - ret = -EINVAL; - goto error; - } - - vma->vm_pgoff = pmem_start_addr(id, data) >> PAGE_SHIFT; - vma->vm_page_prot = pmem_access_prot(file, vma->vm_page_prot); - - if (data->flags & PMEM_FLAGS_CONNECTED) { - struct pmem_region_node *region_node; - struct list_head *elt; - if (pmem_map_garbage(id, vma, data, 0, vma_size)) { - printk("pmem: mmap failed in kernel!\n"); - ret = -EAGAIN; - goto error; - } - list_for_each(elt, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, - list); - DLOG("remapping file: %p %lx %lx\n", file, - region_node->region.offset, - region_node->region.len); - if (pmem_remap_pfn_range(id, vma, data, - region_node->region.offset, - region_node->region.len)) { - ret = -EAGAIN; - goto error; - } - } - data->flags |= PMEM_FLAGS_SUBMAP; - get_task_struct(current->group_leader); - data->task = current->group_leader; - data->vma = vma; -#if PMEM_DEBUG - data->pid = current->pid; -#endif - DLOG("submmapped file %p vma %p pid %u\n", file, vma, - current->pid); - } else { - if (pmem_map_pfn_range(id, vma, data, 0, vma_size)) { - printk(KERN_INFO "pmem: mmap failed in kernel!\n"); - ret = -EAGAIN; - goto error; - } - data->flags |= PMEM_FLAGS_MASTERMAP; - data->pid = current->pid; - } - vma->vm_ops = &vm_ops; -error: - up_write(&data->sem); - return ret; -} - -/* the following are the api for accessing pmem regions by other drivers - * from inside the kernel */ -int get_pmem_user_addr(struct file *file, unsigned long *start, - unsigned long *len) -{ - struct pmem_data *data; - if (!is_pmem_file(file) || !has_allocation(file)) { -#if PMEM_DEBUG - printk(KERN_INFO "pmem: requested pmem data from invalid" - "file.\n"); -#endif - return -1; - } - data = (struct pmem_data *)file->private_data; - down_read(&data->sem); - if (data->vma) { - *start = data->vma->vm_start; - *len = data->vma->vm_end - data->vma->vm_start; - } else { - *start = 0; - *len = 0; - } - up_read(&data->sem); - return 0; -} - -int get_pmem_addr(struct file *file, unsigned long *start, - unsigned long *vstart, unsigned long *len) -{ - struct pmem_data *data; - int id; - - if (!is_pmem_file(file) || !has_allocation(file)) { - return -1; - } - - data = (struct pmem_data *)file->private_data; - if (data->index == -1) { -#if PMEM_DEBUG - printk(KERN_INFO "pmem: requested pmem data from file with no " - "allocation.\n"); - return -1; -#endif - } - id = get_id(file); - - down_read(&data->sem); - *start = pmem_start_addr(id, data); - *len = pmem_len(id, data); - *vstart = (unsigned long)pmem_start_vaddr(id, data); - up_read(&data->sem); -#if PMEM_DEBUG - down_write(&data->sem); - data->ref++; - up_write(&data->sem); -#endif - return 0; -} - -int get_pmem_file(int fd, unsigned long *start, unsigned long *vstart, - unsigned long *len, struct file **filp) -{ - struct file *file; - - file = fget(fd); - if (unlikely(file == NULL)) { - printk(KERN_INFO "pmem: requested data from file descriptor " - "that doesn't exist."); - return -1; - } - - if (get_pmem_addr(file, start, vstart, len)) - goto end; - - if (filp) - *filp = file; - return 0; -end: - fput(file); - return -1; -} - -void put_pmem_file(struct file *file) -{ - struct pmem_data *data; - int id; - - if (!is_pmem_file(file)) - return; - id = get_id(file); - data = (struct pmem_data *)file->private_data; -#if PMEM_DEBUG - down_write(&data->sem); - if (data->ref == 0) { - printk("pmem: pmem_put > pmem_get %s (pid %d)\n", - pmem[id].dev.name, data->pid); - BUG(); - } - data->ref--; - up_write(&data->sem); -#endif - fput(file); -} - -void flush_pmem_file(struct file *file, unsigned long offset, unsigned long len) -{ - struct pmem_data *data; - int id; - void *vaddr; - struct pmem_region_node *region_node; - struct list_head *elt; - void *flush_start, *flush_end; - - if (!is_pmem_file(file) || !has_allocation(file)) { - return; - } - - id = get_id(file); - data = (struct pmem_data *)file->private_data; - if (!pmem[id].cached || file->f_flags & O_SYNC) - return; - - down_read(&data->sem); - vaddr = pmem_start_vaddr(id, data); - /* if this isn't a submmapped file, flush the whole thing */ - if (unlikely(!(data->flags & PMEM_FLAGS_CONNECTED))) { - dmac_flush_range(vaddr, vaddr + pmem_len(id, data)); - goto end; - } - /* otherwise, flush the region of the file we are drawing */ - list_for_each(elt, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, list); - if ((offset >= region_node->region.offset) && - ((offset + len) <= (region_node->region.offset + - region_node->region.len))) { - flush_start = vaddr + region_node->region.offset; - flush_end = flush_start + region_node->region.len; - dmac_flush_range(flush_start, flush_end); - break; - } - } -end: - up_read(&data->sem); -} - -static int pmem_connect(unsigned long connect, struct file *file) -{ - struct pmem_data *data = (struct pmem_data *)file->private_data; - struct pmem_data *src_data; - struct file *src_file; - int ret = 0, put_needed; - - down_write(&data->sem); - /* retrieve the src file and check it is a pmem file with an alloc */ - src_file = fget_light(connect, &put_needed); - DLOG("connect %p to %p\n", file, src_file); - if (!src_file) { - printk("pmem: src file not found!\n"); - ret = -EINVAL; - goto err_no_file; - } - if (unlikely(!is_pmem_file(src_file) || !has_allocation(src_file))) { - printk(KERN_INFO "pmem: src file is not a pmem file or has no " - "alloc!\n"); - ret = -EINVAL; - goto err_bad_file; - } - src_data = (struct pmem_data *)src_file->private_data; - - if (has_allocation(file) && (data->index != src_data->index)) { - printk("pmem: file is already mapped but doesn't match this" - " src_file!\n"); - ret = -EINVAL; - goto err_bad_file; - } - data->index = src_data->index; - data->flags |= PMEM_FLAGS_CONNECTED; - data->master_fd = connect; - data->master_file = src_file; - -err_bad_file: - fput_light(src_file, put_needed); -err_no_file: - up_write(&data->sem); - return ret; -} - -static void pmem_unlock_data_and_mm(struct pmem_data *data, - struct mm_struct *mm) -{ - up_write(&data->sem); - if (mm != NULL) { - up_write(&mm->mmap_sem); - mmput(mm); - } -} - -static int pmem_lock_data_and_mm(struct file *file, struct pmem_data *data, - struct mm_struct **locked_mm) -{ - int ret = 0; - struct mm_struct *mm = NULL; - *locked_mm = NULL; -lock_mm: - down_read(&data->sem); - if (PMEM_IS_SUBMAP(data)) { - mm = get_task_mm(data->task); - if (!mm) { -#if PMEM_DEBUG - printk("pmem: can't remap task is gone!\n"); -#endif - up_read(&data->sem); - return -1; - } - } - up_read(&data->sem); - - if (mm) - down_write(&mm->mmap_sem); - - down_write(&data->sem); - /* check that the file didn't get mmaped before we could take the - * data sem, this should be safe b/c you can only submap each file - * once */ - if (PMEM_IS_SUBMAP(data) && !mm) { - pmem_unlock_data_and_mm(data, mm); - up_write(&data->sem); - goto lock_mm; - } - /* now check that vma.mm is still there, it could have been - * deleted by vma_close before we could get the data->sem */ - if ((data->flags & PMEM_FLAGS_UNSUBMAP) && (mm != NULL)) { - /* might as well release this */ - if (data->flags & PMEM_FLAGS_SUBMAP) { - put_task_struct(data->task); - data->task = NULL; - /* lower the submap flag to show the mm is gone */ - data->flags &= ~(PMEM_FLAGS_SUBMAP); - } - pmem_unlock_data_and_mm(data, mm); - return -1; - } - *locked_mm = mm; - return ret; -} - -int pmem_remap(struct pmem_region *region, struct file *file, - unsigned operation) -{ - int ret; - struct pmem_region_node *region_node; - struct mm_struct *mm = NULL; - struct list_head *elt, *elt2; - int id = get_id(file); - struct pmem_data *data = (struct pmem_data *)file->private_data; - - /* pmem region must be aligned on a page boundry */ - if (unlikely(!PMEM_IS_PAGE_ALIGNED(region->offset) || - !PMEM_IS_PAGE_ALIGNED(region->len))) { -#if PMEM_DEBUG - printk("pmem: request for unaligned pmem suballocation " - "%lx %lx\n", region->offset, region->len); -#endif - return -EINVAL; - } - - /* if userspace requests a region of len 0, there's nothing to do */ - if (region->len == 0) - return 0; - - /* lock the mm and data */ - ret = pmem_lock_data_and_mm(file, data, &mm); - if (ret) - return 0; - - /* only the owner of the master file can remap the client fds - * that back in it */ - if (!is_master_owner(file)) { -#if PMEM_DEBUG - printk("pmem: remap requested from non-master process\n"); -#endif - ret = -EINVAL; - goto err; - } - - /* check that the requested range is within the src allocation */ - if (unlikely((region->offset > pmem_len(id, data)) || - (region->len > pmem_len(id, data)) || - (region->offset + region->len > pmem_len(id, data)))) { -#if PMEM_DEBUG - printk(KERN_INFO "pmem: suballoc doesn't fit in src_file!\n"); -#endif - ret = -EINVAL; - goto err; - } - - if (operation == PMEM_MAP) { - region_node = kmalloc(sizeof(struct pmem_region_node), - GFP_KERNEL); - if (!region_node) { - ret = -ENOMEM; -#if PMEM_DEBUG - printk(KERN_INFO "No space to allocate metadata!"); -#endif - goto err; - } - region_node->region = *region; - list_add(®ion_node->list, &data->region_list); - } else if (operation == PMEM_UNMAP) { - int found = 0; - list_for_each_safe(elt, elt2, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, - list); - if (region->len == 0 || - (region_node->region.offset == region->offset && - region_node->region.len == region->len)) { - list_del(elt); - kfree(region_node); - found = 1; - } - } - if (!found) { -#if PMEM_DEBUG - printk("pmem: Unmap region does not map any mapped " - "region!"); -#endif - ret = -EINVAL; - goto err; - } - } - - if (data->vma && PMEM_IS_SUBMAP(data)) { - if (operation == PMEM_MAP) - ret = pmem_remap_pfn_range(id, data->vma, data, - region->offset, region->len); - else if (operation == PMEM_UNMAP) - ret = pmem_unmap_pfn_range(id, data->vma, data, - region->offset, region->len); - } - -err: - pmem_unlock_data_and_mm(data, mm); - return ret; -} - -static void pmem_revoke(struct file *file, struct pmem_data *data) -{ - struct pmem_region_node *region_node; - struct list_head *elt, *elt2; - struct mm_struct *mm = NULL; - int id = get_id(file); - int ret = 0; - - data->master_file = NULL; - ret = pmem_lock_data_and_mm(file, data, &mm); - /* if lock_data_and_mm fails either the task that mapped the fd, or - * the vma that mapped it have already gone away, nothing more - * needs to be done */ - if (ret) - return; - /* unmap everything */ - /* delete the regions and region list nothing is mapped any more */ - if (data->vma) - list_for_each_safe(elt, elt2, &data->region_list) { - region_node = list_entry(elt, struct pmem_region_node, - list); - pmem_unmap_pfn_range(id, data->vma, data, - region_node->region.offset, - region_node->region.len); - list_del(elt); - kfree(region_node); - } - /* delete the master file */ - pmem_unlock_data_and_mm(data, mm); -} - -static void pmem_get_size(struct pmem_region *region, struct file *file) -{ - struct pmem_data *data = (struct pmem_data *)file->private_data; - int id = get_id(file); - - if (!has_allocation(file)) { - region->offset = 0; - region->len = 0; - return; - } else { - region->offset = pmem_start_addr(id, data); - region->len = pmem_len(id, data); - } - DLOG("offset %lx len %lx\n", region->offset, region->len); -} - - -static long pmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct pmem_data *data; - int id = get_id(file); - - switch (cmd) { - case PMEM_GET_PHYS: - { - struct pmem_region region; - DLOG("get_phys\n"); - if (!has_allocation(file)) { - region.offset = 0; - region.len = 0; - } else { - data = (struct pmem_data *)file->private_data; - region.offset = pmem_start_addr(id, data); - region.len = pmem_len(id, data); - } - printk(KERN_INFO "pmem: request for physical address of pmem region " - "from process %d.\n", current->pid); - if (copy_to_user((void __user *)arg, ®ion, - sizeof(struct pmem_region))) - return -EFAULT; - break; - } - case PMEM_MAP: - { - struct pmem_region region; - if (copy_from_user(®ion, (void __user *)arg, - sizeof(struct pmem_region))) - return -EFAULT; - data = (struct pmem_data *)file->private_data; - return pmem_remap(®ion, file, PMEM_MAP); - } - break; - case PMEM_UNMAP: - { - struct pmem_region region; - if (copy_from_user(®ion, (void __user *)arg, - sizeof(struct pmem_region))) - return -EFAULT; - data = (struct pmem_data *)file->private_data; - return pmem_remap(®ion, file, PMEM_UNMAP); - break; - } - case PMEM_GET_SIZE: - { - struct pmem_region region; - DLOG("get_size\n"); - pmem_get_size(®ion, file); - if (copy_to_user((void __user *)arg, ®ion, - sizeof(struct pmem_region))) - return -EFAULT; - break; - } - case PMEM_GET_TOTAL_SIZE: - { - struct pmem_region region; - DLOG("get total size\n"); - region.offset = 0; - get_id(file); - region.len = pmem[id].size; - if (copy_to_user((void __user *)arg, ®ion, - sizeof(struct pmem_region))) - return -EFAULT; - break; - } - case PMEM_ALLOCATE: - { - if (has_allocation(file)) - return -EINVAL; - data = (struct pmem_data *)file->private_data; - data->index = pmem_allocate(id, arg); - break; - } - case PMEM_CONNECT: - DLOG("connect\n"); - return pmem_connect(arg, file); - break; - case PMEM_CACHE_FLUSH: - { - struct pmem_region region; - DLOG("flush\n"); - if (copy_from_user(®ion, (void __user *)arg, - sizeof(struct pmem_region))) - return -EFAULT; - flush_pmem_file(file, region.offset, region.len); - break; - } - default: - if (pmem[id].ioctl) - return pmem[id].ioctl(file, cmd, arg); - return -EINVAL; - } - return 0; -} - -#if PMEM_DEBUG -static ssize_t debug_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t debug_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - struct list_head *elt, *elt2; - struct pmem_data *data; - struct pmem_region_node *region_node; - int id = (int)file->private_data; - const int debug_bufmax = 4096; - static char buffer[4096]; - int n = 0; - - DLOG("debug open\n"); - n = scnprintf(buffer, debug_bufmax, - "pid #: mapped regions (offset, len) (offset,len)...\n"); - - mutex_lock(&pmem[id].data_list_lock); - list_for_each(elt, &pmem[id].data_list) { - data = list_entry(elt, struct pmem_data, list); - down_read(&data->sem); - n += scnprintf(buffer + n, debug_bufmax - n, "pid %u:", - data->pid); - list_for_each(elt2, &data->region_list) { - region_node = list_entry(elt2, struct pmem_region_node, - list); - n += scnprintf(buffer + n, debug_bufmax - n, - "(%lx,%lx) ", - region_node->region.offset, - region_node->region.len); - } - n += scnprintf(buffer + n, debug_bufmax - n, "\n"); - up_read(&data->sem); - } - mutex_unlock(&pmem[id].data_list_lock); - - n++; - buffer[n] = 0; - return simple_read_from_buffer(buf, count, ppos, buffer, n); -} - -static struct file_operations debug_fops = { - .read = debug_read, - .open = debug_open, -}; -#endif - -#if 0 -static struct miscdevice pmem_dev = { - .name = "pmem", - .fops = &pmem_fops, -}; -#endif - -int pmem_setup(struct android_pmem_platform_data *pdata, - long (*ioctl)(struct file *, unsigned int, unsigned long), - int (*release)(struct inode *, struct file *)) -{ - int err = 0; - int i, index = 0; - int id = id_count; - id_count++; - - pmem[id].no_allocator = pdata->no_allocator; - pmem[id].cached = pdata->cached; - pmem[id].buffered = pdata->buffered; - pmem[id].base = pdata->start; - pmem[id].size = pdata->size; - pmem[id].ioctl = ioctl; - pmem[id].release = release; - init_rwsem(&pmem[id].bitmap_sem); - mutex_init(&pmem[id].data_list_lock); - INIT_LIST_HEAD(&pmem[id].data_list); - pmem[id].dev.name = pdata->name; - pmem[id].dev.minor = id; - pmem[id].dev.fops = &pmem_fops; - printk(KERN_INFO "%s: %d init\n", pdata->name, pdata->cached); - - err = misc_register(&pmem[id].dev); - if (err) { - printk(KERN_ALERT "Unable to register pmem driver!\n"); - goto err_cant_register_device; - } - pmem[id].num_entries = pmem[id].size / PMEM_MIN_ALLOC; - - pmem[id].bitmap = kmalloc(pmem[id].num_entries * - sizeof(struct pmem_bits), GFP_KERNEL); - if (!pmem[id].bitmap) - goto err_no_mem_for_metadata; - - memset(pmem[id].bitmap, 0, sizeof(struct pmem_bits) * - pmem[id].num_entries); - - for (i = sizeof(pmem[id].num_entries) * 8 - 1; i >= 0; i--) { - if ((pmem[id].num_entries) & 1<name, S_IFREG | S_IRUGO, NULL, (void *)id, - &debug_fops); -#endif - return 0; -error_cant_remap: - kfree(pmem[id].bitmap); -err_no_mem_for_metadata: - misc_deregister(&pmem[id].dev); -err_cant_register_device: - return -1; -} - -static int pmem_probe(struct platform_device *pdev) -{ - struct android_pmem_platform_data *pdata; - - if (!pdev || !pdev->dev.platform_data) { - printk(KERN_ALERT "Unable to probe pmem!\n"); - return -1; - } - pdata = pdev->dev.platform_data; - return pmem_setup(pdata, NULL, NULL); -} - - -static int pmem_remove(struct platform_device *pdev) -{ - int id = pdev->id; - __free_page(pfn_to_page(pmem[id].garbage_pfn)); - misc_deregister(&pmem[id].dev); - return 0; -} - -static struct platform_driver pmem_driver = { - .probe = pmem_probe, - .remove = pmem_remove, - .driver = { .name = "android_pmem" } -}; - - -static int __init pmem_init(void) -{ - return platform_driver_register(&pmem_driver); -} - -static void __exit pmem_exit(void) -{ - platform_driver_unregister(&pmem_driver); -} - -module_init(pmem_init); -module_exit(pmem_exit); - diff --git a/include/linux/android_pmem.h b/include/linux/android_pmem.h deleted file mode 100644 index f633621f5be..00000000000 --- a/include/linux/android_pmem.h +++ /dev/null @@ -1,93 +0,0 @@ -/* include/linux/android_pmem.h - * - * Copyright (C) 2007 Google, Inc. - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _ANDROID_PMEM_H_ -#define _ANDROID_PMEM_H_ - -#define PMEM_IOCTL_MAGIC 'p' -#define PMEM_GET_PHYS _IOW(PMEM_IOCTL_MAGIC, 1, unsigned int) -#define PMEM_MAP _IOW(PMEM_IOCTL_MAGIC, 2, unsigned int) -#define PMEM_GET_SIZE _IOW(PMEM_IOCTL_MAGIC, 3, unsigned int) -#define PMEM_UNMAP _IOW(PMEM_IOCTL_MAGIC, 4, unsigned int) -/* This ioctl will allocate pmem space, backing the file, it will fail - * if the file already has an allocation, pass it the len as the argument - * to the ioctl */ -#define PMEM_ALLOCATE _IOW(PMEM_IOCTL_MAGIC, 5, unsigned int) -/* This will connect a one pmem file to another, pass the file that is already - * backed in memory as the argument to the ioctl - */ -#define PMEM_CONNECT _IOW(PMEM_IOCTL_MAGIC, 6, unsigned int) -/* Returns the total size of the pmem region it is sent to as a pmem_region - * struct (with offset set to 0). - */ -#define PMEM_GET_TOTAL_SIZE _IOW(PMEM_IOCTL_MAGIC, 7, unsigned int) -#define PMEM_CACHE_FLUSH _IOW(PMEM_IOCTL_MAGIC, 8, unsigned int) - -struct android_pmem_platform_data -{ - const char* name; - /* starting physical address of memory region */ - unsigned long start; - /* size of memory region */ - unsigned long size; - /* set to indicate the region should not be managed with an allocator */ - unsigned no_allocator; - /* set to indicate maps of this region should be cached, if a mix of - * cached and uncached is desired, set this and open the device with - * O_SYNC to get an uncached region */ - unsigned cached; - /* The MSM7k has bits to enable a write buffer in the bus controller*/ - unsigned buffered; -}; - -struct pmem_region { - unsigned long offset; - unsigned long len; -}; - -#ifdef CONFIG_ANDROID_PMEM -int is_pmem_file(struct file *file); -int get_pmem_file(int fd, unsigned long *start, unsigned long *vstart, - unsigned long *end, struct file **filp); -int get_pmem_user_addr(struct file *file, unsigned long *start, - unsigned long *end); -void put_pmem_file(struct file* file); -void flush_pmem_file(struct file *file, unsigned long start, unsigned long len); -int pmem_setup(struct android_pmem_platform_data *pdata, - long (*ioctl)(struct file *, unsigned int, unsigned long), - int (*release)(struct inode *, struct file *)); -int pmem_remap(struct pmem_region *region, struct file *file, - unsigned operation); - -#else -static inline int is_pmem_file(struct file *file) { return 0; } -static inline int get_pmem_file(int fd, unsigned long *start, - unsigned long *vstart, unsigned long *end, - struct file **filp) { return -ENOSYS; } -static inline int get_pmem_user_addr(struct file *file, unsigned long *start, - unsigned long *end) { return -ENOSYS; } -static inline void put_pmem_file(struct file* file) { return; } -static inline void flush_pmem_file(struct file *file, unsigned long start, - unsigned long len) { return; } -static inline int pmem_setup(struct android_pmem_platform_data *pdata, - long (*ioctl)(struct file *, unsigned int, unsigned long), - int (*release)(struct inode *, struct file *)) { return -ENOSYS; } - -static inline int pmem_remap(struct pmem_region *region, struct file *file, - unsigned operation) { return -ENOSYS; } -#endif - -#endif //_ANDROID_PPP_H_ - From d692df224b8605095cb7f770c1c99d3150834daf Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 8 Aug 2011 12:11:52 +0300 Subject: [PATCH 0652/4025] cfg80211/nl80211: Send AssocReq IEs to user space in AP mode When user space SME/MLME (e.g., hostapd) is not used in AP mode, the IEs from the (Re)Association Request frame that was processed in firmware need to be made available for user space (e.g., RSN IE for hostapd). Allow this to be done with cfg80211_new_sta(). Signed-off-by: Jouni Malinen Acked-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Dmitry Shmidt --- include/net/cfg80211.h | 8 ++++++++ net/wireless/nl80211.c | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 396e8fc8910..69448296e4a 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -536,6 +536,11 @@ struct sta_bss_parameters { * This number should increase every time the list of stations * changes, i.e. when a station is added or removed, so that * userspace can tell whether it got a consistent snapshot. + * @assoc_req_ies: IEs from (Re)Association Request. + * This is used only when in AP mode with drivers that do not use + * user space MLME/SME implementation. The information is provided for + * the cfg80211_new_sta() calls to notify user space of the IEs. + * @assoc_req_ies_len: Length of assoc_req_ies buffer in octets. */ struct station_info { u32 filled; @@ -558,6 +563,9 @@ struct station_info { struct sta_bss_parameters bss_param; int generation; + + const u8 *assoc_req_ies; + size_t assoc_req_ies_len; }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 1ac9443b526..863e502f058 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2209,6 +2209,10 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, } nla_nest_end(msg, sinfoattr); + if (sinfo->assoc_req_ies) + NLA_PUT(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len, + sinfo->assoc_req_ies); + return genlmsg_end(msg, hdr); nla_put_failure: From 87159de9c30dab02b84cbaffa7498140d4ebc1a1 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 11 Aug 2011 11:46:22 +0300 Subject: [PATCH 0653/4025] nl80211/cfg80211: Make addition of new sinfo fields safer Add a comment pointing out the use of enum station_info_flags for all new struct station_info fields. In addition, memset the sinfo buffer to zero before use on all paths in the current tree to avoid leaving uninitialized pointers in the data. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville Signed-off-by: Dmitry Shmidt --- include/net/cfg80211.h | 5 +++++ net/mac80211/sta_info.c | 1 + net/wireless/nl80211.c | 1 + 3 files changed, 7 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 69448296e4a..e95d3acaff0 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -566,6 +566,11 @@ struct station_info { const u8 *assoc_req_ies; size_t assoc_req_ies_len; + + /* + * Note: Add a new enum station_info_flags value for each new field and + * use it to check which fields are initialized. + */ }; /** diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ca7bf1052eb..3ff633e81b6 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -334,6 +334,7 @@ static int sta_info_finish_insert(struct sta_info *sta, bool async) ieee80211_sta_debugfs_add(sta); rate_control_add_sta_debugfs(sta); + memset(&sinfo, 0, sizeof(sinfo)); sinfo.filled = 0; sinfo.generation = local->sta_generation; cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 863e502f058..33115be4936 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2240,6 +2240,7 @@ static int nl80211_dump_station(struct sk_buff *skb, } while (1) { + memset(&sinfo, 0, sizeof(sinfo)); err = dev->ops->dump_station(&dev->wiphy, netdev, sta_idx, mac_addr, &sinfo); if (err == -ENOENT) From d373d5823387f4b753390de087baf2f3938a7dfb Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Tue, 24 Jan 2012 16:38:45 -0800 Subject: [PATCH 0654/4025] Revert "Revert "mmc: Set suspend/resume bus operations if CONFIG_PM_RUNTIME is used"" This reverts commit c96f99d7907853ffb7e29915954dfc38b912fa2c. Change-Id: I1953ba2fda5519023f3d173492b0ea6ce8e33c49 Signed-off-by: Todd Poynor --- drivers/mmc/core/bus.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 393d817ed04..e07d6c90cae 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -120,18 +120,19 @@ static int mmc_bus_remove(struct device *dev) return 0; } -static int mmc_bus_suspend(struct device *dev, pm_message_t state) +static int mmc_bus_pm_suspend(struct device *dev) { struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); int ret = 0; + pm_message_t state = { PM_EVENT_SUSPEND }; if (dev->driver && drv->suspend) ret = drv->suspend(card, state); return ret; } -static int mmc_bus_resume(struct device *dev) +static int mmc_bus_pm_resume(struct device *dev) { struct mmc_driver *drv = to_mmc_driver(dev->driver); struct mmc_card *card = mmc_dev_to_card(dev); @@ -143,7 +144,6 @@ static int mmc_bus_resume(struct device *dev) } #ifdef CONFIG_PM_RUNTIME - static int mmc_runtime_suspend(struct device *dev) { struct mmc_card *card = mmc_dev_to_card(dev); @@ -162,21 +162,13 @@ static int mmc_runtime_idle(struct device *dev) { return pm_runtime_suspend(dev); } +#endif /* CONFIG_PM_RUNTIME */ static const struct dev_pm_ops mmc_bus_pm_ops = { - .runtime_suspend = mmc_runtime_suspend, - .runtime_resume = mmc_runtime_resume, - .runtime_idle = mmc_runtime_idle, + SET_SYSTEM_SLEEP_PM_OPS(mmc_bus_pm_suspend, mmc_bus_pm_resume) + SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, mmc_runtime_idle) }; -#define MMC_PM_OPS_PTR (&mmc_bus_pm_ops) - -#else /* !CONFIG_PM_RUNTIME */ - -#define MMC_PM_OPS_PTR NULL - -#endif /* !CONFIG_PM_RUNTIME */ - static struct bus_type mmc_bus_type = { .name = "mmc", .dev_attrs = mmc_dev_attrs, @@ -184,9 +176,7 @@ static struct bus_type mmc_bus_type = { .uevent = mmc_bus_uevent, .probe = mmc_bus_probe, .remove = mmc_bus_remove, - .suspend = mmc_bus_suspend, - .resume = mmc_bus_resume, - .pm = MMC_PM_OPS_PTR, + .pm = &mmc_bus_pm_ops, }; int mmc_register_bus(void) From 49447e228b5835cc0cfea2f393f721b316c70fd7 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Wed, 25 Jan 2012 12:09:02 -0800 Subject: [PATCH 0655/4025] ARM: herring: Switch to built-in CFG80211 wlan driver Signed-off-by: Dmitry Shmidt --- arch/arm/configs/herring_defconfig | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/arm/configs/herring_defconfig b/arch/arm/configs/herring_defconfig index 13a1c396f8a..a24382364fd 100644 --- a/arch/arm/configs/herring_defconfig +++ b/arch/arm/configs/herring_defconfig @@ -162,6 +162,10 @@ CONFIG_BT_BNEP=y CONFIG_BT_HIDP=y CONFIG_BT_HCIUART=y CONFIG_BT_HCIUART_H4=y +CONFIG_CFG80211=y +CONFIG_NL80211_TESTMODE=y +# CONFIG_CFG80211_WEXT is not set +CONFIG_CFG80211_ALLOW_RECONNECT=y CONFIG_WIMAX=y CONFIG_RFKILL=y CONFIG_RFKILL_INPUT=y @@ -193,9 +197,9 @@ CONFIG_DM_UEVENT=y CONFIG_NETDEVICES=y CONFIG_IFB=y CONFIG_TUN=y -CONFIG_BCM4329=m -CONFIG_BCM4329_FW_PATH="/vendor/firmware/fw_bcm4329.bin" -CONFIG_BCM4329_NVRAM_PATH="/vendor/firmware/nvram_net.txt" +CONFIG_BCMDHD=y +CONFIG_BCMDHD_FW_PATH="/vendor/firmware/fw_bcmdhd.bin" +CONFIG_BCMDHD_NVRAM_PATH="/vendor/firmware/nvram_net.txt" CONFIG_WIMAX_CMC7XX=y CONFIG_PPP=y CONFIG_PPP_DEFLATE=y From a6ccb73389f3df11e788bf84254a7b27c430f949 Mon Sep 17 00:00:00 2001 From: Benoit Goby Date: Fri, 20 Jan 2012 14:42:41 -0800 Subject: [PATCH 0656/4025] usb: gadget: Fix usb string id allocation Don't reset next_string_id every time the gadget is enabled, this makes the next strings allocated overwrite strings allocated at probe time. Instead, fix rndis not to allocate new string ids on every config bind. Change-Id: Ied28ee416bb6f00c434c34176fe5b7f0dcb2b2d4 Signed-off-by: Benoit Goby --- drivers/usb/gadget/android.c | 1 - drivers/usb/gadget/f_rndis.c | 12 +++++------- drivers/usb/gadget/rndis.c | 11 +++++++++++ 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 00a446bce3f..54f80e79de6 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -840,7 +840,6 @@ static ssize_t enable_store(struct device *pdev, struct device_attribute *attr, sscanf(buff, "%d", &enabled); if (enabled && !dev->enabled) { - cdev->next_string_id = 0; /* update values in composite driver's copy of device descriptor */ cdev->desc.idVendor = device_desc.idVendor; cdev->desc.idProduct = device_desc.idProduct; diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index d03b11b51c8..96adf45d44c 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -755,8 +755,6 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f) rndis_deregister(rndis->config); rndis_exit(); - rndis_string_defs[0].id = 0; - if (gadget_is_dualspeed(c->cdev->gadget)) usb_free_descriptors(f->hs_descriptors); usb_free_descriptors(f->descriptors); @@ -796,14 +794,14 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], if (!can_support_rndis(c) || !ethaddr) return -EINVAL; + /* setup RNDIS itself */ + status = rndis_init(); + if (status < 0) + return status; + /* maybe allocate device-global string IDs */ if (rndis_string_defs[0].id == 0) { - /* ... and setup RNDIS itself */ - status = rndis_init(); - if (status < 0) - return status; - /* control interface label */ status = usb_string_id(c->cdev); if (status < 0) diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index d3cdffea9c8..bbfbde74159 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -1147,11 +1147,15 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS]; #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ +static bool rndis_initialized; int rndis_init(void) { u8 i; + if (rndis_initialized) + return 0; + for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { #ifdef CONFIG_USB_GADGET_DEBUG_FILES char name [20]; @@ -1178,6 +1182,7 @@ int rndis_init(void) INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue)); } + rndis_initialized = true; return 0; } @@ -1186,7 +1191,13 @@ void rndis_exit(void) #ifdef CONFIG_USB_GADGET_DEBUG_FILES u8 i; char name[20]; +#endif + if (!rndis_initialized) + return; + rndis_initialized = false; + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { sprintf(name, NAME_TEMPLATE, i); remove_proc_entry(name, NULL); From 09701e3edf03f92f4215aad83b32cd8cec7fb689 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Wed, 18 Jan 2012 15:56:51 -0800 Subject: [PATCH 0657/4025] usb: gadget: android: Honor CONFIG_USB_GADGET_VBUS_DRAW The maximum current draw was hard coded to 500 mA. composite.c has code that uses CONFIG_USB_GADGET_VBUS_DRAW to set the bMaxPower and to set whether or not the device is self-powered if they haven't been set. This change removes the code in android.c to allow composite.c to set them. Change-Id: I9db37922e91ee86e9e5c0e14519e119e5c41ca48 Signed-off-by: Scott Anderson --- drivers/usb/gadget/android.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c index 54f80e79de6..8df739c1a84 100644 --- a/drivers/usb/gadget/android.c +++ b/drivers/usb/gadget/android.c @@ -153,8 +153,6 @@ static struct usb_configuration android_config_driver = { .label = "android", .unbind = android_unbind_config, .bConfigurationValue = 1, - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = 0xFA, /* 500ma */ }; static void android_work(struct work_struct *data) @@ -1033,7 +1031,6 @@ static int android_bind(struct usb_composite_dev *cdev) device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); } - usb_gadget_set_selfpowered(gadget); dev->cdev = cdev; return 0; From 63f0d35a610b2ef1139b5d763ee74cab5257a8c8 Mon Sep 17 00:00:00 2001 From: Roman Tereshonkov Date: Tue, 29 Nov 2011 12:49:18 +0200 Subject: [PATCH 0658/4025] mtdoops: fix the oops_page_used array size commit 556f063580db2953a7e53cd46b47724246320f60 upstream. The array of unsigned long pointed by oops_page_used is allocated by vmalloc which requires the size to be in bytes. BITS_PER_LONG is equal to 32. If we want to allocate memory for 32 pages with one bit per page then 32 / BITS_PER_LONG is equal to 1 byte that is 8 bits. To fix it we need to multiply the result by sizeof(unsigned long) equal to 4. Signed-off-by: Roman Tereshonkov Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/mtdoops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index e3e40f44032..02eeed3f9a4 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -369,7 +369,7 @@ static void mtdoops_notify_add(struct mtd_info *mtd) /* oops_page_used is a bit field */ cxt->oops_page_used = vmalloc(DIV_ROUND_UP(mtdoops_pages, - BITS_PER_LONG)); + BITS_PER_LONG) * sizeof(unsigned long)); if (!cxt->oops_page_used) { printk(KERN_ERR "mtdoops: could not allocate page array\n"); return; From 13205eedda9d80daf129ddad54bd6ffe5df92dff Mon Sep 17 00:00:00 2001 From: Roman Tereshonkov Date: Fri, 2 Dec 2011 15:07:17 +0200 Subject: [PATCH 0659/4025] mtd: mtdoops: skip reading initially bad blocks commit 3538c56329936c78f7d356889908790006d0124c upstream. Use block_isbad to check and skip the bad blocks reading. This will allow to get rid of the read errors if bad blocks are present initially. Signed-off-by: Roman Tereshonkov Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/mtdoops.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index 02eeed3f9a4..43130e8acea 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -253,6 +253,9 @@ static void find_next_position(struct mtdoops_context *cxt) size_t retlen; for (page = 0; page < cxt->oops_pages; page++) { + if (mtd->block_isbad && + mtd->block_isbad(mtd, page * record_size)) + continue; /* Assume the page is used */ mark_page_used(cxt, page); ret = mtd->read(mtd, page * record_size, MTDOOPS_HEADER_SIZE, From 488e572df737befdfc783503642d70ea18b3a001 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 7 Nov 2011 15:51:05 -0800 Subject: [PATCH 0660/4025] mtd: mtd_blkdevs: don't increase 'open' count on error path commit 342ff28f5a2e5aa3236617bd2bddf6c749677ef2 upstream. Some error paths in mtd_blkdevs were fixed in the following commit: commit 94735ec4044a6d318b83ad3c5794e931ed168d10 mtd: mtd_blkdevs: fix error path in blktrans_open But on these error paths, the block device's `dev->open' count is already incremented before we check for errors. This meant that, while the error path was handled correctly on the first time through blktrans_open(), the device is erroneously considered already open on the second time through. This problem can be seen, for instance, when a UBI volume is simultaneously mounted as a UBIFS partition and read through its corresponding gluebi mtdblockX device. This results in blktrans_open() passing its error checks (with `dev->open > 0') without actually having a handle on the device. Here's a summarized log of the actions and results with nandsim: # modprobe nandsim # modprobe mtdblock # modprobe gluebi # modprobe ubifs # ubiattach /dev/ubi_ctrl -m 0 ... # ubimkvol /dev/ubi0 -N test -s 16MiB ... # mount -t ubifs ubi0:test /mnt # ls /dev/mtdblock* /dev/mtdblock0 /dev/mtdblock1 # cat /dev/mtdblock1 > /dev/null cat: can't open '/dev/mtdblock4': Device or resource busy # cat /dev/mtdblock1 > /dev/null CPU 0 Unable to handle kernel paging request at virtual address fffffff0, epc == 8031536c, ra == 8031f280 Oops[#1]: ... Call Trace: [<8031536c>] ubi_leb_read+0x14/0x164 [<8031f280>] gluebi_read+0xf0/0x148 [<802edba8>] mtdblock_readsect+0x64/0x198 [<802ecfe4>] mtd_blktrans_thread+0x330/0x3f4 [<8005be98>] kthread+0x88/0x90 [<8000bc04>] kernel_thread_helper+0x10/0x18 Signed-off-by: Brian Norris Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/mtd_blkdevs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index ca385697446..bff8d4671ad 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -215,7 +215,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode) mutex_lock(&dev->lock); - if (dev->open++) + if (dev->open) goto unlock; kref_get(&dev->ref); @@ -235,6 +235,7 @@ static int blktrans_open(struct block_device *bdev, fmode_t mode) goto error_release; unlock: + dev->open++; mutex_unlock(&dev->lock); blktrans_dev_put(dev); return ret; From f3a6e79c583423a55f7068ccdad732a5f4a0faad Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 29 Nov 2011 15:34:08 +0100 Subject: [PATCH 0661/4025] mtd: tests: stresstest: bail out if device has not enough eraseblocks commit 2f4478ccff7df845dc9c0f8996a96373122c4417 upstream. stresstest needs at least two eraseblocks. Bail out gracefully if that condition is not met. Fixes the following 'division by zero' OOPS: [ 619.100000] mtd_stresstest: MTD device size 131072, eraseblock size 131072, page size 2048, count of eraseblocks 1, pages per eraseblock 64, OOB size 64 [ 619.120000] mtd_stresstest: scanning for bad eraseblocks [ 619.120000] mtd_stresstest: scanned 1 eraseblocks, 0 are bad [ 619.130000] mtd_stresstest: doing operations [ 619.130000] mtd_stresstest: 0 operations done [ 619.140000] Division by zero in kernel. ... caused by /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */ eb %= (ebcnt - 1); Signed-off-by: Wolfram Sang Signed-off-by: Artem Bityutskiy Signed-off-by: David Woodhouse Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/tests/mtd_stresstest.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c index 531625fc925..129bad2e408 100644 --- a/drivers/mtd/tests/mtd_stresstest.c +++ b/drivers/mtd/tests/mtd_stresstest.c @@ -277,6 +277,12 @@ static int __init mtd_stresstest_init(void) (unsigned long long)mtd->size, mtd->erasesize, pgsize, ebcnt, pgcnt, mtd->oobsize); + if (ebcnt < 2) { + printk(PRINT_PREF "error: need at least 2 eraseblocks\n"); + err = -ENOSPC; + goto out_put_mtd; + } + /* Read or write up 2 eraseblocks at a time */ bufsize = mtd->erasesize * 2; @@ -315,6 +321,7 @@ static int __init mtd_stresstest_init(void) kfree(bbt); vfree(writebuf); vfree(readbuf); +out_put_mtd: put_mtd_device(mtd); if (err) printk(PRINT_PREF "error %d occurred\n", err); From 922d41ed4740408d2719a8c99d9f80138e562c03 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 10 Jan 2012 15:11:02 -0800 Subject: [PATCH 0662/4025] drivers/rtc/interface.c: fix alarm rollover when day or month is out-of-range commit e74a8f2edb92cb690b467cea0ab652c509e9f624 upstream. Commit f44f7f96a20a ("RTC: Initialize kernel state from RTC") introduced a potential infinite loop. If an alarm time contains a wildcard month and an invalid day (> 31), or a wildcard year and an invalid month (>= 12), the loop searching for the next matching date will never terminate. Treat the invalid values as wildcards. Fixes , Reported-by: leo weppelman Reported-by: "P. van Gaans" Signed-off-by: Ben Hutchings Signed-off-by: Jonathan Nieder Cc: Mark Brown Cc: Marcelo Roberto Jimenez Cc: Thomas Gleixner Cc: John Stultz Acked-by: Alessandro Zummo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index eb4c88316a1..38d1dc74b2c 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -227,11 +227,11 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) alarm->time.tm_hour = now.tm_hour; /* For simplicity, only support date rollover for now */ - if (alarm->time.tm_mday == -1) { + if (alarm->time.tm_mday < 1 || alarm->time.tm_mday > 31) { alarm->time.tm_mday = now.tm_mday; missing = day; } - if (alarm->time.tm_mon == -1) { + if ((unsigned)alarm->time.tm_mon >= 12) { alarm->time.tm_mon = now.tm_mon; if (missing == none) missing = month; From 0146b288f47cc3ef3f0791b3023643ccdeeeb339 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Tue, 10 Jan 2012 11:51:10 -0500 Subject: [PATCH 0663/4025] ext4: fix undefined behavior in ext4_fill_flex_info() commit d50f2ab6f050311dbf7b8f5501b25f0bf64a439b upstream. Commit 503358ae01b70ce6909d19dd01287093f6b6271c ("ext4: avoid divide by zero when trying to mount a corrupted file system") fixes CVE-2009-4307 by performing a sanity check on s_log_groups_per_flex, since it can be set to a bogus value by an attacker. sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex; groups_per_flex = 1 << sbi->s_log_groups_per_flex; if (groups_per_flex < 2) { ... } This patch fixes two potential issues in the previous commit. 1) The sanity check might only work on architectures like PowerPC. On x86, 5 bits are used for the shifting amount. That means, given a large s_log_groups_per_flex value like 36, groups_per_flex = 1 << 36 is essentially 1 << 4 = 16, rather than 0. This will bypass the check, leaving s_log_groups_per_flex and groups_per_flex inconsistent. 2) The sanity check relies on undefined behavior, i.e., oversized shift. A standard-confirming C compiler could rewrite the check in unexpected ways. Consider the following equivalent form, assuming groups_per_flex is unsigned for simplicity. groups_per_flex = 1 << sbi->s_log_groups_per_flex; if (groups_per_flex == 0 || groups_per_flex == 1) { We compile the code snippet using Clang 3.0 and GCC 4.6. Clang will completely optimize away the check groups_per_flex == 0, leaving the patched code as vulnerable as the original. GCC keeps the check, but there is no guarantee that future versions will do the same. Signed-off-by: Xi Wang Signed-off-by: "Theodore Ts'o" Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 7aa77f04917..df121b20b0d 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1957,17 +1957,16 @@ static int ext4_fill_flex_info(struct super_block *sb) struct ext4_group_desc *gdp = NULL; ext4_group_t flex_group_count; ext4_group_t flex_group; - int groups_per_flex = 0; + unsigned int groups_per_flex = 0; size_t size; int i; sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex; - groups_per_flex = 1 << sbi->s_log_groups_per_flex; - - if (groups_per_flex < 2) { + if (sbi->s_log_groups_per_flex < 1 || sbi->s_log_groups_per_flex > 31) { sbi->s_log_groups_per_flex = 0; return 1; } + groups_per_flex = 1 << sbi->s_log_groups_per_flex; /* We allocate both existing and potentially added groups */ flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) + From 730580b66c412cd8fbe9c7077ce42c55a85e6281 Mon Sep 17 00:00:00 2001 From: Karsten Wiese Date: Fri, 30 Dec 2011 01:42:01 +0100 Subject: [PATCH 0664/4025] ALSA: snd-usb-us122l: Delete calls to preempt_disable commit d0f3a2eb9062560bebca8b923424f3ca02a331ba upstream. They are not needed here. Signed-off-by: Karsten Wiese Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/usx2y/usb_stream.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/usb/usx2y/usb_stream.c b/sound/usb/usx2y/usb_stream.c index c400ade3ff0..1e7a47a8660 100644 --- a/sound/usb/usx2y/usb_stream.c +++ b/sound/usb/usx2y/usb_stream.c @@ -674,7 +674,7 @@ int usb_stream_start(struct usb_stream_kernel *sk) inurb->transfer_buffer_length = inurb->number_of_packets * inurb->iso_frame_desc[0].length; - preempt_disable(); + if (u == 0) { int now; struct usb_device *dev = inurb->dev; @@ -686,19 +686,17 @@ int usb_stream_start(struct usb_stream_kernel *sk) } err = usb_submit_urb(inurb, GFP_ATOMIC); if (err < 0) { - preempt_enable(); snd_printk(KERN_ERR"usb_submit_urb(sk->inurb[%i])" " returned %i\n", u, err); return err; } err = usb_submit_urb(outurb, GFP_ATOMIC); if (err < 0) { - preempt_enable(); snd_printk(KERN_ERR"usb_submit_urb(sk->outurb[%i])" " returned %i\n", u, err); return err; } - preempt_enable(); + if (inurb->start_frame != outurb->start_frame) { snd_printd(KERN_DEBUG "u[%i] start_frames differ in:%u out:%u\n", From 35cdd5ea88762e22c9d21c5c826cbd7ef1edd7db Mon Sep 17 00:00:00 2001 From: Pavel Hofman Date: Thu, 5 Jan 2012 23:05:18 +0100 Subject: [PATCH 0665/4025] ALSA: ice1724 - Check for ac97 to avoid kernel oops commit e7848163aa2a649d9065f230fadff80dc3519775 upstream. Cards with identical PCI ids but no AC97 config in EEPROM do not have the ac97 field initialized. We must check for this case to avoid kernel oops. Signed-off-by: Pavel Hofman Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/ice1712/amp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c index e328cfb7620..e525da2673b 100644 --- a/sound/pci/ice1712/amp.c +++ b/sound/pci/ice1712/amp.c @@ -68,8 +68,11 @@ static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice) static int __devinit snd_vt1724_amp_add_controls(struct snd_ice1712 *ice) { - /* we use pins 39 and 41 of the VT1616 for left and right read outputs */ - snd_ac97_write_cache(ice->ac97, 0x5a, snd_ac97_read(ice->ac97, 0x5a) & ~0x8000); + if (ice->ac97) + /* we use pins 39 and 41 of the VT1616 for left and right + read outputs */ + snd_ac97_write_cache(ice->ac97, 0x5a, + snd_ac97_read(ice->ac97, 0x5a) & ~0x8000); return 0; } From 24973a17310bd933969d79cf4080049df85aff2c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 10 Jan 2012 12:41:22 +0100 Subject: [PATCH 0666/4025] ALSA: hda - Return the error from get_wcaps_type() for invalid NIDs commit 3a90274de3548ebb2aabfbf488cea8e275a73dc6 upstream. When an invalid NID is given, get_wcaps() returns zero as the error, but get_wcaps_type() takes it as the normal value and returns a bogus AC_WID_AUD_OUT value. This confuses the parser. With this patch, get_wcaps_type() returns -1 when value 0 is given, i.e. an invalid NID is passed to get_wcaps(). Bugzilla: https://bugzilla.novell.com/show_bug.cgi?id=740118 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_local.h | 7 ++++++- sound/pci/hda/hda_proc.c | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 08ec073444e..e289a13c488 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -474,7 +474,12 @@ static inline u32 get_wcaps(struct hda_codec *codec, hda_nid_t nid) } /* get the widget type from widget capability bits */ -#define get_wcaps_type(wcaps) (((wcaps) & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT) +static inline int get_wcaps_type(unsigned int wcaps) +{ + if (!wcaps) + return -1; /* invalid type */ + return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; +} static inline unsigned int get_wcaps_channels(u32 wcaps) { diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index bfe74c2fb07..6fe944a386c 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -54,6 +54,8 @@ static const char *get_wid_type_name(unsigned int wid_value) [AC_WID_BEEP] = "Beep Generator Widget", [AC_WID_VENDOR] = "Vendor Defined Widget", }; + if (wid_value == -1) + return "UNKNOWN Widget"; wid_value &= 0xf; if (names[wid_value]) return names[wid_value]; From b48620dfff7a12774bb83348a88eddb5921dcdd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Fri, 23 Dec 2011 20:32:18 +0100 Subject: [PATCH 0667/4025] drm/radeon/kms: workaround invalid AVI infoframe checksum issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 92db7f6c860b8190571a9dc1fcbc16d003422fe8 upstream. This change was verified to fix both issues with no video I've investigated. I've also checked checksum calculation with fglrx on: RV620, HD54xx, HD5450, HD6310, HD6320. Signed-off-by: Rafał Miłecki Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/r600_hdmi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index f5ac7e788d8..c45d92191fd 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -196,6 +196,13 @@ static void r600_hdmi_videoinfoframe( frame[0xD] = (right_bar >> 8); r600_hdmi_infoframe_checksum(0x82, 0x02, 0x0D, frame); + /* Our header values (type, version, length) should be alright, Intel + * is using the same. Checksum function also seems to be OK, it works + * fine for audio infoframe. However calculated value is always lower + * by 2 in comparison to fglrx. It breaks displaying anything in case + * of TVs that strictly check the checksum. Hack it manually here to + * workaround this issue. */ + frame[0x0] += 2; WREG32(offset+R600_HDMI_VIDEOINFOFRAME_0, frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24)); From a674b8b3e345496a96aec389446650455b2fdfa1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 3 Jan 2012 09:48:38 -0500 Subject: [PATCH 0668/4025] drm/radeon/kms: disable writeback on pre-R300 asics commit 28eebb703e28bc455ba704adb1026f76649b768c upstream. We often end up missing fences on older asics with writeback enabled which leads to delays in the userspace accel code, so just disable it by default on those asics. Reported-by: Helge Deller Reported-by: Dave Airlie Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_device.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 440e6ecccc4..5d0c1236dd4 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -223,8 +223,11 @@ int radeon_wb_init(struct radeon_device *rdev) if (radeon_no_wb == 1) rdev->wb.enabled = false; else { - /* often unreliable on AGP */ if (rdev->flags & RADEON_IS_AGP) { + /* often unreliable on AGP */ + rdev->wb.enabled = false; + } else if (rdev->family < CHIP_R300) { + /* often unreliable on pre-r300 */ rdev->wb.enabled = false; } else { rdev->wb.enabled = true; From be2ef85142e6f00c7f6c8842d903701bdf88cb5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Thu, 5 Jan 2012 18:42:17 +0100 Subject: [PATCH 0669/4025] radeon: Fix disabling PCI bus mastering on big endian hosts. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 3df96909b75835d487a9178761622b0cbd7310d4 upstream. It would previously write basically random bits to PCI configuration space... Not very surprising that the GPU tended to stop responding completely. The resulting MCE even froze the whole machine sometimes. Now resetting the GPU after a lockup has at least a fighting chance of succeeding. Signed-off-by: Michel Dänzer Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/r100.c | 5 +++-- drivers/gpu/drm/radeon/rs600.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index b94d871487e..764249587f1 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -2069,6 +2069,7 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev) void r100_bm_disable(struct radeon_device *rdev) { u32 tmp; + u16 tmp16; /* disable bus mastering */ tmp = RREG32(R_000030_BUS_CNTL); @@ -2079,8 +2080,8 @@ void r100_bm_disable(struct radeon_device *rdev) WREG32(R_000030_BUS_CNTL, (tmp & 0xFFFFFFFF) | 0x00000040); tmp = RREG32(RADEON_BUS_CNTL); mdelay(1); - pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp); - pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB); + pci_read_config_word(rdev->pdev, 0x4, &tmp16); + pci_write_config_word(rdev->pdev, 0x4, tmp16 & 0xFFFB); mdelay(1); } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index a37a1efdd22..21acfb5449a 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -324,10 +324,10 @@ void rs600_hpd_fini(struct radeon_device *rdev) void rs600_bm_disable(struct radeon_device *rdev) { - u32 tmp; + u16 tmp; /* disable bus mastering */ - pci_read_config_word(rdev->pdev, 0x4, (u16*)&tmp); + pci_read_config_word(rdev->pdev, 0x4, &tmp); pci_write_config_word(rdev->pdev, 0x4, tmp & 0xFFFB); mdelay(1); } From 2dda99b3d5f3f6be05f0c9cc7cf0b05740e6e9f5 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Mon, 5 Dec 2011 15:40:30 -0500 Subject: [PATCH 0670/4025] NFS: Retry mounting NFSROOT commit 43717c7daebf10b43f12e68512484b3095bb1ba5 upstream. Lukas Razik reports that on his SPARC system, booting with an NFS root file system stopped working after commit 56463e50 "NFS: Use super.c for NFSROOT mount option parsing." We found that the network switch to which Lukas' client was attached was delaying access to the LAN after the client's NIC driver reported that its link was up. The delay was longer than the timeouts used in the NFS client during mounting. NFSROOT worked for Lukas before commit 56463e50 because in those kernels, the client's first operation was an rpcbind request to determine which port the NFS server was listening on. When that request failed after a long timeout, the client simply selected the default NFS port (2049). By that time the switch was allowing access to the LAN, and the mount succeeded. Neither of these client behaviors is desirable, so reverting 56463e50 is really not a choice. Instead, introduce a mechanism that retries the NFSROOT mount request several times. This is the same tactic that normal user space NFS mounts employ to overcome server and network delays. Signed-off-by: Lukas Razik [ cel: match kernel coding style, add proper patch description ] [ cel: add exponential back-off ] Signed-off-by: Chuck Lever Tested-by: Lukas Razik Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- init/do_mounts.c | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/init/do_mounts.c b/init/do_mounts.c index c0851a8e030..ef6478fbb54 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -360,15 +360,42 @@ void __init mount_block_root(char *name, int flags) } #ifdef CONFIG_ROOT_NFS + +#define NFSROOT_TIMEOUT_MIN 5 +#define NFSROOT_TIMEOUT_MAX 30 +#define NFSROOT_RETRY_MAX 5 + static int __init mount_nfs_root(void) { char *root_dev, *root_data; + unsigned int timeout; + int try, err; - if (nfs_root_data(&root_dev, &root_data) != 0) - return 0; - if (do_mount_root(root_dev, "nfs", root_mountflags, root_data) != 0) + err = nfs_root_data(&root_dev, &root_data); + if (err != 0) return 0; - return 1; + + /* + * The server or network may not be ready, so try several + * times. Stop after a few tries in case the client wants + * to fall back to other boot methods. + */ + timeout = NFSROOT_TIMEOUT_MIN; + for (try = 1; ; try++) { + err = do_mount_root(root_dev, "nfs", + root_mountflags, root_data); + if (err == 0) + return 1; + if (try > NFSROOT_RETRY_MAX) + break; + + /* Wait, in case the server refused us immediately */ + ssleep(timeout); + timeout <<= 1; + if (timeout > NFSROOT_TIMEOUT_MAX) + timeout = NFSROOT_TIMEOUT_MAX; + } + return 0; } #endif From 58a902db8896b6bb4c779a223f6e8e7b289cdcc9 Mon Sep 17 00:00:00 2001 From: Andy Adamson Date: Wed, 9 Nov 2011 13:58:20 -0500 Subject: [PATCH 0671/4025] NFSv4.1: fix backchannel slotid off-by-one bug commit 61f2e5106582d02f30b6807e3f9c07463c572ccb upstream. Signed-off-by: Andy Adamson Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/callback_proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index aaa09e948a9..b5c826e17b6 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -324,7 +324,7 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args) dprintk("%s enter. slotid %d seqid %d\n", __func__, args->csa_slotid, args->csa_sequenceid); - if (args->csa_slotid > NFS41_BC_MAX_CALLBACKS) + if (args->csa_slotid >= NFS41_BC_MAX_CALLBACKS) return htonl(NFS4ERR_BADSLOT); slot = tbl->slots + args->csa_slotid; From dbbef3cbdef5e2363caeb343efa68650f20d7bfc Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 20 Dec 2011 06:57:45 -0500 Subject: [PATCH 0672/4025] nfs: fix regression in handling of context= option in NFSv4 commit 8a0d551a59ac92d8ff048d6cb29d3a02073e81e8 upstream. Setting the security context of a NFSv4 mount via the context= mount option is currently broken. The NFSv4 codepath allocates a parsed options struct, and then parses the mount options to fill it. It eventually calls nfs4_remote_mount which calls security_init_mnt_opts. That clobbers the lsm_opts struct that was populated earlier. This bug also looks like it causes a small memory leak on each v4 mount where context= is used. Fix this by moving the initialization of the lsm_opts into nfs_alloc_parsed_mount_data. Also, add a destructor for nfs_parsed_mount_data to make it easier to free all of the allocations hanging off of it, and to ensure that the security_free_mnt_opts is called whenever security_init_mnt_opts is. I believe this regression was introduced quite some time ago, probably by commit c02d7adf. Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/super.c | 43 +++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 858d31be29c..7e8b07d4fa0 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -904,10 +904,24 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int ve data->auth_flavor_len = 1; data->version = version; data->minorversion = 0; + security_init_mnt_opts(&data->lsm_opts); } return data; } +static void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data) +{ + if (data) { + kfree(data->client_address); + kfree(data->mount_server.hostname); + kfree(data->nfs_server.export_path); + kfree(data->nfs_server.hostname); + kfree(data->fscache_uniq); + security_free_mnt_opts(&data->lsm_opts); + kfree(data); + } +} + /* * Sanity-check a server address provided by the mount command. * @@ -2218,9 +2232,7 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type, data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION); mntfh = nfs_alloc_fhandle(); if (data == NULL || mntfh == NULL) - goto out_free_fh; - - security_init_mnt_opts(&data->lsm_opts); + goto out; /* Validate the mount data */ error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name); @@ -2232,8 +2244,6 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type, #ifdef CONFIG_NFS_V4 if (data->version == 4) { mntroot = nfs4_try_mount(flags, dev_name, data); - kfree(data->client_address); - kfree(data->nfs_server.export_path); goto out; } #endif /* CONFIG_NFS_V4 */ @@ -2284,13 +2294,8 @@ static struct dentry *nfs_fs_mount(struct file_system_type *fs_type, s->s_flags |= MS_ACTIVE; out: - kfree(data->nfs_server.hostname); - kfree(data->mount_server.hostname); - kfree(data->fscache_uniq); - security_free_mnt_opts(&data->lsm_opts); -out_free_fh: + nfs_free_parsed_mount_data(data); nfs_free_fhandle(mntfh); - kfree(data); return mntroot; out_err_nosb: @@ -2613,9 +2618,7 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags, mntfh = nfs_alloc_fhandle(); if (data == NULL || mntfh == NULL) - goto out_free_fh; - - security_init_mnt_opts(&data->lsm_opts); + goto out; /* Get a volume representation */ server = nfs4_create_server(data, mntfh); @@ -2663,13 +2666,10 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags, s->s_flags |= MS_ACTIVE; - security_free_mnt_opts(&data->lsm_opts); nfs_free_fhandle(mntfh); return mntroot; out: - security_free_mnt_opts(&data->lsm_opts); -out_free_fh: nfs_free_fhandle(mntfh); return ERR_PTR(error); @@ -2855,7 +2855,7 @@ static struct dentry *nfs4_mount(struct file_system_type *fs_type, data = nfs_alloc_parsed_mount_data(4); if (data == NULL) - goto out_free_data; + goto out; /* Validate the mount data */ error = nfs4_validate_mount_data(raw_data, data, dev_name); @@ -2869,12 +2869,7 @@ static struct dentry *nfs4_mount(struct file_system_type *fs_type, error = PTR_ERR(res); out: - kfree(data->client_address); - kfree(data->nfs_server.export_path); - kfree(data->nfs_server.hostname); - kfree(data->fscache_uniq); -out_free_data: - kfree(data); + nfs_free_parsed_mount_data(data); dprintk("<-- nfs4_mount() = %d%s\n", error, error != 0 ? " [error]" : ""); return res; From 729a9768761809079d07c9716f656da20a14eb2f Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Mon, 7 Nov 2011 11:08:05 -0800 Subject: [PATCH 0673/4025] HID: bump maximum global item tag report size to 96 bytes commit e46e927b9b7e8d95526e69322855243882b7e1a3 upstream. This allows the latest N-Trig devices to function properly. BugLink: https://bugs.launchpad.net/bugs/724831 Signed-off-by: Chase Douglas Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 763797da2d8..22d53e7a223 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -361,7 +361,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: parser->global.report_size = item_udata(item); - if (parser->global.report_size > 32) { + if (parser->global.report_size > 96) { dbg_hid("invalid report_size %d\n", parser->global.report_size); return -1; From 75947f78d026b6eb2c4f16c54042325f97e3288a Mon Sep 17 00:00:00 2001 From: Bhavesh Parekh Date: Wed, 30 Nov 2011 17:43:42 +0530 Subject: [PATCH 0674/4025] UBI: fix missing scrub when there is a bit-flip commit e801e128b2200c40a0ec236cf2330b2586b6e05a upstream. Under some cases, when scrubbing the PEB if we did not get the lock on the PEB it fails to scrub. Add that PEB again to the scrub list Artem: minor amendments. Signed-off-by: Bhavesh Parekh Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/eba.c | 6 ++++-- drivers/mtd/ubi/ubi.h | 2 ++ drivers/mtd/ubi/wl.c | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 4be67181501..c696c9481c9 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -1028,12 +1028,14 @@ int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the * LEB is already locked, we just do not move it and return - * %MOVE_CANCEL_RACE, which means that UBI will re-try, but later. + * %MOVE_RETRY. Note, we do not return %MOVE_CANCEL_RACE here because + * we do not know the reasons of the contention - it may be just a + * normal I/O on this LEB, so we want to re-try. */ err = leb_write_trylock(ubi, vol_id, lnum); if (err) { dbg_wl("contention on LEB %d:%d, cancel", vol_id, lnum); - return MOVE_CANCEL_RACE; + return MOVE_RETRY; } /* diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index c6c22295898..bbfa88d459e 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -121,6 +121,7 @@ enum { * PEB * MOVE_CANCEL_BITFLIPS: canceled because a bit-flip was detected in the * target PEB + * MOVE_RETRY: retry scrubbing the PEB */ enum { MOVE_CANCEL_RACE = 1, @@ -128,6 +129,7 @@ enum { MOVE_TARGET_RD_ERR, MOVE_TARGET_WR_ERR, MOVE_CANCEL_BITFLIPS, + MOVE_RETRY, }; /** diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index ff2c4956eef..f268adeb95e 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -792,7 +792,10 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, protect = 1; goto out_not_moved; } - + if (err == MOVE_RETRY) { + scrubbing = 1; + goto out_not_moved; + } if (err == MOVE_CANCEL_BITFLIPS || err == MOVE_TARGET_WR_ERR || err == MOVE_TARGET_RD_ERR) { /* From c16686fc0c9c8f6fa46741e50c6ab621ab507cf9 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Thu, 5 Jan 2012 10:47:18 +0200 Subject: [PATCH 0675/4025] UBI: fix use-after-free on error path commit e57e0d8e818512047fe379157c3f77f1b9fabffb upstream. When we fail to erase a PEB, we free the corresponding erase entry object, but then re-schedule this object if the error code was something like -EAGAIN. Obviously, it is a bug to use the object after we have freed it. Reported-by: Emese Revfy Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/wl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c index f268adeb95e..12e44c90b32 100644 --- a/drivers/mtd/ubi/wl.c +++ b/drivers/mtd/ubi/wl.c @@ -1049,7 +1049,6 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, ubi_err("failed to erase PEB %d, error %d", pnum, err); kfree(wl_wrk); - kmem_cache_free(ubi_wl_entry_slab, e); if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || err == -EBUSY) { @@ -1062,14 +1061,16 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, goto out_ro; } return err; - } else if (err != -EIO) { + } + + kmem_cache_free(ubi_wl_entry_slab, e); + if (err != -EIO) /* * If this is not %-EIO, we have no idea what to do. Scheduling * this physical eraseblock for erasure again would cause * errors again and again. Well, lets switch to R/O mode. */ goto out_ro; - } /* It is %-EIO, the PEB went bad */ From 58f98e86f9138e283b98766541727af91a58e849 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Wed, 16 Nov 2011 09:24:16 -0700 Subject: [PATCH 0676/4025] PCI: Fix PCI_EXP_TYPE_RC_EC value commit 1830ea91c20b06608f7cdb2455ce05ba834b3214 upstream. Spec shows this as 1010b = 0xa Signed-off-by: Alex Williamson Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- include/linux/pci_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h index e8840964aca..dad7d9a4abc 100644 --- a/include/linux/pci_regs.h +++ b/include/linux/pci_regs.h @@ -392,7 +392,7 @@ #define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ #define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */ #define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */ -#define PCI_EXP_TYPE_RC_EC 0x10 /* Root Complex Event Collector */ +#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */ #define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ #define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ #define PCI_EXP_DEVCAP 4 /* Device capabilities */ From 65d61b46700e059210b4c9f63355d57dc0e1a18e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 17 Oct 2011 11:46:06 -0700 Subject: [PATCH 0677/4025] PCI: msi: Disable msi interrupts when we initialize a pci device commit a776c491ca5e38c26d9f66923ff574d041e747f4 upstream. I traced a nasty kexec on panic boot failure to the fact that we had screaming msi interrupts and we were not disabling the msi messages at kernel startup. The booting kernel had not enabled those interupts so was not prepared to handle them. I can see no reason why we would ever want to leave the msi interrupts enabled at boot if something else has enabled those interrupts. The pci spec specifies that msi interrupts should be off by default. Drivers are expected to enable the msi interrupts if they want to use them. Our interrupt handling code reprograms the interrupt handlers at boot and will not be be able to do anything useful with an unexpected interrupt. This patch applies cleanly all of the way back to 2.6.32 where I noticed the problem. Signed-off-by: Eric W. Biederman Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- drivers/pci/msi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 2f10328bf66..e1749825008 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -869,5 +869,15 @@ EXPORT_SYMBOL(pci_msi_enabled); void pci_msi_init_pci_dev(struct pci_dev *dev) { + int pos; INIT_LIST_HEAD(&dev->msi_list); + + /* Disable the msi hardware to avoid screaming interrupts + * during boot. This is the power on reset default so + * usually this should be a noop. + */ + pos = pci_find_capability(dev, PCI_CAP_ID_MSI); + if (pos) + msi_set_enable(dev, pos, 0); + msix_set_enable(dev, 0); } From 0a4179971477550df61b9218e664eb9128abf2e3 Mon Sep 17 00:00:00 2001 From: Gary Hade Date: Mon, 14 Nov 2011 15:42:16 -0800 Subject: [PATCH 0678/4025] x86/PCI: Ignore CPU non-addressable _CRS reserved memory resources commit ae5cd86455381282ece162966183d3f208c6fad7 upstream. This assures that a _CRS reserved host bridge window or window region is not used if it is not addressable by the CPU. The new code either trims the window to exclude the non-addressable portion or totally ignores the window if the entire window is non-addressable. The current code has been shown to be problematic with 32-bit non-PAE kernels on systems where _CRS reserves resources above 4GB. Signed-off-by: Gary Hade Reviewed-by: Bjorn Helgaas Cc: Thomas Renninger Cc: linux-kernel@vger.kernel.org Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- arch/x86/pci/acpi.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 50b3f14c59a..53f9e684c81 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -149,7 +149,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data) struct acpi_resource_address64 addr; acpi_status status; unsigned long flags; - u64 start, end; + u64 start, orig_end, end; status = resource_to_addr(acpi_res, &addr); if (!ACPI_SUCCESS(status)) @@ -165,7 +165,21 @@ setup_resource(struct acpi_resource *acpi_res, void *data) return AE_OK; start = addr.minimum + addr.translation_offset; - end = addr.maximum + addr.translation_offset; + orig_end = end = addr.maximum + addr.translation_offset; + + /* Exclude non-addressable range or non-addressable portion of range */ + end = min(end, (u64)iomem_resource.end); + if (end <= start) { + dev_info(&info->bridge->dev, + "host bridge window [%#llx-%#llx] " + "(ignored, not CPU addressable)\n", start, orig_end); + return AE_OK; + } else if (orig_end != end) { + dev_info(&info->bridge->dev, + "host bridge window [%#llx-%#llx] " + "([%#llx-%#llx] ignored, not CPU addressable)\n", + start, orig_end, end + 1, orig_end); + } res = &info->res[info->res_num]; res->name = info->name; From 45e7e24360e799f7753f37ca5642a0d6e29b9c62 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 5 Jan 2012 14:27:19 -0700 Subject: [PATCH 0679/4025] x86/PCI: amd: factor out MMCONFIG discovery commit 24d25dbfa63c376323096660bfa9ad45a08870ce upstream. This factors out the AMD native MMCONFIG discovery so we can use it outside amd_bus.c. amd_bus.c reads AMD MSRs so it can remove the MMCONFIG area from the PCI resources. We may also need the MMCONFIG information to work around BIOS defects in the ACPI MCFG table. Cc: Borislav Petkov Cc: Yinghai Lu Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/amd_nb.h | 2 ++ arch/x86/kernel/amd_nb.c | 31 ++++++++++++++++++++++++++ arch/x86/pci/amd_bus.c | 42 +++++++++-------------------------- 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/arch/x86/include/asm/amd_nb.h b/arch/x86/include/asm/amd_nb.h index 67f87f25761..78a1eff7422 100644 --- a/arch/x86/include/asm/amd_nb.h +++ b/arch/x86/include/asm/amd_nb.h @@ -1,6 +1,7 @@ #ifndef _ASM_X86_AMD_NB_H #define _ASM_X86_AMD_NB_H +#include #include struct amd_nb_bus_dev_range { @@ -13,6 +14,7 @@ extern const struct pci_device_id amd_nb_misc_ids[]; extern const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[]; extern bool early_is_amd_nb(u32 value); +extern struct resource *amd_get_mmconfig_range(struct resource *res); extern int amd_cache_northbridges(void); extern void amd_flush_garts(void); extern int amd_numa_init(void); diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index 4c39baa8fac..bae1efe6d51 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -119,6 +119,37 @@ bool __init early_is_amd_nb(u32 device) return false; } +struct resource *amd_get_mmconfig_range(struct resource *res) +{ + u32 address; + u64 base, msr; + unsigned segn_busn_bits; + + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) + return NULL; + + /* assume all cpus from fam10h have mmconfig */ + if (boot_cpu_data.x86 < 0x10) + return NULL; + + address = MSR_FAM10H_MMIO_CONF_BASE; + rdmsrl(address, msr); + + /* mmconfig is not enabled */ + if (!(msr & FAM10H_MMIO_CONF_ENABLE)) + return NULL; + + base = msr & (FAM10H_MMIO_CONF_BASE_MASK<> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) & + FAM10H_MMIO_CONF_BUSRANGE_MASK; + + res->flags = IORESOURCE_MEM; + res->start = base; + res->end = base + (1ULL<<(segn_busn_bits + 20)) - 1; + return res; +} + int amd_get_subcaches(int cpu) { struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link; diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c index 026e4931d16..385a940b542 100644 --- a/arch/x86/pci/amd_bus.c +++ b/arch/x86/pci/amd_bus.c @@ -30,34 +30,6 @@ static struct pci_hostbridge_probe pci_probes[] __initdata = { { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1300 }, }; -static u64 __initdata fam10h_mmconf_start; -static u64 __initdata fam10h_mmconf_end; -static void __init get_pci_mmcfg_amd_fam10h_range(void) -{ - u32 address; - u64 base, msr; - unsigned segn_busn_bits; - - /* assume all cpus from fam10h have mmconf */ - if (boot_cpu_data.x86 < 0x10) - return; - - address = MSR_FAM10H_MMIO_CONF_BASE; - rdmsrl(address, msr); - - /* mmconfig is not enable */ - if (!(msr & FAM10H_MMIO_CONF_ENABLE)) - return; - - base = msr & (FAM10H_MMIO_CONF_BASE_MASK<> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) & - FAM10H_MMIO_CONF_BUSRANGE_MASK; - - fam10h_mmconf_start = base; - fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1; -} - #define RANGE_NUM 16 /** @@ -85,6 +57,9 @@ static int __init early_fill_mp_bus_info(void) u64 val; u32 address; bool found; + struct resource fam10h_mmconf_res, *fam10h_mmconf; + u64 fam10h_mmconf_start; + u64 fam10h_mmconf_end; if (!early_pci_allowed()) return -1; @@ -211,12 +186,17 @@ static int __init early_fill_mp_bus_info(void) subtract_range(range, RANGE_NUM, 0, end); /* get mmconfig */ - get_pci_mmcfg_amd_fam10h_range(); + fam10h_mmconf = amd_get_mmconfig_range(&fam10h_mmconf_res); /* need to take out mmconf range */ - if (fam10h_mmconf_end) { - printk(KERN_DEBUG "Fam 10h mmconf [%llx, %llx]\n", fam10h_mmconf_start, fam10h_mmconf_end); + if (fam10h_mmconf) { + printk(KERN_DEBUG "Fam 10h mmconf %pR\n", fam10h_mmconf); + fam10h_mmconf_start = fam10h_mmconf->start; + fam10h_mmconf_end = fam10h_mmconf->end; subtract_range(range, RANGE_NUM, fam10h_mmconf_start, fam10h_mmconf_end + 1); + } else { + fam10h_mmconf_start = 0; + fam10h_mmconf_end = 0; } /* mmio resource */ From 72ce943013baaba4af7afec76c3556b16b9f6de4 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 12 Jan 2012 08:01:40 -0700 Subject: [PATCH 0680/4025] x86/PCI: build amd_bus.o only when CONFIG_AMD_NB=y commit 5cf9a4e69c1ff0ccdd1d2b7404f95c0531355274 upstream. We only need amd_bus.o for AMD systems with PCI. arch/x86/pci/Makefile already depends on CONFIG_PCI=y, so this patch just adds the dependency on CONFIG_AMD_NB. Cc: Yinghai Lu Signed-off-by: Bjorn Helgaas Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/pci/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile index 6b8759f7634..d24d3da7292 100644 --- a/arch/x86/pci/Makefile +++ b/arch/x86/pci/Makefile @@ -18,8 +18,9 @@ obj-$(CONFIG_X86_NUMAQ) += numaq_32.o obj-$(CONFIG_X86_MRST) += mrst.o obj-y += common.o early.o -obj-y += amd_bus.o bus_numa.o +obj-y += bus_numa.o +obj-$(CONFIG_AMD_NB) += amd_bus.o obj-$(CONFIG_PCI_CNB20LE_QUIRK) += broadcom_bus.o ifeq ($(CONFIG_PCI_DEBUG),y) From de3f88ba084473ce5365632f0209c3e95aeb55e9 Mon Sep 17 00:00:00 2001 From: "nagalakshmi.nandigama@lsi.com" Date: Thu, 1 Dec 2011 07:52:56 +0530 Subject: [PATCH 0681/4025] SCSI: mpt2sas: Release spinlock for the raid device list before blocking it commit 30c43282f3d347f47f9e05199d2b14f56f3f2837 upstream. Added code to release the spinlock that is used to protect the raid device list before calling a function that can block. The blocking was causing a reschedule, and subsequently it is tried to acquire the same lock, resulting in a panic (NMI Watchdog detecting a CPU lockup). Signed-off-by: Nagalakshmi Nandigama Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index c79857e439f..2a4719ae688 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -6425,6 +6425,7 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid, } else sas_target_priv_data = NULL; raid_device->responding = 1; + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); starget_printk(KERN_INFO, raid_device->starget, "handle(0x%04x), wwid(0x%016llx)\n", handle, (unsigned long long)raid_device->wwid); @@ -6435,16 +6436,16 @@ _scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid, */ _scsih_init_warpdrive_properties(ioc, raid_device); if (raid_device->handle == handle) - goto out; + return; printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", raid_device->handle); raid_device->handle = handle; if (sas_target_priv_data) sas_target_priv_data->handle = handle; - goto out; + return; } } - out: + spin_unlock_irqrestore(&ioc->raid_device_lock, flags); } From 73669debb5f508962ffcc8b632ffb2971c606e5c Mon Sep 17 00:00:00 2001 From: "nagalakshmi.nandigama@lsi.com" Date: Thu, 1 Dec 2011 07:53:08 +0530 Subject: [PATCH 0682/4025] SCSI: mpt2sas : Fix for memory allocation error for large host credits commit aff132d95ffe14eca96cab90597cdd010b457af7 upstream. The amount of memory required for tracking chain buffers is rather large, and when the host credit count is big, memory allocation failure occurs inside __get_free_pages. The fix is to limit the number of chains to 100,000. In addition, the number of host credits is limited to 30,000 IOs. However this limitation can be overridden this using the command line option max_queue_depth. The algorithm for calculating the reply_post_queue_depth is changed so that it is equal to (reply_free_queue_depth + 16), previously it was (reply_free_queue_depth * 2). Signed-off-by: Nagalakshmi Nandigama Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mpt2sas/mpt2sas_base.c | 83 +++++++++------------------- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 4 +- 2 files changed, 29 insertions(+), 58 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 39e81cd567a..10f16a306e5 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -66,6 +66,8 @@ static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS]; #define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */ +#define MAX_HBA_QUEUE_DEPTH 30000 +#define MAX_CHAIN_DEPTH 100000 static int max_queue_depth = -1; module_param(max_queue_depth, int, 0); MODULE_PARM_DESC(max_queue_depth, " max controller queue depth "); @@ -2098,8 +2100,6 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc) } if (ioc->chain_dma_pool) pci_pool_destroy(ioc->chain_dma_pool); - } - if (ioc->chain_lookup) { free_pages((ulong)ioc->chain_lookup, ioc->chain_pages); ioc->chain_lookup = NULL; } @@ -2117,9 +2117,7 @@ static int _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) { struct mpt2sas_facts *facts; - u32 queue_size, queue_diff; u16 max_sge_elements; - u16 num_of_reply_frames; u16 chains_needed_per_io; u32 sz, total_sz; u32 retry_sz; @@ -2146,7 +2144,8 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) max_request_credit = (max_queue_depth < facts->RequestCredit) ? max_queue_depth : facts->RequestCredit; else - max_request_credit = facts->RequestCredit; + max_request_credit = min_t(u16, facts->RequestCredit, + MAX_HBA_QUEUE_DEPTH); ioc->hba_queue_depth = max_request_credit; ioc->hi_priority_depth = facts->HighPriorityCredit; @@ -2187,50 +2186,25 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) } ioc->chains_needed_per_io = chains_needed_per_io; - /* reply free queue sizing - taking into account for events */ - num_of_reply_frames = ioc->hba_queue_depth + 32; - - /* number of replies frames can't be a multiple of 16 */ - /* decrease number of reply frames by 1 */ - if (!(num_of_reply_frames % 16)) - num_of_reply_frames--; - - /* calculate number of reply free queue entries - * (must be multiple of 16) - */ - - /* (we know reply_free_queue_depth is not a multiple of 16) */ - queue_size = num_of_reply_frames; - queue_size += 16 - (queue_size % 16); - ioc->reply_free_queue_depth = queue_size; - - /* reply descriptor post queue sizing */ - /* this size should be the number of request frames + number of reply - * frames - */ - - queue_size = ioc->hba_queue_depth + num_of_reply_frames + 1; - /* round up to 16 byte boundary */ - if (queue_size % 16) - queue_size += 16 - (queue_size % 16); - - /* check against IOC maximum reply post queue depth */ - if (queue_size > facts->MaxReplyDescriptorPostQueueDepth) { - queue_diff = queue_size - - facts->MaxReplyDescriptorPostQueueDepth; + /* reply free queue sizing - taking into account for 64 FW events */ + ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; - /* round queue_diff up to multiple of 16 */ - if (queue_diff % 16) - queue_diff += 16 - (queue_diff % 16); - - /* adjust hba_queue_depth, reply_free_queue_depth, - * and queue_size - */ - ioc->hba_queue_depth -= (queue_diff / 2); - ioc->reply_free_queue_depth -= (queue_diff / 2); - queue_size = facts->MaxReplyDescriptorPostQueueDepth; + /* align the reply post queue on the next 16 count boundary */ + if (!ioc->reply_free_queue_depth % 16) + ioc->reply_post_queue_depth = ioc->reply_free_queue_depth + 16; + else + ioc->reply_post_queue_depth = ioc->reply_free_queue_depth + + 32 - (ioc->reply_free_queue_depth % 16); + if (ioc->reply_post_queue_depth > + facts->MaxReplyDescriptorPostQueueDepth) { + ioc->reply_post_queue_depth = min_t(u16, + (facts->MaxReplyDescriptorPostQueueDepth - + (facts->MaxReplyDescriptorPostQueueDepth % 16)), + (ioc->hba_queue_depth - (ioc->hba_queue_depth % 16))); + ioc->reply_free_queue_depth = ioc->reply_post_queue_depth - 16; + ioc->hba_queue_depth = ioc->reply_free_queue_depth - 64; } - ioc->reply_post_queue_depth = queue_size; + dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: " "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), " @@ -2316,15 +2290,12 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) "depth(%d)\n", ioc->name, ioc->request, ioc->scsiio_depth)); - /* loop till the allocation succeeds */ - do { - sz = ioc->chain_depth * sizeof(struct chain_tracker); - ioc->chain_pages = get_order(sz); - ioc->chain_lookup = (struct chain_tracker *)__get_free_pages( - GFP_KERNEL, ioc->chain_pages); - if (ioc->chain_lookup == NULL) - ioc->chain_depth -= 100; - } while (ioc->chain_lookup == NULL); + ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH); + sz = ioc->chain_depth * sizeof(struct chain_tracker); + ioc->chain_pages = get_order(sz); + + ioc->chain_lookup = (struct chain_tracker *)__get_free_pages( + GFP_KERNEL, ioc->chain_pages); ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev, ioc->request_sz, 16, 0); if (!ioc->chain_dma_pool) { diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 2a4719ae688..aa51195a731 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -974,8 +974,8 @@ _scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid) spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); if (list_empty(&ioc->free_chain_list)) { spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - printk(MPT2SAS_WARN_FMT "chain buffers not available\n", - ioc->name); + dfailprintk(ioc, printk(MPT2SAS_WARN_FMT "chain buffers not " + "available\n", ioc->name)); return NULL; } chain_req = list_entry(ioc->free_chain_list.next, From 9919fe804d613e513ef13f5eedc9e583c4429d38 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Wed, 4 Jan 2012 09:34:49 +0000 Subject: [PATCH 0683/4025] xen/xenbus: Reject replies with payload > XENSTORE_PAYLOAD_MAX. commit 9e7860cee18241633eddb36a4c34c7b61d8cecbc upstream. Haogang Chen found out that: There is a potential integer overflow in process_msg() that could result in cross-domain attack. body = kmalloc(msg->hdr.len + 1, GFP_NOIO | __GFP_HIGH); When a malicious guest passes 0xffffffff in msg->hdr.len, the subsequent call to xb_read() would write to a zero-length buffer. The other end of this connection is always the xenstore backend daemon so there is no guest (malicious or otherwise) which can do this. The xenstore daemon is a trusted component in the system. However this seem like a reasonable robustness improvement so we should have it. And Ian when read the API docs found that: The payload length (len field of the header) is limited to 4096 (XENSTORE_PAYLOAD_MAX) in both directions. If a client exceeds the limit, its xenstored connection will be immediately killed by xenstored, which is usually catastrophic from the client's point of view. Clients (particularly domains, which cannot just reconnect) should avoid this. so this patch checks against that instead. This also avoids a potential integer overflow pointed out by Haogang Chen. Signed-off-by: Ian Campbell Cc: Haogang Chen Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- drivers/xen/xenbus/xenbus_xs.c | 6 ++++++ include/xen/interface/io/xs_wire.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index 5534690075a..daee5db4bef 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -801,6 +801,12 @@ static int process_msg(void) goto out; } + if (msg->hdr.len > XENSTORE_PAYLOAD_MAX) { + kfree(msg); + err = -EINVAL; + goto out; + } + body = kmalloc(msg->hdr.len + 1, GFP_NOIO | __GFP_HIGH); if (body == NULL) { kfree(msg); diff --git a/include/xen/interface/io/xs_wire.h b/include/xen/interface/io/xs_wire.h index 99fcffb372d..454ee262923 100644 --- a/include/xen/interface/io/xs_wire.h +++ b/include/xen/interface/io/xs_wire.h @@ -84,4 +84,7 @@ struct xenstore_domain_interface { XENSTORE_RING_IDX rsp_cons, rsp_prod; }; +/* Violating this is very bad. See docs/misc/xenstore.txt. */ +#define XENSTORE_PAYLOAD_MAX 4096 + #endif /* _XS_WIRE_H */ From 808f398267e920a772c1ae07781adfb0d4d1c48a Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Mon, 19 Dec 2011 15:57:27 +0100 Subject: [PATCH 0684/4025] ima: free duplicate measurement memory commit 45fae7493970d7c45626ccd96d4a74f5f1eea5a9 upstream. Info about new measurements are cached in the iint for performance. When the inode is flushed from cache, the associated iint is flushed as well. Subsequent access to the inode will cause the inode to be re-measured and will attempt to add a duplicate entry to the measurement list. This patch frees the duplicate measurement memory, fixing a memory leak. Signed-off-by: Roberto Sassu Signed-off-by: Mimi Zohar Signed-off-by: Greg Kroah-Hartman --- security/integrity/ima/ima_api.c | 4 ++-- security/integrity/ima/ima_queue.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index da36d2c085a..5335605571f 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -177,8 +177,8 @@ void ima_store_measurement(struct ima_iint_cache *iint, struct file *file, strncpy(entry->template.file_name, filename, IMA_EVENT_NAME_LEN_MAX); result = ima_store_template(entry, violation, inode); - if (!result) + if (!result || result == -EEXIST) iint->flags |= IMA_MEASURED; - else + if (result < 0) kfree(entry); } diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index 8e28f04a5e2..e1a5062b1f6 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -114,6 +114,7 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, memcpy(digest, entry->digest, sizeof digest); if (ima_lookup_digest_entry(digest)) { audit_cause = "hash_exists"; + result = -EEXIST; goto out; } } From ffdfcb4347b7f5082e6e191175d46d74c235c2c7 Mon Sep 17 00:00:00 2001 From: Roberto Sassu Date: Mon, 19 Dec 2011 15:57:28 +0100 Subject: [PATCH 0685/4025] ima: fix invalid memory reference commit 7b7e5916aa2f46e57f8bd8cb89c34620ebfda5da upstream. Don't free a valid measurement entry on TPM PCR extend failure. Signed-off-by: Roberto Sassu Signed-off-by: Mimi Zohar Signed-off-by: Greg Kroah-Hartman --- security/integrity/ima/ima_queue.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/security/integrity/ima/ima_queue.c b/security/integrity/ima/ima_queue.c index e1a5062b1f6..55a6271bce7 100644 --- a/security/integrity/ima/ima_queue.c +++ b/security/integrity/ima/ima_queue.c @@ -23,6 +23,8 @@ #include #include "ima.h" +#define AUDIT_CAUSE_LEN_MAX 32 + LIST_HEAD(ima_measurements); /* list of all measurements */ /* key: inode (before secure-hashing a file) */ @@ -94,7 +96,8 @@ static int ima_pcr_extend(const u8 *hash) result = tpm_pcr_extend(TPM_ANY_NUM, CONFIG_IMA_MEASURE_PCR_IDX, hash); if (result != 0) - pr_err("IMA: Error Communicating to TPM chip\n"); + pr_err("IMA: Error Communicating to TPM chip, result: %d\n", + result); return result; } @@ -106,8 +109,9 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, { u8 digest[IMA_DIGEST_SIZE]; const char *audit_cause = "hash_added"; + char tpm_audit_cause[AUDIT_CAUSE_LEN_MAX]; int audit_info = 1; - int result = 0; + int result = 0, tpmresult = 0; mutex_lock(&ima_extend_list_mutex); if (!violation) { @@ -129,9 +133,11 @@ int ima_add_template_entry(struct ima_template_entry *entry, int violation, if (violation) /* invalidate pcr */ memset(digest, 0xff, sizeof digest); - result = ima_pcr_extend(digest); - if (result != 0) { - audit_cause = "TPM error"; + tpmresult = ima_pcr_extend(digest); + if (tpmresult != 0) { + snprintf(tpm_audit_cause, AUDIT_CAUSE_LEN_MAX, "TPM_error(%d)", + tpmresult); + audit_cause = tpm_audit_cause; audit_info = 0; } out: From 982e49a7cbcca1347b701e2098431153d83c3dd2 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 5 Jan 2012 14:27:24 -0700 Subject: [PATCH 0686/4025] PNP: work around Dell 1536/1546 BIOS MMCONFIG bug that breaks USB commit eb31aae8cb5eb54e234ed2d857ddac868195d911 upstream. Some Dell BIOSes have MCFG tables that don't report the entire MMCONFIG area claimed by the chipset. If we move PCI devices into that claimed-but-unreported area, they don't work. This quirk reads the AMD MMCONFIG MSRs and adds PNP0C01 resources as needed to cover the entire area. Example problem scenario: BIOS-e820: 00000000cfec5400 - 00000000d4000000 (reserved) Fam 10h mmconf [d0000000, dfffffff] PCI: MMCONFIG for domain 0000 [bus 00-3f] at [mem 0xd0000000-0xd3ffffff] (base 0xd0000000) pnp 00:0c: [mem 0xd0000000-0xd3ffffff] pci 0000:00:12.0: reg 10: [mem 0xffb00000-0xffb00fff] pci 0000:00:12.0: no compatible bridge window for [mem 0xffb00000-0xffb00fff] pci 0000:00:12.0: BAR 0: assigned [mem 0xd4000000-0xd40000ff] Reported-by: Lisa Salimbas Reported-by: Tested-by: dann frazier References: https://bugzilla.kernel.org/show_bug.cgi?id=31602 References: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/647043 References: https://bugzilla.redhat.com/show_bug.cgi?id=770308 Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- drivers/pnp/quirks.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index dfbd5a6cc58..258fef272ea 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -295,6 +295,45 @@ static void quirk_system_pci_resources(struct pnp_dev *dev) } } +#ifdef CONFIG_AMD_NB + +#include + +static void quirk_amd_mmconfig_area(struct pnp_dev *dev) +{ + resource_size_t start, end; + struct pnp_resource *pnp_res; + struct resource *res; + struct resource mmconfig_res, *mmconfig; + + mmconfig = amd_get_mmconfig_range(&mmconfig_res); + if (!mmconfig) + return; + + list_for_each_entry(pnp_res, &dev->resources, list) { + res = &pnp_res->res; + if (res->end < mmconfig->start || res->start > mmconfig->end || + (res->start == mmconfig->start && res->end == mmconfig->end)) + continue; + + dev_info(&dev->dev, FW_BUG + "%pR covers only part of AMD MMCONFIG area %pR; adding more reservations\n", + res, mmconfig); + if (mmconfig->start < res->start) { + start = mmconfig->start; + end = res->start - 1; + pnp_add_mem_resource(dev, start, end, 0); + } + if (mmconfig->end > res->end) { + start = res->end + 1; + end = mmconfig->end; + pnp_add_mem_resource(dev, start, end, 0); + } + break; + } +} +#endif + /* * PnP Quirks * Cards or devices that need some tweaking due to incomplete resource info @@ -322,6 +361,9 @@ static struct pnp_fixup pnp_fixups[] = { /* PnP resources that might overlap PCI BARs */ {"PNP0c01", quirk_system_pci_resources}, {"PNP0c02", quirk_system_pci_resources}, +#ifdef CONFIG_AMD_NB + {"PNP0c01", quirk_amd_mmconfig_area}, +#endif {""} }; From 93d150e945fdaceb9e8fe18c7b9014569123195d Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 4 Jan 2012 20:50:47 -0600 Subject: [PATCH 0687/4025] rtl8192se: Fix BUG caused by failure to check skb allocation commit d90db4b12bc1b9b8a787ef28550fdb767ee25a49 upstream. When downloading firmware into the device, the driver fails to check the return when allocating an skb. When the allocation fails, a BUG can be generated, as seen in https://bugzilla.redhat.com/show_bug.cgi?id=771656. Signed-off-by: Larry Finger Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rtlwifi/rtl8192se/fw.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c index 3b5af0113d7..0c77a14a382 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c @@ -196,6 +196,8 @@ static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw, /* Allocate skb buffer to contain firmware */ /* info and tx descriptor info. */ skb = dev_alloc_skb(frag_length); + if (!skb) + return false; skb_reserve(skb, extra_descoffset); seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length - extra_descoffset)); @@ -575,6 +577,8 @@ static bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd, len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len); skb = dev_alloc_skb(len); + if (!skb) + return false; cb_desc = (struct rtl_tcb_desc *)(skb->cb); cb_desc->queue_index = TXCMD_QUEUE; cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL; From b9e11747e1227d7ad67c5b80be4b206e4059687e Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 11 Jan 2012 09:26:54 +0100 Subject: [PATCH 0688/4025] mac80211: fix rx->key NULL pointer dereference in promiscuous mode commit 1140afa862842ac3e56678693050760edc4ecde9 upstream. Since: commit 816c04fe7ef01dd9649f5ccfe796474db8708be5 Author: Christian Lamparter Date: Sat Apr 30 15:24:30 2011 +0200 mac80211: consolidate MIC failure report handling is possible to that we dereference rx->key == NULL when driver set RX_FLAG_MMIC_STRIPPED and not RX_FLAG_IV_STRIPPED and we are in promiscuous mode. This happen with rt73usb and rt61pci at least. Before the commit we always check rx->key against NULL, so I assume fix should be done in mac80211 (also mic_fail path has similar check). References: https://bugzilla.redhat.com/show_bug.cgi?id=769766 http://rt2x00.serialmonkey.com/pipermail/users_rt2x00.serialmonkey.com/2012-January/004395.html Reported-by: Stuart D Gathman Reported-by: Kai Wohlfahrt Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/wpa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 8f6a302d2ac..aa1c40ab6a7 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -109,7 +109,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) if (status->flag & RX_FLAG_MMIC_ERROR) goto mic_fail; - if (!(status->flag & RX_FLAG_IV_STRIPPED)) + if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key) goto update_iv; return RX_CONTINUE; From ea1c62778121f6ece5e0120250716b45e204cb13 Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Thu, 12 Jan 2012 17:17:44 -0800 Subject: [PATCH 0689/4025] memcg: add mem_cgroup_replace_page_cache() to fix LRU issue commit ab936cbcd02072a34b60d268f94440fd5cf1970b upstream. Commit ef6a3c6311 ("mm: add replace_page_cache_page() function") added a function replace_page_cache_page(). This function replaces a page in the radix-tree with a new page. WHen doing this, memory cgroup needs to fix up the accounting information. memcg need to check PCG_USED bit etc. In some(many?) cases, 'newpage' is on LRU before calling replace_page_cache(). So, memcg's LRU accounting information should be fixed, too. This patch adds mem_cgroup_replace_page_cache() and removes the old hooks. In that function, old pages will be unaccounted without touching res_counter and new page will be accounted to the memcg (of old page). WHen overwriting pc->mem_cgroup of newpage, take zone->lru_lock and avoid races with LRU handling. Background: replace_page_cache_page() is called by FUSE code in its splice() handling. Here, 'newpage' is replacing oldpage but this newpage is not a newly allocated page and may be on LRU. LRU mis-accounting will be critical for memory cgroup because rmdir() checks the whole LRU is empty and there is no account leak. If a page is on the other LRU than it should be, rmdir() will fail. This bug was added in March 2011, but no bug report yet. I guess there are not many people who use memcg and FUSE at the same time with upstream kernels. The result of this bug is that admin cannot destroy a memcg because of account leak. So, no panic, no deadlock. And, even if an active cgroup exist, umount can succseed. So no problem at shutdown. Signed-off-by: KAMEZAWA Hiroyuki Acked-by: Johannes Weiner Acked-by: Michal Hocko Cc: Miklos Szeredi Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/memcontrol.h | 6 ++++++ mm/filemap.c | 18 ++-------------- mm/memcontrol.c | 44 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 50940da6adf..313a00eca40 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -119,6 +119,8 @@ struct zone_reclaim_stat* mem_cgroup_get_reclaim_stat_from_page(struct page *page); extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p); +extern void mem_cgroup_replace_page_cache(struct page *oldpage, + struct page *newpage); #ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP extern int do_swap_account; @@ -370,6 +372,10 @@ static inline void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx) { } +static inline void mem_cgroup_replace_page_cache(struct page *oldpage, + struct page *newpage) +{ +} #endif /* CONFIG_CGROUP_MEM_CONT */ #if !defined(CONFIG_CGROUP_MEM_RES_CTLR) || !defined(CONFIG_DEBUG_VM) diff --git a/mm/filemap.c b/mm/filemap.c index dd828ea59dc..3c981baadb7 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -396,24 +396,11 @@ EXPORT_SYMBOL(filemap_write_and_wait_range); int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask) { int error; - struct mem_cgroup *memcg = NULL; VM_BUG_ON(!PageLocked(old)); VM_BUG_ON(!PageLocked(new)); VM_BUG_ON(new->mapping); - /* - * This is not page migration, but prepare_migration and - * end_migration does enough work for charge replacement. - * - * In the longer term we probably want a specialized function - * for moving the charge from old to new in a more efficient - * manner. - */ - error = mem_cgroup_prepare_migration(old, new, &memcg, gfp_mask); - if (error) - return error; - error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM); if (!error) { struct address_space *mapping = old->mapping; @@ -435,13 +422,12 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask) if (PageSwapBacked(new)) __inc_zone_page_state(new, NR_SHMEM); spin_unlock_irq(&mapping->tree_lock); + /* mem_cgroup codes must not be called under tree_lock */ + mem_cgroup_replace_page_cache(old, new); radix_tree_preload_end(); if (freepage) freepage(old); page_cache_release(old); - mem_cgroup_end_migration(memcg, old, new, true); - } else { - mem_cgroup_end_migration(memcg, old, new, false); } return error; diff --git a/mm/memcontrol.c b/mm/memcontrol.c index d99217b322a..3791581d3e5 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -3422,6 +3422,50 @@ int mem_cgroup_shmem_charge_fallback(struct page *page, return ret; } +/* + * At replace page cache, newpage is not under any memcg but it's on + * LRU. So, this function doesn't touch res_counter but handles LRU + * in correct way. Both pages are locked so we cannot race with uncharge. + */ +void mem_cgroup_replace_page_cache(struct page *oldpage, + struct page *newpage) +{ + struct mem_cgroup *memcg; + struct page_cgroup *pc; + struct zone *zone; + enum charge_type type = MEM_CGROUP_CHARGE_TYPE_CACHE; + unsigned long flags; + + if (mem_cgroup_disabled()) + return; + + pc = lookup_page_cgroup(oldpage); + /* fix accounting on old pages */ + lock_page_cgroup(pc); + memcg = pc->mem_cgroup; + mem_cgroup_charge_statistics(memcg, PageCgroupCache(pc), -1); + ClearPageCgroupUsed(pc); + unlock_page_cgroup(pc); + + if (PageSwapBacked(oldpage)) + type = MEM_CGROUP_CHARGE_TYPE_SHMEM; + + zone = page_zone(newpage); + pc = lookup_page_cgroup(newpage); + /* + * Even if newpage->mapping was NULL before starting replacement, + * the newpage may be on LRU(or pagevec for LRU) already. We lock + * LRU while we overwrite pc->mem_cgroup. + */ + spin_lock_irqsave(&zone->lru_lock, flags); + if (PageLRU(newpage)) + del_page_from_lru_list(zone, newpage, page_lru(newpage)); + __mem_cgroup_commit_charge(memcg, newpage, 1, pc, type); + if (PageLRU(newpage)) + add_page_to_lru_list(zone, newpage, page_lru(newpage)); + spin_unlock_irqrestore(&zone->lru_lock, flags); +} + #ifdef CONFIG_DEBUG_VM static struct page_cgroup *lookup_page_cgroup_used(struct page *page) { From 59c43b2c3ef410e585646825ea552507cd51ccb1 Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Tue, 15 Nov 2011 14:46:46 -0800 Subject: [PATCH 0690/4025] x86: Fix mmap random address range commit 9af0c7a6fa860698d080481f24a342ba74b68982 upstream. On x86_32 casting the unsigned int result of get_random_int() to long may result in a negative value. On x86_32 the range of mmap_rnd() therefore was -255 to 255. The 32bit mode on x86_64 used 0 to 255 as intended. The bug was introduced by 675a081 ("x86: unify mmap_{32|64}.c") in January 2008. Signed-off-by: Ludwig Nussel Cc: Linus Torvalds Cc: harvey.harrison@gmail.com Cc: "H. Peter Anvin" Cc: Harvey Harrison Signed-off-by: Andrew Morton Link: http://lkml.kernel.org/r/201111152246.pAFMklOB028527@wpaz5.hot.corp.google.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/mmap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/mm/mmap.c b/arch/x86/mm/mmap.c index 1dab5194fd9..f927429d07c 100644 --- a/arch/x86/mm/mmap.c +++ b/arch/x86/mm/mmap.c @@ -87,9 +87,9 @@ static unsigned long mmap_rnd(void) */ if (current->flags & PF_RANDOMIZE) { if (mmap_is_ia32()) - rnd = (long)get_random_int() % (1<<8); + rnd = get_random_int() % (1<<8); else - rnd = (long)(get_random_int() % (1<<28)); + rnd = get_random_int() % (1<<28); } return rnd << PAGE_SHIFT; } From 028bb43eac25b7423198b7e22cfea9bd3e870e24 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Fri, 13 Jan 2012 15:07:40 +0100 Subject: [PATCH 0691/4025] UBI: fix nameless volumes handling commit 4a59c797a18917a5cf3ff7ade296b46134d91e6a upstream. Currently it's possible to create a volume without a name. E.g: ubimkvol -n 32 -s 2MiB -t static /dev/ubi0 -N "" After that vtbl_check() will always fail because it does not permit empty strings. Signed-off-by: Richard Weinberger Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/cdev.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 191f3bb3c41..cdea6692dea 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -628,6 +628,9 @@ static int verify_mkvol_req(const struct ubi_device *ubi, if (req->alignment != 1 && n) goto bad; + if (!req->name[0] || !req->name_len) + goto bad; + if (req->name_len > UBI_VOL_NAME_MAX) { err = -ENAMETOOLONG; goto bad; From d8ece1b43acdec47c0823aa306910239754ef9e9 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 10 Jan 2012 19:32:30 +0200 Subject: [PATCH 0692/4025] UBI: fix debugging messages commit 72f0d453d81d35087b1d3ad7c8285628c2be6e1d upstream. Patch ab50ff684707031ed4bad2fdd313208ae392e5bb broke UBI debugging messages: before that commit when UBI debugging was enabled, users saw few useful debugging messages after attaching an MTD device. However, that patch turned 'dbg_msg()' into 'pr_debug()', so to enable the debugging messages users have to enable them first via /sys/kernel/debug/dynamic_debug/control, which is very impractical. This commit makes 'dbg_msg()' to use 'printk()' instead of 'pr_debug()', just as it was before the breakage. Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/debug.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h index 3f1a09c5c43..5f0e4c2d9cd 100644 --- a/drivers/mtd/ubi/debug.h +++ b/drivers/mtd/ubi/debug.h @@ -51,7 +51,10 @@ struct ubi_mkvol_req; pr_debug("UBI DBG " type ": " fmt "\n", ##__VA_ARGS__) /* Just a debugging messages not related to any specific UBI subsystem */ -#define dbg_msg(fmt, ...) ubi_dbg_msg("msg", fmt, ##__VA_ARGS__) +#define dbg_msg(fmt, ...) \ + printk(KERN_DEBUG "UBI DBG (pid %d): %s: " fmt "\n", \ + current->pid, __func__, ##__VA_ARGS__) + /* General debugging messages */ #define dbg_gen(fmt, ...) ubi_dbg_msg("gen", fmt, ##__VA_ARGS__) /* Messages from the eraseblock association sub-system */ From 8aee2e296d19910d8ad4c676970f0055abc5b5e5 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Tue, 10 Jan 2012 19:32:30 +0200 Subject: [PATCH 0693/4025] UBIFS: fix debugging messages commit d34315da9146253351146140ea4b277193ee5e5f upstream. Patch 56e46742e846e4de167dde0e1e1071ace1c882a5 broke UBIFS debugging messages: before that commit when UBIFS debugging was enabled, users saw few useful debugging messages after mount. However, that patch turned 'dbg_msg()' into 'pr_debug()', so to enable the debugging messages users have to enable them first via /sys/kernel/debug/dynamic_debug/control, which is very impractical. This commit makes 'dbg_msg()' to use 'printk()' instead of 'pr_debug()', just as it was before the breakage. Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/debug.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index a811ac4a26b..3a89c8b4efc 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -134,7 +134,10 @@ const char *dbg_key_str1(const struct ubifs_info *c, } while (0) /* Just a debugging messages not related to any specific UBIFS subsystem */ -#define dbg_msg(fmt, ...) ubifs_dbg_msg("msg", fmt, ##__VA_ARGS__) +#define dbg_msg(fmt, ...) \ + printk(KERN_DEBUG "UBIFS DBG (pid %d): %s: " fmt "\n", current->pid, \ + __func__, ##__VA_ARGS__) + /* General messages */ #define dbg_gen(fmt, ...) ubifs_dbg_msg("gen", fmt, ##__VA_ARGS__) /* Additional journal messages */ From fcf53a1ed4225c1f23997ef02f2770a39e73c515 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 12 Jan 2012 20:32:03 +0100 Subject: [PATCH 0694/4025] i2c: Fix error value returned by several bus drivers commit 7c1f59c9d5caf3a84f35549b5d58f3c055a68da5 upstream. When adding checks for ACPI resource conflicts to many bus drivers, not enough attention was paid to the error paths, and for several drivers this causes 0 to be returned on error in some cases. Fix this by properly returning a non-zero value on every error. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-ali1535.c | 11 +++++++---- drivers/i2c/busses/i2c-nforce2.c | 2 +- drivers/i2c/busses/i2c-sis5595.c | 4 ++-- drivers/i2c/busses/i2c-sis630.c | 6 +++++- drivers/i2c/busses/i2c-viapro.c | 7 +++++-- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index dd364171f9c..cd7ac5c6783 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -140,7 +140,7 @@ static unsigned short ali1535_smba; defined to make the transition easier. */ static int __devinit ali1535_setup(struct pci_dev *dev) { - int retval = -ENODEV; + int retval; unsigned char temp; /* Check the following things: @@ -155,6 +155,7 @@ static int __devinit ali1535_setup(struct pci_dev *dev) if (ali1535_smba == 0) { dev_warn(&dev->dev, "ALI1535_smb region uninitialized - upgrade BIOS?\n"); + retval = -ENODEV; goto exit; } @@ -167,6 +168,7 @@ static int __devinit ali1535_setup(struct pci_dev *dev) ali1535_driver.name)) { dev_err(&dev->dev, "ALI1535_smb region 0x%x already in use!\n", ali1535_smba); + retval = -EBUSY; goto exit; } @@ -174,6 +176,7 @@ static int __devinit ali1535_setup(struct pci_dev *dev) pci_read_config_byte(dev, SMBCFG, &temp); if ((temp & ALI1535_SMBIO_EN) == 0) { dev_err(&dev->dev, "SMB device not enabled - upgrade BIOS?\n"); + retval = -ENODEV; goto exit_free; } @@ -181,6 +184,7 @@ static int __devinit ali1535_setup(struct pci_dev *dev) pci_read_config_byte(dev, SMBHSTCFG, &temp); if ((temp & 1) == 0) { dev_err(&dev->dev, "SMBus controller not enabled - upgrade BIOS?\n"); + retval = -ENODEV; goto exit_free; } @@ -198,12 +202,11 @@ static int __devinit ali1535_setup(struct pci_dev *dev) dev_dbg(&dev->dev, "SMBREV = 0x%X\n", temp); dev_dbg(&dev->dev, "ALI1535_smba = 0x%X\n", ali1535_smba); - retval = 0; -exit: - return retval; + return 0; exit_free: release_region(ali1535_smba, ALI1535_SMB_IOSIZE); +exit: return retval; } diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index ff1e127dfea..4853b52a40a 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -356,7 +356,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, error = acpi_check_region(smbus->base, smbus->size, nforce2_driver.name); if (error) - return -1; + return error; if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) { dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n", diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 437586611d4..6d60284cc04 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -147,7 +147,7 @@ static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev) u16 a; u8 val; int *i; - int retval = -ENODEV; + int retval; /* Look for imposters */ for (i = blacklist; *i != 0; i++) { @@ -223,7 +223,7 @@ static int __devinit sis5595_setup(struct pci_dev *SIS5595_dev) error: release_region(sis5595_base + SMB_INDEX, 2); - return retval; + return -ENODEV; } static int sis5595_transaction(struct i2c_adapter *adap) diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index e6f539e26f6..b617fd068ac 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -393,7 +393,7 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev) { unsigned char b; struct pci_dev *dummy = NULL; - int retval = -ENODEV, i; + int retval, i; /* check for supported SiS devices */ for (i=0; supported[i] > 0 ; i++) { @@ -418,18 +418,21 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev) */ if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) { dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n"); + retval = -ENODEV; goto exit; } /* if ACPI already enabled , do nothing */ if (!(b & 0x80) && pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) { dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n"); + retval = -ENODEV; goto exit; } /* Determine the ACPI base address */ if (pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) { dev_err(&sis630_dev->dev, "Error: Can't determine ACPI base address\n"); + retval = -ENODEV; goto exit; } @@ -445,6 +448,7 @@ static int __devinit sis630_setup(struct pci_dev *sis630_dev) sis630_driver.name)) { dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already " "in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA); + retval = -EBUSY; goto exit; } diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 0b012f1f8ac..58261d4725b 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -324,7 +324,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev, const struct pci_device_id *id) { unsigned char temp; - int error = -ENODEV; + int error; /* Determine the address of the SMBus areas */ if (force_addr) { @@ -390,6 +390,7 @@ static int __devinit vt596_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "SMBUS: Error: Host SMBus " "controller not enabled! - upgrade BIOS or " "use force=1\n"); + error = -ENODEV; goto release_region; } } @@ -422,9 +423,11 @@ static int __devinit vt596_probe(struct pci_dev *pdev, "SMBus Via Pro adapter at %04x", vt596_smba); vt596_pdev = pci_dev_get(pdev); - if (i2c_add_adapter(&vt596_adapter)) { + error = i2c_add_adapter(&vt596_adapter); + if (error) { pci_dev_put(vt596_pdev); vt596_pdev = NULL; + goto release_region; } /* Always return failure here. This is to allow other drivers to bind From 1cfbbb9ba574157c9f2312d3267762fdde0bfc59 Mon Sep 17 00:00:00 2001 From: Girish K S Date: Thu, 15 Dec 2011 17:27:42 +0530 Subject: [PATCH 0695/4025] mmc: core: Fix voltage select in DDR mode commit 913047e9e5787a90696533a9f109552b7694ecc9 upstream. This patch fixes the wrong comparison before setting the interface voltage in DDR mode. The assignment to the variable ddr before comaprison is either ddr = MMC_1_2V_DDR_MODE; or ddr == MMC_1_8V_DDR_MODE. But the comparison is done with the extended csd value if ddr == EXT_CSD_CARD_TYPE_DDR_1_2V. Signed-off-by: Girish K S Acked-by: Subhash Jadavani Acked-by: Philip Rakity Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index 20b42c835ab..f6011802745 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -830,7 +830,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * * WARNING: eMMC rules are NOT the same as SD DDR */ - if (ddr == EXT_CSD_CARD_TYPE_DDR_1_2V) { + if (ddr == MMC_1_2V_DDR_MODE) { err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120, 0); if (err) From 62a0e438f7275e845bfbcccd6e641e07d4b89182 Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Wed, 28 Dec 2011 11:11:12 +0800 Subject: [PATCH 0696/4025] mmc: sdhci: Fix tuning timer incorrect setting when suspending host commit c6ced0db08010ed75df221a2946c5228454b38d5 upstream. When suspending host, the tuning timer shoule be deactivated. And the HOST_NEEDS_TUNING flag should be set after tuning timer is deactivated. Signed-off-by: Philip Rakity Signed-off-by: Aaron Lu Acked-by: Adrian Hunter Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6d3de0888e7..9bd62faac0a 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2227,9 +2227,8 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state) /* Disable tuning since we are suspending */ if (host->version >= SDHCI_SPEC_300 && host->tuning_count && host->tuning_mode == SDHCI_TUNING_MODE_1) { + del_timer_sync(&host->tuning_timer); host->flags &= ~SDHCI_NEEDS_RETUNING; - mod_timer(&host->tuning_timer, jiffies + - host->tuning_count * HZ); } ret = mmc_suspend_host(host->mmc); From b1830247c9927d7d2ca17c9f84908fc130051792 Mon Sep 17 00:00:00 2001 From: Alexander Elbs Date: Tue, 3 Jan 2012 23:26:53 -0500 Subject: [PATCH 0697/4025] mmc: sd: Fix SDR12 timing regression commit dd8df17fe83483d7ea06ff229895e35a42071599 upstream. This patch fixes a failure to recognize SD cards reported on a Dell Vostro with O2 Micro SD card reader. Patch 49c468f ("mmc: sd: add support for uhs bus speed mode selection") caused the problem, by setting the SDHCI_CTRL_HISPD flag even for legacy timings. Signed-off-by: Alexander Elbs Acked-by: Philip Rakity Acked-by: Arindam Nath Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9bd62faac0a..153008fff54 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1340,8 +1340,7 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if ((ios->timing == MMC_TIMING_UHS_SDR50) || (ios->timing == MMC_TIMING_UHS_SDR104) || (ios->timing == MMC_TIMING_UHS_DDR50) || - (ios->timing == MMC_TIMING_UHS_SDR25) || - (ios->timing == MMC_TIMING_UHS_SDR12)) + (ios->timing == MMC_TIMING_UHS_SDR25)) ctrl |= SDHCI_CTRL_HISPD; ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); From 065449fd56d2f75cc943a6d501b292f6b0e40325 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 5 Jan 2012 02:27:57 -0300 Subject: [PATCH 0698/4025] V4L/DVB: v4l2-ioctl: integer overflow in video_usercopy() commit 6c06108be53ca5e94d8b0e93883d534dd9079646 upstream. If ctrls->count is too high the multiplication could overflow and array_size would be lower than expected. Mauro and Hans Verkuil suggested that we cap it at 1024. That comes from the maximum number of controls with lots of room for expantion. $ grep V4L2_CID include/linux/videodev2.h | wc -l 211 Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/v4l2-ioctl.c | 4 ++++ include/linux/videodev2.h | 1 + 2 files changed, 5 insertions(+) diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c index 69e8c6ffcc4..bda252f04e8 100644 --- a/drivers/media/video/v4l2-ioctl.c +++ b/drivers/media/video/v4l2-ioctl.c @@ -2289,6 +2289,10 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size, struct v4l2_ext_controls *ctrls = parg; if (ctrls->count != 0) { + if (ctrls->count > V4L2_CID_MAX_CTRLS) { + ret = -EINVAL; + break; + } *user_ptr = (void __user *)ctrls->controls; *kernel_ptr = (void **)&ctrls->controls; *array_size = sizeof(struct v4l2_ext_control) diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 8a4c309d234..eeeda13b4d5 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -1075,6 +1075,7 @@ struct v4l2_querymenu { #define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000 /* User-class control IDs defined by V4L2 */ +#define V4L2_CID_MAX_CTRLS 1024 #define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900) #define V4L2_CID_USER_BASE V4L2_CID_BASE /* IDs reserved for driver specific controls */ From e5303c25bfacd745f6c6b99a2604ef4e11926c34 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 13 Jan 2012 17:50:39 -0500 Subject: [PATCH 0699/4025] kconfig/streamline-config.pl: Simplify backslash line concatination commit d060d963e88f3e990cec2fe5214de49de9a49eca upstream. Simplify the way lines ending with backslashes (continuation) in Makefiles is parsed. This is needed to implement a necessary fix. Tested-by: Thomas Lange Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- scripts/kconfig/streamline_config.pl | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index a4fe923c013..f25809200a9 100644 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -245,17 +245,22 @@ sub read_kconfig { # Read all Makefiles to map the configs to the objects foreach my $makefile (@makefiles) { - my $cont = 0; + my $line = ""; open(MIN,$makefile) || die "Can't open $makefile"; while () { - my $objs; - - # is this a line after a line with a backslash? - if ($cont && /(\S.*)$/) { - $objs = $1; + # if this line ends with a backslash, continue + chomp; + if (/^(.*)\\$/) { + $line .= $1; + next; } - $cont = 0; + + $line .= $_; + $_ = $line; + $line = ""; + + my $objs; # collect objects after obj-$(CONFIG_FOO_BAR) if (/obj-\$\((CONFIG_[^\)]*)\)\s*[+:]?=\s*(.*)/) { @@ -263,12 +268,6 @@ sub read_kconfig { $objs = $2; } if (defined($objs)) { - # test if the line ends with a backslash - if ($objs =~ m,(.*)\\$,) { - $objs = $1; - $cont = 1; - } - foreach my $obj (split /\s+/,$objs) { $obj =~ s/-/_/g; if ($obj =~ /(.*)\.o$/) { From adc0186cfa38e2736048a638681db511e65e51fd Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Fri, 13 Jan 2012 17:53:40 -0500 Subject: [PATCH 0700/4025] kconfig/streamline-config.pl: Fix parsing Makefile with variables commit 364212fddaaa60c5a64f67a0f5624ad996ecc8a0 upstream. Thomas Lange reported that when he did a 'make localmodconfig', his config was missing the brcmsmac driver, even though he had the module loaded. Looking into this, I found the file: drivers/net/wireless/brcm80211/brcmsmac/Makefile had the following in the Makefile: MODULEPFX := brcmsmac obj-$(CONFIG_BRCMSMAC) += $(MODULEPFX).o The way streamline-config.pl works, is parsing all the obj-$(CONFIG_FOO) += foo.o lines to find that CONFIG_FOO belongs to the module foo.ko. But in this case, the brcmsmac.o was not used, but a variable in its place. By changing streamline-config.pl to remember defined variables in Makefiles and substituting them when they are used in the obj-X lines, allows Thomas (and others) to have their brcmsmac module stay configured when it is loaded and running "make localmodconfig". Reported-by: Thomas Lange Tested-by: Thomas Lange Cc: Arend van Spriel Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- scripts/kconfig/streamline_config.pl | 29 ++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index f25809200a9..25f1e71c9bb 100644 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -242,10 +242,33 @@ sub read_kconfig { read_kconfig($kconfig); } +sub convert_vars { + my ($line, %vars) = @_; + + my $process = ""; + + while ($line =~ s/^(.*?)(\$\((.*?)\))//) { + my $start = $1; + my $variable = $2; + my $var = $3; + + if (defined($vars{$var})) { + $process .= $start . $vars{$var}; + } else { + $process .= $start . $variable; + } + } + + $process .= $line; + + return $process; +} + # Read all Makefiles to map the configs to the objects foreach my $makefile (@makefiles) { my $line = ""; + my %make_vars; open(MIN,$makefile) || die "Can't open $makefile"; while () { @@ -262,10 +285,16 @@ sub read_kconfig { my $objs; + $_ = convert_vars($_, %make_vars); + # collect objects after obj-$(CONFIG_FOO_BAR) if (/obj-\$\((CONFIG_[^\)]*)\)\s*[+:]?=\s*(.*)/) { $var = $1; $objs = $2; + + # check if variables are set + } elsif (/^\s*(\S+)\s*[:]?=\s*(.*\S)/) { + $make_vars{$1} = $2; } if (defined($objs)) { foreach my $obj (split /\s+/,$objs) { From b09577ca6680033a4315e2f5cb3a95ebbb8dea79 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 22 Dec 2011 18:22:49 -0700 Subject: [PATCH 0701/4025] svcrpc: fix double-free on shutdown of nfsd after changing pool mode commit 61c8504c428edcebf23b97775a129c5b393a302b upstream. The pool_to and to_pool fields of the global svc_pool_map are freed on shutdown, but are initialized in nfsd startup only in the SVC_POOL_PERCPU and SVC_POOL_PERNODE cases. They *are* initialized to zero on kernel startup. So as long as you use only SVC_POOL_GLOBAL (the default), this will never be a problem. You're also OK if you only ever use SVC_POOL_PERCPU or SVC_POOL_PERNODE. However, the following sequence events leads to a double-free: 1. set SVC_POOL_PERCPU or SVC_POOL_PERNODE 2. start nfsd: both fields are initialized. 3. shutdown nfsd: both fields are freed. 4. set SVC_POOL_GLOBAL 5. start nfsd: the fields are left untouched. 6. shutdown nfsd: now we try to free them again. Step 4 is actually unnecessary, since (for some bizarre reason), nfsd automatically resets the pool mode to SVC_POOL_GLOBAL on shutdown. Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/svc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 2b90292e950..131da58efdc 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -167,6 +167,7 @@ svc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools) fail_free: kfree(m->to_pool); + m->to_pool = NULL; fail: return -ENOMEM; } @@ -287,7 +288,9 @@ svc_pool_map_put(void) if (!--m->count) { m->mode = SVC_POOL_DEFAULT; kfree(m->to_pool); + m->to_pool = NULL; kfree(m->pool_to); + m->pool_to = NULL; m->npools = 0; } From 7df22768c0af8769d805f6db21144d71d91fe13d Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 29 Nov 2011 11:35:35 -0500 Subject: [PATCH 0702/4025] svcrpc: destroy server sockets all at once commit 2fefb8a09e7ed251ae8996e0c69066e74c5aa560 upstream. There's no reason I can see that we need to call sv_shutdown between closing the two lists of sockets. Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- include/linux/sunrpc/svcsock.h | 2 +- net/sunrpc/svc.c | 7 +------ net/sunrpc/svc_xprt.c | 11 ++++++++++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 85c50b40759..c84e9741cb2 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h @@ -34,7 +34,7 @@ struct svc_sock { /* * Function prototypes. */ -void svc_close_all(struct list_head *); +void svc_close_all(struct svc_serv *); int svc_recv(struct svc_rqst *, long); int svc_send(struct svc_rqst *); void svc_drop(struct svc_rqst *); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 131da58efdc..4d5cb99194c 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -476,16 +476,11 @@ svc_destroy(struct svc_serv *serv) del_timer_sync(&serv->sv_temptimer); - svc_close_all(&serv->sv_tempsocks); + svc_close_all(serv); if (serv->sv_shutdown) serv->sv_shutdown(serv); - svc_close_all(&serv->sv_permsocks); - - BUG_ON(!list_empty(&serv->sv_permsocks)); - BUG_ON(!list_empty(&serv->sv_tempsocks)); - cache_clean_deferred(serv); if (svc_serv_is_pooled(serv)) diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index bd31208bbb6..9cb2621a882 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -936,7 +936,7 @@ void svc_close_xprt(struct svc_xprt *xprt) } EXPORT_SYMBOL_GPL(svc_close_xprt); -void svc_close_all(struct list_head *xprt_list) +static void svc_close_list(struct list_head *xprt_list) { struct svc_xprt *xprt; struct svc_xprt *tmp; @@ -954,6 +954,15 @@ void svc_close_all(struct list_head *xprt_list) } } +void svc_close_all(struct svc_serv *serv) +{ + svc_close_list(&serv->sv_tempsocks); + svc_close_list(&serv->sv_permsocks); + BUG_ON(!list_empty(&serv->sv_permsocks)); + BUG_ON(!list_empty(&serv->sv_tempsocks)); + +} + /* * Handle defer and revisit of requests */ From a141a5eb3ab45131cb168e7a561d662722b43ec3 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 29 Nov 2011 17:00:26 -0500 Subject: [PATCH 0703/4025] svcrpc: avoid memory-corruption on pool shutdown commit b4f36f88b3ee7cf26bf0be84e6c7fc15f84dcb71 upstream. Socket callbacks use svc_xprt_enqueue() to add an xprt to a pool->sp_sockets list. In normal operation a server thread will later come along and take the xprt off that list. On shutdown, after all the threads have exited, we instead manually walk the sv_tempsocks and sv_permsocks lists to find all the xprt's and delete them. So the sp_sockets lists don't really matter any more. As a result, we've mostly just ignored them and hoped they would go away. Which has gotten us into trouble; witness for example ebc63e531cc6 "svcrpc: fix list-corrupting race on nfsd shutdown", the result of Ben Greear noticing that a still-running svc_xprt_enqueue() could re-add an xprt to an sp_sockets list just before it was deleted. The fix was to remove it from the list at the end of svc_delete_xprt(). But that only made corruption less likely--I can see nothing that prevents a svc_xprt_enqueue() from adding another xprt to the list at the same moment that we're removing this xprt from the list. In fact, despite the earlier xpo_detach(), I don't even see what guarantees that svc_xprt_enqueue() couldn't still be running on this xprt. So, instead, note that svc_xprt_enqueue() essentially does: lock sp_lock if XPT_BUSY unset add to sp_sockets unlock sp_lock So, if we do: set XPT_BUSY on every xprt. Empty every sp_sockets list, under the sp_socks locks. Then we're left knowing that the sp_sockets lists are all empty and will stay that way, since any svc_xprt_enqueue() will check XPT_BUSY under the sp_lock and see it set. And *then* we can continue deleting the xprt's. (Thanks to Jeff Layton for being correctly suspicious of this code....) Cc: Ben Greear Cc: Jeff Layton Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/svc.c | 10 ++++++++- net/sunrpc/svc_xprt.c | 48 ++++++++++++++++++++++++++----------------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 4d5cb99194c..ce5f111fe32 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -475,7 +475,15 @@ svc_destroy(struct svc_serv *serv) printk("svc_destroy: no threads for serv=%p!\n", serv); del_timer_sync(&serv->sv_temptimer); - + /* + * The set of xprts (contained in the sv_tempsocks and + * sv_permsocks lists) is now constant, since it is modified + * only by accepting new sockets (done by service threads in + * svc_recv) or aging old ones (done by sv_temptimer), or + * configuration changes (excluded by whatever locking the + * caller is using--nfsd_mutex in the case of nfsd). So it's + * safe to traverse those lists and shut everything down: + */ svc_close_all(serv); if (serv->sv_shutdown) diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 9cb2621a882..9d7ed0b48b5 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c @@ -901,14 +901,7 @@ void svc_delete_xprt(struct svc_xprt *xprt) spin_lock_bh(&serv->sv_lock); if (!test_and_set_bit(XPT_DETACHED, &xprt->xpt_flags)) list_del_init(&xprt->xpt_list); - /* - * The only time we're called while xpt_ready is still on a list - * is while the list itself is about to be destroyed (in - * svc_destroy). BUT svc_xprt_enqueue could still be attempting - * to add new entries to the sp_sockets list, so we can't leave - * a freed xprt on it. - */ - list_del_init(&xprt->xpt_ready); + BUG_ON(!list_empty(&xprt->xpt_ready)); if (test_bit(XPT_TEMP, &xprt->xpt_flags)) serv->sv_tmpcnt--; spin_unlock_bh(&serv->sv_lock); @@ -939,28 +932,45 @@ EXPORT_SYMBOL_GPL(svc_close_xprt); static void svc_close_list(struct list_head *xprt_list) { struct svc_xprt *xprt; - struct svc_xprt *tmp; - /* - * The server is shutting down, and no more threads are running. - * svc_xprt_enqueue() might still be running, but at worst it - * will re-add the xprt to sp_sockets, which will soon get - * freed. So we don't bother with any more locking, and don't - * leave the close to the (nonexistent) server threads: - */ - list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { + list_for_each_entry(xprt, xprt_list, xpt_list) { set_bit(XPT_CLOSE, &xprt->xpt_flags); - svc_delete_xprt(xprt); + set_bit(XPT_BUSY, &xprt->xpt_flags); } } void svc_close_all(struct svc_serv *serv) { + struct svc_pool *pool; + struct svc_xprt *xprt; + struct svc_xprt *tmp; + int i; + svc_close_list(&serv->sv_tempsocks); svc_close_list(&serv->sv_permsocks); + + for (i = 0; i < serv->sv_nrpools; i++) { + pool = &serv->sv_pools[i]; + + spin_lock_bh(&pool->sp_lock); + while (!list_empty(&pool->sp_sockets)) { + xprt = list_first_entry(&pool->sp_sockets, struct svc_xprt, xpt_ready); + list_del_init(&xprt->xpt_ready); + } + spin_unlock_bh(&pool->sp_lock); + } + /* + * At this point the sp_sockets lists will stay empty, since + * svc_enqueue will not add new entries without taking the + * sp_lock and checking XPT_BUSY. + */ + list_for_each_entry_safe(xprt, tmp, &serv->sv_tempsocks, xpt_list) + svc_delete_xprt(xprt); + list_for_each_entry_safe(xprt, tmp, &serv->sv_permsocks, xpt_list) + svc_delete_xprt(xprt); + BUG_ON(!list_empty(&serv->sv_permsocks)); BUG_ON(!list_empty(&serv->sv_tempsocks)); - } /* From 46a5392ffcb492b8042776ce44b5cc1c07be1b23 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Fri, 18 Nov 2011 12:14:49 +0200 Subject: [PATCH 0704/4025] nfsd: Fix oops when parsing a 0 length export commit b2ea70afade7080360ac55c4e64ff7a5fafdb67b upstream. expkey_parse() oopses when handling a 0 length export. This is easily triggerable from usermode by writing 0 bytes into '/proc/[proc id]/net/rpc/nfsd.fh/channel'. Below is the log: [ 1402.286893] BUG: unable to handle kernel paging request at ffff880077c49fff [ 1402.287632] IP: [] expkey_parse+0x28/0x2e1 [ 1402.287632] PGD 2206063 PUD 1fdfd067 PMD 1ffbc067 PTE 8000000077c49160 [ 1402.287632] Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC [ 1402.287632] CPU 1 [ 1402.287632] Pid: 20198, comm: trinity Not tainted 3.2.0-rc2-sasha-00058-gc65cd37 #6 [ 1402.287632] RIP: 0010:[] [] expkey_parse+0x28/0x2e1 [ 1402.287632] RSP: 0018:ffff880077f0fd68 EFLAGS: 00010292 [ 1402.287632] RAX: ffff880077c49fff RBX: 00000000ffffffea RCX: 0000000001043400 [ 1402.287632] RDX: 0000000000000000 RSI: ffff880077c4a000 RDI: ffffffff82283de0 [ 1402.287632] RBP: ffff880077f0fe18 R08: 0000000000000001 R09: ffff880000000000 [ 1402.287632] R10: 0000000000000000 R11: 0000000000000001 R12: ffff880077c4a000 [ 1402.287632] R13: ffffffff82283de0 R14: 0000000001043400 R15: ffffffff82283de0 [ 1402.287632] FS: 00007f25fec3f700(0000) GS:ffff88007d400000(0000) knlGS:0000000000000000 [ 1402.287632] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 1402.287632] CR2: ffff880077c49fff CR3: 0000000077e1d000 CR4: 00000000000406e0 [ 1402.287632] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 1402.287632] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 1402.287632] Process trinity (pid: 20198, threadinfo ffff880077f0e000, task ffff880077db17b0) [ 1402.287632] Stack: [ 1402.287632] ffff880077db17b0 ffff880077c4a000 ffff880077f0fdb8 ffffffff810b411e [ 1402.287632] ffff880000000000 ffff880077db17b0 ffff880077c4a000 ffffffff82283de0 [ 1402.287632] 0000000001043400 ffffffff82283de0 ffff880077f0fde8 ffffffff81111f63 [ 1402.287632] Call Trace: [ 1402.287632] [] ? lock_release+0x1af/0x1bc [ 1402.287632] [] ? might_fault+0x97/0x9e [ 1402.287632] [] ? might_fault+0x4e/0x9e [ 1402.287632] [] cache_do_downcall+0x3e/0x4f [ 1402.287632] [] cache_write.clone.16+0xbb/0x130 [ 1402.287632] [] ? cache_write_pipefs+0x1a/0x1a [ 1402.287632] [] cache_write_procfs+0x19/0x1b [ 1402.287632] [] proc_reg_write+0x8e/0xad [ 1402.287632] [] vfs_write+0xaa/0xfd [ 1402.287632] [] ? fget_light+0x35/0x9e [ 1402.287632] [] sys_write+0x48/0x6f [ 1402.287632] [] system_call_fastpath+0x16/0x1b [ 1402.287632] Code: c0 c9 c3 55 48 63 d2 48 89 e5 48 8d 44 32 ff 41 57 41 56 41 55 41 54 53 bb ea ff ff ff 48 81 ec 88 00 00 00 48 89 b5 58 ff ff ff [ 1402.287632] 38 0a 0f 85 89 02 00 00 c6 00 00 48 8b 3d 44 4a e5 01 48 85 [ 1402.287632] RIP [] expkey_parse+0x28/0x2e1 [ 1402.287632] RSP [ 1402.287632] CR2: ffff880077c49fff [ 1402.287632] ---[ end trace 368ef53ff773a5e3 ]--- Cc: "J. Bruce Fields" Cc: Neil Brown Cc: linux-nfs@vger.kernel.org Signed-off-by: Sasha Levin Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/export.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index b9566e46219..4b470f6043e 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -88,7 +88,7 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) struct svc_expkey key; struct svc_expkey *ek = NULL; - if (mesg[mlen-1] != '\n') + if (mlen < 1 || mesg[mlen-1] != '\n') return -EINVAL; mesg[mlen-1] = 0; From a9680ece8e3874382fb2db1b8e247452c306b735 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Thu, 12 Jan 2012 17:59:46 +0100 Subject: [PATCH 0705/4025] fsnotify: don't BUG in fsnotify_destroy_mark() commit fed474857efbed79cd390d0aee224231ca718f63 upstream. Removing the parent of a watched file results in "kernel BUG at fs/notify/mark.c:139". To reproduce add "-w /tmp/audit/dir/watched_file" to audit.rules rm -rf /tmp/audit/dir This is caused by fsnotify_destroy_mark() being called without an extra reference taken by the caller. Reported by Francesco Cosoleto here: https://bugzilla.novell.com/show_bug.cgi?id=689860 Fix by removing the BUG_ON and adding a comment about not accessing mark after the iput. Signed-off-by: Miklos Szeredi Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/notify/mark.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 252ab1f6452..42ed195771f 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -135,9 +135,6 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; - /* 1 from caller and 1 for being on i_list/g_list */ - BUG_ON(atomic_read(&mark->refcnt) < 2); - spin_lock(&group->mark_lock); if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { @@ -181,6 +178,11 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark) if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) iput(inode); + /* + * We don't necessarily have a ref on mark from caller so the above iput + * may have already destroyed it. Don't touch from now on. + */ + /* * it's possible that this group tried to destroy itself, but this * this mark was simultaneously being freed by inode. If that's the From 15274414badc6ef0a893454e7102f3753f2c1ccd Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Fri, 6 Jan 2012 13:19:00 -0600 Subject: [PATCH 0706/4025] x86, UV: Update Boot messages for SGI UV2 platform commit da517a08ac5913cd80ce3507cddd00f2a091b13c upstream. SGI UV systems print a message during boot: UV: Found blades Due to packaging changes, the blade count is not accurate for on the next generation of the platform. This patch corrects the count. Signed-off-by: Jack Steiner Link: http://lkml.kernel.org/r/20120106191900.GA19772@sgi.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/apic/x2apic_uv_x.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index cfeb978f49f..874c2087714 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c @@ -779,7 +779,12 @@ void __init uv_system_init(void) for(i = 0; i < UVH_NODE_PRESENT_TABLE_DEPTH; i++) uv_possible_blades += hweight64(uv_read_local_mmr( UVH_NODE_PRESENT_TABLE + i * 8)); - printk(KERN_DEBUG "UV: Found %d blades\n", uv_num_possible_blades()); + + /* uv_num_possible_blades() is really the hub count */ + printk(KERN_INFO "UV: Found %d blades, %d hubs\n", + is_uv1_hub() ? uv_num_possible_blades() : + (uv_num_possible_blades() + 1) / 2, + uv_num_possible_blades()); bytes = sizeof(struct uv_blade_info) * uv_num_possible_blades(); uv_blade_info = kzalloc(bytes, GFP_KERNEL); From 9d3f99878bf33d36739bd772c7dafcb1f71387fb Mon Sep 17 00:00:00 2001 From: David Daney Date: Mon, 19 Dec 2011 17:42:42 -0800 Subject: [PATCH 0707/4025] recordmcount: Fix handling of elf64 big-endian objects. commit 2e885057b7f75035f0b85e02f737891482815a81 upstream. In ELF64, the sh_flags field is 64-bits wide. recordmcount was erroneously treating it as a 32-bit wide field. For little endian objects this works because the flags of interest (SHF_EXECINSTR) reside in the lower 32 bits of the word, and you get the same result with either a 32-bit or 64-bit read. Big endian objects on the other hand do not work at all with this error. The fix: Correctly treat sh_flags as 64-bits wide in elf64 objects. The symptom I observed was that my __start_mcount_loc..__stop_mcount_loc was empty even though ftrace function tracing was enabled. Link: http://lkml.kernel.org/r/1324345362-12230-1-git-send-email-ddaney.cavm@gmail.com Signed-off-by: David Daney Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- scripts/recordmcount.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/recordmcount.h b/scripts/recordmcount.h index f40a6af6bf4..54e35c1e594 100644 --- a/scripts/recordmcount.h +++ b/scripts/recordmcount.h @@ -462,7 +462,7 @@ __has_rel_mcount(Elf_Shdr const *const relhdr, /* is SHT_REL or SHT_RELA */ succeed_file(); } if (w(txthdr->sh_type) != SHT_PROGBITS || - !(w(txthdr->sh_flags) & SHF_EXECINSTR)) + !(_w(txthdr->sh_flags) & SHF_EXECINSTR)) return NULL; return txtname; } From 087bc746ef05511c3e416846a8eae4588756462c Mon Sep 17 00:00:00 2001 From: Haogang Chen Date: Tue, 29 Nov 2011 18:32:25 -0300 Subject: [PATCH 0708/4025] uvcvideo: Fix integer overflow in uvc_ioctl_ctrl_map() commit 806e23e95f94a27ee445022d724060b9b45cb64a upstream. There is a potential integer overflow in uvc_ioctl_ctrl_map(). When a large xmap->menu_count is passed from the userspace, the subsequent call to kmalloc() will allocate a buffer smaller than expected. map->menu_count and map->menu_info would later be used in a loop (e.g. in uvc_query_v4l2_ctrl), which leads to out-of-bound access. The patch checks the ioctl argument and returns -EINVAL for zero or too large values in xmap->menu_count. Signed-off-by: Haogang Chen [laurent.pinchart@ideasonboard.com Prevent excessive memory consumption] Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/uvc/uvc_v4l2.c | 9 +++++++++ drivers/media/video/uvc/uvcvideo.h | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 543a80395b7..dbefdb09c10 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -65,6 +65,15 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, goto done; } + /* Prevent excessive memory consumption, as well as integer + * overflows. + */ + if (xmap->menu_count == 0 || + xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) { + ret = -EINVAL; + goto done; + } + size = xmap->menu_count * sizeof(*map->menu_info); map->menu_info = kmalloc(size, GFP_KERNEL); if (map->menu_info == NULL) { diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index 2a38d5e5535..cf2401a041a 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -200,6 +200,7 @@ struct uvc_xu_control { /* Maximum allowed number of control mappings per device */ #define UVC_MAX_CONTROL_MAPPINGS 1024 +#define UVC_MAX_CONTROL_MENU_ENTRIES 32 /* Devices quirks */ #define UVC_QUIRK_STATUS_INTERVAL 0x00000001 From 8039a47e67451b8efd6100c4a7f27829fc2d8edd Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 10 Jan 2012 18:22:25 +0100 Subject: [PATCH 0709/4025] fix shrink_dcache_parent() livelock commit eaf5f9073533cde21c7121c136f1c3f072d9cf59 upstream. Two (or more) concurrent calls of shrink_dcache_parent() on the same dentry may cause shrink_dcache_parent() to loop forever. Here's what appears to happen: 1 - CPU0: select_parent(P) finds C and puts it on dispose list, returns 1 2 - CPU1: select_parent(P) locks P->d_lock 3 - CPU0: shrink_dentry_list() locks C->d_lock dentry_kill(C) tries to lock P->d_lock but fails, unlocks C->d_lock 4 - CPU1: select_parent(P) locks C->d_lock, moves C from dispose list being processed on CPU0 to the new dispose list, returns 1 5 - CPU0: shrink_dentry_list() finds dispose list empty, returns 6 - Goto 2 with CPU0 and CPU1 switched Basically select_parent() steals the dentry from shrink_dentry_list() and thinks it found a new one, causing shrink_dentry_list() to think it's making progress and loop over and over. One way to trigger this is to make udev calls stat() on the sysfs file while it is going away. Having a file in /lib/udev/rules.d/ with only this one rule seems to the trick: ATTR{vendor}=="0x8086", ATTR{device}=="0x10ca", ENV{PCI_SLOT_NAME}="%k", ENV{MATCHADDR}="$attr{address}", RUN+="/bin/true" Then execute the following loop: while true; do echo -bond0 > /sys/class/net/bonding_masters echo +bond0 > /sys/class/net/bonding_masters echo -bond1 > /sys/class/net/bonding_masters echo +bond1 > /sys/class/net/bonding_masters done One fix would be to check all callers and prevent concurrent calls to shrink_dcache_parent(). But I think a better solution is to stop the stealing behavior. This patch adds a new dentry flag that is set when the dentry is added to the dispose list. The flag is cleared in dentry_lru_del() in case the dentry gets a new reference just before being pruned. If the dentry has this flag, select_parent() will skip it and let shrink_dentry_list() retry pruning it. With select_parent() skipping those dentries there will not be the appearance of progress (new dentries found) when there is none, hence shrink_dcache_parent() will not loop forever. Set the flag is also set in prune_dcache_sb() for consistency as suggested by Linus. Signed-off-by: Miklos Szeredi Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/dcache.c | 14 ++++++++++---- include/linux/dcache.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index d2f8feb75da..f598b98c00d 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -241,6 +241,7 @@ static void dentry_lru_add(struct dentry *dentry) static void __dentry_lru_del(struct dentry *dentry) { list_del_init(&dentry->d_lru); + dentry->d_flags &= ~DCACHE_SHRINK_LIST; dentry->d_sb->s_nr_dentry_unused--; dentry_stat.nr_unused--; } @@ -753,6 +754,7 @@ static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags) spin_unlock(&dentry->d_lock); } else { list_move_tail(&dentry->d_lru, &tmp); + dentry->d_flags |= DCACHE_SHRINK_LIST; spin_unlock(&dentry->d_lock); if (!--cnt) break; @@ -1144,14 +1146,18 @@ static int select_parent(struct dentry * parent) /* * move only zero ref count dentries to the end * of the unused list for prune_dcache + * + * Those which are presently on the shrink list, being processed + * by shrink_dentry_list(), shouldn't be moved. Otherwise the + * loop in shrink_dcache_parent() might not make any progress + * and loop forever. */ - if (!dentry->d_count) { + if (dentry->d_count) { + dentry_lru_del(dentry); + } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) { dentry_lru_move_tail(dentry); found++; - } else { - dentry_lru_del(dentry); } - /* * We can return to the caller if we have found some (this * ensures forward progress). We'll be coming back to find diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 8f848e462b2..f13bb6dd156 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -207,6 +207,7 @@ struct dentry_operations { #define DCACHE_CANT_MOUNT 0x0100 #define DCACHE_GENOCIDE 0x0200 +#define DCACHE_SHRINK_LIST 0x0400 #define DCACHE_OP_HASH 0x1000 #define DCACHE_OP_COMPARE 0x2000 From d253520a7b2c2223fb4f704f06d10f2c547bdeef Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Tue, 8 Nov 2011 12:12:44 +0000 Subject: [PATCH 0710/4025] ah: Correctly pass error codes in ahash output callback. commit 069294e813ed5f27f82613b027609bcda5f1b914 upstream. The AH4/6 ahash output callbacks pass nexthdr to xfrm_output_resume instead of the error code. This appears to be a copy+paste error from the input case, where nexthdr is expected. This causes the driver to continuously add AH headers to the datagram until either an allocation fails and the packet is dropped or the ahash driver hits a synchronous fallback and the resulting monstrosity is transmitted. Correct this issue by simply passing the error code unadulterated. Signed-off-by: Nick Bowler Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ah4.c | 2 -- net/ipv6/ah6.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index c1f4154552f..33ca18603e3 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -136,8 +136,6 @@ static void ah_output_done(struct crypto_async_request *base, int err) memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); } - err = ah->nexthdr; - kfree(AH_SKB_CB(skb)->tmp); xfrm_output_resume(skb, err); } diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 2195ae65192..ede4d9d6cc2 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -324,8 +324,6 @@ static void ah6_output_done(struct crypto_async_request *base, int err) #endif } - err = ah->nexthdr; - kfree(AH_SKB_CB(skb)->tmp); xfrm_output_resume(skb, err); } From c0ab420c6822529fa5aba05668e1e983b065460f Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Tue, 8 Nov 2011 12:12:45 +0000 Subject: [PATCH 0711/4025] ah: Read nexthdr value before overwriting it in ahash input callback. commit b7ea81a58adc123a4e980cb0eff9eb5c144b5dc7 upstream. The AH4/6 ahash input callbacks read out the nexthdr field from the AH header *after* they overwrite that header. This is obviously not going to end well. Fix it up. Signed-off-by: Nick Bowler Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ah4.c | 4 ++-- net/ipv6/ah6.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 33ca18603e3..c7056b2e831 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -262,12 +262,12 @@ static void ah_input_done(struct crypto_async_request *base, int err) if (err) goto out; + err = ah->nexthdr; + skb->network_header += ah_hlen; memcpy(skb_network_header(skb), work_iph, ihl); __skb_pull(skb, ah_hlen + ihl); skb_set_transport_header(skb, -ihl); - - err = ah->nexthdr; out: kfree(AH_SKB_CB(skb)->tmp); xfrm_input_resume(skb, err); diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index ede4d9d6cc2..7a33aaa0022 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -464,12 +464,12 @@ static void ah6_input_done(struct crypto_async_request *base, int err) if (err) goto out; + err = ah->nexthdr; + skb->network_header += ah_hlen; memcpy(skb_network_header(skb), work_iph, hdr_len); __skb_pull(skb, ah_hlen + hdr_len); skb_set_transport_header(skb, -hdr_len); - - err = ah->nexthdr; out: kfree(AH_SKB_CB(skb)->tmp); xfrm_input_resume(skb, err); From 242d5138b1a8f4a2519518027fff884fce3eeba4 Mon Sep 17 00:00:00 2001 From: Chris Bagwell Date: Wed, 23 Nov 2011 10:54:27 +0100 Subject: [PATCH 0712/4025] HID: hid-multitouch - add another eGalax id commit 1fd8f047490dd0ec4e4db710fcbc1bd4798d944c upstream. This allows ASUS Eee Slate touchscreens to work. Signed-off-by: Chris Bagwell Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-multitouch.c | 3 +++ 3 files changed, 5 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 22d53e7a223..e7373bfbba8 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1387,6 +1387,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH5) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) }, { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 206f75021d5..c1732e1d197 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -235,6 +235,7 @@ #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2 0x72a1 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3 0x480e #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4 0x726b +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH5 0xa001 #define USB_VENDOR_ID_ELECOM 0x056e #define USB_DEVICE_ID_ELECOM_BM084 0x0061 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 685d8e42587..0099bc4e270 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -646,6 +646,9 @@ static const struct hid_device_id mt_devices[] = { { .driver_data = MT_CLS_EGALAX, HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, + { .driver_data = MT_CLS_EGALAX, + HID_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH5) }, /* Elo TouchSystems IntelliTouch Plus panel */ { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID, From 369f7532bcaa78eb3919306e1ff997aa14bbfbbb Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 23 Nov 2011 10:54:31 +0100 Subject: [PATCH 0713/4025] HID: multitouch: cleanup with eGalax PID definitions commit e36f690b37945e0a9bb1554e1546eeec93f7d1f6 upstream. This is just a renaming of USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH{N} to USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_{PID} to handle more eGalax devices. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 12 ++++++------ drivers/hid/hid-ids.h | 12 ++++++------ drivers/hid/hid-multitouch.c | 24 ++++++++++++------------ 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e7373bfbba8..f4465f1f1bc 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1382,12 +1382,12 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) }, - { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, - { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) }, - { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, - { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH5) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) }, { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index c1732e1d197..c4ee677d20b 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -230,12 +230,12 @@ #define USB_VENDOR_ID_DWAV 0x0eef #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001 -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH 0x480d -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1 0x720c -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2 0x72a1 -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3 0x480e -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4 0x726b -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH5 0xa001 +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D 0x480d +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E 0x480e +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C 0x720c +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B 0x726b +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1 0x72a1 +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001 #define USB_VENDOR_ID_ELECOM 0x056e #define USB_DEVICE_ID_ELECOM_BM084 0x0061 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 0099bc4e270..fdf573cb412 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -629,26 +629,26 @@ static const struct hid_device_id mt_devices[] = { USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, /* eGalax devices (resistive) */ - { .driver_data = MT_CLS_EGALAX, + { .driver_data = MT_CLS_EGALAX, HID_USB_DEVICE(USB_VENDOR_ID_DWAV, - USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, - { .driver_data = MT_CLS_EGALAX, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D) }, + { .driver_data = MT_CLS_EGALAX, HID_USB_DEVICE(USB_VENDOR_ID_DWAV, - USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) }, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E) }, /* eGalax devices (capacitive) */ - { .driver_data = MT_CLS_EGALAX, + { .driver_data = MT_CLS_EGALAX, HID_USB_DEVICE(USB_VENDOR_ID_DWAV, - USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, - { .driver_data = MT_CLS_EGALAX, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) }, + { .driver_data = MT_CLS_EGALAX, HID_USB_DEVICE(USB_VENDOR_ID_DWAV, - USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) }, - { .driver_data = MT_CLS_EGALAX, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) }, + { .driver_data = MT_CLS_EGALAX, HID_USB_DEVICE(USB_VENDOR_ID_DWAV, - USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, - { .driver_data = MT_CLS_EGALAX, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) }, + { .driver_data = MT_CLS_EGALAX, HID_USB_DEVICE(USB_VENDOR_ID_DWAV, - USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH5) }, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, /* Elo TouchSystems IntelliTouch Plus panel */ { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID, From a92035b63540e2d47326540dc38625283143b770 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 23 Nov 2011 10:54:32 +0100 Subject: [PATCH 0714/4025] HID: multitouch: Add egalax ID for Acer Iconia W500 commit bb9ff21072043634f147c05ac65dbf8185d4af6d upstream. This patch adds USB ID for the touchpanel in Acer Iconia W500. The panel supports up to five fingers, therefore the need for a new addition of panel types. Signed-off-by: Marek Vasut Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + drivers/hid/hid-multitouch.c | 3 +++ 3 files changed, 5 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index f4465f1f1bc..2f855b128d8 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1387,6 +1387,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2515) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index c4ee677d20b..d25c8c583ee 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -235,6 +235,7 @@ #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C 0x720c #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B 0x726b #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1 0x72a1 +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302 0x7302 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001 #define USB_VENDOR_ID_ELECOM 0x056e diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index fdf573cb412..d0afd12158e 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -646,6 +646,9 @@ static const struct hid_device_id mt_devices[] = { { .driver_data = MT_CLS_EGALAX, HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) }, + { .driver_data = MT_CLS_EGALAX, + HID_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) }, { .driver_data = MT_CLS_EGALAX, HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, From 1628de01ac388c9104ddc2816491ff591dfe28a8 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 23 Nov 2011 10:54:33 +0100 Subject: [PATCH 0715/4025] HID: multitouch: add support for the MSI Windpad 110W commit 66f06127f34ad6e8a1b24a2c03144b694d19f99f upstream. Just another eGalax device. Please note that adding this device to have_special_driver in hid-core.c is not required anymore. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-multitouch.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index d25c8c583ee..92d4f07c48f 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -235,6 +235,7 @@ #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C 0x720c #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B 0x726b #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1 0x72a1 +#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA 0x72fa #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302 0x7302 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index d0afd12158e..c78350ea25a 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -646,6 +646,9 @@ static const struct hid_device_id mt_devices[] = { { .driver_data = MT_CLS_EGALAX, HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1) }, + { .driver_data = MT_CLS_EGALAX, + HID_USB_DEVICE(USB_VENDOR_ID_DWAV, + USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA) }, { .driver_data = MT_CLS_EGALAX, HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302) }, From 277a05f83af8c82291cf5f2ad0c2dd1aa6f29de7 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 23 Dec 2011 15:41:00 +0100 Subject: [PATCH 0716/4025] HID: multitouch: add support for 3M 32" commit c4fad877cd0efb51d8180ae2eaa791c99c92051c upstream. Signed-off-by: Benjamin Tissoires Acked-by: Henrik Rydberg Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-multitouch.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 92d4f07c48f..e0a28ade952 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -21,6 +21,7 @@ #define USB_VENDOR_ID_3M 0x0596 #define USB_DEVICE_ID_3M1968 0x0500 #define USB_DEVICE_ID_3M2256 0x0502 +#define USB_DEVICE_ID_3M3266 0x0506 #define USB_VENDOR_ID_A4TECH 0x09da #define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index c78350ea25a..1308703afdb 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -593,6 +593,9 @@ static const struct hid_device_id mt_devices[] = { { .driver_data = MT_CLS_3M, HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) }, + { .driver_data = MT_CLS_3M, + HID_USB_DEVICE(USB_VENDOR_ID_3M, + USB_DEVICE_ID_3M3266) }, /* ActionStar panels */ { .driver_data = MT_CLS_DEFAULT, From 3ec3f83aee534f732fd7012ff6c04776952e47fd Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 15 Dec 2011 14:56:10 +0100 Subject: [PATCH 0717/4025] fix cputime overflow in uptime_proc_show commit c3e0ef9a298e028a82ada28101ccd5cf64d209ee upstream. For 32-bit architectures using standard jiffies the idletime calculation in uptime_proc_show will quickly overflow. It takes (2^32 / HZ) seconds of idle-time, or e.g. 12.45 days with no load on a quad-core with HZ=1000. Switch to 64-bit calculations. Cc: Michael Abbott Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- fs/proc/uptime.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/proc/uptime.c b/fs/proc/uptime.c index 766b1d45605..29166ecd03a 100644 --- a/fs/proc/uptime.c +++ b/fs/proc/uptime.c @@ -11,15 +11,20 @@ static int uptime_proc_show(struct seq_file *m, void *v) { struct timespec uptime; struct timespec idle; + cputime64_t idletime; + u64 nsec; + u32 rem; int i; - cputime_t idletime = cputime_zero; + idletime = 0; for_each_possible_cpu(i) idletime = cputime64_add(idletime, kstat_cpu(i).cpustat.idle); do_posix_clock_monotonic_gettime(&uptime); monotonic_to_bootbased(&uptime); - cputime_to_timespec(idletime, &idle); + nsec = cputime64_to_jiffies64(idletime) * TICK_NSEC; + idle.tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem); + idle.tv_nsec = rem; seq_printf(m, "%lu.%02lu %lu.%02lu\n", (unsigned long) uptime.tv_sec, (uptime.tv_nsec / (NSEC_PER_SEC / 100)), From 3b8373b85c761b2a12bdaf9fcee4c7a3eefa8459 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 12 Jan 2012 16:01:27 +0100 Subject: [PATCH 0718/4025] block: add and use scsi_blk_cmd_ioctl commit 577ebb374c78314ac4617242f509e2f5e7156649 upstream. Introduce a wrapper around scsi_cmd_ioctl that takes a block device. The function will then be enhanced to detect partition block devices and, in that case, subject the ioctls to whitelisting. Cc: linux-scsi@vger.kernel.org Cc: Jens Axboe Cc: James Bottomley Signed-off-by: Paolo Bonzini Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- block/scsi_ioctl.c | 7 +++++++ drivers/block/cciss.c | 6 +++--- drivers/block/ub.c | 3 +-- drivers/block/virtio_blk.c | 4 ++-- drivers/cdrom/cdrom.c | 3 +-- drivers/ide/ide-floppy_ioctl.c | 3 +-- drivers/scsi/sd.c | 2 +- include/linux/blkdev.h | 2 ++ 8 files changed, 18 insertions(+), 12 deletions(-) diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 4f4230b79bb..57ac9375484 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -691,6 +691,13 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod } EXPORT_SYMBOL(scsi_cmd_ioctl); +int scsi_cmd_blk_ioctl(struct block_device *bd, fmode_t mode, + unsigned int cmd, void __user *arg) +{ + return scsi_cmd_ioctl(bd->bd_disk->queue, bd->bd_disk, mode, cmd, arg); +} +EXPORT_SYMBOL(scsi_cmd_blk_ioctl); + static int __init blk_scsi_ioctl_init(void) { blk_set_cmd_filter_defaults(&blk_default_cmd_filter); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index c2f9b3e3dec..1dab802d82b 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -1716,7 +1716,7 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode, case CCISS_BIG_PASSTHRU: return cciss_bigpassthru(h, argp); - /* scsi_cmd_ioctl handles these, below, though some are not */ + /* scsi_cmd_blk_ioctl handles these, below, though some are not */ /* very meaningful for cciss. SG_IO is the main one people want. */ case SG_GET_VERSION_NUM: @@ -1727,9 +1727,9 @@ static int cciss_ioctl(struct block_device *bdev, fmode_t mode, case SG_EMULATED_HOST: case SG_IO: case SCSI_IOCTL_SEND_COMMAND: - return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp); + return scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); - /* scsi_cmd_ioctl would normally handle these, below, but */ + /* scsi_cmd_blk_ioctl would normally handle these, below, but */ /* they aren't a good fit for cciss, as CD-ROMs are */ /* not supported, and we don't have any bus/target/lun */ /* which we present to the kernel. */ diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 0e376d46bdd..7333b9e4441 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -1744,12 +1744,11 @@ static int ub_bd_release(struct gendisk *disk, fmode_t mode) static int ub_bd_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { - struct gendisk *disk = bdev->bd_disk; void __user *usermem = (void __user *) arg; int ret; mutex_lock(&ub_mutex); - ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, usermem); + ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, usermem); mutex_unlock(&ub_mutex); return ret; diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 079c08808d8..5d7a9340363 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -236,8 +236,8 @@ static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI)) return -ENOTTY; - return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, - (void __user *)data); + return scsi_cmd_blk_ioctl(bdev, mode, cmd, + (void __user *)data); } /* We provide getgeo only to please some old bootloader/partitioning tools */ diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 75fb965b8f7..b693cbdb421 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2741,12 +2741,11 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, { void __user *argp = (void __user *)arg; int ret; - struct gendisk *disk = bdev->bd_disk; /* * Try the generic SCSI command ioctl's first. */ - ret = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp); + ret = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); if (ret != -ENOTTY) return ret; diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c index d267b7affad..a22ca846701 100644 --- a/drivers/ide/ide-floppy_ioctl.c +++ b/drivers/ide/ide-floppy_ioctl.c @@ -292,8 +292,7 @@ int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev, * and CDROM_SEND_PACKET (legacy) ioctls */ if (cmd != CDROM_SEND_PACKET && cmd != SCSI_IOCTL_SEND_COMMAND) - err = scsi_cmd_ioctl(bdev->bd_disk->queue, bdev->bd_disk, - mode, cmd, argp); + err = scsi_cmd_blk_ioctl(bdev, mode, cmd, argp); if (err == -ENOTTY) err = generic_ide_ioctl(drive, bdev, cmd, arg); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 953773cb26d..c88885d9132 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1095,7 +1095,7 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, error = scsi_ioctl(sdp, cmd, p); break; default: - error = scsi_cmd_ioctl(disk->queue, disk, mode, cmd, p); + error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p); if (error != -ENOTTY) break; error = scsi_ioctl(sdp, cmd, p); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index cd93f9994ad..0eca8080bb6 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -670,6 +670,8 @@ extern int blk_insert_cloned_request(struct request_queue *q, struct request *rq); extern void blk_delay_queue(struct request_queue *, unsigned long); extern void blk_recount_segments(struct request_queue *, struct bio *); +extern int scsi_cmd_blk_ioctl(struct block_device *, fmode_t, + unsigned int, void __user *); extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, unsigned int, void __user *); extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t, From 8bd8442fec18284924e17a0fa8ef89d98b0a6d71 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 12 Jan 2012 16:01:28 +0100 Subject: [PATCH 0719/4025] block: fail SCSI passthrough ioctls on partition devices commit 0bfc96cb77224736dfa35c3c555d37b3646ef35e upstream. [ Changes with respect to 3.3: return -ENOTTY from scsi_verify_blk_ioctl and -ENOIOCTLCMD from sd_compat_ioctl. ] Linux allows executing the SG_IO ioctl on a partition or LVM volume, and will pass the command to the underlying block device. This is well-known, but it is also a large security problem when (via Unix permissions, ACLs, SELinux or a combination thereof) a program or user needs to be granted access only to part of the disk. This patch lets partitions forward a small set of harmless ioctls; others are logged with printk so that we can see which ioctls are actually sent. In my tests only CDROM_GET_CAPABILITY actually occurred. Of course it was being sent to a (partition on a) hard disk, so it would have failed with ENOTTY and the patch isn't changing anything in practice. Still, I'm treating it specially to avoid spamming the logs. In principle, this restriction should include programs running with CAP_SYS_RAWIO. If for example I let a program access /dev/sda2 and /dev/sdb, it still should not be able to read/write outside the boundaries of /dev/sda2 independent of the capabilities. However, for now programs with CAP_SYS_RAWIO will still be allowed to send the ioctls. Their actions will still be logged. This patch does not affect the non-libata IDE driver. That driver however already tests for bd != bd->bd_contains before issuing some ioctl; it could be restricted further to forbid these ioctls even for programs running with CAP_SYS_ADMIN/CAP_SYS_RAWIO. Cc: linux-scsi@vger.kernel.org Cc: Jens Axboe Cc: James Bottomley Signed-off-by: Paolo Bonzini [ Make it also print the command name when warning - Linus ] Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- block/scsi_ioctl.c | 45 ++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/sd.c | 11 +++++++++-- include/linux/blkdev.h | 1 + 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index 57ac9375484..5ef1f4c17e6 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -691,9 +692,53 @@ int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mod } EXPORT_SYMBOL(scsi_cmd_ioctl); +int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd) +{ + if (bd && bd == bd->bd_contains) + return 0; + + /* Actually none of these is particularly useful on a partition, + * but they are safe. + */ + switch (cmd) { + case SCSI_IOCTL_GET_IDLUN: + case SCSI_IOCTL_GET_BUS_NUMBER: + case SCSI_IOCTL_GET_PCI: + case SCSI_IOCTL_PROBE_HOST: + case SG_GET_VERSION_NUM: + case SG_SET_TIMEOUT: + case SG_GET_TIMEOUT: + case SG_GET_RESERVED_SIZE: + case SG_SET_RESERVED_SIZE: + case SG_EMULATED_HOST: + return 0; + case CDROM_GET_CAPABILITY: + /* Keep this until we remove the printk below. udev sends it + * and we do not want to spam dmesg about it. CD-ROMs do + * not have partitions, so we get here only for disks. + */ + return -ENOTTY; + default: + break; + } + + /* In particular, rule out all resets and host-specific ioctls. */ + printk_ratelimited(KERN_WARNING + "%s: sending ioctl %x to a partition!\n", current->comm, cmd); + + return capable(CAP_SYS_RAWIO) ? 0 : -ENOTTY; +} +EXPORT_SYMBOL(scsi_verify_blk_ioctl); + int scsi_cmd_blk_ioctl(struct block_device *bd, fmode_t mode, unsigned int cmd, void __user *arg) { + int ret; + + ret = scsi_verify_blk_ioctl(bd, cmd); + if (ret < 0) + return ret; + return scsi_cmd_ioctl(bd->bd_disk->queue, bd->bd_disk, mode, cmd, arg); } EXPORT_SYMBOL(scsi_cmd_blk_ioctl); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index c88885d9132..7d8b5d8d749 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1073,6 +1073,10 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode, SCSI_LOG_IOCTL(1, printk("sd_ioctl: disk=%s, cmd=0x%x\n", disk->disk_name, cmd)); + error = scsi_verify_blk_ioctl(bdev, cmd); + if (error < 0) + return error; + /* * If we are in the middle of error recovery, don't let anyone * else try and use this device. Also, if error recovery fails, it @@ -1265,6 +1269,11 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device; + int ret; + + ret = scsi_verify_blk_ioctl(bdev, cmd); + if (ret < 0) + return -ENOIOCTLCMD; /* * If we are in the middle of error recovery, don't let anyone @@ -1276,8 +1285,6 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode, return -ENODEV; if (sdev->host->hostt->compat_ioctl) { - int ret; - ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg); return ret; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 0eca8080bb6..1b130216ccd 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -670,6 +670,7 @@ extern int blk_insert_cloned_request(struct request_queue *q, struct request *rq); extern void blk_delay_queue(struct request_queue *, unsigned long); extern void blk_recount_segments(struct request_queue *, struct bio *); +extern int scsi_verify_blk_ioctl(struct block_device *, unsigned int); extern int scsi_cmd_blk_ioctl(struct block_device *, fmode_t, unsigned int, void __user *); extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, From 12c3b3ac1e8004616b30aec6acee1bb91badeb99 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 12 Jan 2012 16:01:29 +0100 Subject: [PATCH 0720/4025] dm: do not forward ioctls from logical volumes to the underlying device commit ec8013beddd717d1740cfefb1a9b900deef85462 upstream. A logical volume can map to just part of underlying physical volume. In this case, it must be treated like a partition. Based on a patch from Alasdair G Kergon. Cc: Alasdair G Kergon Cc: dm-devel@redhat.com Signed-off-by: Paolo Bonzini Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-flakey.c | 11 ++++++++++- drivers/md/dm-linear.c | 12 +++++++++++- drivers/md/dm-mpath.c | 6 ++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c index ea790623c30..3e90b8014f9 100644 --- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -149,8 +149,17 @@ static int flakey_status(struct dm_target *ti, status_type_t type, static int flakey_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg) { struct flakey_c *fc = ti->private; + struct dm_dev *dev = fc->dev; + int r = 0; - return __blkdev_driver_ioctl(fc->dev->bdev, fc->dev->mode, cmd, arg); + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (fc->start || + ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT) + r = scsi_verify_blk_ioctl(NULL, cmd); + + return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg); } static int flakey_merge(struct dm_target *ti, struct bvec_merge_data *bvm, diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 3921e3bb43c..9728839f844 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -116,7 +116,17 @@ static int linear_ioctl(struct dm_target *ti, unsigned int cmd, unsigned long arg) { struct linear_c *lc = (struct linear_c *) ti->private; - return __blkdev_driver_ioctl(lc->dev->bdev, lc->dev->mode, cmd, arg); + struct dm_dev *dev = lc->dev; + int r = 0; + + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (lc->start || + ti->len != i_size_read(dev->bdev->bd_inode) >> SECTOR_SHIFT) + r = scsi_verify_blk_ioctl(NULL, cmd); + + return r ? : __blkdev_driver_ioctl(dev->bdev, dev->mode, cmd, arg); } static int linear_merge(struct dm_target *ti, struct bvec_merge_data *bvm, diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 209991bebd3..70373bfa20b 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -1584,6 +1584,12 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, spin_unlock_irqrestore(&m->lock, flags); + /* + * Only pass ioctls through if the device sizes match exactly. + */ + if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) + r = scsi_verify_blk_ioctl(NULL, cmd); + return r ? : __blkdev_driver_ioctl(bdev, mode, cmd, arg); } From c8fec258e5d1c35712795641350cc78da4334629 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 17 Jan 2012 15:21:19 -0800 Subject: [PATCH 0721/4025] proc: clean up and fix /proc//mem handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e268337dfe26dfc7efd422a804dbb27977a3cccc upstream. Jüri Aedla reported that the /proc//mem handling really isn't very robust, and it also doesn't match the permission checking of any of the other related files. This changes it to do the permission checks at open time, and instead of tracking the process, it tracks the VM at the time of the open. That simplifies the code a lot, but does mean that if you hold the file descriptor open over an execve(), you'll continue to read from the _old_ VM. That is different from our previous behavior, but much simpler. If somebody actually finds a load where this matters, we'll need to revert this commit. I suspect that nobody will ever notice - because the process mapping addresses will also have changed as part of the execve. So you cannot actually usefully access the fd across a VM change simply because all the offsets for IO would have changed too. Reported-by: Jüri Aedla Cc: Al Viro Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/proc/base.c | 145 +++++++++++++------------------------------------ 1 file changed, 39 insertions(+), 106 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index f0390177be9..7b28f27ad80 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -194,65 +194,7 @@ static int proc_root_link(struct inode *inode, struct path *path) return result; } -static struct mm_struct *__check_mem_permission(struct task_struct *task) -{ - struct mm_struct *mm; - - mm = get_task_mm(task); - if (!mm) - return ERR_PTR(-EINVAL); - - /* - * A task can always look at itself, in case it chooses - * to use system calls instead of load instructions. - */ - if (task == current) - return mm; - - /* - * If current is actively ptrace'ing, and would also be - * permitted to freshly attach with ptrace now, permit it. - */ - if (task_is_stopped_or_traced(task)) { - int match; - rcu_read_lock(); - match = (tracehook_tracer_task(task) == current); - rcu_read_unlock(); - if (match && ptrace_may_access(task, PTRACE_MODE_ATTACH)) - return mm; - } - - /* - * No one else is allowed. - */ - mmput(mm); - return ERR_PTR(-EPERM); -} - -/* - * If current may access user memory in @task return a reference to the - * corresponding mm, otherwise ERR_PTR. - */ -static struct mm_struct *check_mem_permission(struct task_struct *task) -{ - struct mm_struct *mm; - int err; - - /* - * Avoid racing if task exec's as we might get a new mm but validate - * against old credentials. - */ - err = mutex_lock_killable(&task->signal->cred_guard_mutex); - if (err) - return ERR_PTR(err); - - mm = __check_mem_permission(task); - mutex_unlock(&task->signal->cred_guard_mutex); - - return mm; -} - -struct mm_struct *mm_for_maps(struct task_struct *task) +static struct mm_struct *mm_access(struct task_struct *task, unsigned int mode) { struct mm_struct *mm; int err; @@ -263,7 +205,7 @@ struct mm_struct *mm_for_maps(struct task_struct *task) mm = get_task_mm(task); if (mm && mm != current->mm && - !ptrace_may_access(task, PTRACE_MODE_READ)) { + !ptrace_may_access(task, mode)) { mmput(mm); mm = ERR_PTR(-EACCES); } @@ -272,6 +214,11 @@ struct mm_struct *mm_for_maps(struct task_struct *task) return mm; } +struct mm_struct *mm_for_maps(struct task_struct *task) +{ + return mm_access(task, PTRACE_MODE_READ); +} + static int proc_pid_cmdline(struct task_struct *task, char * buffer) { int res = 0; @@ -816,38 +763,39 @@ static const struct file_operations proc_single_file_operations = { static int mem_open(struct inode* inode, struct file* file) { - file->private_data = (void*)((long)current->self_exec_id); + struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); + struct mm_struct *mm; + + if (!task) + return -ESRCH; + + mm = mm_access(task, PTRACE_MODE_ATTACH); + put_task_struct(task); + + if (IS_ERR(mm)) + return PTR_ERR(mm); + /* OK to pass negative loff_t, we can catch out-of-range */ file->f_mode |= FMODE_UNSIGNED_OFFSET; + file->private_data = mm; + return 0; } static ssize_t mem_read(struct file * file, char __user * buf, size_t count, loff_t *ppos) { - struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); + int ret; char *page; unsigned long src = *ppos; - int ret = -ESRCH; - struct mm_struct *mm; + struct mm_struct *mm = file->private_data; - if (!task) - goto out_no_task; + if (!mm) + return 0; - ret = -ENOMEM; page = (char *)__get_free_page(GFP_TEMPORARY); if (!page) - goto out; - - mm = check_mem_permission(task); - ret = PTR_ERR(mm); - if (IS_ERR(mm)) - goto out_free; - - ret = -EIO; - - if (file->private_data != (void*)((long)current->self_exec_id)) - goto out_put; + return -ENOMEM; ret = 0; @@ -874,13 +822,7 @@ static ssize_t mem_read(struct file * file, char __user * buf, } *ppos = src; -out_put: - mmput(mm); -out_free: free_page((unsigned long) page); -out: - put_task_struct(task); -out_no_task: return ret; } @@ -889,27 +831,15 @@ static ssize_t mem_write(struct file * file, const char __user *buf, { int copied; char *page; - struct task_struct *task = get_proc_task(file->f_path.dentry->d_inode); unsigned long dst = *ppos; - struct mm_struct *mm; + struct mm_struct *mm = file->private_data; - copied = -ESRCH; - if (!task) - goto out_no_task; + if (!mm) + return 0; - copied = -ENOMEM; page = (char *)__get_free_page(GFP_TEMPORARY); if (!page) - goto out_task; - - mm = check_mem_permission(task); - copied = PTR_ERR(mm); - if (IS_ERR(mm)) - goto out_free; - - copied = -EIO; - if (file->private_data != (void *)((long)current->self_exec_id)) - goto out_mm; + return -ENOMEM; copied = 0; while (count > 0) { @@ -933,13 +863,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf, } *ppos = dst; -out_mm: - mmput(mm); -out_free: free_page((unsigned long) page); -out_task: - put_task_struct(task); -out_no_task: return copied; } @@ -959,11 +883,20 @@ loff_t mem_lseek(struct file *file, loff_t offset, int orig) return file->f_pos; } +static int mem_release(struct inode *inode, struct file *file) +{ + struct mm_struct *mm = file->private_data; + + mmput(mm); + return 0; +} + static const struct file_operations proc_mem_operations = { .llseek = mem_lseek, .read = mem_read, .write = mem_write, .open = mem_open, + .release = mem_release, }; static ssize_t environ_read(struct file *file, char __user *buf, From cb86f0a0920b63b179d2fa653c6c851db27d069a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Sat, 14 Jan 2012 16:42:24 +0100 Subject: [PATCH 0722/4025] ALSA: virtuoso: Xonar DS: fix polarity of front output commit f0e48b6bd4e407459715240cd241ddb6b89bdf81 upstream. The two DACs for the front output and the surround/center/LFE/back outputs are wired up out of phase, so when channels are duplicated, their sound can cancel out each other and result in a weaker bass response. To fix this, reverse the polarity of the neutron flow to the front output. Reported-any-tested-by: Daniel Hill Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/oxygen/xonar_wm87x6.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 42d1ab13621..915546a7954 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -177,6 +177,7 @@ static void wm8776_registers_init(struct oxygen *chip) struct xonar_wm87x6 *data = chip->model_data; wm8776_write(chip, WM8776_RESET, 0); + wm8776_write(chip, WM8776_PHASESWAP, WM8776_PH_MASK); wm8776_write(chip, WM8776_DACCTRL1, WM8776_DZCEN | WM8776_PL_LEFT_LEFT | WM8776_PL_RIGHT_RIGHT); wm8776_write(chip, WM8776_DACMUTE, chip->dac_mute ? WM8776_DMUTE : 0); From db52a757b355ec71670b4b0f85cd2d6f28306a79 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Mon, 16 Jan 2012 10:52:20 +0100 Subject: [PATCH 0723/4025] ALSA: HDA: Fix internal microphone on Dell Studio 16 XPS 1645 commit ffe535edb9a9c5b4d5fe03dfa3d89a1495580f1b upstream. More than one user reports that changing the model from "both" to "dmic" makes their Internal Mic work. Tested-by: Martin Ling BugLink: https://bugs.launchpad.net/bugs/795823 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_sigmatel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 5d2e97abb2e..0d8db75535d 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1602,7 +1602,7 @@ static const struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd, "Dell Studio 1557", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe, - "Dell Studio XPS 1645", STAC_DELL_M6_BOTH), + "Dell Studio XPS 1645", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413, "Dell Studio 1558", STAC_DELL_M6_DMIC), {} /* terminator */ From 57700d3c569071c4c43f220de637461850d027a1 Mon Sep 17 00:00:00 2001 From: Thomas Renninger Date: Sun, 4 Dec 2011 22:17:29 +0100 Subject: [PATCH 0724/4025] intel idle: Make idle driver more robust commit 5c2a9f06a9cd7194f884cdc88144866235dec07d upstream. kvm -cpu host passes the original cpuid info to the guest. Latest kvm version seem to return true for mwait_leaf cpuid function on recent Intel CPUs. But it does not return mwait C-states (mwait_substates), instead zero is returned. While real CPUs seem to always return non-zero values, the intel idle driver should not get active in kvm (mwait_substates == 0) case and bail out. Otherwise a Null pointer exception will happen later when the cpuidle subsystem tries to get active: [0.984807] BUG: unable to handle kernel NULL pointer dereference at (null) [0.984807] IP: [<(null)>] (null) ... [0.984807][] ? cpuidle_idle_call+0xb4/0x340 [0.984807][] ? __atomic_notifier_call_chain+0x4c/0x70 [0.984807][] ? cpu_idle+0x78/0xd0 Reference: https://bugzilla.novell.com/show_bug.cgi?id=726296 Signed-off-by: Thomas Renninger CC: Bruno Friedmann Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/idle/intel_idle.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index a46dddf6107..19c07c09106 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -321,7 +321,8 @@ static int intel_idle_probe(void) cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &mwait_substates); if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) || - !(ecx & CPUID5_ECX_INTERRUPT_BREAK)) + !(ecx & CPUID5_ECX_INTERRUPT_BREAK) || + !mwait_substates) return -ENODEV; pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates); From e26a6033d0d0183e613a1ae5eafefd3baf7f3e6c Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Tue, 10 Jan 2012 15:48:19 -0800 Subject: [PATCH 0725/4025] intel_idle: fix API misuse commit 39a74fdedd1c1461d6fb6d330b5266886513c98f upstream. smp_call_function() only lets all other CPUs execute a specific function, while we expect all CPUs do in intel_idle. Without the fix, we could have one cpu which has auto_demotion enabled or has no broadcast timer setup. Usually we don't see impact because auto demotion just harms power and the intel_idle init is called in CPU 0, where boradcast timer delivers interrupt, but this still could be a problem. Signed-off-by: Shaohua Li Signed-off-by: Andrew Morton Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/idle/intel_idle.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 19c07c09106..026f9aa789e 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -368,7 +368,7 @@ static int intel_idle_probe(void) if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE; else { - smp_call_function(__setup_broadcast_timer, (void *)true, 1); + on_each_cpu(__setup_broadcast_timer, (void *)true, 1); register_cpu_notifier(&setup_broadcast_notifier); } @@ -460,7 +460,7 @@ static int intel_idle_cpuidle_devices_init(void) } } if (auto_demotion_disable_flags) - smp_call_function(auto_demotion_disable, NULL, 1); + on_each_cpu(auto_demotion_disable, NULL, 1); return 0; } @@ -500,7 +500,7 @@ static void __exit intel_idle_exit(void) cpuidle_unregister_driver(&intel_idle_driver); if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) { - smp_call_function(__setup_broadcast_timer, (void *)false, 1); + on_each_cpu(__setup_broadcast_timer, (void *)false, 1); unregister_cpu_notifier(&setup_broadcast_notifier); } From 643147c50fde7eb0456953f468cc277d621f629e Mon Sep 17 00:00:00 2001 From: Kurt Garloff Date: Tue, 17 Jan 2012 04:18:02 -0500 Subject: [PATCH 0726/4025] ACPI: Store SRAT table revision commit 8df0eb7c9d96f9e82f233ee8b74e0f0c8471f868 upstream. In SRAT v1, we had 8bit proximity domain (PXM) fields; SRAT v2 provides 32bits for these. The new fields were reserved before. According to the ACPI spec, the OS must disregrard reserved fields. In order to know whether or not, we must know what version the SRAT table has. This patch stores the SRAT table revision for later consumption by arch specific __init functions. Signed-off-by: Kurt Garloff Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/numa.c | 6 ++++++ include/acpi/acpi_numa.h | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 3b5c3189fd9..e56f3be7b07 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -45,6 +45,8 @@ static int pxm_to_node_map[MAX_PXM_DOMAINS] static int node_to_pxm_map[MAX_NUMNODES] = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; +unsigned char acpi_srat_revision __initdata; + int pxm_to_node(int pxm) { if (pxm < 0) @@ -255,9 +257,13 @@ acpi_parse_memory_affinity(struct acpi_subtable_header * header, static int __init acpi_parse_srat(struct acpi_table_header *table) { + struct acpi_table_srat *srat; if (!table) return -EINVAL; + srat = (struct acpi_table_srat *)table; + acpi_srat_revision = srat->header.revision; + /* Real work done in acpi_table_parse_srat below. */ return 0; diff --git a/include/acpi/acpi_numa.h b/include/acpi/acpi_numa.h index 17397267217..451823cb883 100644 --- a/include/acpi/acpi_numa.h +++ b/include/acpi/acpi_numa.h @@ -15,6 +15,7 @@ extern int pxm_to_node(int); extern int node_to_pxm(int); extern void __acpi_map_pxm_to_node(int, int); extern int acpi_map_pxm_to_node(int); +extern unsigned char acpi_srat_revision; #endif /* CONFIG_ACPI_NUMA */ #endif /* __ACP_NUMA_H */ From ef9a04d5b336853aeb3f3975c4e52b07c1c4d3ec Mon Sep 17 00:00:00 2001 From: Kurt Garloff Date: Tue, 17 Jan 2012 04:20:31 -0500 Subject: [PATCH 0727/4025] ACPI, x86: Use SRAT table rev to use 8bit or 32bit PXM fields (x86/x86-64) commit cd298f60a2451a16e0f077404bf69b62ec868733 upstream. In SRAT v1, we had 8bit proximity domain (PXM) fields; SRAT v2 provides 32bits for these. The new fields were reserved before. According to the ACPI spec, the OS must disregrard reserved fields. x86/x86-64 was rather inconsistent prior to this patch; it used 8 bits for the pxm field in cpu_affinity, but 32 bits in mem_affinity. This patch makes it consistent: Either use 8 bits consistently (SRAT rev 1 or lower) or 32 bits (SRAT rev 2 or higher). cc: x86@kernel.org Signed-off-by: Kurt Garloff Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/srat.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c index 81dbfdeb080..7efd0c615d5 100644 --- a/arch/x86/mm/srat.c +++ b/arch/x86/mm/srat.c @@ -104,6 +104,8 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0) return; pxm = pa->proximity_domain_lo; + if (acpi_srat_revision >= 2) + pxm |= *((unsigned int*)pa->proximity_domain_hi) << 8; node = setup_node(pxm); if (node < 0) { printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm); @@ -155,6 +157,8 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma) start = ma->base_address; end = start + ma->length; pxm = ma->proximity_domain; + if (acpi_srat_revision <= 1) + pxm &= 0xff; node = setup_node(pxm); if (node < 0) { printk(KERN_ERR "SRAT: Too many proximity domains.\n"); From 0076d42a31bac7853d3c77c3858d2685f6fe8f2d Mon Sep 17 00:00:00 2001 From: Kurt Garloff Date: Tue, 17 Jan 2012 04:21:49 -0500 Subject: [PATCH 0728/4025] ACPI, ia64: Use SRAT table rev to use 8bit or 16/32bit PXM fields (ia64) commit 9f10f6a520deb3639fac78d81151a3ade88b4e7f upstream. In SRAT v1, we had 8bit proximity domain (PXM) fields; SRAT v2 provides 32bits for these. The new fields were reserved before. According to the ACPI spec, the OS must disregrard reserved fields. ia64 did handle the PXM fields almost consistently, but depending on sgi's sn2 platform. This patch leaves the sn2 logic in, but does also use 16/32 bits for PXM if the SRAT has rev 2 or higher. The patch also adds __init to the two pxm accessor functions, as they access __initdata now and are called from an __init function only anyway. Note that the code only uses 16 bits for the PXM field in the processor proximity field; the patch does not address this as 16 bits are more than enough. Signed-off-by: Kurt Garloff Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- arch/ia64/kernel/acpi.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 3be485a300b..f19de9f7f5f 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -429,22 +429,24 @@ static u32 __devinitdata pxm_flag[PXM_FLAG_LEN]; static struct acpi_table_slit __initdata *slit_table; cpumask_t early_cpu_possible_map = CPU_MASK_NONE; -static int get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa) +static int __init +get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa) { int pxm; pxm = pa->proximity_domain_lo; - if (ia64_platform_is("sn2")) + if (ia64_platform_is("sn2") || acpi_srat_revision >= 2) pxm += pa->proximity_domain_hi[0] << 8; return pxm; } -static int get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma) +static int __init +get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma) { int pxm; pxm = ma->proximity_domain; - if (!ia64_platform_is("sn2")) + if (!ia64_platform_is("sn2") && acpi_srat_revision <= 1) pxm &= 0xff; return pxm; From 55bd02eb4c6e40c2870aee19c5e36d1a85713be8 Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Tue, 29 Nov 2011 22:13:35 +0800 Subject: [PATCH 0729/4025] ACPICA: Put back the call to acpi_os_validate_address commit da4d8b287abe783d30e968155614531a0937d090 upstream. The call to acpi_os_validate_address in acpi_ds_get_region_arguments was removed by mistake in commit 9ad19ac(ACPICA: Split large dsopcode and dsload.c files). Put it back. Reported-and-bisected-by: Luca Tettamanti Signed-off-by: Lin Ming Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpica/dsargs.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c index 8c7b99728aa..42163d8db50 100644 --- a/drivers/acpi/acpica/dsargs.c +++ b/drivers/acpi/acpica/dsargs.c @@ -387,5 +387,29 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc) status = acpi_ds_execute_arguments(node, node->parent, extra_desc->extra.aml_length, extra_desc->extra.aml_start); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Validate the region address/length via the host OS */ + + status = acpi_os_validate_address(obj_desc->region.space_id, + obj_desc->region.address, + (acpi_size) obj_desc->region.length, + acpi_ut_get_node_name(node)); + + if (ACPI_FAILURE(status)) { + /* + * Invalid address/length. We will emit an error message and mark + * the region as invalid, so that it will cause an additional error if + * it is ever used. Then return AE_OK. + */ + ACPI_EXCEPTION((AE_INFO, status, + "During address validation of OpRegion [%4.4s]", + node->name.ascii)); + obj_desc->common.flags |= AOPOBJ_INVALID; + status = AE_OK; + } + return_ACPI_STATUS(status); } From 68e6689b9b35c8a2fa73e00947238d2c5cb0387c Mon Sep 17 00:00:00 2001 From: Lin Ming Date: Tue, 13 Dec 2011 09:36:03 +0800 Subject: [PATCH 0730/4025] ACPI: processor: fix acpi_get_cpuid for UP processor commit d640113fe80e45ebd4a5b420b220d3f6bf37f682 upstream. For UP processor, it is likely that no _MAT method or MADT table defined. So currently acpi_get_cpuid(...) always return -1 for UP processor. This is wrong. It should return valid value for CPU0. In the other hand, BIOS may define multiple CPU handles even for UP processor, for example Scope (_PR) { Processor (CPU0, 0x00, 0x00000410, 0x06) {} Processor (CPU1, 0x01, 0x00000410, 0x06) {} Processor (CPU2, 0x02, 0x00000410, 0x06) {} Processor (CPU3, 0x03, 0x00000410, 0x06) {} } We should only return valid value for CPU0's acpi handle. And return invalid value for others. http://marc.info/?t=132329819900003&r=1&w=2 Reported-and-tested-by: wallak@free.fr Signed-off-by: Lin Ming Signed-off-by: Len Brown Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/processor_core.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 02d2a4c9084..0c0669fb1cc 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -172,8 +172,30 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) apic_id = map_mat_entry(handle, type, acpi_id); if (apic_id == -1) apic_id = map_madt_entry(type, acpi_id); - if (apic_id == -1) - return apic_id; + if (apic_id == -1) { + /* + * On UP processor, there is no _MAT or MADT table. + * So above apic_id is always set to -1. + * + * BIOS may define multiple CPU handles even for UP processor. + * For example, + * + * Scope (_PR) + * { + * Processor (CPU0, 0x00, 0x00000410, 0x06) {} + * Processor (CPU1, 0x01, 0x00000410, 0x06) {} + * Processor (CPU2, 0x02, 0x00000410, 0x06) {} + * Processor (CPU3, 0x03, 0x00000410, 0x06) {} + * } + * + * Ignores apic_id and always return 0 for CPU0's handle. + * Return -1 for other CPU's handle. + */ + if (acpi_id == 0) + return acpi_id; + else + return apic_id; + } #ifdef CONFIG_SMP for_each_possible_cpu(i) { From 7b3e8a2073d9875dbdcdfec5d40ff54c8e8c418c Mon Sep 17 00:00:00 2001 From: Stratos Psomadakis Date: Sun, 4 Dec 2011 02:23:54 +0200 Subject: [PATCH 0731/4025] sym53c8xx: Fix NULL pointer dereference in slave_destroy commit cced5041ed5a2d1352186510944b0ddfbdbe4c0b upstream. sym53c8xx_slave_destroy unconditionally assumes that sym53c8xx_slave_alloc has succesesfully allocated a sym_lcb. This can lead to a NULL pointer dereference (exposed by commit 4e6c82b). Signed-off-by: Stratos Psomadakis Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sym53c8xx_2/sym_glue.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index b4543f575f4..36d1ed7817e 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -839,6 +839,10 @@ static void sym53c8xx_slave_destroy(struct scsi_device *sdev) struct sym_lcb *lp = sym_lp(tp, sdev->lun); unsigned long flags; + /* if slave_alloc returned before allocating a sym_lcb, return */ + if (!lp) + return; + spin_lock_irqsave(np->s.host->host_lock, flags); if (lp->busy_itlq || lp->busy_itl) { From 640bb6ec4ff89b0349d1c7cb42aa25db191b4f63 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 6 Dec 2011 10:02:09 -0800 Subject: [PATCH 0732/4025] target: Set response format in INQUIRY response commit ce136176fea522fc8f4c16dcae7e8ed1d890ca39 upstream. Current SCSI specs say that the "response format" field in the standard INQUIRY response should be set to 2, and all the real SCSI devices I have do put 2 here. So let's do that too. Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_cdb.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 7f19c8b7b84..f044d45fc58 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -83,6 +83,18 @@ target_emulate_inquiry_std(struct se_cmd *cmd) buf[1] = 0x80; buf[2] = dev->transport->get_device_rev(dev); + /* + * NORMACA and HISUP = 0, RESPONSE DATA FORMAT = 2 + * + * SPC4 says: + * A RESPONSE DATA FORMAT field set to 2h indicates that the + * standard INQUIRY data is in the format defined in this + * standard. Response data format values less than 2h are + * obsolete. Response data format values greater than 2h are + * reserved. + */ + buf[3] = 2; + /* * Enable SCCS and TPGS fields for Emulated ALUA */ From 06a23648ebbb532745eb85c1a381b83dd90e94af Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 13 Dec 2011 14:55:33 -0800 Subject: [PATCH 0733/4025] target: Set additional sense length field in sense data commit 895f3022523361e9b383cf48f51feb1f7d5e7e53 upstream. The target code was not setting the additional sense length field in the sense data it returned, which meant that at least the Linux stack ignored the ASC/ASCQ fields. For example, without this patch, on a tcm_loop device: # sg_raw -v /dev/sda 2 0 0 0 0 0 gives cdb to send: 02 00 00 00 00 00 SCSI Status: Check Condition Sense Information: Fixed format, current; Sense key: Illegal Request Raw sense data (in hex): 70 00 05 00 00 00 00 00 while after the patch we correctly get the following (which matches what a regular disk returns): cdb to send: 02 00 00 00 00 00 SCSI Status: Check Condition Sense Information: Fixed format, current; Sense key: Illegal Request Additional sense: Invalid command operation code Raw sense data (in hex): 70 00 05 00 00 00 00 0a 00 00 00 00 20 00 00 00 00 00 Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_transport.c | 14 ++++++++++++++ include/target/target_core_base.h | 1 + 2 files changed, 15 insertions(+) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 1340ffd7648..bb86655dd40 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -5668,6 +5668,8 @@ int transport_send_check_condition_and_sense( case TCM_SECTOR_COUNT_TOO_MANY: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ILLEGAL REQUEST */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* INVALID COMMAND OPERATION CODE */ @@ -5676,6 +5678,7 @@ int transport_send_check_condition_and_sense( case TCM_UNKNOWN_MODE_PAGE: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ILLEGAL REQUEST */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* INVALID FIELD IN CDB */ @@ -5684,6 +5687,7 @@ int transport_send_check_condition_and_sense( case TCM_CHECK_CONDITION_ABORT_CMD: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* BUS DEVICE RESET FUNCTION OCCURRED */ @@ -5693,6 +5697,7 @@ int transport_send_check_condition_and_sense( case TCM_INCORRECT_AMOUNT_OF_DATA: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* WRITE ERROR */ @@ -5703,6 +5708,7 @@ int transport_send_check_condition_and_sense( case TCM_INVALID_CDB_FIELD: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* INVALID FIELD IN CDB */ @@ -5711,6 +5717,7 @@ int transport_send_check_condition_and_sense( case TCM_INVALID_PARAMETER_LIST: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* INVALID FIELD IN PARAMETER LIST */ @@ -5719,6 +5726,7 @@ int transport_send_check_condition_and_sense( case TCM_UNEXPECTED_UNSOLICITED_DATA: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* WRITE ERROR */ @@ -5729,6 +5737,7 @@ int transport_send_check_condition_and_sense( case TCM_SERVICE_CRC_ERROR: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* PROTOCOL SERVICE CRC ERROR */ @@ -5739,6 +5748,7 @@ int transport_send_check_condition_and_sense( case TCM_SNACK_REJECTED: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ABORTED COMMAND */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; /* READ ERROR */ @@ -5749,6 +5759,7 @@ int transport_send_check_condition_and_sense( case TCM_WRITE_PROTECTED: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* DATA PROTECT */ buffer[offset+SPC_SENSE_KEY_OFFSET] = DATA_PROTECT; /* WRITE PROTECTED */ @@ -5757,6 +5768,7 @@ int transport_send_check_condition_and_sense( case TCM_CHECK_CONDITION_UNIT_ATTENTION: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* UNIT ATTENTION */ buffer[offset+SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; core_scsi3_ua_for_check_condition(cmd, &asc, &ascq); @@ -5766,6 +5778,7 @@ int transport_send_check_condition_and_sense( case TCM_CHECK_CONDITION_NOT_READY: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* Not Ready */ buffer[offset+SPC_SENSE_KEY_OFFSET] = NOT_READY; transport_get_sense_codes(cmd, &asc, &ascq); @@ -5776,6 +5789,7 @@ int transport_send_check_condition_and_sense( default: /* CURRENT ERROR */ buffer[offset] = 0x70; + buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; /* ILLEGAL REQUEST */ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* LOGICAL UNIT COMMUNICATION FAILURE */ diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 561ac99def5..0fe667901ed 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -36,6 +36,7 @@ #define TRANSPORT_SENSE_BUFFER SCSI_SENSE_BUFFERSIZE /* Used by transport_send_check_condition_and_sense() */ #define SPC_SENSE_KEY_OFFSET 2 +#define SPC_ADD_SENSE_LEN_OFFSET 7 #define SPC_ASC_KEY_OFFSET 12 #define SPC_ASCQ_KEY_OFFSET 13 #define TRANSPORT_IQN_LEN 224 From 6c8e76e158a9bc849ec946ab030595e06ad89210 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Thu, 8 Dec 2011 15:43:53 +0100 Subject: [PATCH 0734/4025] I2C: OMAP: correct SYSC register offset for OMAP4 commit 2727b1753934e154931d6b3bdf20c9b2398457a2 upstream. Correct OMAP_I2C_SYSC_REG offset in omap4 register map. Offset 0x20 is reserved and OMAP_I2C_SYSC_REG has 0x10 as offset. Signed-off-by: Alexander Aring [khilman@ti.com: minor changelog edits] Signed-off-by: Kevin Hilman Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 58a58c7eaa1..137e1a3bfad 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -235,7 +235,7 @@ const static u8 omap4_reg_map[] = { [OMAP_I2C_BUF_REG] = 0x94, [OMAP_I2C_CNT_REG] = 0x98, [OMAP_I2C_DATA_REG] = 0x9c, - [OMAP_I2C_SYSC_REG] = 0x20, + [OMAP_I2C_SYSC_REG] = 0x10, [OMAP_I2C_CON_REG] = 0xa4, [OMAP_I2C_OA_REG] = 0xa8, [OMAP_I2C_SA_REG] = 0xac, From 415b95df641c998a7cf15c916047f338ab2ce87b Mon Sep 17 00:00:00 2001 From: Cliff Wickman Date: Mon, 16 Jan 2012 15:18:48 -0600 Subject: [PATCH 0735/4025] x86/UV2: Fix BAU destination timeout initialization commit d059f9fa84a30e04279c6ff615e9e2cf3b260191 upstream. Move the call to enable_timeouts() forward so that BAU_MISC_CONTROL is initialized before using it in calculate_destination_timeout(). Fix the calculation of a BAU destination timeout for UV2 (in calculate_destination_timeout()). Signed-off-by: Cliff Wickman Link: http://lkml.kernel.org/r/20120116211848.GB5767@sgi.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/platform/uv/tlb_uv.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index 82cff4a25f4..edf435b74e8 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c @@ -1575,14 +1575,14 @@ static int calculate_destination_timeout(void) ts_ns = base * mult1 * mult2; ret = ts_ns / 1000; } else { - /* 4 bits 0/1 for 10/80us, 3 bits of multiplier */ - mmr_image = uv_read_local_mmr(UVH_AGING_PRESCALE_SEL); + /* 4 bits 0/1 for 10/80us base, 3 bits of multiplier */ + mmr_image = uv_read_local_mmr(UVH_LB_BAU_MISC_CONTROL); mmr_image = (mmr_image & UV_SA_MASK) >> UV_SA_SHFT; if (mmr_image & (1L << UV2_ACK_UNITS_SHFT)) - mult1 = 80; + base = 80; else - mult1 = 10; - base = mmr_image & UV2_ACK_MASK; + base = 10; + mult1 = mmr_image & UV2_ACK_MASK; ret = mult1 * base; } return ret; @@ -1820,6 +1820,8 @@ static int __init uv_bau_init(void) uv_base_pnode = uv_blade_to_pnode(uvhub); } + enable_timeouts(); + if (init_per_cpu(nuvhubs, uv_base_pnode)) { nobau = 1; return 0; @@ -1830,7 +1832,6 @@ static int __init uv_bau_init(void) if (uv_blade_nr_possible_cpus(uvhub)) init_uvhub(uvhub, vector, uv_base_pnode); - enable_timeouts(); alloc_intr_gate(vector, uv_bau_message_intr1); for_each_possible_blade(uvhub) { From ac631973a9ad6bba3d666f687288ebeb819c0df0 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 13 Jan 2012 12:59:32 +0100 Subject: [PATCH 0736/4025] rt2800pci: fix spurious interrupts generation commit dfd00c4c8f3dfa1fd7cec45f83d98b2a49743dcd upstream. Same devices can generate interrupt without properly setting bit in INT_SOURCE_CSR register (spurious interrupt), what will cause IRQ line will be disabled by interrupts controller driver. We discovered that clearing INT_MASK_CSR stops such behaviour. We previously first read that register, and then clear all know interrupt sources bits and do not touch reserved bits. After this patch, we write to all register content (I believe writing to reserved bits on that register will not cause any problems, I tested that on my rt2800pci device). This fix very bad performance problem, practically making device unusable (since worked without interrupts), reported in: https://bugzilla.redhat.com/show_bug.cgi?id=658451 We previously tried to workaround that issue in commit 4ba7d9997869d25bd223dea7536fc1ce9fab3b3b "rt2800pci: handle spurious interrupts", but it was reverted in commit 82e5fc2a34fa9ffea38f00c4066b7e600a0ca5e6 as thing, that will prevent to detect real spurious interrupts. Reported-and-tested-by: Amir Hedayaty Signed-off-by: Stanislaw Gruszka Acked-by: Gertjan van Wingerde Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rt2x00/rt2800pci.c | 28 +++++++------------------ 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 55cd3e1f75b..dab7dc16a6c 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -426,7 +426,6 @@ static int rt2800pci_init_queues(struct rt2x00_dev *rt2x00dev) static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, enum dev_state state) { - int mask = (state == STATE_RADIO_IRQ_ON); u32 reg; unsigned long flags; @@ -448,25 +447,14 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev, } spin_lock_irqsave(&rt2x00dev->irqmask_lock, flags); - rt2x00pci_register_read(rt2x00dev, INT_MASK_CSR, ®); - rt2x00_set_field32(®, INT_MASK_CSR_RXDELAYINT, 0); - rt2x00_set_field32(®, INT_MASK_CSR_TXDELAYINT, 0); - rt2x00_set_field32(®, INT_MASK_CSR_RX_DONE, mask); - rt2x00_set_field32(®, INT_MASK_CSR_AC0_DMA_DONE, 0); - rt2x00_set_field32(®, INT_MASK_CSR_AC1_DMA_DONE, 0); - rt2x00_set_field32(®, INT_MASK_CSR_AC2_DMA_DONE, 0); - rt2x00_set_field32(®, INT_MASK_CSR_AC3_DMA_DONE, 0); - rt2x00_set_field32(®, INT_MASK_CSR_HCCA_DMA_DONE, 0); - rt2x00_set_field32(®, INT_MASK_CSR_MGMT_DMA_DONE, 0); - rt2x00_set_field32(®, INT_MASK_CSR_MCU_COMMAND, 0); - rt2x00_set_field32(®, INT_MASK_CSR_RXTX_COHERENT, 0); - rt2x00_set_field32(®, INT_MASK_CSR_TBTT, mask); - rt2x00_set_field32(®, INT_MASK_CSR_PRE_TBTT, mask); - rt2x00_set_field32(®, INT_MASK_CSR_TX_FIFO_STATUS, mask); - rt2x00_set_field32(®, INT_MASK_CSR_AUTO_WAKEUP, mask); - rt2x00_set_field32(®, INT_MASK_CSR_GPTIMER, 0); - rt2x00_set_field32(®, INT_MASK_CSR_RX_COHERENT, 0); - rt2x00_set_field32(®, INT_MASK_CSR_TX_COHERENT, 0); + reg = 0; + if (state == STATE_RADIO_IRQ_ON) { + rt2x00_set_field32(®, INT_MASK_CSR_RX_DONE, 1); + rt2x00_set_field32(®, INT_MASK_CSR_TBTT, 1); + rt2x00_set_field32(®, INT_MASK_CSR_PRE_TBTT, 1); + rt2x00_set_field32(®, INT_MASK_CSR_TX_FIFO_STATUS, 1); + rt2x00_set_field32(®, INT_MASK_CSR_AUTO_WAKEUP, 1); + } rt2x00pci_register_write(rt2x00dev, INT_MASK_CSR, reg); spin_unlock_irqrestore(&rt2x00dev->irqmask_lock, flags); From 8edf7c13515fa2dee528ab348919058b14454457 Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Fri, 6 Jan 2012 09:28:12 +0200 Subject: [PATCH 0737/4025] pnfs-obj: pNFS errors are communicated on iodata->pnfs_error commit 5c0b4129c07b902b27d3f3ebc087757f534a3abd upstream. Some time along the way pNFS IO errors were switched to communicate with a special iodata->pnfs_error member instead of the regular RPC members. But objlayout was not switched over. Fix that! Without this fix any IO error is hanged, because IO is not switched to MDS and pages are never cleared or read. Signed-off-by: Boaz Harrosh Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/objlayout/objlayout.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/fs/nfs/objlayout/objlayout.c b/fs/nfs/objlayout/objlayout.c index 1d06f8e2ade..fefa1224aff 100644 --- a/fs/nfs/objlayout/objlayout.c +++ b/fs/nfs/objlayout/objlayout.c @@ -294,9 +294,11 @@ objlayout_read_done(struct objlayout_io_state *state, ssize_t status, bool sync) dprintk("%s: Begin status=%zd eof=%d\n", __func__, status, eof); rdata = state->rpcdata; rdata->task.tk_status = status; - if (status >= 0) { + if (likely(status >= 0)) { rdata->res.count = status; rdata->res.eof = eof; + } else { + rdata->pnfs_error = status; } objlayout_iodone(state); /* must not use state after this point */ @@ -380,15 +382,17 @@ objlayout_write_done(struct objlayout_io_state *state, ssize_t status, wdata = state->rpcdata; state->status = status; wdata->task.tk_status = status; - if (status >= 0) { + if (likely(status >= 0)) { wdata->res.count = status; wdata->verf.committed = state->committed; dprintk("%s: Return status %d committed %d\n", __func__, wdata->task.tk_status, wdata->verf.committed); - } else + } else { + wdata->pnfs_error = status; dprintk("%s: Return status %d\n", __func__, wdata->task.tk_status); + } objlayout_iodone(state); /* must not use state after this point */ From 5e383255dab2f12e7e111e23c057a30955de8cf3 Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Fri, 6 Jan 2012 09:31:20 +0200 Subject: [PATCH 0738/4025] pnfs-obj: Must return layout on IO error commit fe0fe83585f88346557868a803a479dfaaa0688a upstream. As mandated by the standard. In case of an IO error, a pNFS objects layout driver must return it's layout. This is because all device errors are reported to the server as part of the layout return buffer. This is implemented the same way PNFS_LAYOUTRET_ON_SETATTR is done, through a bit flag on the pnfs_layoutdriver_type->flags member. The flag is set by the layout driver that wants a layout_return preformed at pnfs_ld_{write,read}_done in case of an error. (Though I have not defined a wrapper like pnfs_ld_layoutret_on_setattr because this code is never called outside of pnfs.c and pnfs IO paths) Without this patch 3.[0-2] Kernels leak memory and have an annoying WARN_ON after every IO error utilizing the pnfs-obj driver. Signed-off-by: Boaz Harrosh Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/objlayout/objio_osd.c | 3 ++- fs/nfs/pnfs.c | 12 ++++++++++++ fs/nfs/pnfs.h | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c index 1d1dc1ee394..75fe694d78d 100644 --- a/fs/nfs/objlayout/objio_osd.c +++ b/fs/nfs/objlayout/objio_osd.c @@ -1006,7 +1006,8 @@ static bool objio_pg_test(struct nfs_pageio_descriptor *pgio, static struct pnfs_layoutdriver_type objlayout_type = { .id = LAYOUT_OSD2_OBJECTS, .name = "LAYOUT_OSD2_OBJECTS", - .flags = PNFS_LAYOUTRET_ON_SETATTR, + .flags = PNFS_LAYOUTRET_ON_SETATTR | + PNFS_LAYOUTRET_ON_ERROR, .alloc_layout_hdr = objlayout_alloc_layout_hdr, .free_layout_hdr = objlayout_free_layout_hdr, diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 36d2a29bfbe..99518872f42 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1119,6 +1119,14 @@ pnfs_ld_write_done(struct nfs_write_data *data) data->mds_ops->rpc_release(data); return 0; } + if (NFS_SERVER(data->inode)->pnfs_curr_ld->flags & + PNFS_LAYOUTRET_ON_ERROR) { + /* Don't lo_commit on error, Server will needs to + * preform a file recovery. + */ + clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(data->inode)->flags); + pnfs_return_layout(data->inode); + } dprintk("%s: pnfs_error=%d, retry via MDS\n", __func__, data->pnfs_error); @@ -1167,6 +1175,10 @@ pnfs_ld_read_done(struct nfs_read_data *data) return 0; } + if (NFS_SERVER(data->inode)->pnfs_curr_ld->flags & + PNFS_LAYOUTRET_ON_ERROR) + pnfs_return_layout(data->inode); + dprintk("%s: pnfs_error=%d, retry via MDS\n", __func__, data->pnfs_error); status = nfs_initiate_read(data, NFS_CLIENT(data->inode), diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 9d147d963bd..bb8b3247f29 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -68,6 +68,7 @@ enum { enum layoutdriver_policy_flags { /* Should the pNFS client commit and return the layout upon a setattr */ PNFS_LAYOUTRET_ON_SETATTR = 1 << 0, + PNFS_LAYOUTRET_ON_ERROR = 1 << 1, }; struct nfs4_deviceid_node; From d7531928ae349a5d59a6820bc3a5e46c9907f5ad Mon Sep 17 00:00:00 2001 From: Dirk Eibach Date: Tue, 18 Oct 2011 03:04:11 +0000 Subject: [PATCH 0739/4025] net: Fix driver name for mdio-gpio.c commit f42af6c486aa5ca6ee62800cb45c5b252020509d upstream. Since commit "7488876... dt/net: Eliminate users of of_platform_{,un}register_driver" there are two platform drivers named "mdio-gpio" registered. I renamed the of variant to "mdio-ofgpio". Signed-off-by: Dirk Eibach Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/mdio-gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index 47c8339a035..2843c90f712 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -241,7 +241,7 @@ MODULE_DEVICE_TABLE(of, mdio_ofgpio_match); static struct platform_driver mdio_ofgpio_driver = { .driver = { - .name = "mdio-gpio", + .name = "mdio-ofgpio", .owner = THIS_MODULE, .of_match_table = mdio_ofgpio_match, }, From a6007c036e0a0e10c0b4dbd533576d201b822a90 Mon Sep 17 00:00:00 2001 From: Toshiharu Okada Date: Mon, 26 Sep 2011 16:16:23 +0900 Subject: [PATCH 0740/4025] i2c-eg20t: modified the setting of transfer rate. commit ff35e8b18984ad2a82cbd259fc07f0be4b34b1aa upstream. This patch modified the setting value of I2C Bus Transfer Rate Setting Counter regisrer. Signed-off-by: Toshiharu Okada Signed-off-by: Ben Dooks Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-eg20t.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 8abfa4a03ce..656b028d981 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -242,7 +242,7 @@ static void pch_i2c_init(struct i2c_algo_pch_data *adap) if (pch_clk > PCH_MAX_CLK) pch_clk = 62500; - pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / pch_i2c_speed * 8; + pch_i2cbc = (pch_clk + (pch_i2c_speed * 4)) / (pch_i2c_speed * 8); /* Set transfer speed in I2CBC */ iowrite32(pch_i2cbc, p + PCH_I2CBC); From 72a82010500dea88b2d786a76b063a871e2a4603 Mon Sep 17 00:00:00 2001 From: Dan Rosenberg Date: Fri, 20 Jan 2012 14:34:27 -0800 Subject: [PATCH 0741/4025] score: fix off-by-one index into syscall table commit c25a785d6647984505fa165b5cd84cfc9a95970b upstream. If the provided system call number is equal to __NR_syscalls, the current check will pass and a function pointer just after the system call table may be called, since sys_call_table is an array with total size __NR_syscalls. Whether or not this is a security bug depends on what the compiler puts immediately after the system call table. It's likely that this won't do anything bad because there is an additional NULL check on the syscall entry, but if there happens to be a non-NULL value immediately after the system call table, this may result in local privilege escalation. Signed-off-by: Dan Rosenberg Cc: Chen Liqin Cc: Lennox Wu Cc: Eugene Teo Cc: Arnd Bergmann Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/score/kernel/entry.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/score/kernel/entry.S b/arch/score/kernel/entry.S index 577abba3fac..83bb96079c4 100644 --- a/arch/score/kernel/entry.S +++ b/arch/score/kernel/entry.S @@ -408,7 +408,7 @@ ENTRY(handle_sys) sw r9, [r0, PT_EPC] cmpi.c r27, __NR_syscalls # check syscall number - bgtu illegal_syscall + bgeu illegal_syscall slli r8, r27, 2 # get syscall routine la r11, sys_call_table From b8f256956a063ebc60a674ec5795c7ca5aaa79c6 Mon Sep 17 00:00:00 2001 From: Ananth N Mavinakayanahalli Date: Fri, 20 Jan 2012 14:34:04 -0800 Subject: [PATCH 0742/4025] kprobes: initialize before using a hlist commit d496aab567e7e52b3e974c9192a5de6e77dce32c upstream. Commit ef53d9c5e ("kprobes: improve kretprobe scalability with hashed locking") introduced a bug where we can potentially leak kretprobe_instances since we initialize a hlist head after having used it. Initialize the hlist head before using it. Reported by: Jim Keniston Acked-by: Jim Keniston Signed-off-by: Ananth N Mavinakayanahalli Acked-by: Masami Hiramatsu Cc: Srinivasa D S Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/kprobes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 77981813a1e..e0f0bdd92ca 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1077,6 +1077,7 @@ void __kprobes kprobe_flush_task(struct task_struct *tk) /* Early boot. kretprobe_table_locks not yet initialized. */ return; + INIT_HLIST_HEAD(&empty_rp); hash = hash_ptr(tk, KPROBE_HASH_BITS); head = &kretprobe_inst_table[hash]; kretprobe_table_lock(hash, &flags); @@ -1085,7 +1086,6 @@ void __kprobes kprobe_flush_task(struct task_struct *tk) recycle_rp_inst(ri, &empty_rp); } kretprobe_table_unlock(hash, &flags); - INIT_HLIST_HEAD(&empty_rp); hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { hlist_del(&ri->hlist); kfree(ri); From c2c9f543718e15227a4aa0135e793480b94c4d97 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 20 Jan 2012 14:34:09 -0800 Subject: [PATCH 0743/4025] proc: clear_refs: do not clear reserved pages commit 85e72aa5384b1a614563ad63257ded0e91d1a620 upstream. /proc/pid/clear_refs is used to clear the Referenced and YOUNG bits for pages and corresponding page table entries of the task with PID pid, which includes any special mappings inserted into the page tables in order to provide things like vDSOs and user helper functions. On ARM this causes a problem because the vectors page is mapped as a global mapping and since ec706dab ("ARM: add a vma entry for the user accessible vector page"), a VMA is also inserted into each task for this page to aid unwinding through signals and syscall restarts. Since the vectors page is required for handling faults, clearing the YOUNG bit (and subsequently writing a faulting pte) means that we lose the vectors page *globally* and cannot fault it back in. This results in a system deadlock on the next exception. To see this problem in action, just run: $ echo 1 > /proc/self/clear_refs on an ARM platform (as any user) and watch your system hang. I think this has been the case since 2.6.37 This patch avoids clearing the aforementioned bits for reserved pages, therefore leaving the vectors page intact on ARM. Since reserved pages are not candidates for swap, this change should not have any impact on the usefulness of clear_refs. Signed-off-by: Will Deacon Reported-by: Moussa Ba Acked-by: Hugh Dickins Cc: David Rientjes Cc: Russell King Acked-by: Nicolas Pitre Cc: Matt Mackall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/proc/task_mmu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index c7d4ee663f1..3487b066500 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -516,6 +516,9 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, if (!page) continue; + if (PageReserved(page)) + continue; + /* Clear accessed and referenced bits. */ ptep_test_and_clear_young(vma, addr, pte); ClearPageReferenced(page); From bcbef18db94dfb991bd3025069b3413cbc52f8b6 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Fri, 20 Jan 2012 14:33:55 -0800 Subject: [PATCH 0744/4025] mm: fix NULL ptr dereference in __count_immobile_pages commit 687875fb7de4a95223af20ee024282fa9099f860 upstream. Fix the following NULL ptr dereference caused by cat /sys/devices/system/memory/memory0/removable Pid: 13979, comm: sed Not tainted 3.0.13-0.5-default #1 IBM BladeCenter LS21 -[7971PAM]-/Server Blade RIP: __count_immobile_pages+0x4/0x100 Process sed (pid: 13979, threadinfo ffff880221c36000, task ffff88022e788480) Call Trace: is_pageblock_removable_nolock+0x34/0x40 is_mem_section_removable+0x74/0xf0 show_mem_removable+0x41/0x70 sysfs_read_file+0xfe/0x1c0 vfs_read+0xc7/0x130 sys_read+0x53/0xa0 system_call_fastpath+0x16/0x1b We are crashing because we are trying to dereference NULL zone which came from pfn=0 (struct page ffffea0000000000). According to the boot log this page is marked reserved: e820 update range: 0000000000000000 - 0000000000010000 (usable) ==> (reserved) and early_node_map confirms that: early_node_map[3] active PFN ranges 1: 0x00000010 -> 0x0000009c 1: 0x00000100 -> 0x000bffa3 1: 0x00100000 -> 0x00240000 The problem is that memory_present works in PAGE_SECTION_MASK aligned blocks so the reserved range sneaks into the the section as well. This also means that free_area_init_node will not take care of those reserved pages and they stay uninitialized. When we try to read the removable status we walk through all available sections and hope that the zone is valid for all pages in the section. But this is not true in this case as the zone and nid are not initialized. We have only one node in this particular case and it is marked as node=1 (rather than 0) and that made the problem visible because page_to_nid will return 0 and there are no zones on the node. Let's check that the zone is valid and that the given pfn falls into its boundaries and mark the section not removable. This might cause some false positives, probably, but we do not have any sane way to find out whether the page is reserved by the platform or it is just not used for whatever other reasons. Signed-off-by: Michal Hocko Acked-by: Mel Gorman Cc: KAMEZAWA Hiroyuki Cc: Andrea Arcangeli Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/page_alloc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 8439d2a04f2..947a7e96f91 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -5565,6 +5565,17 @@ __count_immobile_pages(struct zone *zone, struct page *page, int count) bool is_pageblock_removable_nolock(struct page *page) { struct zone *zone = page_zone(page); + unsigned long pfn = page_to_pfn(page); + + /* + * We have to be careful here because we are iterating over memory + * sections which are not zone aware so we might end up outside of + * the zone but still within the section. + */ + if (!zone || zone->zone_start_pfn > pfn || + zone->zone_start_pfn + zone->spanned_pages <= pfn) + return false; + return __count_immobile_pages(zone, page, 0); } From dd558f1e43567fd51a258f61081809e60735f9f4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Thu, 10 Nov 2011 06:55:04 -0800 Subject: [PATCH 0745/4025] iwlagn: check for SMPS mode commit b2ccccdca46273c7b321ecf5041c362cd950da20 upstream. Check and report WARN only when its invalid Resolves: https://bugzilla.kernel.org/show_bug.cgi?id=42621 https://bugzilla.redhat.com/show_bug.cgi?id=766071 Signed-off-by: Wey-Yi Guy Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 1 + drivers/net/wireless/iwlwifi/iwl-agn-rxon.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index f803fb62f8b..857cf613092 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -2023,6 +2023,7 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) case IEEE80211_SMPS_STATIC: case IEEE80211_SMPS_DYNAMIC: return IWL_NUM_IDLE_CHAINS_SINGLE; + case IEEE80211_SMPS_AUTOMATIC: case IEEE80211_SMPS_OFF: return active_cnt; default: diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 39a3c9c235f..272bcdfe53a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -442,6 +442,9 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) mutex_lock(&priv->mutex); + if (test_bit(STATUS_EXIT_PENDING, &priv->status)) + goto out; + if (unlikely(test_bit(STATUS_SCANNING, &priv->status))) { IWL_DEBUG_MAC80211(priv, "leave - scanning\n"); goto out; From e4ae34bbc7386489a0c8253f246e7a5d316f249a Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Fri, 23 Dec 2011 08:13:50 +0100 Subject: [PATCH 0746/4025] iwlegacy: 3945: fix hw passive scan on radar channels commit 68acc4afb040d98ddfd2cae0de09e2f4e1ee127f upstream. Patch fix firmware error on "iw dev wlan0 scan passive" for hardware scanning (with disable_hw_scan=0 module parameter). iwl3945 0000:03:00.0: Microcode SW error detected. Restarting 0x82000008. iwl3945 0000:03:00.0: Loaded firmware version: 15.32.2.9 iwl3945 0000:03:00.0: Start IWL Error Log Dump: iwl3945 0000:03:00.0: Status: 0x0002A2E4, count: 1 iwl3945 0000:03:00.0: Desc Time asrtPC blink2 ilink1 nmiPC Line iwl3945 0000:03:00.0: SYSASSERT (0x5) 0041263900 0x13756 0x0031C 0x00000 764 iwl3945 0000:03:00.0: Error Reply type 0x000002FC cmd C_SCAN (0x80) seq 0x443E ser 0x00340000 iwl3945 0000:03:00.0: Command C_SCAN failed: FW Error iwl3945 0000:03:00.0: Can't stop Rx DMA. We have disable ability to change passive scanning to active on particular channel when traffic is detected on that channel. Otherwise firmware will report error, when we try to do passive scan on radar channels. Reported-and-debugged-by: Pedro Francisco Signed-off-by: Stanislaw Gruszka Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/iwlegacy/iwl3945-base.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/iwlegacy/iwl3945-base.c b/drivers/net/wireless/iwlegacy/iwl3945-base.c index 421d5c8b8e3..a9355856e2e 100644 --- a/drivers/net/wireless/iwlegacy/iwl3945-base.c +++ b/drivers/net/wireless/iwlegacy/iwl3945-base.c @@ -2910,14 +2910,13 @@ int iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) IWL_WARN(priv, "Invalid scan band\n"); return -EIO; } - /* - * If active scaning is requested but a certain channel - * is marked passive, we can do active scanning if we - * detect transmissions. + * If active scaning is requested but a certain channel is marked + * passive, we can do active scanning if we detect transmissions. For + * passive only scanning disable switching to active on any channel. */ scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT : - IWL_GOOD_CRC_TH_DISABLED; + IWL_GOOD_CRC_TH_NEVER; if (!priv->is_internal_short_scan) { scan->tx_cmd.len = cpu_to_le16( From 20ef6312522d42407e8030bb17f25c4fde724a37 Mon Sep 17 00:00:00 2001 From: Artem Bityutskiy Date: Wed, 11 Jan 2012 15:13:27 +0200 Subject: [PATCH 0747/4025] UBIFS: make debugging messages light again commit 1f5d78dc4823a85f112aaa2d0f17624f8c2a6c52 upstream. We switch to dynamic debugging in commit 56e46742e846e4de167dde0e1e1071ace1c882a5 but did not take into account that now we do not control anymore whether a specific message is enabled or not. So now we lock the "dbg_lock" and release it in every debugging macro, which make them not so light-weight. This commit removes the "dbg_lock" protection from the debugging macros to fix the issue. The downside is that now our DBGKEY() stuff is broken, but this is not critical at all and will be fixed later. Signed-off-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/debug.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h index 3a89c8b4efc..fd75b635dae 100644 --- a/fs/ubifs/debug.h +++ b/fs/ubifs/debug.h @@ -121,17 +121,15 @@ const char *dbg_key_str1(const struct ubifs_info *c, const union ubifs_key *key); /* - * DBGKEY macros require @dbg_lock to be held, which it is in the dbg message - * macros. + * TODO: these macros are now broken because there is no locking around them + * and we use a global buffer for the key string. This means that in case of + * concurrent execution we will end up with incorrect and messy key strings. */ #define DBGKEY(key) dbg_key_str0(c, (key)) #define DBGKEY1(key) dbg_key_str1(c, (key)) -#define ubifs_dbg_msg(type, fmt, ...) do { \ - spin_lock(&dbg_lock); \ - pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__); \ - spin_unlock(&dbg_lock); \ -} while (0) +#define ubifs_dbg_msg(type, fmt, ...) \ + pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__) /* Just a debugging messages not related to any specific UBIFS subsystem */ #define dbg_msg(fmt, ...) \ From 235eae6e5e402f5f723203e4444f10c16c7c3be3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 25 Jan 2012 17:26:46 -0800 Subject: [PATCH 0748/4025] Linux 3.0.18 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 295fbda0036..581b8e9bb35 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 17 +SUBLEVEL = 18 EXTRAVERSION = NAME = Sneaky Weasel From b1a94205e9ab943d4c18f8e0a081b32bc8bd1f50 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Fri, 20 Jan 2012 14:15:05 -0800 Subject: [PATCH 0749/4025] net: wireless: bcmdhd: Fake PNO event to wake up the wpa_supplicant Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_linux.c | 4 +++- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 20 ++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index d4cc56f4043..f25fc324f24 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -1501,10 +1501,12 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) &data); wl_event_to_host_order(&event); + tout = DHD_EVENT_TIMEOUT_MS; if (event.event_type == WLC_E_BTA_HCI_EVENT) { dhd_bta_doevt(dhdp, data, event.datalen); + } else if (event.event_type == WLC_E_PFN_NET_FOUND) { + tout *= 2; } - tout = DHD_EVENT_TIMEOUT_MS; } ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 32241d52add..23aee57d745 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -256,6 +256,8 @@ static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); +static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); /* * register/deregister sdio function */ @@ -4787,6 +4789,19 @@ wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, return 0; } +static s32 +wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + WL_ERR((" PNO Event\n")); + + mutex_lock(&wl->usr_sync); + /* TODO: Use cfg80211_sched_scan_results(wiphy); */ + cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); + mutex_unlock(&wl->usr_sync); + return 0; +} + static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) @@ -4997,7 +5012,7 @@ static void wl_init_event_handler(struct wl_priv *wl) wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; - + wl->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; } static s32 wl_init_priv_mem(struct wl_priv *wl) @@ -5759,9 +5774,6 @@ wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t * e, void *data) WL_DBG(("event_type (%d):" "WLC_E_" "%s\n", event_type, estr)); #endif /* (WL_DBG_LEVEL > 0) */ - if (event_type == WLC_E_PFN_NET_FOUND) - WL_ERR((" PNO Event\n")); - if (likely(!wl_enq_event(wl, ndev, event_type, e, data))) wl_wakeup_event(wl); } From 52bdb6f54335bce7861d756ce1eb03ea9b7adb8f Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 23 Jan 2012 12:47:21 -0800 Subject: [PATCH 0750/4025] net: wireless: bcmdhd: Add WIPHY_FLAG_SUPPORTS_FW_ROAM flag Adding this flag will allow NL80211_ATTR_ROAM_SUPPORT, and will set WPA_DRIVER_FLAGS_BSS_SELECTION flag in wpa_supplicant Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 23aee57d745..e026a7db28a 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -4114,7 +4114,9 @@ static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev) WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS | #endif WIPHY_FLAG_4ADDR_STATION; - +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) + wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; +#endif WL_DBG(("Registering custom regulatory)\n")); wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; wiphy_apply_custom_regulatory(wdev->wiphy, &brcm_regdom); From 1dddb0cc0de2840a2fe43a02fcb0196bb5cb86c8 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 24 Jan 2012 13:37:34 -0800 Subject: [PATCH 0751/4025] net: wireless: bcmdhd: Update to Version 5.90.195.15 - Add WFD concurrent mode support Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/bcmevent.c | 8 +- .../net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c | 12 +- drivers/net/wireless/bcmdhd/bcmutils.c | 4 +- drivers/net/wireless/bcmdhd/dhd.h | 25 +- drivers/net/wireless/bcmdhd/dhd_cdc.c | 9 +- drivers/net/wireless/bcmdhd/dhd_common.c | 4 +- drivers/net/wireless/bcmdhd/dhd_linux.c | 148 +-- drivers/net/wireless/bcmdhd/dhd_linux_mon.c | 28 +- drivers/net/wireless/bcmdhd/dhd_sdio.c | 27 +- drivers/net/wireless/bcmdhd/dhd_wlfc.h | 12 +- drivers/net/wireless/bcmdhd/hndpmu.c | 44 +- drivers/net/wireless/bcmdhd/include/Makefile | 2 +- drivers/net/wireless/bcmdhd/include/aidmp.h | 2 +- drivers/net/wireless/bcmdhd/include/bcmcdc.h | 2 +- drivers/net/wireless/bcmdhd/include/bcmdefs.h | 37 +- drivers/net/wireless/bcmdhd/include/bcmdevs.h | 573 +++++++++++- .../net/wireless/bcmdhd/include/bcmendian.h | 2 +- .../net/wireless/bcmdhd/include/bcmpcispi.h | 2 +- drivers/net/wireless/bcmdhd/include/bcmperf.h | 2 +- .../net/wireless/bcmdhd/include/bcmsdbus.h | 10 +- drivers/net/wireless/bcmdhd/include/bcmsdh.h | 10 +- .../wireless/bcmdhd/include/bcmsdh_sdmmc.h | 2 +- .../net/wireless/bcmdhd/include/bcmsdpcm.h | 2 +- .../net/wireless/bcmdhd/include/bcmsdspi.h | 2 +- .../net/wireless/bcmdhd/include/bcmsdstd.h | 34 +- drivers/net/wireless/bcmdhd/include/bcmspi.h | 2 +- .../net/wireless/bcmdhd/include/bcmutils.h | 14 +- drivers/net/wireless/bcmdhd/include/bcmwifi.h | 2 +- .../net/wireless/bcmdhd/include/dhdioctl.h | 2 +- drivers/net/wireless/bcmdhd/include/epivers.h | 14 +- drivers/net/wireless/bcmdhd/include/hndpmu.h | 2 +- .../wireless/bcmdhd/include/hndrte_armtrap.h | 2 +- .../net/wireless/bcmdhd/include/hndrte_cons.h | 2 +- drivers/net/wireless/bcmdhd/include/hndsoc.h | 2 +- drivers/net/wireless/bcmdhd/include/htsf.h | 2 +- .../net/wireless/bcmdhd/include/linux_osl.h | 2 +- .../net/wireless/bcmdhd/include/linuxver.h | 6 +- drivers/net/wireless/bcmdhd/include/miniopt.h | 2 +- .../net/wireless/bcmdhd/include/msgtrace.h | 2 +- drivers/net/wireless/bcmdhd/include/osl.h | 2 +- .../bcmdhd/include/packed_section_end.h | 2 +- .../bcmdhd/include/packed_section_start.h | 2 +- drivers/net/wireless/bcmdhd/include/pcicfg.h | 28 +- .../wireless/bcmdhd/include/proto/802.11.h | 317 ++++++- .../bcmdhd/include/proto/802.11_bta.h | 2 +- .../wireless/bcmdhd/include/proto/802.11e.h | 2 +- .../wireless/bcmdhd/include/proto/802.1d.h | 2 +- .../wireless/bcmdhd/include/proto/bcmeth.h | 2 +- .../wireless/bcmdhd/include/proto/bcmevent.h | 9 +- .../net/wireless/bcmdhd/include/proto/bcmip.h | 2 +- .../bcmdhd/include/proto/bt_amp_hci.h | 2 +- .../net/wireless/bcmdhd/include/proto/eapol.h | 2 +- .../wireless/bcmdhd/include/proto/ethernet.h | 3 +- .../net/wireless/bcmdhd/include/proto/p2p.h | 2 +- .../net/wireless/bcmdhd/include/proto/sdspi.h | 2 +- .../net/wireless/bcmdhd/include/proto/vlan.h | 2 +- .../net/wireless/bcmdhd/include/proto/wpa.h | 12 +- drivers/net/wireless/bcmdhd/include/sbchipc.h | 168 +++- .../net/wireless/bcmdhd/include/sbconfig.h | 2 +- .../net/wireless/bcmdhd/include/sbhnddma.h | 6 +- .../net/wireless/bcmdhd/include/sbpcmcia.h | 2 +- drivers/net/wireless/bcmdhd/include/sbsdio.h | 2 +- .../net/wireless/bcmdhd/include/sbsdpcmdev.h | 2 +- .../net/wireless/bcmdhd/include/sbsocram.h | 2 +- drivers/net/wireless/bcmdhd/include/sdio.h | 5 +- drivers/net/wireless/bcmdhd/include/sdioh.h | 32 +- drivers/net/wireless/bcmdhd/include/sdiovar.h | 2 +- drivers/net/wireless/bcmdhd/include/siutils.h | 30 +- drivers/net/wireless/bcmdhd/include/trxhdr.h | 3 +- .../net/wireless/bcmdhd/include/typedefs.h | 5 +- .../net/wireless/bcmdhd/include/wlfc_proto.h | 2 +- drivers/net/wireless/bcmdhd/include/wlioctl.h | 87 +- drivers/net/wireless/bcmdhd/linux_osl.c | 23 +- drivers/net/wireless/bcmdhd/siutils.c | 195 +++- drivers/net/wireless/bcmdhd/wl_android.c | 6 +- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 875 +++++++++++------- drivers/net/wireless/bcmdhd/wl_cfg80211.h | 282 ++++-- drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 165 +++- drivers/net/wireless/bcmdhd/wl_cfgp2p.h | 12 +- drivers/net/wireless/bcmdhd/wl_iw.c | 110 ++- drivers/net/wireless/bcmdhd/wl_iw.h | 17 +- 81 files changed, 2737 insertions(+), 752 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/bcmevent.c b/drivers/net/wireless/bcmdhd/bcmevent.c index 24581ddd353..6a25d9a5a57 100644 --- a/drivers/net/wireless/bcmdhd/bcmevent.c +++ b/drivers/net/wireless/bcmdhd/bcmevent.c @@ -20,7 +20,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmevent.c,v 1.8.2.7 2011-02-01 06:23:39 Exp $ + * $Id: bcmevent.c,v 1.8.2.7 2011-02-01 06:23:39 $ */ #include @@ -29,7 +29,7 @@ #include #include -#if WLC_E_LAST != 85 +#if WLC_E_LAST != 87 #error "You need to add an entry to bcmevent_names[] for the new event" #endif @@ -117,8 +117,10 @@ const bcmevent_name_t bcmevent_names[] = { { WLC_E_PFN_SCAN_NONE, "PFN_SCAN_NONE" }, { WLC_E_PFN_SCAN_ALLGONE, "PFN_SCAN_ALLGONE" }, #ifdef SOFTAP - { WLC_E_GTK_PLUMBED, "GTK_PLUMBED" } + { WLC_E_GTK_PLUMBED, "GTK_PLUMBED" }, #endif + { WLC_E_ASSOC_REQ_IE, "ASSOC_REQ_IE" }, + { WLC_E_ASSOC_RESP_IE, "ASSOC_RESP_IE" } }; diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c index 0fa2329e2ae..e19c2fd5028 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_sdmmc_linux.c,v 1.8.6.2 2011-02-01 18:38:36 Exp $ + * $Id: bcmsdh_sdmmc_linux.c 300908 2011-12-06 10:32:01Z $ */ #include @@ -55,13 +55,16 @@ #if !defined(SDIO_DEVICE_ID_BROADCOM_4319) #define SDIO_DEVICE_ID_BROADCOM_4319 0x4319 #endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4319) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4330) +#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */ #include #include #ifdef WL_CFG80211 -extern void wl_cfg80211_set_sdio_func(void *func); +extern void wl_cfg80211_set_parent_dev(void *dev); #endif extern void sdioh_sdmmc_devintr_off(sdioh_info_t *sd); @@ -118,7 +121,7 @@ static int bcmsdh_sdmmc_probe(struct sdio_func *func, if (func->num == 2) { #ifdef WL_CFG80211 - wl_cfg80211_set_sdio_func(func); + wl_cfg80211_set_parent_dev(&func->dev); #endif sd_trace(("F2 found, calling bcmsdh_probe...\n")); ret = bcmsdh_probe(&func->dev); @@ -153,7 +156,10 @@ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4325) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) }, +#ifndef BOARD_PANDA { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, +#endif { /* end: all zeroes */ }, }; diff --git a/drivers/net/wireless/bcmdhd/bcmutils.c b/drivers/net/wireless/bcmdhd/bcmutils.c index fbdd7cd2d19..6b578e65364 100644 --- a/drivers/net/wireless/bcmdhd/bcmutils.c +++ b/drivers/net/wireless/bcmdhd/bcmutils.c @@ -20,7 +20,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. - * $Id: bcmutils.c,v 1.277.2.18 2011-01-26 02:32:08 Exp $ + * $Id: bcmutils.c,v 1.277.2.18 2011-01-26 02:32:08 $ */ #include @@ -987,7 +987,6 @@ pktsetprio(void *pkt, bool update_vtag) return (rc | priority); } -#ifndef BCM_BOOTLOADER static char bcm_undeferrstr[32]; static const char *bcmerrorstrtable[] = BCMERRSTRINGTABLE; @@ -1009,7 +1008,6 @@ bcmerrorstr(int bcmerror) return bcmerrorstrtable[-bcmerror]; } -#endif /* !BCM_BOOTLOADER */ diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index 84d1761a906..4335d0d6a8a 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd.h 290844 2011-10-20 08:54:39Z $ + * $Id: dhd.h 301794 2011-12-08 20:41:35Z $ */ /**************** @@ -83,6 +83,9 @@ enum dhd_bus_state { /* max sequential rxcntl timeouts to set HANG event */ #define MAX_CNTL_TIMEOUT 2 +#define DHD_SCAN_ACTIVE_TIME 40 /* ms : Embedded default Active setting from DHD Driver */ +#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD Driver */ + enum dhd_bus_wake_state { WAKE_LOCK_OFF, WAKE_LOCK_PRIV, @@ -365,6 +368,11 @@ void dhd_osl_detach(osl_t *osh); * bus_hdrlen specifies required headroom for bus module header. */ extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen); +#if defined(WLP2P) && defined(WL_CFG80211) +/* To allow attach/detach calls corresponding to p2p0 interface */ +extern int dhd_attach_p2p(dhd_pub_t *); +extern int dhd_detach_p2p(dhd_pub_t *); +#endif /* WLP2P && WL_CFG80211 */ extern int dhd_net_attach(dhd_pub_t *dhdp, int idx); /* Indication from bus module regarding removal/absence of dongle */ @@ -411,6 +419,8 @@ extern int dhd_custom_get_mac_address(unsigned char *buf); extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); + +#ifdef PNO_SUPPORT extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); extern int dhd_pno_clean(dhd_pub_t *dhd); extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, @@ -421,9 +431,9 @@ extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max); extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); extern int dhd_dev_get_pno_status(struct net_device *dev); -extern int dhd_get_dtim_skip(dhd_pub_t *dhd); +#endif /* PNO_SUPPORT */ + extern bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd); -extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); #define DHD_UNICAST_FILTER_NUM 0 #define DHD_BROADCAST_FILTER_NUM 1 @@ -432,6 +442,9 @@ extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); extern int net_os_set_packet_filter(struct net_device *dev, int val); extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); +extern int dhd_get_dtim_skip(dhd_pub_t *dhd); +extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); + #ifdef DHD_DEBUG extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); #endif /* DHD_DEBUG */ @@ -701,12 +714,6 @@ typedef struct dhd_pkttag { #define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether typedef int (*f_commitpkt_t)(void* ctx, void* p); -int dhd_wlfc_enable(dhd_pub_t *dhd); -int dhd_wlfc_interface_event(struct dhd_info *, uint8 action, uint8 ifid, uint8 iftype, uint8* ea); -int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data); -int dhd_wlfc_event(struct dhd_info *dhd); -int dhd_os_wlfc_block(dhd_pub_t *pub); -int dhd_os_wlfc_unblock(dhd_pub_t *pub); #ifdef PROP_TXSTATUS_DEBUG #define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0) diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c index 84609920603..50e275a4ae2 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cdc.c +++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_cdc.c,v 1.51.6.31 2011-02-09 14:31:43 Exp $ + * $Id: dhd_cdc.c 301794 2011-12-08 20:41:35Z $ * * BDC is like CDC, except it includes a header for data packets to convey * packet priority over the bus, and flags (e.g. to indicate checksum status @@ -78,6 +78,8 @@ typedef struct dhd_prot { unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN]; } dhd_prot_t; +extern int dhd_dbus_txdata(dhd_pub_t *dhdp, void *pktbuf); + static int dhdcdc_msg(dhd_pub_t *dhd) { @@ -2174,6 +2176,7 @@ dhd_wlfc_init(dhd_pub_t *dhd) WLFC_FLAGS_CREDIT_STATUS_SIGNALS | WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE : 0; + dhd->wlfc_state = NULL; /* try to enable/disable signaling by sending "tlv" iovar. if that fails, @@ -2463,7 +2466,7 @@ dhd_prot_attach(dhd_pub_t *dhd) #ifndef CONFIG_DHD_USE_STATIC_BUF if (cdc != NULL) MFREE(dhd->osh, cdc, sizeof(dhd_prot_t)); -#endif +#endif /* CONFIG_DHD_USE_STATIC_BUF */ return BCME_NOMEM; } @@ -2476,7 +2479,7 @@ dhd_prot_detach(dhd_pub_t *dhd) #endif #ifndef CONFIG_DHD_USE_STATIC_BUF MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t)); -#endif +#endif /* CONFIG_DHD_USE_STATIC_BUF */ dhd->prot = NULL; } diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index 9df70a00dbf..6376546c62c 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_common.c 290546 2011-10-19 01:55:21Z $ + * $Id: dhd_common.c 297563 2011-11-20 15:38:29Z $ */ #include #include @@ -857,6 +857,8 @@ wl_show_host_event(wl_event_msg_t *event, void *event_data) break; case WLC_E_SCAN_COMPLETE: + case WLC_E_ASSOC_REQ_IE: + case WLC_E_ASSOC_RESP_IE: case WLC_E_PMKID_CACHE: DHD_EVENT(("MACEVENT: %s\n", event_name)); break; diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index f25fc324f24..48c970a6b5b 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c 291449 2011-10-22 12:16:26Z $ + * $Id: dhd_linux.c 301794 2011-12-08 20:41:35Z $ */ #include @@ -109,6 +109,7 @@ extern bool ap_fw_loaded; #include #ifdef ARP_OFFLOAD_SUPPORT +void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add); static int dhd_device_event(struct notifier_block *this, unsigned long event, void *ptr); @@ -273,6 +274,10 @@ typedef struct dhd_info { #ifdef CONFIG_HAS_EARLYSUSPEND struct early_suspend early_suspend; #endif /* CONFIG_HAS_EARLYSUSPEND */ + +#ifdef ARP_OFFLOAD_SUPPORT + u32 pend_ipaddr; +#endif /* ARP_OFFLOAD_SUPPORT */ } dhd_info_t; /* Definitions to provide path to the firmware and nvram @@ -941,8 +946,9 @@ dhd_op_if(dhd_if_t *ifp) unsigned long flags; #endif + if (!ifp || !ifp->info || !ifp->idx) + return; ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */ - dhd = ifp->info; DHD_TRACE(("%s: idx %d, state %d\n", __FUNCTION__, ifp->idx, ifp->state)); @@ -1032,10 +1038,8 @@ dhd_op_if(dhd_if_t *ifp) if (ret < 0) { ifp->set_multicast = FALSE; if (ifp->net) { -#ifdef WL_CFG80211 - wl_cfg80211_post_del((void*)(ifp->net)); -#endif free_netdev(ifp->net); + ifp->net = NULL; } dhd->iflist[ifp->idx] = NULL; #ifdef SOFTAP @@ -1166,6 +1170,7 @@ dhd_os_wlfc_block(dhd_pub_t *pub) { dhd_info_t *di = (dhd_info_t *)(pub->info); ASSERT(di != NULL); + spin_lock_bh(&di->wlfc_spinlock); return 1; } @@ -1199,7 +1204,7 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) } /* Update multicast statistic */ - if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_ADDR_LEN) { + if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) { uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); eh = (struct ether_header *)pktdata; @@ -1207,6 +1212,9 @@ dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) dhdp->tx_multicast++; if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) atomic_inc(&dhd->pend_8021x_cnt); + } else { + PKTFREE(dhd->pub.osh, pktbuf, TRUE); + return BCME_ERROR; } /* Look into the packet and update the packet priority */ @@ -1593,8 +1601,10 @@ dhd_get_stats(struct net_device *net) DHD_TRACE(("%s: Enter\n", __FUNCTION__)); ifidx = dhd_net2idx(dhd, net); - if (ifidx == DHD_BAD_IF) + if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__)); return NULL; + } ifp = dhd->iflist[ifidx]; ASSERT(dhd && ifp); @@ -2043,6 +2053,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); if (ifidx == DHD_BAD_IF) { + DHD_ERROR(("%s: BAD IF\n", __FUNCTION__)); DHD_OS_WAKE_UNLOCK(&dhd->pub); return -1; } @@ -2240,6 +2251,7 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd) #endif for (i = 1; i < DHD_MAX_IFS; i++) { + dhd_net_if_lock_local(dhd); if (dhd->iflist[i]) { DHD_TRACE(("Deleting IF: %d \n", i)); if ((dhd->iflist[i]->state != DHD_IF_DEL) && @@ -2249,6 +2261,7 @@ dhd_cleanup_virt_ifaces(dhd_info_t *dhd) dhd_op_if(dhd->iflist[i]); } } + dhd_net_if_unlock_local(dhd); } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) @@ -2364,7 +2377,6 @@ dhd_open(struct net_device *net) #endif /* defined(WL_CFG80211) */ if (dhd->pub.busstate != DHD_BUS_DATA) { - int ret; /* try to bring up bus */ if ((ret = dhd_bus_start(&dhd->pub)) != 0) { @@ -2490,6 +2502,26 @@ dhd_del_if(dhd_info_t *dhd, int ifidx) up(&dhd->thr_sysioc_ctl.sema); } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) +static struct net_device_ops dhd_ops_pri = { + .ndo_open = dhd_open, + .ndo_stop = dhd_stop, + .ndo_get_stats = dhd_get_stats, + .ndo_do_ioctl = dhd_ioctl_entry, + .ndo_start_xmit = dhd_start_xmit, + .ndo_set_mac_address = dhd_set_mac_address, + .ndo_set_multicast_list = dhd_set_multicast_list, +}; + +static struct net_device_ops dhd_ops_virt = { + .ndo_get_stats = dhd_get_stats, + .ndo_do_ioctl = dhd_ioctl_entry, + .ndo_start_xmit = dhd_start_xmit, + .ndo_set_mac_address = dhd_set_mac_address, + .ndo_set_multicast_list = dhd_set_multicast_list, +}; +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ + dhd_pub_t * dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) { @@ -2682,6 +2714,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #endif #ifdef ARP_OFFLOAD_SUPPORT + dhd->pend_ipaddr = 0; register_inetaddr_notifier(&dhd_notifier); #endif /* ARP_OFFLOAD_SUPPORT */ @@ -2715,7 +2748,8 @@ dhd_bus_start(dhd_pub_t *dhdp) DHD_TRACE(("Enter %s:\n", __FUNCTION__)); #ifdef DHDTHREAD - dhd_os_sdlock(dhdp); + if (dhd->threads_only) + dhd_os_sdlock(dhdp); #endif /* DHDTHREAD */ /* try to download image and nvram to the dongle */ @@ -2728,14 +2762,16 @@ dhd_bus_start(dhd_pub_t *dhdp) DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", __FUNCTION__, fw_path, nv_path)); #ifdef DHDTHREAD - dhd_os_sdunlock(dhdp); + if (dhd->threads_only) + dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ return -1; } } if (dhd->pub.busstate != DHD_BUS_LOAD) { #ifdef DHDTHREAD - dhd_os_sdunlock(dhdp); + if (dhd->threads_only) + dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ return -ENETDOWN; } @@ -2749,7 +2785,8 @@ dhd_bus_start(dhd_pub_t *dhdp) DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); #ifdef DHDTHREAD - dhd_os_sdunlock(dhdp); + if (dhd->threads_only) + dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ return ret; } @@ -2765,7 +2802,8 @@ dhd_bus_start(dhd_pub_t *dhdp) DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__)); #ifdef DHDTHREAD - dhd_os_sdunlock(dhdp); + if (dhd->threads_only) + dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ return -ENODEV; } @@ -2782,13 +2820,15 @@ dhd_bus_start(dhd_pub_t *dhdp) del_timer_sync(&dhd->timer); DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); #ifdef DHDTHREAD - dhd_os_sdunlock(dhdp); + if (dhd->threads_only) + dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ return -ENODEV; } #ifdef DHDTHREAD - dhd_os_sdunlock(dhdp); + if (dhd->threads_only) + dhd_os_sdunlock(dhdp); #endif /* DHDTHREAD */ #ifdef READ_MACADDR @@ -2803,6 +2843,15 @@ dhd_bus_start(dhd_pub_t *dhdp) dhd_write_macaddr(dhd->pub.mac.octet); #endif +#ifdef ARP_OFFLOAD_SUPPORT + if (dhd->pend_ipaddr) { +#ifdef AOE_IP_ALIAS_SUPPORT + aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE); +#endif /* AOE_IP_ALIAS_SUPPORT */ + dhd->pend_ipaddr = 0; + } +#endif /* ARP_OFFLOAD_SUPPORT */ + return 0; } @@ -2822,9 +2871,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if defined(ARP_OFFLOAD_SUPPORT) int arpoe = 1; #endif - int scan_assoc_time = 40; + int scan_assoc_time = DHD_SCAN_ACTIVE_TIME; int scan_unassoc_time = 40; - int scan_passive_time = 130; + int scan_passive_time = DHD_SCAN_PASSIVE_TIME; char buf[WLC_IOCTL_SMLEN]; char *ptr; uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ @@ -3022,6 +3071,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) setbit(eventmask, WLC_E_LINK); setbit(eventmask, WLC_E_NDIS_LINK); setbit(eventmask, WLC_E_MIC_ERROR); + setbit(eventmask, WLC_E_ASSOC_REQ_IE); + setbit(eventmask, WLC_E_ASSOC_RESP_IE); setbit(eventmask, WLC_E_PMKID_CACHE); setbit(eventmask, WLC_E_TXFAIL); setbit(eventmask, WLC_E_JOIN_START); @@ -3142,26 +3193,6 @@ dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, in return ret; } -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) -static struct net_device_ops dhd_ops_pri = { - .ndo_open = dhd_open, - .ndo_stop = dhd_stop, - .ndo_get_stats = dhd_get_stats, - .ndo_do_ioctl = dhd_ioctl_entry, - .ndo_start_xmit = dhd_start_xmit, - .ndo_set_mac_address = dhd_set_mac_address, - .ndo_set_multicast_list = dhd_set_multicast_list, -}; - -static struct net_device_ops dhd_ops_virt = { - .ndo_get_stats = dhd_get_stats, - .ndo_do_ioctl = dhd_ioctl_entry, - .ndo_start_xmit = dhd_start_xmit, - .ndo_set_mac_address = dhd_set_mac_address, - .ndo_set_multicast_list = dhd_set_multicast_list, -}; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ - int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) { struct dhd_info *dhd = dhdp->info; @@ -3265,9 +3296,13 @@ static int dhd_device_event(struct notifier_block *this, DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n", __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); - /* firmware not downloaded, do nothing */ - if (dhd->pub.busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: bus is down, exit\n", __FUNCTION__)); + if (dhd->pub.busstate != DHD_BUS_DATA) { + DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__)); + if (dhd->pend_ipaddr) { + DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n", + __FUNCTION__, dhd->pend_ipaddr)); + } + dhd->pend_ipaddr = ifa->ifa_address; break; } @@ -3285,7 +3320,7 @@ static int dhd_device_event(struct notifier_block *this, case NETDEV_DOWN: DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n", __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); - + dhd->pend_ipaddr = 0; #ifdef AOE_IP_ALIAS_SUPPORT if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) { DHD_ARPOE(("%s: primary interface is down, AOE clr all\n", @@ -3359,7 +3394,8 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) * portable hotspot. This will not work in simultaneous AP/STA mode, * nor with P2P. Need to set the Donlge's MAC address, and then use that. */ - if (ifidx > 0) { + if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr, + ETHER_ADDR_LEN)) { DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n", __func__, net->name)); temp_addr[0] |= 0x02; @@ -3496,13 +3532,15 @@ void dhd_detach(dhd_pub_t *dhdp) dhd_if_t *ifp; /* Cleanup virtual interfaces */ - for (i = 1; i < DHD_MAX_IFS; i++) + for (i = 1; i < DHD_MAX_IFS; i++) { + dhd_net_if_lock_local(dhd); if (dhd->iflist[i]) { dhd->iflist[i]->state = DHD_IF_DEL; dhd->iflist[i]->idx = i; dhd_op_if(dhd->iflist[i]); } - + dhd_net_if_unlock_local(dhd); + } /* delete primary interface 0 */ ifp = dhd->iflist[0]; ASSERT(ifp); @@ -4538,15 +4576,6 @@ int dhd_os_check_wakelock(void *dhdp) return 0; } -int dhd_os_check_if_up(void *dhdp) -{ - dhd_pub_t *pub = (dhd_pub_t *)dhdp; - - if (!pub) - return 0; - return pub->up; -} - int net_os_wake_unlock(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); @@ -4557,6 +4586,15 @@ int net_os_wake_unlock(struct net_device *dev) return ret; } +int dhd_os_check_if_up(void *dhdp) +{ + dhd_pub_t *pub = (dhd_pub_t *)dhdp; + + if (!pub) + return 0; + return pub->up; +} + int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) { int ifidx; @@ -4596,8 +4634,8 @@ extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t uint8 iftype, uint8* ea); extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits); -int dhd_wlfc_interface_event(struct dhd_info *dhd, uint8 action, uint8 ifid, uint8 iftype, - uint8* ea) +int dhd_wlfc_interface_event(struct dhd_info *dhd, + ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) { if (dhd->pub.wlfc_state == NULL) return BCME_OK; diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c index ce94ff9993d..d4dca260721 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux_mon.c @@ -2,13 +2,13 @@ * Broadcom Dongle Host Driver (DHD), Linux monitor network interface * * Copyright (C) 1999-2011, Broadcom Corporation - * + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,12 +16,12 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux_mon.c,v 1.131.2.55 2011-02-09 05:31:56 Exp $ + * $Id: dhd_linux_mon.c 297563 2011-11-20 15:38:29Z $ */ #include @@ -96,16 +96,30 @@ static const struct net_device_ops dhd_mon_if_ops = { static struct net_device* lookup_real_netdev(char *name) { int i; + int len = 0; int last_name_len = 0; struct net_device *ndev; struct net_device *ndev_found = NULL; - /* We want to find interface "p2p-eth0-0" for monitor interface "mon.p2p-eth0-0", so - * we skip "eth0" even if "mon.p2p-eth0-0" contains "eth0" + /* We need to find interface "p2p-p2p-0" corresponding to monitor interface "mon-p2p-0", + * Once mon iface name reaches IFNAMSIZ, it is reset to p2p0-0 and corresponding mon + * iface would be mon-p2p0-0. */ for (i = 0; i < DHD_MAX_IFS; i++) { ndev = dhd_idx2net(g_monitor.dhd_pub, i); - if (ndev && strstr(name, ndev->name)) { + + /* Skip "p2p" and look for "-p2p0-x" in monitor interface name. If it + * it matches, then this netdev is the corresponding real_netdev. + */ + if (ndev && strstr(ndev->name, "p2p-p2p0")) { + len = strlen("p2p"); + } else { + /* if p2p- is not present, then the IFNAMSIZ have reached and name + * would have got reset. In this casse,look for p2p0-x in mon-p2p0-x + */ + len = 0; + } + if (ndev && strstr(name, (ndev->name + len))) { if (strlen(ndev->name) > last_name_len) { ndev_found = ndev; last_name_len = strlen(ndev->name); diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 1bdc7d50f1f..7866eb771d5 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_sdio.c 288105 2011-10-06 01:58:02Z $ + * $Id: dhd_sdio.c 301794 2011-12-08 20:41:35Z $ */ #include @@ -1366,9 +1366,7 @@ dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) /* Send from dpc */ bus->ctrl_frame_buf = frame; bus->ctrl_frame_len = len; - dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat); - if (bus->ctrl_frame_stat == FALSE) { DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__)); ret = 0; @@ -3565,7 +3563,7 @@ dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) if ((uint8)(txmax - bus->tx_seq) > 0x40) { DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", __FUNCTION__, txmax, bus->tx_seq)); - txmax = bus->tx_seq; + txmax = bus->tx_max; } bus->tx_max = txmax; @@ -3766,6 +3764,14 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN; rxseq++, rxleft--) { +#ifdef DHDTHREAD + /* tx more to improve rx performance */ + if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && + pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) { + dhdsdio_sendfromq(bus, dhd_txbound); + } +#endif /* DHDTHREAD */ + /* Handle glomming separately */ if (bus->glom || bus->glomd) { uint8 cnt; @@ -3986,7 +3992,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) if ((uint8)(txmax - bus->tx_seq) > 0x40) { DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", __FUNCTION__, txmax, bus->tx_seq)); - txmax = bus->tx_seq; + txmax = bus->tx_max; } bus->tx_max = txmax; @@ -4143,7 +4149,7 @@ dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) if ((uint8)(txmax - bus->tx_seq) > 0x40) { DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", __FUNCTION__, txmax, bus->tx_seq)); - txmax = bus->tx_seq; + txmax = bus->tx_max; } bus->tx_max = txmax; @@ -5183,16 +5189,8 @@ dhdsdio_chipmatch(uint16 chipid) return TRUE; if (chipid == BCM4319_CHIP_ID) return TRUE; - if (chipid == BCM4336_CHIP_ID) - return TRUE; if (chipid == BCM4330_CHIP_ID) return TRUE; - if (chipid == BCM43237_CHIP_ID) - return TRUE; - if (chipid == BCM43362_CHIP_ID) - return TRUE; - if (chipid == BCM43239_CHIP_ID) - return TRUE; return FALSE; } @@ -5369,6 +5367,7 @@ dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, if (ret == BCME_NOTUP) goto fail; } + /* Ok, have the per-port tell the stack we're open for business */ if (dhd_net_attach(bus->dhd, 0) != 0) { DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__)); diff --git a/drivers/net/wireless/bcmdhd/dhd_wlfc.h b/drivers/net/wireless/bcmdhd/dhd_wlfc.h index 59d018b64c6..c4d251806d7 100644 --- a/drivers/net/wireless/bcmdhd/dhd_wlfc.h +++ b/drivers/net/wireless/bcmdhd/dhd_wlfc.h @@ -18,7 +18,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. -* $Id: dhd_wlfc.h,v 1.1.8.1 2010-09-09 22:41:08 Exp $ +* $Id: dhd_wlfc.h 286994 2011-09-29 21:27:44Z $ * */ #ifndef __wlfc_host_driver_definitions_h__ @@ -201,6 +201,7 @@ typedef struct athost_wl_stat_counters { #define WLFC_FCMODE_IMPLIED_CREDIT 1 #define WLFC_FCMODE_EXPLICIT_CREDIT 2 +/* How long to defer borrowing in milliseconds */ #define WLFC_BORROW_DEFER_PERIOD_MS 100 /* Mask to represent available ACs (note: BC/MC is ignored */ @@ -261,6 +262,15 @@ typedef struct athost_wl_status_info { /* Timestamp to compute how long to defer borrowing for */ uint32 borrow_defer_timestamp; + } athost_wl_status_info_t; +int dhd_wlfc_enable(dhd_pub_t *dhd); +int dhd_wlfc_interface_event(struct dhd_info *, + ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea); +int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data); +int dhd_wlfc_event(struct dhd_info *dhd); +int dhd_os_wlfc_block(dhd_pub_t *pub); +int dhd_os_wlfc_unblock(dhd_pub_t *pub); + #endif /* __wlfc_host_driver_definitions_h__ */ diff --git a/drivers/net/wireless/bcmdhd/hndpmu.c b/drivers/net/wireless/bcmdhd/hndpmu.c index b9586e40d0c..111b5be9cbf 100644 --- a/drivers/net/wireless/bcmdhd/hndpmu.c +++ b/drivers/net/wireless/bcmdhd/hndpmu.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: hndpmu.c,v 1.228.2.56 2011-02-11 22:49:07 Exp $ + * $Id: hndpmu.c,v 1.228.2.56 2011-02-11 22:49:07 $ */ #include @@ -93,26 +93,8 @@ static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v8[] = { {0, 0x1} }; /* SDIO Drive Strength to sel value table for PMU Rev 11 (1.2v) */ -static const sdiod_drive_str_t sdiod_drive_strength_tab4_1v2[] = { - {16, 0x3}, - {13, 0x2}, - {11, 0x1}, - {8, 0x0}, - {6, 0x7}, - {4, 0x6}, - {2, 0x5}, - {0, 0x4} }; /* SDIO Drive Strength to sel value table for PMU Rev 11 (2.5v) */ -static const sdiod_drive_str_t sdiod_drive_strength_tab4_2v5[] = { - {80, 0x5}, - {65, 0x4}, - {55, 0x7}, - {40, 0x6}, - {30, 0x1}, - {20, 0x0}, - {10, 0x3}, - {0, 0x2} }; /* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = { @@ -125,14 +107,6 @@ static const sdiod_drive_str_t sdiod_drive_strength_tab5_1v8[] = { {0, 0x0} }; /* SDIO Drive Strength to sel value table for PMU Rev 13 (3.3v) */ -static const sdiod_drive_str_t sdiod_drive_strength_tab5_3v3[] = { - {12, 0x7}, - {10, 0x6}, - {8, 0x5}, - {6, 0x4}, - {4, 0x2}, - {2, 0x1}, - {0, 0x0} }; #define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu)) @@ -166,27 +140,11 @@ si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) str_mask = 0x00003800; str_shift = 11; break; - case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): - case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): - if (sih->pmurev == 8) { - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; - } - else if (sih->pmurev == 11) { - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; - } - str_mask = 0x00003800; - str_shift = 11; - break; case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; str_mask = 0x00003800; str_shift = 11; break; - case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): - str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; - str_mask = 0x00003800; - str_shift = 11; - break; default: PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); diff --git a/drivers/net/wireless/bcmdhd/include/Makefile b/drivers/net/wireless/bcmdhd/include/Makefile index c07266fd6fd..67c4906f588 100644 --- a/drivers/net/wireless/bcmdhd/include/Makefile +++ b/drivers/net/wireless/bcmdhd/include/Makefile @@ -10,7 +10,7 @@ # # Copyright 2005, Broadcom, Inc. # -# $Id: Makefile 241702 2011-02-19 00:41:03Z automrgr $ +# $Id: Makefile 241702 2011-02-19 00:41:03Z $ # SRCBASE := .. diff --git a/drivers/net/wireless/bcmdhd/include/aidmp.h b/drivers/net/wireless/bcmdhd/include/aidmp.h index 375df443a29..b993a033abc 100644 --- a/drivers/net/wireless/bcmdhd/include/aidmp.h +++ b/drivers/net/wireless/bcmdhd/include/aidmp.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: aidmp.h,v 13.4.14.1 2010-03-09 18:40:06 Exp $ + * $Id: aidmp.h 277737 2011-08-16 17:54:59Z $ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmcdc.h b/drivers/net/wireless/bcmdhd/include/bcmcdc.h index ce45c50d964..77a20f87b7e 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmcdc.h +++ b/drivers/net/wireless/bcmdhd/include/bcmcdc.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmcdc.h,v 13.25.10.3 2010-12-22 23:47:26 Exp $ + * $Id: bcmcdc.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _bcmcdc_h_ diff --git a/drivers/net/wireless/bcmdhd/include/bcmdefs.h b/drivers/net/wireless/bcmdhd/include/bcmdefs.h index da1fd5e4eac..17cc0e955f6 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmdefs.h +++ b/drivers/net/wireless/bcmdhd/include/bcmdefs.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmdefs.h,v 13.68.2.8 2011-01-08 04:04:19 Exp $ + * $Id: bcmdefs.h 279282 2011-08-23 22:44:02Z $ */ @@ -30,12 +30,26 @@ + +#define BCM_REFERENCE(data) ((void)(data)) + + + #define bcmreclaimed 0 #define _data _data #define _fn _fn +#define BCMPREATTACHDATA(_data) _data +#define BCMPREATTACHFN(_fn) _fn #define _data _data #define _fn _fn #define _fn _fn +#define BCMNMIATTACHFN(_fn) _fn +#define BCMNMIATTACHDATA(_data) _data +#define BCMOVERLAY0DATA(_sym) _sym +#define BCMOVERLAY0FN(_fn) _fn +#define BCMOVERLAY1DATA(_sym) _sym +#define BCMOVERLAY1FN(_fn) _fn +#define BCMOVERLAYERRFN(_fn) _fn #define CONST const #define BCMFASTPATH @@ -43,9 +57,30 @@ #define _data _data +#define BCMROMDAT_NAME(_data) _data #define _fn _fn #define _fn _fn #define STATIC static +#define BCMROMDAT_ARYSIZ(data) ARRAYSIZE(data) +#define BCMROMDAT_SIZEOF(data) sizeof(data) +#define BCMROMDAT_APATCH(data) +#define BCMROMDAT_SPATCH(data) + + + +#define OVERLAY_INLINE +#define OSTATIC static +#define BCMOVERLAYDATA(_ovly, _sym) _sym +#define BCMOVERLAYFN(_ovly, _fn) _fn +#define BCMOVERLAYERRFN(_fn) _fn +#define BCMROMOVERLAYDATA(_ovly, _data) _data +#define BCMROMOVERLAYFN(_ovly, _fn) _fn +#define BCMATTACHOVERLAYDATA(_ovly, _sym) _sym +#define BCMATTACHOVERLAYFN(_ovly, _fn) _fn +#define BCMINITOVERLAYDATA(_ovly, _sym) _sym +#define BCMINITOVERLAYFN(_ovly, _fn) _fn +#define BCMUNINITOVERLAYFN(_ovly, _fn) _fn + #define SI_BUS 0 diff --git a/drivers/net/wireless/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/bcmdhd/include/bcmdevs.h index 4f707c0c692..f0542f2ac11 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmdevs.h +++ b/drivers/net/wireless/bcmdhd/include/bcmdevs.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmdevs.h,v 13.285.2.39 2011-02-04 05:03:16 Exp $ + * $Id: bcmdevs.h 295140 2011-11-09 17:22:01Z $ */ @@ -31,7 +31,16 @@ #define VENDOR_EPIGRAM 0xfeda #define VENDOR_BROADCOM 0x14e4 +#define VENDOR_3COM 0x10b7 +#define VENDOR_NETGEAR 0x1385 +#define VENDOR_DIAMOND 0x1092 +#define VENDOR_INTEL 0x8086 +#define VENDOR_DELL 0x1028 +#define VENDOR_HP 0x103c +#define VENDOR_HP_COMPAQ 0x0e11 +#define VENDOR_APPLE 0x106b #define VENDOR_SI_IMAGE 0x1095 +#define VENDOR_BUFFALO 0x1154 #define VENDOR_TI 0x104c #define VENDOR_RICOH 0x1180 #define VENDOR_JMICRON 0x197b @@ -48,15 +57,41 @@ #define BCM_DNGL_BL_PID_4328 0xbd12 #define BCM_DNGL_BL_PID_4322 0xbd13 #define BCM_DNGL_BL_PID_4319 0xbd16 -#define BCM_DNGL_BL_PID_43236 0xbd17 #define BCM_DNGL_BL_PID_4332 0xbd18 #define BCM_DNGL_BL_PID_4330 0xbd19 -#define BCM_DNGL_BL_PID_43239 0xbd1b #define BCM_DNGL_BDC_PID 0x0bdc #define BCM_DNGL_JTAG_PID 0x4a44 + + +#define BCM_HWUSB_PID_43239 43239 + + +#define BCM4210_DEVICE_ID 0x1072 +#define BCM4230_DEVICE_ID 0x1086 +#define BCM4401_ENET_ID 0x170c +#define BCM3352_DEVICE_ID 0x3352 +#define BCM3360_DEVICE_ID 0x3360 +#define BCM4211_DEVICE_ID 0x4211 +#define BCM4231_DEVICE_ID 0x4231 +#define BCM4303_D11B_ID 0x4303 +#define BCM4311_D11G_ID 0x4311 +#define BCM4311_D11DUAL_ID 0x4312 +#define BCM4311_D11A_ID 0x4313 +#define BCM4328_D11DUAL_ID 0x4314 +#define BCM4328_D11G_ID 0x4315 +#define BCM4328_D11A_ID 0x4316 +#define BCM4318_D11G_ID 0x4318 +#define BCM4318_D11DUAL_ID 0x4319 +#define BCM4318_D11A_ID 0x431a #define BCM4325_D11DUAL_ID 0x431b #define BCM4325_D11G_ID 0x431c #define BCM4325_D11A_ID 0x431d +#define BCM4306_D11G_ID 0x4320 +#define BCM4306_D11A_ID 0x4321 +#define BCM4306_UART_ID 0x4322 +#define BCM4306_V90_ID 0x4323 +#define BCM4306_D11DUAL_ID 0x4324 +#define BCM4306_D11G_ID2 0x4325 #define BCM4321_D11N_ID 0x4328 #define BCM4321_D11N2G_ID 0x4329 #define BCM4321_D11N5G_ID 0x432a @@ -98,17 +133,58 @@ #define BCM43237_D11N5G_ID 0x4356 #define BCM43227_D11N2G_ID 0x4358 #define BCM43228_D11N_ID 0x4359 -#define BCM43228_D11N5G_ID 0x435a +#define BCM43228_D11N5G_ID 0x435a #define BCM43362_D11N_ID 0x4363 #define BCM43239_D11N_ID 0x4370 +#define BCM4324_D11N_ID 0x4374 +#define BCM43217_D11N2G_ID 0x43a9 +#define BCM43131_D11N2G_ID 0x43aa +#define BCM4314_D11N2G_ID 0x4364 +#define BCM43142_D11N2G_ID 0x4365 +#define BCMGPRS_UART_ID 0x4333 +#define BCMGPRS2_UART_ID 0x4344 +#define FPGA_JTAGM_ID 0x43f0 +#define BCM_JTAGM_ID 0x43f1 #define SDIOH_FPGA_ID 0x43f2 +#define BCM_SDIOH_ID 0x43f3 +#define SDIOD_FPGA_ID 0x43f4 #define SPIH_FPGA_ID 0x43f5 +#define BCM_SPIH_ID 0x43f6 +#define MIMO_FPGA_ID 0x43f8 +#define BCM_JTAGM2_ID 0x43f9 +#define SDHCI_FPGA_ID 0x43fa +#define BCM4402_ENET_ID 0x4402 +#define BCM4402_V90_ID 0x4403 +#define BCM4410_DEVICE_ID 0x4410 +#define BCM4412_DEVICE_ID 0x4412 +#define BCM4430_DEVICE_ID 0x4430 +#define BCM4432_DEVICE_ID 0x4432 +#define BCM4704_ENET_ID 0x4706 #define BCM4710_DEVICE_ID 0x4710 +#define BCM47XX_AUDIO_ID 0x4711 +#define BCM47XX_V90_ID 0x4712 +#define BCM47XX_ENET_ID 0x4713 +#define BCM47XX_EXT_ID 0x4714 +#define BCM47XX_GMAC_ID 0x4715 +#define BCM47XX_USBH_ID 0x4716 +#define BCM47XX_USBD_ID 0x4717 +#define BCM47XX_IPSEC_ID 0x4718 +#define BCM47XX_ROBO_ID 0x4719 +#define BCM47XX_USB20H_ID 0x471a +#define BCM47XX_USB20D_ID 0x471b +#define BCM47XX_ATA100_ID 0x471d +#define BCM47XX_SATAXOR_ID 0x471e +#define BCM47XX_GIGETH_ID 0x471f +#define BCM4712_MIPS_ID 0x4720 +#define BCM4716_DEVICE_ID 0x4722 +#define BCM47XX_SMBUS_EMU_ID 0x47fe +#define BCM47XX_XOR_EMU_ID 0x47ff +#define EPI41210_DEVICE_ID 0xa0fa +#define EPI41230_DEVICE_ID 0xa10e +#define JINVANI_SDIOH_ID 0x4743 #define BCM27XX_SDIOH_ID 0x2702 -#define PCIXX21_FLASHMEDIA0_ID 0x8033 -#define PCIXX21_SDIOH0_ID 0x8034 #define PCIXX21_FLASHMEDIA_ID 0x803b #define PCIXX21_SDIOH_ID 0x803c #define R5C822_SDIOH_ID 0x0822 @@ -121,11 +197,13 @@ #define BCM43112_CHIP_ID 43112 #define BCM4312_CHIP_ID 0x4312 #define BCM4313_CHIP_ID 0x4313 +#define BCM43131_CHIP_ID 43131 #define BCM4315_CHIP_ID 0x4315 #define BCM4318_CHIP_ID 0x4318 #define BCM4319_CHIP_ID 0x4319 #define BCM4320_CHIP_ID 0x4320 #define BCM4321_CHIP_ID 0x4321 +#define BCM43217_CHIP_ID 43217 #define BCM4322_CHIP_ID 0x4322 #define BCM43221_CHIP_ID 43221 #define BCM43222_CHIP_ID 43222 @@ -152,15 +230,28 @@ #define BCM4336_CHIP_ID 0x4336 #define BCM43362_CHIP_ID 43362 #define BCM4330_CHIP_ID 0x4330 +#define BCM6362_CHIP_ID 0x6362 +#define BCM4314_CHIP_ID 0x4314 +#define BCM43142_CHIP_ID 43142 +#define BCM4324_CHIP_ID 0x4324 + +#define BCM4342_CHIP_ID 4342 #define BCM4402_CHIP_ID 0x4402 #define BCM4704_CHIP_ID 0x4704 #define BCM4710_CHIP_ID 0x4710 #define BCM4712_CHIP_ID 0x4712 +#define BCM4716_CHIP_ID 0x4716 +#define BCM47162_CHIP_ID 47162 +#define BCM4748_CHIP_ID 0x4748 +#define BCM4749_CHIP_ID 0x4749 #define BCM4785_CHIP_ID 0x4785 #define BCM5350_CHIP_ID 0x5350 #define BCM5352_CHIP_ID 0x5352 #define BCM5354_CHIP_ID 0x5354 #define BCM5365_CHIP_ID 0x5365 +#define BCM5356_CHIP_ID 0x5356 +#define BCM5357_CHIP_ID 0x5357 +#define BCM53572_CHIP_ID 53572 #define BCM4303_PKG_ID 2 @@ -175,8 +266,478 @@ #define BCM4329_289PIN_PKG_ID 0 #define BCM4329_182PIN_PKG_ID 1 #define BCM5354E_PKG_ID 1 +#define BCM4716_PKG_ID 8 +#define BCM4717_PKG_ID 9 +#define BCM4718_PKG_ID 10 +#define BCM5356_PKG_NONMODE 1 +#define BCM5358U_PKG_ID 8 +#define BCM5358_PKG_ID 9 +#define BCM47186_PKG_ID 10 +#define BCM5357_PKG_ID 11 +#define BCM5356U_PKG_ID 12 +#define BCM53572_PKG_ID 8 +#define BCM47188_PKG_ID 9 +#define BCM4331TT_PKG_ID 8 +#define BCM4331TN_PKG_ID 9 +#define BCM4331TNA0_PKG_ID 0xb + + #define HDLSIM5350_PKG_ID 1 #define HDLSIM_PKG_ID 14 #define HWSIM_PKG_ID 15 +#define BCM43224_FAB_CSM 0x8 +#define BCM43224_FAB_SMIC 0xa +#define BCM4336_WLBGA_PKG_ID 0x8 +#define BCM4330_WLBGA_PKG_ID 0x0 +#define BCM4314PCIE_ARM_PKG_ID (8 | 0) +#define BCM4314SDIO_PKG_ID (8 | 1) +#define BCM4314PCIE_PKG_ID (8 | 2) +#define BCM4314SDIO_ARM_PKG_ID (8 | 3) +#define BCM4314SDIO_FPBGA_PKG_ID (8 | 4) +#define BCM4314DEV_PKG_ID (8 | 6) + +#define PCIXX21_FLASHMEDIA0_ID 0x8033 +#define PCIXX21_SDIOH0_ID 0x8034 + + +#define BFL_BTC2WIRE 0x00000001 +#define BFL_BTCOEX 0x00000001 +#define BFL_PACTRL 0x00000002 +#define BFL_AIRLINEMODE 0x00000004 +#define BFL_ADCDIV 0x00000008 +#define BFL_ENETROBO 0x00000010 +#define BFL_NOPLLDOWN 0x00000020 +#define BFL_CCKHIPWR 0x00000040 +#define BFL_ENETADM 0x00000080 +#define BFL_ENETVLAN 0x00000100 +#ifdef WLAFTERBURNER +#define BFL_AFTERBURNER 0x00000200 +#endif +#define BFL_NOPCI 0x00000400 +#define BFL_FEM 0x00000800 +#define BFL_EXTLNA 0x00001000 +#define BFL_HGPA 0x00002000 +#define BFL_BTC2WIRE_ALTGPIO 0x00004000 +#define BFL_ALTIQ 0x00008000 +#define BFL_NOPA 0x00010000 +#define BFL_RSSIINV 0x00020000 +#define BFL_PAREF 0x00040000 +#define BFL_3TSWITCH 0x00080000 +#define BFL_PHASESHIFT 0x00100000 +#define BFL_BUCKBOOST 0x00200000 +#define BFL_FEM_BT 0x00400000 +#define BFL_NOCBUCK 0x00800000 +#define BFL_CCKFAVOREVM 0x01000000 +#define BFL_PALDO 0x02000000 +#define BFL_LNLDO2_2P5 0x04000000 +#define BFL_FASTPWR 0x08000000 +#define BFL_UCPWRCTL_MININDX 0x08000000 +#define BFL_EXTLNA_5GHz 0x10000000 +#define BFL_TRSW_1by2 0x20000000 +#define BFL_LO_TRSW_R_5GHz 0x40000000 +#define BFL_ELNA_GAINDEF 0x80000000 +#define BFL_EXTLNA_TX 0x20000000 + + +#define BFL2_RXBB_INT_REG_DIS 0x00000001 +#define BFL2_APLL_WAR 0x00000002 +#define BFL2_TXPWRCTRL_EN 0x00000004 +#define BFL2_2X4_DIV 0x00000008 +#define BFL2_5G_PWRGAIN 0x00000010 +#define BFL2_PCIEWAR_OVR 0x00000020 +#define BFL2_CAESERS_BRD 0x00000040 +#define BFL2_BTC3WIRE 0x00000080 +#define BFL2_BTCLEGACY 0x00000080 +#define BFL2_SKWRKFEM_BRD 0x00000100 +#define BFL2_SPUR_WAR 0x00000200 +#define BFL2_GPLL_WAR 0x00000400 +#define BFL2_TRISTATE_LED 0x00000800 +#define BFL2_SINGLEANT_CCK 0x00001000 +#define BFL2_2G_SPUR_WAR 0x00002000 +#define BFL2_BPHY_ALL_TXCORES 0x00004000 +#define BFL2_FCC_BANDEDGE_WAR 0x00008000 +#define BFL2_GPLL_WAR2 0x00010000 +#define BFL2_IPALVLSHIFT_3P3 0x00020000 +#define BFL2_INTERNDET_TXIQCAL 0x00040000 +#define BFL2_XTALBUFOUTEN 0x00080000 +#define BFL2_ANAPACTRL_2G 0x00100000 +#define BFL2_ANAPACTRL_5G 0x00200000 +#define BFL2_ELNACTRL_TRSW_2G 0x00400000 +#define BFL2_BT_SHARE_ANT0 0x00800000 +#define BFL2_TEMPSENSE_HIGHER 0x01000000 +#define BFL2_BTC3WIREONLY 0x02000000 +#define BFL2_PWR_NOMINAL 0x04000000 +#define BFL2_EXTLNA_TX 0x08000000 + +#define BFL2_4313_RADIOREG 0x10000000 + + + +#define BOARD_GPIO_BTC3W_IN 0x850 +#define BOARD_GPIO_BTC3W_OUT 0x020 +#define BOARD_GPIO_BTCMOD_IN 0x010 +#define BOARD_GPIO_BTCMOD_OUT 0x020 +#define BOARD_GPIO_BTC_IN 0x080 +#define BOARD_GPIO_BTC_OUT 0x100 +#define BOARD_GPIO_PACTRL 0x200 +#define BOARD_GPIO_12 0x1000 +#define BOARD_GPIO_13 0x2000 +#define BOARD_GPIO_BTC4_IN 0x0800 +#define BOARD_GPIO_BTC4_BT 0x2000 +#define BOARD_GPIO_BTC4_STAT 0x4000 +#define BOARD_GPIO_BTC4_WLAN 0x8000 +#define BOARD_GPIO_1_WLAN_PWR 0x2 +#define BOARD_GPIO_4_WLAN_PWR 0x10 + +#define GPIO_BTC4W_OUT_4312 0x010 +#define GPIO_BTC4W_OUT_43224 0x020 +#define GPIO_BTC4W_OUT_43224_SHARED 0x0e0 +#define GPIO_BTC4W_OUT_43225 0x0e0 +#define GPIO_BTC4W_OUT_43421 0x020 +#define GPIO_BTC4W_OUT_4313 0x060 + +#define PCI_CFG_GPIO_SCS 0x10 +#define PCI_CFG_GPIO_HWRAD 0x20 +#define PCI_CFG_GPIO_XTAL 0x40 +#define PCI_CFG_GPIO_PLL 0x80 + + +#define PLL_DELAY 150 +#define FREF_DELAY 200 +#define MIN_SLOW_CLK 32 +#define XTAL_ON_DELAY 1000 + + +#define BU4710_BOARD 0x0400 +#define VSIM4710_BOARD 0x0401 +#define QT4710_BOARD 0x0402 + +#define BU4309_BOARD 0x040a +#define BCM94309CB_BOARD 0x040b +#define BCM94309MP_BOARD 0x040c +#define BCM4309AP_BOARD 0x040d + +#define BCM94302MP_BOARD 0x040e + +#define BU4306_BOARD 0x0416 +#define BCM94306CB_BOARD 0x0417 +#define BCM94306MP_BOARD 0x0418 + +#define BCM94710D_BOARD 0x041a +#define BCM94710R1_BOARD 0x041b +#define BCM94710R4_BOARD 0x041c +#define BCM94710AP_BOARD 0x041d + +#define BU2050_BOARD 0x041f + +#define BCM94306P50_BOARD 0x0420 + +#define BCM94309G_BOARD 0x0421 + +#define BU4704_BOARD 0x0423 +#define BU4702_BOARD 0x0424 + +#define BCM94306PC_BOARD 0x0425 + +#define MPSG4306_BOARD 0x0427 + +#define BCM94702MN_BOARD 0x0428 + + +#define BCM94702CPCI_BOARD 0x0429 + + +#define BCM95380RR_BOARD 0x042a + + +#define BCM94306CBSG_BOARD 0x042b + + +#define PCSG94306_BOARD 0x042d + + +#define BU4704SD_BOARD 0x042e + + +#define BCM94704AGR_BOARD 0x042f + + +#define BCM94308MP_BOARD 0x0430 + + +#define BCM94306GPRS_BOARD 0x0432 + + +#define BU5365_FPGA_BOARD 0x0433 + +#define BU4712_BOARD 0x0444 +#define BU4712SD_BOARD 0x045d +#define BU4712L_BOARD 0x045f + + +#define BCM94712AP_BOARD 0x0445 +#define BCM94712P_BOARD 0x0446 + + +#define BU4318_BOARD 0x0447 +#define CB4318_BOARD 0x0448 +#define MPG4318_BOARD 0x0449 +#define MP4318_BOARD 0x044a +#define SD4318_BOARD 0x044b + + +#define BCM94313BU_BOARD 0x050f +#define BCM94313HM_BOARD 0x0510 +#define BCM94313EPA_BOARD 0x0511 +#define BCM94313HMG_BOARD 0x051C + + +#define BCM96338_BOARD 0x6338 +#define BCM96348_BOARD 0x6348 +#define BCM96358_BOARD 0x6358 +#define BCM96368_BOARD 0x6368 + + +#define BCM94306P_BOARD 0x044c + + +#define BCM94303MP_BOARD 0x044e + + +#define BCM94306MPSGH_BOARD 0x044f + + +#define BCM94306MPM 0x0450 +#define BCM94306MPL 0x0453 + + +#define BCM94712AGR_BOARD 0x0451 + + +#define PC4303_BOARD 0x0454 + + +#define BCM95350K_BOARD 0x0455 + + +#define BCM95350R_BOARD 0x0456 + + +#define BCM94306MPLNA_BOARD 0x0457 + + +#define BU4320_BOARD 0x0458 +#define BU4320S_BOARD 0x0459 +#define BCM94320PH_BOARD 0x045a + + +#define BCM94306MPH_BOARD 0x045b + + +#define BCM94306PCIV_BOARD 0x045c + +#define BU4712SD_BOARD 0x045d + +#define BCM94320PFLSH_BOARD 0x045e + +#define BU4712L_BOARD 0x045f +#define BCM94712LGR_BOARD 0x0460 +#define BCM94320R_BOARD 0x0461 + +#define BU5352_BOARD 0x0462 + +#define BCM94318MPGH_BOARD 0x0463 + +#define BU4311_BOARD 0x0464 +#define BCM94311MC_BOARD 0x0465 +#define BCM94311MCAG_BOARD 0x0466 + +#define BCM95352GR_BOARD 0x0467 + + +#define BCM95351AGR_BOARD 0x0470 + + +#define BCM94704MPCB_BOARD 0x0472 + + +#define BU4785_BOARD 0x0478 + + +#define BU4321_BOARD 0x046b +#define BU4321E_BOARD 0x047c +#define MP4321_BOARD 0x046c +#define CB2_4321_BOARD 0x046d +#define CB2_4321_AG_BOARD 0x0066 +#define MC4321_BOARD 0x046e + + +#define BU4328_BOARD 0x0481 +#define BCM4328SDG_BOARD 0x0482 +#define BCM4328SDAG_BOARD 0x0483 +#define BCM4328UG_BOARD 0x0484 +#define BCM4328UAG_BOARD 0x0485 +#define BCM4328PC_BOARD 0x0486 +#define BCM4328CF_BOARD 0x0487 + + +#define BCM94325DEVBU_BOARD 0x0490 +#define BCM94325BGABU_BOARD 0x0491 + +#define BCM94325SDGWB_BOARD 0x0492 + +#define BCM94325SDGMDL_BOARD 0x04aa +#define BCM94325SDGMDL2_BOARD 0x04c6 +#define BCM94325SDGMDL3_BOARD 0x04c9 + +#define BCM94325SDABGWBA_BOARD 0x04e1 + + +#define BCM94322MC_SSID 0x04a4 +#define BCM94322USB_SSID 0x04a8 +#define BCM94322HM_SSID 0x04b0 +#define BCM94322USB2D_SSID 0x04bf + + +#define BCM4312MCGSG_BOARD 0x04b5 + + +#define BCM94315DEVBU_SSID 0x04c2 +#define BCM94315USBGP_SSID 0x04c7 +#define BCM94315BGABU_SSID 0x04ca +#define BCM94315USBGP41_SSID 0x04cb + + +#define BCM94319DEVBU_SSID 0X04e5 +#define BCM94319USB_SSID 0X04e6 +#define BCM94319SD_SSID 0X04e7 + + +#define BCM94716NR2_SSID 0x04cd + + +#define BCM94319DEVBU_SSID 0X04e5 +#define BCM94319USBNP4L_SSID 0X04e6 +#define BCM94319WLUSBN4L_SSID 0X04e7 +#define BCM94319SDG_SSID 0X04ea +#define BCM94319LCUSBSDN4L_SSID 0X04eb +#define BCM94319USBB_SSID 0x04ee +#define BCM94319LCSDN4L_SSID 0X0507 +#define BCM94319LSUSBN4L_SSID 0X0508 +#define BCM94319SDNA4L_SSID 0X0517 +#define BCM94319SDELNA4L_SSID 0X0518 +#define BCM94319SDELNA6L_SSID 0X0539 +#define BCM94319ARCADYAN_SSID 0X0546 +#define BCM94319WINDSOR_SSID 0x0561 +#define BCM94319MLAP_SSID 0x0562 +#define BCM94319SDNA_SSID 0x058b +#define BCM94319BHEMU3_SSID 0x0563 +#define BCM94319SDHMB_SSID 0x058c +#define BCM94319SDBREF_SSID 0x05a1 +#define BCM94319USBSDB_SSID 0x05a2 + + + +#define BCM94329AGB_SSID 0X04b9 +#define BCM94329TDKMDL1_SSID 0X04ba +#define BCM94329TDKMDL11_SSID 0X04fc +#define BCM94329OLYMPICN18_SSID 0X04fd +#define BCM94329OLYMPICN90_SSID 0X04fe +#define BCM94329OLYMPICN90U_SSID 0X050c +#define BCM94329OLYMPICN90M_SSID 0X050b +#define BCM94329AGBF_SSID 0X04ff +#define BCM94329OLYMPICX17_SSID 0X0504 +#define BCM94329OLYMPICX17M_SSID 0X050a +#define BCM94329OLYMPICX17U_SSID 0X0509 +#define BCM94329OLYMPICUNO_SSID 0X0564 +#define BCM94329MOTOROLA_SSID 0X0565 +#define BCM94329OLYMPICLOCO_SSID 0X0568 + +#define BCM94336SD_WLBGABU_SSID 0x0511 +#define BCM94336SD_WLBGAREF_SSID 0x0519 +#define BCM94336SDGP_SSID 0x0538 +#define BCM94336SDG_SSID 0x0519 +#define BCM94336SDGN_SSID 0x0538 +#define BCM94336SDGFC_SSID 0x056B + + +#define BCM94330SDG_SSID 0x0528 +#define BCM94330SD_FCBGABU_SSID 0x052e +#define BCM94330SD_WLBGABU_SSID 0x052f +#define BCM94330SD_FCBGA_SSID 0x0530 +#define BCM94330FCSDAGB_SSID 0x0532 +#define BCM94330OLYMPICAMG_SSID 0x0549 +#define BCM94330OLYMPICAMGEPA_SSID 0x054F +#define BCM94330OLYMPICUNO3_SSID 0x0551 +#define BCM94330WLSDAGB_SSID 0x0547 +#define BCM94330CSPSDAGBB_SSID 0x054A + + +#define BCM943224X21 0x056e +#define BCM943224X21_FCC 0x00d1 + + +#define BCM943228BU8_SSID 0x0540 +#define BCM943228BU9_SSID 0x0541 +#define BCM943228BU_SSID 0x0542 +#define BCM943227HM4L_SSID 0x0543 +#define BCM943227HMB_SSID 0x0544 +#define BCM943228HM4L_SSID 0x0545 +#define BCM943228SD_SSID 0x0573 + + +#define BCM943239MOD_SSID 0x05ac +#define BCM943239REF_SSID 0x05aa + + +#define BCM94331X19 0x00D6 +#define BCM94331PCIEBT3Ax_SSID 0x00E4 +#define BCM94331X12_2G_SSID 0x00EC +#define BCM94331X12_5G_SSID 0x00ED +#define BCM94331X29B 0x00EF +#define BCM94331BU_SSID 0x0523 +#define BCM94331S9BU_SSID 0x0524 +#define BCM94331MC_SSID 0x0525 +#define BCM94331MCI_SSID 0x0526 +#define BCM94331PCIEBT4_SSID 0x0527 +#define BCM94331HM_SSID 0x0574 +#define BCM94331PCIEDUAL_SSID 0x059B +#define BCM94331MCH5_SSID 0x05A9 +#define BCM94331PCIEDUALV2_SSID 0x05B7 +#define BCM94331CS_SSID 0x05C6 +#define BCM94331CSAX_SSID 0x00EF + + +#define BCM953572BU_SSID 0x058D +#define BCM953572NR2_SSID 0x058E +#define BCM947188NR2_SSID 0x058F +#define BCM953572SDRNR2_SSID 0x0590 + + +#define BCM943236OLYMPICSULLEY_SSID 0x594 +#define BCM943236PREPROTOBLU2O3_SSID 0x5b9 +#define BCM943236USBELNA_SSID 0x5f8 + + +#define GPIO_NUMPINS 32 + + +#define RDL_RAM_BASE_4319 0x60000000 +#define RDL_RAM_BASE_4329 0x60000000 +#define RDL_RAM_SIZE_4319 0x48000 +#define RDL_RAM_SIZE_4329 0x48000 +#define RDL_RAM_SIZE_43236 0x70000 +#define RDL_RAM_BASE_43236 0x60000000 +#define RDL_RAM_SIZE_4328 0x60000 +#define RDL_RAM_BASE_4328 0x80000000 +#define RDL_RAM_SIZE_4322 0x60000 +#define RDL_RAM_BASE_4322 0x60000000 + + +#define MUXENAB_UART 0x00000001 +#define MUXENAB_GPIO 0x00000002 +#define MUXENAB_ERCX 0x00000004 +#define MUXENAB_JTAG 0x00000008 +#define MUXENAB_HOST_WAKE 0x00000010 #endif diff --git a/drivers/net/wireless/bcmdhd/include/bcmendian.h b/drivers/net/wireless/bcmdhd/include/bcmendian.h index 04b07ecb804..f3356a724b4 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmendian.h +++ b/drivers/net/wireless/bcmdhd/include/bcmendian.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmendian.h,v 1.36 2009-11-09 05:29:43 Exp $ + * $Id: bcmendian.h 277737 2011-08-16 17:54:59Z $ * * This file by default provides proper behavior on little-endian architectures. * On big-endian architectures, IL_BIGENDIAN should be defined. diff --git a/drivers/net/wireless/bcmdhd/include/bcmpcispi.h b/drivers/net/wireless/bcmdhd/include/bcmpcispi.h index fd148c591d8..51e0427e7f6 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmpcispi.h +++ b/drivers/net/wireless/bcmdhd/include/bcmpcispi.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmpcispi.h,v 13.15.112.1 2010-11-15 18:22:12 Exp $ + * $Id: bcmpcispi.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _BCM_PCI_SPI_H #define _BCM_PCI_SPI_H diff --git a/drivers/net/wireless/bcmdhd/include/bcmperf.h b/drivers/net/wireless/bcmdhd/include/bcmperf.h index a3985cf2937..a503edbd622 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmperf.h +++ b/drivers/net/wireless/bcmdhd/include/bcmperf.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmperf.h,v 13.5 2007-09-14 22:00:59 Exp $ + * $Id: bcmperf.h 277737 2011-08-16 17:54:59Z $ */ /* essai */ #ifndef _BCMPERF_H_ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h index 5fda5e9b5df..21a58b473e9 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmsdbus.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdbus.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdbus.h,v 13.17.86.2 2010-12-23 01:13:20 Exp $ + * $Id: bcmsdbus.h 300017 2011-12-01 20:30:27Z $ */ #ifndef _sdio_api_h_ @@ -117,4 +117,12 @@ void *bcmsdh_get_sdioh(bcmsdh_info_t *sdh); +extern SDIOH_API_RC sdioh_sleep(sdioh_info_t *si, bool enab); + +/* GPIO support */ +extern SDIOH_API_RC sdioh_gpio_init(sdioh_info_t *sd); +extern bool sdioh_gpioin(sdioh_info_t *sd, uint32 gpio); +extern SDIOH_API_RC sdioh_gpioouten(sdioh_info_t *sd, uint32 gpio); +extern SDIOH_API_RC sdioh_gpioout(sdioh_info_t *sd, uint32 gpio, bool enab); + #endif /* _sdio_api_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh.h b/drivers/net/wireless/bcmdhd/include/bcmsdh.h index 6131d8ae430..def3c026927 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmsdh.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdh.h @@ -23,7 +23,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh.h,v 13.46.52.3 2010-10-19 00:41:44 Exp $ + * $Id: bcmsdh.h 300017 2011-12-01 20:30:27Z $ */ #ifndef _bcmsdh_h_ @@ -208,4 +208,12 @@ extern uint32 bcmsdh_cur_sbwad(void *sdh); extern void bcmsdh_chipinfo(void *sdh, uint32 chip, uint32 chiprev); +extern int bcmsdh_sleep(void *sdh, bool enab); + +/* GPIO support */ +extern int bcmsdh_gpio_init(void *sd); +extern bool bcmsdh_gpioin(void *sd, uint32 gpio); +extern int bcmsdh_gpioouten(void *sd, uint32 gpio); +extern int bcmsdh_gpioout(void *sd, uint32 gpio, bool enab); + #endif /* _bcmsdh_h_ */ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h index d188c4ec7d5..bea97b610a8 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_sdmmc.h,v 13.5.88.1 2010-12-23 01:13:20 Exp $ + * $Id: bcmsdh_sdmmc.h 277737 2011-08-16 17:54:59Z $ */ #ifndef __BCMSDH_SDMMC_H__ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h index ee29b5c08a5..1b9d39fee8f 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdpcm.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdpcm.h,v 13.4.90.2 2010-05-12 04:14:25 Exp $ + * $Id: bcmsdpcm.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _bcmsdpcm_h_ diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdspi.h b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h index 0bff355f8ff..a62bee42b2b 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmsdspi.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdspi.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdspi.h,v 13.11.86.1 2010-11-15 18:14:56 Exp $ + * $Id: bcmsdspi.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _BCM_SD_SPI_H #define _BCM_SD_SPI_H diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h index 0f4c0267dbc..c14444c57d3 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmsdstd.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdstd.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdstd.h,v 13.21.2.6 2010-11-15 18:14:01 Exp $ + * $Id: bcmsdstd.h 281604 2011-09-02 18:58:49Z $ */ #ifndef _BCM_SD_STD_H #define _BCM_SD_STD_H @@ -78,6 +78,7 @@ extern void sdstd_osfree(sdioh_info_t *sd); #define SDIOH_CMD7_EXP_STATUS 0x00001E00 #define RETRIES_LARGE 100000 +#define sdstd_os_yield(sd) do {} while (0) #define RETRIES_SMALL 100 @@ -148,8 +149,8 @@ struct sdioh_info { bool got_hcint; /* local interrupt flag */ uint16 last_intrstatus; /* to cache intrstatus */ int host_UHSISupported; /* whether UHSI is supported for HC. */ - int card_UHSI_voltage_Supported; /* whether UHSI is supported for - * Card in terms of Voltage [1.8 or 3.3]. + int card_UHSI_voltage_Supported; /* whether UHSI is supported for + * Card in terms of Voltage [1.8 or 3.3]. */ int global_UHSI_Supp; /* type of UHSI support in both host and card. * HOST_SDR_UNSUPP: capabilities not supported/matched @@ -171,21 +172,6 @@ struct sdioh_info { #define USE_DMA(sd) ((bool)((sd->sd_dma_mode > 0) ? TRUE : FALSE)) -/* SDIO Host Control Register DMA Mode Definitions */ -#define SDIOH_SDMA_MODE 0 -#define SDIOH_ADMA1_MODE 1 -#define SDIOH_ADMA2_MODE 2 -#define SDIOH_ADMA2_64_MODE 3 - -#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */ -#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */ -#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */ -#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */ -#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */ -#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */ -#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */ -#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */ - /* States for Tuning and corr data */ #define TUNING_IDLE 0 #define TUNING_START 1 @@ -195,17 +181,6 @@ struct sdioh_info { #define DATA_TRANSFER_IDLE 0 #define DATA_TRANSFER_ONGOING 1 -/* ADMA2 Descriptor Table Entry for 32-bit Address */ -typedef struct adma2_dscr_32b { - uint32 len_attr; - uint32 phys_addr; -} adma2_dscr_32b_t; - -/* ADMA1 Descriptor Table Entry */ -typedef struct adma1_dscr { - uint32 phys_addr_attr; -} adma1_dscr_t; - /************************************************************ * Internal interfaces: per-port references into bcmsdstd.c */ @@ -254,6 +229,7 @@ extern void sdstd_3_disable_retuning_int(sdioh_info_t *sd); extern bool sdstd_3_is_retuning_int_set(sdioh_info_t *sd); extern bool sdstd_3_check_and_set_retuning(sdioh_info_t *sd); extern int sdstd_3_get_tune_state(sdioh_info_t *sd); +extern int sdstd_3_get_data_state(sdioh_info_t *sd); extern void sdstd_3_set_tune_state(sdioh_info_t *sd, int state); extern uint8 sdstd_3_get_tuning_exp(sdioh_info_t *sd); extern uint32 sdstd_3_get_uhsi_clkmode(sdioh_info_t *sd); diff --git a/drivers/net/wireless/bcmdhd/include/bcmspi.h b/drivers/net/wireless/bcmdhd/include/bcmspi.h index 0eb2a30c9a8..34a02d00c6b 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmspi.h +++ b/drivers/net/wireless/bcmdhd/include/bcmspi.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmspi.h,v 13.5.112.1 2010-11-15 18:13:09 Exp $ + * $Id: bcmspi.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _BCM_SPI_H #define _BCM_SPI_H diff --git a/drivers/net/wireless/bcmdhd/include/bcmutils.h b/drivers/net/wireless/bcmdhd/include/bcmutils.h index 530036f0ba7..6849c26da83 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmutils.h +++ b/drivers/net/wireless/bcmdhd/include/bcmutils.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmutils.h,v 13.236.2.16 2011-01-26 00:45:06 Exp $ + * $Id: bcmutils.h 294991 2011-11-09 00:17:28Z $ */ @@ -221,7 +221,9 @@ extern uint16 pktpool_avail(pktpool_t *pktp); extern int pktpool_avail_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); extern int pktpool_empty_register(pktpool_t *pktp, pktpool_cb_t cb, void *arg); extern int pktpool_setmaxlen(pktpool_t *pktp, uint16 maxlen); +extern int pktpool_setmaxlen_strict(osl_t *osh, pktpool_t *pktp, uint16 maxlen); extern void pktpool_emptycb_disable(pktpool_t *pktp, bool disable); +extern bool pktpool_emptycb_disabled(pktpool_t *pktp); #define POOLPTR(pp) ((pktpool_t *)(pp)) #define pktpool_len(pp) (POOLPTR(pp)->len - 1) @@ -330,6 +332,8 @@ extern char *bcm_ip_ntoa(struct ipv4_addr *ia, char *buf); extern void bcm_mdelay(uint ms); +#define NVRAM_RECLAIM_CHECK(name) + extern char *getvar(char *vars, const char *name); extern int getintvar(char *vars, const char *name); extern int getintvararray(char *vars, const char *name, int index); @@ -534,9 +538,17 @@ extern int bcm_format_ssid(char* buf, const uchar ssid[], uint ssid_len); & ~((boundary) - 1)) #define ISPOWEROF2(x) ((((x)-1)&(x)) == 0) #define VALID_MASK(mask) !((mask) & ((mask) + 1)) + #ifndef OFFSETOF +#ifdef __ARMCC_VERSION + +#include +#define OFFSETOF(type, member) offsetof(type, member) +#else #define OFFSETOF(type, member) ((uint)(uintptr)&((type *)0)->member) #endif +#endif + #ifndef ARRAYSIZE #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) #endif diff --git a/drivers/net/wireless/bcmdhd/include/bcmwifi.h b/drivers/net/wireless/bcmdhd/include/bcmwifi.h index 45f3c0312dc..e5207e9c408 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmwifi.h +++ b/drivers/net/wireless/bcmdhd/include/bcmwifi.h @@ -23,7 +23,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmwifi.h,v 1.29.6.3 2010-08-03 17:47:04 Exp $ + * $Id: bcmwifi.h 277737 2011-08-16 17:54:59Z $ */ diff --git a/drivers/net/wireless/bcmdhd/include/dhdioctl.h b/drivers/net/wireless/bcmdhd/include/dhdioctl.h index 9661dac2603..3f3755b53b0 100644 --- a/drivers/net/wireless/bcmdhd/include/dhdioctl.h +++ b/drivers/net/wireless/bcmdhd/include/dhdioctl.h @@ -25,7 +25,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhdioctl.h,v 13.11.10.1 2010-12-22 23:47:26 Exp $ + * $Id: dhdioctl.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _dhdioctl_h_ diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index fe71e166a7d..41a078c42a0 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -19,7 +19,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: epivers.h.in,v 13.32.4.1 2010-09-17 00:39:18 $ + * $Id: epivers.h.in 277737 2011-08-16 17:54:59Z $ * */ @@ -31,19 +31,19 @@ #define EPI_MINOR_VERSION 90 -#define EPI_RC_NUMBER 125 +#define EPI_RC_NUMBER 195 -#define EPI_INCREMENTAL_NUMBER 94 +#define EPI_INCREMENTAL_NUMBER 15 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 5, 90, 125, 94 +#define EPI_VERSION 5, 90, 195, 15 -#define EPI_VERSION_NUM 0x055a7d5e +#define EPI_VERSION_NUM 0x055ac30f -#define EPI_VERSION_DEV 5.90.125 +#define EPI_VERSION_DEV 5.90.195 -#define EPI_VERSION_STR "5.90.125.94.1" +#define EPI_VERSION_STR "5.90.195.15" #endif diff --git a/drivers/net/wireless/bcmdhd/include/hndpmu.h b/drivers/net/wireless/bcmdhd/include/hndpmu.h index 51c51b9734a..69a834c6b7e 100644 --- a/drivers/net/wireless/bcmdhd/include/hndpmu.h +++ b/drivers/net/wireless/bcmdhd/include/hndpmu.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: hndpmu.h,v 13.35.8.5 2011-02-11 00:56:32 Exp $ + * $Id: hndpmu.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _hndpmu_h_ diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h b/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h index 8b9615c35f3..7d862c4deb2 100644 --- a/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h +++ b/drivers/net/wireless/bcmdhd/include/hndrte_armtrap.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: hndrte_armtrap.h,v 13.4.14.1 2011-02-05 00:04:30 Exp $ + * $Id: hndrte_armtrap.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _hndrte_armtrap_h diff --git a/drivers/net/wireless/bcmdhd/include/hndrte_cons.h b/drivers/net/wireless/bcmdhd/include/hndrte_cons.h index b9ede53af70..859ddc8953a 100644 --- a/drivers/net/wireless/bcmdhd/include/hndrte_cons.h +++ b/drivers/net/wireless/bcmdhd/include/hndrte_cons.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: hndrte_cons.h,v 13.4.10.4 2011-02-05 00:08:20 Exp $ + * $Id: hndrte_cons.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _HNDRTE_CONS_H diff --git a/drivers/net/wireless/bcmdhd/include/hndsoc.h b/drivers/net/wireless/bcmdhd/include/hndsoc.h index 4e26121c388..34f927c6af8 100644 --- a/drivers/net/wireless/bcmdhd/include/hndsoc.h +++ b/drivers/net/wireless/bcmdhd/include/hndsoc.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: hndsoc.h,v 13.11 2009-12-03 23:52:31 Exp $ + * $Id: hndsoc.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _HNDSOC_H diff --git a/drivers/net/wireless/bcmdhd/include/htsf.h b/drivers/net/wireless/bcmdhd/include/htsf.h index 379fbbe37db..d875edb816c 100644 --- a/drivers/net/wireless/bcmdhd/include/htsf.h +++ b/drivers/net/wireless/bcmdhd/include/htsf.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: htsf.h,v 1.1.2.4 2011-01-21 08:27:03 Exp $ + * $Id: htsf.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _HTSF_H_ #define _HTSF_H_ diff --git a/drivers/net/wireless/bcmdhd/include/linux_osl.h b/drivers/net/wireless/bcmdhd/include/linux_osl.h index 38de2982f13..830d351d882 100644 --- a/drivers/net/wireless/bcmdhd/include/linux_osl.h +++ b/drivers/net/wireless/bcmdhd/include/linux_osl.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: linux_osl.h,v 13.158.6.3 2010-12-22 23:47:26 Exp $ + * $Id: linux_osl.h 301794 2011-12-08 20:41:35Z $ */ diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h index 96844db2f05..e5189821b4c 100644 --- a/drivers/net/wireless/bcmdhd/include/linuxver.h +++ b/drivers/net/wireless/bcmdhd/include/linuxver.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: linuxver.h,v 13.53.2.2 2010-12-22 23:47:26 Exp $ + * $Id: linuxver.h 280266 2011-08-28 04:18:20Z $ */ @@ -482,7 +482,11 @@ typedef struct { #define DBG_THR(x) #endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define SMP_RD_BARRIER_DEPENDS(x) smp_read_barrier_depends(x) +#else #define SMP_RD_BARRIER_DEPENDS(x) smp_rmb(x) +#endif #define PROC_START(thread_func, owner, tsk_ctl, flags) \ diff --git a/drivers/net/wireless/bcmdhd/include/miniopt.h b/drivers/net/wireless/bcmdhd/include/miniopt.h index f468420f534..77eace6252d 100644 --- a/drivers/net/wireless/bcmdhd/include/miniopt.h +++ b/drivers/net/wireless/bcmdhd/include/miniopt.h @@ -20,7 +20,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. - * $Id: miniopt.h,v 1.3 2009-01-15 00:06:54 Exp $ + * $Id: miniopt.h 277737 2011-08-16 17:54:59Z $ */ diff --git a/drivers/net/wireless/bcmdhd/include/msgtrace.h b/drivers/net/wireless/bcmdhd/include/msgtrace.h index 721d42100f2..088f1e845a4 100644 --- a/drivers/net/wireless/bcmdhd/include/msgtrace.h +++ b/drivers/net/wireless/bcmdhd/include/msgtrace.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: msgtrace.h,v 1.4 2009-04-10 04:15:32 Exp $ + * $Id: msgtrace.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _MSGTRACE_H diff --git a/drivers/net/wireless/bcmdhd/include/osl.h b/drivers/net/wireless/bcmdhd/include/osl.h index 80248ee7604..b8cc2569f50 100644 --- a/drivers/net/wireless/bcmdhd/include/osl.h +++ b/drivers/net/wireless/bcmdhd/include/osl.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: osl.h,v 13.44.96.1 2010-05-20 11:09:18 Exp $ + * $Id: osl.h 277737 2011-08-16 17:54:59Z $ */ diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_end.h b/drivers/net/wireless/bcmdhd/include/packed_section_end.h index 5d4a8767807..71f8b2e13b3 100644 --- a/drivers/net/wireless/bcmdhd/include/packed_section_end.h +++ b/drivers/net/wireless/bcmdhd/include/packed_section_end.h @@ -34,7 +34,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. - * $Id: packed_section_end.h,v 1.4 2008-12-09 23:43:22 Exp $ + * $Id: packed_section_end.h 277737 2011-08-16 17:54:59Z $ */ diff --git a/drivers/net/wireless/bcmdhd/include/packed_section_start.h b/drivers/net/wireless/bcmdhd/include/packed_section_start.h index da2fed68afa..afc2ba32fd9 100644 --- a/drivers/net/wireless/bcmdhd/include/packed_section_start.h +++ b/drivers/net/wireless/bcmdhd/include/packed_section_start.h @@ -34,7 +34,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. - * $Id: packed_section_start.h,v 1.4.124.1 2010-09-17 00:47:03 Exp $ + * $Id: packed_section_start.h 277737 2011-08-16 17:54:59Z $ */ diff --git a/drivers/net/wireless/bcmdhd/include/pcicfg.h b/drivers/net/wireless/bcmdhd/include/pcicfg.h index fae063a72f1..66199431fb9 100644 --- a/drivers/net/wireless/bcmdhd/include/pcicfg.h +++ b/drivers/net/wireless/bcmdhd/include/pcicfg.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: pcicfg.h,v 1.50 2009-12-07 21:56:06 Exp $ + * $Id: pcicfg.h 277737 2011-08-16 17:54:59Z $ */ @@ -39,6 +39,19 @@ #define PCI_INT_MASK 0x94 #define PCIE_EXTCFG_OFFSET 0x100 +#define PCI_SPROM_CONTROL 0x88 +#define PCI_BAR1_CONTROL 0x8c +#define PCI_TO_SB_MB 0x98 +#define PCI_BACKPLANE_ADDR 0xa0 +#define PCI_BACKPLANE_DATA 0xa4 +#define PCI_CLK_CTL_ST 0xa8 +#define PCI_BAR0_WIN2 0xac +#define PCI_GPIO_IN 0xb0 +#define PCI_GPIO_OUT 0xb4 +#define PCI_GPIO_OUTEN 0xb8 + +#define PCI_BAR0_SHADOW_OFFSET (2 * 1024) +#define PCI_BAR0_SPROM_OFFSET (4 * 1024) #define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) #define PCI_BAR0_PCISBR_OFFSET (4 * 1024) @@ -49,4 +62,17 @@ #define PCI_16KB0_CCREGS_OFFSET (12 * 1024) #define PCI_16KBB0_WINSZ (16 * 1024) + +#define PCI_16KB0_WIN2_OFFSET (4 * 1024) + + + +#define SPROM_SZ_MSK 0x02 +#define SPROM_LOCKED 0x08 +#define SPROM_BLANK 0x04 +#define SPROM_WRITEEN 0x10 +#define SPROM_BOOTROM_WE 0x20 +#define SPROM_BACKPLANE_EN 0x40 +#define SPROM_OTPIN_USE 0x80 + #endif diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11.h b/drivers/net/wireless/bcmdhd/include/proto/802.11.h index 2342cb38314..8850b2ded23 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/802.11.h +++ b/drivers/net/wireless/bcmdhd/include/proto/802.11.h @@ -21,7 +21,7 @@ * * Fundamental types and constants relating to 802.11 * - * $Id: 802.11.h,v 9.260.2.6 2010-12-15 21:41:14 Exp $ + * $Id: 802.11.h 289520 2011-10-13 04:44:55Z $ */ @@ -429,10 +429,26 @@ typedef struct dot11_obss_chanlist dot11_obss_chanlist_t; BWL_PRE_PACKED_STRUCT struct dot11_extcap_ie { uint8 id; uint8 len; - uint8 cap; + uint8 cap[1]; } BWL_POST_PACKED_STRUCT; typedef struct dot11_extcap_ie dot11_extcap_ie_t; #define DOT11_EXTCAP_LEN 1 +#define DOT11_EXTCAP_LEN_TDLS 5 + +BWL_PRE_PACKED_STRUCT struct dot11_extcap { + uint8 extcap[DOT11_EXTCAP_LEN_TDLS]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_extcap dot11_extcap_t; + + +#define TDLS_CAP_TDLS 37 +#define TDLS_CAP_PU_BUFFER_STA 28 +#define TDLS_CAP_PEER_PSM 20 +#define TDLS_CAP_CH_SW 30 +#define TDLS_CAP_PROH 38 +#define TDLS_CAP_CH_SW_PROH 39 + +#define TDLS_CAP_MAX_BIT 39 @@ -545,6 +561,9 @@ typedef struct dot11_ibss_dfs dot11_ibss_dfs_t; #define WME_SUBTYPE_IE 0 #define WME_SUBTYPE_PARAM_IE 1 #define WME_SUBTYPE_TSPEC 2 +#define WME_VERSION_LEN 1 +#define WME_PARAMETER_IE_LEN 24 + #define AC_BE 0 @@ -709,6 +728,15 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification { #define DOT11_MGMT_NOTIFICATION_LEN 4 +BWL_PRE_PACKED_STRUCT struct ti_ie { + uint8 ti_type; + uint32 ti_val; +} BWL_POST_PACKED_STRUCT; +typedef struct ti_ie ti_ie_t; +#define TI_TYPE_REASSOC_DEADLINE 1 +#define TI_TYPE_KEY_LIFETIME 2 + + #define WME_ADDTS_REQUEST 0 #define WME_ADDTS_RESPONSE 1 #define WME_DELTS_REQUEST 2 @@ -724,8 +752,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification { #define DOT11_OPEN_SYSTEM 0 #define DOT11_SHARED_KEY 1 -#define DOT11_OPEN_SHARED 2 -#define DOT11_FAST_BSS 3 +#define DOT11_FAST_BSS 2 #define DOT11_CHALLENGE_LEN 128 @@ -926,9 +953,18 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification { #define DOT11_RC_MAX 23 +#define DOT11_RC_TDLS_PEER_UNREACH 25 +#define DOT11_RC_TDLS_DOWN_UNSPECIFIED 26 + #define DOT11_SC_SUCCESS 0 #define DOT11_SC_FAILURE 1 +#define DOT11_SC_TDLS_WAKEUP_SCH_ALT 2 + +#define DOT11_SC_TDLS_WAKEUP_SCH_REJ 3 +#define DOT11_SC_TDLS_SEC_DISABLED 5 +#define DOT11_SC_LIFETIME_REJ 6 +#define DOT11_SC_NOT_SAME_BSS 7 #define DOT11_SC_CAP_MISMATCH 10 #define DOT11_SC_REASSOC_FAIL 11 #define DOT11_SC_ASSOC_FAIL 12 @@ -947,13 +983,22 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification { #define DOT11_SC_ASSOC_SHORTSLOT_REQUIRED 25 #define DOT11_SC_ASSOC_ERPBCC_REQUIRED 26 #define DOT11_SC_ASSOC_DSSOFDM_REQUIRED 27 - -#define DOT11_SC_DECLINED 37 -#define DOT11_SC_INVALID_PARAMS 38 -#define DOT11_SC_INVALID_AKMP 43 -#define DOT11_SC_INVALID_MDID 54 -#define DOT11_SC_INVALID_FTIE 55 - +#define DOT11_SC_ASSOC_R0KH_UNREACHABLE 28 +#define DOT11_SC_ASSOC_TRY_LATER 30 +#define DOT11_SC_ASSOC_MFP_VIOLATION 31 + +#define DOT11_SC_DECLINED 37 +#define DOT11_SC_INVALID_PARAMS 38 +#define DOT11_SC_INVALID_PAIRWISE_CIPHER 42 +#define DOT11_SC_INVALID_AKMP 43 +#define DOT11_SC_INVALID_RSNIE_CAP 45 +#define DOT11_SC_INVALID_PMKID 53 +#define DOT11_SC_INVALID_MDID 54 +#define DOT11_SC_INVALID_FTIE 55 + +#define DOT11_SC_UNEXP_MSG 70 +#define DOT11_SC_INVALID_SNONCE 71 +#define DOT11_SC_INVALID_RSNIE 72 #define DOT11_MNG_DS_PARAM_LEN 1 #define DOT11_MNG_IBSS_PARAM_LEN 2 @@ -1008,6 +1053,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification { #define DOT11_MNG_MDIE_ID 54 #define DOT11_MNG_FTIE_ID 55 #define DOT11_MNG_FT_TI_ID 56 +#define DOT11_MNG_RDE_ID 57 #define DOT11_MNG_REGCLASS_ID 59 #define DOT11_MNG_EXT_CSA_ID 60 #define DOT11_MNG_HT_ADD 61 @@ -1018,7 +1064,13 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification { #define DOT11_MNG_HT_BSS_COEXINFO_ID 72 #define DOT11_MNG_HT_BSS_CHANNEL_REPORT_ID 73 #define DOT11_MNG_HT_OBSS_ID 74 -#define DOT11_MNG_EXT_CAP 127 +#define DOT11_MNG_CHANNEL_USAGE 97 +#define DOT11_MNG_LINK_IDENTIFIER_ID 101 +#define DOT11_MNG_WAKEUP_SCHEDULE_ID 102 +#define DOT11_MNG_CHANNEL_SWITCH_TIMING_ID 104 +#define DOT11_MNG_PTI_CONTROL_ID 105 +#define DOT11_MNG_PU_BUFFER_STATUS_ID 106 +#define DOT11_MNG_EXT_CAP_ID 127 #define DOT11_MNG_WPA_ID 221 #define DOT11_MNG_PROPR_ID 221 @@ -1070,8 +1122,14 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification { #define DOT11_ACTION_CAT_RRM 5 #define DOT11_ACTION_CAT_FBT 6 #define DOT11_ACTION_CAT_HT 7 +#if defined(MFP) || defined(WLFBT) || defined(WLWNM) +#define DOT11_ACTION_CAT_SA_QUERY 8 +#define DOT11_ACTION_CAT_PDPA 9 #define DOT11_ACTION_CAT_BSSMGMT 10 #define DOT11_ACTION_NOTIFICATION 17 +#define DOT11_ACTION_CAT_VSP 126 +#endif +#define DOT11_ACTION_NOTIFICATION 17 #define DOT11_ACTION_CAT_VS 127 @@ -1107,6 +1165,121 @@ BWL_PRE_PACKED_STRUCT struct dot11_management_notification { #define DOT11_ADDBA_POLICY_DELAYED 0 #define DOT11_ADDBA_POLICY_IMMEDIATE 1 + +#define DOT11_FT_ACTION_FT_RESERVED 0 +#define DOT11_FT_ACTION_FT_REQ 1 +#define DOT11_FT_ACTION_FT_RES 2 +#define DOT11_FT_ACTION_FT_CON 3 +#define DOT11_FT_ACTION_FT_ACK 4 + + + +#define DOT11_WNM_ACTION_EVENT_REQ 0 +#define DOT11_WNM_ACTION_EVENT_REP 1 +#define DOT11_WNM_ACTION_DIAG_REQ 2 +#define DOT11_WNM_ACTION_DIAG_REP 3 +#define DOT11_WNM_ACTION_LOC_CFG_REQ 4 +#define DOT11_WNM_ACTION_LOC_RFG_RESP 5 +#define DOT11_WNM_ACTION_BSS_TRANS_QURY 6 +#define DOT11_WNM_ACTION_BSS_TRANS_REQ 7 +#define DOT11_WNM_ACTION_BSS_TRANS_RESP 8 +#define DOT11_WNM_ACTION_FMS_REQ 9 +#define DOT11_WNM_ACTION_FMS_RESP 10 +#define DOT11_WNM_ACTION_COL_INTRFRNCE_REQ 11 +#define DOT11_WNM_ACTION_COL_INTRFRNCE_REP 12 +#define DOT11_WNM_ACTION_TFS_REQ 13 +#define DOT11_WNM_ACTION_TFS_RESP 14 +#define DOT11_WNM_ACTION_TFS_NOTIFY 15 +#define DOT11_WNM_ACTION_WNM_SLEEP_REQ 16 +#define DOT11_WNM_ACTION_WNM_SLEEP_RESP 17 +#define DOT11_WNM_ACTION_TIM_BCAST_REQ 18 +#define DOT11_WNM_ACTION_TIM_BCAST_RESP 19 +#define DOT11_WNM_ACTION_QOS_TRFC_CAP_UPD 20 +#define DOT11_WNM_ACTION_CHAN_USAGE_REQ 21 +#define DOT11_WNM_ACTION_CHAN_USAGE_RESP 22 +#define DOT11_WNM_ACTION_DMS_REQ 23 +#define DOT11_WNM_ACTION_DMS_RESP 24 +#define DOT11_WNM_ACTION_TMNG_MEASUR_REQ 25 +#define DOT11_WNM_ACTION_NOTFCTN_REQ 26 +#define DOT11_WNM_ACTION_NOTFCTN_RES 27 + + + +BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_query { + uint8 category; + uint8 action; + uint8 token; + uint8 reason; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bss_trans_query dot11_bss_trans_query_t; +#define DOT11_BSS_TRANS_QUERY_LEN 4 + + +BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_req { + uint8 category; + uint8 action; + uint8 token; + uint8 reqmode; + uint16 disassoc_tmr; + uint8 validity_intrvl; + uint8 data[1]; + +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bss_trans_req dot11_bss_trans_req_t; +#define DOT11_BSS_TRANS_REQ_LEN 7 + +#define DOT11_BSS_TERM_DUR_LEN 12 + + + +#define DOT11_BSS_TRNS_REQMODE_PREF_LIST_INCL 0x01 +#define DOT11_BSS_TRNS_REQMODE_ABRIDGED 0x02 +#define DOT11_BSS_TRNS_REQMODE_DISASSOC_IMMINENT 0x04 +#define DOT11_BSS_TRNS_REQMODE_BSS_TERM_INCL 0x08 +#define DOT11_BSS_TRNS_REQMODE_ESS_DISASSOC_IMNT 0x10 + + + +BWL_PRE_PACKED_STRUCT struct dot11_bss_trans_res { + uint8 category; + uint8 action; + uint8 token; + uint8 status; + uint8 term_delay; + uint8 data[1]; + +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_bss_trans_res dot11_bss_trans_res_t; +#define DOT11_BSS_TRANS_RES_LEN 5 + + +#define DOT11_BSS_TRNS_RES_STATUS_ACCEPT 0 +#define DOT11_BSS_TRNS_RES_STATUS_REJECT 1 +#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_BCN 2 +#define DOT11_BSS_TRNS_RES_STATUS_REJ_INSUFF_CAP 3 +#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_UNDESIRED 4 +#define DOT11_BSS_TRNS_RES_STATUS_REJ_TERM_DELAY_REQ 5 +#define DOT11_BSS_TRNS_RES_STATUS_REJ_BSS_LIST_PROVIDED 6 +#define DOT11_BSS_TRNS_RES_STATUS_REJ_NO_SUITABLE_BSS 7 +#define DOT11_BSS_TRNS_RES_STATUS_REJ_LEAVING_ESS 8 + + + +#define DOT11_NBR_RPRT_BSSID_INFO_REACHABILTY 0x0003 +#define DOT11_NBR_RPRT_BSSID_INFO_SEC 0x0004 +#define DOT11_NBR_RPRT_BSSID_INFO_KEY_SCOPE 0x0008 +#define DOT11_NBR_RPRT_BSSID_INFO_CAP 0x03f0 + +#define DOT11_NBR_RPRT_BSSID_INFO_CAP_SPEC_MGMT 0x0010 +#define DOT11_NBR_RPRT_BSSID_INFO_CAP_QOS 0x0020 +#define DOT11_NBR_RPRT_BSSID_INFO_CAP_APSD 0x0040 +#define DOT11_NBR_RPRT_BSSID_INFO_CAP_RDIO_MSMT 0x0080 +#define DOT11_NBR_RPRT_BSSID_INFO_CAP_DEL_BA 0x0100 +#define DOT11_NBR_RPRT_BSSID_INFO_CAP_IMM_BA 0x0200 + + +#define DOT11_NBR_RPRT_SUBELEM_BSS_CANDDT_PREF_ID 3 BWL_PRE_PACKED_STRUCT struct dot11_addba_req { uint8 category; uint8 action; @@ -1145,6 +1318,48 @@ typedef struct dot11_delba dot11_delba_t; #define DOT11_DELBA_LEN 6 +#define SA_QUERY_REQUEST 0 +#define SA_QUERY_RESPONSE 1 + + + + +BWL_PRE_PACKED_STRUCT struct dot11_ft_req { + uint8 category; + uint8 action; + uint8 sta_addr[ETHER_ADDR_LEN]; + uint8 tgt_ap_addr[ETHER_ADDR_LEN]; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_req dot11_ft_req_t; +#define DOT11_FT_REQ_FIXED_LEN 14 + + +BWL_PRE_PACKED_STRUCT struct dot11_ft_res { + uint8 category; + uint8 action; + uint8 sta_addr[ETHER_ADDR_LEN]; + uint8 tgt_ap_addr[ETHER_ADDR_LEN]; + uint16 status; + uint8 data[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ft_res dot11_ft_res_t; +#define DOT11_FT_RES_FIXED_LEN 16 + + +BWL_PRE_PACKED_STRUCT struct dot11_rde_ie { + uint8 id; + uint8 length; + uint8 rde_id; + uint8 rd_count; + uint16 status; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_rde_ie dot11_rde_ie_t; + + +#define DOT11_MNG_RDE_IE_LEN sizeof(dot11_rde_ie_t) + + @@ -1166,6 +1381,20 @@ typedef struct dot11_rrm_cap_ie dot11_rrm_cap_ie_t; #define DOT11_RRM_CAP_AP_CHANREP 16 + +#define DOT11_EXT_CAP_LEN 4 +BWL_PRE_PACKED_STRUCT struct dot11_ext_cap_ie { + uint8 cap[DOT11_EXT_CAP_LEN]; +} BWL_POST_PACKED_STRUCT; +typedef struct dot11_ext_cap_ie dot11_ext_cap_ie_t; + + +#define DOT11_EXT_CAP_BSS_TRANSITION_MGMT 19 + + +#define DOT11_OP_CLASS_NONE 255 + + #define DOT11_RM_ACTION_RM_REQ 0 #define DOT11_RM_ACTION_RM_REP 1 #define DOT11_RM_ACTION_LM_REQ 2 @@ -1272,6 +1501,7 @@ BWL_PRE_PACKED_STRUCT struct dot11_rmrep_nbr { uint8 reg; uint8 channel; uint8 phytype; + uchar sub_elements[1]; } BWL_POST_PACKED_STRUCT; typedef struct dot11_rmrep_nbr dot11_rmrep_nbr_t; #define DOT11_RMREP_NBR_LEN 13 @@ -1660,6 +1890,9 @@ typedef struct dot11_obss_ie dot11_obss_ie_t; #define RSN_AKM_PSK 2 #define RSN_AKM_FBT_1X 3 #define RSN_AKM_FBT_PSK 4 +#define RSN_AKM_MFP_1X 5 +#define RSN_AKM_MFP_PSK 6 +#define RSN_AKM_TPK 7 #define DOT11_MAX_DEFAULT_KEYS 4 @@ -1724,6 +1957,66 @@ BWL_PRE_PACKED_STRUCT struct dot11_gtk_ie { } BWL_POST_PACKED_STRUCT; typedef struct dot11_gtk_ie dot11_gtk_ie_t; +#define BSSID_INVALID "\x00\x00\x00\x00\x00\x00" +#define BSSID_BROADCAST "\xFF\xFF\xFF\xFF\xFF\xFF" + + + +BWL_PRE_PACKED_STRUCT struct link_id_ie { + uint8 id; + uint8 len; + struct ether_addr bssid; + struct ether_addr tdls_init_mac; + struct ether_addr tdls_resp_mac; +} BWL_POST_PACKED_STRUCT; +typedef struct link_id_ie link_id_ie_t; +#define TDLS_LINK_ID_IE_LEN 18 + + +BWL_PRE_PACKED_STRUCT struct wakeup_sch_ie { + uint8 id; + uint8 len; + uint32 offset; + uint32 interval; + uint32 awake_win_slots; + uint32 max_wake_win; + uint16 idle_cnt; +} BWL_POST_PACKED_STRUCT; +typedef struct wakeup_sch_ie wakeup_sch_ie_t; +#define TDLS_WAKEUP_SCH_IE_LEN 18 + + +BWL_PRE_PACKED_STRUCT struct channel_switch_timing_ie { + uint8 id; + uint8 len; + uint16 switch_time; + uint16 switch_timeout; +} BWL_POST_PACKED_STRUCT; +typedef struct channel_switch_timing_ie channel_switch_timing_ie_t; +#define TDLS_CHANNEL_SWITCH_TIMING_IE_LEN 4 + + +BWL_PRE_PACKED_STRUCT struct pti_control_ie { + uint8 id; + uint8 len; + uint8 tid; + uint16 seq_control; +} BWL_POST_PACKED_STRUCT; +typedef struct pti_control_ie pti_control_ie_t; +#define TDLS_PTI_CONTROL_IE_LEN 3 + + +BWL_PRE_PACKED_STRUCT struct pu_buffer_status_ie { + uint8 id; + uint8 len; + uint8 status; +} BWL_POST_PACKED_STRUCT; +typedef struct pu_buffer_status_ie pu_buffer_status_ie_t; +#define TDLS_PU_BUFFER_STATUS_IE_LEN 1 +#define TDLS_PU_BUFFER_STATUS_AC_BK 1 +#define TDLS_PU_BUFFER_STATUS_AC_BE 2 +#define TDLS_PU_BUFFER_STATUS_AC_VI 4 +#define TDLS_PU_BUFFER_STATUS_AC_VO 8 #include diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h index 4ccfab02056..cbdd05e624b 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h +++ b/drivers/net/wireless/bcmdhd/include/proto/802.11_bta.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: 802.11_bta.h,v 9.2 2008-10-28 23:27:13 Exp $ + * $Id: 802.11_bta.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _802_11_BTA_H_ diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h index ce8ad083f28..0e070a475b6 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/802.11e.h +++ b/drivers/net/wireless/bcmdhd/include/proto/802.11e.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: 802.11e.h,v 1.6 2008-12-01 22:55:11 Exp $ + * $Id: 802.11e.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _802_11e_H_ diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.1d.h b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h index cf206250246..c7e07bd5e7c 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/802.1d.h +++ b/drivers/net/wireless/bcmdhd/include/proto/802.1d.h @@ -21,7 +21,7 @@ * * Fundamental types and constants relating to 802.1D * - * $Id: 802.1d.h,v 9.3 2007-04-10 21:33:06 Exp $ + * $Id: 802.1d.h 277737 2011-08-16 17:54:59Z $ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h index 46fa4c9f89e..0f75d3c8f1d 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h +++ b/drivers/net/wireless/bcmdhd/include/proto/bcmeth.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmeth.h,v 9.12 2009-12-29 19:57:18 Exp $ + * $Id: bcmeth.h 277737 2011-08-16 17:54:59Z $ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h index 30ec848c40a..e8c2387dd10 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h +++ b/drivers/net/wireless/bcmdhd/include/proto/bcmevent.h @@ -23,7 +23,7 @@ * * Dependencies: proto/bcmeth.h * - * $Id: bcmevent.h,v 9.64.2.9 2011-02-01 06:24:21 Exp $ + * $Id: bcmevent.h 288077 2011-10-06 00:08:47Z $ * */ @@ -182,7 +182,10 @@ typedef BWL_PRE_PACKED_STRUCT struct bcm_event { #define WLC_E_PFN_SCAN_NONE 82 #define WLC_E_PFN_SCAN_ALLGONE 83 #define WLC_E_GTK_PLUMBED 84 -#define WLC_E_LAST 85 +#define WLC_E_ASSOC_REQ_IE 85 +#define WLC_E_ASSOC_RESP_IE 86 +#define WLC_E_LAST 87 + typedef struct { @@ -226,6 +229,8 @@ extern const int bcmevent_names_size; #define WLC_E_REASON_TSPEC_REJECTED 7 #define WLC_E_REASON_BETTER_AP 8 +#define WLC_E_REASON_REQUESTED_ROAM 11 + #define WLC_E_PRUNE_ENCR_MISMATCH 1 #define WLC_E_PRUNE_BCAST_BSSID 2 diff --git a/drivers/net/wireless/bcmdhd/include/proto/bcmip.h b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h index 8a8f3146d56..55eff247c49 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/bcmip.h +++ b/drivers/net/wireless/bcmdhd/include/proto/bcmip.h @@ -21,7 +21,7 @@ * * Fundamental constants relating to IP Protocol * - * $Id: bcmip.h,v 9.19 2009-11-10 20:08:33 Exp $ + * $Id: bcmip.h 277737 2011-08-16 17:54:59Z $ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h index 89c11817915..91ab4fe538f 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h +++ b/drivers/net/wireless/bcmdhd/include/proto/bt_amp_hci.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bt_amp_hci.h,v 9.14.8.2 2010-09-10 18:37:47 Exp $ + * $Id: bt_amp_hci.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _bt_amp_hci_h diff --git a/drivers/net/wireless/bcmdhd/include/proto/eapol.h b/drivers/net/wireless/bcmdhd/include/proto/eapol.h index 5781d1312e3..92634c1221a 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/eapol.h +++ b/drivers/net/wireless/bcmdhd/include/proto/eapol.h @@ -7,7 +7,7 @@ * * Copyright (C) 2002 Broadcom Corporation * - * $Id: eapol.h,v 9.23.86.1 2010-09-02 18:09:39 Exp $ + * $Id: eapol.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _eapol_h_ diff --git a/drivers/net/wireless/bcmdhd/include/proto/ethernet.h b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h index 6a6dd14c1bb..20865dc5a23 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/ethernet.h +++ b/drivers/net/wireless/bcmdhd/include/proto/ethernet.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: ethernet.h,v 9.56 2009-10-15 22:54:58 Exp $ + * $Id: ethernet.h 285437 2011-09-21 22:16:56Z $ */ @@ -69,6 +69,7 @@ #define ETHER_TYPE_802_1X 0x888e #define ETHER_TYPE_802_1X_PREAUTH 0x88c7 #define ETHER_TYPE_WAI 0x88b4 +#define ETHER_TYPE_89_0D 0x890d diff --git a/drivers/net/wireless/bcmdhd/include/proto/p2p.h b/drivers/net/wireless/bcmdhd/include/proto/p2p.h index 4a0c9d1ddc3..d2bf3f20688 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/p2p.h +++ b/drivers/net/wireless/bcmdhd/include/proto/p2p.h @@ -21,7 +21,7 @@ * * Fundamental types and constants relating to WFA P2P (aka WiFi Direct) * - * $Id: p2p.h,v 9.17.2.4 2010-12-15 21:41:21 Exp $ + * $Id: p2p.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _P2P_H_ diff --git a/drivers/net/wireless/bcmdhd/include/proto/sdspi.h b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h index 7fe4fbce310..7353ff0d7c7 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/sdspi.h +++ b/drivers/net/wireless/bcmdhd/include/proto/sdspi.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: sdspi.h,v 9.2.120.1 2010-11-15 17:56:25 Exp $ + * $Id: sdspi.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _SD_SPI_H diff --git a/drivers/net/wireless/bcmdhd/include/proto/vlan.h b/drivers/net/wireless/bcmdhd/include/proto/vlan.h index 07fa7e499c2..27f00553760 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/vlan.h +++ b/drivers/net/wireless/bcmdhd/include/proto/vlan.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: vlan.h,v 9.7 2009-03-13 01:11:50 Exp $ + * $Id: vlan.h 277737 2011-08-16 17:54:59Z $ */ diff --git a/drivers/net/wireless/bcmdhd/include/proto/wpa.h b/drivers/net/wireless/bcmdhd/include/proto/wpa.h index 1ff06dc7942..7361cbf20b0 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/wpa.h +++ b/drivers/net/wireless/bcmdhd/include/proto/wpa.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wpa.h,v 1.19 2009-07-13 08:29:58 Exp $ + * $Id: wpa.h 285437 2011-09-21 22:16:56Z $ */ @@ -114,6 +114,8 @@ typedef BWL_PRE_PACKED_STRUCT struct #define WPA_CIPHER_AES_OCB 3 #define WPA_CIPHER_AES_CCM 4 #define WPA_CIPHER_WEP_104 5 +#define WPA_CIPHER_BIP 6 +#define WPA_CIPHER_TPK 7 #define IS_WPA_CIPHER(cipher) ((cipher) == WPA_CIPHER_NONE || \ @@ -121,7 +123,9 @@ typedef BWL_PRE_PACKED_STRUCT struct (cipher) == WPA_CIPHER_WEP_104 || \ (cipher) == WPA_CIPHER_TKIP || \ (cipher) == WPA_CIPHER_AES_OCB || \ - (cipher) == WPA_CIPHER_AES_CCM) + (cipher) == WPA_CIPHER_AES_CCM || \ + (cipher) == WPA_CIPHER_TPK) + #define WPA_TKIP_CM_DETECT 60 @@ -149,7 +153,11 @@ typedef BWL_PRE_PACKED_STRUCT struct #define WPA_CAP_REPLAY_CNTR_MASK RSN_CAP_PTK_REPLAY_CNTR_MASK +#define WPA_CAP_PEER_KEY_ENABLE (0x1 << 1) + + #define WPA_CAP_LEN RSN_CAP_LEN +#define WPA_PMKID_CNT_LEN 2 #define WPA_CAP_WPA2_PREAUTH RSN_CAP_PREAUTH diff --git a/drivers/net/wireless/bcmdhd/include/sbchipc.h b/drivers/net/wireless/bcmdhd/include/sbchipc.h index cbd37490f1c..3fe2a5a49d3 100644 --- a/drivers/net/wireless/bcmdhd/include/sbchipc.h +++ b/drivers/net/wireless/bcmdhd/include/sbchipc.h @@ -5,7 +5,7 @@ * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer, * GPIO interface, extbus, and support for serial and parallel flashes. * - * $Id: sbchipc.h,v 13.169.2.14 2011-02-10 23:43:55 Exp $ + * $Id: sbchipc.h 277737 2011-08-16 17:54:59Z $ * * Copyright (C) 1999-2011, Broadcom Corporation * @@ -41,6 +41,50 @@ #define PAD _XSTR(__LINE__) #endif +typedef struct eci_prerev35 { + uint32 eci_output; + uint32 eci_control; + uint32 eci_inputlo; + uint32 eci_inputmi; + uint32 eci_inputhi; + uint32 eci_inputintpolaritylo; + uint32 eci_inputintpolaritymi; + uint32 eci_inputintpolarityhi; + uint32 eci_intmasklo; + uint32 eci_intmaskmi; + uint32 eci_intmaskhi; + uint32 eci_eventlo; + uint32 eci_eventmi; + uint32 eci_eventhi; + uint32 eci_eventmasklo; + uint32 eci_eventmaskmi; + uint32 eci_eventmaskhi; + uint32 PAD[3]; +} eci_prerev35_t; + +typedef struct eci_rev35 { + uint32 eci_outputlo; + uint32 eci_outputhi; + uint32 eci_controllo; + uint32 eci_controlhi; + uint32 eci_inputlo; + uint32 eci_inputhi; + uint32 eci_inputintpolaritylo; + uint32 eci_inputintpolarityhi; + uint32 eci_intmasklo; + uint32 eci_intmaskhi; + uint32 eci_eventlo; + uint32 eci_eventhi; + uint32 eci_eventmasklo; + uint32 eci_eventmaskhi; + uint32 eci_auxtx; + uint32 eci_auxrx; + uint32 eci_datatag; + uint32 eci_uartescvalue; + uint32 eci_autobaudctr; + uint32 eci_uartfifolevel; +} eci_rev35_t; + typedef volatile struct { uint32 chipid; uint32 capabilities; @@ -153,10 +197,26 @@ typedef volatile struct { uint32 prog_waitcount; uint32 flash_config; uint32 flash_waitcount; - uint32 PAD[4]; - uint32 PAD[40]; + uint32 SECI_config; + uint32 SECI_status; + uint32 SECI_statusmask; + uint32 SECI_rxnibchanged; + + uint32 PAD[20]; + uint32 sromcontrol; + uint32 sromaddress; + uint32 sromdata; + uint32 PAD[9]; + uint32 seci_uart_data; + uint32 seci_uart_bauddiv; + uint32 seci_uart_fcr; + uint32 seci_uart_lcr; + uint32 seci_uart_mcr; + uint32 seci_uart_lsr; + uint32 seci_uart_msr; + uint32 seci_uart_baudadj; uint32 clk_ctl_st; uint32 hw_war; @@ -1332,9 +1392,27 @@ typedef volatile struct { #define CST43237_BOOT_FROM_INVALID 3 +#define RES43239_CBUCK_LPOM 0 +#define RES43239_CBUCK_BURST 1 +#define RES43239_CBUCK_LP_PWM 2 +#define RES43239_CBUCK_PWM 3 +#define RES43239_CLDO_PU 4 +#define RES43239_DIS_INT_RESET_PD 5 +#define RES43239_ILP_REQUEST 6 +#define RES43239_LNLDO_PU 7 +#define RES43239_LDO3P3_PU 8 #define RES43239_OTP_PU 9 +#define RES43239_XTAL_PU 10 +#define RES43239_ALP_AVAIL 11 +#define RES43239_RADIO_PU 12 #define RES43239_MACPHY_CLKAVAIL 23 #define RES43239_HT_AVAIL 24 +#define RES43239_XOLDO_PU 25 +#define RES43239_WL_XTAL_CTL_SEL 26 +#define RES43239_SR_CLK_STABLE 27 +#define RES43239_SR_SAVE_RESTORE 28 +#define RES43239_SR_PHY_PIC 29 +#define RES43239_SR_PHY_PWR_SW 30 #define CST43239_SPROM_MASK 0x00000002 @@ -1342,7 +1420,7 @@ typedef volatile struct { #define CST43239_RES_INIT_MODE_SHIFT 7 #define CST43239_RES_INIT_MODE_MASK 0x000001f0 #define CST43239_CHIPMODE_SDIOD(cs) ((cs) & (1 << 15)) -#define CST43239_CHIPMODE_USB20D(cs) ((cs) & !(1 << 15)) +#define CST43239_CHIPMODE_USB20D(cs) (~(cs) & (1 << 15)) #define CST43239_CHIPMODE_SDIO(cs) (((cs) & (1 << 0)) == 0) #define CST43239_CHIPMODE_GSPI(cs) (((cs) & (1 << 0)) == (1 << 0)) @@ -1350,6 +1428,40 @@ typedef volatile struct { #define CCTRL43239_XTAL_STRENGTH(ctl) ((ctl & 0x3F) << 12) +#define RES4331_REGULATOR 0 +#define RES4331_ILP_REQUEST 1 +#define RES4331_XTAL_PU 2 +#define RES4331_ALP_AVAIL 3 +#define RES4331_SI_PLL_ON 4 +#define RES4331_HT_SI_AVAIL 5 + + +#define CCTRL4331_BT_COEXIST (1<<0) +#define CCTRL4331_SECI (1<<1) +#define CCTRL4331_EXT_LNA_G (1<<2) +#define CCTRL4331_SPROM_GPIO13_15 (1<<3) +#define CCTRL4331_EXTPA_EN (1<<4) +#define CCTRL4331_GPIOCLK_ON_SPROMCS <1<<5) +#define CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6) +#define CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7) +#define CCTRL4331_OVR_PIPEAUXCLKEN (1<<8) +#define CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9) +#define CCTRL4331_PCIE_AUXCLKEN <1<<10) +#define CCTRL4331_PCIE_PIPE_PLLDOWN <1<<11) +#define CCTRL4331_EXTPA_EN2 (1<<12) +#define CCTRL4331_EXT_LNA_A (1<<13) +#define CCTRL4331_BT_SHD0_ON_GPIO4 <1<<16) +#define CCTRL4331_BT_SHD1_ON_GPIO5 <1<<17) +#define CCTRL4331_EXTPA_ANA_EN (1<<24) + + +#define CST4331_XTAL_FREQ 0x00000001 +#define CST4331_SPROM_OTP_SEL_MASK 0x00000006 +#define CST4331_SPROM_OTP_SEL_SHIFT 1 +#define CST4331_SPROM_PRESENT 0x00000002 +#define CST4331_OTP_PRESENT 0x00000004 +#define CST4331_LDO_RF 0x00000008 +#define CST4331_LDO_PAR 0x00000010 #define RES4315_CBUCK_LPOM 1 @@ -1597,6 +1709,54 @@ typedef volatile struct { +#define SECI_MODE_UART 0x0 +#define SECI_MODE_SECI 0x1 +#define SECI_MODE_LEGACY_3WIRE_BT 0x2 +#define SECI_MODE_LEGACY_3WIRE_WLAN 0x3 +#define SECI_MODE_HALF_SECI 0x4 + +#define SECI_RESET (1 << 0) +#define SECI_RESET_BAR_UART (1 << 1) +#define SECI_ENAB_SECI_ECI (1 << 2) +#define SECI_ENAB_SECIOUT_DIS (1 << 3) +#define SECI_MODE_MASK 0x7 +#define SECI_MODE_SHIFT 4 +#define SECI_UPD_SECI (1 << 7) + + +#define CLKCTL_STS_SECI_CLK_REQ (1 << 8) +#define CLKCTL_STS_SECI_CLK_AVAIL (1 << 24) + +#define SECI_UART_MSR_CTS_STATE (1 << 0) +#define SECI_UART_MSR_RTS_STATE (1 << 1) +#define SECI_UART_SECI_IN_STATE (1 << 2) +#define SECI_UART_SECI_IN2_STATE (1 << 3) + + +#define SECI_UART_LCR_STOP_BITS (1 << 0) +#define SECI_UART_LCR_PARITY_EN (1 << 1) +#define SECI_UART_LCR_PARITY (1 << 2) +#define SECI_UART_LCR_RX_EN (1 << 3) +#define SECI_UART_LCR_LBRK_CTRL (1 << 4) +#define SECI_UART_LCR_TXO_EN (1 << 5) +#define SECI_UART_LCR_RTSO_EN (1 << 6) +#define SECI_UART_LCR_SLIPMODE_EN (1 << 7) +#define SECI_UART_LCR_RXCRC_CHK (1 << 8) +#define SECI_UART_LCR_TXCRC_INV (1 << 9) +#define SECI_UART_LCR_TXCRC_LSBF (1 << 10) +#define SECI_UART_LCR_TXCRC_EN (1 << 11) + +#define SECI_UART_MCR_TX_EN (1 << 0) +#define SECI_UART_MCR_PRTS (1 << 1) +#define SECI_UART_MCR_SWFLCTRL_EN (1 << 2) +#define SECI_UART_MCR_HIGHRATE_EN (1 << 3) +#define SECI_UART_MCR_LOOPBK_EN (1 << 4) +#define SECI_UART_MCR_AUTO_RTS (1 << 5) +#define SECI_UART_MCR_AUTO_TX_DIS (1 << 6) +#define SECI_UART_MCR_BAUD_ADJ_EN (1 << 7) +#define SECI_UART_MCR_XONOFF_RPT (1 << 9) + + #define ECI_BW_20 0x0 diff --git a/drivers/net/wireless/bcmdhd/include/sbconfig.h b/drivers/net/wireless/bcmdhd/include/sbconfig.h index 76f05ae34bd..f45351a586c 100644 --- a/drivers/net/wireless/bcmdhd/include/sbconfig.h +++ b/drivers/net/wireless/bcmdhd/include/sbconfig.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: sbconfig.h,v 13.70 2008-03-28 19:17:04 Exp $ + * $Id: sbconfig.h 277737 2011-08-16 17:54:59Z $ */ diff --git a/drivers/net/wireless/bcmdhd/include/sbhnddma.h b/drivers/net/wireless/bcmdhd/include/sbhnddma.h index 05d0587bc20..77c413f75f0 100644 --- a/drivers/net/wireless/bcmdhd/include/sbhnddma.h +++ b/drivers/net/wireless/bcmdhd/include/sbhnddma.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: sbhnddma.h,v 13.20.2.3 2010-10-14 22:21:29 Exp $ + * $Id: sbhnddma.h 278779 2011-08-19 22:07:18Z $ */ @@ -217,7 +217,7 @@ typedef volatile struct { #define D64_XC_BL_SHIFT 18 -#define D64_XP_LD_MASK 0x00000fff +#define D64_XP_LD_MASK 0x00001fff #define D64_XS0_CD_MASK 0x00001fff @@ -260,7 +260,7 @@ typedef volatile struct { #define DMA_CTRL_USB_BOUNDRY4KB_WAR (1 << 4) -#define D64_RP_LD_MASK 0x00000fff +#define D64_RP_LD_MASK 0x00001fff #define D64_RS0_CD_MASK 0x00001fff diff --git a/drivers/net/wireless/bcmdhd/include/sbpcmcia.h b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h index aba914bd014..d84f69ab561 100644 --- a/drivers/net/wireless/bcmdhd/include/sbpcmcia.h +++ b/drivers/net/wireless/bcmdhd/include/sbpcmcia.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: sbpcmcia.h,v 13.48.12.6 2010-11-04 09:39:42 Exp $ + * $Id: sbpcmcia.h 277737 2011-08-16 17:54:59Z $ */ diff --git a/drivers/net/wireless/bcmdhd/include/sbsdio.h b/drivers/net/wireless/bcmdhd/include/sbsdio.h index 4280d5bf9c1..7aaeb73f010 100644 --- a/drivers/net/wireless/bcmdhd/include/sbsdio.h +++ b/drivers/net/wireless/bcmdhd/include/sbsdio.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: sbsdio.h,v 13.34 2009-03-11 20:27:16 Exp $ + * $Id: sbsdio.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _SBSDIO_H diff --git a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h index 107a8b07c9e..e5176483e9a 100644 --- a/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h +++ b/drivers/net/wireless/bcmdhd/include/sbsdpcmdev.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: sbsdpcmdev.h,v 13.38 2009-09-22 22:56:45 Exp $ + * $Id: sbsdpcmdev.h 282638 2011-09-08 21:18:10Z $ */ #ifndef _sbsdpcmdev_h_ diff --git a/drivers/net/wireless/bcmdhd/include/sbsocram.h b/drivers/net/wireless/bcmdhd/include/sbsocram.h index 1cba4223890..45c4dc208bd 100644 --- a/drivers/net/wireless/bcmdhd/include/sbsocram.h +++ b/drivers/net/wireless/bcmdhd/include/sbsocram.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: sbsocram.h,v 13.15 2009-10-02 16:55:44 Exp $ + * $Id: sbsocram.h 277737 2011-08-16 17:54:59Z $ */ diff --git a/drivers/net/wireless/bcmdhd/include/sdio.h b/drivers/net/wireless/bcmdhd/include/sdio.h index ca932266a1b..c8ac7b773fb 100644 --- a/drivers/net/wireless/bcmdhd/include/sdio.h +++ b/drivers/net/wireless/bcmdhd/include/sdio.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: sdio.h,v 13.27.14.1 2010-09-07 13:37:45 Exp $ + * $Id: sdio.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _SDIO_H @@ -366,7 +366,7 @@ typedef volatile struct { * SDIO Commands and responses * * I/O only commands are: - * CMD0, CMD3, CMD5, CMD7, CMD15, CMD52, CMD53 + * CMD0, CMD3, CMD5, CMD7, CMD14, CMD15, CMD52, CMD53 * ------------------------------------------------ */ @@ -412,6 +412,7 @@ typedef volatile struct { #define CMD7_RCA_M BITFIELD_MASK(16) #define CMD7_RCA_S 16 + #define CMD14_RCA_M BITFIELD_MASK(16) #define CMD14_RCA_S 16 #define CMD14_SLEEP_M BITFIELD_MASK(1) diff --git a/drivers/net/wireless/bcmdhd/include/sdioh.h b/drivers/net/wireless/bcmdhd/include/sdioh.h index 3d37c7a7e30..5f47d6f88ce 100644 --- a/drivers/net/wireless/bcmdhd/include/sdioh.h +++ b/drivers/net/wireless/bcmdhd/include/sdioh.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: sdioh.h,v 13.17.2.3 2011-01-08 05:28:21 Exp $ + * $Id: sdioh.h 300017 2011-12-01 20:30:27Z $ */ #ifndef _SDIOH_H @@ -68,6 +68,10 @@ #define SD_ADMA_SysAddr 0x58 #define SD_SlotInterruptStatus 0x0FC #define SD_HostControllerVersion 0x0FE +#define SD_GPIO_Reg 0x100 +#define SD_GPIO_OE 0x104 +#define SD_GPIO_Enable 0x108 + /* SD specific registers in PCI config space */ #define SD_SlotInfo 0x40 @@ -409,4 +413,30 @@ /* SD_SlotInterruptStatus: Offset 0x0FC , size = bytes */ /* SD_HostControllerVersion : Offset 0x0FE , size = bytes */ +/* SDIO Host Control Register DMA Mode Definitions */ +#define SDIOH_SDMA_MODE 0 +#define SDIOH_ADMA1_MODE 1 +#define SDIOH_ADMA2_MODE 2 +#define SDIOH_ADMA2_64_MODE 3 + +#define ADMA2_ATTRIBUTE_VALID (1 << 0) /* ADMA Descriptor line valid */ +#define ADMA2_ATTRIBUTE_END (1 << 1) /* End of Descriptor */ +#define ADMA2_ATTRIBUTE_INT (1 << 2) /* Interrupt when line is done */ +#define ADMA2_ATTRIBUTE_ACT_NOP (0 << 4) /* Skip current line, go to next. */ +#define ADMA2_ATTRIBUTE_ACT_RSV (1 << 4) /* Same as NOP */ +#define ADMA1_ATTRIBUTE_ACT_SET (1 << 4) /* ADMA1 Only - set transfer length */ +#define ADMA2_ATTRIBUTE_ACT_TRAN (2 << 4) /* Transfer Data of one descriptor line. */ +#define ADMA2_ATTRIBUTE_ACT_LINK (3 << 4) /* Link Descriptor */ + +/* ADMA2 Descriptor Table Entry for 32-bit Address */ +typedef struct adma2_dscr_32b { + uint32 len_attr; + uint32 phys_addr; +} adma2_dscr_32b_t; + +/* ADMA1 Descriptor Table Entry */ +typedef struct adma1_dscr { + uint32 phys_addr_attr; +} adma1_dscr_t; + #endif /* _SDIOH_H */ diff --git a/drivers/net/wireless/bcmdhd/include/sdiovar.h b/drivers/net/wireless/bcmdhd/include/sdiovar.h index 2c5bcf97e91..55a3d3490c3 100644 --- a/drivers/net/wireless/bcmdhd/include/sdiovar.h +++ b/drivers/net/wireless/bcmdhd/include/sdiovar.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: sdiovar.h,v 13.9 2009-12-08 22:30:15 Exp $ + * $Id: sdiovar.h 277737 2011-08-16 17:54:59Z $ */ #ifndef _sdiovar_h_ diff --git a/drivers/net/wireless/bcmdhd/include/siutils.h b/drivers/net/wireless/bcmdhd/include/siutils.h index c5a33832b58..6a7b93c7b97 100644 --- a/drivers/net/wireless/bcmdhd/include/siutils.h +++ b/drivers/net/wireless/bcmdhd/include/siutils.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: siutils.h,v 13.251.2.10 2011-02-04 05:06:32 Exp $ + * $Id: siutils.h 285387 2011-09-21 18:38:37Z $ */ @@ -60,6 +60,7 @@ struct si_pub { typedef const struct si_pub si_t; + #define SI_OSH NULL #define BADIDX (SI_MAXCORES + 1) @@ -213,8 +214,34 @@ extern int si_corepciid(si_t *sih, uint func, uint16 *pcivendor, uint16 *pcidevi #define si_eci(sih) 0 #define si_eci_init(sih) (0) #define si_eci_notify_bt(sih, type, val) (0) +#define si_seci(sih) 0 +static INLINE void * si_seci_init(si_t *sih, uint8 use_seci) {return NULL;} +#define si_seci_down(sih) do { } while (0) + + +extern bool si_is_otp_disabled(si_t *sih); +extern bool si_is_otp_powered(si_t *sih); +extern void si_otp_power(si_t *sih, bool on); + + +extern bool si_is_sprom_available(si_t *sih); +extern bool si_is_sprom_enabled(si_t *sih); +extern void si_sprom_enable(si_t *sih, bool enable); +extern int si_cis_source(si_t *sih); +#define CIS_DEFAULT 0 +#define CIS_SROM 1 +#define CIS_OTP 2 + + +#define DEFAULT_FAB 0x0 +#define CSM_FAB7 0x1 +#define TSMC_FAB12 0x2 +#define SMIC_FAB4 0x3 +extern int si_otp_fabid(si_t *sih, uint16 *fabid, bool rw); +extern uint16 si_fabid(si_t *sih); + extern int si_devpath(si_t *sih, char *path, int size); @@ -244,4 +271,5 @@ extern uint32 si_pcieserdesreg(si_t *sih, uint32 mdioslave, uint32 offset, uint3 char *si_getnvramflvar(si_t *sih, const char *name); + #endif diff --git a/drivers/net/wireless/bcmdhd/include/trxhdr.h b/drivers/net/wireless/bcmdhd/include/trxhdr.h index 397006ab005..b52fb15ba5c 100644 --- a/drivers/net/wireless/bcmdhd/include/trxhdr.h +++ b/drivers/net/wireless/bcmdhd/include/trxhdr.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: trxhdr.h,v 13.15.108.2 2010-11-15 17:57:30 Exp $ + * $Id: trxhdr.h 286295 2011-09-27 06:39:43Z $ */ #ifndef _TRX_HDR_H_ @@ -37,6 +37,7 @@ #define TRX_OVERLAYS 0x4 /* Contains an overlay header after the trx header */ #define TRX_MAX_OFFSET 3 /* Max number of individual files */ #define TRX_UNCOMP_IMAGE 0x20 /* Trx contains uncompressed rtecdc.bin image */ +#define TRX_ROMSIM_IMAGE 0x10 /* Trx contains ROM simulation image */ struct trx_header { uint32 magic; /* "HDR0" */ diff --git a/drivers/net/wireless/bcmdhd/include/typedefs.h b/drivers/net/wireless/bcmdhd/include/typedefs.h index 228b5dcf11c..d0902fe8089 100644 --- a/drivers/net/wireless/bcmdhd/include/typedefs.h +++ b/drivers/net/wireless/bcmdhd/include/typedefs.h @@ -18,7 +18,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. - * $Id: typedefs.h,v 1.103.2.1 2010-05-11 18:19:28 Exp $ + * $Id: typedefs.h 290055 2011-10-15 21:26:26Z $ */ @@ -305,5 +305,8 @@ typedef float64 float_t; #define UNUSED_PARAMETER(x) (void)(x) +#define DISCARD_QUAL(ptr, type) ((type *)(uintptr)(ptr)) + + #include #endif diff --git a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h index 7230d3b67ab..d37105165ba 100644 --- a/drivers/net/wireless/bcmdhd/include/wlfc_proto.h +++ b/drivers/net/wireless/bcmdhd/include/wlfc_proto.h @@ -18,7 +18,7 @@ * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. -* $Id: wlfc_proto.h,v 1.1.6.2 2010-05-08 01:30:41 Exp $ +* $Id: wlfc_proto.h 277737 2011-08-16 17:54:59Z $ * */ #ifndef __wlfc_proto_definitions_h__ diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h index 9357552c919..676068c0b38 100644 --- a/drivers/net/wireless/bcmdhd/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wlioctl.h,v 1.767.2.38 2011-02-01 23:04:28 Exp $ + * $Id: wlioctl.h 302303 2011-12-10 07:51:07Z $ */ @@ -65,8 +65,8 @@ typedef struct wl_action_frame { typedef struct ssid_info { - uint8 ssid_len; - uint8 ssid[32]; + uint8 ssid_len; + uint8 ssid[32]; } ssid_info_t; typedef struct wl_af_params { @@ -191,6 +191,7 @@ typedef struct wlc_ssid { #define WL_SCANFLAGS_PROHIBITED 0x04 #define WL_SCAN_PARAMS_SSID_MAX 10 + typedef struct wl_scan_params { wlc_ssid_t ssid; struct ether_addr bssid; @@ -376,6 +377,8 @@ typedef struct { #define NRATE_SGI_SHIFT 23 #define NRATE_LDPC_CODING 0x00400000 #define NRATE_LDPC_SHIFT 22 +#define NRATE_BCMC_OVERRIDE 0x00200000 +#define NRATE_BCMC_SHIFT 21 #define NRATE_STF_SISO 0 #define NRATE_STF_CDD 1 @@ -555,7 +558,7 @@ typedef enum sup_auth_status { #define CRYPTO_ALGO_AES_OCB_MSDU 5 #define CRYPTO_ALGO_AES_OCB_MPDU 6 #define CRYPTO_ALGO_NALG 7 -#define CRYPTO_ALGO_PMK 12 +#define CRYPTO_ALGO_PMK 12 #define WSEC_GEN_MIC_ERROR 0x0001 #define WSEC_GEN_REPLAY 0x0002 @@ -617,9 +620,9 @@ typedef struct { #define WPA2_AUTH_PSK 0x0080 #define BRCM_AUTH_PSK 0x0100 #define BRCM_AUTH_DPT 0x0200 -#define WPA2_AUTH_MFP 0x1000 -#define WPA2_AUTH_TPK 0x2000 -#define WPA2_AUTH_FT 0x4000 +#define WPA2_AUTH_MFP 0x1000 +#define WPA2_AUTH_TPK 0x2000 +#define WPA2_AUTH_FT 0x4000 #define MAXPMKID 16 @@ -649,12 +652,12 @@ typedef struct wl_assoc_info { uint32 resp_len; uint32 flags; struct dot11_assoc_req req; - struct ether_addr reassoc_bssid; + struct ether_addr reassoc_bssid; struct dot11_assoc_resp resp; } wl_assoc_info_t; -#define WLC_ASSOC_REQ_IS_REASSOC 0x01 +#define WLC_ASSOC_REQ_IS_REASSOC 0x01 typedef struct { @@ -851,6 +854,7 @@ typedef struct wlc_iov_trx_s { #define WLC_GET_SSID 25 #define WLC_SET_SSID 26 #define WLC_RESTART 27 +#define WLC_TERMINATED 28 #define WLC_GET_CHANNEL 29 #define WLC_SET_CHANNEL 30 @@ -1203,7 +1207,7 @@ typedef struct { #define WL_AUTH_OPEN_SYSTEM 0 #define WL_AUTH_SHARED_KEY 1 -#define WL_AUTH_OPEN_SHARED 2 +#define WL_AUTH_OPEN_SHARED 3 #define WL_RADIO_SW_DISABLE (1<<0) @@ -1280,18 +1284,17 @@ typedef struct wl_po { #define WL_CHAN_FREQ_RANGE_5GM 2 #define WL_CHAN_FREQ_RANGE_5GH 3 -#define WL_CHAN_FREQ_RANGE_5GLL_VER2 4 -#define WL_CHAN_FREQ_RANGE_5GLH_VER2 5 -#define WL_CHAN_FREQ_RANGE_5GML_VER2 6 -#define WL_CHAN_FREQ_RANGE_5GMH_VER2 7 -#define WL_CHAN_FREQ_RANGE_5GH_VER2 8 - #define WL_CHAN_FREQ_RANGE_5GLL_5BAND 4 #define WL_CHAN_FREQ_RANGE_5GLH_5BAND 5 #define WL_CHAN_FREQ_RANGE_5GML_5BAND 6 #define WL_CHAN_FREQ_RANGE_5GMH_5BAND 7 #define WL_CHAN_FREQ_RANGE_5GH_5BAND 8 +#define WL_CHAN_FREQ_RANGE_5G_BAND0 1 +#define WL_CHAN_FREQ_RANGE_5G_BAND1 2 +#define WL_CHAN_FREQ_RANGE_5G_BAND2 3 +#define WL_CHAN_FREQ_RANGE_5G_BAND3 4 + #define WLC_PHY_TYPE_A 0 #define WLC_PHY_TYPE_B 1 @@ -1363,7 +1366,7 @@ typedef struct wl_po { #define PM_MAX 1 #define PM_FAST 2 -#define LISTEN_INTERVAL 10 +#define LISTEN_INTERVAL 10 #define INTERFERE_OVRRIDE_OFF -1 #define INTERFERE_NONE 0 @@ -1493,6 +1496,7 @@ typedef struct wl_sampledata { #define WL_P2P_VAL 0x00000200 #define WL_TXRX_VAL 0x00000400 #define WL_MCHAN_VAL 0x00000800 +#define WL_TDLS_VAL 0x00001000 #define WL_LED_NUMGPIO 16 @@ -1546,7 +1550,7 @@ typedef struct wl_sampledata { #define WL_JOIN_PREF_WPA 2 #define WL_JOIN_PREF_BAND 3 #define WL_JOIN_PREF_RSSI_DELTA 4 -#define WL_JOIN_PREF_TRANS_PREF 5 +#define WL_JOIN_PREF_TRANS_PREF 5 #define WLJP_BAND_ASSOC_PREF 255 @@ -1797,17 +1801,19 @@ struct wl_msglevel2 { }; typedef struct wl_mkeep_alive_pkt { - uint16 version; - uint16 length; + uint16 version; + uint16 length; uint32 period_msec; uint16 len_bytes; - uint8 keep_alive_id; + uint8 keep_alive_id; uint8 data[1]; } wl_mkeep_alive_pkt_t; -#define WL_MKEEP_ALIVE_VERSION 1 -#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data) -#define WL_MKEEP_ALIVE_PRECISION 500 +#define WL_MKEEP_ALIVE_VERSION 1 +#define WL_MKEEP_ALIVE_FIXED_LEN OFFSETOF(wl_mkeep_alive_pkt_t, data) +#define WL_MKEEP_ALIVE_PRECISION 500 + + #define WLC_ROAM_TRIGGER_DEFAULT 0 #define WLC_ROAM_TRIGGER_BANDWIDTH 1 @@ -1897,7 +1903,7 @@ typedef struct wl_pfn_param { uint8 mscan; uint8 repeat; uint8 exp; - int32 slow_freq; + int32 slow_freq; } wl_pfn_param_t; typedef struct wl_pfn_bssid { @@ -2016,8 +2022,31 @@ typedef struct wl_keep_alive_pkt { +#define MAX_WAKE_PACKET_BYTES 128 + + +typedef struct pm_wake_packet { + uint32 status; + uint32 pattern_id; + uint32 original_packet_size; + uint32 saved_packet_size; + uchar packet[MAX_WAKE_PACKET_BYTES]; +} pm_wake_packet_t; + + + +#define PKT_FILTER_MODE_FORWARD_ON_MATCH 1 + +#define PKT_FILTER_MODE_DISABLE 2 + +#define PKT_FILTER_MODE_PKT_CACHE_ON_MATCH 4 + +#define PKT_FILTER_MODE_PKT_FORWARD_OFF_DEFAULT 8 + + typedef enum wl_pkt_filter_type { - WL_PKT_FILTER_TYPE_PATTERN_MATCH + WL_PKT_FILTER_TYPE_PATTERN_MATCH, + WL_PKT_FILTER_TYPE_MAGIC_PATTERN_MATCH } wl_pkt_filter_type_t; #define WL_PKT_FILTER_TYPE wl_pkt_filter_type_t @@ -2550,6 +2579,12 @@ typedef struct wl_phycal_state { #define WL_PHYCAL_STAT_FIXED_LEN OFFSETOF(wl_phycal_state_t, phycal_core) #endif +#ifdef WLDSTA +typedef struct wl_dsta_if { + struct ether_addr addr; +} wl_dsta_if_t; +#endif + #ifdef WLP2P typedef struct wl_p2p_disc_st { diff --git a/drivers/net/wireless/bcmdhd/linux_osl.c b/drivers/net/wireless/bcmdhd/linux_osl.c index b3fcdd2f1ad..4ef7bf7b24d 100644 --- a/drivers/net/wireless/bcmdhd/linux_osl.c +++ b/drivers/net/wireless/bcmdhd/linux_osl.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: linux_osl.c,v 1.168.2.7 2011-01-27 17:01:13 Exp $ + * $Id: linux_osl.c,v 1.168.2.7 2011-01-27 17:01:13 $ */ @@ -226,17 +226,16 @@ osl_attach(void *pdev, uint bustype, bool pkttag) } if (!bcm_static_skb) { - void *skb_buff_ptr = dhd_os_prealloc(osh, 4, 0); - - if (skb_buff_ptr) { - bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); - bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * 16); - for (i = 0; i < STATIC_PKT_MAX_NUM * 2; i++) - bcm_static_skb->pkt_use[i] = 0; - sema_init(&bcm_static_skb->osl_pkt_sem, 1); - } else { - printk("can not alloc static skb buffers\n"); - } + int i; + void *skb_buff_ptr = 0; + bcm_static_skb = (bcm_static_pkt_t *)((char *)bcm_static_buf + 2048); + skb_buff_ptr = dhd_os_prealloc(osh, 4, 0); + + bcopy(skb_buff_ptr, bcm_static_skb, sizeof(struct sk_buff *) * 16); + for (i = 0; i < STATIC_PKT_MAX_NUM * 2; i++) + bcm_static_skb->pkt_use[i] = 0; + + sema_init(&bcm_static_skb->osl_pkt_sem, 1); } #endif diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c index 22aa4126576..4b715630355 100644 --- a/drivers/net/wireless/bcmdhd/siutils.c +++ b/drivers/net/wireless/bcmdhd/siutils.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: siutils.c,v 1.813.2.36 2011-02-10 23:43:55 Exp $ + * $Id: siutils.c,v 1.813.2.36 2011-02-10 23:43:55 $ */ #include @@ -213,11 +213,11 @@ si_buscore_setup(si_info_t *sii, chipcregs_t *cc, uint bustype, uint32 savewin, /* figure out bus/orignal core idx */ sii->pub.buscoretype = NODEV_CORE_ID; - sii->pub.buscorerev = NOREV; + sii->pub.buscorerev = (uint)NOREV; sii->pub.buscoreidx = BADIDX; pci = pcie = FALSE; - pcirev = pcierev = NOREV; + pcirev = pcierev = (uint)NOREV; pciidx = pcieidx = BADIDX; for (i = 0; i < sii->numcores; i++) { @@ -365,6 +365,19 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, return NULL; } +#if defined(HW_OOB) + if (CHIPID(sih->chip) == BCM43362_CHIP_ID) { + uint32 gpiocontrol, addr; + addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, gpiocontrol); + gpiocontrol = bcmsdh_reg_read(sdh, addr, 4); + gpiocontrol |= 0x2; + bcmsdh_reg_write(sdh, addr, 4, gpiocontrol); + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10005, 0xf, NULL); + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10006, 0x0, NULL); + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, 0x10007, 0x2, NULL); + } +#endif + if ((CHIPID(sih->chip) == BCM4329_CHIP_ID) && (sih->chiprev == 0) && (sih->chippkg != BCM4329_289PIN_PKG_ID)) { sih->chippkg = BCM4329_182PIN_PKG_ID; @@ -401,8 +414,9 @@ si_doattach(si_info_t *sii, uint devid, osl_t *osh, void *regs, } /* assume current core is CC */ - if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43236_CHIP_ID || + if ((sii->pub.ccrev == 0x25) && ((CHIPID(sih->chip) == BCM43234_CHIP_ID || CHIPID(sih->chip) == BCM43235_CHIP_ID || + CHIPID(sih->chip) == BCM43236_CHIP_ID || CHIPID(sih->chip) == BCM43238_CHIP_ID) && (CHIPREV(sii->pub.chiprev) == 0))) { @@ -1093,6 +1107,126 @@ si_watchdog_ms(si_t *sih, uint32 ms) +/* return the slow clock source - LPO, XTAL, or PCI */ +static uint +si_slowclk_src(si_info_t *sii) +{ + chipcregs_t *cc; + + ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); + + if (sii->pub.ccrev < 6) { + if ((BUSTYPE(sii->pub.bustype) == PCI_BUS) && + (OSL_PCI_READ_CONFIG(sii->osh, PCI_GPIO_OUT, sizeof(uint32)) & + PCI_CFG_GPIO_SCS)) + return (SCC_SS_PCI); + else + return (SCC_SS_XTAL); + } else if (sii->pub.ccrev < 10) { + cc = (chipcregs_t *)si_setcoreidx(&sii->pub, sii->curidx); + return (R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_SS_MASK); + } else /* Insta-clock */ + return (SCC_SS_XTAL); +} + +/* return the ILP (slowclock) min or max frequency */ +static uint +si_slowclk_freq(si_info_t *sii, bool max_freq, chipcregs_t *cc) +{ + uint32 slowclk; + uint div; + + ASSERT(SI_FAST(sii) || si_coreid(&sii->pub) == CC_CORE_ID); + + /* shouldn't be here unless we've established the chip has dynamic clk control */ + ASSERT(R_REG(sii->osh, &cc->capabilities) & CC_CAP_PWR_CTL); + + slowclk = si_slowclk_src(sii); + if (sii->pub.ccrev < 6) { + if (slowclk == SCC_SS_PCI) + return (max_freq ? (PCIMAXFREQ / 64) : (PCIMINFREQ / 64)); + else + return (max_freq ? (XTALMAXFREQ / 32) : (XTALMINFREQ / 32)); + } else if (sii->pub.ccrev < 10) { + div = 4 * + (((R_REG(sii->osh, &cc->slow_clk_ctl) & SCC_CD_MASK) >> SCC_CD_SHIFT) + 1); + if (slowclk == SCC_SS_LPO) + return (max_freq ? LPOMAXFREQ : LPOMINFREQ); + else if (slowclk == SCC_SS_XTAL) + return (max_freq ? (XTALMAXFREQ / div) : (XTALMINFREQ / div)); + else if (slowclk == SCC_SS_PCI) + return (max_freq ? (PCIMAXFREQ / div) : (PCIMINFREQ / div)); + else + ASSERT(0); + } else { + /* Chipc rev 10 is InstaClock */ + div = R_REG(sii->osh, &cc->system_clk_ctl) >> SYCC_CD_SHIFT; + div = 4 * (div + 1); + return (max_freq ? XTALMAXFREQ : (XTALMINFREQ / div)); + } + return (0); +} + +static void +si_clkctl_setdelay(si_info_t *sii, void *chipcregs) +{ + chipcregs_t *cc = (chipcregs_t *)chipcregs; + uint slowmaxfreq, pll_delay, slowclk; + uint pll_on_delay, fref_sel_delay; + + pll_delay = PLL_DELAY; + + /* If the slow clock is not sourced by the xtal then add the xtal_on_delay + * since the xtal will also be powered down by dynamic clk control logic. + */ + + slowclk = si_slowclk_src(sii); + if (slowclk != SCC_SS_XTAL) + pll_delay += XTAL_ON_DELAY; + + /* Starting with 4318 it is ILP that is used for the delays */ + slowmaxfreq = si_slowclk_freq(sii, (sii->pub.ccrev >= 10) ? FALSE : TRUE, cc); + + pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000; + fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000; + + W_REG(sii->osh, &cc->pll_on_delay, pll_on_delay); + W_REG(sii->osh, &cc->fref_sel_delay, fref_sel_delay); +} + +/* initialize power control delay registers */ +void +si_clkctl_init(si_t *sih) +{ + si_info_t *sii; + uint origidx = 0; + chipcregs_t *cc; + bool fast; + + if (!CCCTL_ENAB(sih)) + return; + + sii = SI_INFO(sih); + fast = SI_FAST(sii); + if (!fast) { + origidx = sii->curidx; + if ((cc = (chipcregs_t *)si_setcore(sih, CC_CORE_ID, 0)) == NULL) + return; + } else if ((cc = (chipcregs_t *)CCREGS_FAST(sii)) == NULL) + return; + ASSERT(cc != NULL); + + /* set all Instaclk chip ILP to 1 MHz */ + if (sih->ccrev >= 10) + SET_REG(sii->osh, &cc->system_clk_ctl, SYCC_CD_MASK, + (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); + + si_clkctl_setdelay(sii, (void *)(uintptr)cc); + + if (!fast) + si_setcoreidx(sih, origidx); +} + /* change logical "focus" to the gpio core for optimized access */ void * si_gpiosetcore(si_t *sih) @@ -1718,3 +1852,56 @@ si_deviceremoved(si_t *sih) } return FALSE; } + +bool +si_is_sprom_available(si_t *sih) +{ + if (sih->ccrev >= 31) { + si_info_t *sii; + uint origidx; + chipcregs_t *cc; + uint32 sromctrl; + + if ((sih->cccaps & CC_CAP_SROM) == 0) + return FALSE; + + sii = SI_INFO(sih); + origidx = sii->curidx; + cc = si_setcoreidx(sih, SI_CC_IDX); + sromctrl = R_REG(sii->osh, &cc->sromcontrol); + si_setcoreidx(sih, origidx); + return (sromctrl & SRC_PRESENT); + } + + switch (CHIPID(sih->chip)) { + case BCM4312_CHIP_ID: + return ((sih->chipst & CST4312_SPROM_OTP_SEL_MASK) != CST4312_OTP_SEL); + case BCM4325_CHIP_ID: + return (sih->chipst & CST4325_SPROM_SEL) != 0; + case BCM4322_CHIP_ID: + case BCM43221_CHIP_ID: + case BCM43231_CHIP_ID: + case BCM43222_CHIP_ID: + case BCM43111_CHIP_ID: + case BCM43112_CHIP_ID: + case BCM4342_CHIP_ID: + { + uint32 spromotp; + spromotp = (sih->chipst & CST4322_SPROM_OTP_SEL_MASK) >> + CST4322_SPROM_OTP_SEL_SHIFT; + return (spromotp & CST4322_SPROM_PRESENT) != 0; + } + case BCM4329_CHIP_ID: + return (sih->chipst & CST4329_SPROM_SEL) != 0; + case BCM4315_CHIP_ID: + return (sih->chipst & CST4315_SPROM_SEL) != 0; + case BCM4319_CHIP_ID: + return (sih->chipst & CST4319_SPROM_SEL) != 0; + case BCM4330_CHIP_ID: + return (sih->chipst & CST4330_SPROM_PRESENT) != 0; + case BCM4313_CHIP_ID: + return (sih->chipst & CST4313_SPROM_PRESENT) != 0; + default: + return TRUE; + } +} diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index b6804817240..dc32f17a91f 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -2,13 +2,13 @@ * Linux cfg80211 driver - Android related functions * * Copyright (C) 1999-2011, Broadcom Corporation - * + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,7 +16,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index e026a7db28a..93fa447c16b 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -2,13 +2,13 @@ * Linux cfg80211 driver * * Copyright (C) 1999-2011, Broadcom Corporation - * + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,7 +16,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -65,8 +65,8 @@ #include #include -static struct sdio_func *cfg80211_sdio_func; -static struct wl_priv *wlcfg_drv_priv; +static struct device *cfg80211_parent_dev = NULL; +static struct wl_priv *wlcfg_drv_priv = NULL; u32 wl_dbg_level = WL_DBG_ERR; @@ -103,6 +103,11 @@ static int wl_cfg80211_btcoex_init(struct wl_priv *wl); static void wl_cfg80211_btcoex_deinit(struct wl_priv *wl); #endif +/* Set this to 1 to use a seperate interface (p2p0) + * for p2p operations. + */ +#define ENABLE_P2P_INTERFACE 1 + /* This is to override regulatory domains defined in cfg80211 module (reg.c) * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165). @@ -224,7 +229,7 @@ static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_pmksa *pmksa); static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev); -static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted); +static void wl_notify_escan_complete(struct wl_priv *wl, struct net_device *ndev, bool aborted); /* * event & event Q handlers for cfg80211 interfaces */ @@ -261,8 +266,7 @@ static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, /* * register/deregister sdio function */ -struct sdio_func *wl_cfg80211_get_sdio_func(void); -static void wl_clear_sdio_func(void); +static void wl_cfg80211_clear_parent_dev(void); /* * ioctl utilites @@ -285,10 +289,10 @@ static s32 wl_set_retry(struct net_device *dev, u32 retry, bool l); /* * wl profile utilities */ -static s32 wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, - void *data, s32 item); -static void *wl_read_prof(struct wl_priv *wl, s32 item); -static void wl_init_prof(struct wl_priv *wl); +static s32 wl_update_prof(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data, s32 item); +static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item); +static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev); /* * cfg80211 connect utilites @@ -316,7 +320,6 @@ static s32 wl_mrg_ie(struct wl_priv *wl, u8 *ie_stream, u16 ie_size); static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size); static u32 wl_get_ielen(struct wl_priv *wl); -static s32 wl_mode_to_nl80211_iftype(s32 mode); static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev); static void wl_free_wdev(struct wl_priv *wl); @@ -324,6 +327,7 @@ static void wl_free_wdev(struct wl_priv *wl); static s32 wl_inform_bss(struct wl_priv *wl); static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi); static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev); +static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy); static s32 wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, u8 key_idx, const u8 *mac_addr, @@ -426,7 +430,7 @@ static __used s32 wl_update_pmklist(struct net_device *dev, /* * debufs support */ -static int wl_debugfs_add_netdev_params(struct wl_priv *wl); +static int wl_debugfs_add_netdev_params(struct wl_priv *wl, struct net_device *ndev); static void wl_debugfs_remove_netdev(struct wl_priv *wl); /* @@ -446,10 +450,10 @@ int dhd_start_xmit(struct sk_buff *skb, struct net_device *net); #define CHECK_SYS_UP(wlpriv) \ do { \ - if (unlikely(!wl_get_drv_status(wlpriv, READY))) { \ - WL_INFO(("device is not ready : status (%d)\n", \ - (int)wlpriv->status)); \ - return -EIO; \ + struct net_device *ndev = wl_to_prmry_ndev(wlpriv); \ + if (unlikely(!wl_get_drv_status(wlpriv, READY, ndev))) { \ + WL_INFO(("device is not ready\n")); \ + return -EIO; \ } \ } while (0) @@ -591,7 +595,7 @@ static const u32 __wl_cipher_suites[] = { WLAN_CIPHER_SUITE_WEP104, WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, - WLAN_CIPHER_SUITE_AES_CMAC + WLAN_CIPHER_SUITE_AES_CMAC, }; /* There isn't a lot of sense in it, but you can transmit anything you like */ @@ -742,6 +746,40 @@ wl_validate_wps_ie(char *wps_ie, bool *pbc) } } +static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) +{ + chanspec_t chspec; + int err = 0; + struct wl_priv *wl = wiphy_priv(wiphy); + struct net_device *dev = wl_to_prmry_ndev(wl); + struct ether_addr bssid; + struct wl_bss_info *bss = NULL; + + if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) { + /* STA interface is not associated. So start the new interface on a temp + * channel . Later proper channel will be applied by the above framework + * via set_channel (cfg80211 API). + */ + WL_DBG(("Not associated. Return a temp channel. \n")); + return wf_chspec_aton(WL_P2P_TEMP_CHAN); + } + + + *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); + if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf, + sizeof(WL_EXTRA_BUF_MAX), false))) { + WL_ERR(("Failed to get associated bss info, use temp channel \n")); + chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN); + } + else { + bss = (struct wl_bss_info *) (wl->extra_buf + 4); + chspec = bss->chanspec; + WL_DBG(("Valid BSS Found. chanspec:%d \n", bss->chanspec)); + } + + return chspec; +} + static struct net_device* wl_cfg80211_add_monitor_if(char *name) { int ret = 0; @@ -760,7 +798,6 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, s32 err; s32 timeout = -1; s32 wlif_type = -1; - s32 index = 0; s32 mode = 0; chanspec_t chspec; struct wl_priv *wl = wiphy_priv(wiphy); @@ -768,6 +805,8 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); int (*net_attach)(dhd_pub_t *dhdp, int ifidx); bool rollback_lock = false; + /* Use primary I/F for sending cmds down to firmware */ + _ndev = wl_to_prmry_ndev(wl); WL_DBG(("if name: %s, type: %d\n", name, type)); switch (type) { @@ -800,6 +839,8 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, WL_ERR(("name is NULL\n")); return NULL; } + if (wl->iface_cnt == IFACE_MAX_CNT) + return ERR_PTR(-ENOMEM); if (wl->p2p_supported && (wlif_type != -1)) { if (wl_get_p2p_status(wl, IF_DELETING)) { /* wait till IF_DEL is complete @@ -828,7 +869,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, return ERR_PTR(-EAGAIN); } } - if (!p2p_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) { + if (!p2p_is_on(wl) && strstr(name, WL_P2P_INTERFACE_PREFIX)) { p2p_on(wl) = true; wl_cfgp2p_set_firm_p2p(wl); wl_cfgp2p_init_discovery(wl); @@ -837,8 +878,11 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1); wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); - /* Temporary use channel 11, in case GO will be changed with set_channel API */ - chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN); + /* In concurrency case, STA may be already associated in a particular channel. + * so retrieve the current channel of primary interface and then start the virtual + * interface on that. + */ + chspec = wl_cfg80211_get_shared_freq(wiphy); /* For P2P mode, use P2P-specific driver features to create the * bss: "wl p2p_ifadd" @@ -865,26 +909,21 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, vwdev->wiphy = wl->wdev->wiphy; WL_INFO((" virtual interface(%s) is created memalloc done \n", wl->p2p->vir_ifname)); - index = alloc_idx_vwdev(wl); - wl->vwdev[index] = vwdev; - vwdev->iftype = - (wlif_type == WL_P2P_IF_CLIENT) ? NL80211_IFTYPE_STATION - : NL80211_IFTYPE_AP; + vwdev->iftype = type; _ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); _ndev->ieee80211_ptr = vwdev; SET_NETDEV_DEV(_ndev, wiphy_dev(vwdev->wiphy)); vwdev->netdev = _ndev; - wl_set_drv_status(wl, READY); + wl_set_drv_status(wl, READY, _ndev); wl->p2p->vif_created = true; - set_mode_by_netdev(wl, _ndev, mode); - WL_DBG((" virtual interface(%s) wl->wdev %p wl->wdev->netdev %p vwdev %p vwdev->netdev %p\n", - wl->p2p->vir_ifname, wl->wdev, wl->wdev->netdev, vwdev, vwdev->netdev)); + wl_set_mode_by_netdev(wl, _ndev, mode); net_attach = wl_to_p2p_bss_private(wl, P2PAPI_BSSCFG_CONNECTION); if (rtnl_is_locked()) { rtnl_unlock(); rollback_lock = true; } if (net_attach && !net_attach(dhd, _ndev->ifindex)) { + wl_alloc_netinfo(wl, _ndev, vwdev, mode); WL_DBG((" virtual interface(%s) is " "created net attach done\n", wl->p2p->vir_ifname)); } else { @@ -917,10 +956,18 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) s32 timeout = -1; s32 ret = 0; WL_DBG(("Enter\n")); + + if (wl->p2p_net == dev) { + /* Since there is no ifidx corresponding to p2p0, cmds to + * firmware should be routed through primary I/F + */ + dev = wl_to_prmry_ndev(wl); + } + if (wl->p2p_supported) { memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN); if (wl->p2p->vif_created) { - if (wl_get_drv_status(wl, SCANNING)) { + if (wl_get_drv_status(wl, SCANNING, dev)) { wl_cfg80211_scan_abort(wl, dev); } wldev_iovar_setint(dev, "mpc", 1); @@ -933,14 +980,10 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) * ifconfig down and up sequnce, which will reload the fw * however we should cleanup the linux network virtual interfaces */ - /* Request framework to RESET and clean up */ - struct net_device *ndev = wl_to_prmry_ndev(wl); - WL_ERR(("Firmware returned an error (%d) from p2p_ifdel" - "HANG Notification sent to %s dev %p wdev %p ndev %p\n", ret, ndev->name, dev, wl->wdev, wl_to_prmry_ndev(wl))); - wl_cfg80211_hang(ndev, WLAN_REASON_UNSPECIFIED); - } - else { - WL_ERR(("Firmware success from p2p_ifdel dev %p wdev %p ndev %p", dev, wl->wdev, wl_to_prmry_ndev(wl))); + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); + WL_ERR(("Firmware returned an error from p2p_ifdel\n")); + WL_ERR(("try to remove linux virtual interface %s\n", dev->name)); + dhd_del_if(dhd->info, dhd_net2idx(dhd->info, dev)); } /* Wait for any pending scan req to get aborted from the sysioc context */ @@ -998,13 +1041,18 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, return -EINVAL; } - if (ap) { - set_mode_by_netdev(wl, ndev, mode); + wl_set_mode_by_netdev(wl, ndev, mode); if (wl->p2p_supported && wl->p2p->vif_created) { WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created, p2p_on(wl))); - chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN); + + /* In concurrency case, STA may be already associated in a particular + * channel. so retrieve the current channel of primary interface and + * then start the virtual interface on that. + */ + chspec = wl_cfg80211_get_shared_freq(wiphy); + wlif_type = ap ? WL_P2P_IF_GO : WL_P2P_IF_CLIENT; WL_ERR(("%s : ap (%d), infra (%d), iftype: (%d)\n", ndev->name, ap, infra, type)); @@ -1014,12 +1062,12 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, (wl_get_p2p_status(wl, IF_CHANGED) == true), msecs_to_jiffies(MAX_WAIT_TIME)); - set_mode_by_netdev(wl, ndev, mode); + wl_set_mode_by_netdev(wl, ndev, mode); wl_clr_p2p_status(wl, IF_CHANGING); wl_clr_p2p_status(wl, IF_CHANGED); } else if (ndev == wl_to_prmry_ndev(wl) && - !wl_get_drv_status(wl, AP_CREATED)) { - wl_set_drv_status(wl, AP_CREATING); + !wl_get_drv_status(wl, AP_CREATED, ndev)) { + wl_set_drv_status(wl, AP_CREATING, ndev); if (!wl->ap_info && !(wl->ap_info = kzalloc(sizeof(struct ap_info), GFP_KERNEL))) { WL_ERR(("struct ap_saved_ie allocation failed\n")); @@ -1077,7 +1125,8 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev) if (p2p_is_on(wl) && wl->p2p->vif_created && wl_get_p2p_status(wl, IF_DELETING)) { - if (wl->scan_request) { + if (wl->scan_request && + (wl->escan_info.ndev == ndev)) { /* Abort any pending scan requests */ wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; if (!rtnl_is_locked()) { @@ -1085,7 +1134,7 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev) rollback_lock = true; } WL_DBG(("ESCAN COMPLETED\n")); - wl_notify_escan_complete(wl, true); + wl_notify_escan_complete(wl, ndev, true); if (rollback_lock) rtnl_unlock(); } @@ -1109,18 +1158,6 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev) return 0; } -s32 wl_cfg80211_post_del(void* ndev) -{ - int index; - struct wl_priv *wl = wlcfg_drv_priv; - index = get_idx_vwdev_by_netdev(wl, (struct net_device *)ndev); - WL_DBG(("index : %d\n", index)); - if (index >= 0) { - free_vwdev_by_index(wl, index); - } - return 0; -} - s32 wl_cfg80211_is_progress_ifadd(void) { @@ -1386,7 +1423,7 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, WL_ERR((" Escan set error (%d)\n", err)); kfree(params); } - else if (p2p_on(wl) && p2p_scan(wl)) { + else if (p2p_is_on(wl) && p2p_scan(wl)) { /* P2P SCAN TRIGGER */ if (scan_request && scan_request->n_channels) { num_chans = scan_request->n_channels; @@ -1412,7 +1449,7 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, search_state = WL_P2P_DISC_ST_SEARCH; WL_INFO(("P2P SEARCH PHASE START \n")); } else if ((dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION)) && - (get_mode_by_netdev(wl, dev) == WL_MODE_AP)) { + (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP)) { /* If you are already a GO, then do SEARCH only */ WL_INFO(("Already a GO. Do SEARCH Only")); search_state = WL_P2P_DISC_ST_SEARCH; @@ -1442,7 +1479,7 @@ wl_do_escan(struct wl_priv *wl, struct wiphy *wiphy, struct net_device *ndev, s32 passive_scan; wl_scan_results_t *results; WL_SCAN(("Enter \n")); - + wl->escan_info.ndev = ndev; wl->escan_info.wiphy = wiphy; wl->escan_info.escan_state = WL_ESCAN_STATE_SCANING; passive_scan = wl->active_scan ? 0 : 1; @@ -1473,21 +1510,27 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, s32 passive_scan; bool iscan_req; bool escan_req; - bool spec_scan; bool p2p_ssid; s32 err = 0; s32 i; u32 wpsie_len = 0; u8 wpsie[IE_MAX_LEN]; + /* If scan req comes for p2p0, send it over primary I/F as there + * there is no firmware interface corresponding to p2p0. + * Scan results will be delivered corresponding to cfg80211_scan_request + */ + if (ndev == wl->p2p_net) { + ndev = wl_to_prmry_ndev(wl); + } + WL_DBG(("Enter wiphy (%p)\n", wiphy)); - if (unlikely(wl_get_drv_status(wl, SCANNING))) { - WL_ERR(("Scanning already : status (%d)\n", (int)wl->status)); + if (wl_get_drv_status_all(wl, SCANNING)) { + WL_ERR(("Scanning already\n")); return -EAGAIN; } - if (unlikely(wl_get_drv_status(wl, SCAN_ABORTING))) { - WL_ERR(("Scanning being aborted : status (%d)\n", - (int)wl->status)); + if (wl_get_drv_status(wl, SCAN_ABORTING, ndev)) { + WL_ERR(("Scanning being aborted\n")); return -EAGAIN; } if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) { @@ -1498,7 +1541,6 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, /* Arm scan timeout timer */ mod_timer(&wl->scan_timeout, jiffies + WL_SCAN_TIMER_INTERVAL_MS * HZ / 1000); iscan_req = false; - spec_scan = false; if (request) { /* scan bss */ ssids = request->ssids; if (wl->iscan_on && (!ssids || !ssids->ssid_len || request->n_ssids != 1)) { @@ -1572,7 +1614,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, ssids = this_ssid; } wl->scan_request = request; - wl_set_drv_status(wl, SCANNING); + wl_set_drv_status(wl, SCANNING, ndev); if (iscan_req) { err = wl_do_iscan(wl, request); if (likely(!err)) @@ -1607,7 +1649,6 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, sr->ssid.SSID_len = htod32(sr->ssid.SSID_len); WL_SCAN(("Specific scan ssid=\"%s\" len=%d\n", sr->ssid.SSID, sr->ssid.SSID_len)); - spec_scan = true; } else { WL_SCAN(("Broadcast scan\n")); } @@ -1635,7 +1676,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, return 0; scan_out: - wl_clr_drv_status(wl, SCANNING); + wl_clr_drv_status(wl, SCANNING, ndev); wl->scan_request = NULL; return err; } @@ -1891,7 +1932,7 @@ wl_set_wpa_version(struct net_device *dev, struct cfg80211_connect_params *sme) WL_ERR(("set wpa_auth failed (%d)\n", err)); return err; } - sec = wl_read_prof(wl, WL_PROF_SEC); + sec = wl_read_prof(wl, dev, WL_PROF_SEC); sec->wpa_versions = sme->crypto.wpa_versions; return err; } @@ -1930,7 +1971,7 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) WL_ERR(("set auth failed (%d)\n", err)); return err; } - sec = wl_read_prof(wl, WL_PROF_SEC); + sec = wl_read_prof(wl, dev, WL_PROF_SEC); sec->auth_type = sme->auth_type; return err; } @@ -2002,7 +2043,7 @@ wl_set_set_cipher(struct net_device *dev, struct cfg80211_connect_params *sme) return err; } - sec = wl_read_prof(wl, WL_PROF_SEC); + sec = wl_read_prof(wl, dev, WL_PROF_SEC); sec->cipher_pairwise = sme->crypto.ciphers_pairwise[0]; sec->cipher_group = sme->crypto.cipher_group; @@ -2059,7 +2100,7 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) return err; } } - sec = wl_read_prof(wl, WL_PROF_SEC); + sec = wl_read_prof(wl, dev, WL_PROF_SEC); sec->wpa_auth = sme->crypto.akm_suites[0]; return err; @@ -2078,7 +2119,7 @@ wl_set_set_sharedkey(struct net_device *dev, WL_DBG(("key len (%d)\n", sme->key_len)); if (sme->key_len) { - sec = wl_read_prof(wl, WL_PROF_SEC); + sec = wl_read_prof(wl, dev, WL_PROF_SEC); WL_DBG(("wpa_versions 0x%x cipher_pairwise 0x%x\n", sec->wpa_versions, sec->cipher_pairwise)); if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 | @@ -2162,11 +2203,11 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, } /* Clean BSSID */ bzero(&bssid, sizeof(bssid)); - wl_update_prof(wl, NULL, (void *)&bssid, WL_PROF_BSSID); + wl_update_prof(wl, dev, NULL, (void *)&bssid, WL_PROF_BSSID); if (IS_P2P_SSID(sme->ssid) && (dev != wl_to_prmry_ndev(wl))) { /* we only allow to connect using virtual interface in case of P2P */ - if (p2p_on(wl) && is_wps_conn(sme)) { + if (p2p_is_on(wl) && is_wps_conn(sme)) { WL_DBG(("ASSOC1 p2p index : %d sme->ie_len %d\n", wl_cfgp2p_find_idx(wl, dev), sme->ie_len)); /* Have to apply WPS IE + P2P IE in assoc req frame */ @@ -2177,7 +2218,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len); wl_cfgp2p_set_management_ie(wl, dev, wl_cfgp2p_find_idx(wl, dev), VNDR_IE_ASSOCREQ_FLAG, sme->ie, sme->ie_len); - } else if (p2p_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) { + } else if (p2p_is_on(wl) && (sme->crypto.wpa_versions & NL80211_WPA_VERSION_2)) { /* This is the connect req after WPS is done [credentials exchanged] * currently identified with WPA_VERSION_2 . * Update the previously set IEs with @@ -2278,7 +2319,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ext_join_params = (wl_extjoin_params_t*)kzalloc(join_params_size, GFP_KERNEL); if (ext_join_params == NULL) { err = -ENOMEM; - wl_clr_drv_status(wl, CONNECTING); + wl_clr_drv_status(wl, CONNECTING, dev); goto exit; } ext_join_params->ssid.SSID_len = min(sizeof(ext_join_params->ssid.SSID), sme->ssid_len); @@ -2287,12 +2328,13 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, /* Set up join scan parameters */ ext_join_params->scan.scan_type = -1; ext_join_params->scan.nprobes = 2; - /* increate dwell time to receive probe response - * from target AP at a noisy air + /* increate dwell time to receive probe response or detect Beacon + * from target AP at a noisy air only during connect command */ - ext_join_params->scan.active_time = 150; - ext_join_params->scan.passive_time = 300; + ext_join_params->scan.active_time = DHD_SCAN_ACTIVE_TIME*3; + ext_join_params->scan.passive_time = DHD_SCAN_PASSIVE_TIME*3; ext_join_params->scan.home_time = -1; + if (sme->bssid) memcpy(&ext_join_params->assoc.bssid, sme->bssid, ETH_ALEN); else @@ -2317,12 +2359,12 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, WL_INFO(("ssid \"%s\", len (%d)\n", ext_join_params->ssid.SSID, ext_join_params->ssid.SSID_len)); } - wl_set_drv_status(wl, CONNECTING); + wl_set_drv_status(wl, CONNECTING, dev); err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, ioctlbuf, sizeof(ioctlbuf), wl_cfgp2p_find_idx(wl, dev)); kfree(ext_join_params); if (err) { - wl_clr_drv_status(wl, CONNECTING); + wl_clr_drv_status(wl, CONNECTING, dev); if (err == BCME_UNSUPPORTED) { WL_DBG(("join iovar is not supported\n")); goto set_ssid; @@ -2338,7 +2380,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, join_params.ssid.SSID_len = min(sizeof(join_params.ssid.SSID), sme->ssid_len); memcpy(&join_params.ssid.SSID, sme->ssid, join_params.ssid.SSID_len); join_params.ssid.SSID_len = htod32(join_params.ssid.SSID_len); - wl_update_prof(wl, NULL, &join_params.ssid, WL_PROF_SSID); + wl_update_prof(wl, dev, NULL, &join_params.ssid, WL_PROF_SSID); if (sme->bssid) memcpy(&join_params.params.bssid, sme->bssid, ETH_ALEN); else @@ -2351,11 +2393,11 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, WL_INFO(("ssid \"%s\", len (%d)\n", join_params.ssid.SSID, join_params.ssid.SSID_len)); } - wl_set_drv_status(wl, CONNECTING); + wl_set_drv_status(wl, CONNECTING, dev); err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true); if (err) { WL_ERR(("error (%d)\n", err)); - wl_clr_drv_status(wl, CONNECTING); + wl_clr_drv_status(wl, CONNECTING, dev); } exit: return err; @@ -2372,23 +2414,23 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, u8 *curbssid; WL_ERR(("Reason %d\n", reason_code)); CHECK_SYS_UP(wl); - act = *(bool *) wl_read_prof(wl, WL_PROF_ACT); - curbssid = wl_read_prof(wl, WL_PROF_BSSID); - if (likely(act)) { + act = *(bool *) wl_read_prof(wl, dev, WL_PROF_ACT); + curbssid = wl_read_prof(wl, dev, WL_PROF_BSSID); + if (act) { /* * Cancel ongoing scan to sync up with sme state machine of cfg80211. */ if (wl->scan_request) { wl_cfg80211_scan_abort(wl, dev); } - wl_set_drv_status(wl, DISCONNECTING); + wl_set_drv_status(wl, DISCONNECTING, dev); scbval.val = reason_code; memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); scbval.val = htod32(scbval.val); err = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), true); if (unlikely(err)) { - wl_clr_drv_status(wl, DISCONNECTING); + wl_clr_drv_status(wl, DISCONNECTING, dev); WL_ERR(("error (%d)\n", err)); return err; } @@ -2507,7 +2549,7 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, struct wl_wsec_key key; s32 err = 0; s32 bssidx = wl_cfgp2p_find_idx(wl, dev); - s32 mode = get_mode_by_netdev(wl, dev); + s32 mode = wl_get_mode_by_netdev(wl, dev); memset(&key, 0, sizeof(key)); key.index = (u32) key_idx; @@ -2603,7 +2645,7 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, u8 keybuf[8]; s32 bssidx = 0; struct wl_priv *wl = wiphy_priv(wiphy); - s32 mode = get_mode_by_netdev(wl, dev); + s32 mode = wl_get_mode_by_netdev(wl, dev); WL_DBG(("key index (%d)\n", key_idx)); CHECK_SYS_UP(wl); @@ -2753,7 +2795,7 @@ wl_cfg80211_get_key(struct wiphy *wiphy, struct net_device *dev, } switch (wsec & ~SES_OW_ENABLED) { case WEP_ENABLED: - sec = wl_read_prof(wl, WL_PROF_SEC); + sec = wl_read_prof(wl, dev, WL_PROF_SEC); if (sec->cipher_pairwise & WLAN_CIPHER_SUITE_WEP40) { params.cipher = WLAN_CIPHER_SUITE_WEP40; WL_DBG(("WLAN_CIPHER_SUITE_WEP40\n")); @@ -2803,7 +2845,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); CHECK_SYS_UP(wl); - if (get_mode_by_netdev(wl, dev) == WL_MODE_AP) { + if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) { err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac, ETHER_ADDR_LEN, ioctlbuf, sizeof(ioctlbuf)); if (err < 0) { @@ -2827,10 +2869,9 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, bcm_ether_ntoa((const struct ether_addr *)mac, eabuf), sinfo->inactive_time, sta->idle * 1000)); #endif - } else if (get_mode_by_netdev(wl, dev) == WL_MODE_BSS) { - u8 *curmacp = wl_read_prof(wl, WL_PROF_BSSID); - - if (!wl_get_drv_status(wl, CONNECTED) || + } else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) { + u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID); + if (!wl_get_drv_status(wl, CONNECTED, dev) || (dhd_is_associated(dhd, NULL) == FALSE)) { WL_ERR(("NOT assoc\n")); err = -ENODEV; @@ -2870,7 +2911,7 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, if (err) { /* Disconnect due to zero BSSID or error to get RSSI */ WL_ERR(("force cfg80211_disconnected\n")); - wl_clr_drv_status(wl, CONNECTED); + wl_clr_drv_status(wl, CONNECTED, dev); cfg80211_disconnected(dev, 0, NULL, 0, GFP_KERNEL); wl_link_down(wl); } @@ -2888,6 +2929,14 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, struct wl_priv *wl = wiphy_priv(wiphy); CHECK_SYS_UP(wl); + + if (wl->p2p_net == dev) { + /* Since p2p0 is a hidden interface in firmware, power + * mgmt doesn't apply. + */ + return err; + } + pm = enabled ? PM_FAST : PM_OFF; /* Do not enable the power save after assoc if it is p2p interface */ if (wl->p2p && wl->p2p->vif_created) { @@ -2937,11 +2986,11 @@ static __used u32 wl_find_msb(u16 bit16) static s32 wl_cfg80211_resume(struct wiphy *wiphy) { struct wl_priv *wl = wiphy_priv(wiphy); + struct net_device *ndev = wl_to_prmry_ndev(wl); s32 err = 0; - if (unlikely(!wl_get_drv_status(wl, READY))) { - WL_INFO(("device is not ready : status (%d)\n", - (int)wl->status)); + if (unlikely(!wl_get_drv_status(wl, READY, ndev))) { + WL_INFO(("device is not ready\n")); return 0; } @@ -2958,29 +3007,34 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy) { #ifdef DHD_CLEAR_ON_SUSPEND struct wl_priv *wl = wiphy_priv(wiphy); + struct net_info *iter, *next; struct net_device *ndev = wl_to_prmry_ndev(wl); unsigned long flags; - if (unlikely(!wl_get_drv_status(wl, READY))) { + if (unlikely(!wl_get_drv_status(wl, READY, ndev))) { WL_INFO(("device is not ready : status (%d)\n", (int)wl->status)); return 0; } - - wl_set_drv_status(wl, SCAN_ABORTING); + for_each_ndev(wl, iter, next) + wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev); wl_term_iscan(wl); flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); if (wl->scan_request) { cfg80211_scan_done(wl->scan_request, true); wl->scan_request = NULL; } - wl_clr_drv_status(wl, SCANNING); - wl_clr_drv_status(wl, SCAN_ABORTING); + for_each_ndev(wl, iter, next) { + wl_clr_drv_status(wl, SCANNING, iter->ndev); + wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev); + } dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags); - if (wl_get_drv_status(wl, CONNECTING)) { - wl_bss_connect_done(wl, ndev, NULL, NULL, false); + for_each_ndev(wl, iter, next) { + if (wl_get_drv_status(wl, CONNECTING, iter->ndev)) { + wl_bss_connect_done(wl, iter->ndev, NULL, NULL, false); + } } -#endif +#endif /* DHD_CLEAR_ON_SUSPEND */ return 0; } @@ -3179,7 +3233,7 @@ wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev) cfg80211_scan_done(wl->scan_request, true); wl->scan_request = NULL; } - wl_clr_drv_status(wl, SCANNING); + wl_clr_drv_status(wl, SCANNING, ndev); dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags); if (params) kfree(params); @@ -3193,22 +3247,36 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, unsigned int duration, u64 *cookie) { s32 target_channel; - + u32 id; + struct net_device *ndev = NULL; s32 err = BCME_OK; struct wl_priv *wl = wiphy_priv(wiphy); dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); WL_DBG(("Enter, netdev_ifidx: %d \n", dev->ifindex)); - if (likely(wl_get_drv_status(wl, SCANNING))) { + + if (wl->p2p_net == dev) { + /* Since there is no ifidx corresponding to p2p0, cmds to + * firmware should be routed through primary I/F + */ + ndev = wl_to_prmry_ndev(wl); + } else { + ndev = dev; + } + + if (wl_get_drv_status(wl, SCANNING, dev)) { wl_cfg80211_scan_abort(wl, dev); } target_channel = ieee80211_frequency_to_channel(channel->center_freq); memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel)); wl->remain_on_chan_type = channel_type; - wl->cache_cookie = *cookie; + id = ++wl->last_roc_id; + if (id == 0) + id = ++wl->last_roc_id; + *cookie = id; cfg80211_ready_on_channel(dev, *cookie, channel, channel_type, duration, GFP_KERNEL); - if (!p2p_on(wl)) { + if (!p2p_is_on(wl)) { wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); /* In case of p2p_listen command, supplicant send remain_on_channel @@ -3222,7 +3290,7 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, goto exit; } } - if (p2p_on(wl)) + if (p2p_is_on(wl)) wl_cfgp2p_discover_listen(wl, target_channel, duration); @@ -3240,7 +3308,7 @@ wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev } static s32 -wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, +wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, struct ieee80211_channel *channel, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, @@ -3252,6 +3320,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, wpa_ie_fixed_t *wps_ie; const struct ieee80211_mgmt *mgmt; struct wl_priv *wl = wiphy_priv(wiphy); + struct net_device *dev = NULL; dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); s32 err = BCME_OK; s32 bssidx = 0; @@ -3260,7 +3329,20 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, u16 fc; bool ack = false; wifi_p2p_pub_act_frame_t *act_frm; + WL_DBG(("Enter \n")); + + if (ndev == wl->p2p_net) { + /* Firmware doesn't have an ifidx corresponding to p2p0 interface. + * so divert commands received on p2p0 to wlan0. Note that the TX status + * will be sent back to the interface(ndev) on which request is received + */ + dev = wl_to_prmry_ndev(wl); + } else { + /* If TX req is for any valid ifidx. Use as is */ + dev = ndev; + } + /* find bssidx based on ndev */ bssidx = wl_cfgp2p_find_idx(wl, dev); /* cookie generation */ @@ -3271,7 +3353,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("Can not find the bssidx for dev( %p )\n", dev)); return -ENODEV; } - if (wl->p2p_supported && p2p_on(wl)) { + if (p2p_is_on(wl)) { wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); /* Suspend P2P discovery search-listen to prevent it from changing the * channel. @@ -3292,13 +3374,6 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, != NULL) { /* Total length of P2P Information Element */ p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id); - /* Have to change p2p device address in dev_info attribute - * because Supplicant use primary eth0 address - */ - #ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */ - wl_cfg80211_change_ifaddr((u8 *)p2p_ie, - &wl->p2p_dev_addr, P2P_SEID_DEV_INFO); - #endif } if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)(buf + ie_offset), ie_len)) != NULL) { @@ -3314,7 +3389,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, (u8 *)wps_ie, wpsie_len + p2pie_len); } } - cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_KERNEL); + cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); goto exit; } else { /* Abort the dwell time of any previous off-channel action frame that may @@ -3350,6 +3425,14 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, af_params->channel = ieee80211_frequency_to_channel(channel->center_freq); + if (channel->band == IEEE80211_BAND_5GHZ) { + err = wldev_ioctl(dev, WLC_SET_CHANNEL, + &af_params->channel, sizeof(af_params->channel), true); + if (err < 0) { + WL_ERR(("WLC_SET_CHANNEL error %d\n", err)); + } + } + /* Add the dwell time * Dwell time to stay off-channel to wait for a response action frame * after transmitting an GO Negotiation action frame @@ -3377,7 +3460,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, } ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true; - cfg80211_mgmt_tx_status(dev, *cookie, buf, len, ack, GFP_KERNEL); + cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL); kfree(af_params); exit: @@ -3432,7 +3515,14 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, { s32 channel; s32 err = BCME_OK; + struct wl_priv *wl = wiphy_priv(wiphy); + if (wl->p2p_net == dev) { + /* Since there is no ifidx corresponding to p2p0, cmds to + * firmware should be routed through primary I/F + */ + dev = wl_to_prmry_ndev(wl); + } channel = ieee80211_frequency_to_channel(chan->center_freq); WL_DBG(("netdev_ifidx(%d), chan_type(%d) target channel(%d) \n", dev->ifindex, channel_type, channel)); @@ -3713,13 +3803,22 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, u16 p2pie_len = 0; u8 beacon_ie[IE_MAX_LEN]; s32 ie_offset = 0; - s32 bssidx = wl_cfgp2p_find_idx(wl, dev); + s32 bssidx = 0; s32 infra = 1; s32 join_params_size = 0; s32 ap = 0; WL_DBG(("interval (%d) dtim_period (%d) head_len (%d) tail_len (%d)\n", info->interval, info->dtim_period, info->head_len, info->tail_len)); - if (wl->p2p_supported && p2p_on(wl) && + + if (wl->p2p_net == dev) { + /* Since there is no ifidx corresponding to p2p0, cmds to + * firmware should be routed through primary I/F + */ + dev = wl_to_prmry_ndev(wl); + } + + bssidx = wl_cfgp2p_find_idx(wl, dev); + if (p2p_is_on(wl) && (bssidx == wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION))) { memset(beacon_ie, 0, sizeof(beacon_ie)); @@ -3757,12 +3856,6 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)info->tail, info->tail_len)) != NULL) { /* Total length of P2P Information Element */ p2pie_len = p2p_ie->len + sizeof(p2p_ie->len) + sizeof(p2p_ie->id); - #ifdef ENABLE_DRIVER_CHANGE_IFADDR /* We are now doing this in supplicant */ - /* Have to change device address in dev_id attribute because Supplicant - * use primary eth0 address - */ - wl_cfg80211_change_ifaddr((u8 *)p2p_ie, &wl->p2p_dev_addr, P2P_SEID_DEV_ID); - #endif memcpy(&beacon_ie[wpsie_len], p2p_ie, p2pie_len); } else { @@ -3802,7 +3895,7 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, goto exit; } } - } else if (wl_get_drv_status(wl, AP_CREATING)) { + } else if (wl_get_drv_status(wl, AP_CREATING, dev)) { ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; ap = 1; /* find the SSID */ @@ -3908,11 +4001,11 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, /* create softap */ if ((err = wldev_ioctl(dev, WLC_SET_SSID, &join_params, join_params_size, true)) == 0) { - wl_clr_drv_status(wl, AP_CREATING); - wl_set_drv_status(wl, AP_CREATED); + wl_clr_drv_status(wl, AP_CREATING, dev); + wl_set_drv_status(wl, AP_CREATED, dev); } } - } else if (wl_get_drv_status(wl, AP_CREATED)) { + } else if (wl_get_drv_status(wl, AP_CREATED, dev)) { ap = 1; /* find the WPSIE */ if ((wps_ie = wl_cfgp2p_find_wpsie((u8 *)info->tail, info->tail_len)) != NULL) { @@ -4053,7 +4146,7 @@ static struct cfg80211_ops wl_cfg80211_ops = { .add_beacon = wl_cfg80211_add_set_beacon, }; -static s32 wl_mode_to_nl80211_iftype(s32 mode) +s32 wl_mode_to_nl80211_iftype(s32 mode) { s32 err = 0; @@ -4139,24 +4232,15 @@ static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev) static void wl_free_wdev(struct wl_priv *wl) { - int i; struct wireless_dev *wdev = wl->wdev; - - if (unlikely(!wdev)) { + if (!wdev) { WL_ERR(("wdev is invalid\n")); return; } - - for (i = 0; i < VWDEV_CNT; i++) { - if ((wl->vwdev[i] != NULL)) { - kfree(wl->vwdev[i]); - wl->vwdev[i] = NULL; - } - } wiphy_unregister(wdev->wiphy); wdev->wiphy->dev.parent = NULL; wiphy_free(wdev->wiphy); - kfree(wdev); + wl_delete_all_netinfo(wl); } static s32 wl_inform_bss(struct wl_priv *wl) @@ -4336,8 +4420,10 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, memset(body, 0, sizeof(body)); memset(&bssid, 0, ETHER_ADDR_LEN); WL_DBG(("Enter \n")); + if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID) + return WL_INVALID; - if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { + if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { memcpy(body, data, len); wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx); @@ -4398,21 +4484,20 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, if (wl_is_linkup(wl, e, ndev)) { wl_link_up(wl); act = true; - wl_update_prof(wl, e, &act, WL_PROF_ACT); - wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); + wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT); + wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); if (wl_is_ibssmode(wl, ndev)) { printk("cfg80211_ibss_joined\n"); cfg80211_ibss_joined(ndev, (s8 *)&e->addr, GFP_KERNEL); WL_DBG(("joined in IBSS network\n")); } else { - if (!wl_get_drv_status(wl, DISCONNECTING)) { - printk("wl_bss_connect_done succeeded status=(0x%x)\n", - (int)wl->status); + if (!wl_get_drv_status(wl, DISCONNECTING, ndev)) { + printk("wl_bss_connect_done succeeded\n"); wl_bss_connect_done(wl, ndev, e, data, true); WL_DBG(("joined in BSS network \"%s\"\n", ((struct wlc_ssid *) - wl_read_prof(wl, WL_PROF_SSID))->SSID)); + wl_read_prof(wl, ndev, WL_PROF_SSID))->SSID)); } } @@ -4420,15 +4505,15 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, if (wl->scan_request) { del_timer_sync(&wl->scan_timeout); if (wl->escan_on) { - wl_notify_escan_complete(wl, true); + wl_notify_escan_complete(wl, ndev, true); } else wl_iscan_aborted(wl); } - if (wl_get_drv_status(wl, CONNECTED)) { + if (wl_get_drv_status(wl, CONNECTED, ndev)) { scb_val_t scbval; - u8 *curbssid = wl_read_prof(wl, WL_PROF_BSSID); + u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); printk("link down, call cfg80211_disconnected\n"); - wl_clr_drv_status(wl, CONNECTED); + wl_clr_drv_status(wl, CONNECTED, ndev); /* To make sure disconnect, explictly send dissassoc * for BSSID 00:00:00:00:00:00 issue */ @@ -4440,12 +4525,12 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, sizeof(scb_val_t), true); cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); wl_link_down(wl); - wl_init_prof(wl); - } else if (wl_get_drv_status(wl, CONNECTING)) { + wl_init_prof(wl, ndev); + } else if (wl_get_drv_status(wl, CONNECTING, ndev)) { printk("link down, during connecting\n"); wl_bss_connect_done(wl, ndev, e, data, false); } - wl_clr_drv_status(wl, DISCONNECTING); + wl_clr_drv_status(wl, DISCONNECTING, ndev); } else if (wl_is_nonetwork(wl, e)) { printk("connect failed event=%d e->status 0x%x\n", @@ -4454,11 +4539,11 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, if (wl->scan_request) { del_timer_sync(&wl->scan_timeout); if (wl->escan_on) { - wl_notify_escan_complete(wl, true); + wl_notify_escan_complete(wl, ndev, true); } else wl_iscan_aborted(wl); } - if (wl_get_drv_status(wl, CONNECTING)) + if (wl_get_drv_status(wl, CONNECTING, ndev)) wl_bss_connect_done(wl, ndev, e, data, false); } else { printk("%s nothing\n", __FUNCTION__); @@ -4480,13 +4565,13 @@ wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev, u32 status = be32_to_cpu(e->status); WL_DBG(("Enter \n")); if (event == WLC_E_ROAM && status == WLC_E_STATUS_SUCCESS) { - if (wl_get_drv_status(wl, CONNECTED)) + if (wl_get_drv_status(wl, CONNECTED, ndev)) wl_bss_roaming_done(wl, ndev, e, data); else wl_bss_connect_done(wl, ndev, e, data, true); act = true; - wl_update_prof(wl, e, &act, WL_PROF_ACT); - wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); + wl_update_prof(wl, ndev, e, &act, WL_PROF_ACT); + wl_update_prof(wl, ndev, NULL, (void *)&e->addr, WL_PROF_BSSID); } return err; } @@ -4646,14 +4731,14 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) if (wl_is_ibssmode(wl, ndev)) return err; - ssid = (struct wlc_ssid *)wl_read_prof(wl, WL_PROF_SSID); - curbssid = wl_read_prof(wl, WL_PROF_BSSID); + ssid = (struct wlc_ssid *)wl_read_prof(wl, ndev, WL_PROF_SSID); + curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); bss = cfg80211_get_bss(wiphy, NULL, curbssid, ssid->SSID, ssid->SSID_len, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); mutex_lock(&wl->usr_sync); - if (unlikely(!bss)) { + if (!bss) { WL_DBG(("Could not find the AP\n")); *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); err = wldev_ioctl(ndev, WLC_GET_BSS_INFO, @@ -4699,8 +4784,8 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) } } - wl_update_prof(wl, NULL, &beacon_interval, WL_PROF_BEACONINT); - wl_update_prof(wl, NULL, &dtim_period, WL_PROF_DTIMPERIOD); + wl_update_prof(wl, ndev, NULL, &beacon_interval, WL_PROF_BEACONINT); + wl_update_prof(wl, ndev, NULL, &dtim_period, WL_PROF_DTIMPERIOD); update_bss_info_out: mutex_unlock(&wl->usr_sync); @@ -4716,8 +4801,8 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, u8 *curbssid; wl_get_assoc_ies(wl, ndev); - wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); - curbssid = wl_read_prof(wl, WL_PROF_BSSID); + wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); + curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); wl_update_bss_info(wl, ndev); wl_update_pmklist(ndev, wl->pmk_list, err); cfg80211_roamed(ndev, @@ -4729,7 +4814,7 @@ wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL); WL_DBG(("Report roaming result\n")); - wl_set_drv_status(wl, CONNECTED); + wl_set_drv_status(wl, CONNECTED, ndev); return err; } @@ -4740,20 +4825,20 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, { struct wl_connect_info *conn_info = wl_to_conn(wl); s32 err = 0; - u8 *curbssid = wl_read_prof(wl, WL_PROF_BSSID); + u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); WL_DBG((" enter\n")); if (wl->scan_request) { wl_cfg80211_scan_abort(wl, ndev); } - if (wl_get_drv_status(wl, CONNECTING)) { - wl_clr_drv_status(wl, CONNECTING); + if (wl_get_drv_status(wl, CONNECTING, ndev)) { + wl_clr_drv_status(wl, CONNECTING, ndev); if (completed) { wl_get_assoc_ies(wl, ndev); - wl_update_prof(wl, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); - curbssid = wl_read_prof(wl, WL_PROF_BSSID); + wl_update_prof(wl, ndev, NULL, (void *)(e->addr.octet), WL_PROF_BSSID); + curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); wl_update_bss_info(wl, ndev); wl_update_pmklist(ndev, wl->pmk_list, err); - wl_set_drv_status(wl, CONNECTED); + wl_set_drv_status(wl, CONNECTED, ndev); } cfg80211_connect_result(ndev, curbssid, @@ -4815,11 +4900,15 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, unsigned long flags; WL_DBG(("Enter \n")); + if (!wl_get_drv_status(wl, SCANNING, ndev)) { + WL_ERR(("scan is not ready \n")); + return err; + } if (wl->iscan_on && wl->iscan_kickstart) return wl_wakeup_iscan(wl_to_iscan(wl)); mutex_lock(&wl->usr_sync); - wl_clr_drv_status(wl, SCANNING); + wl_clr_drv_status(wl, SCANNING, ndev); err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, sizeof(channel_inform), false); if (unlikely(err)) { @@ -4912,6 +5001,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, bool isfree = false; s32 err = 0; s32 freq; + struct net_device *dev = NULL; wifi_p2p_pub_act_frame_t *act_frm; wl_event_rx_frame_data_t *rxframe = (wl_event_rx_frame_data_t*)data; @@ -4922,6 +5012,16 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, u16 channel = ((ntoh16(rxframe->channel) & WL_CHANSPEC_CHAN_MASK)); memset(&bssid, 0, ETHER_ADDR_LEN); + + if (wl->p2p_net == ndev) { + /* Since there is no ifidx corresponding to p2p0, cmds to + * firmware should be routed through primary I/F + */ + dev = wl_to_prmry_ndev(wl); + } else { + dev = ndev; + } + if (channel <= CH_MAX_2G_CHANNEL) band = wiphy->bands[IEEE80211_BAND_2GHZ]; else @@ -4933,10 +5033,10 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, freq = ieee80211_channel_to_frequency(channel, band->band); #endif if (event == WLC_E_ACTION_FRAME_RX) { - wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", + wldev_iovar_getbuf_bsscfg(dev, "cur_etheraddr", NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx); - wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN); err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid, &mgmt_frame, &mgmt_frame_len, @@ -4953,7 +5053,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, * After complete GO Negotiation, roll back to mpc mode */ if (act_frm->subtype == P2P_PAF_GON_CONF) { - wldev_iovar_setint(ndev, "mpc", 1); + wldev_iovar_setint(dev, "mpc", 1); } } else { mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); @@ -4972,12 +5072,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, static void wl_init_conf(struct wl_conf *conf) { - s32 i = 0; WL_DBG(("Enter \n")); - for (i = 0; i <= VWDEV_CNT; i++) { - conf->mode[i].type = -1; - conf->mode[i].ndev = NULL; - } conf->frag_threshold = (u32)-1; conf->rts_threshold = (u32)-1; conf->retry_short = (u32)-1; @@ -4985,12 +5080,12 @@ static void wl_init_conf(struct wl_conf *conf) conf->tx_power = -1; } -static void wl_init_prof(struct wl_priv *wl) +static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev) { unsigned long flags; - + struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); - memset(wl->profile, 0, sizeof(struct wl_profile)); + memset(profile, 0, sizeof(struct wl_profile)); dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags); } @@ -5030,16 +5125,6 @@ static s32 wl_init_priv_mem(struct wl_priv *wl) WL_ERR(("wl_conf alloc failed\n")); goto init_priv_mem_out; } - wl->profile = (void *)kzalloc(sizeof(*wl->profile), GFP_KERNEL); - if (unlikely(!wl->profile)) { - WL_ERR(("wl_profile alloc failed\n")); - goto init_priv_mem_out; - } - wl->bss_info = (void *)kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL); - if (unlikely(!wl->bss_info)) { - WL_ERR(("Bss information alloc failed\n")); - goto init_priv_mem_out; - } wl->scan_req_int = (void *)kzalloc(sizeof(*wl->scan_req_int), GFP_KERNEL); if (unlikely(!wl->scan_req_int)) { @@ -5093,12 +5178,8 @@ static void wl_deinit_priv_mem(struct wl_priv *wl) { kfree(wl->scan_results); wl->scan_results = NULL; - kfree(wl->bss_info); - wl->bss_info = NULL; kfree(wl->conf); wl->conf = NULL; - kfree(wl->profile); - wl->profile = NULL; kfree(wl->scan_req_int); wl->scan_req_int = NULL; kfree(wl->ioctl_buf); @@ -5159,16 +5240,17 @@ static void wl_term_iscan(struct wl_priv *wl) static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted) { struct wl_priv *wl = iscan_to_wl(iscan); + struct net_device *ndev = wl_to_prmry_ndev(wl); unsigned long flags; WL_DBG(("Enter \n")); - if (unlikely(!wl_get_drv_status(wl, SCANNING))) { - wl_clr_drv_status(wl, SCANNING); + if (!wl_get_drv_status(wl, SCANNING, ndev)) { + wl_clr_drv_status(wl, SCANNING, ndev); WL_ERR(("Scan complete while device not scanning\n")); return; } flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); - wl_clr_drv_status(wl, SCANNING); + wl_clr_drv_status(wl, SCANNING, ndev); if (likely(wl->scan_request)) { cfg80211_scan_done(wl->scan_request, aborted); wl->scan_request = NULL; @@ -5323,7 +5405,7 @@ static void wl_scan_timeout(unsigned long data) if (wl->scan_request) { WL_ERR(("timer expired\n")); if (wl->escan_on) - wl_notify_escan_complete(wl, true); + wl_notify_escan_complete(wl, wl->escan_info.ndev, true); else wl_notify_iscan_complete(wl_to_iscan(wl), true); } @@ -5369,13 +5451,39 @@ static void wl_init_iscan_handler(struct wl_iscan_ctrl *iscan) iscan->iscan_handler[WL_SCAN_RESULTS_NO_MEM] = wl_iscan_aborted; } -static void wl_notify_escan_complete(struct wl_priv *wl, bool aborted) +static s32 +wl_cfg80211_netdev_notifier_call(struct notifier_block * nb, + unsigned long state, + void *ndev) +{ + struct net_device *dev = ndev; + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wl_priv *wl = wlcfg_drv_priv; + + WL_DBG(("Enter \n")); + if (!wdev || dev == wl_to_prmry_ndev(wl)) + return NOTIFY_DONE; + switch (state) { + case NETDEV_UNREGISTER: + /* after calling list_del_rcu(&wdev->list) */ + wl_dealloc_netinfo(wl, ndev); + break; + } + return NOTIFY_DONE; +} +static struct notifier_block wl_cfg80211_netdev_notifier = { + .notifier_call = wl_cfg80211_netdev_notifier_call, +}; + +static void wl_notify_escan_complete(struct wl_priv *wl, + struct net_device *ndev, + bool aborted) { unsigned long flags; WL_DBG(("Enter \n")); - wl_clr_drv_status(wl, SCANNING); - if (wl->p2p_supported && p2p_on(wl)) + wl_clr_drv_status(wl, SCANNING, ndev); + if (p2p_is_on(wl)) wl_clr_p2p_status(wl, SCANNING); flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); @@ -5400,8 +5508,11 @@ static s32 wl_escan_handler(struct wl_priv *wl, u32 i; WL_DBG((" enter event type : %d, status : %d \n", ntoh32(e->event_type), ntoh32(e->status))); - if (!wl->escan_on && - !wl_get_drv_status(wl, SCANNING)) { + /* P2P SCAN is coming from primary interface */ + if (wl_get_p2p_status(wl, SCANNING)) + ndev = wl->escan_info.ndev; + if (!ndev || !wl->escan_on || + !wl_get_drv_status(wl, SCANNING, ndev)) { WL_ERR(("escan is not ready \n")); return err; } @@ -5473,7 +5584,7 @@ static s32 wl_escan_handler(struct wl_priv *wl, WL_INFO(("ESCAN COMPLETED\n")); wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; wl_inform_bss(wl); - wl_notify_escan_complete(wl, false); + wl_notify_escan_complete(wl, ndev, false); mutex_unlock(&wl->usr_sync); } } @@ -5485,7 +5596,7 @@ static s32 wl_escan_handler(struct wl_priv *wl, WL_INFO(("ESCAN ABORTED\n")); wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; wl_inform_bss(wl); - wl_notify_escan_complete(wl, true); + wl_notify_escan_complete(wl, ndev, true); mutex_unlock(&wl->usr_sync); } } @@ -5497,7 +5608,7 @@ static s32 wl_escan_handler(struct wl_priv *wl, del_timer_sync(&wl->scan_timeout); wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; wl_inform_bss(wl); - wl_notify_escan_complete(wl, true); + wl_notify_escan_complete(wl, ndev, true); mutex_unlock(&wl->usr_sync); } } @@ -5546,9 +5657,8 @@ static void wl_init_fw(struct wl_fw_ctrl *fw) static s32 wl_init_priv(struct wl_priv *wl) { struct wiphy *wiphy = wl_to_wiphy(wl); + struct net_device *ndev = wl_to_prmry_ndev(wl); s32 err = 0; - s32 i = 0; - wl->scan_request = NULL; wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT); wl->iscan_on = false; @@ -5559,24 +5669,21 @@ static s32 wl_init_priv(struct wl_priv *wl) wl->dongle_up = false; wl->rf_blocked = false; - for (i = 0; i < VWDEV_CNT; i++) - wl->vwdev[i] = NULL; - init_waitqueue_head(&wl->dongle_event_wait); wl_init_eq(wl); err = wl_init_priv_mem(wl); - if (unlikely(err)) + if (err) return err; - if (unlikely(wl_create_event_handler(wl))) + if (wl_create_event_handler(wl)) return -ENOMEM; wl_init_event_handler(wl); mutex_init(&wl->usr_sync); err = wl_init_scan(wl); - if (unlikely(err)) + if (err) return err; wl_init_fw(wl->fw); wl_init_conf(wl->conf); - wl_init_prof(wl); + wl_init_prof(wl, ndev); wl_link_down(wl); return err; @@ -5591,25 +5698,45 @@ static void wl_deinit_priv(struct wl_priv *wl) del_timer_sync(&wl->scan_timeout); wl_term_iscan(wl); wl_deinit_priv_mem(wl); + unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier); } -#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL) -s32 wl_cfg80211_sysctl_export_devaddr(void *data) +#if defined(WLP2P) && ENABLE_P2P_INTERFACE +static s32 wl_cfg80211_attach_p2p(void) +{ + struct wl_priv *wl = wlcfg_drv_priv; + + WL_TRACE(("Enter \n")); + + if (wl_cfgp2p_register_ndev(wl) < 0) { + WL_ERR(("%s: P2P attach failed. \n", __func__)); + return -ENODEV; + } + + return 0; +} + +static s32 wl_cfg80211_detach_p2p(void) { - /* Export the p2p_dev_addr via sysctl interface - * so that wpa_supplicant can access it - */ - dhd_pub_t *dhd = (dhd_pub_t *)data; struct wl_priv *wl = wlcfg_drv_priv; + struct wireless_dev *wdev = wl->p2p_wdev; + + WL_TRACE(("Enter \n")); + if (!wdev || !wl) { + WL_ERR(("Invalid Ptr\n")); + return -EINVAL; + } + + wl_cfgp2p_unregister_ndev(wl); - wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); + wl->p2p_wdev = NULL; + wl->p2p_net = NULL; - sprintf((char *)&wl_sysctl_macstring[0], MACSTR, MAC2STR(wl->p2p->dev_addr.octet)); - sprintf((char *)&wl_sysctl_macstring[1], MACSTR, MAC2STR(wl->p2p->int_addr.octet)); + kfree(wdev); return 0; } -#endif /* CONFIG_SYSCTL */ +#endif /* defined(WLP2P) && (ENABLE_P2P_INTERFACE) */ s32 wl_cfg80211_attach_post(struct net_device *ndev) { @@ -5621,7 +5748,7 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) return -ENODEV; } wl = wlcfg_drv_priv; - if (wl && !wl_get_drv_status(wl, READY)) { + if (wl && !wl_get_drv_status(wl, READY, ndev)) { if (wl->wdev && wl_cfgp2p_supported(wl, ndev)) { wl->wdev->wiphy->interface_modes |= @@ -5629,67 +5756,90 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) BIT(NL80211_IFTYPE_P2P_GO)); if ((err = wl_cfgp2p_init_priv(wl)) != 0) goto fail; -#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL) - wl_cfg80211_sysctl_export_devaddr(wl->pub); -#endif + +#if defined(WLP2P) && ENABLE_P2P_INTERFACE + if (wl->p2p_net) { + /* Update MAC addr for p2p0 interface here. */ + memcpy(wl->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN); + wl->p2p_net->dev_addr[0] |= 0x02; + printk("%s: p2p_dev_addr="MACSTR "\n", + wl->p2p_net->name, MAC2STR(wl->p2p_net->dev_addr)); + } else { + WL_ERR(("p2p_net not yet populated." + " Couldn't update the MAC Address for p2p0 \n")); + return -ENODEV; + } +#endif /* defined(WLP2P) && (ENABLE_P2P_INTERFACE) */ + wl->p2p_supported = true; } } else return -ENODEV; - - wl_set_drv_status(wl, READY); + wl_set_drv_status(wl, READY, ndev); fail: return err; } + s32 wl_cfg80211_attach(struct net_device *ndev, void *data) { struct wireless_dev *wdev; struct wl_priv *wl; s32 err = 0; + struct device *dev; WL_TRACE(("In\n")); - if (unlikely(!ndev)) { + if (!ndev) { WL_ERR(("ndev is invaild\n")); return -ENODEV; } - WL_DBG(("func %p\n", wl_cfg80211_get_sdio_func())); - wdev = wl_alloc_wdev(&wl_cfg80211_get_sdio_func()->dev); - if (unlikely(IS_ERR(wdev))) + WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev())); + dev = wl_cfg80211_get_parent_dev(); + wdev = wl_alloc_wdev(dev); + if (IS_ERR(wdev)) return -ENOMEM; wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); wl = (struct wl_priv *)wiphy_priv(wdev->wiphy); wl->wdev = wdev; wl->pub = data; - + INIT_LIST_HEAD(&wl->net_list); ndev->ieee80211_ptr = wdev; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; - + err = wl_alloc_netinfo(wl, ndev, wdev, WL_MODE_BSS); + if (err) { + WL_ERR(("Failed to alloc net_info (%d)\n", err)); + goto cfg80211_attach_out; + } err = wl_init_priv(wl); - if (unlikely(err)) { + if (err) { WL_ERR(("Failed to init iwm_priv (%d)\n", err)); goto cfg80211_attach_out; } err = wl_setup_rfkill(wl, TRUE); - if (unlikely(err)) { + if (err) { WL_ERR(("Failed to setup rfkill %d\n", err)); goto cfg80211_attach_out; } - -#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL) - if (!(wl_sysctl_hdr = register_sysctl_table(wl_sysctl_table))) { - WL_ERR(("%s: sysctl register failed!! \n", __func__)); + err = register_netdevice_notifier(&wl_cfg80211_netdev_notifier); + if (err) { + WL_ERR(("Failed to register notifierl %d\n", err)); goto cfg80211_attach_out; } -#endif #if defined(COEX_DHCP) if (wl_cfg80211_btcoex_init(wl)) goto cfg80211_attach_out; #endif /* COEX_DHCP */ wlcfg_drv_priv = wl; + +#if defined(WLP2P) && ENABLE_P2P_INTERFACE + err = wl_cfg80211_attach_p2p(); + if (err) + goto cfg80211_attach_out; +#endif + return err; cfg80211_attach_out: @@ -5710,16 +5860,15 @@ void wl_cfg80211_detach(void) wl_cfg80211_btcoex_deinit(wl); #endif /* COEX_DHCP */ -#if defined(DHD_P2P_DEV_ADDR_FROM_SYSFS) && defined(CONFIG_SYSCTL) - if (wl_sysctl_hdr) - unregister_sysctl_table(wl_sysctl_hdr); +#if defined(WLP2P) && ENABLE_P2P_INTERFACE + wl_cfg80211_detach_p2p(); #endif wl_setup_rfkill(wl, FALSE); if (wl->p2p_supported) wl_cfgp2p_deinit_priv(wl); wl_deinit_priv(wl); wlcfg_drv_priv = NULL; - wl_clear_sdio_func(); + wl_cfg80211_clear_parent_dev(); wl_free_wdev(wl); } @@ -5731,6 +5880,42 @@ static void wl_wakeup_event(struct wl_priv *wl) } } +static int wl_is_p2p_event(struct wl_event_q *e) +{ + switch (e->etype) { + /* We have to seperate out the P2P events received + * on primary interface so that it can be send up + * via p2p0 interface. + */ + case WLC_E_P2P_PROBREQ_MSG: + case WLC_E_P2P_DISC_LISTEN_COMPLETE: + case WLC_E_ACTION_FRAME_RX: + case WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE: + case WLC_E_ACTION_FRAME_COMPLETE: + + if (e->emsg.ifidx != 0) { + WL_TRACE(("P2P Event on Virtual I/F (ifidx:%d) \n", + e->emsg.ifidx)); + /* We are only bothered about the P2P events received + * on primary interface. For rest of them return false + * so that it is sent over the interface corresponding + * to the ifidx. + */ + return FALSE; + } else { + WL_TRACE(("P2P Event on Primary I/F (ifidx:%d)." + " Sent it to p2p0 \n", e->emsg.ifidx)); + return TRUE; + } + break; + + default: + WL_TRACE(("NON-P2P Event %d on ifidx (ifidx:%d) \n", + e->etype, e->emsg.ifidx)); + return FALSE; + } +} + static s32 wl_event_handler(void *data) { struct net_device *netdev; @@ -5747,9 +5932,20 @@ static s32 wl_event_handler(void *data) break; while ((e = wl_deq_event(wl))) { WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx)); - netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx); - if (!netdev) - netdev = wl_to_prmry_ndev(wl); + + /* All P2P device address related events comes on primary interface since + * there is no corresponding interface in the firmware. Map it to p2p0 + * interface. + */ + if ((wl_is_p2p_event(e) == TRUE) && (wl->p2p_net)) { + netdev = wl->p2p_net; + } else { + netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx); + if (!netdev) { + netdev = wl_to_prmry_ndev(wl); + } + } + if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) { wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata); } else { @@ -5860,21 +6056,6 @@ static void wl_put_event(struct wl_event_q *e) kfree(e); } -void wl_cfg80211_set_sdio_func(void *func) -{ - cfg80211_sdio_func = (struct sdio_func *)func; -} - -static void wl_clear_sdio_func(void) -{ - cfg80211_sdio_func = NULL; -} - -struct sdio_func *wl_cfg80211_get_sdio_func(void) -{ - return cfg80211_sdio_func; -} - static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype) { s32 infra = 0; @@ -5912,7 +6093,7 @@ static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftyp return err; } - set_mode_by_netdev(wl, ndev, mode); + wl_set_mode_by_netdev(wl, ndev, mode); return 0; } @@ -6276,14 +6457,11 @@ s32 wl_config_dongle(struct wl_priv *wl, bool need_lock) goto default_conf_out; } - /* -EINPROGRESS: Call commit handler */ - + wl->dongle_up = true; default_conf_out: if (need_lock) rtnl_unlock(); - wl->dongle_up = true; - return err; } @@ -6315,16 +6493,16 @@ static s32 wl_update_wiphybands(struct wl_priv *wl) static s32 __wl_cfg80211_up(struct wl_priv *wl) { s32 err = 0; - + struct net_device *ndev = wl_to_prmry_ndev(wl); WL_TRACE(("In\n")); - wl_debugfs_add_netdev_params(wl); + wl_debugfs_add_netdev_params(wl, ndev); err = wl_config_dongle(wl, false); if (unlikely(err)) return err; dhd_monitor_init(wl->pub); wl_invoke_iscan(wl); - wl_set_drv_status(wl, READY); + wl_set_drv_status(wl, READY, ndev); return err; } @@ -6332,13 +6510,14 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) { s32 err = 0; unsigned long flags; - + struct net_info *iter, *next; + struct net_device *ndev = wl_to_prmry_ndev(wl); WL_TRACE(("In\n")); /* Check if cfg80211 interface is already down */ - if (!wl_get_drv_status(wl, READY)) + if (!wl_get_drv_status(wl, READY, ndev)) return err; /* it is even not ready */ - - wl_set_drv_status(wl, SCAN_ABORTING); + for_each_ndev(wl, iter, next) + wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev); wl_term_iscan(wl); flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); @@ -6346,15 +6525,15 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) cfg80211_scan_done(wl->scan_request, true); wl->scan_request = NULL; } - wl_clr_drv_status(wl, READY); - wl_clr_drv_status(wl, SCANNING); - wl_clr_drv_status(wl, SCAN_ABORTING); - wl_clr_drv_status(wl, CONNECTING); - wl_clr_drv_status(wl, CONNECTED); - wl_clr_drv_status(wl, DISCONNECTING); - if (wl_get_drv_status(wl, AP_CREATED)) { - wl_clr_drv_status(wl, AP_CREATED); - wl_clr_drv_status(wl, AP_CREATING); + for_each_ndev(wl, iter, next) { + wl_clr_drv_status(wl, READY, iter->ndev); + wl_clr_drv_status(wl, SCANNING, iter->ndev); + wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev); + wl_clr_drv_status(wl, CONNECTING, iter->ndev); + wl_clr_drv_status(wl, CONNECTED, iter->ndev); + wl_clr_drv_status(wl, DISCONNECTING, iter->ndev); + wl_clr_drv_status(wl, AP_CREATED, iter->ndev); + wl_clr_drv_status(wl, AP_CREATING, iter->ndev); } wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; @@ -6428,24 +6607,26 @@ static s32 wl_dongle_probecap(struct wl_priv *wl) return err; } -static void *wl_read_prof(struct wl_priv *wl, s32 item) +static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item) { unsigned long flags; void *rptr = NULL; - + struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); + if (!profile) + return NULL; flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); switch (item) { case WL_PROF_SEC: - rptr = &wl->profile->sec; + rptr = &profile->sec; break; case WL_PROF_ACT: - rptr = &wl->profile->active; + rptr = &profile->active; break; case WL_PROF_BSSID: - rptr = &wl->profile->bssid; + rptr = profile->bssid; break; case WL_PROF_SSID: - rptr = &wl->profile->ssid; + rptr = &profile->ssid; break; } dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags); @@ -6455,39 +6636,41 @@ static void *wl_read_prof(struct wl_priv *wl, s32 item) } static s32 -wl_update_prof(struct wl_priv *wl, const wl_event_msg_t *e, void *data, - s32 item) +wl_update_prof(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data, s32 item) { s32 err = 0; struct wlc_ssid *ssid; unsigned long flags; - + struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); + if (!profile) + return WL_INVALID; flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); switch (item) { case WL_PROF_SSID: ssid = (wlc_ssid_t *) data; - memset(wl->profile->ssid.SSID, 0, - sizeof(wl->profile->ssid.SSID)); - memcpy(wl->profile->ssid.SSID, ssid->SSID, ssid->SSID_len); - wl->profile->ssid.SSID_len = ssid->SSID_len; + memset(profile->ssid.SSID, 0, + sizeof(profile->ssid.SSID)); + memcpy(profile->ssid.SSID, ssid->SSID, ssid->SSID_len); + profile->ssid.SSID_len = ssid->SSID_len; break; case WL_PROF_BSSID: if (data) - memcpy(wl->profile->bssid, data, ETHER_ADDR_LEN); + memcpy(profile->bssid, data, ETHER_ADDR_LEN); else - memset(wl->profile->bssid, 0, ETHER_ADDR_LEN); + memset(profile->bssid, 0, ETHER_ADDR_LEN); break; case WL_PROF_SEC: - memcpy(&wl->profile->sec, data, sizeof(wl->profile->sec)); + memcpy(&profile->sec, data, sizeof(profile->sec)); break; case WL_PROF_ACT: - wl->profile->active = *(bool *)data; + profile->active = *(bool *)data; break; case WL_PROF_BEACONINT: - wl->profile->beacon_interval = *(u16 *)data; + profile->beacon_interval = *(u16 *)data; break; case WL_PROF_DTIMPERIOD: - wl->profile->dtim_period = *(u8 *)data; + profile->dtim_period = *(u8 *)data; break; default: WL_ERR(("unsupported item (%d)\n", item)); @@ -6511,7 +6694,7 @@ void wl_cfg80211_dbg_level(u32 level) static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev) { - return get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS; + return wl_get_mode_by_netdev(wl, ndev) == WL_MODE_IBSS; } static __used bool wl_is_ibssstarter(struct wl_priv *wl) @@ -6660,7 +6843,7 @@ void *wl_cfg80211_request_fw(s8 *file_name) if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) { err = request_firmware(&wl->fw->fw_entry, file_name, - &wl_cfg80211_get_sdio_func()->dev); + wl_cfg80211_get_parent_dev()); if (unlikely(err)) { WL_ERR(("Could not download fw (%d)\n", err)); goto req_fw_out; @@ -6673,7 +6856,7 @@ void *wl_cfg80211_request_fw(s8 *file_name) } } else if (!test_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status)) { err = request_firmware(&wl->fw->fw_entry, file_name, - &wl_cfg80211_get_sdio_func()->dev); + wl_cfg80211_get_parent_dev()); if (unlikely(err)) { WL_ERR(("Could not download nvram (%d)\n", err)); goto req_fw_out; @@ -6763,8 +6946,8 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, if (wl->p2p && wl->p2p->vif_created) { ndev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION); bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_CONNECTION); - } else if (wl_get_drv_status(wl, AP_CREATING) || - wl_get_drv_status(wl, AP_CREATED)) { + } else if (wl_get_drv_status(wl, AP_CREATING, net) || + wl_get_drv_status(wl, AP_CREATED, net)) { ndev = net; bssidx = 0; } @@ -6817,10 +7000,11 @@ static __used void wl_dongle_poweroff(struct wl_priv *wl) dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); } -static int wl_debugfs_add_netdev_params(struct wl_priv *wl) +static int wl_debugfs_add_netdev_params(struct wl_priv *wl, struct net_device *ndev) { char buf[10+IFNAMSIZ]; struct dentry *fd; + struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); s32 err = 0; WL_TRACE(("In\n")); @@ -6828,14 +7012,14 @@ static int wl_debugfs_add_netdev_params(struct wl_priv *wl) wl->debugfsdir = debugfs_create_dir(buf, wl_to_wiphy(wl)->debugfsdir); fd = debugfs_create_u16("beacon_int", S_IRUGO, wl->debugfsdir, - (u16 *)&wl->profile->beacon_interval); + (u16 *)&profile->beacon_interval); if (!fd) { err = -ENOMEM; goto err_out; } fd = debugfs_create_u8("dtim_period", S_IRUGO, wl->debugfsdir, - (u8 *)&wl->profile->dtim_period); + (u8 *)&profile->dtim_period); if (!fd) { err = -ENOMEM; goto err_out; @@ -6878,7 +7062,7 @@ static int wl_setup_rfkill(struct wl_priv *wl, bool setup) return -EINVAL; if (setup) { wl->rfkill = rfkill_alloc("brcmfmac-wifi", - &wl_cfg80211_get_sdio_func()->dev, + wl_cfg80211_get_parent_dev(), RFKILL_TYPE_WLAN, &wl_rfkill_ops, (void *)wl); if (!wl->rfkill) { @@ -7372,3 +7556,18 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) return (strlen("OK")); } + +struct device *wl_cfg80211_get_parent_dev(void) +{ + return cfg80211_parent_dev; +} + +void wl_cfg80211_set_parent_dev(void *dev) +{ + cfg80211_parent_dev = dev; +} + +static void wl_cfg80211_clear_parent_dev(void) +{ + cfg80211_parent_dev = NULL; +} diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index 232db1b1f83..18ff27680cb 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -2,13 +2,13 @@ * Linux cfg80211 driver * * Copyright (C) 1999-2011, Broadcom Corporation - * + * * Unless you and Broadcom execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2 (the "GPL"), * available at http://www.broadcom.com/licenses/GPLv2.php, with the * following added to such license: - * + * * As a special exception, the copyright holders of this software give you * permission to link this software with independent modules, and to copy and * distribute the resulting executable under terms of your choice, provided that @@ -16,7 +16,7 @@ * the license of that module. An independent module is a module which is not * derived from this software. The special exception does not apply to any * modifications of the software. - * + * * Notwithstanding the above, under no circumstances may you combine this * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. @@ -130,10 +130,11 @@ do { \ #define WL_FILE_NAME_MAX 256 #define WL_DWELL_TIME 200 #define WL_LONG_DWELL_TIME 1000 -#define VWDEV_CNT 3 +#define IFACE_MAX_CNT 2 #define WL_SCAN_TIMER_INTERVAL_MS 8000 /* Scan timeout */ +#define WL_INVALID -1 /* dongle status */ enum wl_status { WL_STATUS_READY = 0, @@ -198,10 +199,6 @@ struct beacon_proberesp { /* dongle configuration */ struct wl_conf { - struct net_mode { - struct net_device *ndev; - s32 type; - } mode [VWDEV_CNT + 1]; /* adhoc , infrastructure or ap */ u32 frag_threshold; u32 rts_threshold; u32 retry_short; @@ -262,16 +259,24 @@ struct wl_ibss { /* dongle profile */ struct wl_profile { u32 mode; + s32 band; struct wlc_ssid ssid; + struct wl_security sec; + struct wl_ibss ibss; u8 bssid[ETHER_ADDR_LEN]; u16 beacon_interval; u8 dtim_period; - struct wl_security sec; - struct wl_ibss ibss; - s32 band; bool active; }; +struct net_info { + struct net_device *ndev; + struct wireless_dev *wdev; + struct wl_profile profile; /* holding dongle profile */ + s32 mode; + unsigned long sme_state; + struct list_head list; /* list of all net_info structure */ +}; typedef s32(*ISCAN_HANDLER) (struct wl_priv *wl); /* dongle iscan controller */ @@ -323,9 +328,10 @@ struct wl_pmk_list { #define ESCAN_BUF_SIZE (64 * 1024) struct escan_info { - u32 escan_state; - u8 escan_buf[ESCAN_BUF_SIZE]; - struct wiphy *wiphy; + u32 escan_state; + u8 escan_buf[ESCAN_BUF_SIZE]; + struct wiphy *wiphy; + struct net_device *ndev; }; struct ap_info { @@ -341,14 +347,14 @@ struct ap_info { }; struct btcoex_info { struct timer_list timer; - uint32 timer_ms; - uint32 timer_on; - uint32 ts_dhcp_start; /* ms ts ecord time stats */ - uint32 ts_dhcp_ok; /* ms ts ecord time stats */ - bool dhcp_done; /* flag, indicates that host done with - * dhcp before t1/t2 expiration - */ - int bt_state; + u32 timer_ms; + u32 timer_on; + u32 ts_dhcp_start; /* ms ts ecord time stats */ + u32 ts_dhcp_ok; /* ms ts ecord time stats */ + bool dhcp_done; /* flag, indicates that host done with + * dhcp before t1/t2 expiration + */ + s32 bt_state; struct work_struct work; struct net_device *dev; }; @@ -363,11 +369,15 @@ struct sta_info { /* dongle private data of cfg80211 interface */ struct wl_priv { struct wireless_dev *wdev; /* representing wl cfg80211 device */ - struct wireless_dev *vwdev[VWDEV_CNT]; + + struct wireless_dev *p2p_wdev; /* representing wl cfg80211 device for P2P */ + struct net_device *p2p_net; /* reference to p2p0 interface */ + struct wl_conf *conf; /* dongle configuration */ struct cfg80211_scan_request *scan_request; /* scan request object */ EVENT_HANDLER evt_handler[WLC_E_LAST]; struct list_head eq_list; /* used for event queue */ + struct list_head net_list; /* used for struct net_info */ spinlock_t eq_lock; /* for event queue synchronization */ struct mutex usr_sync; /* maily for dongle up/down synchronization */ struct wl_scan_results *bss_list; @@ -375,14 +385,8 @@ struct wl_priv { /* scan request object for internal purpose */ struct wl_scan_req *scan_req_int; - - /* bss information for cfg80211 layer */ - struct wl_cfg80211_bss_info *bss_info; /* information element object for internal purpose */ struct wl_ie ie; - - /* for synchronization of main event thread */ - struct wl_profile *profile; /* holding dongle profile */ struct wl_iscan_ctrl *iscan; /* iscan controller */ /* association information container */ @@ -392,8 +396,8 @@ struct wl_priv { struct wl_fw_ctrl *fw; struct wl_pmk_list *pmk_list; /* wpa2 pmk list */ tsk_ctl_t event_tsk; /* task of main event handler thread */ - unsigned long status; /* current dongle status */ void *pub; + u32 iface_cnt; u32 channel; /* current channel */ bool iscan_on; /* iscan on/off switch */ bool iscan_kickstart; /* indicate iscan already started */ @@ -416,7 +420,7 @@ struct wl_priv { bool rf_blocked; struct ieee80211_channel remain_on_chan; enum nl80211_channel_type remain_on_chan_type; - u64 cache_cookie; + u64 last_roc_id; wait_queue_head_t dongle_event_wait; struct ap_info *ap_info; struct sta_info *sta_info; @@ -426,98 +430,183 @@ struct wl_priv { struct timer_list scan_timeout; /* Timer for catch scan event timeout */ }; -#define wl_to_wiphy(w) (w->wdev->wiphy) -#define wl_to_prmry_ndev(w) (w->wdev->netdev) -#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) -#define wl_to_sr(w) (w->scan_req_int) -#define wl_to_ie(w) (&w->ie) -#define iscan_to_wl(i) ((struct wl_priv *)(i->data)) -#define wl_to_iscan(w) (w->iscan) -#define wl_to_conn(w) (&w->conn_info) -#define wiphy_from_scan(w) (w->escan_info.wiphy) -#define wl_get_drv_status(wl, stat) (test_bit(WL_STATUS_ ## stat, &(wl)->status)) -#define wl_set_drv_status(wl, stat) (set_bit(WL_STATUS_ ## stat, &(wl)->status)) -#define wl_clr_drv_status(wl, stat) (clear_bit(WL_STATUS_ ## stat, &(wl)->status)) -#define wl_chg_drv_status(wl, stat) (change_bit(WL_STATUS_ ## stat, &(wl)->status)) - static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) { return bss = bss ? (struct wl_bss_info *)((uintptr) bss + dtoh32(bss->length)) : list->bss_info; } -static inline s32 alloc_idx_vwdev(struct wl_priv *wl) + +static inline s32 +wl_alloc_netinfo(struct wl_priv *wl, struct net_device *ndev, + struct wireless_dev * wdev, s32 mode) { - s32 i = 0; - for (i = 0; i < VWDEV_CNT; i++) { - if (wl->vwdev[i] == NULL) - return i; + struct net_info *_net_info; + s32 err = 0; + if (wl->iface_cnt == IFACE_MAX_CNT) + return -ENOMEM; + _net_info = kzalloc(sizeof(struct net_info), GFP_KERNEL); + if (!_net_info) + err = -ENOMEM; + else { + _net_info->mode = mode; + _net_info->ndev = ndev; + _net_info->wdev = wdev; + wl->iface_cnt++; + list_add(&_net_info->list, &wl->net_list); } - WL_ERR((" *********alloc_idx_vwdev failed (%d) \n", -1)); - return -1; + return err; } -static inline s32 get_idx_vwdev_by_netdev(struct wl_priv *wl, struct net_device *ndev) +static inline void +wl_dealloc_netinfo(struct wl_priv *wl, struct net_device *ndev) { - s32 i = 0; - for (i = 0; i < VWDEV_CNT; i++) { - if ((wl->vwdev[i] != NULL) && (wl->vwdev[i]->netdev == ndev)) - return i; + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) { + list_del(&_net_info->list); + wl->iface_cnt--; + if (_net_info->wdev) { + kfree(_net_info->wdev); + ndev->ieee80211_ptr = NULL; + } + kfree(_net_info); + } } - WL_ERR((" *********get_idx_vwdev_by_netdev failed (%d) \n", -1)); - return -1; } +static inline void +wl_delete_all_netinfo(struct wl_priv *wl) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { + list_del(&_net_info->list); + if (_net_info->wdev) + kfree(_net_info->wdev); + kfree(_net_info); + } + wl->iface_cnt = 0; +} + +static inline bool +wl_get_status_all(struct wl_priv *wl, s32 status) -static inline s32 get_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev) { - s32 i = 0; - for (i = 0; i <= VWDEV_CNT; i++) { - if (wl->conf->mode[i].ndev != NULL && (wl->conf->mode[i].ndev == ndev)) - return wl->conf->mode[i].type; + struct net_info *_net_info, *next; + u32 cnt = 0; + list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { + if (_net_info->ndev && + test_bit(status, &_net_info->sme_state)) + cnt++; } - return -1; + return cnt? true: false; } -static inline void set_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev, s32 type) + +static inline void +wl_set_status_by_netdev(struct wl_priv *wl, s32 status, + struct net_device *ndev, u32 op) { - s32 i = 0; - for (i = 0; i <= VWDEV_CNT; i++) { - if (type == -1) { - /* free the info of netdev */ - if (wl->conf->mode[i].ndev == ndev) { - wl->conf->mode[i].ndev = NULL; - wl->conf->mode[i].type = -1; - break; - } - } else { - if ((wl->conf->mode[i].ndev != NULL)&& - (wl->conf->mode[i].ndev == ndev)) { - /* update type of ndev */ - wl->conf->mode[i].type = type; - break; - } - else if ((wl->conf->mode[i].ndev == NULL)&& - (wl->conf->mode[i].type == -1)) { - wl->conf->mode[i].ndev = ndev; - wl->conf->mode[i].type = type; - break; + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) { + switch (op) { + case 1: + set_bit(status, &_net_info->sme_state); + break; + case 2: + clear_bit(status, &_net_info->sme_state); + break; + case 4: + change_bit(status, &_net_info->sme_state); + break; } } + + } +} + +static inline u32 +wl_get_status_by_netdev(struct wl_priv *wl, s32 status, + struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + return test_bit(status, &_net_info->sme_state); } + return 0; } -#define free_vwdev_by_index(wl, __i) do { \ - if (wl->vwdev[__i] != NULL) \ - kfree(wl->vwdev[__i]); \ - wl->vwdev[__i] = NULL; \ - } while (0) + +static inline s32 +wl_get_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + return _net_info->mode; + } + return -1; +} + +static inline void +wl_set_mode_by_netdev(struct wl_priv *wl, struct net_device *ndev, + s32 mode) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + _net_info->mode = mode; + } +} + +static inline struct wl_profile * +wl_get_profile_by_netdev(struct wl_priv *wl, struct net_device *ndev) +{ + struct net_info *_net_info, *next; + + list_for_each_entry_safe(_net_info, next, &wl->net_list, list) { + if (ndev && (_net_info->ndev == ndev)) + return &_net_info->profile; + } + return NULL; +} +#define wl_to_wiphy(w) (w->wdev->wiphy) +#define wl_to_prmry_ndev(w) (w->wdev->netdev) +#define ndev_to_wl(n) (wdev_to_wl(n->ieee80211_ptr)) +#define wl_to_sr(w) (w->scan_req_int) +#define wl_to_ie(w) (&w->ie) +#define iscan_to_wl(i) ((struct wl_priv *)(i->data)) +#define wl_to_iscan(w) (w->iscan) +#define wl_to_conn(w) (&w->conn_info) +#define wiphy_from_scan(w) (w->escan_info.wiphy) +#define wl_get_drv_status_all(wl, stat) \ + (wl_get_status_all(wl, WL_STATUS_ ## stat)) +#define wl_get_drv_status(wl, stat, ndev) \ + (wl_get_status_by_netdev(wl, WL_STATUS_ ## stat, ndev)) +#define wl_set_drv_status(wl, stat, ndev) \ + (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 1)) +#define wl_clr_drv_status(wl, stat, ndev) \ + (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 2)) +#define wl_chg_drv_status(wl, stat, ndev) \ + (wl_set_status_by_netdev(wl, WL_STATUS_ ## stat, ndev, 4)) #define for_each_bss(list, bss, __i) \ for (__i = 0; __i < list->count && __i < WL_AP_MAX; __i++, bss = next_bss(list, bss)) +#define for_each_ndev(wl, iter, next) \ + list_for_each_entry_safe(iter, next, &wl->net_list, list) + + /* In case of WPS from wpa_supplicant, pairwise siute and group suite is 0. * In addtion to that, wpa_version is WPA_VERSION_1 */ #define is_wps_conn(_sme) \ - ((_sme->crypto.wpa_versions & NL80211_WPA_VERSION_1) && \ + ((wl_cfgp2p_find_wpsie((u8 *)_sme->ie, _sme->ie_len) != NULL) && \ (!_sme->crypto.n_ciphers_pairwise) && \ (!_sme->crypto.cipher_group)) extern s32 wl_cfg80211_attach(struct net_device *ndev, void *data); @@ -526,14 +615,14 @@ extern void wl_cfg80211_detach(void); /* event handler from dongle */ extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, void *data); -extern void wl_cfg80211_set_sdio_func(void *func); /* set sdio function info */ -extern struct sdio_func *wl_cfg80211_get_sdio_func(void); /* set sdio function info */ +void wl_cfg80211_set_parent_dev(void *dev); +struct device *wl_cfg80211_get_parent_dev(void); + extern s32 wl_cfg80211_up(void); /* dongle up */ extern s32 wl_cfg80211_down(void); /* dongle down */ extern s32 wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx, int (*_net_attach)(dhd_pub_t *dhdp, int ifidx)); extern s32 wl_cfg80211_notify_ifdel(struct net_device *ndev); -extern s32 wl_cfg80211_post_del(void *ndev); extern s32 wl_cfg80211_is_progress_ifadd(void); extern s32 wl_cfg80211_is_progress_ifchange(void); extern s32 wl_cfg80211_is_progress_ifadd(void); @@ -551,6 +640,7 @@ extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len enum wl_management_type type); extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len); extern int wl_cfg80211_hang(struct net_device *dev, u16 reason); +extern s32 wl_mode_to_nl80211_iftype(s32 mode); /* do scan abort */ extern s32 diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index 4ee6557e17d..85c36101ab4 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -47,7 +47,7 @@ #include #include #include - +#include static s8 ioctlbuf[WLC_IOCTL_MAXLEN]; static s8 scanparambuf[WLC_IOCTL_SMLEN]; @@ -59,6 +59,19 @@ wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u static s32 wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag, s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete); + +static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev); +static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd); +static int wl_cfgp2p_if_open(struct net_device *net); +static int wl_cfgp2p_if_stop(struct net_device *net); + +static const struct net_device_ops wl_cfgp2p_if_ops = { + .ndo_open = wl_cfgp2p_if_open, + .ndo_stop = wl_cfgp2p_if_stop, + .ndo_do_ioctl = wl_cfgp2p_do_ioctl, + .ndo_start_xmit = wl_cfgp2p_start_xmit, +}; + /* * Initialize variables related to P2P * @@ -569,7 +582,7 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, eparams->params.nprobes = htod32(P2PAPI_SCAN_NPROBES); eparams->params.home_time = htod32(P2PAPI_SCAN_HOME_TIME_MS); - if (wl_get_drv_status(wl, CONNECTED)) + if (wl_get_drv_status_all(wl, CONNECTED)) eparams->params.active_time = htod32(-1); else if (num_chans == 3) eparams->params.active_time = htod32(P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS); @@ -670,7 +683,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss CFGP2P_ERR(("not suitable type\n")); return -1; } - } else if (get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { + } else if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { switch (pktflag) { case VNDR_IE_PRBRSP_FLAG : mgmt_ie_buf = wl->ap_info->probe_res_ie; @@ -689,7 +702,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss return -1; } bssidx = 0; - } else if (bssidx == -1 && get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) { + } else if (bssidx == -1 && wl_get_mode_by_netdev(wl, ndev) == WL_MODE_BSS) { switch (pktflag) { case VNDR_IE_PRBREQ_FLAG : mgmt_ie_buf = wl->sta_info->probe_req_ie; @@ -964,7 +977,7 @@ wl_cfgp2p_listen_complete(struct wl_priv *wl, struct net_device *ndev, del_timer_sync(&wl->p2p->listen_timer); spin_unlock_bh(&wl->p2p->timer_lock); } - cfg80211_remain_on_channel_expired(ndev, wl->cache_cookie, &wl->remain_on_chan, + cfg80211_remain_on_channel_expired(ndev, wl->last_roc_id, &wl->remain_on_chan, wl->remain_on_chan_type, GFP_KERNEL); } else wl_clr_p2p_status(wl, LISTEN_EXPIRED); @@ -1467,3 +1480,145 @@ s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, } return ret; } + +s32 +wl_cfgp2p_register_ndev(struct wl_priv *wl) +{ + int ret = 0; + struct net_device* net = NULL; + struct wireless_dev *wdev; + uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x33, 0x22, 0x11 }; + + /* Allocate etherdev, including space for private structure */ + if (!(net = alloc_etherdev(sizeof(wl)))) { + CFGP2P_ERR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); + goto fail; + } + + strcpy(net->name, "p2p%d"); + net->name[IFNAMSIZ - 1] = '\0'; + + /* Copy the reference to wl_priv */ + memcpy((void *)netdev_priv(net), &wl, sizeof(wl)); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) + ASSERT(!net->open); + net->do_ioctl = wl_cfgp2p_do_ioctl; + net->hard_start_xmit = wl_cfgp2p_start_xmit; + net->open = wl_cfgp2p_if_open; + net->stop = wl_cfgp2p_if_stop; +#else + ASSERT(!net->netdev_ops); + net->netdev_ops = &wl_cfgp2p_if_ops; +#endif + + /* Register with a dummy MAC addr */ + memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); + + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (unlikely(!wdev)) { + WL_ERR(("Could not allocate wireless device\n")); + return -ENOMEM; + } + + wdev->wiphy = wl->wdev->wiphy; + + wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); + + net->ieee80211_ptr = wdev; + + SET_NETDEV_DEV(net, wiphy_dev(wdev->wiphy)); + + /* Associate p2p0 network interface with new wdev */ + wdev->netdev = net; + + /* store p2p net ptr for further reference. Note that iflist won't have this + * entry as there corresponding firmware interface is a "Hidden" interface. + */ + if (wl->p2p_net) { + CFGP2P_ERR(("p2p_net defined already.\n")); + return -EINVAL; + } else { + wl->p2p_wdev = wdev; + wl->p2p_net = net; + } + + ret = register_netdev(net); + if (ret) { + CFGP2P_ERR((" register_netdevice failed (%d)\n", ret)); + goto fail; + } + + printk("%s: P2P Interface Registered\n", net->name); + + return ret; +fail: + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) + net->open = NULL; +#else + net->netdev_ops = NULL; +#endif + + if (net) { + unregister_netdev(net); + free_netdev(net); + } + + return -ENODEV; +} + +s32 +wl_cfgp2p_unregister_ndev(struct wl_priv *wl) +{ + + if (!wl || !wl->p2p_net) { + CFGP2P_ERR(("Invalid Ptr\n")); + return -EINVAL; + } + + unregister_netdev(wl->p2p_net); + free_netdev(wl->p2p_net); + + return 0; +} + +static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + CFGP2P_DBG(("(%s) is not used for data operations. Droping the packet. \n", ndev->name)); + return 0; +} + +static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd) +{ + int ret = 0; + struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net); + struct net_device *ndev = wl_to_prmry_ndev(wl); + + /* There is no ifidx corresponding to p2p0 in our firmware. So we should + * not Handle any IOCTL cmds on p2p0 other than ANDROID PRIVATE CMDs. + * For Android PRIV CMD handling map it to primary I/F + */ + if (cmd == SIOCDEVPRIVATE+1) { + ret = wl_android_priv_cmd(ndev, ifr, cmd); + + } else { + CFGP2P_ERR(("%s: IOCTL req 0x%x on p2p0 I/F. Ignoring. \n", + __FUNCTION__, cmd)); + return -1; + } + + return ret; +} + +static int wl_cfgp2p_if_open(struct net_device *net) +{ + CFGP2P_DBG(("Do Nothing \n")); + return 0; +} + +static int wl_cfgp2p_if_stop(struct net_device *net) +{ + CFGP2P_DBG(("Do Nothing \n")); + return 0; +} diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h index 5a69168c6a3..6934d8f1c9b 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h @@ -103,11 +103,11 @@ enum wl_cfgp2p_status { #define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type]) #define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) -#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : set_bit(WLP2P_STATUS_ ## stat, \ +#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : set_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) -#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : clear_bit(WLP2P_STATUS_ ## stat, \ +#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : clear_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) -#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? : change_bit(WLP2P_STATUS_ ## stat, \ +#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : change_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) #define p2p_on(wl) ((wl)->p2p->on) #define p2p_scan(wl) ((wl)->p2p->scan) @@ -235,6 +235,12 @@ wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, in extern s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len); +extern s32 +wl_cfgp2p_register_ndev(struct wl_priv *wl); + +extern s32 +wl_cfgp2p_unregister_ndev(struct wl_priv *wl); + /* WiFi Direct */ #define SOCIAL_CHAN_1 1 #define SOCIAL_CHAN_2 6 diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c index 32f7b57d2d4..d09448a7932 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/bcmdhd/wl_iw.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_iw.c,v 1.132.2.18 2011-02-05 01:44:47 Exp $ + * $Id: wl_iw.c,v 1.132.2.18 2011-02-05 01:44:47 $ */ #include @@ -1564,6 +1564,63 @@ wl_iw_set_pno_set( net_os_wake_unlock(dev); return res; } + +static int +wl_iw_set_pno_setadd( + struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra +) +{ + int ret = -1; + char *tmp_ptr; + int size, tmp_size; + + net_os_wake_lock(dev); + WL_ERROR(("\n### %s: info->cmd:%x, info->flags:%x, u.data=0x%p, u.len=%d\n", + __FUNCTION__, info->cmd, info->flags, + wrqu->data.pointer, wrqu->data.length)); + + if (g_onoff == G_WLAN_SET_OFF) { + WL_TRACE(("%s: driver is not up yet after START\n", __FUNCTION__)); + goto exit_proc; + } + + if (wrqu->data.length <= strlen(PNOSETADD_SET_CMD) + sizeof(cmd_tlv_t)) { + WL_ERROR(("%s argument=%d less than %d\n", __FUNCTION__, + wrqu->data.length, (int)(strlen(PNOSETADD_SET_CMD) + sizeof(cmd_tlv_t)))); + goto exit_proc; + } + + + bcopy(PNOSETUP_SET_CMD, extra, strlen(PNOSETUP_SET_CMD)); + + tmp_ptr = extra + strlen(PNOSETUP_SET_CMD); + size = wrqu->data.length - strlen(PNOSETUP_SET_CMD); + tmp_size = size; + + while (*tmp_ptr && tmp_size > 0) { + if ((*tmp_ptr == 'S') && (size - tmp_size) >= sizeof(cmd_tlv_t)) { + *(tmp_ptr + 1) = ((*(tmp_ptr + 1) - '0') << 4) + (*(tmp_ptr + 2) - '0'); + memmove(tmp_ptr + 2, tmp_ptr + 3, tmp_size - 3); + tmp_size -= 2 + *(tmp_ptr + 1); + tmp_ptr += 2 + *(tmp_ptr + 1); + size--; + } else { + tmp_ptr++; + tmp_size--; + } + } + + wrqu->data.length = strlen(PNOSETUP_SET_CMD) + size; + ret = wl_iw_set_pno_set(dev, info, wrqu, extra); + +exit_proc: + net_os_wake_unlock(dev); + return ret; + +} #endif static int @@ -2567,6 +2624,8 @@ wl_iw_get_range( IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); IW_EVENT_CAPA_SET(range->event_capa, IWEVTXDROP); IW_EVENT_CAPA_SET(range->event_capa, IWEVMICHAELMICFAILURE); + IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCREQIE); + IW_EVENT_CAPA_SET(range->event_capa, IWEVASSOCRESPIE); IW_EVENT_CAPA_SET(range->event_capa, IWEVPMKIDCAND); #endif @@ -5473,7 +5532,15 @@ wl_iw_set_wpaauth( switch (paramid) { case IW_AUTH_WPA_VERSION: - iw->wpaversion = paramval; + if (paramval & IW_AUTH_WPA_VERSION_DISABLED) + val = WPA_AUTH_DISABLED; + else if (paramval & (IW_AUTH_WPA_VERSION_WPA)) + val = WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED; + else if (paramval & IW_AUTH_WPA_VERSION_WPA2) + val = WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED; + WL_ERROR(("%s: %d: setting wpa_auth to 0x%0x\n", __FUNCTION__, __LINE__, val)); + if ((error = dev_wlc_intvar_set(dev, "wpa_auth", val))) + return error; break; case IW_AUTH_CIPHER_PAIRWISE: @@ -5491,7 +5558,27 @@ wl_iw_set_wpaauth( break; case IW_AUTH_KEY_MGMT: - if (paramval & IW_AUTH_KEY_MGMT_PSK) { + if ((error = dev_wlc_intvar_get(dev, "wpa_auth", &val))) + return error; + + if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) { + if (paramval & IW_AUTH_KEY_MGMT_PSK) + val = WPA_AUTH_PSK; + else + val = WPA_AUTH_UNSPECIFIED; + if (paramval & 0x04) + val |= WPA2_AUTH_FT; + } + else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) { + if (paramval & IW_AUTH_KEY_MGMT_PSK) + val = WPA2_AUTH_PSK; + else + val = WPA2_AUTH_UNSPECIFIED; + if (paramval & 0x04) + val |= WPA2_AUTH_FT; + } + + else if (paramval & IW_AUTH_KEY_MGMT_PSK) { if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA) val = WPA_AUTH_PSK; else if (iw->wpaversion == IW_AUTH_WPA_VERSION_WPA2) @@ -7526,6 +7613,8 @@ wl_iw_set_priv( ret = wl_iw_set_pno_reset(dev, info, (union iwreq_data *)dwrq, extra); else if (strnicmp(extra, PNOSETUP_SET_CMD, strlen(PNOSETUP_SET_CMD)) == 0) ret = wl_iw_set_pno_set(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, PNOSETADD_SET_CMD, strlen(PNOSETADD_SET_CMD)) == 0) + ret = wl_iw_set_pno_setadd(dev, info, (union iwreq_data *)dwrq, extra); else if (strnicmp(extra, PNOENABLE_SET_CMD, strlen(PNOENABLE_SET_CMD)) == 0) ret = wl_iw_set_pno_enable(dev, info, (union iwreq_data *)dwrq, extra); #endif @@ -8251,6 +8340,21 @@ wl_iw_event(struct net_device *dev, wl_event_msg_t *e, void* data) break; } + + case WLC_E_ASSOC_REQ_IE: + cmd = IWEVASSOCREQIE; + wrqu.data.length = datalen; + if (datalen < sizeof(extra)) + memcpy(extra, data, datalen); + break; + + case WLC_E_ASSOC_RESP_IE: + cmd = IWEVASSOCRESPIE; + wrqu.data.length = datalen; + if (datalen < sizeof(extra)) + memcpy(extra, data, datalen); + break; + case WLC_E_PMKID_CACHE: { if (data) { diff --git a/drivers/net/wireless/bcmdhd/wl_iw.h b/drivers/net/wireless/bcmdhd/wl_iw.h index c0cc14bdde4..faca5f72e22 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.h +++ b/drivers/net/wireless/bcmdhd/wl_iw.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wl_iw.h,v 1.15.80.6 2010-12-23 01:13:23 Exp $ + * $Id: wl_iw.h,v 1.15.80.6 2010-12-23 01:13:23 $ */ @@ -51,9 +51,10 @@ #define PNOSSIDCLR_SET_CMD "PNOSSIDCLR" #define PNOSETUP_SET_CMD "PNOSETUP " +#define PNOSETADD_SET_CMD "PNOSETADD" #define PNOENABLE_SET_CMD "PNOFORCE" #define PNODEBUG_SET_CMD "PNODEBUG" -#define TXPOWER_SET_CMD "TXPOWER" +#define TXPOWER_SET_CMD "TXPOWER" #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" @@ -226,6 +227,18 @@ extern void get_customized_country_code(char *country_iso_code, wl_country_t *cs iwe_stream_add_point(stream, ends, iwe, extra) #endif +extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); +extern int dhd_pno_clean(dhd_pub_t *dhd); +extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, + ushort scan_fr, int pno_repeat, int pno_freq_expo_max); +extern int dhd_pno_get_status(dhd_pub_t *dhd); +extern int dhd_dev_pno_reset(struct net_device *dev); +extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, + int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max); +extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); +extern int dhd_dev_get_pno_status(struct net_device *dev); +extern int dhd_get_dtim_skip(dhd_pub_t *dhd); + void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec); #define PNO_TLV_PREFIX 'S' From 494661a1acbd4767e4d7daaff8d7ce55328913d9 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 24 Jan 2012 13:47:47 -0800 Subject: [PATCH 0752/4025] net: wireless: bcmdhd: Update to Version 5.90.195.19 - Add WFD changes - Add extra locking for internal ioctl operations Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/Makefile | 4 +- drivers/net/wireless/bcmdhd/bcmsdh_linux.c | 25 +- drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c | 4 +- drivers/net/wireless/bcmdhd/dhd.h | 10 +- drivers/net/wireless/bcmdhd/dhd_cdc.c | 7 +- drivers/net/wireless/bcmdhd/dhd_cfg80211.c | 862 +++++++ drivers/net/wireless/bcmdhd/dhd_cfg80211.h | 42 + drivers/net/wireless/bcmdhd/dhd_common.c | 7 +- drivers/net/wireless/bcmdhd/dhd_linux.c | 103 +- drivers/net/wireless/bcmdhd/dhd_sdio.c | 4 +- .../net/wireless/bcmdhd/include/dhdioctl.h | 3 +- drivers/net/wireless/bcmdhd/include/epivers.h | 8 +- .../wireless/bcmdhd/include/proto/802.11.h | 12 +- drivers/net/wireless/bcmdhd/include/wlioctl.h | 19 +- drivers/net/wireless/bcmdhd/wl_android.c | 22 +- drivers/net/wireless/bcmdhd/wl_android.h | 2 +- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 2142 +++++------------ drivers/net/wireless/bcmdhd/wl_cfg80211.h | 125 +- drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 245 +- drivers/net/wireless/bcmdhd/wl_cfgp2p.h | 27 +- .../{dhd_linux_mon.c => wl_linux_mon.c} | 2 +- drivers/net/wireless/bcmdhd/wldev_common.c | 69 +- drivers/net/wireless/bcmdhd/wldev_common.h | 20 +- 23 files changed, 2077 insertions(+), 1687 deletions(-) create mode 100644 drivers/net/wireless/bcmdhd/dhd_cfg80211.c create mode 100644 drivers/net/wireless/bcmdhd/dhd_cfg80211.h rename drivers/net/wireless/bcmdhd/{dhd_linux_mon.c => wl_linux_mon.c} (99%) diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index e82c9856f00..17f07ca3a30 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -13,7 +13,7 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \ dhd_linux_sched.o bcmwifi.o dhd_sdio.o bcmevent.o dhd_bta.o hndpmu.o \ bcmsdh.o dhd_cdc.o bcmsdh_linux.o dhd_common.o linux_osl.o \ - bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o + bcmsdh_sdmmc.o dhd_custom_gpio.o sbutils.o wldev_common.o wl_android.o dhd_cfg80211.o obj-$(CONFIG_BCMDHD) += bcmdhd.o bcmdhd-objs += $(DHDOFILES) @@ -22,7 +22,7 @@ bcmdhd-objs += wl_iw.o DHDCFLAGS += -DSOFTAP endif ifneq ($(CONFIG_CFG80211),) -bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o dhd_linux_mon.o +bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o DHDCFLAGS += -DWL_CFG80211 endif EXTRA_CFLAGS = $(DHDCFLAGS) diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c index 04c43a3225c..5abfecc2cf1 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_linux.c,v 1.72.6.5 2010-12-23 01:13:15 Exp $ + * $Id: bcmsdh_linux.c 294990 2011-11-09 00:13:10Z $ */ /** @@ -238,9 +238,9 @@ int bcmsdh_probe(struct device *dev) /* chain SDIO Host Controller info together */ sdhc->next = sdhcinfo; sdhcinfo = sdhc; + /* Read the vendor/device ID from the CIS */ vendevid = bcmsdh_query_device(sdh); - /* try to attach to the target device */ if (!(sdhc->ch = drvinfo.attach((vendevid >> 16), (vendevid & 0xFFFF), 0, 0, 0, 0, @@ -274,6 +274,7 @@ int bcmsdh_remove(struct device *dev) sdhc = sdhcinfo; drvinfo.detach(sdhc->ch); bcmsdh_detach(sdhc->osh, sdhc->sdh); + /* find the SDIO Host Controller state for this pdev and take it out from the list */ for (sdhc = sdhcinfo, prev = NULL; sdhc; sdhc = sdhc->next) { if (sdhc->dev == (void *)dev) { @@ -290,7 +291,6 @@ int bcmsdh_remove(struct device *dev) return 0; } - /* release SDIO Host Controller info */ osh = sdhc->osh; MFREE(osh, sdhc, sizeof(bcmsdh_hc_t)); @@ -611,13 +611,6 @@ static irqreturn_t wlan_oob_irq(int irq, void *dev_id) return IRQ_HANDLED; } -void *bcmsdh_get_drvdata(void) -{ - if (!sdhcinfo) - return NULL; - return dev_get_drvdata(sdhcinfo->dev); -} - int bcmsdh_register_oob_intr(void * dhdp) { int error = 0; @@ -645,6 +638,13 @@ int bcmsdh_register_oob_intr(void * dhdp) return 0; } +void *bcmsdh_get_drvdata(void) +{ + if (!sdhcinfo) + return NULL; + return dev_get_drvdata(sdhcinfo->dev); +} + void bcmsdh_set_irq(int flag) { if (sdhcinfo->oob_irq_registered && sdhcinfo->oob_irq_enable_flag != flag) { @@ -671,6 +671,7 @@ void bcmsdh_unregister_oob_intr(void) } } #endif /* defined(OOB_INTR_ONLY) */ + /* Module parameters specific to each host-controller driver */ extern uint sd_msglevel; /* Debug message level */ @@ -694,6 +695,10 @@ module_param(sd_hiok, uint, 0); extern uint sd_f2_blocksize; module_param(sd_f2_blocksize, int, 0); +#ifdef BCMSDIOH_STD +extern int sd_uhsimode; +module_param(sd_uhsimode, int, 0); +#endif #ifdef BCMSDH_MODULE EXPORT_SYMBOL(bcmsdh_attach); diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c index aedb508c594..6a8ff9431e9 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_sdmmc.c 282820 2011-09-09 15:40:35Z $ + * $Id: bcmsdh_sdmmc.c 301794 2011-12-08 20:41:35Z $ */ #include @@ -448,6 +448,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name, bcopy(params, &int_val, sizeof(int_val)); bool_val = (int_val != 0) ? TRUE : FALSE; + BCM_REFERENCE(bool_val); actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); switch (actionid) { @@ -1179,6 +1180,7 @@ static void IRQHandlerF2(struct sdio_func *func) sd = gInstance->sd; ASSERT(sd != NULL); + BCM_REFERENCE(sd); } #endif /* !defined(OOB_INTR_ONLY) */ diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index 4335d0d6a8a..25e74f44a53 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd.h 301794 2011-12-08 20:41:35Z $ + * $Id: dhd.h 306879 2012-01-09 21:33:03Z $ */ /**************** @@ -419,6 +419,7 @@ extern int dhd_custom_get_mac_address(unsigned char *buf); extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); +extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); #ifdef PNO_SUPPORT extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); @@ -433,8 +434,6 @@ extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); extern int dhd_dev_get_pno_status(struct net_device *dev); #endif /* PNO_SUPPORT */ -extern bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd); - #define DHD_UNICAST_FILTER_NUM 0 #define DHD_BROADCAST_FILTER_NUM 1 #define DHD_MULTICAST4_FILTER_NUM 2 @@ -443,7 +442,7 @@ extern int net_os_set_packet_filter(struct net_device *dev, int val); extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); extern int dhd_get_dtim_skip(dhd_pub_t *dhd); -extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); +extern bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd); #ifdef DHD_DEBUG extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); @@ -466,7 +465,7 @@ extern int dhd_timeout_expired(dhd_timeout_t *tmo); extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net); -extern struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx); +extern struct net_device * dhd_idx2net(void *pub, int ifidx); extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, wl_event_msg_t *, void **data_ptr); extern void wl_event_to_host_order(wl_event_msg_t * evt); @@ -478,6 +477,7 @@ extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uin extern struct dhd_cmn *dhd_common_init(osl_t *osh); extern void dhd_common_deinit(dhd_pub_t *dhd_pub, dhd_cmn_t *sa_cmn); +extern int dhd_do_driver_init(struct net_device *net); extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle, char *name, uint8 *mac_addr, uint32 flags, uint8 bssidx); extern void dhd_del_if(struct dhd_info *dhd, int ifidx); diff --git a/drivers/net/wireless/bcmdhd/dhd_cdc.c b/drivers/net/wireless/bcmdhd/dhd_cdc.c index 50e275a4ae2..d01853c71a2 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cdc.c +++ b/drivers/net/wireless/bcmdhd/dhd_cdc.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_cdc.c 301794 2011-12-08 20:41:35Z $ + * $Id: dhd_cdc.c 303389 2011-12-16 09:30:48Z $ * * BDC is like CDC, except it includes a header for data packets to convey * packet priority over the bus, and flags (e.g. to indicate checksum status @@ -2515,9 +2515,10 @@ dhd_prot_init(dhd_pub_t *dhd) ret = dhd_wlfc_init(dhd); #endif -#if !defined(WL_CFG80211) +#if defined(WL_CFG80211) + if (dhd_download_fw_on_driverload) +#endif /* defined(WL_CFG80211) */ ret = dhd_preinit_ioctls(dhd); -#endif /* WL_CFG80211 */ /* Always assumes wl for now */ dhd->iswl = TRUE; diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c new file mode 100644 index 00000000000..058749deba3 --- /dev/null +++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c @@ -0,0 +1,862 @@ +/* + * Linux cfg80211 driver - Dongle Host Driver (DHD) related + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ + */ + +#include + +#include +#include +#include +#include +extern struct wl_priv *wlcfg_drv_priv; +static int dhd_dongle_up = FALSE; + +static s32 wl_dongle_up(struct net_device *ndev, u32 up); +static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode); +static s32 wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align); +static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout); +static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, s32 scan_unassoc_time); +static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol); +static s32 wl_pattern_atoh(s8 *src, s8 *dst); +static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode); + +/** + * Function implementations + */ + +s32 dhd_cfg80211_init(struct wl_priv *wl) +{ + dhd_dongle_up = FALSE; + return 0; +} + +s32 dhd_cfg80211_deinit(struct wl_priv *wl) +{ + dhd_dongle_up = FALSE; + return 0; +} + +s32 dhd_cfg80211_down(struct wl_priv *wl) +{ + dhd_dongle_up = FALSE; + return 0; +} + +static s32 wl_dongle_up(struct net_device *ndev, u32 up) +{ + s32 err = 0; + + err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true); + if (unlikely(err)) { + WL_ERR(("WLC_UP error (%d)\n", err)); + } + return err; +} + +static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode) +{ + s32 err = 0; + + WL_TRACE(("In\n")); + err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), true); + if (unlikely(err)) { + WL_ERR(("WLC_SET_PM error (%d)\n", err)); + } + return err; +} + +static s32 +wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align) +{ + s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; + + s32 err = 0; + + /* Match Host and Dongle rx alignment */ + bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, + sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); + if (unlikely(err)) { + WL_ERR(("txglomalign error (%d)\n", err)); + goto dongle_glom_out; + } + /* disable glom option per default */ + bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); + if (unlikely(err)) { + WL_ERR(("txglom error (%d)\n", err)); + goto dongle_glom_out; + } +dongle_glom_out: + return err; +} + +static s32 +wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) +{ + s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; + + s32 err = 0; + + /* Setup timeout if Beacons are lost and roam is off to report link down */ + if (roamvar) { + bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, + sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); + if (unlikely(err)) { + WL_ERR(("bcn_timeout error (%d)\n", err)); + goto dongle_rom_out; + } + } + /* Enable/Disable built-in roaming to allow supplicant to take care of roaming */ + bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); + if (unlikely(err)) { + WL_ERR(("roam_off error (%d)\n", err)); + goto dongle_rom_out; + } +dongle_rom_out: + return err; +} + +static s32 +wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, + s32 scan_unassoc_time) +{ + s32 err = 0; + + err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time, + sizeof(scan_assoc_time), true); + if (err) { + if (err == -EOPNOTSUPP) { + WL_INFO(("Scan assoc time is not supported\n")); + } else { + WL_ERR(("Scan assoc time error (%d)\n", err)); + } + goto dongle_scantime_out; + } + err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time, + sizeof(scan_unassoc_time), true); + if (err) { + if (err == -EOPNOTSUPP) { + WL_INFO(("Scan unassoc time is not supported\n")); + } else { + WL_ERR(("Scan unassoc time error (%d)\n", err)); + } + goto dongle_scantime_out; + } + +dongle_scantime_out: + return err; +} + +static s32 +wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol) +{ + /* Room for "event_msgs" + '\0' + bitvec */ + s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; + + s32 err = 0; + + /* Set ARP offload */ + bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); + if (err) { + if (err == -EOPNOTSUPP) + WL_INFO(("arpoe is not supported\n")); + else + WL_ERR(("arpoe error (%d)\n", err)); + + goto dongle_offload_out; + } + bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); + if (err) { + if (err == -EOPNOTSUPP) + WL_INFO(("arp_ol is not supported\n")); + else + WL_ERR(("arp_ol error (%d)\n", err)); + + goto dongle_offload_out; + } + +dongle_offload_out: + return err; +} + +static s32 wl_pattern_atoh(s8 *src, s8 *dst) +{ + int i; + if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) { + WL_ERR(("Mask invalid format. Needs to start with 0x\n")); + return -1; + } + src = src + 2; /* Skip past 0x */ + if (strlen(src) % 2 != 0) { + WL_ERR(("Mask invalid format. Needs to be of even length\n")); + return -1; + } + for (i = 0; *src != '\0'; i++) { + char num[3]; + strncpy(num, src, 2); + num[2] = '\0'; + dst[i] = (u8) simple_strtoul(num, NULL, 16); + src += 2; + } + return i; +} + +static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode) +{ + /* Room for "event_msgs" + '\0' + bitvec */ + s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; + + const s8 *str; + struct wl_pkt_filter pkt_filter; + struct wl_pkt_filter *pkt_filterp; + s32 buf_len; + s32 str_len; + u32 mask_size; + u32 pattern_size; + s8 buf[256]; + s32 err = 0; + + /* add a default packet filter pattern */ + str = "pkt_filter_add"; + str_len = strlen(str); + strncpy(buf, str, str_len); + buf[str_len] = '\0'; + buf_len = str_len + 1; + + pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1); + + /* Parse packet filter id. */ + pkt_filter.id = htod32(100); + + /* Parse filter polarity. */ + pkt_filter.negate_match = htod32(0); + + /* Parse filter type. */ + pkt_filter.type = htod32(0); + + /* Parse pattern filter offset. */ + pkt_filter.u.pattern.offset = htod32(0); + + /* Parse pattern filter mask. */ + mask_size = htod32(wl_pattern_atoh("0xff", + (char *)pkt_filterp->u.pattern. + mask_and_pattern)); + + /* Parse pattern filter pattern. */ + pattern_size = htod32(wl_pattern_atoh("0x00", + (char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size])); + + if (mask_size != pattern_size) { + WL_ERR(("Mask and pattern not the same size\n")); + err = -EINVAL; + goto dongle_filter_out; + } + + pkt_filter.u.pattern.size_bytes = mask_size; + buf_len += WL_PKT_FILTER_FIXED_LEN; + buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); + + /* Keep-alive attributes are set in local + * variable (keep_alive_pkt), and + * then memcpy'ed into buffer (keep_alive_pktp) since there is no + * guarantee that the buffer is properly aligned. + */ + memcpy((char *)pkt_filterp, &pkt_filter, + WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); + + err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, true); + if (err) { + if (err == -EOPNOTSUPP) { + WL_INFO(("filter not supported\n")); + } else { + WL_ERR(("filter (%d)\n", err)); + } + goto dongle_filter_out; + } + + /* set mode to allow pattern */ + bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, + sizeof(iovbuf)); + err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); + if (err) { + if (err == -EOPNOTSUPP) { + WL_INFO(("filter_mode not supported\n")); + } else { + WL_ERR(("filter_mode (%d)\n", err)); + } + goto dongle_filter_out; + } + +dongle_filter_out: + return err; +} + +s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock) +{ +#ifndef DHD_SDALIGN +#define DHD_SDALIGN 32 +#endif + struct net_device *ndev; + s32 err = 0; + + WL_TRACE(("In\n")); + if (dhd_dongle_up) { + WL_ERR(("Dongle is already up\n")); + return err; + } + + ndev = wl_to_prmry_ndev(wl); + + if (need_lock) + rtnl_lock(); + + err = wl_dongle_up(ndev, 0); + if (unlikely(err)) { + WL_ERR(("wl_dongle_up failed\n")); + goto default_conf_out; + } + err = wl_dongle_power(ndev, PM_FAST); + if (unlikely(err)) { + WL_ERR(("wl_dongle_power failed\n")); + goto default_conf_out; + } + err = wl_dongle_glom(ndev, 0, DHD_SDALIGN); + if (unlikely(err)) { + WL_ERR(("wl_dongle_glom failed\n")); + goto default_conf_out; + } + err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3); + if (unlikely(err)) { + WL_ERR(("wl_dongle_roam failed\n")); + goto default_conf_out; + } + wl_dongle_scantime(ndev, 40, 80); + wl_dongle_offload(ndev, 1, 0xf); + wl_dongle_filter(ndev, 1); + dhd_dongle_up = true; + +default_conf_out: + if (need_lock) + rtnl_unlock(); + return err; + +} + + +/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */ +#define COEX_DHCP + +#if defined(COEX_DHCP) + +/* use New SCO/eSCO smart YG suppression */ +#define BT_DHCP_eSCO_FIX +/* this flag boost wifi pkt priority to max, caution: -not fair to sco */ +#define BT_DHCP_USE_FLAGS +/* T1 start SCO/ESCo priority suppression */ +#define BT_DHCP_OPPR_WIN_TIME 2500 +/* T2 turn off SCO/SCO supperesion is (timeout) */ +#define BT_DHCP_FLAG_FORCE_TIME 5500 + +enum wl_cfg80211_btcoex_status { + BT_DHCP_IDLE, + BT_DHCP_START, + BT_DHCP_OPPR_WIN, + BT_DHCP_FLAG_FORCE_TIMEOUT +}; + +/* + * get named driver variable to uint register value and return error indication + * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value) + */ +static int +dev_wlc_intvar_get_reg(struct net_device *dev, char *name, + uint reg, int *retval) +{ + union { + char buf[WLC_IOCTL_SMLEN]; + int val; + } var; + int error; + + bcm_mkiovar(name, (char *)(®), sizeof(reg), + (char *)(&var), sizeof(var.buf)); + error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false); + + *retval = dtoh32(var.val); + return (error); +} + +static int +dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) + char ioctlbuf_local[1024]; +#else + static char ioctlbuf_local[1024]; +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ + + bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local)); + + return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true)); +} +/* +get named driver variable to uint register value and return error indication +calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value) +*/ +static int +dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val) +{ + char reg_addr[8]; + + memset(reg_addr, 0, sizeof(reg_addr)); + memcpy((char *)®_addr[0], (char *)addr, 4); + memcpy((char *)®_addr[4], (char *)val, 4); + + return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); +} + +static bool btcoex_is_sco_active(struct net_device *dev) +{ + int ioc_res = 0; + bool res = FALSE; + int sco_id_cnt = 0; + int param27; + int i; + + for (i = 0; i < 12; i++) { + + ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27); + + WL_TRACE(("%s, sample[%d], btc params: 27:%x\n", + __FUNCTION__, i, param27)); + + if (ioc_res < 0) { + WL_ERR(("%s ioc read btc params error\n", __FUNCTION__)); + break; + } + + if ((param27 & 0x6) == 2) { /* count both sco & esco */ + sco_id_cnt++; + } + + if (sco_id_cnt > 2) { + WL_TRACE(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n", + __FUNCTION__, sco_id_cnt, i)); + res = TRUE; + break; + } + + msleep(5); + } + + return res; +} + +#if defined(BT_DHCP_eSCO_FIX) +/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */ +static int set_btc_esco_params(struct net_device *dev, bool trump_sco) +{ + static bool saved_status = FALSE; + + char buf_reg50va_dhcp_on[8] = + { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 }; + char buf_reg51va_dhcp_on[8] = + { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg64va_dhcp_on[8] = + { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg65va_dhcp_on[8] = + { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + char buf_reg71va_dhcp_on[8] = + { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; + uint32 regaddr; + static uint32 saved_reg50; + static uint32 saved_reg51; + static uint32 saved_reg64; + static uint32 saved_reg65; + static uint32 saved_reg71; + + if (trump_sco) { + /* this should reduce eSCO agressive retransmit + * w/o breaking it + */ + + /* 1st save current */ + WL_TRACE(("Do new SCO/eSCO coex algo {save &" + "override}\n")); + if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) { + saved_status = TRUE; + WL_TRACE(("%s saved bt_params[50,51,64,65,71]:" + "0x%x 0x%x 0x%x 0x%x 0x%x\n", + __FUNCTION__, saved_reg50, saved_reg51, + saved_reg64, saved_reg65, saved_reg71)); + } else { + WL_ERR((":%s: save btc_params failed\n", + __FUNCTION__)); + saved_status = FALSE; + return -1; + } + + WL_TRACE(("override with [50,51,64,65,71]:" + "0x%x 0x%x 0x%x 0x%x 0x%x\n", + *(u32 *)(buf_reg50va_dhcp_on+4), + *(u32 *)(buf_reg51va_dhcp_on+4), + *(u32 *)(buf_reg64va_dhcp_on+4), + *(u32 *)(buf_reg65va_dhcp_on+4), + *(u32 *)(buf_reg71va_dhcp_on+4))); + + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg50va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg51va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg64va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg65va_dhcp_on[0], 8); + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg71va_dhcp_on[0], 8); + + saved_status = TRUE; + } else if (saved_status) { + /* restore previously saved bt params */ + WL_TRACE(("Do new SCO/eSCO coex algo {save &" + "override}\n")); + + regaddr = 50; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg50); + regaddr = 51; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg51); + regaddr = 64; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg64); + regaddr = 65; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg65); + regaddr = 71; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg71); + + WL_TRACE(("restore bt_params[50,51,64,65,71]:" + "0x%x 0x%x 0x%x 0x%x 0x%x\n", + saved_reg50, saved_reg51, saved_reg64, + saved_reg65, saved_reg71)); + + saved_status = FALSE; + } else { + WL_ERR((":%s att to restore not saved BTCOEX params\n", + __FUNCTION__)); + return -1; + } + return 0; +} +#endif /* BT_DHCP_eSCO_FIX */ + +static void +wl_cfg80211_bt_setflag(struct net_device *dev, bool set) +{ +#if defined(BT_DHCP_USE_FLAGS) + char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; + char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; +#endif + + +#if defined(BT_DHCP_eSCO_FIX) + /* set = 1, save & turn on 0 - off & restore prev settings */ + set_btc_esco_params(dev, set); +#endif + +#if defined(BT_DHCP_USE_FLAGS) + WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set)); + if (set == TRUE) + /* Forcing bt_flag7 */ + dev_wlc_bufvar_set(dev, "btc_flags", + (char *)&buf_flag7_dhcp_on[0], + sizeof(buf_flag7_dhcp_on)); + else + /* Restoring default bt flag7 */ + dev_wlc_bufvar_set(dev, "btc_flags", + (char *)&buf_flag7_default[0], + sizeof(buf_flag7_default)); +#endif +} + +static void wl_cfg80211_bt_timerfunc(ulong data) +{ + struct btcoex_info *bt_local = (struct btcoex_info *)data; + WL_TRACE(("%s\n", __FUNCTION__)); + bt_local->timer_on = 0; + schedule_work(&bt_local->work); +} + +static void wl_cfg80211_bt_handler(struct work_struct *work) +{ + struct btcoex_info *btcx_inf; + + btcx_inf = container_of(work, struct btcoex_info, work); + + if (btcx_inf->timer_on) { + btcx_inf->timer_on = 0; + del_timer_sync(&btcx_inf->timer); + } + + switch (btcx_inf->bt_state) { + case BT_DHCP_START: + /* DHCP started + * provide OPPORTUNITY window to get DHCP address + */ + WL_TRACE(("%s bt_dhcp stm: started \n", + __FUNCTION__)); + btcx_inf->bt_state = BT_DHCP_OPPR_WIN; + mod_timer(&btcx_inf->timer, + jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000); + btcx_inf->timer_on = 1; + break; + + case BT_DHCP_OPPR_WIN: + if (btcx_inf->dhcp_done) { + WL_TRACE(("%s DHCP Done before T1 expiration\n", + __FUNCTION__)); + goto btc_coex_idle; + } + + /* DHCP is not over yet, start lowering BT priority + * enforce btc_params + flags if necessary + */ + WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__, + BT_DHCP_OPPR_WIN_TIME)); + if (btcx_inf->dev) + wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); + btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; + mod_timer(&btcx_inf->timer, + jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000); + btcx_inf->timer_on = 1; + break; + + case BT_DHCP_FLAG_FORCE_TIMEOUT: + if (btcx_inf->dhcp_done) { + WL_TRACE(("%s DHCP Done before T2 expiration\n", + __FUNCTION__)); + } else { + /* Noo dhcp during T1+T2, restore BT priority */ + WL_TRACE(("%s DHCP wait interval T2:%d" + "msec expired\n", __FUNCTION__, + BT_DHCP_FLAG_FORCE_TIME)); + } + + /* Restoring default bt priority */ + if (btcx_inf->dev) + wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); +btc_coex_idle: + btcx_inf->bt_state = BT_DHCP_IDLE; + btcx_inf->timer_on = 0; + break; + + default: + WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__, + btcx_inf->bt_state)); + if (btcx_inf->dev) + wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); + btcx_inf->bt_state = BT_DHCP_IDLE; + btcx_inf->timer_on = 0; + break; + } + + net_os_wake_unlock(btcx_inf->dev); +} + +int wl_cfg80211_btcoex_init(struct wl_priv *wl) +{ + struct btcoex_info *btco_inf = NULL; + + btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL); + if (!btco_inf) + return -ENOMEM; + + btco_inf->bt_state = BT_DHCP_IDLE; + btco_inf->ts_dhcp_start = 0; + btco_inf->ts_dhcp_ok = 0; + /* Set up timer for BT */ + btco_inf->timer_ms = 10; + init_timer(&btco_inf->timer); + btco_inf->timer.data = (ulong)btco_inf; + btco_inf->timer.function = wl_cfg80211_bt_timerfunc; + + btco_inf->dev = wl->wdev->netdev; + + INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler); + + wl->btcoex_info = btco_inf; + return 0; +} + +void wl_cfg80211_btcoex_deinit(struct wl_priv *wl) +{ + if (!wl->btcoex_info) + return; + + if (!wl->btcoex_info->timer_on) { + wl->btcoex_info->timer_on = 0; + del_timer_sync(&wl->btcoex_info->timer); + } + + cancel_work_sync(&wl->btcoex_info->work); + + kfree(wl->btcoex_info); + wl->btcoex_info = NULL; +} +#endif + +int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) +{ + + struct wl_priv *wl = wlcfg_drv_priv; + char powermode_val = 0; + char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; + char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; + char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; + + uint32 regaddr; + static uint32 saved_reg66; + static uint32 saved_reg41; + static uint32 saved_reg68; + static bool saved_status = FALSE; + +#ifdef COEX_DHCP + char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; + struct btcoex_info *btco_inf = wl->btcoex_info; +#endif /* COEX_DHCP */ + + /* Figure out powermode 1 or o command */ + strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1); + + if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { + + WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__)); + + /* Retrieve and saved orig regs value */ + if ((saved_status == FALSE) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && + (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { + saved_status = TRUE; + WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", + saved_reg66, saved_reg41, saved_reg68)); + + /* Disable PM mode during dhpc session */ + + /* Disable PM mode during dhpc session */ +#ifdef COEX_DHCP + /* Start BT timer only for SCO connection */ + if (btcoex_is_sco_active(dev)) { + /* btc_params 66 */ + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg66va_dhcp_on[0], + sizeof(buf_reg66va_dhcp_on)); + /* btc_params 41 0x33 */ + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg41va_dhcp_on[0], + sizeof(buf_reg41va_dhcp_on)); + /* btc_params 68 0x190 */ + dev_wlc_bufvar_set(dev, "btc_params", + (char *)&buf_reg68va_dhcp_on[0], + sizeof(buf_reg68va_dhcp_on)); + saved_status = TRUE; + + btco_inf->bt_state = BT_DHCP_START; + btco_inf->timer_on = 1; + mod_timer(&btco_inf->timer, btco_inf->timer.expires); + WL_TRACE(("%s enable BT DHCP Timer\n", + __FUNCTION__)); + } +#endif /* COEX_DHCP */ + } + else if (saved_status == TRUE) { + WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__)); + } + } + else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { + + + /* Restoring PM mode */ + +#ifdef COEX_DHCP + /* Stop any bt timer because DHCP session is done */ + WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__)); + if (btco_inf->timer_on) { + btco_inf->timer_on = 0; + del_timer_sync(&btco_inf->timer); + + if (btco_inf->bt_state != BT_DHCP_IDLE) { + /* need to restore original btc flags & extra btc params */ + WL_TRACE(("%s bt->bt_state:%d\n", + __FUNCTION__, btco_inf->bt_state)); + /* wake up btcoex thread to restore btlags+params */ + schedule_work(&btco_inf->work); + } + } + + /* Restoring btc_flag paramter anyway */ + if (saved_status == TRUE) + dev_wlc_bufvar_set(dev, "btc_flags", + (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); +#endif /* COEX_DHCP */ + + /* Restore original values */ + if (saved_status == TRUE) { + regaddr = 66; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg66); + regaddr = 41; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg41); + regaddr = 68; + dev_wlc_intvar_set_reg(dev, "btc_params", + (char *)®addr, (char *)&saved_reg68); + + WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", + saved_reg66, saved_reg41, saved_reg68)); + } + saved_status = FALSE; + + } + else { + WL_ERR(("%s Unkwown yet power setting, ignored\n", + __FUNCTION__)); + } + + snprintf(command, 3, "OK"); + + return (strlen("OK")); +} diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h new file mode 100644 index 00000000000..8dab652c1a2 --- /dev/null +++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h @@ -0,0 +1,42 @@ +/* + * Linux cfg80211 driver - Dongle Host Driver (DHD) related + * + * Copyright (C) 1999-2011, Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2 (the "GPL"), + * available at http://www.broadcom.com/licenses/GPLv2.php, with the + * following added to such license: + * + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions of + * the license of that module. An independent module is a module which is not + * derived from this software. The special exception does not apply to any + * modifications of the software. + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a license + * other than the GPL, without Broadcom's express prior written consent. + * + * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ + */ + + +#ifndef __DHD_CFG80211__ +#define __DHD_CFG80211__ + +#include +#include + +s32 dhd_cfg80211_init(struct wl_priv *wl); +s32 dhd_cfg80211_deinit(struct wl_priv *wl); +s32 dhd_cfg80211_down(struct wl_priv *wl); +s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock); + +int wl_cfg80211_btcoex_init(struct wl_priv *wl); +void wl_cfg80211_btcoex_deinit(struct wl_priv *wl); + +#endif /* __DHD_CFG80211__ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index 6376546c62c..a54c39152e4 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_common.c 297563 2011-11-20 15:38:29Z $ + * $Id: dhd_common.c 307573 2012-01-12 00:04:39Z $ */ #include #include @@ -336,6 +336,11 @@ dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const ch case IOV_SVAL(IOV_MSGLEVEL): dhd_msg_level = int_val; +#ifdef WL_CFG80211 + /* Enable DHD and WL logs in oneshot */ + if (dhd_msg_level & DHD_WL_VAL) + wl_cfg80211_enable_trace(dhd_msg_level); +#endif break; case IOV_GVAL(IOV_BCMERRORSTR): bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 48c970a6b5b..07d8430ea18 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c 301794 2011-12-08 20:41:35Z $ + * $Id: dhd_linux.c 307603 2012-01-12 01:32:01Z $ */ #include @@ -286,6 +286,8 @@ typedef struct dhd_info { char firmware_path[MOD_PARAM_PATHLEN]; char nvram_path[MOD_PARAM_PATHLEN]; +int op_mode = 0; +module_param(op_mode, int, 0644); extern int wl_control_wl_start(struct net_device *dev); extern int net_os_send_hang_message(struct net_device *dev); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) @@ -441,6 +443,9 @@ static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR ; static void dhd_net_if_lock_local(dhd_info_t *dhd); static void dhd_net_if_unlock_local(dhd_info_t *dhd); +#if !defined(AP) && defined(WLP2P) +static u32 dhd_concurrent_fw(dhd_pub_t *dhd); +#endif #ifdef WLMEDIA_HTSF void htsf_update(dhd_info_t *dhd, void *data); @@ -698,8 +703,9 @@ dhd_net2idx(dhd_info_t *dhd, struct net_device *net) return DHD_BAD_IF; } -struct net_device * dhd_idx2net(struct dhd_pub *dhd_pub, int ifidx) +struct net_device * dhd_idx2net(void *pub, int ifidx) { + struct dhd_pub *dhd_pub = (struct dhd_pub *)pub; struct dhd_info *dhd_info; if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS) @@ -927,6 +933,7 @@ _dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr) DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx))); } else { memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); + memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN); } return ret; @@ -983,7 +990,7 @@ dhd_op_if(dhd_if_t *ifp) #ifdef WL_CFG80211 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx, - dhd_net_attach)) { + (void*)dhd_net_attach)) { ifp->state = DHD_IF_NONE; return; } @@ -1425,7 +1432,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) PKTFREE(dhdp->osh, pktbuf, TRUE); continue; } - +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) /* Dropping packets before registering net device to avoid kernel panic */ if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || !dhd->pub.up) { @@ -1434,6 +1441,7 @@ dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) PKTFREE(dhdp->osh, pktbuf, TRUE); continue; } +#endif pnext = PKTNEXT(dhdp->osh, pktbuf); PKTSETNEXT(wl->sh.osh, pktbuf, NULL); @@ -2279,7 +2287,7 @@ dhd_stop(struct net_device *net) int ifidx; dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); + DHD_TRACE(("%s: Enter %p\n", __FUNCTION__, net)); if (dhd->pub.up == 0) { goto exit; } @@ -2287,7 +2295,7 @@ dhd_stop(struct net_device *net) #ifdef WL_CFG80211 if (ifidx == 0) { - wl_cfg80211_down(); + wl_cfg80211_down(NULL); /* * For CFG80211: Clean up all the left over virtual interfaces @@ -2399,7 +2407,7 @@ dhd_open(struct net_device *net) #endif /* TOE */ #if defined(WL_CFG80211) - if (unlikely(wl_cfg80211_up())) { + if (unlikely(wl_cfg80211_up(NULL))) { DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__)); ret = -1; goto exit; @@ -2421,6 +2429,32 @@ dhd_open(struct net_device *net) return ret; } +int dhd_do_driver_init(struct net_device *net) +{ + dhd_info_t *dhd = NULL; + + if (!net) { + DHD_ERROR(("Primary Interface not initialized \n")); + return -EINVAL; + } + + dhd = *(dhd_info_t **)netdev_priv(net); + + /* If driver is already initialized, do nothing + */ + if (dhd->pub.busstate == DHD_BUS_DATA) { + DHD_TRACE(("Driver already Inititalized. Nothing to do")); + return 0; + } + + if (dhd_open(net) < 0) { + DHD_ERROR(("Driver Init Failed \n")); + return -1; + } + + return 0; +} + osl_t * dhd_osl_attach(void *pdev, uint bustype) { @@ -2855,6 +2889,37 @@ dhd_bus_start(dhd_pub_t *dhdp) return 0; } +#if !defined(AP) && defined(WLP2P) +/* For Android ICS MR2 release, the concurrent mode is enabled by default and the firmware + * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA + * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware + * would still be named as fw_bcmdhd_apsta. + */ +static u32 +dhd_concurrent_fw(dhd_pub_t *dhd) +{ + int ret = 0; + char buf[WLC_IOCTL_SMLEN]; + + if ((!op_mode) && (strstr(fw_path, "_p2p") == NULL) && + (strstr(fw_path, "_apsta") == NULL)) { + /* Given path is for the STA firmware. Check whether P2P support is present in + * the firmware. If so, set mode as P2P (concurrent support). + */ + memset(buf, 0, sizeof(buf)); + bcm_mkiovar("p2p", 0, 0, buf, sizeof(buf)); + if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), + FALSE, 0)) < 0) { + DHD_TRACE(("%s: Get P2P failed (error=%d)\n", __FUNCTION__, ret)); + } else if (buf[0] == 1) { + DHD_TRACE(("%s: P2P is supported\n", __FUNCTION__)); + return 1; + } + } + return 0; +} +#endif + int dhd_preinit_ioctls(dhd_pub_t *dhd) { @@ -2920,7 +2985,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif /* GET_CUSTOM_MAC_ENABLE */ #ifdef SET_RANDOM_MAC_SOFTAP - if (strstr(fw_path, "_apsta") != NULL) { + if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == 0x02)) { uint rand_mac; srandom32((uint)jiffies); @@ -2944,7 +3009,8 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) DHD_TRACE(("Firmware = %s\n", fw_path)); #if !defined(AP) && defined(WLP2P) /* Check if firmware with WFD support used */ - if (strstr(fw_path, "_p2p") != NULL) { + if ((!op_mode && strstr(fw_path, "_p2p") != NULL) || (op_mode == 0x04) || + (dhd_concurrent_fw(dhd))) { bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { @@ -2961,7 +3027,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if !defined(AP) && defined(WL_CFG80211) /* Check if firmware with HostAPD support used */ - if (strstr(fw_path, "_apsta") != NULL) { + if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == 0x02)) { /* Turn off MPC in AP mode */ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, @@ -3591,7 +3657,7 @@ void dhd_detach(dhd_pub_t *dhdp) #ifdef WL_CFG80211 if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { - wl_cfg80211_detach(); + wl_cfg80211_detach(NULL); dhd_monitor_uninit(); } #endif @@ -3638,7 +3704,6 @@ dhd_module_cleanup(void) dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); } - static int __init dhd_module_init(void) { @@ -3697,7 +3762,7 @@ dhd_module_init(void) } #endif #if defined(WL_CFG80211) - error = wl_android_post_init(); + wl_android_post_init(); #endif return error; @@ -3716,7 +3781,11 @@ dhd_module_init(void) return error; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) late_initcall(dhd_module_init); +#else +module_init(dhd_module_init); +#endif module_exit(dhd_module_cleanup); /* @@ -4017,7 +4086,13 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, #endif /* defined(CONFIG_WIRELESS_EXT) */ #ifdef WL_CFG80211 - + if ((ntoh32(event->event_type) == WLC_E_IF) && + (((dhd_if_event_t *)*data)->action == WLC_E_IF_ADD)) + /* If ADD_IF has been called directly by wl utility then we + * should not report this. In case if ADD_IF was called from + * CFG stack, then too this event need not be reported back + */ + return (BCME_OK); if ((wl_cfg80211_is_progress_ifchange() || wl_cfg80211_is_progress_ifadd()) && (*ifidx != 0)) { /* diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 7866eb771d5..e19ec6b9c7e 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_sdio.c 301794 2011-12-08 20:41:35Z $ + * $Id: dhd_sdio.c 303389 2011-12-16 09:30:48Z $ */ #include @@ -1518,7 +1518,7 @@ enum { #ifdef DHD_DEBUG IOV_CHECKDIED, IOV_SERIALCONS, -#endif +#endif /* DHD_DEBUG */ IOV_DOWNLOAD, IOV_SOCRAM_STATE, IOV_FORCEEVEN, diff --git a/drivers/net/wireless/bcmdhd/include/dhdioctl.h b/drivers/net/wireless/bcmdhd/include/dhdioctl.h index 3f3755b53b0..0312d220601 100644 --- a/drivers/net/wireless/bcmdhd/include/dhdioctl.h +++ b/drivers/net/wireless/bcmdhd/include/dhdioctl.h @@ -25,7 +25,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhdioctl.h 277737 2011-08-16 17:54:59Z $ + * $Id: dhdioctl.h 307573 2012-01-12 00:04:39Z $ */ #ifndef _dhdioctl_h_ @@ -87,6 +87,7 @@ enum { #define DHD_BTA_VAL 0x1000 #define DHD_ISCAN_VAL 0x2000 #define DHD_ARPOE_VAL 0x4000 +#define DHD_WL_VAL 0x8000 #ifdef SDTEST /* For pktgen iovar */ diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index 41a078c42a0..a0e9ed12b88 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -33,17 +33,17 @@ #define EPI_RC_NUMBER 195 -#define EPI_INCREMENTAL_NUMBER 15 +#define EPI_INCREMENTAL_NUMBER 19 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 5, 90, 195, 15 +#define EPI_VERSION 5, 90, 195, 19 -#define EPI_VERSION_NUM 0x055ac30f +#define EPI_VERSION_NUM 0x055ac313 #define EPI_VERSION_DEV 5.90.195 -#define EPI_VERSION_STR "5.90.195.15" +#define EPI_VERSION_STR "5.90.195.19" #endif diff --git a/drivers/net/wireless/bcmdhd/include/proto/802.11.h b/drivers/net/wireless/bcmdhd/include/proto/802.11.h index 8850b2ded23..fd69aac4130 100644 --- a/drivers/net/wireless/bcmdhd/include/proto/802.11.h +++ b/drivers/net/wireless/bcmdhd/include/proto/802.11.h @@ -21,7 +21,7 @@ * * Fundamental types and constants relating to 802.11 * - * $Id: 802.11.h 289520 2011-10-13 04:44:55Z $ + * $Id: 802.11.h 304058 2011-12-21 00:39:12Z $ */ @@ -1394,6 +1394,14 @@ typedef struct dot11_ext_cap_ie dot11_ext_cap_ie_t; #define DOT11_OP_CLASS_NONE 255 +BWL_PRE_PACKED_STRUCT struct do11_ap_chrep { + uint8 id; + uint8 len; + uint8 reg; + uint8 chanlist[1]; +} BWL_POST_PACKED_STRUCT; +typedef struct do11_ap_chrep dot11_ap_chrep_t; + #define DOT11_RM_ACTION_RM_REQ 0 #define DOT11_RM_ACTION_RM_REP 1 @@ -1484,7 +1492,7 @@ typedef struct dot11_rmrep_bcn dot11_rmrep_bcn_t; #define DOT11_RMREQ_BCN_REPINFO_ID 1 #define DOT11_RMREQ_BCN_REPDET_ID 2 #define DOT11_RMREQ_BCN_REQUEST_ID 10 -#define DOT11_RMREQ_BCN_APCHREP_ID 51 +#define DOT11_RMREQ_BCN_APCHREP_ID DOT11_MNG_AP_CHREP_ID #define DOT11_RMREQ_BCN_REPDET_FIXED 0 diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h index 676068c0b38..e31bfa94c00 100644 --- a/drivers/net/wireless/bcmdhd/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wlioctl.h 302303 2011-12-10 07:51:07Z $ + * $Id: wlioctl.h 307468 2012-01-11 18:29:27Z $ */ @@ -821,8 +821,14 @@ typedef struct wlc_iov_trx_s { #define WLC_IOCTL_MEDLEN 1536 #ifdef WLC_HIGH_ONLY #define WLC_SAMPLECOLLECT_MAXLEN 1024 +#define WLC_SAMPLECOLLECT_MAXLEN_LCN40 1024 #else -#define WLC_SAMPLECOLLECT_MAXLEN 10240 +#if defined(LCNCONF) || defined(LCN40CONF) +#define WLC_SAMPLECOLLECT_MAXLEN 8192 +#else +#define WLC_SAMPLECOLLECT_MAXLEN 10240 +#endif +#define WLC_SAMPLECOLLECT_MAXLEN_LCN40 8192 #endif @@ -1411,7 +1417,7 @@ typedef struct wl_aci_args { #define TRIGGER_BADPLCP 0x10 #define TRIGGER_CRSGLITCH 0x20 #define WL_ACI_ARGS_LEGACY_LENGTH 16 -#define WL_SAMPLECOLLECT_T_VERSION 1 +#define WL_SAMPLECOLLECT_T_VERSION 2 typedef struct wl_samplecollect_args { uint8 coll_us; @@ -1419,7 +1425,7 @@ typedef struct wl_samplecollect_args { uint16 version; uint16 length; - uint8 trigger; + int8 trigger; uint16 timeout; uint16 mode; uint32 pre_dur; @@ -1429,6 +1435,11 @@ typedef struct wl_samplecollect_args { bool be_deaf; bool agc; bool filter; + + uint8 trigger_state; + uint8 module_sel1; + uint8 module_sel2; + uint16 nsamps; } wl_samplecollect_args_t; #define WL_SAMPLEDATA_HEADER_TYPE 1 diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index dc32f17a91f..2cbe333b0dd 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -73,7 +73,6 @@ #define CMD_GETBAND "GETBAND" #define CMD_COUNTRY "COUNTRY" #define CMD_P2P_SET_NOA "P2P_SET_NOA" -#define CMD_P2P_GET_NOA "P2P_GET_NOA" #define CMD_P2P_SET_PS "P2P_SET_PS" #define CMD_SET_AP_WPS_P2P_IE "SET_AP_WPS_P2P_IE" @@ -537,9 +536,6 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) bytes_written = wl_cfg80211_set_p2p_noa(net, command + skip, priv_cmd.total_len - skip); } - else if (strnicmp(command, CMD_P2P_GET_NOA, strlen(CMD_P2P_GET_NOA)) == 0) { - bytes_written = wl_cfg80211_get_p2p_noa(net, command, priv_cmd.total_len); - } else if (strnicmp(command, CMD_P2P_SET_PS, strlen(CMD_P2P_SET_PS)) == 0) { int skip = strlen(CMD_P2P_SET_PS) + 1; bytes_written = wl_cfg80211_set_p2p_ps(net, command + skip, @@ -611,30 +607,14 @@ int wl_android_exit(void) return ret; } -int wl_android_post_init(void) +void wl_android_post_init(void) { - struct net_device *ndev; - int ret = 0; - char buf[IFNAMSIZ]; if (!dhd_download_fw_on_driverload) { /* Call customer gpio to turn off power with WL_REG_ON signal */ dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); g_wifi_on = 0; - } else { - memset(buf, 0, IFNAMSIZ); -#ifdef CUSTOMER_HW2 - snprintf(buf, IFNAMSIZ, "%s%d", iface_name, 0); -#else - snprintf(buf, IFNAMSIZ, "%s%d", "eth", 0); -#endif - if ((ndev = dev_get_by_name (&init_net, buf)) != NULL) { - dhd_dev_init_ioctl(ndev); - dev_put(ndev); - } } - return ret; } - /** * Functions for Android WiFi card detection */ diff --git a/drivers/net/wireless/bcmdhd/wl_android.h b/drivers/net/wireless/bcmdhd/wl_android.h index 17373b7f6d5..3983306cfe3 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.h +++ b/drivers/net/wireless/bcmdhd/wl_android.h @@ -40,7 +40,7 @@ */ int wl_android_init(void); int wl_android_exit(void); -int wl_android_post_init(void); +void wl_android_post_init(void); int wl_android_wifi_on(struct net_device *dev); int wl_android_wifi_off(struct net_device *dev); int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd); diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 93fa447c16b..2312e0d2443 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -41,10 +41,9 @@ #include #include #include +#include #include -#include -#include #include #include #include @@ -54,11 +53,7 @@ #include #include #include - #include -#include -#include -#include #include #include @@ -66,42 +61,20 @@ #include static struct device *cfg80211_parent_dev = NULL; -static struct wl_priv *wlcfg_drv_priv = NULL; +static int vsdb_supported = 0; +struct wl_priv *wlcfg_drv_priv = NULL; u32 wl_dbg_level = WL_DBG_ERR; -#define WL_4329_FW_FILE "brcm/bcm4329-fullmac-4-218-248-5.bin" -#define WL_4329_NVRAM_FILE "brcm/bcm4329-fullmac-4-218-248-5.txt" #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" #define MAX_WAIT_TIME 1500 -static s8 ioctlbuf[WLC_IOCTL_MAXLEN]; +#define WL_SCAN_ACTIVE_TIME 40 +#define WL_SCAN_PASSIVE_TIME 130 +#define DNGL_FUNC(func, parameters) func parameters; #define COEX_DHCP -#if defined(COEX_DHCP) -#define BT_DHCP_eSCO_FIX /* use New SCO/eSCO smart YG - * suppression - */ -#define BT_DHCP_USE_FLAGS /* this flag boost wifi pkt priority - * to max, caution: -not fair to sco - */ -#define BT_DHCP_OPPR_WIN_TIME 2500 /* T1 start SCO/ESCo priority - * suppression - */ -#define BT_DHCP_FLAG_FORCE_TIME 5500 /* T2 turn off SCO/SCO supperesion - * is (timeout) - */ -enum wl_cfg80211_btcoex_status { - BT_DHCP_IDLE, - BT_DHCP_START, - BT_DHCP_OPPR_WIN, - BT_DHCP_FLAG_FORCE_TIMEOUT -}; - -static int wl_cfg80211_btcoex_init(struct wl_priv *wl); -static void wl_cfg80211_btcoex_deinit(struct wl_priv *wl); -#endif /* Set this to 1 to use a seperate interface (p2p0) * for p2p operations. @@ -247,6 +220,8 @@ static s32 wl_enq_event(struct wl_priv *wl, struct net_device *ndev, u32 type, const wl_event_msg_t *msg, void *data); static void wl_put_event(struct wl_event_q *e); static void wl_wakeup_event(struct wl_priv *wl); +static s32 wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); static s32 wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); @@ -264,21 +239,10 @@ static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); /* - * register/deregister sdio function + * register/deregister parent device */ static void wl_cfg80211_clear_parent_dev(void); -/* - * ioctl utilites - */ -static s32 wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, - s32 buf_len); -static __used s32 wl_dev_bufvar_set(struct net_device *dev, s8 *name, - s8 *buf, s32 len); -static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val); -static s32 wl_dev_intvar_get(struct net_device *dev, s8 *name, - s32 *retval); - /* * cfg80211 set_wiphy_params utilities */ @@ -321,7 +285,7 @@ static s32 wl_cp_ie(struct wl_priv *wl, u8 *dst, u16 dst_size); static u32 wl_get_ielen(struct wl_priv *wl); -static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev); +static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *dev); static void wl_free_wdev(struct wl_priv *wl); static s32 wl_inform_bss(struct wl_priv *wl); @@ -353,42 +317,19 @@ static bool wl_is_ibssmode(struct wl_priv *wl, struct net_device *ndev); static __used bool wl_is_ibssstarter(struct wl_priv *wl); /* - * dongle up/down , default configuration utilities + * link up/down , default configuration utilities */ +static s32 __wl_cfg80211_up(struct wl_priv *wl); +static s32 __wl_cfg80211_down(struct wl_priv *wl); +static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add); static bool wl_is_linkdown(struct wl_priv *wl, const wl_event_msg_t *e); static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net_device *ndev); static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e); static void wl_link_up(struct wl_priv *wl); static void wl_link_down(struct wl_priv *wl); -static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype); -static s32 __wl_cfg80211_up(struct wl_priv *wl); -static s32 __wl_cfg80211_down(struct wl_priv *wl); -static s32 wl_dongle_probecap(struct wl_priv *wl); +static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype); static void wl_init_conf(struct wl_conf *conf); -static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add); - -/* - * dongle configuration utilities - */ -#ifndef EMBEDDED_PLATFORM -static s32 wl_dongle_country(struct net_device *ndev, u8 ccode); -static s32 wl_dongle_up(struct net_device *ndev, u32 up); -static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode); -static s32 wl_dongle_glom(struct net_device *ndev, u32 glom, - u32 dongle_align); -static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar, - u32 bcn_timeout); -static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, - s32 scan_unassoc_time); -static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe, - s32 arp_ol); -static s32 wl_pattern_atoh(s8 *src, s8 *dst); -static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode); static s32 wl_update_wiphybands(struct wl_priv *wl); -#endif /* !EMBEDDED_PLATFORM */ -static __used void wl_dongle_poweron(struct wl_priv *wl); -static __used void wl_dongle_poweroff(struct wl_priv *wl); -static s32 wl_config_dongle(struct wl_priv *wl, bool need_lock); /* * iscan handler @@ -411,34 +352,21 @@ static s32 wl_iscan_pending(struct wl_priv *wl); static s32 wl_iscan_inprogress(struct wl_priv *wl); static s32 wl_iscan_aborted(struct wl_priv *wl); -/* - * fw/nvram downloading handler - */ -static void wl_init_fw(struct wl_fw_ctrl *fw); - /* * find most significant bit set */ static __used u32 wl_find_msb(u16 bit16); -/* - * update pmklist to dongle - */ -static __used s32 wl_update_pmklist(struct net_device *dev, - struct wl_pmk_list *pmk_list, s32 err); - -/* - * debufs support - */ -static int wl_debugfs_add_netdev_params(struct wl_priv *wl, struct net_device *ndev); -static void wl_debugfs_remove_netdev(struct wl_priv *wl); - /* * rfkill support */ static int wl_setup_rfkill(struct wl_priv *wl, bool setup); static int wl_rfkill_set(void *data, bool blocked); +static wl_scan_params_t *wl_cfg80211_scan_alloc_params(int channel, + int nprobes, int *out_params_size); +static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac); + /* * Some external functions, TODO: move them to dhd_linux.h */ @@ -579,7 +507,22 @@ static struct ieee80211_supported_band __wl_band_2ghz = { .channels = __wl_2ghz_channels, .n_channels = ARRAY_SIZE(__wl_2ghz_channels), .bitrates = wl_g_rates, - .n_bitrates = wl_g_rates_size + .n_bitrates = wl_g_rates_size, +#if ENABLE_P2P_INTERFACE + /* wpa_supplicant sets wmm_enabled based on whether ht_cap + * is present or not. The wmm_enabled is inturn used to + * set the replay counters in the RSN IE. Without this + * the 4way handshake will fail complaining that IE in beacon + * doesn't match with the IE present in the 3/4 EAPOL msg. + */ + .ht_cap = { + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU, + .ht_supported = TRUE, + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16 + } +#endif }; static struct ieee80211_supported_band __wl_band_5ghz_a = { @@ -748,36 +691,39 @@ wl_validate_wps_ie(char *wps_ie, bool *pbc) static chanspec_t wl_cfg80211_get_shared_freq(struct wiphy *wiphy) { - chanspec_t chspec; - int err = 0; - struct wl_priv *wl = wiphy_priv(wiphy); - struct net_device *dev = wl_to_prmry_ndev(wl); - struct ether_addr bssid; - struct wl_bss_info *bss = NULL; - - if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) { - /* STA interface is not associated. So start the new interface on a temp - * channel . Later proper channel will be applied by the above framework - * via set_channel (cfg80211 API). - */ - WL_DBG(("Not associated. Return a temp channel. \n")); + if (vsdb_supported) { return wf_chspec_aton(WL_P2P_TEMP_CHAN); } + else { + chanspec_t chspec; + int err = 0; + struct wl_priv *wl = wiphy_priv(wiphy); + struct net_device *dev = wl_to_prmry_ndev(wl); + struct ether_addr bssid; + struct wl_bss_info *bss = NULL; + if ((err = wldev_ioctl(dev, WLC_GET_BSSID, &bssid, sizeof(bssid), false))) { + /* STA interface is not associated. So start the new interface on a temp + * channel . Later proper channel will be applied by the above framework + * via set_channel (cfg80211 API). + */ + WL_DBG(("Not associated. Return a temp channel. \n")); + return wf_chspec_aton(WL_P2P_TEMP_CHAN); + } - *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); - if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf, - sizeof(WL_EXTRA_BUF_MAX), false))) { - WL_ERR(("Failed to get associated bss info, use temp channel \n")); - chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN); - } - else { - bss = (struct wl_bss_info *) (wl->extra_buf + 4); - chspec = bss->chanspec; - WL_DBG(("Valid BSS Found. chanspec:%d \n", bss->chanspec)); + *(u32 *) wl->extra_buf = htod32(WL_EXTRA_BUF_MAX); + if ((err = wldev_ioctl(dev, WLC_GET_BSS_INFO, wl->extra_buf, + sizeof(WL_EXTRA_BUF_MAX), false))) { + WL_ERR(("Failed to get associated bss info, use temp channel \n")); + chspec = wf_chspec_aton(WL_P2P_TEMP_CHAN); + } + else { + bss = (struct wl_bss_info *) (wl->extra_buf + 4); + chspec = bss->chanspec; + WL_DBG(("Valid BSS Found. chanspec:%d \n", bss->chanspec)); + } + return chspec; } - - return chspec; } static struct net_device* wl_cfg80211_add_monitor_if(char *name) @@ -802,9 +748,10 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, chanspec_t chspec; struct wl_priv *wl = wiphy_priv(wiphy); struct net_device *_ndev; - dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); - int (*net_attach)(dhd_pub_t *dhdp, int ifidx); + struct ether_addr primary_mac; + int (*net_attach)(void *dhdp, int ifidx); bool rollback_lock = false; + /* Use primary I/F for sending cmds down to firmware */ _ndev = wl_to_prmry_ndev(wl); @@ -852,7 +799,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, } WL_INFO(("%s: Released the lock and wait till IF_DEL is complete\n", __func__)); - timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, + timeout = wait_event_interruptible_timeout(wl->netif_change_event, (wl_get_p2p_status(wl, IF_DELETING) == false), msecs_to_jiffies(MAX_WAIT_TIME)); @@ -874,9 +821,11 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, wl_cfgp2p_set_firm_p2p(wl); wl_cfgp2p_init_discovery(wl); } + memset(wl->p2p->vir_ifname, 0, IFNAMSIZ); strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1); - wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); + get_primary_mac(wl, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); /* In concurrency case, STA may be already associated in a particular channel. * so retrieve the current channel of primary interface and then start the virtual @@ -895,7 +844,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, return ERR_PTR(-ENOMEM); } - timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, + timeout = wait_event_interruptible_timeout(wl->netif_change_event, (wl_get_p2p_status(wl, IF_ADD) == false), msecs_to_jiffies(MAX_WAIT_TIME)); if (timeout > 0 && (!wl_get_p2p_status(wl, IF_ADD))) { @@ -922,7 +871,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, rtnl_unlock(); rollback_lock = true; } - if (net_attach && !net_attach(dhd, _ndev->ifindex)) { + if (net_attach && !net_attach(wl->pub, _ndev->ifindex)) { wl_alloc_netinfo(wl, _ndev, vwdev, mode); WL_DBG((" virtual interface(%s) is " "created net attach done\n", wl->p2p->vir_ifname)); @@ -973,21 +922,22 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) wldev_iovar_setint(dev, "mpc", 1); wl_set_p2p_status(wl, IF_DELETING); ret = wl_cfgp2p_ifdel(wl, &p2p_mac); - if (ret) { /* Firmware could not delete the interface so we will not get WLC_E_IF * event for cleaning the dhd virtual nw interace * So lets do it here. Failures from fw will ensure the application to do * ifconfig down and up sequnce, which will reload the fw * however we should cleanup the linux network virtual interfaces */ - dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); - WL_ERR(("Firmware returned an error from p2p_ifdel\n")); - WL_ERR(("try to remove linux virtual interface %s\n", dev->name)); - dhd_del_if(dhd->info, dhd_net2idx(dhd->info, dev)); + /* Request framework to RESET and clean up */ + if (ret) { + struct net_device *ndev = wl_to_prmry_ndev(wl); + WL_ERR(("Firmware returned an error (%d) from p2p_ifdel" + "HANG Notification sent to %s\n", ret, ndev->name)); + wl_cfg80211_hang(ndev, WLAN_REASON_UNSPECIFIED); } /* Wait for any pending scan req to get aborted from the sysioc context */ - timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, + timeout = wait_event_interruptible_timeout(wl->netif_change_event, (wl_get_p2p_status(wl, IF_DELETING) == false), msecs_to_jiffies(MAX_WAIT_TIME)); if (timeout > 0 && !wl_get_p2p_status(wl, IF_DELETING)) { @@ -1014,6 +964,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, s32 mode = 0; chanspec_t chspec; struct wl_priv *wl = wiphy_priv(wiphy); + WL_DBG(("Enter \n")); switch (type) { case NL80211_IFTYPE_MONITOR: @@ -1046,7 +997,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, if (wl->p2p_supported && wl->p2p->vif_created) { WL_DBG(("p2p_vif_created (%d) p2p_on (%d)\n", wl->p2p->vif_created, p2p_on(wl))); - + wldev_iovar_setint(ndev, "mpc", 0); /* In concurrency case, STA may be already associated in a particular * channel. so retrieve the current channel of primary interface and * then start the virtual interface on that. @@ -1059,7 +1010,7 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, wl_set_p2p_status(wl, IF_CHANGING); wl_clr_p2p_status(wl, IF_CHANGED); err = wl_cfgp2p_ifchange(wl, &wl->p2p->int_addr, htod32(wlif_type), chspec); - timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, + timeout = wait_event_interruptible_timeout(wl->netif_change_event, (wl_get_p2p_status(wl, IF_CHANGED) == true), msecs_to_jiffies(MAX_WAIT_TIME)); wl_set_mode_by_netdev(wl, ndev, mode); @@ -1085,10 +1036,11 @@ wl_cfg80211_change_virtual_iface(struct wiphy *wiphy, struct net_device *ndev, s32 wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx, -int (*_net_attach)(dhd_pub_t *dhdp, int ifidx)) + void* _net_attach) { struct wl_priv *wl = wlcfg_drv_priv; s32 ret = BCME_OK; + WL_DBG(("Enter")); if (!ndev) { WL_ERR(("net is NULL\n")); return 0; @@ -1104,7 +1056,7 @@ int (*_net_attach)(dhd_pub_t *dhdp, int ifidx)) ndev->ifindex = idx; wl_clr_p2p_status(wl, IF_ADD); - wake_up_interruptible(&wl->dongle_event_wait); + wake_up_interruptible(&wl->netif_change_event); } else { ret = BCME_NOTREADY; } @@ -1153,7 +1105,7 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev) } /* Wake up any waiting thread */ - wake_up_interruptible(&wl->dongle_event_wait); + wake_up_interruptible(&wl->netif_change_event); return 0; } @@ -1185,7 +1137,7 @@ wl_cfg80211_notify_ifchange(void) struct wl_priv *wl = wlcfg_drv_priv; if (wl_get_p2p_status(wl, IF_CHANGING)) { wl_set_p2p_status(wl, IF_CHANGED); - wake_up_interruptible(&wl->dongle_event_wait); + wake_up_interruptible(&wl->netif_change_event); } return 0; } @@ -1222,6 +1174,7 @@ static void wl_scan_prep(struct wl_scan_params *params, struct cfg80211_scan_req params->passive_time = htod32(params->passive_time); params->home_time = htod32(params->home_time); + /* if request is null just exit so it will be all channel broadcast scan */ if (!request) return; @@ -1328,7 +1281,7 @@ wl_run_iscan(struct wl_iscan_ctrl *iscan, struct cfg80211_scan_request *request, goto done; } err = wldev_iovar_setbuf(iscan->dev, "iscan", params, params_size, - iscan->ioctl_buf, WLC_IOCTL_MEDLEN); + iscan->ioctl_buf, WLC_IOCTL_MEDLEN, NULL); if (unlikely(err)) { if (err == -EBUSY) { WL_ERR(("system busy : iscan canceled\n")); @@ -1418,7 +1371,7 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, goto exit; } err = wldev_iovar_setbuf(ndev, "escan", params, params_size, - wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN); + wl->escan_ioctl_buf, WLC_IOCTL_MEDLEN, NULL); if (unlikely(err)) WL_ERR((" Escan set error (%d)\n", err)); kfree(params); @@ -1516,8 +1469,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, u32 wpsie_len = 0; u8 wpsie[IE_MAX_LEN]; - /* If scan req comes for p2p0, send it over primary I/F as there - * there is no firmware interface corresponding to p2p0. + /* If scan req comes for p2p0, send it over primary I/F * Scan results will be delivered corresponding to cfg80211_scan_request */ if (ndev == wl->p2p_net) { @@ -1534,7 +1486,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, return -EAGAIN; } if (request && request->n_ssids > WL_SCAN_PARAMS_SSID_MAX) { - WL_ERR(("n_ssids > WL_SCAN_PARAMS_SSID_MAX\n")); + WL_ERR(("request null or n_ssids > WL_SCAN_PARAMS_SSID_MAX\n")); return -EOPNOTSUPP; } @@ -1700,52 +1652,11 @@ wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, return err; } -static s32 wl_dev_intvar_set(struct net_device *dev, s8 *name, s32 val) -{ - s8 buf[WLC_IOCTL_SMLEN]; - u32 len; - s32 err = 0; - - val = htod32(val); - len = bcm_mkiovar(name, (char *)(&val), sizeof(val), buf, sizeof(buf)); - BUG_ON(unlikely(!len)); - - err = wldev_ioctl(dev, WLC_SET_VAR, buf, len, false); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - } - - return err; -} - -static s32 -wl_dev_intvar_get(struct net_device *dev, s8 *name, s32 *retval) -{ - union { - s8 buf[WLC_IOCTL_SMLEN]; - s32 val; - } var; - u32 len; - u32 data_null; - s32 err = 0; - - len = bcm_mkiovar(name, (char *)(&data_null), 0, - (char *)(&var), sizeof(var.buf)); - BUG_ON(unlikely(!len)); - err = wldev_ioctl(dev, WLC_GET_VAR, &var, len, false); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - } - *retval = dtoh32(var.val); - - return err; -} - static s32 wl_set_rts(struct net_device *dev, u32 rts_threshold) { s32 err = 0; - err = wl_dev_intvar_set(dev, "rtsthresh", rts_threshold); + err = wldev_iovar_setint(dev, "rtsthresh", rts_threshold); if (unlikely(err)) { WL_ERR(("Error (%d)\n", err)); return err; @@ -1757,7 +1668,7 @@ static s32 wl_set_frag(struct net_device *dev, u32 frag_threshold) { s32 err = 0; - err = wl_dev_intvar_set(dev, "fragthresh", frag_threshold); + err = wldev_iovar_setint_bsscfg(dev, "fragthresh", frag_threshold, 0); if (unlikely(err)) { WL_ERR(("Error (%d)\n", err)); return err; @@ -1786,6 +1697,7 @@ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) s32 err = 0; CHECK_SYS_UP(wl); + WL_DBG(("Enter\n")); if (changed & WIPHY_PARAM_RTS_THRESHOLD && (wl->conf->rts_threshold != wiphy->rts_threshold)) { wl->conf->rts_threshold = wiphy->rts_threshold; @@ -1815,7 +1727,6 @@ static s32 wl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) return err; } } - return err; } @@ -2060,7 +1971,7 @@ wl_set_key_mgmt(struct net_device *dev, struct cfg80211_connect_params *sme) s32 bssidx = wl_cfgp2p_find_idx(wl, dev); if (sme->crypto.n_akm_suites) { - err = wl_dev_intvar_get(dev, "wpa_auth", &val); + err = wldev_iovar_getint(dev, "wpa_auth", &val); if (unlikely(err)) { WL_ERR(("could not get wpa_auth (%d)\n", err)); return err; @@ -2125,7 +2036,8 @@ wl_set_set_sharedkey(struct net_device *dev, if (!(sec->wpa_versions & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) && (sec->cipher_pairwise & (WLAN_CIPHER_SUITE_WEP40 | - WLAN_CIPHER_SUITE_WEP104))) { + WLAN_CIPHER_SUITE_WEP104))) + { memset(&key, 0, sizeof(key)); key.len = (u32) sme->key_len; key.index = (u32) sme->key_idx; @@ -2153,7 +2065,7 @@ wl_set_set_sharedkey(struct net_device *dev, WL_DBG(("key \"%s\"\n", key.data)); swap_key_from_BE(&key); err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), - ioctlbuf, sizeof(ioctlbuf), bssidx); + wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); if (unlikely(err)) { WL_ERR(("WLC_SET_KEY error (%d)\n", err)); return err; @@ -2247,10 +2159,10 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, wpaie_len = (wpa_ie != NULL) ? wpa_ie->length : wpa2_ie->len; wpaie_len += WPA_RSN_IE_TAG_FIXED_LEN; wldev_iovar_setbuf(dev, "wpaie", wpaie, wpaie_len, - ioctlbuf, sizeof(ioctlbuf)); + wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); } else { wldev_iovar_setbuf(dev, "wpaie", NULL, 0, - ioctlbuf, sizeof(ioctlbuf)); + wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); } /* find the WPSIE */ @@ -2331,8 +2243,8 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, /* increate dwell time to receive probe response or detect Beacon * from target AP at a noisy air only during connect command */ - ext_join_params->scan.active_time = DHD_SCAN_ACTIVE_TIME*3; - ext_join_params->scan.passive_time = DHD_SCAN_PASSIVE_TIME*3; + ext_join_params->scan.active_time = WL_SCAN_ACTIVE_TIME*3; + ext_join_params->scan.passive_time = WL_SCAN_PASSIVE_TIME*3; ext_join_params->scan.home_time = -1; if (sme->bssid) @@ -2360,8 +2272,8 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, ext_join_params->ssid.SSID_len)); } wl_set_drv_status(wl, CONNECTING, dev); - err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, ioctlbuf, - sizeof(ioctlbuf), wl_cfgp2p_find_idx(wl, dev)); + err = wldev_iovar_setbuf_bsscfg(dev, "join", ext_join_params, join_params_size, + wl->ioctl_buf, WLC_IOCTL_MAXLEN, wl_cfgp2p_find_idx(wl, dev), &wl->ioctl_buf_sync); kfree(ext_join_params); if (err) { wl_clr_drv_status(wl, CONNECTING, dev); @@ -2480,7 +2392,7 @@ wl_cfg80211_set_tx_power(struct wiphy *wiphy, txpwrmw = 0xffff; else txpwrmw = (u16) dbm; - err = wl_dev_intvar_set(ndev, "qtxpower", + err = wldev_iovar_setint(ndev, "qtxpower", (s32) (bcm_mw_to_qdbm(txpwrmw))); if (unlikely(err)) { WL_ERR(("qtxpower error (%d)\n", err)); @@ -2500,7 +2412,7 @@ static s32 wl_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm) s32 err = 0; CHECK_SYS_UP(wl); - err = wl_dev_intvar_get(ndev, "qtxpower", &txpwrdbm); + err = wldev_iovar_getint(ndev, "qtxpower", &txpwrdbm); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); return err; @@ -2561,8 +2473,8 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, if (key.len == 0) { /* key delete */ swap_key_from_BE(&key); - wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf, - sizeof(ioctlbuf), bssidx); + wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), + wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); if (unlikely(err)) { WL_ERR(("key delete error (%d)\n", err)); return err; @@ -2620,11 +2532,11 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; } swap_key_from_BE(&key); -#ifdef CONFIG_WIRELESS_EXT +#if defined(CONFIG_WIRELESS_EXT) dhd_wait_pend8021x(dev); #endif - wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf, - sizeof(ioctlbuf), bssidx); + wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), + wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); if (unlikely(err)) { WL_ERR(("WLC_SET_KEY error (%d)\n", err)); return err; @@ -2706,8 +2618,8 @@ wl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *dev, /* Set the new key/index */ swap_key_from_BE(&key); - err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf, - sizeof(ioctlbuf), bssidx); + err = wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, + WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); if (unlikely(err)) { WL_ERR(("WLC_SET_KEY error (%d)\n", err)); return err; @@ -2750,8 +2662,8 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, WL_DBG(("key index (%d)\n", key_idx)); /* Set the new key/index */ swap_key_from_BE(&key); - wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), ioctlbuf, - sizeof(ioctlbuf), bssidx); + wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, + WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); if (unlikely(err)) { if (err == -EINVAL) { if (key.index >= DOT11_MAX_DEFAULT_KEYS) { @@ -2847,13 +2759,13 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(wl); if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_AP) { err = wldev_iovar_getbuf(dev, "sta_info", (struct ether_addr *)mac, - ETHER_ADDR_LEN, ioctlbuf, sizeof(ioctlbuf)); + ETHER_ADDR_LEN, wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); if (err < 0) { WL_ERR(("GET STA INFO failed, %d\n", err)); return err; } sinfo->filled = STATION_INFO_INACTIVE_TIME; - sta = (sta_info_t *)ioctlbuf; + sta = (sta_info_t *)wl->ioctl_buf; sta->len = dtoh16(sta->len); sta->cap = dtoh16(sta->cap); sta->flags = dtoh32(sta->flags); @@ -2931,9 +2843,6 @@ wl_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(wl); if (wl->p2p_net == dev) { - /* Since p2p0 is a hidden interface in firmware, power - * mgmt doesn't apply. - */ return err; } @@ -3019,7 +2928,7 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy) for_each_ndev(wl, iter, next) wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev); wl_term_iscan(wl); - flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); + spin_lock_irqsave(&wl->cfgdrv_lock, flags); if (wl->scan_request) { cfg80211_scan_done(wl->scan_request, true); wl->scan_request = NULL; @@ -3028,7 +2937,7 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy) wl_clr_drv_status(wl, SCANNING, iter->ndev); wl_clr_drv_status(wl, SCAN_ABORTING, iter->ndev); } - dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags); + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); for_each_ndev(wl, iter, next) { if (wl_get_drv_status(wl, CONNECTING, iter->ndev)) { wl_bss_connect_done(wl, iter->ndev, NULL, NULL, false); @@ -3038,7 +2947,7 @@ static s32 wl_cfg80211_suspend(struct wiphy *wiphy) return 0; } -static __used s32 +static s32 wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, s32 err) { @@ -3046,9 +2955,12 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, struct wl_priv *wl = wlcfg_drv_priv; struct net_device *primary_dev = wl_to_prmry_ndev(wl); - /* Firmware is supporting pmk list only for STA interface i.e. primary interface + if (!pmk_list) { + printk("pmk_list is NULL\n"); + return -EINVAL; + } + /* pmk list is supported only for STA interface i.e. primary interface * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init - * Do we really need to support PMK cache in P2P in firmware? */ if (primary_dev != dev) { WL_INFO(("Not supporting Flushing pmklist on virtual" @@ -3065,8 +2977,8 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, } } if (likely(!err)) { - err = wl_dev_bufvar_set(dev, "pmkid_info", (char *)pmk_list, - sizeof(*pmk_list)); + err = wldev_iovar_setbuf(dev, "pmkid_info", (char *)pmk_list, + sizeof(*pmk_list), wl->ioctl_buf, WLC_IOCTL_MAXLEN, NULL); } return err; @@ -3167,7 +3079,7 @@ wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev) } -wl_scan_params_t * +static wl_scan_params_t * wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) { wl_scan_params_t *params; @@ -3228,13 +3140,13 @@ wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev) } } del_timer_sync(&wl->scan_timeout); - flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); + spin_lock_irqsave(&wl->cfgdrv_lock, flags); if (wl->scan_request) { cfg80211_scan_done(wl->scan_request, true); wl->scan_request = NULL; } wl_clr_drv_status(wl, SCANNING, ndev); - dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags); + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); if (params) kfree(params); return err; @@ -3248,23 +3160,21 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, { s32 target_channel; u32 id; + struct ether_addr primary_mac; struct net_device *ndev = NULL; + s32 err = BCME_OK; struct wl_priv *wl = wiphy_priv(wiphy); - dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); WL_DBG(("Enter, netdev_ifidx: %d \n", dev->ifindex)); if (wl->p2p_net == dev) { - /* Since there is no ifidx corresponding to p2p0, cmds to - * firmware should be routed through primary I/F - */ ndev = wl_to_prmry_ndev(wl); } else { ndev = dev; } - if (wl_get_drv_status(wl, SCANNING, dev)) { - wl_cfg80211_scan_abort(wl, dev); + if (wl_get_drv_status(wl, SCANNING, ndev)) { + wl_cfg80211_scan_abort(wl, ndev); } target_channel = ieee80211_frequency_to_channel(channel->center_freq); @@ -3277,14 +3187,15 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, cfg80211_ready_on_channel(dev, *cookie, channel, channel_type, duration, GFP_KERNEL); if (!p2p_is_on(wl)) { - wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); + get_primary_mac(wl, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); /* In case of p2p_listen command, supplicant send remain_on_channel * without turning on P2P */ p2p_on(wl) = true; - err = wl_cfgp2p_enable_discovery(wl, dev, NULL, 0); + err = wl_cfgp2p_enable_discovery(wl, ndev, NULL, 0); if (unlikely(err)) { goto exit; @@ -3307,6 +3218,93 @@ wl_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev return err; } +static s32 +wl_cfg80211_send_pending_tx_act_frm(struct wl_priv *wl) +{ + wl_af_params_t *tx_act_frm; + struct net_device *dev = wl->afx_hdl->dev; + if (!p2p_is_on(wl)) + return -1; + + if (dev == wl->p2p_net) { + dev = wl_to_prmry_ndev(wl); + } + + tx_act_frm = wl->afx_hdl->pending_tx_act_frm; + WL_DBG(("Sending the action frame\n")); + wl->afx_hdl->pending_tx_act_frm = NULL; + if (tx_act_frm != NULL) { + /* Suspend P2P discovery's search-listen to prevent it from + * starting a scan or changing the channel. + */ + wl_clr_drv_status(wl, SENDING_ACT_FRM, wl->afx_hdl->dev); + wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); + wl_cfg80211_scan_abort(wl, dev); + wl_cfgp2p_discover_enable_search(wl, false); + tx_act_frm->channel = wl->afx_hdl->peer_chan; + wl->afx_hdl->ack_recv = (wl_cfgp2p_tx_action_frame(wl, dev, + tx_act_frm, wl->afx_hdl->bssidx)) ? false : true; + } + return 0; +} +static void +wl_cfg80211_afx_handler(struct work_struct *work) +{ + + struct afx_hdl *afx_instance; + struct wl_priv *wl = wlcfg_drv_priv; + afx_instance = container_of(work, struct afx_hdl, work); + if (afx_instance != NULL) { + wl_cfgp2p_act_frm_search(wl, wl->afx_hdl->dev, + wl->afx_hdl->bssidx, 0); + } +} + +static bool +wl_cfg80211_send_at_common_channel(struct wl_priv *wl, + struct net_device *dev, + wl_af_params_t *af_params) +{ + WL_DBG((" enter ) \n")); + /* initialize afx_hdl */ + wl->afx_hdl->pending_tx_act_frm = af_params; + wl->afx_hdl->bssidx = wl_cfgp2p_find_idx(wl, dev); + wl->afx_hdl->dev = dev; + wl->afx_hdl->retry = 0; + wl->afx_hdl->peer_chan = WL_INVALID; + wl->afx_hdl->ack_recv = false; + memcpy(wl->afx_hdl->pending_tx_dst_addr.octet, + af_params->action_frame.da.octet, + sizeof(wl->afx_hdl->pending_tx_dst_addr.octet)); + /* Loop to wait until we have sent the pending tx action frame or the + * pending action frame tx is cancelled. + */ + while ((wl->afx_hdl->retry < WL_CHANNEL_SYNC_RETRY) && + (wl->afx_hdl->peer_chan == WL_INVALID)) { + wl_set_drv_status(wl, SENDING_ACT_FRM, dev); + wl_set_drv_status(wl, SCANNING, dev); + WL_DBG(("Scheduling the action frame for sending.. retry %d\n", + wl->afx_hdl->retry)); + /* Do find_peer_for_action */ + schedule_work(&wl->afx_hdl->work); + wait_for_completion(&wl->act_frm_scan); + wl->afx_hdl->retry++; + } + if (wl->afx_hdl->peer_chan != WL_INVALID) + wl_cfg80211_send_pending_tx_act_frm(wl); + else { + WL_ERR(("Couldn't find the peer after %d retries\n", + wl->afx_hdl->retry)); + } + wl->afx_hdl->dev = NULL; + wl->afx_hdl->bssidx = WL_INVALID; + wl_clr_drv_status(wl, SENDING_ACT_FRM, dev); + if (wl->afx_hdl->ack_recv) + return true; /* ACK */ + else + return false; /* NO ACK */ +} + static s32 wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, struct ieee80211_channel *channel, bool offchan, @@ -3314,29 +3312,28 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, bool channel_type_valid, unsigned int wait, const u8* buf, size_t len, u64 *cookie) { + struct ether_addr primary_mac; wl_action_frame_t *action_frame; wl_af_params_t *af_params; wifi_p2p_ie_t *p2p_ie; wpa_ie_fixed_t *wps_ie; + scb_val_t scb_val; const struct ieee80211_mgmt *mgmt; struct wl_priv *wl = wiphy_priv(wiphy); struct net_device *dev = NULL; - dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); s32 err = BCME_OK; s32 bssidx = 0; u32 p2pie_len = 0; u32 wpsie_len = 0; - u16 fc; + u32 id; + u32 retry = 0; bool ack = false; wifi_p2p_pub_act_frame_t *act_frm; + s8 eabuf[ETHER_ADDR_STR_LEN]; WL_DBG(("Enter \n")); if (ndev == wl->p2p_net) { - /* Firmware doesn't have an ifidx corresponding to p2p0 interface. - * so divert commands received on p2p0 to wlan0. Note that the TX status - * will be sent back to the interface(ndev) on which request is received - */ dev = wl_to_prmry_ndev(wl); } else { /* If TX req is for any valid ifidx. Use as is */ @@ -3345,16 +3342,14 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, /* find bssidx based on ndev */ bssidx = wl_cfgp2p_find_idx(wl, dev); - /* cookie generation */ - *cookie = (unsigned long) buf; - if (bssidx == -1) { WL_ERR(("Can not find the bssidx for dev( %p )\n", dev)); return -ENODEV; } if (p2p_is_on(wl)) { - wl_cfgp2p_generate_bss_mac(&dhd->mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); + get_primary_mac(wl, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); /* Suspend P2P discovery search-listen to prevent it from changing the * channel. */ @@ -3363,11 +3358,14 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, return -EFAULT; } } - - mgmt = (const struct ieee80211_mgmt *) buf; - fc = mgmt->frame_control; - if (fc != IEEE80211_STYPE_ACTION) { - if (fc == IEEE80211_STYPE_PROBE_RESP) { + *cookie = 0; + id = wl->send_action_id++; + if (id == 0) + id = wl->send_action_id++; + *cookie = id; + mgmt = (const struct ieee80211_mgmt *)buf; + if (ieee80211_is_mgmt(mgmt->frame_control)) { + if (ieee80211_is_probe_resp(mgmt->frame_control)) { s32 ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN; s32 ie_len = len - ie_offset; if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)(buf + ie_offset), ie_len)) @@ -3380,7 +3378,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, /* Order of Vendor IE is 1) WPS IE + * 2) P2P IE created by supplicant * So, it is ok to find start address of WPS IE - * to save IEs to firmware + * to save IEs */ wpsie_len = wps_ie->length + sizeof(wps_ie->length) + sizeof(wps_ie->tag); @@ -3388,18 +3386,35 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, VNDR_IE_PRBRSP_FLAG, (u8 *)wps_ie, wpsie_len + p2pie_len); } + cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); + goto exit; + } else if (ieee80211_is_disassoc(mgmt->frame_control) || + ieee80211_is_deauth(mgmt->frame_control)) { + memcpy(scb_val.ea.octet, mgmt->da, ETH_ALEN); + scb_val.val = mgmt->u.disassoc.reason_code; + wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, + sizeof(scb_val_t), true); + WL_DBG(("Disconnect STA : %s\n", + bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf))); + cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); + goto exit; + + } else if (ieee80211_is_action(mgmt->frame_control)) { + /* Abort the dwell time of any previous off-channel action frame that may + * be still in effect. Sending off-channel action frames relies on the + * driver's scan engine. If a previous off-channel action frame tx is + * still in progress (including the dwell time), then this new action + * frame will not be sent out. + */ + wl_cfg80211_scan_abort(wl, dev); + } - cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); - goto exit; + } else { - /* Abort the dwell time of any previous off-channel action frame that may - * be still in effect. Sending off-channel action frames relies on the - * driver's scan engine. If a previous off-channel action frame tx is - * still in progress (including the dwell time), then this new action - * frame will not be sent out. - */ - wl_cfg80211_scan_abort(wl, dev); + WL_ERR(("Driver only allows MGMT packet type\n")); + goto exit; } + af_params = (wl_af_params_t *) kzalloc(WL_WIFI_AF_PARAMS_SIZE, GFP_KERNEL); if (af_params == NULL) @@ -3411,7 +3426,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, action_frame = &af_params->action_frame; /* Add the packet Id */ - action_frame->packetId = (u32) action_frame; + action_frame->packetId = *cookie; WL_DBG(("action frame %d\n", action_frame->packetId)); /* Add BSSID */ memcpy(&action_frame->da, &mgmt->da[0], ETHER_ADDR_LEN); @@ -3445,23 +3460,47 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, WL_DBG(("action_frame->len: %d chan %d category %d subtype %d\n", action_frame->len, af_params->channel, act_frm->category, act_frm->subtype)); - if (wl->p2p->vif_created) { - /* - * To make sure to send successfully action frame, we have to turn off mpc - */ - if ((act_frm->subtype == P2P_PAF_GON_REQ)|| - (act_frm->subtype == P2P_PAF_GON_RSP)) { - wldev_iovar_setint(dev, "mpc", 0); - } else if (act_frm->subtype == P2P_PAF_GON_CONF) { - wldev_iovar_setint(dev, "mpc", 1); - } else if (act_frm->subtype == P2P_PAF_DEVDIS_REQ) { + /* + * To make sure to send successfully action frame, we have to turn off mpc + */ + if ((IS_PUB_ACT_FRAME(act_frm->category)) && + ((act_frm->subtype == P2P_PAF_GON_REQ) || + (act_frm->subtype == P2P_PAF_GON_RSP) || + (act_frm->subtype == P2P_PAF_GON_CONF) || + (act_frm->subtype == P2P_PAF_PROVDIS_REQ))) { + wldev_iovar_setint(dev, "mpc", 0); + } + + if (IS_PUB_ACT_FRAME(act_frm->category)) { + if (act_frm->subtype == P2P_PAF_DEVDIS_REQ) { af_params->dwell_time = WL_LONG_DWELL_TIME; + } else if ((act_frm->subtype == P2P_PAF_PROVDIS_REQ) || + (act_frm->subtype == P2P_PAF_PROVDIS_RSP)) { + af_params->dwell_time = WL_MED_DWELL_TIME; + } + } + if (IS_P2P_SOCIAL(af_params->channel) && + (IS_P2P_ACT_REQ(act_frm->category, act_frm->subtype) || + IS_GAS_REQ(act_frm->category, act_frm->action)) && + wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { + /* channel offload require P2P IE for Probe request + * otherwise, we will use wl_cfgp2p_tx_action_frame directly. + * channel offload for action request frame + */ + ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params); + } else { + for (retry = 0; retry < WL_CHANNEL_SYNC_RETRY; retry++) { + ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? + false : true; + if (ack) + break; } } - - ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true; cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL); - + if (IS_PUB_ACT_FRAME(act_frm->category) && + (act_frm->subtype == P2P_PAF_GON_CONF)) { + wldev_iovar_setint(dev, "mpc", 1); + } kfree(af_params); exit: return err; @@ -3518,9 +3557,6 @@ wl_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, struct wl_priv *wl = wiphy_priv(wiphy); if (wl->p2p_net == dev) { - /* Since there is no ifidx corresponding to p2p0, cmds to - * firmware should be routed through primary I/F - */ dev = wl_to_prmry_ndev(wl); } channel = ieee80211_frequency_to_channel(chan->center_freq); @@ -3539,7 +3575,6 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) s32 len = 0; s32 err = BCME_OK; u16 auth = 0; /* d11 open authentication */ - u16 count; u32 wsec; u32 pval = 0; u32 gval = 0; @@ -3577,7 +3612,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) len -= WPA_SUITE_LEN; /* check the unicast cipher */ ucast = (wpa_suite_ucast_t *)&mcast[1]; - count = ltoh16_ua(&ucast->count); + ltoh16_ua(&ucast->count); tmp = ucast->list[0].oui; switch (tmp[DOT11_OUI_LEN]) { case WPA_CIPHER_NONE: @@ -3600,7 +3635,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) wsec = (pval | gval | SES_OW_ENABLED); /* check the AKM */ mgmt = (wpa_suite_auth_key_mgmt_t *)&ucast->list[1]; - count = ltoh16_ua(&mgmt->count); + ltoh16_ua(&mgmt->count); tmp = (u8 *)&mgmt->list[0]; switch (tmp[DOT11_OUI_LEN]) { case RSN_AKM_NONE: @@ -3811,9 +3846,6 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, info->interval, info->dtim_period, info->head_len, info->tail_len)); if (wl->p2p_net == dev) { - /* Since there is no ifidx corresponding to p2p0, cmds to - * firmware should be routed through primary I/F - */ dev = wl_to_prmry_ndev(wl); } @@ -3862,7 +3894,7 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, WL_ERR(("No P2PIE in beacon \n")); } /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ - wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG, beacon_ie, wpsie_len + p2pie_len); @@ -3885,12 +3917,13 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, goto exit; } err = wldev_iovar_setbuf_bsscfg(dev, "ssid", &wl->p2p->ssid, - sizeof(wl->p2p->ssid), ioctlbuf, sizeof(ioctlbuf), bssidx); + sizeof(wl->p2p->ssid), wl->ioctl_buf, WLC_IOCTL_MAXLEN, + bssidx, &wl->ioctl_buf_sync); if (err < 0) { WL_ERR(("GO SSID setting error %d\n", err)); goto exit; } - if ((err = wl_cfgp2p_bss(dev, bssidx, 1)) < 0) { + if ((err = wl_cfgp2p_bss(wl, dev, bssidx, 1)) < 0) { WL_ERR(("GO Bring up error %d\n", err)); goto exit; } @@ -3970,7 +4003,7 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, beacon_ie, wpsie_len); wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ - wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } else { WL_DBG(("No WPSIE in beacon \n")); } @@ -4023,12 +4056,12 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, kfree(wl->ap_info->wps_ie); wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ - wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } else if (wl->ap_info->wps_ie == NULL) { WL_DBG((" WPS IE is added\n")); wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ - wl_dongle_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); + wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } /* find the RSN_IE */ if ((wpa2_ie = bcm_parse_tlvs((u8 *)info->tail, info->tail_len, @@ -4094,12 +4127,12 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, } if (update_bss) { wl->ap_info->security_mode = true; - wl_cfgp2p_bss(dev, bssidx, 0); + wl_cfgp2p_bss(wl, dev, bssidx, 0); if (wl_validate_wpa2ie(dev, wpa2_ie, bssidx) < 0 || wl_validate_wpaie(dev, wpa_ie, bssidx) < 0) { return BCME_ERROR; } - wl_cfgp2p_bss(dev, bssidx, 1); + wl_cfgp2p_bss(wl, dev, bssidx, 1); } } } else { @@ -4164,21 +4197,15 @@ s32 wl_mode_to_nl80211_iftype(s32 mode) return err; } -static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev) +static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev) { - struct wireless_dev *wdev; s32 err = 0; - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); - if (unlikely(!wdev)) { - WL_ERR(("Could not allocate wireless device\n")); - return ERR_PTR(-ENOMEM); - } wdev->wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct wl_priv)); if (unlikely(!wdev->wiphy)) { WL_ERR(("Couldn not allocate wiphy device\n")); err = -ENOMEM; - goto wiphy_new_out; + return err; } set_wiphy_dev(wdev->wiphy, sdiofunc_dev); wdev->wiphy->max_scan_ie_len = WL_SCAN_IE_LEN_MAX; @@ -4217,30 +4244,28 @@ static struct wireless_dev *wl_alloc_wdev(struct device *sdiofunc_dev) err = wiphy_register(wdev->wiphy); if (unlikely(err < 0)) { WL_ERR(("Couldn not register wiphy device (%d)\n", err)); - goto wiphy_register_out; + wiphy_free(wdev->wiphy); } - return wdev; - -wiphy_register_out: - wiphy_free(wdev->wiphy); - -wiphy_new_out: - kfree(wdev); - - return ERR_PTR(err); + return err; } static void wl_free_wdev(struct wl_priv *wl) { struct wireless_dev *wdev = wl->wdev; + struct wiphy *wiphy; if (!wdev) { WL_ERR(("wdev is invalid\n")); return; } + wiphy = wdev->wiphy; wiphy_unregister(wdev->wiphy); wdev->wiphy->dev.parent = NULL; - wiphy_free(wdev->wiphy); + wl_delete_all_netinfo(wl); + wiphy_free(wiphy); + /* PLEASE do NOT call any function after wiphy_free, the driver's private structure "wl", + * which is the private part of wiphy, has been freed in wiphy_free !!!!!!!!!!! + */ } static s32 wl_inform_bss(struct wl_priv *wl) @@ -4329,6 +4354,21 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) signal = notif_bss_info->rssi * 100; +#if defined(WLP2P) && ENABLE_P2P_INTERFACE + if (wl->p2p_net && wl->scan_request && wl->scan_request->dev == wl->p2p_net) { +#else + if (p2p_is_on(wl) && p2p_scan(wl)) { +#endif + /* find the P2PIE, if we do not find it, we will discard this frame */ + wifi_p2p_ie_t * p2p_ie; + if ((p2p_ie = wl_cfgp2p_find_p2pie((u8 *)beacon_proberesp->variable, + wl_get_ielen(wl))) == NULL) { + WL_ERR(("Couldn't find P2PIE in probe response/beacon\n")); + kfree(notif_bss_info); + return err; + } + } + cbss = cfg80211_inform_bss_frame(wiphy, channel, mgmt, le16_to_cpu(notif_bss_info->frame_len), signal, GFP_KERNEL); if (unlikely(!cbss)) { @@ -4395,89 +4435,136 @@ static bool wl_is_nonetwork(struct wl_priv *wl, const wl_event_msg_t *e) return false; } +/* The mainline kernel >= 3.2.0 has support for indicating new/del station + * to AP/P2P GO via events. If this change is backported to kernel for which + * this driver is being built, set CFG80211_STA_EVENT_AVAILABLE to 1. You + * should use this new/del sta event mechanism for BRCM supplicant from BRANCH + * HOSTAP_BRANCH_0_15 (ver >= 15_1). + */ +#define CFG80211_STA_EVENT_AVAILABLE 0 static s32 -wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, +wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) { - bool act; - bool isfree = false; s32 err = 0; - s32 freq; - s32 channel; - u8 body[200]; u32 event = ntoh32(e->event_type); u32 reason = ntoh32(e->reason); u32 len = ntoh32(e->datalen); - u16 fc = 0; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE + bool isfree = false; u8 *mgmt_frame; u8 bsscfgidx = e->bsscfgidx; + s32 freq; + s32 channel; + u8 body[200]; + u16 fc = 0; struct ieee80211_supported_band *band; struct ether_addr da; struct ether_addr bssid; struct wiphy *wiphy = wl_to_wiphy(wl); channel_info_t ci; +#else + struct station_info sinfo; +#endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE */ + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE memset(body, 0, sizeof(body)); memset(&bssid, 0, ETHER_ADDR_LEN); WL_DBG(("Enter \n")); if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID) return WL_INVALID; - if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { - memcpy(body, data, len); - wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", - NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx); - memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN); - err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); - switch (event) { - case WLC_E_ASSOC_IND: - fc = FC_ASSOC_REQ; - break; - case WLC_E_REASSOC_IND: - fc = FC_REASSOC_REQ; - break; - case WLC_E_DISASSOC_IND: - fc = FC_DISASSOC; - break; - case WLC_E_DEAUTH_IND: - fc = FC_DISASSOC; - break; - case WLC_E_DEAUTH: - fc = FC_DISASSOC; - break; - default: - fc = 0; - goto exit; - } - if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) - return err; + memcpy(body, data, len); + wldev_iovar_getbuf_bsscfg(ndev, "cur_etheraddr", + NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync); + memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); + err = wldev_ioctl(ndev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); + switch (event) { + case WLC_E_ASSOC_IND: + fc = FC_ASSOC_REQ; + break; + case WLC_E_REASSOC_IND: + fc = FC_REASSOC_REQ; + break; + case WLC_E_DISASSOC_IND: + fc = FC_DISASSOC; + break; + case WLC_E_DEAUTH_IND: + fc = FC_DISASSOC; + break; + case WLC_E_DEAUTH: + fc = FC_DISASSOC; + break; + default: + fc = 0; + goto exit; + } + if ((err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &ci, sizeof(ci), false))) + return err; - channel = dtoh32(ci.hw_channel); - if (channel <= CH_MAX_2G_CHANNEL) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else - band = wiphy->bands[IEEE80211_BAND_5GHZ]; + channel = dtoh32(ci.hw_channel); + if (channel <= CH_MAX_2G_CHANNEL) + band = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + band = wiphy->bands[IEEE80211_BAND_5GHZ]; #if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 38) && !defined(WL_COMPAT_WIRELESS) - freq = ieee80211_channel_to_frequency(channel); + freq = ieee80211_channel_to_frequency(channel); #else - freq = ieee80211_channel_to_frequency(channel, band->band); + freq = ieee80211_channel_to_frequency(channel, band->band); #endif - err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid, + err = wl_frame_get_mgmt(fc, &da, &e->addr, &bssid, &mgmt_frame, &len, body); - if (err < 0) - goto exit; - isfree = true; + if (err < 0) + goto exit; + isfree = true; - if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); - } else if (event == WLC_E_DISASSOC_IND) { - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); - } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { - cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + if (event == WLC_E_ASSOC_IND && reason == DOT11_SC_SUCCESS) { + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + } else if (event == WLC_E_DISASSOC_IND) { + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { + cfg80211_rx_mgmt(ndev, freq, mgmt_frame, len, GFP_ATOMIC); + } + +exit: + if (isfree) + kfree(mgmt_frame); + return err; +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !CFG80211_STA_EVENT_AVAILABLE */ + sinfo.filled = 0; + if (((event == WLC_E_ASSOC_IND) || (event == WLC_E_REASSOC_IND)) && + reason == DOT11_SC_SUCCESS) { + sinfo.filled = STATION_INFO_ASSOC_REQ_IES; + if (!data) { + WL_ERR(("No IEs present in ASSOC/REASSOC_IND")); + return -EINVAL; } + sinfo.assoc_req_ies = data; + sinfo.assoc_req_ies_len = len; + cfg80211_new_sta(ndev, e->addr.octet, &sinfo, GFP_ATOMIC); + } else if (event == WLC_E_DISASSOC_IND) { + cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); + } else if ((event == WLC_E_DEAUTH_IND) || (event == WLC_E_DEAUTH)) { + cfg80211_del_sta(ndev, e->addr.octet, GFP_ATOMIC); + } +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0) && !CFG80211_STA_EVENT_AVAILABLE */ + return err; +} + +static s32 +wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + bool act; + s32 err = 0; + u32 event = ntoh32(e->event_type); + if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { + wl_notify_connect_status_ap(wl, ndev, e, data); } else { WL_DBG(("wl_notify_connect_status : event %d status : %d \n", ntoh32(e->event_type), ntoh32(e->status))); @@ -4549,9 +4636,6 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, printk("%s nothing\n", __FUNCTION__); } } -exit: - if (isfree) - kfree(mgmt_frame); return err; } @@ -4576,48 +4660,15 @@ wl_notify_roaming_status(struct wl_priv *wl, struct net_device *ndev, return err; } -static __used s32 -wl_dev_bufvar_set(struct net_device *dev, s8 *name, s8 *buf, s32 len) -{ - struct wl_priv *wl = wlcfg_drv_priv; - u32 buflen; - - buflen = bcm_mkiovar(name, buf, len, wl->ioctl_buf, WL_IOCTL_LEN_MAX); - BUG_ON(unlikely(!buflen)); - - return wldev_ioctl(dev, WLC_SET_VAR, wl->ioctl_buf, buflen, true); -} - -static s32 -wl_dev_bufvar_get(struct net_device *dev, s8 *name, s8 *buf, - s32 buf_len) +static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) { - struct wl_priv *wl = wlcfg_drv_priv; - u32 len; - s32 err = 0; - - len = bcm_mkiovar(name, NULL, 0, wl->ioctl_buf, WL_IOCTL_LEN_MAX); - BUG_ON(unlikely(!len)); - err = wldev_ioctl(dev, WLC_GET_VAR, (void *)wl->ioctl_buf, - WL_IOCTL_LEN_MAX, false); - if (unlikely(err)) { - WL_ERR(("error (%d)\n", err)); - return err; - } - memcpy(buf, wl->ioctl_buf, buf_len); - - return err; -} - -static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) -{ - wl_assoc_info_t assoc_info; - struct wl_connect_info *conn_info = wl_to_conn(wl); + wl_assoc_info_t assoc_info; + struct wl_connect_info *conn_info = wl_to_conn(wl); s32 err = 0; WL_DBG(("Enter \n")); - err = wl_dev_bufvar_get(ndev, "assoc_info", wl->extra_buf, - WL_ASSOC_INFO_MAX); + err = wldev_iovar_getbuf(ndev, "assoc_info", NULL, 0, wl->extra_buf, + WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc info (%d)\n", err)); return err; @@ -4635,8 +4686,8 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) bzero(conn_info->resp_ie, sizeof(conn_info->resp_ie)); } if (assoc_info.req_len) { - err = wl_dev_bufvar_get(ndev, "assoc_req_ies", wl->extra_buf, - WL_ASSOC_INFO_MAX); + err = wldev_iovar_getbuf(ndev, "assoc_req_ies", NULL, 0, wl->extra_buf, + WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc req (%d)\n", err)); return err; @@ -4656,8 +4707,8 @@ static s32 wl_get_assoc_ies(struct wl_priv *wl, struct net_device *ndev) conn_info->req_ie_len = 0; } if (assoc_info.resp_len) { - err = wl_dev_bufvar_get(ndev, "assoc_resp_ies", wl->extra_buf, - WL_ASSOC_INFO_MAX); + err = wldev_iovar_getbuf(ndev, "assoc_resp_ies", NULL, 0, wl->extra_buf, + WL_ASSOC_INFO_MAX, NULL); if (unlikely(err)) { WL_ERR(("could not get assoc resp (%d)\n", err)); return err; @@ -4719,8 +4770,8 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) struct wl_bss_info *bi; struct wlc_ssid *ssid; struct bcm_tlv *tim; - u16 beacon_interval; - u8 dtim_period; + s32 beacon_interval; + s32 dtim_period; size_t ie_len; u8 *ie; u8 *curbssid; @@ -4774,7 +4825,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) /* * active scan was done so we could not get dtim * information out of probe response. - * so we speficially query dtim information to dongle. + * so we speficially query dtim information. */ err = wldev_ioctl(ndev, WLC_GET_DTIMPRD, &dtim_period, sizeof(dtim_period), false); @@ -4826,6 +4877,7 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, struct wl_connect_info *conn_info = wl_to_conn(wl); s32 err = 0; u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); + WL_DBG((" enter\n")); if (wl->scan_request) { wl_cfg80211_scan_abort(wl, ndev); @@ -4939,13 +4991,13 @@ wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, scan_done_out: del_timer_sync(&wl->scan_timeout); - flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); + spin_lock_irqsave(&wl->cfgdrv_lock, flags); if (wl->scan_request) { WL_DBG(("cfg80211_scan_done\n")); cfg80211_scan_done(wl->scan_request, false); wl->scan_request = NULL; } - dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags); + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); mutex_unlock(&wl->usr_sync); return err; } @@ -5014,9 +5066,6 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, memset(&bssid, 0, ETHER_ADDR_LEN); if (wl->p2p_net == ndev) { - /* Since there is no ifidx corresponding to p2p0, cmds to - * firmware should be routed through primary I/F - */ dev = wl_to_prmry_ndev(wl); } else { dev = ndev; @@ -5034,10 +5083,10 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, #endif if (event == WLC_E_ACTION_FRAME_RX) { wldev_iovar_getbuf_bsscfg(dev, "cur_etheraddr", - NULL, 0, ioctlbuf, sizeof(ioctlbuf), bsscfgidx); + NULL, 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bsscfgidx, &wl->ioctl_buf_sync); wldev_ioctl(dev, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN, false); - memcpy(da.octet, ioctlbuf, ETHER_ADDR_LEN); + memcpy(da.octet, wl->ioctl_buf, ETHER_ADDR_LEN); err = wl_frame_get_mgmt(FC_ACTION, &da, &e->addr, &bssid, &mgmt_frame, &mgmt_frame_len, (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1)); @@ -5052,9 +5101,18 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, /* * After complete GO Negotiation, roll back to mpc mode */ - if (act_frm->subtype == P2P_PAF_GON_CONF) { + if (IS_PUB_ACT_FRAME(act_frm->category) && + ((act_frm->subtype == P2P_PAF_GON_CONF)|| + (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { wldev_iovar_setint(dev, "mpc", 1); } + + if (IS_P2P_ACT_FRAME(act_frm->category) && + (act_frm->subtype == P2P_AF_PRESENCE_REQ)) { + /* TODO Do not submit these frames to supplicant, + * we will handle it in the driver + */ + } } else { mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); } @@ -5084,9 +5142,10 @@ static void wl_init_prof(struct wl_priv *wl, struct net_device *ndev) { unsigned long flags; struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); - flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); + + spin_lock_irqsave(&wl->cfgdrv_lock, flags); memset(profile, 0, sizeof(struct wl_profile)); - dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags); + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); } static void wl_init_event_handler(struct wl_priv *wl) @@ -5131,7 +5190,7 @@ static s32 wl_init_priv_mem(struct wl_priv *wl) WL_ERR(("Scan req alloc failed\n")); goto init_priv_mem_out; } - wl->ioctl_buf = (void *)kzalloc(WL_IOCTL_LEN_MAX, GFP_KERNEL); + wl->ioctl_buf = (void *)kzalloc(WLC_IOCTL_MAXLEN, GFP_KERNEL); if (unlikely(!wl->ioctl_buf)) { WL_ERR(("Ioctl buf alloc failed\n")); goto init_priv_mem_out; @@ -5151,11 +5210,6 @@ static s32 wl_init_priv_mem(struct wl_priv *wl) WL_ERR(("Iscan buf alloc failed\n")); goto init_priv_mem_out; } - wl->fw = (void *)kzalloc(sizeof(*wl->fw), GFP_KERNEL); - if (unlikely(!wl->fw)) { - WL_ERR(("fw object alloc failed\n")); - goto init_priv_mem_out; - } wl->pmk_list = (void *)kzalloc(sizeof(*wl->pmk_list), GFP_KERNEL); if (unlikely(!wl->pmk_list)) { WL_ERR(("pmk list alloc failed\n")); @@ -5166,6 +5220,14 @@ static s32 wl_init_priv_mem(struct wl_priv *wl) WL_ERR(("sta info alloc failed\n")); goto init_priv_mem_out; } + wl->afx_hdl = (void *)kzalloc(sizeof(*wl->afx_hdl), GFP_KERNEL); + if (unlikely(!wl->afx_hdl)) { + WL_ERR(("afx hdl alloc failed\n")); + goto init_priv_mem_out; + } else { + init_completion(&wl->act_frm_scan); + INIT_WORK(&wl->afx_hdl->work, wl_cfg80211_afx_handler); + } return 0; init_priv_mem_out: @@ -5190,12 +5252,16 @@ static void wl_deinit_priv_mem(struct wl_priv *wl) wl->extra_buf = NULL; kfree(wl->iscan); wl->iscan = NULL; - kfree(wl->fw); - wl->fw = NULL; kfree(wl->pmk_list); wl->pmk_list = NULL; kfree(wl->sta_info); wl->sta_info = NULL; + if (wl->afx_hdl) { + cancel_work_sync(&wl->afx_hdl->work); + kfree(wl->afx_hdl); + wl->afx_hdl = NULL; + } + if (wl->ap_info) { kfree(wl->ap_info->wpa_ie); kfree(wl->ap_info->rsn_ie); @@ -5210,7 +5276,8 @@ static s32 wl_create_event_handler(struct wl_priv *wl) int ret = 0; WL_DBG(("Enter \n")); - wl->event_tsk.thr_pid = DHD_PID_KT_INVALID; + /* Do not use DHD in cfg driver */ + wl->event_tsk.thr_pid = -1; PROC_START(wl_event_handler, wl, &wl->event_tsk, 0); if (wl->event_tsk.thr_pid < 0) ret = -ENOMEM; @@ -5249,13 +5316,13 @@ static void wl_notify_iscan_complete(struct wl_iscan_ctrl *iscan, bool aborted) WL_ERR(("Scan complete while device not scanning\n")); return; } - flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); + spin_lock_irqsave(&wl->cfgdrv_lock, flags); wl_clr_drv_status(wl, SCANNING, ndev); if (likely(wl->scan_request)) { cfg80211_scan_done(wl->scan_request, aborted); wl->scan_request = NULL; } - dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags); + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); wl->iscan_kickstart = false; } @@ -5291,7 +5358,7 @@ wl_get_iscan_results(struct wl_iscan_ctrl *iscan, u32 *status, list.results.buflen = htod32(WL_ISCAN_BUF_MAX); err = wldev_iovar_getbuf(iscan->dev, "iscanresults", &list, WL_ISCAN_RESULTS_FIXED_SIZE, iscan->scan_buf, - WL_ISCAN_BUF_MAX); + WL_ISCAN_BUF_MAX, NULL); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); return err; @@ -5364,13 +5431,11 @@ static s32 wl_iscan_aborted(struct wl_priv *wl) static s32 wl_iscan_thread(void *data) { - struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1 }; struct wl_iscan_ctrl *iscan = (struct wl_iscan_ctrl *)data; struct wl_priv *wl = iscan_to_wl(iscan); u32 status; int err = 0; - sched_setscheduler(current, SCHED_FIFO, ¶m); allow_signal(SIGTERM); status = WL_SCAN_RESULTS_PARTIAL; while (likely(!down_interruptible(&iscan->sync))) { @@ -5486,12 +5551,12 @@ static void wl_notify_escan_complete(struct wl_priv *wl, if (p2p_is_on(wl)) wl_clr_p2p_status(wl, SCANNING); - flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); + spin_lock_irqsave(&wl->cfgdrv_lock, flags); if (likely(wl->scan_request)) { cfg80211_scan_done(wl->scan_request, aborted); wl->scan_request = NULL; } - dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags); + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); } static s32 wl_escan_handler(struct wl_priv *wl, @@ -5506,14 +5571,22 @@ static s32 wl_escan_handler(struct wl_priv *wl, wl_scan_results_t *list; u32 bi_length; u32 i; + u8 *p2p_dev_addr = NULL; + WL_DBG((" enter event type : %d, status : %d \n", ntoh32(e->event_type), ntoh32(e->status))); /* P2P SCAN is coming from primary interface */ - if (wl_get_p2p_status(wl, SCANNING)) - ndev = wl->escan_info.ndev; + if (wl_get_p2p_status(wl, SCANNING)) { + if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) + ndev = wl->afx_hdl->dev; + else + ndev = wl->escan_info.ndev; + + } if (!ndev || !wl->escan_on || !wl_get_drv_status(wl, SCANNING, ndev)) { - WL_ERR(("escan is not ready \n")); + WL_ERR(("escan is not ready ndev %p wl->escan_on %d drv_status 0x%x\n", + ndev, wl->escan_on, wl_get_drv_status(wl, SCANNING, ndev))); return err; } @@ -5538,47 +5611,69 @@ static s32 wl_escan_handler(struct wl_priv *wl, WL_ERR(("Invalid bss_info length %d: ignoring\n", bi_length)); goto exit; } - list = (wl_scan_results_t *)wl->escan_info.escan_buf; - if (bi_length > ESCAN_BUF_SIZE - list->buflen) { - WL_ERR(("Buffer is too small: ignoring\n")); - goto exit; - } -#define WLC_BSS_RSSI_ON_CHANNEL 0x0002 - for (i = 0; i < list->count; i++) { - bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) - : list->bss_info; - - if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) && - CHSPEC_BAND(bi->chanspec) == CHSPEC_BAND(bss->chanspec) && - bi->SSID_len == bss->SSID_len && - !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) { - if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) == - (bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) { - /* preserve max RSSI if the measurements are - * both on-channel or both off-channel - */ - bss->RSSI = MAX(bss->RSSI, bi->RSSI); - } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) && - (bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) { - /* preserve the on-channel rssi measurement - * if the new measurement is off channel - */ - bss->RSSI = bi->RSSI; - bss->flags |= WLC_BSS_RSSI_ON_CHANNEL; - } + if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) { + p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length); + if (p2p_dev_addr && !memcmp(p2p_dev_addr, + wl->afx_hdl->pending_tx_dst_addr.octet, ETHER_ADDR_LEN)) { + s32 channel = CHSPEC_CHANNEL(dtohchanspec(bi->chanspec)); + WL_DBG(("ACTION FRAME SCAN : Peer found, channel : %d\n", channel)); + wl_clr_p2p_status(wl, SCANNING); + wl->afx_hdl->peer_chan = channel; + complete(&wl->act_frm_scan); goto exit; } + + } else { + list = (wl_scan_results_t *)wl->escan_info.escan_buf; + if (bi_length > ESCAN_BUF_SIZE - list->buflen) { + WL_ERR(("Buffer is too small: ignoring\n")); + goto exit; + } +#define WLC_BSS_RSSI_ON_CHANNEL 0x0002 + for (i = 0; i < list->count; i++) { + bss = bss ? (wl_bss_info_t *)((uintptr)bss + dtoh32(bss->length)) + : list->bss_info; + + if (!bcmp(&bi->BSSID, &bss->BSSID, ETHER_ADDR_LEN) && + CHSPEC_BAND(bi->chanspec) == CHSPEC_BAND(bss->chanspec) && + bi->SSID_len == bss->SSID_len && + !bcmp(bi->SSID, bss->SSID, bi->SSID_len)) { + if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) == + (bi->flags & WLC_BSS_RSSI_ON_CHANNEL)) { + /* preserve max RSSI if the measurements are + * both on-channel or both off-channel + */ + bss->RSSI = MAX(bss->RSSI, bi->RSSI); + } else if ((bss->flags & WLC_BSS_RSSI_ON_CHANNEL) && + (bi->flags & WLC_BSS_RSSI_ON_CHANNEL) == 0) { + /* preserve the on-channel rssi measurement + * if the new measurement is off channel + */ + bss->RSSI = bi->RSSI; + bss->flags |= WLC_BSS_RSSI_ON_CHANNEL; + } + + goto exit; + } + } + memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length); + list->version = dtoh32(bi->version); + list->buflen += bi_length; + list->count++; + } - memcpy(&(wl->escan_info.escan_buf[list->buflen]), bi, bi_length); - list->version = dtoh32(bi->version); - list->buflen += bi_length; - list->count++; } else if (status == WLC_E_STATUS_SUCCESS) { wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - if (likely(wl->scan_request)) { + if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) { + WL_INFO(("ACTION FRAME SCAN DONE\n")); + wl_clr_p2p_status(wl, SCANNING); + wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); + if (wl->afx_hdl->peer_chan == WL_INVALID) + complete(&wl->act_frm_scan); + } else if (likely(wl->scan_request)) { mutex_lock(&wl->usr_sync); del_timer_sync(&wl->scan_timeout); WL_INFO(("ESCAN COMPLETED\n")); @@ -5590,7 +5685,13 @@ static s32 wl_escan_handler(struct wl_priv *wl, } else if (status == WLC_E_STATUS_ABORT) { wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - if (likely(wl->scan_request)) { + if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) { + WL_INFO(("ACTION FRAME SCAN DONE\n")); + wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); + wl_clr_p2p_status(wl, SCANNING); + if (wl->afx_hdl->peer_chan == WL_INVALID) + complete(&wl->act_frm_scan); + } else if (likely(wl->scan_request)) { mutex_lock(&wl->usr_sync); del_timer_sync(&wl->scan_timeout); WL_INFO(("ESCAN ABORTED\n")); @@ -5603,7 +5704,13 @@ static s32 wl_escan_handler(struct wl_priv *wl, else { WL_ERR(("unexpected Escan Event %d : abort\n", status)); wl->escan_info.escan_state = WL_ESCAN_STATE_IDLE; - if (likely(wl->scan_request)) { + if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) { + WL_INFO(("ACTION FRAME SCAN DONE\n")); + wl_clr_p2p_status(wl, SCANNING); + wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); + if (wl->afx_hdl->peer_chan == WL_INVALID) + complete(&wl->act_frm_scan); + } else if (likely(wl->scan_request)) { mutex_lock(&wl->usr_sync); del_timer_sync(&wl->scan_timeout); wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; @@ -5649,16 +5756,12 @@ static s32 wl_init_scan(struct wl_priv *wl) return err; } -static void wl_init_fw(struct wl_fw_ctrl *fw) -{ - fw->status = 0; -} - static s32 wl_init_priv(struct wl_priv *wl) { struct wiphy *wiphy = wl_to_wiphy(wl); struct net_device *ndev = wl_to_prmry_ndev(wl); s32 err = 0; + wl->scan_request = NULL; wl->pwr_save = !!(wiphy->flags & WIPHY_FLAG_PS_ON_BY_DEFAULT); wl->iscan_on = false; @@ -5666,10 +5769,10 @@ static s32 wl_init_priv(struct wl_priv *wl) wl->roam_on = false; wl->iscan_kickstart = false; wl->active_scan = true; - wl->dongle_up = false; wl->rf_blocked = false; - - init_waitqueue_head(&wl->dongle_event_wait); + spin_lock_init(&wl->cfgdrv_lock); + mutex_init(&wl->ioctl_buf_sync); + init_waitqueue_head(&wl->netif_change_event); wl_init_eq(wl); err = wl_init_priv_mem(wl); if (err) @@ -5681,18 +5784,18 @@ static s32 wl_init_priv(struct wl_priv *wl) err = wl_init_scan(wl); if (err) return err; - wl_init_fw(wl->fw); wl_init_conf(wl->conf); wl_init_prof(wl, ndev); wl_link_down(wl); + DNGL_FUNC(dhd_cfg80211_init, (wl)); return err; } static void wl_deinit_priv(struct wl_priv *wl) { + DNGL_FUNC(dhd_cfg80211_deinit, (wl)); wl_destroy_event_handler(wl); - wl->dongle_up = false; /* dongle down */ wl_flush_eq(wl); wl_link_down(wl); del_timer_sync(&wl->scan_timeout); @@ -5721,7 +5824,7 @@ static s32 wl_cfg80211_detach_p2p(void) struct wl_priv *wl = wlcfg_drv_priv; struct wireless_dev *wdev = wl->p2p_wdev; - WL_TRACE(("Enter \n")); + WL_DBG(("Enter \n")); if (!wdev || !wl) { WL_ERR(("Invalid Ptr\n")); return -EINVAL; @@ -5731,7 +5834,7 @@ static s32 wl_cfg80211_detach_p2p(void) wl->p2p_wdev = NULL; wl->p2p_net = NULL; - + WL_DBG(("Freeing 0x%08x \n", (unsigned int)wdev)); kfree(wdev); return 0; @@ -5751,9 +5854,11 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) if (wl && !wl_get_drv_status(wl, READY, ndev)) { if (wl->wdev && wl_cfgp2p_supported(wl, ndev)) { +#if !ENABLE_P2P_INTERFACE wl->wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT)| BIT(NL80211_IFTYPE_P2P_GO)); +#endif if ((err = wl_cfgp2p_init_priv(wl)) != 0) goto fail; @@ -5794,10 +5899,17 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) } WL_DBG(("func %p\n", wl_cfg80211_get_parent_dev())); dev = wl_cfg80211_get_parent_dev(); - wdev = wl_alloc_wdev(dev); - if (IS_ERR(wdev)) - return -ENOMEM; + wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); + if (unlikely(!wdev)) { + WL_ERR(("Could not allocate wireless device\n")); + return -ENOMEM; + } + err = wl_setup_wiphy(wdev, dev); + if (unlikely(err)) { + kfree(wdev); + return -ENOMEM; + } wdev->iftype = wl_mode_to_nl80211_iftype(WL_MODE_BSS); wl = (struct wl_priv *)wiphy_priv(wdev->wiphy); wl->wdev = wdev; @@ -5830,7 +5942,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) #if defined(COEX_DHCP) if (wl_cfg80211_btcoex_init(wl)) goto cfg80211_attach_out; -#endif /* COEX_DHCP */ +#endif wlcfg_drv_priv = wl; @@ -5848,7 +5960,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) return err; } -void wl_cfg80211_detach(void) +void wl_cfg80211_detach(void *para) { struct wl_priv *wl; @@ -5858,7 +5970,7 @@ void wl_cfg80211_detach(void) #if defined(COEX_DHCP) wl_cfg80211_btcoex_deinit(wl); -#endif /* COEX_DHCP */ +#endif #if defined(WLP2P) && ENABLE_P2P_INTERFACE wl_cfg80211_detach_p2p(); @@ -5870,6 +5982,9 @@ void wl_cfg80211_detach(void) wlcfg_drv_priv = NULL; wl_cfg80211_clear_parent_dev(); wl_free_wdev(wl); + /* PLEASE do NOT call any function after wl_free_wdev, the driver's private structure "wl", + * which is the private part of wiphy, has been freed in wl_free_wdev !!!!!!!!!!! + */ } static void wl_wakeup_event(struct wl_priv *wl) @@ -5932,20 +6047,17 @@ static s32 wl_event_handler(void *data) break; while ((e = wl_deq_event(wl))) { WL_DBG(("event type (%d), if idx: %d\n", e->etype, e->emsg.ifidx)); - /* All P2P device address related events comes on primary interface since - * there is no corresponding interface in the firmware. Map it to p2p0 + * there is no corresponding bsscfg for P2P interface. Map it to p2p0 * interface. */ if ((wl_is_p2p_event(e) == TRUE) && (wl->p2p_net)) { netdev = wl->p2p_net; } else { netdev = dhd_idx2net((struct dhd_pub *)(wl->pub), e->emsg.ifidx); - if (!netdev) { - netdev = wl_to_prmry_ndev(wl); - } } - + if (!netdev) + netdev = wl_to_prmry_ndev(wl); if (e->etype < WLC_E_LAST && wl->evt_handler[e->etype]) { wl->evt_handler[e->etype] (wl, netdev, &e->emsg, e->edata); } else { @@ -6056,7 +6168,7 @@ static void wl_put_event(struct wl_event_q *e) kfree(e); } -static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftype) +static s32 wl_config_ifmode(struct wl_priv *wl, struct net_device *ndev, s32 iftype) { s32 infra = 0; s32 err = 0; @@ -6097,7 +6209,8 @@ static s32 wl_dongle_mode(struct wl_priv *wl, struct net_device *ndev, s32 iftyp return 0; } -static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) + +static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) { s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; @@ -6110,7 +6223,7 @@ static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, boo err = wldev_ioctl(ndev, WLC_GET_VAR, iovbuf, sizeof(iovbuf), false); if (unlikely(err)) { WL_ERR(("Get event_msgs error (%d)\n", err)); - goto dongle_eventmsg_out; + goto eventmsg_out; } memcpy(eventmask, iovbuf, WL_EVENTING_MASK_LEN); if (add) { @@ -6123,350 +6236,15 @@ static s32 wl_dongle_add_remove_eventmsg(struct net_device *ndev, u16 event, boo err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); if (unlikely(err)) { WL_ERR(("Set event_msgs error (%d)\n", err)); - goto dongle_eventmsg_out; - } - -dongle_eventmsg_out: - return err; - -} - - -#ifndef EMBEDDED_PLATFORM -static s32 wl_dongle_country(struct net_device *ndev, u8 ccode) -{ - - s32 err = 0; - - return err; -} - -static s32 wl_dongle_up(struct net_device *ndev, u32 up) -{ - s32 err = 0; - - err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true); - if (unlikely(err)) { - WL_ERR(("WLC_UP error (%d)\n", err)); - } - return err; -} - -static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode) -{ - s32 err = 0; - - WL_TRACE(("In\n")); - err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), true); - if (unlikely(err)) { - WL_ERR(("WLC_SET_PM error (%d)\n", err)); - } - return err; -} - -static s32 -wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align) -{ - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - - s32 err = 0; - - /* Match Host and Dongle rx alignment */ - bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, - sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (unlikely(err)) { - WL_ERR(("txglomalign error (%d)\n", err)); - goto dongle_glom_out; - } - /* disable glom option per default */ - bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (unlikely(err)) { - WL_ERR(("txglom error (%d)\n", err)); - goto dongle_glom_out; - } -dongle_glom_out: - return err; -} - -static s32 -wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) -{ - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - - s32 err = 0; - - /* Setup timeout if Beacons are lost and roam is off to report link down */ - if (roamvar) { - bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, - sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (unlikely(err)) { - WL_ERR(("bcn_timeout error (%d)\n", err)); - goto dongle_rom_out; - } - } - /* Enable/Disable built-in roaming to allow supplicant to take care of roaming */ - bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (unlikely(err)) { - WL_ERR(("roam_off error (%d)\n", err)); - goto dongle_rom_out; - } -dongle_rom_out: - return err; -} - -static s32 -wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, - s32 scan_unassoc_time) -{ - s32 err = 0; - - err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time, - sizeof(scan_assoc_time), true); - if (err) { - if (err == -EOPNOTSUPP) { - WL_INFO(("Scan assoc time is not supported\n")); - } else { - WL_ERR(("Scan assoc time error (%d)\n", err)); - } - goto dongle_scantime_out; + goto eventmsg_out; } - err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time, - sizeof(scan_unassoc_time), true); - if (err) { - if (err == -EOPNOTSUPP) { - WL_INFO(("Scan unassoc time is not supported\n")); - } else { - WL_ERR(("Scan unassoc time error (%d)\n", err)); - } - goto dongle_scantime_out; - } - -dongle_scantime_out: - return err; -} - -static s32 -wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol) -{ - /* Room for "event_msgs" + '\0' + bitvec */ - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - - s32 err = 0; - - /* Set ARP offload */ - bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (err) { - if (err == -EOPNOTSUPP) - WL_INFO(("arpoe is not supported\n")); - else - WL_ERR(("arpoe error (%d)\n", err)); - - goto dongle_offload_out; - } - bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (err) { - if (err == -EOPNOTSUPP) - WL_INFO(("arp_ol is not supported\n")); - else - WL_ERR(("arp_ol error (%d)\n", err)); - - goto dongle_offload_out; - } - -dongle_offload_out: - return err; -} - -static s32 wl_pattern_atoh(s8 *src, s8 *dst) -{ - int i; - if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) { - WL_ERR(("Mask invalid format. Needs to start with 0x\n")); - return -1; - } - src = src + 2; /* Skip past 0x */ - if (strlen(src) % 2 != 0) { - WL_ERR(("Mask invalid format. Needs to be of even length\n")); - return -1; - } - for (i = 0; *src != '\0'; i++) { - char num[3]; - strncpy(num, src, 2); - num[2] = '\0'; - dst[i] = (u8) simple_strtoul(num, NULL, 16); - src += 2; - } - return i; -} - -static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode) -{ - /* Room for "event_msgs" + '\0' + bitvec */ - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - - const s8 *str; - struct wl_pkt_filter pkt_filter; - struct wl_pkt_filter *pkt_filterp; - s32 buf_len; - s32 str_len; - u32 mask_size; - u32 pattern_size; - s8 buf[256]; - s32 err = 0; - - /* add a default packet filter pattern */ - str = "pkt_filter_add"; - str_len = strlen(str); - strncpy(buf, str, str_len); - buf[str_len] = '\0'; - buf_len = str_len + 1; - - pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1); - - /* Parse packet filter id. */ - pkt_filter.id = htod32(100); - - /* Parse filter polarity. */ - pkt_filter.negate_match = htod32(0); - - /* Parse filter type. */ - pkt_filter.type = htod32(0); - - /* Parse pattern filter offset. */ - pkt_filter.u.pattern.offset = htod32(0); - - /* Parse pattern filter mask. */ - mask_size = htod32(wl_pattern_atoh("0xff", - (char *)pkt_filterp->u.pattern. - mask_and_pattern)); - - /* Parse pattern filter pattern. */ - pattern_size = htod32(wl_pattern_atoh("0x00", - (char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size])); - - if (mask_size != pattern_size) { - WL_ERR(("Mask and pattern not the same size\n")); - err = -EINVAL; - goto dongle_filter_out; - } - - pkt_filter.u.pattern.size_bytes = mask_size; - buf_len += WL_PKT_FILTER_FIXED_LEN; - buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); - - /* Keep-alive attributes are set in local - * variable (keep_alive_pkt), and - * then memcpy'ed into buffer (keep_alive_pktp) since there is no - * guarantee that the buffer is properly aligned. - */ - memcpy((char *)pkt_filterp, &pkt_filter, - WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); - - err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, true); - if (err) { - if (err == -EOPNOTSUPP) { - WL_INFO(("filter not supported\n")); - } else { - WL_ERR(("filter (%d)\n", err)); - } - goto dongle_filter_out; - } - - /* set mode to allow pattern */ - bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, - sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (err) { - if (err == -EOPNOTSUPP) { - WL_INFO(("filter_mode not supported\n")); - } else { - WL_ERR(("filter_mode (%d)\n", err)); - } - goto dongle_filter_out; - } - -dongle_filter_out: - return err; -} -#endif /* !EMBEDDED_PLATFORM */ - -s32 wl_config_dongle(struct wl_priv *wl, bool need_lock) -{ -#ifndef DHD_SDALIGN -#define DHD_SDALIGN 32 -#endif - struct net_device *ndev; - struct wireless_dev *wdev; - s32 err = 0; - - WL_TRACE(("In\n")); - if (wl->dongle_up) { - WL_ERR(("Dongle is already up\n")); - return err; - } - - ndev = wl_to_prmry_ndev(wl); - wdev = ndev->ieee80211_ptr; - if (need_lock) - rtnl_lock(); -#ifndef EMBEDDED_PLATFORM - err = wl_dongle_up(ndev, 0); - if (unlikely(err)) { - WL_ERR(("wl_dongle_up failed\n")); - goto default_conf_out; - } - err = wl_dongle_country(ndev, 0); - if (unlikely(err)) { - WL_ERR(("wl_dongle_country failed\n")); - goto default_conf_out; - } - err = wl_dongle_power(ndev, PM_FAST); - if (unlikely(err)) { - WL_ERR(("wl_dongle_power failed\n")); - goto default_conf_out; - } - err = wl_dongle_glom(ndev, 0, DHD_SDALIGN); - if (unlikely(err)) { - WL_ERR(("wl_dongle_glom failed\n")); - goto default_conf_out; - } - err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3); - if (unlikely(err)) { - WL_ERR(("wl_dongle_roam failed\n")); - goto default_conf_out; - } - wl_dongle_scantime(ndev, 40, 80); - wl_dongle_offload(ndev, 1, 0xf); - wl_dongle_filter(ndev, 1); -#endif /* !EMBEDDED_PLATFORM */ - - err = wl_dongle_mode(wl, ndev, wdev->iftype); - if (unlikely(err && err != -EINPROGRESS)) { - WL_ERR(("wl_dongle_mode failed\n")); - goto default_conf_out; - } - err = wl_dongle_probecap(wl); - if (unlikely(err)) { - WL_ERR(("wl_dongle_probecap failed\n")); - goto default_conf_out; - } - - wl->dongle_up = true; -default_conf_out: - if (need_lock) - rtnl_unlock(); +eventmsg_out: return err; } -static s32 wl_update_wiphybands(struct wl_priv *wl) +s32 wl_update_wiphybands(struct wl_priv *wl) { struct wiphy *wiphy; s8 phylist_buf[128]; @@ -6494,14 +6272,25 @@ static s32 __wl_cfg80211_up(struct wl_priv *wl) { s32 err = 0; struct net_device *ndev = wl_to_prmry_ndev(wl); + struct wireless_dev *wdev = ndev->ieee80211_ptr; + WL_TRACE(("In\n")); - wl_debugfs_add_netdev_params(wl, ndev); - err = wl_config_dongle(wl, false); + err = dhd_config_dongle(wl, false); if (unlikely(err)) return err; - dhd_monitor_init(wl->pub); - wl_invoke_iscan(wl); + + err = wl_config_ifmode(wl, ndev, wdev->iftype); + if (unlikely(err && err != -EINPROGRESS)) { + WL_ERR(("wl_config_ifmode failed\n")); + } + err = wl_update_wiphybands(wl); + if (unlikely(err)) { + WL_ERR(("wl_update_wiphybands failed\n")); + } + + err = dhd_monitor_init(wl->pub); + err = wl_invoke_iscan(wl); wl_set_drv_status(wl, READY, ndev); return err; } @@ -6512,6 +6301,7 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) unsigned long flags; struct net_info *iter, *next; struct net_device *ndev = wl_to_prmry_ndev(wl); + WL_TRACE(("In\n")); /* Check if cfg80211 interface is already down */ if (!wl_get_drv_status(wl, READY, ndev)) @@ -6520,7 +6310,7 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) wl_set_drv_status(wl, SCAN_ABORTING, iter->ndev); wl_term_iscan(wl); - flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); + spin_lock_irqsave(&wl->cfgdrv_lock, flags); if (wl->scan_request) { cfg80211_scan_done(wl->scan_request, true); wl->scan_request = NULL; @@ -6537,21 +6327,19 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) } wl_to_prmry_ndev(wl)->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; - dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags); + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); - wl->dongle_up = false; + DNGL_FUNC(dhd_cfg80211_down, (wl)); wl_flush_eq(wl); wl_link_down(wl); if (wl->p2p_supported) wl_cfgp2p_down(wl); dhd_monitor_uninit(); - wl_debugfs_remove_netdev(wl); - return err; } -s32 wl_cfg80211_up(void) +s32 wl_cfg80211_up(void *para) { struct wl_priv *wl; s32 err = 0; @@ -6564,17 +6352,16 @@ s32 wl_cfg80211_up(void) if (err) WL_ERR(("__wl_cfg80211_up failed\n")); mutex_unlock(&wl->usr_sync); - return err; } -/* Private Event to Supplicant with indication that FW hangs */ +/* Private Event to Supplicant with indication that chip hangs */ int wl_cfg80211_hang(struct net_device *dev, u16 reason) { struct wl_priv *wl; wl = wlcfg_drv_priv; - WL_ERR(("In : FW crash Eventing\n")); + WL_ERR(("In : chip crash eventing\n")); cfg80211_disconnected(dev, reason, NULL, 0, GFP_KERNEL); if (wl != NULL) { wl_link_down(wl); @@ -6582,7 +6369,7 @@ int wl_cfg80211_hang(struct net_device *dev, u16 reason) return 0; } -s32 wl_cfg80211_down(void) +s32 wl_cfg80211_down(void *para) { struct wl_priv *wl; s32 err = 0; @@ -6596,25 +6383,15 @@ s32 wl_cfg80211_down(void) return err; } -static s32 wl_dongle_probecap(struct wl_priv *wl) -{ - s32 err = 0; - - err = wl_update_wiphybands(wl); - if (unlikely(err)) - return err; - - return err; -} - static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item) { unsigned long flags; void *rptr = NULL; struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); + if (!profile) return NULL; - flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); + spin_lock_irqsave(&wl->cfgdrv_lock, flags); switch (item) { case WL_PROF_SEC: rptr = &profile->sec; @@ -6629,7 +6406,7 @@ static void *wl_read_prof(struct wl_priv *wl, struct net_device *ndev, s32 item) rptr = &profile->ssid; break; } - dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags); + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); if (!rptr) WL_ERR(("invalid item (%d)\n", item)); return rptr; @@ -6643,9 +6420,10 @@ wl_update_prof(struct wl_priv *wl, struct net_device *ndev, struct wlc_ssid *ssid; unsigned long flags; struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); + if (!profile) return WL_INVALID; - flags = dhd_os_spin_lock((dhd_pub_t *)(wl->pub)); + spin_lock_irqsave(&wl->cfgdrv_lock, flags); switch (item) { case WL_PROF_SSID: ssid = (wlc_ssid_t *) data; @@ -6677,7 +6455,7 @@ wl_update_prof(struct wl_priv *wl, struct net_device *ndev, err = -EOPNOTSUPP; break; } - dhd_os_spin_unlock((dhd_pub_t *)(wl->pub), flags); + spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); return err; } @@ -6805,114 +6583,22 @@ static void wl_delay(u32 ms) } } -s32 wl_cfg80211_read_fw(s8 *buf, u32 size) -{ - const struct firmware *fw_entry; - struct wl_priv *wl; - - wl = wlcfg_drv_priv; - - fw_entry = wl->fw->fw_entry; - - if (fw_entry->size < wl->fw->ptr + size) - size = fw_entry->size - wl->fw->ptr; - - memcpy(buf, &fw_entry->data[wl->fw->ptr], size); - wl->fw->ptr += size; - return size; -} - -void wl_cfg80211_release_fw(void) -{ - struct wl_priv *wl; - - wl = wlcfg_drv_priv; - release_firmware(wl->fw->fw_entry); - wl->fw->ptr = 0; -} - -void *wl_cfg80211_request_fw(s8 *file_name) -{ - struct wl_priv *wl; - const struct firmware *fw_entry = NULL; - s32 err = 0; - - WL_TRACE(("In\n")); - WL_DBG(("file name : \"%s\"\n", file_name)); - wl = wlcfg_drv_priv; - - if (!test_bit(WL_FW_LOADING_DONE, &wl->fw->status)) { - err = request_firmware(&wl->fw->fw_entry, file_name, - wl_cfg80211_get_parent_dev()); - if (unlikely(err)) { - WL_ERR(("Could not download fw (%d)\n", err)); - goto req_fw_out; - } - set_bit(WL_FW_LOADING_DONE, &wl->fw->status); - fw_entry = wl->fw->fw_entry; - if (fw_entry) { - WL_DBG(("fw size (%zd), data (%p)\n", fw_entry->size, - fw_entry->data)); - } - } else if (!test_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status)) { - err = request_firmware(&wl->fw->fw_entry, file_name, - wl_cfg80211_get_parent_dev()); - if (unlikely(err)) { - WL_ERR(("Could not download nvram (%d)\n", err)); - goto req_fw_out; - } - set_bit(WL_NVRAM_LOADING_DONE, &wl->fw->status); - fw_entry = wl->fw->fw_entry; - if (fw_entry) { - WL_DBG(("nvram size (%zd), data (%p)\n", fw_entry->size, - fw_entry->data)); - } - } else { - WL_DBG(("Downloading already done. Nothing to do more\n")); - err = -EPERM; - } - -req_fw_out: - if (unlikely(err)) { - return NULL; - } - wl->fw->ptr = 0; - return (void *)fw_entry->data; -} - -s8 *wl_cfg80211_get_fwname(void) -{ - struct wl_priv *wl; - - wl = wlcfg_drv_priv; - strcpy(wl->fw->fw_name, WL_4329_FW_FILE); - return wl->fw->fw_name; -} - -s8 *wl_cfg80211_get_nvramname(void) -{ - struct wl_priv *wl; - - wl = wlcfg_drv_priv; - strcpy(wl->fw->nvram_name, WL_4329_NVRAM_FILE); - return wl->fw->nvram_name; -} - s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) { struct wl_priv *wl; - dhd_pub_t *dhd_pub; struct ether_addr p2pif_addr; + struct ether_addr primary_mac; wl = wlcfg_drv_priv; - dhd_pub = (dhd_pub_t *)wl->pub; - wl_cfgp2p_generate_bss_mac(&dhd_pub->mac, p2pdev_addr, &p2pif_addr); + get_primary_mac(wl, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr); return 0; } s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len) { struct wl_priv *wl; + wl = wlcfg_drv_priv; return wl_cfgp2p_set_p2p_noa(wl, net, buf, len); @@ -6970,70 +6656,6 @@ s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len, return ret; } -static __used void wl_dongle_poweron(struct wl_priv *wl) -{ - WL_DBG(("Enter \n")); - dhd_customer_gpio_wlan_ctrl(WLAN_RESET_ON); - -#if defined(BCMLXSDMMC) - sdioh_start(NULL, 0); -#endif -#if defined(BCMLXSDMMC) - sdioh_start(NULL, 1); -#endif - wl_cfg80211_resume(wl_to_wiphy(wl)); -} - -static __used void wl_dongle_poweroff(struct wl_priv *wl) -{ - WL_DBG(("Enter \n")); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39) - wl_cfg80211_suspend(wl_to_wiphy(wl), NULL); -#else - wl_cfg80211_suspend(wl_to_wiphy(wl)); -#endif - -#if defined(BCMLXSDMMC) - sdioh_stop(NULL); -#endif - /* clean up dtim_skip setting */ - dhd_customer_gpio_wlan_ctrl(WLAN_RESET_OFF); -} - -static int wl_debugfs_add_netdev_params(struct wl_priv *wl, struct net_device *ndev) -{ - char buf[10+IFNAMSIZ]; - struct dentry *fd; - struct wl_profile *profile = wl_get_profile_by_netdev(wl, ndev); - s32 err = 0; - - WL_TRACE(("In\n")); - sprintf(buf, "netdev:%s", wl_to_prmry_ndev(wl)->name); - wl->debugfsdir = debugfs_create_dir(buf, wl_to_wiphy(wl)->debugfsdir); - - fd = debugfs_create_u16("beacon_int", S_IRUGO, wl->debugfsdir, - (u16 *)&profile->beacon_interval); - if (!fd) { - err = -ENOMEM; - goto err_out; - } - - fd = debugfs_create_u8("dtim_period", S_IRUGO, wl->debugfsdir, - (u8 *)&profile->dtim_period); - if (!fd) { - err = -ENOMEM; - goto err_out; - } - -err_out: - return err; -} - -static void wl_debugfs_remove_netdev(struct wl_priv *wl) -{ - WL_DBG(("Enter \n")); -} - static const struct rfkill_ops wl_rfkill_ops = { .set_block = wl_rfkill_set }; @@ -7088,486 +6710,42 @@ static int wl_setup_rfkill(struct wl_priv *wl, bool setup) return err; } -#if defined(COEX_DHCP) -/* - * get named driver variable to uint register value and return error indication - * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value) - */ -static int -dev_wlc_intvar_get_reg(struct net_device *dev, char *name, - uint reg, int *retval) -{ - union { - char buf[WLC_IOCTL_SMLEN]; - int val; - } var; - int error; - - bcm_mkiovar(name, (char *)(®), sizeof(reg), - (char *)(&var), sizeof(var.buf)); - error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false); - - *retval = dtoh32(var.val); - return (error); -} - -static int -dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) - char ioctlbuf[1024]; -#else - static char ioctlbuf[1024]; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ - - bcm_mkiovar(name, buf, len, ioctlbuf, sizeof(ioctlbuf)); - - return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf, sizeof(ioctlbuf), true)); -} -/* -get named driver variable to uint register value and return error indication -calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value) -*/ -static int -dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val) -{ - char reg_addr[8]; - - memset(reg_addr, 0, sizeof(reg_addr)); - memcpy((char *)®_addr[0], (char *)addr, 4); - memcpy((char *)®_addr[4], (char *)val, 4); - - return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); -} - -static bool btcoex_is_sco_active(struct net_device *dev) -{ - int ioc_res = 0; - bool res = FALSE; - int sco_id_cnt = 0; - int param27; - int i; - - for (i = 0; i < 12; i++) { - - ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27); - - WL_TRACE(("%s, sample[%d], btc params: 27:%x\n", - __FUNCTION__, i, param27)); - - if (ioc_res < 0) { - WL_ERR(("%s ioc read btc params error\n", __FUNCTION__)); - break; - } - - if ((param27 & 0x6) == 2) { /* count both sco & esco */ - sco_id_cnt++; - } - - if (sco_id_cnt > 2) { - WL_TRACE(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n", - __FUNCTION__, sco_id_cnt, i)); - res = TRUE; - break; - } - - msleep(5); - } - - return res; -} - -#if defined(BT_DHCP_eSCO_FIX) -/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */ -static int set_btc_esco_params(struct net_device *dev, bool trump_sco) +struct device *wl_cfg80211_get_parent_dev(void) { - static bool saved_status = FALSE; - - char buf_reg50va_dhcp_on[8] = - { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 }; - char buf_reg51va_dhcp_on[8] = - { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg64va_dhcp_on[8] = - { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg65va_dhcp_on[8] = - { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg71va_dhcp_on[8] = - { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - uint32 regaddr; - static uint32 saved_reg50; - static uint32 saved_reg51; - static uint32 saved_reg64; - static uint32 saved_reg65; - static uint32 saved_reg71; - - if (trump_sco) { - /* this should reduce eSCO agressive retransmit - * w/o breaking it - */ - - /* 1st save current */ - WL_TRACE(("Do new SCO/eSCO coex algo {save &" - "override}\n")); - if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) { - saved_status = TRUE; - WL_TRACE(("%s saved bt_params[50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - __FUNCTION__, saved_reg50, saved_reg51, - saved_reg64, saved_reg65, saved_reg71)); - } else { - WL_ERR((":%s: save btc_params failed\n", - __FUNCTION__)); - saved_status = FALSE; - return -1; - } - - WL_TRACE(("override with [50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - *(u32 *)(buf_reg50va_dhcp_on+4), - *(u32 *)(buf_reg51va_dhcp_on+4), - *(u32 *)(buf_reg64va_dhcp_on+4), - *(u32 *)(buf_reg65va_dhcp_on+4), - *(u32 *)(buf_reg71va_dhcp_on+4))); - - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg50va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg51va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg64va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg65va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg71va_dhcp_on[0], 8); - - saved_status = TRUE; - } else if (saved_status) { - /* restore previously saved bt params */ - WL_TRACE(("Do new SCO/eSCO coex algo {save &" - "override}\n")); - - regaddr = 50; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg50); - regaddr = 51; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg51); - regaddr = 64; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg64); - regaddr = 65; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg65); - regaddr = 71; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg71); - - WL_TRACE(("restore bt_params[50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - saved_reg50, saved_reg51, saved_reg64, - saved_reg65, saved_reg71)); - - saved_status = FALSE; - } else { - WL_ERR((":%s att to restore not saved BTCOEX params\n", - __FUNCTION__)); - return -1; - } - return 0; + return cfg80211_parent_dev; } -#endif /* BT_DHCP_eSCO_FIX */ -static void -wl_cfg80211_bt_setflag(struct net_device *dev, bool set) +void wl_cfg80211_set_parent_dev(void *dev) { -#if defined(BT_DHCP_USE_FLAGS) - char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; - char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; -#endif - -#if defined(BT_DHCP_eSCO_FIX) - /* set = 1, save & turn on 0 - off & restore prev settings */ - set_btc_esco_params(dev, set); -#endif - -#if defined(BT_DHCP_USE_FLAGS) - WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set)); - if (set == TRUE) - /* Forcing bt_flag7 */ - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_dhcp_on[0], - sizeof(buf_flag7_dhcp_on)); - else - /* Restoring default bt flag7 */ - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_default[0], - sizeof(buf_flag7_default)); -#endif + cfg80211_parent_dev = dev; } -static void wl_cfg80211_bt_timerfunc(ulong data) +static void wl_cfg80211_clear_parent_dev(void) { - struct btcoex_info *bt_local = (struct btcoex_info *)data; - WL_TRACE(("%s\n", __FUNCTION__)); - bt_local->timer_on = 0; - schedule_work(&bt_local->work); + cfg80211_parent_dev = NULL; } -static void wl_cfg80211_bt_handler(struct work_struct *work) +static void get_primary_mac(struct wl_priv *wl, struct ether_addr *mac) { - struct btcoex_info *btcx_inf; - - btcx_inf = container_of(work, struct btcoex_info, work); - - if (btcx_inf->timer_on) { - btcx_inf->timer_on = 0; - del_timer_sync(&btcx_inf->timer); - } - - switch (btcx_inf->bt_state) { - case BT_DHCP_START: - /* DHCP started - * provide OPPORTUNITY window to get DHCP address - */ - WL_TRACE(("%s bt_dhcp stm: started \n", - __FUNCTION__)); - btcx_inf->bt_state = BT_DHCP_OPPR_WIN; - mod_timer(&btcx_inf->timer, - jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000); - btcx_inf->timer_on = 1; - break; - - case BT_DHCP_OPPR_WIN: - if (btcx_inf->dhcp_done) { - WL_TRACE(("%s DHCP Done before T1 expiration\n", - __FUNCTION__)); - goto btc_coex_idle; - } - - /* DHCP is not over yet, start lowering BT priority - * enforce btc_params + flags if necessary - */ - WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__, - BT_DHCP_OPPR_WIN_TIME)); - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); - btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; - mod_timer(&btcx_inf->timer, - jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000); - btcx_inf->timer_on = 1; - break; - - case BT_DHCP_FLAG_FORCE_TIMEOUT: - if (btcx_inf->dhcp_done) { - WL_TRACE(("%s DHCP Done before T2 expiration\n", - __FUNCTION__)); - } else { - /* Noo dhcp during T1+T2, restore BT priority */ - WL_TRACE(("%s DHCP wait interval T2:%d" - "msec expired\n", __FUNCTION__, - BT_DHCP_FLAG_FORCE_TIME)); - } - - /* Restoring default bt priority */ - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); -btc_coex_idle: - btcx_inf->bt_state = BT_DHCP_IDLE; - btcx_inf->timer_on = 0; - break; - - default: - WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__, - btcx_inf->bt_state)); - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); - btcx_inf->bt_state = BT_DHCP_IDLE; - btcx_inf->timer_on = 0; - break; - } - - net_os_wake_unlock(btcx_inf->dev); + wldev_iovar_getbuf_bsscfg(wl_to_prmry_ndev(wl), "cur_etheraddr", NULL, + 0, wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync); + memcpy(mac->octet, wl->ioctl_buf, ETHER_ADDR_LEN); } -static int wl_cfg80211_btcoex_init(struct wl_priv *wl) +int wl_cfg80211_do_driver_init(struct net_device *net) { - struct btcoex_info *btco_inf = NULL; - - btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL); - if (!btco_inf) - return -ENOMEM; + struct wl_priv *wl = *(struct wl_priv **)netdev_priv(net); - btco_inf->bt_state = BT_DHCP_IDLE; - btco_inf->ts_dhcp_start = 0; - btco_inf->ts_dhcp_ok = 0; - /* Set up timer for BT */ - btco_inf->timer_ms = 10; - init_timer(&btco_inf->timer); - btco_inf->timer.data = (ulong)btco_inf; - btco_inf->timer.function = wl_cfg80211_bt_timerfunc; - - btco_inf->dev = wl->wdev->netdev; + if (!wl || !wl->wdev) + return -EINVAL; - INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler); + if (dhd_do_driver_init(wl->wdev->netdev) < 0) + return -1; - wl->btcoex_info = btco_inf; return 0; } -static void -wl_cfg80211_btcoex_deinit(struct wl_priv *wl) -{ - if (!wl->btcoex_info) - return; - - if (!wl->btcoex_info->timer_on) { - wl->btcoex_info->timer_on = 0; - del_timer_sync(&wl->btcoex_info->timer); - } - - cancel_work_sync(&wl->btcoex_info->work); - - kfree(wl->btcoex_info); - wl->btcoex_info = NULL; -} -#endif /* COEX_DHCP */ - -int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) -{ - char powermode_val = 0; - char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; - char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; - char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; - - uint32 regaddr; - static uint32 saved_reg66; - static uint32 saved_reg41; - static uint32 saved_reg68; - static bool saved_status = FALSE; - -#ifdef COEX_DHCP - char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; - struct btcoex_info *btco_inf = wlcfg_drv_priv->btcoex_info; -#endif /* COEX_DHCP */ - - /* Figure out powermode 1 or o command */ - strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1); - - if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { - - WL_TRACE(("%s: DHCP session starts\n", __FUNCTION__)); - - /* Retrieve and saved orig regs value */ - if ((saved_status == FALSE) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { - saved_status = TRUE; - WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", - saved_reg66, saved_reg41, saved_reg68)); - - /* Disable PM mode during dhpc session */ - - /* Disable PM mode during dhpc session */ -#ifdef COEX_DHCP - /* Start BT timer only for SCO connection */ - if (btcoex_is_sco_active(dev)) { - /* btc_params 66 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg66va_dhcp_on[0], - sizeof(buf_reg66va_dhcp_on)); - /* btc_params 41 0x33 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg41va_dhcp_on[0], - sizeof(buf_reg41va_dhcp_on)); - /* btc_params 68 0x190 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg68va_dhcp_on[0], - sizeof(buf_reg68va_dhcp_on)); - saved_status = TRUE; - - btco_inf->bt_state = BT_DHCP_START; - btco_inf->timer_on = 1; - mod_timer(&btco_inf->timer, btco_inf->timer.expires); - WL_TRACE(("%s enable BT DHCP Timer\n", - __FUNCTION__)); - } -#endif /* COEX_DHCP */ - } - else if (saved_status == TRUE) { - WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__)); - } - } - else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { - - - /* Restoring PM mode */ - -#ifdef COEX_DHCP - /* Stop any bt timer because DHCP session is done */ - WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__)); - if (btco_inf->timer_on) { - btco_inf->timer_on = 0; - del_timer_sync(&btco_inf->timer); - - if (btco_inf->bt_state != BT_DHCP_IDLE) { - /* need to restore original btc flags & extra btc params */ - WL_TRACE(("%s bt->bt_state:%d\n", - __FUNCTION__, btco_inf->bt_state)); - /* wake up btcoex thread to restore btlags+params */ - schedule_work(&btco_inf->work); - } - } - - /* Restoring btc_flag paramter anyway */ - if (saved_status == TRUE) - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); -#endif /* COEX_DHCP */ - - /* Restore original values */ - if (saved_status == TRUE) { - regaddr = 66; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg66); - regaddr = 41; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg41); - regaddr = 68; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg68); - - WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", - saved_reg66, saved_reg41, saved_reg68)); - } - saved_status = FALSE; - - } - else { - WL_ERR(("%s Unkwown yet power setting, ignored\n", - __FUNCTION__)); - } - - snprintf(command, 3, "OK"); - - return (strlen("OK")); -} - -struct device *wl_cfg80211_get_parent_dev(void) -{ - return cfg80211_parent_dev; -} - -void wl_cfg80211_set_parent_dev(void *dev) +void wl_cfg80211_enable_trace(int level) { - cfg80211_parent_dev = dev; -} - -static void wl_cfg80211_clear_parent_dev(void) -{ - cfg80211_parent_dev = NULL; + wl_dbg_level |= WL_DBG_DBG; } diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index 18ff27680cb..2b8e66413f2 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -68,6 +68,9 @@ do { \ printk args; \ } \ } while (0) +#ifdef WL_INFO +#undef WL_INFO +#endif #define WL_INFO(args) \ do { \ if (wl_dbg_level & WL_DBG_INFO) { \ @@ -75,6 +78,9 @@ do { \ printk args; \ } \ } while (0) +#ifdef WL_SCAN +#undef WL_SCAN +#endif #define WL_SCAN(args) \ do { \ if (wl_dbg_level & WL_DBG_SCAN) { \ @@ -82,6 +88,9 @@ do { \ printk args; \ } \ } while (0) +#ifdef WL_TRACE +#undef WL_TRACE +#endif #define WL_TRACE(args) \ do { \ if (wl_dbg_level & WL_DBG_TRACE) { \ @@ -102,40 +111,30 @@ do { \ #endif /* (WL_DBG_LEVEL > 0) */ -#define WL_SCAN_RETRY_MAX 3 /* used for ibss scan */ -#define WL_NUM_PMKIDS_MAX MAXPMKID /* will be used - * for 2.6.33 kernel - * or later - */ -#define WL_SCAN_BUF_MAX (1024 * 8) -#define WL_TLV_INFO_MAX 1024 +#define WL_SCAN_RETRY_MAX 3 +#define WL_NUM_PMKIDS_MAX MAXPMKID +#define WL_SCAN_BUF_MAX (1024 * 8) +#define WL_TLV_INFO_MAX 1024 #define WL_SCAN_IE_LEN_MAX 2048 -#define WL_BSS_INFO_MAX 2048 -#define WL_ASSOC_INFO_MAX 512 /* - * needs to grab assoc info from dongle to - * report it to cfg80211 through "connect" - * event - */ +#define WL_BSS_INFO_MAX 2048 +#define WL_ASSOC_INFO_MAX 512 #define WL_IOCTL_LEN_MAX 1024 #define WL_EXTRA_BUF_MAX 2048 -#define WL_ISCAN_BUF_MAX 2048 /* - * the buf lengh can be WLC_IOCTL_MAXLEN (8K) - * to reduce iteration - */ +#define WL_ISCAN_BUF_MAX 2048 #define WL_ISCAN_TIMER_INTERVAL_MS 3000 #define WL_SCAN_ERSULTS_LAST (WL_SCAN_RESULTS_NO_MEM+1) -#define WL_AP_MAX 256 /* virtually unlimitted as long - * as kernel memory allows - */ +#define WL_AP_MAX 256 #define WL_FILE_NAME_MAX 256 -#define WL_DWELL_TIME 200 -#define WL_LONG_DWELL_TIME 1000 -#define IFACE_MAX_CNT 2 +#define WL_DWELL_TIME 200 +#define WL_MED_DWELL_TIME 400 +#define WL_LONG_DWELL_TIME 1000 +#define IFACE_MAX_CNT 2 #define WL_SCAN_TIMER_INTERVAL_MS 8000 /* Scan timeout */ +#define WL_CHANNEL_SYNC_RETRY 5 +#define WL_INVALID -1 -#define WL_INVALID -1 -/* dongle status */ +/* driver status */ enum wl_status { WL_STATUS_READY = 0, WL_STATUS_SCANNING, @@ -144,7 +143,8 @@ enum wl_status { WL_STATUS_CONNECTED, WL_STATUS_DISCONNECTING, WL_STATUS_AP_CREATING, - WL_STATUS_AP_CREATED + WL_STATUS_AP_CREATED, + WL_STATUS_SENDING_ACT_FRM }; /* wi-fi mode */ @@ -154,7 +154,7 @@ enum wl_mode { WL_MODE_AP }; -/* dongle profile list */ +/* driver profile list */ enum wl_prof_list { WL_PROF_MODE, WL_PROF_SSID, @@ -167,7 +167,7 @@ enum wl_prof_list { WL_PROF_DTIMPERIOD }; -/* dongle iscan state */ +/* driver iscan state */ enum wl_iscan_state { WL_ISCAN_STATE_IDLE, WL_ISCAN_STATE_SCANING @@ -197,7 +197,7 @@ struct beacon_proberesp { u8 variable[0]; } __attribute__ ((packed)); -/* dongle configuration */ +/* driver configuration */ struct wl_conf { u32 frag_threshold; u32 rts_threshold; @@ -256,7 +256,7 @@ struct wl_ibss { u8 channel; }; -/* dongle profile */ +/* wl driver profile */ struct wl_profile { u32 mode; s32 band; @@ -272,14 +272,14 @@ struct wl_profile { struct net_info { struct net_device *ndev; struct wireless_dev *wdev; - struct wl_profile profile; /* holding dongle profile */ + struct wl_profile profile; s32 mode; unsigned long sme_state; struct list_head list; /* list of all net_info structure */ }; typedef s32(*ISCAN_HANDLER) (struct wl_priv *wl); -/* dongle iscan controller */ +/* iscan controller */ struct wl_iscan_ctrl { struct net_device *dev; struct timer_list timer; @@ -366,20 +366,34 @@ struct sta_info { u32 probe_req_ie_len; u32 assoc_req_ie_len; }; -/* dongle private data of cfg80211 interface */ + +struct afx_hdl { + wl_af_params_t *pending_tx_act_frm; + struct ether_addr pending_tx_dst_addr; + struct net_device *dev; + struct work_struct work; + u32 bssidx; + u32 retry; + s32 peer_chan; + bool ack_recv; +}; + +/* private data of cfg80211 interface */ struct wl_priv { struct wireless_dev *wdev; /* representing wl cfg80211 device */ struct wireless_dev *p2p_wdev; /* representing wl cfg80211 device for P2P */ struct net_device *p2p_net; /* reference to p2p0 interface */ - struct wl_conf *conf; /* dongle configuration */ + struct wl_conf *conf; struct cfg80211_scan_request *scan_request; /* scan request object */ EVENT_HANDLER evt_handler[WLC_E_LAST]; struct list_head eq_list; /* used for event queue */ struct list_head net_list; /* used for struct net_info */ spinlock_t eq_lock; /* for event queue synchronization */ - struct mutex usr_sync; /* maily for dongle up/down synchronization */ + spinlock_t cfgdrv_lock; /* to protect scan status (and others if needed) */ + struct completion act_frm_scan; + struct mutex usr_sync; /* maily for up/down synchronization */ struct wl_scan_results *bss_list; struct wl_scan_results *scan_results; @@ -392,8 +406,6 @@ struct wl_priv { /* association information container */ struct wl_connect_info conn_info; - /* control firwmare and nvram paramter downloading */ - struct wl_fw_ctrl *fw; struct wl_pmk_list *pmk_list; /* wpa2 pmk list */ tsk_ctl_t event_tsk; /* task of main event handler thread */ void *pub; @@ -407,12 +419,12 @@ struct wl_priv { bool ibss_starter; /* indicates this sta is ibss starter */ bool link_up; /* link/connection up flag */ - /* indicate whether dongle to support power save mode */ + /* indicate whether chip to support power save mode */ bool pwr_save; - bool dongle_up; /* indicate whether dongle up or not */ - bool roam_on; /* on/off switch for dongle self-roaming */ + bool roam_on; /* on/off switch for self-roaming */ bool scan_tried; /* indicates if first scan attempted */ - u8 *ioctl_buf; /* ioctl buffer */ + u8 *ioctl_buf; /* ioctl buffer */ + struct mutex ioctl_buf_sync; u8 *escan_ioctl_buf; u8 *extra_buf; /* maily to grab assoc information */ struct dentry *debugfsdir; @@ -420,8 +432,10 @@ struct wl_priv { bool rf_blocked; struct ieee80211_channel remain_on_chan; enum nl80211_channel_type remain_on_chan_type; + u64 send_action_id; u64 last_roc_id; - wait_queue_head_t dongle_event_wait; + wait_queue_head_t netif_change_event; + struct afx_hdl *afx_hdl; struct ap_info *ap_info; struct sta_info *sta_info; struct p2p_info *p2p; @@ -474,6 +488,7 @@ wl_dealloc_netinfo(struct wl_priv *wl, struct net_device *ndev) } } } + static inline void wl_delete_all_netinfo(struct wl_priv *wl) { @@ -611,28 +626,24 @@ wl_get_profile_by_netdev(struct wl_priv *wl, struct net_device *ndev) (!_sme->crypto.cipher_group)) extern s32 wl_cfg80211_attach(struct net_device *ndev, void *data); extern s32 wl_cfg80211_attach_post(struct net_device *ndev); -extern void wl_cfg80211_detach(void); -/* event handler from dongle */ +extern void wl_cfg80211_detach(void *para); + extern void wl_cfg80211_event(struct net_device *ndev, const wl_event_msg_t *e, void *data); void wl_cfg80211_set_parent_dev(void *dev); struct device *wl_cfg80211_get_parent_dev(void); -extern s32 wl_cfg80211_up(void); /* dongle up */ -extern s32 wl_cfg80211_down(void); /* dongle down */ -extern s32 wl_cfg80211_notify_ifadd(struct net_device *net, s32 idx, s32 bssidx, -int (*_net_attach)(dhd_pub_t *dhdp, int ifidx)); +extern s32 wl_cfg80211_up(void *para); +extern s32 wl_cfg80211_down(void *para); +extern s32 wl_cfg80211_notify_ifadd(struct net_device *ndev, s32 idx, s32 bssidx, + void* _net_attach); +extern s32 wl_cfg80211_ifdel_ops(struct net_device *net); extern s32 wl_cfg80211_notify_ifdel(struct net_device *ndev); extern s32 wl_cfg80211_is_progress_ifadd(void); extern s32 wl_cfg80211_is_progress_ifchange(void); extern s32 wl_cfg80211_is_progress_ifadd(void); extern s32 wl_cfg80211_notify_ifchange(void); extern void wl_cfg80211_dbg_level(u32 level); -extern void *wl_cfg80211_request_fw(s8 *file_name); -extern s32 wl_cfg80211_read_fw(s8 *buf, u32 size); -extern void wl_cfg80211_release_fw(void); -extern s8 *wl_cfg80211_get_fwname(void); -extern s8 *wl_cfg80211_get_nvramname(void); extern s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr); extern s32 wl_cfg80211_set_p2p_noa(struct net_device *net, char* buf, int len); extern s32 wl_cfg80211_get_p2p_noa(struct net_device *net, char* buf, int len); @@ -641,11 +652,11 @@ extern s32 wl_cfg80211_set_wps_p2p_ie(struct net_device *net, char *buf, int len extern s32 wl_cfg80211_set_p2p_ps(struct net_device *net, char* buf, int len); extern int wl_cfg80211_hang(struct net_device *dev, u16 reason); extern s32 wl_mode_to_nl80211_iftype(s32 mode); +int wl_cfg80211_do_driver_init(struct net_device *net); +void wl_cfg80211_enable_trace(int level); /* do scan abort */ -extern s32 -wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev); +extern s32 wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev); -extern s32 -wl_cfg80211_if_is_group_owner(void); +extern s32 wl_cfg80211_if_is_group_owner(void); #endif /* _wl_cfg80211_h_ */ diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index 85c36101ab4..6991a9d7855 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -39,25 +40,19 @@ #include #include #include -#include -#include -#include -#include #include #include #include #include -static s8 ioctlbuf[WLC_IOCTL_MAXLEN]; static s8 scanparambuf[WLC_IOCTL_SMLEN]; -static s8 *smbuf = ioctlbuf; static bool wl_cfgp2p_has_ie(u8 *ie, u8 **tlvs, u32 *tlvs_len, const u8 *oui, u32 oui_len, u8 type); static s32 -wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag, +wl_cfgp2p_vndr_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete); static int wl_cfgp2p_start_xmit(struct sk_buff *skb, struct net_device *ndev); @@ -123,6 +118,8 @@ wl_cfgp2p_init_priv(struct wl_priv *wl) void wl_cfgp2p_deinit_priv(struct wl_priv *wl) { + CFGP2P_DBG(("In\n")); + if (wl->p2p) { kfree(wl->p2p); wl->p2p = NULL; @@ -155,7 +152,7 @@ wl_cfgp2p_set_firm_p2p(struct wl_priv *wl) * firmware for P2P device address */ ret = wldev_iovar_setbuf_bsscfg(ndev, "p2p_da_override", &null_eth_addr, - sizeof(null_eth_addr), ioctlbuf, sizeof(ioctlbuf), 0); + sizeof(null_eth_addr), wl->ioctl_buf, WLC_IOCTL_MAXLEN, 0, &wl->ioctl_buf_sync); if (ret && ret != BCME_UNSUPPORTED) { CFGP2P_ERR(("failed to update device address\n")); } @@ -181,14 +178,14 @@ wl_cfgp2p_ifadd(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, ifreq.chspec = chspec; memcpy(ifreq.addr.octet, mac->octet, sizeof(ifreq.addr.octet)); - CFGP2P_INFO(("---wl p2p_ifadd %02x:%02x:%02x:%02x:%02x:%02x %s %u\n", + CFGP2P_DBG(("---wl p2p_ifadd %02x:%02x:%02x:%02x:%02x:%02x %s %u\n", ifreq.addr.octet[0], ifreq.addr.octet[1], ifreq.addr.octet[2], ifreq.addr.octet[3], ifreq.addr.octet[4], ifreq.addr.octet[5], (if_type == WL_P2P_IF_GO) ? "go" : "client", (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT)); err = wldev_iovar_setbuf(ndev, "p2p_ifadd", &ifreq, sizeof(ifreq), - ioctlbuf, sizeof(ioctlbuf)); + wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); return err; } @@ -207,7 +204,7 @@ wl_cfgp2p_ifdel(struct wl_priv *wl, struct ether_addr *mac) netdev->ifindex, mac->octet[0], mac->octet[1], mac->octet[2], mac->octet[3], mac->octet[4], mac->octet[5])); ret = wldev_iovar_setbuf(netdev, "p2p_ifdel", mac, sizeof(*mac), - ioctlbuf, sizeof(ioctlbuf)); + wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); if (unlikely(ret < 0)) { printk("'wl p2p_ifdel' error %d\n", ret); } @@ -238,7 +235,7 @@ wl_cfgp2p_ifchange(struct wl_priv *wl, struct ether_addr *mac, u8 if_type, (chspec & WL_CHANSPEC_CHAN_MASK) >> WL_CHANSPEC_CHAN_SHIFT)); err = wldev_iovar_setbuf(netdev, "p2p_ifupd", &ifreq, sizeof(ifreq), - ioctlbuf, sizeof(ioctlbuf)); + wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); if (unlikely(err < 0)) { printk("'wl p2p_ifupd' error %d\n", err); @@ -264,8 +261,8 @@ wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index) mac->octet[0], mac->octet[1], mac->octet[2], mac->octet[3], mac->octet[4], mac->octet[5])); - ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), - getbuf, sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY)); + ret = wldev_iovar_getbuf_bsscfg(dev, "p2p_if", mac, sizeof(*mac), getbuf, + sizeof(getbuf), wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_PRIMARY), NULL); if (ret == 0) { memcpy(index, getbuf, sizeof(index)); @@ -275,7 +272,7 @@ wl_cfgp2p_ifidx(struct wl_priv *wl, struct ether_addr *mac, s32 *index) return ret; } -s32 +static s32 wl_cfgp2p_set_discovery(struct wl_priv *wl, s32 on) { s32 ret = BCME_OK; @@ -324,13 +321,14 @@ wl_cfgp2p_set_p2p_mode(struct wl_priv *wl, u8 mode, u32 channel, u16 listen_ms, discovery_mode.chspec = CH20MHZ_CHSPEC(channel); discovery_mode.dwell = listen_ms; ret = wldev_iovar_setbuf_bsscfg(dev, "p2p_state", &discovery_mode, - sizeof(discovery_mode), ioctlbuf, sizeof(ioctlbuf), bssidx); + sizeof(discovery_mode), wl->ioctl_buf, WLC_IOCTL_MAXLEN, + bssidx, &wl->ioctl_buf_sync); return ret; } /* Get the index of the P2P Discovery BSS */ -s32 +static s32 wl_cfgp2p_get_disc_idx(struct wl_priv *wl, s32 *index) { s32 ret; @@ -394,7 +392,7 @@ wl_cfgp2p_init_discovery(struct wl_priv *wl) * @wl : wl_private data * Returns 0 if succes */ -s32 +static s32 wl_cfgp2p_deinit_discovery(struct wl_priv *wl) { s32 ret = BCME_OK; @@ -432,7 +430,8 @@ wl_cfgp2p_deinit_discovery(struct wl_priv *wl) * Returns 0 if success. */ s32 -wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, const u8 *ie, u32 ie_len) +wl_cfgp2p_enable_discovery(struct wl_priv *wl, struct net_device *dev, + const u8 *ie, u32 ie_len) { s32 ret = BCME_OK; if (wl_get_p2p_status(wl, DISCOVERY_ON)) { @@ -524,9 +523,9 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, wl_escan_params_t *eparams; wlc_ssid_t ssid; /* Scan parameters */ -#define P2PAPI_SCAN_NPROBES 4 -#define P2PAPI_SCAN_DWELL_TIME_MS 80 -#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 100 +#define P2PAPI_SCAN_NPROBES 1 +#define P2PAPI_SCAN_DWELL_TIME_MS 50 +#define P2PAPI_SCAN_SOCIAL_DWELL_TIME_MS 40 #define P2PAPI_SCAN_HOME_TIME_MS 10 struct net_device *pri_dev = wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_PRIMARY); wl_set_p2p_status(wl, SCANNING); @@ -543,7 +542,7 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, return -1; } memset(memblk, 0, memsize); - memset(ioctlbuf, 0, sizeof(ioctlbuf)); + memset(wl->ioctl_buf, 0, WLC_IOCTL_MAXLEN); if (search_state == WL_P2P_DISC_ST_SEARCH) { /* * If we in SEARCH STATE, we don't need to set SSID explictly @@ -608,9 +607,54 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, CFGP2P_INFO(("\n")); ret = wldev_iovar_setbuf_bsscfg(pri_dev, "p2p_scan", - memblk, memsize, smbuf, sizeof(ioctlbuf), bssidx); + memblk, memsize, wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); + return ret; +} + +/* search function to reach at common channel to send action frame + * Parameters: + * @wl : wl_private data + * @ndev : net device for bssidx + * @bssidx : bssidx for BSS + * Returns 0 if success. + */ +s32 +wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, + s32 bssidx, s32 channel) +{ + s32 ret = 0; + u32 chan_cnt = 0; + u16 *default_chan_list = NULL; + if (!p2p_is_on(wl)) + return -BCME_ERROR; + CFGP2P_ERR((" Enter\n")); + if (bssidx == P2PAPI_BSSCFG_PRIMARY) + bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); + if (channel) + chan_cnt = 1; + else + chan_cnt = SOCIAL_CHAN_CNT; + default_chan_list = kzalloc(chan_cnt * sizeof(*default_chan_list), GFP_KERNEL); + if (default_chan_list == NULL) { + CFGP2P_ERR(("channel list allocation failed \n")); + ret = -ENOMEM; + goto exit; + } + if (channel) { + default_chan_list[0] = channel; + } else { + default_chan_list[0] = SOCIAL_CHAN_1; + default_chan_list[1] = SOCIAL_CHAN_2; + default_chan_list[2] = SOCIAL_CHAN_3; + } + ret = wl_cfgp2p_escan(wl, ndev, true, SOCIAL_CHAN_CNT, + default_chan_list, WL_P2P_DISC_ST_SEARCH, + WL_SCAN_ACTION_START, bssidx); + kfree(default_chan_list); +exit: return ret; } + /* Check whether pointed-to IE looks like WPA. */ #define wl_cfgp2p_is_wpa_ie(ie, tlvs, len) wl_cfgp2p_has_ie(ie, tlvs, len, \ (const uint8 *)WPS_OUI, WPS_OUI_LEN, WPA_OUI_TYPE) @@ -648,7 +692,7 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss u8 delete = 0; #define IE_TYPE(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie) #define IE_TYPE_LEN(type, bsstype) (wl_to_p2p_bss_saved_ie(wl, bsstype).p2p_ ## type ## _ie_len) - if (wl->p2p_supported && p2p_on(wl) && bssidx != -1) { + if (p2p_is_on(wl) && bssidx != -1) { if (bssidx == P2PAPI_BSSCFG_PRIMARY) bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); switch (pktflag) { @@ -748,8 +792,9 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss CFGP2P_INFO(("DELELED ID : %d, Len : %d , OUI :" "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos], ie_buf[pos+1], ie_buf[pos+2])); - ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos, - VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete); + ret = wl_cfgp2p_vndr_ie(wl, ndev, bssidx, pktflag, + ie_buf+pos, VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, + ie_len-3, delete); } pos += ie_len; } @@ -773,8 +818,9 @@ wl_cfgp2p_set_management_ie(struct wl_priv *wl, struct net_device *ndev, s32 bss CFGP2P_INFO(("ADDED ID : %d, Len : %d , OUI :" "%02x:%02x:%02x\n", ie_id, ie_len, ie_buf[pos], ie_buf[pos+1], ie_buf[pos+2])); - ret = wl_cfgp2p_vndr_ie(ndev, bssidx, pktflag, ie_buf+pos, - VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, ie_len-3, delete); + ret = wl_cfgp2p_vndr_ie(wl, ndev, bssidx, pktflag, + ie_buf+pos, VNDR_SPEC_ELEMENT_ID, ie_buf+pos+3, + ie_len-3, delete); } pos += ie_len; } @@ -880,7 +926,7 @@ wl_cfgp2p_find_p2pie(u8 *parse, u32 len) } static s32 -wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag, +wl_cfgp2p_vndr_ie(struct wl_priv *wl, struct net_device *ndev, s32 bssidx, s32 pktflag, s8 *oui, s32 ie_id, s8 *data, s32 data_len, s32 delete) { s32 err = BCME_OK; @@ -922,7 +968,7 @@ wl_cfgp2p_vndr_ie(struct net_device *ndev, s32 bssidx, s32 pktflag, memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.oui, oui, 3); memcpy(ie_setbuf->vndr_ie_buffer.vndr_ie_list[0].vndr_ie_data.data, data, data_len); err = wldev_iovar_setbuf_bsscfg(ndev, "vndr_ie", ie_setbuf, buf_len, - ioctlbuf, sizeof(ioctlbuf), bssidx); + wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); CFGP2P_INFO(("vndr_ie iovar returns %d\n", err)); kfree(ie_setbuf); @@ -1106,10 +1152,10 @@ wl_cfgp2p_action_tx_complete(struct wl_priv *wl, struct net_device *ndev, wl_set_p2p_status(wl, ACTION_TX_NOACK); CFGP2P_ERR(("WLC_E_ACTION_FRAME_COMPLETE : NO ACK\n")); } - wake_up_interruptible(&wl->dongle_event_wait); } else { CFGP2P_INFO((" WLC_E_ACTION_FRAME_OFFCHAN_COMPLETE is received," "status : %d\n", status)); + wake_up_interruptible(&wl->netif_change_event); } return ret; } @@ -1139,15 +1185,15 @@ wl_cfgp2p_tx_action_frame(struct wl_priv *wl, struct net_device *dev, if (bssidx == P2PAPI_BSSCFG_PRIMARY) bssidx = wl_to_p2p_bss_bssidx(wl, P2PAPI_BSSCFG_DEVICE); - ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", - af_params, sizeof(*af_params), ioctlbuf, sizeof(ioctlbuf), bssidx); + ret = wldev_iovar_setbuf_bsscfg(dev, "actframe", af_params, sizeof(*af_params), + wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); if (ret < 0) { CFGP2P_ERR((" sending action frame is failed\n")); goto exit; } - timeout = wait_event_interruptible_timeout(wl->dongle_event_wait, + timeout = wait_event_interruptible_timeout(wl->netif_change_event, (wl_get_p2p_status(wl, ACTION_TX_COMPLETED) || wl_get_p2p_status(wl, ACTION_TX_NOACK)), msecs_to_jiffies(MAX_WAIT_TIME)); @@ -1256,7 +1302,7 @@ wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx) /* Check if the BSS is up */ *(int*)getbuf = -1; result = wldev_iovar_getbuf_bsscfg(ndev, "bss", &bsscfg_idx, - sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0); + sizeof(bsscfg_idx), getbuf, sizeof(getbuf), 0, NULL); if (result != 0) { CFGP2P_ERR(("'wl bss -C %d' failed: %d\n", bsscfg_idx, result)); CFGP2P_ERR(("NOTE: this ioctl error is normal " @@ -1273,7 +1319,7 @@ wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx) /* Bring up or down a BSS */ s32 -wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up) +wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up) { s32 ret = BCME_OK; s32 val = up ? 1 : 0; @@ -1287,7 +1333,7 @@ wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up) bss_setbuf.val = htod32(val); CFGP2P_INFO(("---wl bss -C %d %s\n", bsscfg_idx, up ? "up" : "down")); ret = wldev_iovar_setbuf(ndev, "bss", &bss_setbuf, sizeof(bss_setbuf), - ioctlbuf, sizeof(ioctlbuf)); + wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); if (ret != 0) { CFGP2P_ERR(("'bss %d' failed with %d\n", up, ret)); @@ -1343,7 +1389,7 @@ s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf sscanf(buf, "%d %d %d", &count, &start, &duration); CFGP2P_DBG(("set_p2p_noa count %d start %d duration %d\n", - count, start, duration)); + count, start, duration)); if (count != -1) wl->p2p->noa.desc[0].count = count; @@ -1387,7 +1433,8 @@ s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf dongle_noa.desc[0].interval = htod32(wl->p2p->noa.desc[0].interval*1000); ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), - "p2p_noa", &dongle_noa, sizeof(dongle_noa), ioctlbuf, sizeof(ioctlbuf)); + "p2p_noa", &dongle_noa, sizeof(dongle_noa), wl->ioctl_buf, WLC_IOCTL_MAXLEN, + &wl->ioctl_buf_sync); if (ret < 0) { CFGP2P_ERR(("fw set p2p_noa failed %d\n", ret)); @@ -1459,7 +1506,7 @@ s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, wl->p2p->ops.ops = ps; ret = wldev_iovar_setbuf(wl_to_p2p_bss_ndev(wl, P2PAPI_BSSCFG_CONNECTION), "p2p_ops", &wl->p2p->ops, sizeof(wl->p2p->ops), - ioctlbuf, sizeof(ioctlbuf)); + wl->ioctl_buf, WLC_IOCTL_MAXLEN, &wl->ioctl_buf_sync); if (ret < 0) { CFGP2P_ERR(("fw set p2p_ops failed %d\n", ret)); } @@ -1481,6 +1528,96 @@ s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, return ret; } +u8 * +wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id) +{ + wifi_p2p_ie_t *ie = NULL; + u16 len = 0; + u8 *subel; + u8 subelt_id; + u16 subelt_len; + + if (!buf) { + WL_ERR(("P2P IE not present")); + return 0; + } + + ie = (wifi_p2p_ie_t*) buf; + len = ie->len; + + /* Point subel to the P2P IE's subelt field. + * Subtract the preceding fields (id, len, OUI, oui_type) from the length. + */ + subel = ie->subelts; + len -= 4; /* exclude OUI + OUI_TYPE */ + + while (len >= 3) { + /* attribute id */ + subelt_id = *subel; + subel += 1; + len -= 1; + + /* 2-byte little endian */ + subelt_len = *subel++; + subelt_len |= *subel++ << 8; + + len -= 2; + len -= subelt_len; /* for the remaining subelt fields */ + + if (subelt_id == element_id) { + /* This will point to start of subelement attrib after + * attribute id & len + */ + return subel; + } + + /* Go to next subelement */ + subel += subelt_len; + } + + /* Not Found */ + return NULL; +} + +#define P2P_GROUP_CAPAB_GO_BIT 0x01 +u8 * +wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length) +{ + wifi_p2p_ie_t * p2p_ie = NULL; + u8 *capability = NULL; + bool p2p_go = 0; + u8 *ptr = NULL; + + if (!(p2p_ie = wl_cfgp2p_find_p2pie(((u8 *) bi) + bi->ie_offset, bi->ie_length))) { + WL_ERR(("P2P IE not found")); + return NULL; + } + + if (!(capability = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_P2P_INFO))) { + WL_ERR(("P2P Capability attribute not found")); + return NULL; + } + + /* Check Group capability for Group Owner bit */ + p2p_go = capability[1] & P2P_GROUP_CAPAB_GO_BIT; + if (!p2p_go) { + return bi->BSSID.octet; + } + + /* In probe responses, DEVICE INFO attribute will be present */ + if (!(ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_INFO))) { + /* If DEVICE_INFO is not found, this might be a beacon frame. + * check for DEVICE_ID in the beacon frame. + */ + ptr = wl_cfgp2p_retreive_p2pattrib(p2p_ie, P2P_SEID_DEV_ID); + } + + if (!ptr) + WL_ERR((" Both DEVICE_ID & DEVICE_INFO attribute not present in P2P IE ")); + + return ptr; +} + s32 wl_cfgp2p_register_ndev(struct wl_priv *wl) { @@ -1613,12 +1750,34 @@ static int wl_cfgp2p_do_ioctl(struct net_device *net, struct ifreq *ifr, int cmd static int wl_cfgp2p_if_open(struct net_device *net) { - CFGP2P_DBG(("Do Nothing \n")); + struct wireless_dev *wdev = net->ieee80211_ptr; + + if (!wdev) + return -EINVAL; + + /* If suppose F/W download (ifconfig wlan0 up) hasn't been done by now, + * do it here. This will make sure that in concurrent mode, supplicant + * is not dependent on a particular order of interface initialization. + * i.e you may give wpa_supp -iwlan0 -N -ip2p0 or wpa_supp -ip2p0 -N + * -iwlan0. + */ + wl_cfg80211_do_driver_init(net); + + wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT) + | BIT(NL80211_IFTYPE_P2P_GO)); + return 0; } static int wl_cfgp2p_if_stop(struct net_device *net) { - CFGP2P_DBG(("Do Nothing \n")); + struct wireless_dev *wdev = net->ieee80211_ptr; + + if (!wdev) + return -EINVAL; + + wdev->wiphy->interface_modes = (wdev->wiphy->interface_modes) + & (~(BIT(NL80211_IFTYPE_P2P_CLIENT)| + BIT(NL80211_IFTYPE_P2P_GO))); return 0; } diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h index 6934d8f1c9b..d50b00f8394 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h @@ -107,7 +107,7 @@ enum wl_cfgp2p_status { &(wl)->p2p->status)) #define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : clear_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) -#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : change_bit(WLP2P_STATUS_ ## stat, \ +#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0: change_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) #define p2p_on(wl) ((wl)->p2p->on) #define p2p_scan(wl) ((wl)->p2p->scan) @@ -172,6 +172,10 @@ wl_cfgp2p_escan(struct wl_priv *wl, struct net_device *dev, u16 active, u32 num_ u16 *channels, s32 search_state, u16 action, u32 bssidx); +extern s32 +wl_cfgp2p_act_frm_search(struct wl_priv *wl, struct net_device *ndev, + s32 bssidx, s32 channel); + extern wpa_ie_fixed_t * wl_cfgp2p_find_wpaie(u8 *parse, u32 len); @@ -217,7 +221,7 @@ extern bool wl_cfgp2p_bss_isup(struct net_device *ndev, int bsscfg_idx); extern s32 -wl_cfgp2p_bss(struct net_device *ndev, s32 bsscfg_idx, s32 up); +wl_cfgp2p_bss(struct wl_priv *wl, struct net_device *ndev, s32 bsscfg_idx, s32 up); extern s32 @@ -235,6 +239,12 @@ wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, in extern s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len); +extern u8 * +wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id); + +extern u8 * +wl_cfgp2p_retreive_p2p_dev_addr(wl_bss_info_t *bi, u32 bi_length); + extern s32 wl_cfgp2p_register_ndev(struct wl_priv *wl); @@ -245,9 +255,22 @@ wl_cfgp2p_unregister_ndev(struct wl_priv *wl); #define SOCIAL_CHAN_1 1 #define SOCIAL_CHAN_2 6 #define SOCIAL_CHAN_3 11 +#define SOCIAL_CHAN_CNT 3 #define WL_P2P_WILDCARD_SSID "DIRECT-" #define WL_P2P_WILDCARD_SSID_LEN 7 #define WL_P2P_INTERFACE_PREFIX "p2p" #define WL_P2P_TEMP_CHAN "11" +#define IS_PUB_ACT_FRAME(category) ((category == P2P_PUB_AF_CATEGORY)) +#define IS_P2P_ACT_FRAME(category) ((category == P2P_AF_CATEGORY)) + +#define IS_P2P_ACTION(categry, action) (IS_PUB_ACT_FRAME(category) && (action == P2P_PUB_AF_ACTION)) +#define IS_GAS_REQ(category, action) (IS_PUB_ACT_FRAME(category) && \ + ((action == P2PSD_ACTION_ID_GAS_IREQ) || \ + (action == P2PSD_ACTION_ID_GAS_CREQ))) +#define IS_P2P_ACT_REQ(category, subtype) (IS_PUB_ACT_FRAME(category) && \ + ((subtype == P2P_PAF_GON_REQ) || \ + (subtype == P2P_PAF_INVITE_REQ) || \ + (subtype == P2P_PAF_PROVDIS_REQ))) +#define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3)) #define IS_P2P_SSID(ssid) (memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) == 0) #endif /* _wl_cfgp2p_h_ */ diff --git a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c b/drivers/net/wireless/bcmdhd/wl_linux_mon.c similarity index 99% rename from drivers/net/wireless/bcmdhd/dhd_linux_mon.c rename to drivers/net/wireless/bcmdhd/wl_linux_mon.c index d4dca260721..f44b4b04bb9 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux_mon.c +++ b/drivers/net/wireless/bcmdhd/wl_linux_mon.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux_mon.c 297563 2011-11-20 15:38:29Z $ + * $Id: wl_linux_mon.c 303266 2011-12-16 00:15:23Z $ */ #include diff --git a/drivers/net/wireless/bcmdhd/wldev_common.c b/drivers/net/wireless/bcmdhd/wldev_common.c index bb3eaea90d0..d9a0b93d689 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.c +++ b/drivers/net/wireless/bcmdhd/wldev_common.c @@ -24,12 +24,13 @@ * $Id: wldev_common.c,v 1.1.4.1.2.14 2011-02-09 01:40:07 $ */ -#include +#include +#include +#include #include #include #include -#include #define htod32(i) i #define htod16(i) i @@ -37,6 +38,13 @@ #define dtoh16(i) i #define htodchanspec(i) i #define dtohchanspec(i) i + +#define WLDEV_ERROR(args) \ + do { \ + printk(KERN_ERR "WLDEV-ERROR) %s : ", __func__); \ + printk args; \ + } while (0) + extern int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd); s32 wldev_ioctl( @@ -71,26 +79,34 @@ static s32 wldev_mkiovar( s32 wldev_iovar_getbuf( struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen) + void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) { s32 ret = 0; s32 iovar_len = 0; - + if (buf_sync) { + mutex_lock(buf_sync); + } iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); + if (buf_sync) + mutex_unlock(buf_sync); return ret; } s32 wldev_iovar_setbuf( struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen) + void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync) { s32 ret = 0; s32 iovar_len; - + if (buf_sync) { + mutex_lock(buf_sync); + } iovar_len = wldev_mkiovar(iovar_name, param, paramlen, buf, buflen); ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); + if (buf_sync) + mutex_unlock(buf_sync); return ret; } @@ -102,7 +118,7 @@ s32 wldev_iovar_setint( val = htod32(val); memset(iovar_buf, 0, sizeof(iovar_buf)); return wldev_iovar_setbuf(dev, iovar, &val, sizeof(val), iovar_buf, - sizeof(iovar_buf)); + sizeof(iovar_buf), NULL); } @@ -114,7 +130,7 @@ s32 wldev_iovar_getint( memset(iovar_buf, 0, sizeof(iovar_buf)); err = wldev_iovar_getbuf(dev, iovar, pval, sizeof(*pval), iovar_buf, - sizeof(iovar_buf)); + sizeof(iovar_buf), NULL); if (err == 0) { memcpy(pval, iovar_buf, sizeof(*pval)); @@ -148,7 +164,7 @@ s32 wldev_mkiovar_bsscfg( if (buflen < 0 || iolen > (u32)buflen) { - DHD_ERROR(("%s: buffer is too short\n", __FUNCTION__)); + WLDEV_ERROR(("%s: buffer is too short\n", __FUNCTION__)); return BCME_BUFTOOSHORT; } @@ -177,26 +193,37 @@ s32 wldev_mkiovar_bsscfg( s32 wldev_iovar_getbuf_bsscfg( struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx) + void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) { s32 ret = 0; s32 iovar_len = 0; - + if (buf_sync) { + mutex_lock(buf_sync); + } iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); ret = wldev_ioctl(dev, WLC_GET_VAR, buf, buflen, FALSE); + if (buf_sync) { + mutex_unlock(buf_sync); + } return ret; } s32 wldev_iovar_setbuf_bsscfg( struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx) + void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync) { s32 ret = 0; s32 iovar_len; - + if (buf_sync) { + mutex_lock(buf_sync); + } iovar_len = wldev_mkiovar_bsscfg(iovar_name, param, paramlen, buf, buflen, bsscfg_idx); + ret = wldev_ioctl(dev, WLC_SET_VAR, buf, iovar_len, TRUE); + if (buf_sync) { + mutex_unlock(buf_sync); + } return ret; } @@ -208,7 +235,7 @@ s32 wldev_iovar_setint_bsscfg( val = htod32(val); memset(iovar_buf, 0, sizeof(iovar_buf)); return wldev_iovar_setbuf_bsscfg(dev, iovar, &val, sizeof(val), iovar_buf, - sizeof(iovar_buf), bssidx); + sizeof(iovar_buf), bssidx, NULL); } @@ -220,7 +247,7 @@ s32 wldev_iovar_getint_bsscfg( memset(iovar_buf, 0, sizeof(iovar_buf)); err = wldev_iovar_getbuf_bsscfg(dev, iovar, pval, sizeof(*pval), iovar_buf, - sizeof(iovar_buf), bssidx); + sizeof(iovar_buf), bssidx, NULL); if (err == 0) { memcpy(pval, iovar_buf, sizeof(*pval)); @@ -309,16 +336,16 @@ int wldev_set_country( return error; error = wldev_iovar_getbuf(dev, "country", &cspec, sizeof(cspec), - smbuf, sizeof(smbuf)); + smbuf, sizeof(smbuf), NULL); if (error < 0) - DHD_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error)); + WLDEV_ERROR(("%s: get country failed = %d\n", __FUNCTION__, error)); if ((error < 0) || (strncmp(country_code, smbuf, WLC_CNTRY_BUF_SZ) != 0)) { bzero(&scbval, sizeof(scb_val_t)); error = wldev_ioctl(dev, WLC_DISASSOC, &scbval, sizeof(scb_val_t), 1); if (error < 0) { - DHD_ERROR(("%s: set country failed due to Disassoc error %d\n", + WLDEV_ERROR(("%s: set country failed due to Disassoc error %d\n", __FUNCTION__, error)); return error; } @@ -328,14 +355,14 @@ int wldev_set_country( memcpy(cspec.ccode, country_code, WLC_CNTRY_BUF_SZ); get_customized_country_code((char *)&cspec.country_abbrev, &cspec); error = wldev_iovar_setbuf(dev, "country", &cspec, sizeof(cspec), - smbuf, sizeof(smbuf)); + smbuf, sizeof(smbuf), NULL); if (error < 0) { - DHD_ERROR(("%s: set country for %s as %s rev %d failed\n", + WLDEV_ERROR(("%s: set country for %s as %s rev %d failed\n", __FUNCTION__, country_code, cspec.ccode, cspec.rev)); return error; } dhd_bus_country_set(dev, &cspec); - DHD_INFO(("%s: set country for %s as %s rev %d\n", + WLDEV_ERROR(("%s: set country for %s as %s rev %d\n", __FUNCTION__, country_code, cspec.ccode, cspec.rev)); return 0; } diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h index 46326803e21..6a1ba153360 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.h +++ b/drivers/net/wireless/bcmdhd/wldev_common.h @@ -21,33 +21,33 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wldev_common.h,v 1.1.4.1.2.14 2011-02-09 01:40:07 Exp $ + * $Id: wldev_common.h,v 1.1.4.1.2.14 2011-02-09 01:40:07 $ */ #ifndef __WLDEV_COMMON_H__ #define __WLDEV_COMMON_H__ #include -/** wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or +/* wl_dev_ioctl - get/set IOCTLs, will call net_device's do_ioctl (or * netdev_ops->ndo_do_ioctl in new kernels) * @dev: the net_device handle */ s32 wldev_ioctl( struct net_device *dev, u32 cmd, void *arg, u32 len, u32 set); -/** Retrieve named IOVARs, this function calls wl_dev_ioctl with +/** Retrieve named IOVARs, this function calls wl_dev_ioctl with * WLC_GET_VAR IOCTL code */ s32 wldev_iovar_getbuf( struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen); + void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); /** Set named IOVARs, this function calls wl_dev_ioctl with * WLC_SET_VAR IOCTL code */ s32 wldev_iovar_setbuf( struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen); + void *param, s32 paramlen, void *buf, s32 buflen, struct mutex* buf_sync); s32 wldev_iovar_setint( struct net_device *dev, s8 *iovar, s32 val); @@ -67,15 +67,15 @@ s32 wldev_mkiovar_bsscfg( * WLC_GET_VAR IOCTL code */ s32 wldev_iovar_getbuf_bsscfg( - struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx); + struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, + void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); /** Set named and bsscfg indexed IOVARs, this function calls wl_dev_ioctl with * WLC_SET_VAR IOCTL code */ s32 wldev_iovar_setbuf_bsscfg( - struct net_device *dev, s8 *iovar_name, - void *param, s32 paramlen, void *buf, s32 buflen, s32 bsscfg_idx); + struct net_device *dev, s8 *iovar_name, void *param, s32 paramlen, + void *buf, s32 buflen, s32 bsscfg_idx, struct mutex* buf_sync); s32 wldev_iovar_getint_bsscfg( struct net_device *dev, s8 *iovar, s32 *pval, s32 bssidx); @@ -94,7 +94,7 @@ extern int net_os_set_dtim_skip(struct net_device *dev, int val); extern int net_os_set_suspend_disable(struct net_device *dev, int val); extern int net_os_set_suspend(struct net_device *dev, int val); extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, - int max, int *bytes_left); + int max, int *bytes_left); /* Get the link speed from dongle, speed is in kpbs */ int wldev_get_link_speed(struct net_device *dev, int *plink_speed); From 96034c20069fe841f4be741755f94671a328702e Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 24 Jan 2012 13:55:00 -0800 Subject: [PATCH 0753/4025] net: wireless: bcmdhd: Update to Version 5.90.195.22 - Disable Ad-hoc support for cfg80211 - dhd_linux.c: Fix incorrect pid check - Merge Android changes from Android tree Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/bcmsdh_linux.c | 24 +++--------------- .../net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c | 25 +++++++++++++------ drivers/net/wireless/bcmdhd/dhd_linux.c | 10 ++++---- drivers/net/wireless/bcmdhd/dhd_sdio.c | 11 +++++--- drivers/net/wireless/bcmdhd/hndpmu.c | 16 ++++++++++++ drivers/net/wireless/bcmdhd/include/bcmdevs.h | 2 ++ drivers/net/wireless/bcmdhd/include/epivers.h | 8 +++--- drivers/net/wireless/bcmdhd/siutils.c | 3 +++ drivers/net/wireless/bcmdhd/wl_cfg80211.c | 11 ++++++-- 9 files changed, 68 insertions(+), 42 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c index 5abfecc2cf1..e01b6f8a2d4 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_linux.c 294990 2011-11-09 00:13:10Z $ + * $Id: bcmsdh_linux.c 308641 2012-01-17 02:18:02Z $ */ /** @@ -146,17 +146,6 @@ static int __devinit bcmsdh_probe(struct device *dev); static int __devexit bcmsdh_remove(struct device *dev); #endif /* BCMLXSDMMC */ -#ifndef BCMLXSDMMC -static struct device_driver bcmsdh_driver = { - .name = "pxa2xx-mci", - .bus = &platform_bus_type, - .probe = bcmsdh_probe, - .remove = bcmsdh_remove, - .suspend = NULL, - .resume = NULL, - }; -#endif /* BCMLXSDMMC */ - #ifndef BCMLXSDMMC static #endif /* BCMLXSDMMC */ @@ -531,13 +520,8 @@ bcmsdh_register(bcmsdh_driver_t *driver) drvinfo = *driver; #if defined(BCMPLATFORM_BUS) -#if defined(BCMLXSDMMC) SDLX_MSG(("Linux Kernel SDIO/MMC Driver\n")); error = sdio_function_init(); -#else - SDLX_MSG(("Intel PXA270 SDIO Driver\n")); - error = driver_register(&bcmsdh_driver); -#endif /* defined(BCMLXSDMMC) */ return error; #endif /* defined(BCMPLATFORM_BUS) */ @@ -565,14 +549,12 @@ bcmsdh_unregister(void) if (bcmsdh_pci_driver.node.next) #endif -#if defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC) - driver_unregister(&bcmsdh_driver); -#endif #if defined(BCMLXSDMMC) sdio_function_cleanup(); #endif /* BCMLXSDMMC */ + #if !defined(BCMPLATFORM_BUS) && !defined(BCMLXSDMMC) - pci_unregister_driver(&bcmsdh_pci_driver); + pci_unregister_driver(&bcmsdh_pci_driver); #endif /* BCMPLATFORM_BUS */ } diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c index e19c2fd5028..83f4d3df671 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_sdmmc_linux.c 300908 2011-12-06 10:32:01Z $ + * $Id: bcmsdh_sdmmc_linux.c 308645 2012-01-17 02:33:26Z $ */ #include @@ -58,6 +58,12 @@ #if !defined(SDIO_DEVICE_ID_BROADCOM_4330) #define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 #endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4330) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_4334) +#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_4334) */ +#if !defined(SDIO_DEVICE_ID_BROADCOM_43239) +#define SDIO_DEVICE_ID_BROADCOM_43239 43239 +#endif /* !defined(SDIO_DEVICE_ID_BROADCOM_43239) */ #include @@ -157,9 +163,9 @@ static const struct sdio_device_id bcmsdh_sdmmc_ids[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4319) }, { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330) }, -#ifndef BOARD_PANDA + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334) }, + { SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43239) }, { SDIO_DEVICE_CLASS(SDIO_CLASS_NONE) }, -#endif { /* end: all zeroes */ }, }; @@ -172,11 +178,14 @@ static int bcmsdh_sdmmc_suspend(struct device *pdev) if (func->num != 2) return 0; + + sd_trace(("%s Enter\n", __FUNCTION__)); + if (dhd_os_check_wakelock(bcmsdh_get_drvdata())) return -EBUSY; #if defined(OOB_INTR_ONLY) bcmsdh_oob_intr_set(0); -#endif +#endif /* defined(OOB_INTR_ONLY) */ dhd_mmc_suspend = TRUE; smp_mb(); @@ -187,11 +196,13 @@ static int bcmsdh_sdmmc_resume(struct device *pdev) { struct sdio_func *func = dev_to_sdio_func(pdev); + sd_trace(("%s Enter\n", __FUNCTION__)); dhd_mmc_suspend = FALSE; #if defined(OOB_INTR_ONLY) if ((func->num == 2) && dhd_os_check_if_up(bcmsdh_get_drvdata())) bcmsdh_oob_intr_set(1); -#endif +#endif /* (OOB_INTR_ONLY) */ + smp_mb(); return 0; } @@ -200,7 +211,7 @@ static const struct dev_pm_ops bcmsdh_sdmmc_pm_ops = { .suspend = bcmsdh_sdmmc_suspend, .resume = bcmsdh_sdmmc_resume, }; -#endif +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ static struct sdio_driver bcmsdh_sdmmc_driver = { .probe = bcmsdh_sdmmc_probe, @@ -211,7 +222,7 @@ static struct sdio_driver bcmsdh_sdmmc_driver = { .drv = { .pm = &bcmsdh_sdmmc_pm_ops, }, -#endif +#endif /* (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 39)) && defined(CONFIG_PM) */ }; struct sdos_info { diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 07d8430ea18..29bd8930f24 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -1148,7 +1148,7 @@ dhd_set_mac_address(struct net_device *dev, void *addr) if (ifidx == DHD_BAD_IF) return -1; - ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); + ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN); dhd->set_macaddress = TRUE; up(&dhd->thr_sysioc_ctl.sema); @@ -1166,7 +1166,7 @@ dhd_set_multicast_list(struct net_device *dev) if (ifidx == DHD_BAD_IF) return; - ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); + ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); dhd->iflist[ifidx]->set_multicast = TRUE; up(&dhd->thr_sysioc_ctl.sema); } @@ -2508,7 +2508,7 @@ dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, ifp->state = DHD_IF_ADD; ifp->idx = ifidx; ifp->bssidx = bssidx; - ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); + ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); up(&dhd->thr_sysioc_ctl.sema); } else ifp->net = (struct net_device *)handle; @@ -2532,7 +2532,7 @@ dhd_del_if(dhd_info_t *dhd, int ifidx) ifp->state = DHD_IF_DEL; ifp->idx = ifidx; - ASSERT(&dhd->thr_sysioc_ctl.thr_pid >= 0); + ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); up(&dhd->thr_sysioc_ctl.sema); } @@ -3588,7 +3588,7 @@ void dhd_detach(dhd_pub_t *dhdp) } #endif /* defined(CONFIG_WIRELESS_EXT) */ - if (&dhd->thr_sysioc_ctl.thr_pid >= 0) { + if (dhd->thr_sysioc_ctl.thr_pid >= 0) { PROC_STOP(&dhd->thr_sysioc_ctl); } diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index e19ec6b9c7e..80ee7d56cb2 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_sdio.c 303389 2011-12-16 09:30:48Z $ + * $Id: dhd_sdio.c 308574 2012-01-16 22:56:40Z $ */ #include @@ -851,8 +851,10 @@ dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); /* Isolate the bus */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, - SBSDIO_DEVCTL_PADS_ISO, NULL); + if (bus->sih->chip != BCM4329_CHIP_ID && bus->sih->chip != BCM4319_CHIP_ID) { + bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, + SBSDIO_DEVCTL_PADS_ISO, NULL); + } /* Change state */ bus->sleeping = TRUE; @@ -5191,6 +5193,9 @@ dhdsdio_chipmatch(uint16 chipid) return TRUE; if (chipid == BCM4330_CHIP_ID) return TRUE; + if (chipid == BCM43239_CHIP_ID) + return TRUE; + return FALSE; } diff --git a/drivers/net/wireless/bcmdhd/hndpmu.c b/drivers/net/wireless/bcmdhd/hndpmu.c index 111b5be9cbf..0e493343c80 100644 --- a/drivers/net/wireless/bcmdhd/hndpmu.c +++ b/drivers/net/wireless/bcmdhd/hndpmu.c @@ -140,11 +140,27 @@ si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength) str_mask = 0x00003800; str_shift = 11; break; + case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8): + case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 11): + if (sih->pmurev == 8) { + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab3; + } + else if (sih->pmurev == 11) { + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; + } + str_mask = 0x00003800; + str_shift = 11; + break; case SDIOD_DRVSTR_KEY(BCM4330_CHIP_ID, 12): str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab4_1v8; str_mask = 0x00003800; str_shift = 11; break; + case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): + str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab5_1v8; + str_mask = 0x00003800; + str_shift = 11; + break; default: PMU_MSG(("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", bcm_chipname(sih->chip, chn, 8), sih->chiprev, sih->pmurev)); diff --git a/drivers/net/wireless/bcmdhd/include/bcmdevs.h b/drivers/net/wireless/bcmdhd/include/bcmdevs.h index f0542f2ac11..ee01d8b4567 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmdevs.h +++ b/drivers/net/wireless/bcmdhd/include/bcmdevs.h @@ -57,8 +57,10 @@ #define BCM_DNGL_BL_PID_4328 0xbd12 #define BCM_DNGL_BL_PID_4322 0xbd13 #define BCM_DNGL_BL_PID_4319 0xbd16 +#define BCM_DNGL_BL_PID_43236 0xbd17 #define BCM_DNGL_BL_PID_4332 0xbd18 #define BCM_DNGL_BL_PID_4330 0xbd19 +#define BCM_DNGL_BL_PID_43239 0xbd1b #define BCM_DNGL_BDC_PID 0x0bdc #define BCM_DNGL_JTAG_PID 0x4a44 diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index a0e9ed12b88..f82ee102574 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -33,17 +33,17 @@ #define EPI_RC_NUMBER 195 -#define EPI_INCREMENTAL_NUMBER 19 +#define EPI_INCREMENTAL_NUMBER 22 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 5, 90, 195, 19 +#define EPI_VERSION 5, 90, 195, 22 -#define EPI_VERSION_NUM 0x055ac313 +#define EPI_VERSION_NUM 0x055ac316 #define EPI_VERSION_DEV 5.90.195 -#define EPI_VERSION_STR "5.90.195.19" +#define EPI_VERSION_STR "5.90.195.22" #endif diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c index 4b715630355..1cc977f51ee 100644 --- a/drivers/net/wireless/bcmdhd/siutils.c +++ b/drivers/net/wireless/bcmdhd/siutils.c @@ -1901,6 +1901,9 @@ si_is_sprom_available(si_t *sih) return (sih->chipst & CST4330_SPROM_PRESENT) != 0; case BCM4313_CHIP_ID: return (sih->chipst & CST4313_SPROM_PRESENT) != 0; + case BCM43239_CHIP_ID: + return ((sih->chipst & CST43239_SPROM_MASK) && + !(sih->chipst & CST43239_SFLASH_MASK)); default: return TRUE; } diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 2312e0d2443..7bab18d6d4a 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -4213,8 +4213,8 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX; wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; wdev->wiphy->interface_modes = - BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) - | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR); + BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR); wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; @@ -5612,6 +5612,13 @@ static s32 wl_escan_handler(struct wl_priv *wl, goto exit; } + if (!(wl_to_wiphy(wl)->interface_modes & BIT(NL80211_IFTYPE_ADHOC))) { + if (dtoh16(bi->capability) & DOT11_CAP_IBSS) { + WL_ERR(("Ignoring IBSS result\n")); + goto exit; + } + } + if (wl_get_drv_status_all(wl, SENDING_ACT_FRM)) { p2p_dev_addr = wl_cfgp2p_retreive_p2p_dev_addr(bi, bi_length); if (p2p_dev_addr && !memcmp(p2p_dev_addr, From ff93146589f6f28ba8a46f85e9b319bbd2cc8cfd Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 24 Jan 2012 13:59:40 -0800 Subject: [PATCH 0754/4025] net: wireless: bcmdhd: Update to Version 5.90.195.23 - WFD fixes Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_cfg80211.c | 269 ------------------ drivers/net/wireless/bcmdhd/dhd_linux.c | 2 +- drivers/net/wireless/bcmdhd/dhd_sdio.c | 8 +- drivers/net/wireless/bcmdhd/include/epivers.h | 8 +- drivers/net/wireless/bcmdhd/siutils.c | 5 + drivers/net/wireless/bcmdhd/wl_cfg80211.c | 223 ++++++++++----- drivers/net/wireless/bcmdhd/wl_cfgp2p.c | 175 +++++++++++- drivers/net/wireless/bcmdhd/wl_cfgp2p.h | 37 +-- 8 files changed, 368 insertions(+), 359 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c index 058749deba3..800590cca65 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c @@ -34,13 +34,6 @@ extern struct wl_priv *wlcfg_drv_priv; static int dhd_dongle_up = FALSE; static s32 wl_dongle_up(struct net_device *ndev, u32 up); -static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode); -static s32 wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align); -static s32 wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout); -static s32 wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, s32 scan_unassoc_time); -static s32 wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol); -static s32 wl_pattern_atoh(s8 *src, s8 *dst); -static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode); /** * Function implementations @@ -74,250 +67,6 @@ static s32 wl_dongle_up(struct net_device *ndev, u32 up) } return err; } - -static s32 wl_dongle_power(struct net_device *ndev, u32 power_mode) -{ - s32 err = 0; - - WL_TRACE(("In\n")); - err = wldev_ioctl(ndev, WLC_SET_PM, &power_mode, sizeof(power_mode), true); - if (unlikely(err)) { - WL_ERR(("WLC_SET_PM error (%d)\n", err)); - } - return err; -} - -static s32 -wl_dongle_glom(struct net_device *ndev, u32 glom, u32 dongle_align) -{ - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - - s32 err = 0; - - /* Match Host and Dongle rx alignment */ - bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, - sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (unlikely(err)) { - WL_ERR(("txglomalign error (%d)\n", err)); - goto dongle_glom_out; - } - /* disable glom option per default */ - bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (unlikely(err)) { - WL_ERR(("txglom error (%d)\n", err)); - goto dongle_glom_out; - } -dongle_glom_out: - return err; -} - -static s32 -wl_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout) -{ - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - - s32 err = 0; - - /* Setup timeout if Beacons are lost and roam is off to report link down */ - if (roamvar) { - bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, - sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (unlikely(err)) { - WL_ERR(("bcn_timeout error (%d)\n", err)); - goto dongle_rom_out; - } - } - /* Enable/Disable built-in roaming to allow supplicant to take care of roaming */ - bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (unlikely(err)) { - WL_ERR(("roam_off error (%d)\n", err)); - goto dongle_rom_out; - } -dongle_rom_out: - return err; -} - -static s32 -wl_dongle_scantime(struct net_device *ndev, s32 scan_assoc_time, - s32 scan_unassoc_time) -{ - s32 err = 0; - - err = wldev_ioctl(ndev, WLC_SET_SCAN_CHANNEL_TIME, &scan_assoc_time, - sizeof(scan_assoc_time), true); - if (err) { - if (err == -EOPNOTSUPP) { - WL_INFO(("Scan assoc time is not supported\n")); - } else { - WL_ERR(("Scan assoc time error (%d)\n", err)); - } - goto dongle_scantime_out; - } - err = wldev_ioctl(ndev, WLC_SET_SCAN_UNASSOC_TIME, &scan_unassoc_time, - sizeof(scan_unassoc_time), true); - if (err) { - if (err == -EOPNOTSUPP) { - WL_INFO(("Scan unassoc time is not supported\n")); - } else { - WL_ERR(("Scan unassoc time error (%d)\n", err)); - } - goto dongle_scantime_out; - } - -dongle_scantime_out: - return err; -} - -static s32 -wl_dongle_offload(struct net_device *ndev, s32 arpoe, s32 arp_ol) -{ - /* Room for "event_msgs" + '\0' + bitvec */ - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - - s32 err = 0; - - /* Set ARP offload */ - bcm_mkiovar("arpoe", (char *)&arpoe, 4, iovbuf, sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (err) { - if (err == -EOPNOTSUPP) - WL_INFO(("arpoe is not supported\n")); - else - WL_ERR(("arpoe error (%d)\n", err)); - - goto dongle_offload_out; - } - bcm_mkiovar("arp_ol", (char *)&arp_ol, 4, iovbuf, sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (err) { - if (err == -EOPNOTSUPP) - WL_INFO(("arp_ol is not supported\n")); - else - WL_ERR(("arp_ol error (%d)\n", err)); - - goto dongle_offload_out; - } - -dongle_offload_out: - return err; -} - -static s32 wl_pattern_atoh(s8 *src, s8 *dst) -{ - int i; - if (strncmp(src, "0x", 2) != 0 && strncmp(src, "0X", 2) != 0) { - WL_ERR(("Mask invalid format. Needs to start with 0x\n")); - return -1; - } - src = src + 2; /* Skip past 0x */ - if (strlen(src) % 2 != 0) { - WL_ERR(("Mask invalid format. Needs to be of even length\n")); - return -1; - } - for (i = 0; *src != '\0'; i++) { - char num[3]; - strncpy(num, src, 2); - num[2] = '\0'; - dst[i] = (u8) simple_strtoul(num, NULL, 16); - src += 2; - } - return i; -} - -static s32 wl_dongle_filter(struct net_device *ndev, u32 filter_mode) -{ - /* Room for "event_msgs" + '\0' + bitvec */ - s8 iovbuf[WL_EVENTING_MASK_LEN + 12]; - - const s8 *str; - struct wl_pkt_filter pkt_filter; - struct wl_pkt_filter *pkt_filterp; - s32 buf_len; - s32 str_len; - u32 mask_size; - u32 pattern_size; - s8 buf[256]; - s32 err = 0; - - /* add a default packet filter pattern */ - str = "pkt_filter_add"; - str_len = strlen(str); - strncpy(buf, str, str_len); - buf[str_len] = '\0'; - buf_len = str_len + 1; - - pkt_filterp = (struct wl_pkt_filter *)(buf + str_len + 1); - - /* Parse packet filter id. */ - pkt_filter.id = htod32(100); - - /* Parse filter polarity. */ - pkt_filter.negate_match = htod32(0); - - /* Parse filter type. */ - pkt_filter.type = htod32(0); - - /* Parse pattern filter offset. */ - pkt_filter.u.pattern.offset = htod32(0); - - /* Parse pattern filter mask. */ - mask_size = htod32(wl_pattern_atoh("0xff", - (char *)pkt_filterp->u.pattern. - mask_and_pattern)); - - /* Parse pattern filter pattern. */ - pattern_size = htod32(wl_pattern_atoh("0x00", - (char *)&pkt_filterp->u.pattern.mask_and_pattern[mask_size])); - - if (mask_size != pattern_size) { - WL_ERR(("Mask and pattern not the same size\n")); - err = -EINVAL; - goto dongle_filter_out; - } - - pkt_filter.u.pattern.size_bytes = mask_size; - buf_len += WL_PKT_FILTER_FIXED_LEN; - buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); - - /* Keep-alive attributes are set in local - * variable (keep_alive_pkt), and - * then memcpy'ed into buffer (keep_alive_pktp) since there is no - * guarantee that the buffer is properly aligned. - */ - memcpy((char *)pkt_filterp, &pkt_filter, - WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); - - err = wldev_ioctl(ndev, WLC_SET_VAR, buf, buf_len, true); - if (err) { - if (err == -EOPNOTSUPP) { - WL_INFO(("filter not supported\n")); - } else { - WL_ERR(("filter (%d)\n", err)); - } - goto dongle_filter_out; - } - - /* set mode to allow pattern */ - bcm_mkiovar("pkt_filter_mode", (char *)&filter_mode, 4, iovbuf, - sizeof(iovbuf)); - err = wldev_ioctl(ndev, WLC_SET_VAR, iovbuf, sizeof(iovbuf), true); - if (err) { - if (err == -EOPNOTSUPP) { - WL_INFO(("filter_mode not supported\n")); - } else { - WL_ERR(("filter_mode (%d)\n", err)); - } - goto dongle_filter_out; - } - -dongle_filter_out: - return err; -} - s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock) { #ifndef DHD_SDALIGN @@ -342,24 +91,6 @@ s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock) WL_ERR(("wl_dongle_up failed\n")); goto default_conf_out; } - err = wl_dongle_power(ndev, PM_FAST); - if (unlikely(err)) { - WL_ERR(("wl_dongle_power failed\n")); - goto default_conf_out; - } - err = wl_dongle_glom(ndev, 0, DHD_SDALIGN); - if (unlikely(err)) { - WL_ERR(("wl_dongle_glom failed\n")); - goto default_conf_out; - } - err = wl_dongle_roam(ndev, (wl->roam_on ? 0 : 1), 3); - if (unlikely(err)) { - WL_ERR(("wl_dongle_roam failed\n")); - goto default_conf_out; - } - wl_dongle_scantime(ndev, 40, 80); - wl_dongle_offload(ndev, 1, 0xf); - wl_dongle_filter(ndev, 1); dhd_dongle_up = true; default_conf_out: diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 29bd8930f24..53c507acb7b 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c 307603 2012-01-12 01:32:01Z $ + * $Id: dhd_linux.c 308879 2012-01-17 22:03:47Z $ */ #include diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 80ee7d56cb2..ff5a75ef165 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_sdio.c 308574 2012-01-16 22:56:40Z $ + * $Id: dhd_sdio.c 309234 2012-01-19 01:44:16Z $ */ #include @@ -5195,6 +5195,12 @@ dhdsdio_chipmatch(uint16 chipid) return TRUE; if (chipid == BCM43239_CHIP_ID) return TRUE; + if (chipid == BCM4336_CHIP_ID) + return TRUE; + if (chipid == BCM43237_CHIP_ID) + return TRUE; + if (chipid == BCM43362_CHIP_ID) + return TRUE; return FALSE; } diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index f82ee102574..53dd2f73673 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -33,17 +33,17 @@ #define EPI_RC_NUMBER 195 -#define EPI_INCREMENTAL_NUMBER 22 +#define EPI_INCREMENTAL_NUMBER 23 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 5, 90, 195, 22 +#define EPI_VERSION 5, 90, 195, 23 -#define EPI_VERSION_NUM 0x055ac316 +#define EPI_VERSION_NUM 0x055ac317 #define EPI_VERSION_DEV 5.90.195 -#define EPI_VERSION_STR "5.90.195.22" +#define EPI_VERSION_STR "5.90.195.23" #endif diff --git a/drivers/net/wireless/bcmdhd/siutils.c b/drivers/net/wireless/bcmdhd/siutils.c index 1cc977f51ee..a655ac4ef14 100644 --- a/drivers/net/wireless/bcmdhd/siutils.c +++ b/drivers/net/wireless/bcmdhd/siutils.c @@ -1897,6 +1897,11 @@ si_is_sprom_available(si_t *sih) return (sih->chipst & CST4315_SPROM_SEL) != 0; case BCM4319_CHIP_ID: return (sih->chipst & CST4319_SPROM_SEL) != 0; + + case BCM4336_CHIP_ID: + case BCM43362_CHIP_ID: + return (sih->chipst & CST4336_SPROM_PRESENT) != 0; + case BCM4330_CHIP_ID: return (sih->chipst & CST4330_SPROM_PRESENT) != 0; case BCM4313_CHIP_ID: diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 7bab18d6d4a..455c43c30cd 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -820,12 +820,14 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, p2p_on(wl) = true; wl_cfgp2p_set_firm_p2p(wl); wl_cfgp2p_init_discovery(wl); + get_primary_mac(wl, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, + &wl->p2p->dev_addr, &wl->p2p->int_addr); } memset(wl->p2p->vir_ifname, 0, IFNAMSIZ); strncpy(wl->p2p->vir_ifname, name, IFNAMSIZ - 1); - get_primary_mac(wl, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); + /* In concurrency case, STA may be already associated in a particular channel. * so retrieve the current channel of primary interface and then start the virtual @@ -1318,6 +1320,25 @@ static s32 wl_do_iscan(struct wl_priv *wl, struct cfg80211_scan_request *request return err; } +static s32 +wl_get_valid_channels(struct net_device *ndev, u8 *valid_chan_list, s32 size) +{ + wl_uint32_list_t *list; + s32 err = BCME_OK; + if (valid_chan_list == NULL || size <= 0) + return -ENOMEM; + + memset(valid_chan_list, 0, size); + list = (wl_uint32_list_t *)(void *) valid_chan_list; + list->count = htod32(WL_NUMCHANNELS); + err = wldev_ioctl(ndev, WLC_GET_VALID_CHANNELS, valid_chan_list, size, false); + if (err != 0) { + WL_ERR(("get channels failed with %d\n", err)); + } + + return err; +} + static s32 wl_run_escan(struct wl_priv *wl, struct net_device *ndev, struct cfg80211_scan_request *request, uint16 action) @@ -1326,12 +1347,16 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, u32 n_channels; u32 n_ssids; s32 params_size = (WL_SCAN_PARAMS_FIXED_SIZE + OFFSETOF(wl_escan_params_t, params)); - wl_escan_params_t *params; + wl_escan_params_t *params = NULL; struct cfg80211_scan_request *scan_request = wl->scan_request; + u8 chan_buf[sizeof(u32)*(WL_NUMCHANNELS + 1)]; u32 num_chans = 0; + s32 channel; + s32 n_valid_chan; s32 search_state = WL_P2P_DISC_ST_SCAN; - u32 i; + u32 i, j, n_nodfs = 0; u16 *default_chan_list = NULL; + wl_uint32_list_t *list; struct net_device *dev = NULL; WL_DBG(("Enter \n")); @@ -1378,6 +1403,8 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, } else if (p2p_is_on(wl) && p2p_scan(wl)) { /* P2P SCAN TRIGGER */ + s32 _freq = 0; + n_nodfs = 0; if (scan_request && scan_request->n_channels) { num_chans = scan_request->n_channels; WL_SCAN((" chann number : %d\n", num_chans)); @@ -1388,11 +1415,26 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, err = -ENOMEM; goto exit; } - for (i = 0; i < num_chans; i++) - { - default_chan_list[i] = - ieee80211_frequency_to_channel( - scan_request->channels[i]->center_freq); + if (!wl_get_valid_channels(ndev, chan_buf, sizeof(chan_buf))) { + list = (wl_uint32_list_t *) chan_buf; + n_valid_chan = dtoh32(list->count); + for (i = 0; i < num_chans; i++) + { + _freq = scan_request->channels[i]->center_freq; + channel = ieee80211_frequency_to_channel(_freq); + /* remove DFS channels */ + if (channel < 52 || channel > 140) { + for (j = 0; j < n_valid_chan; j++) { + /* allows only supported channel on + * current reguatory + */ + if (channel == (dtoh32(list->element[j]))) + default_chan_list[n_nodfs++] = + channel; + } + } + + } } if (num_chans == 3 && ( (default_chan_list[0] == SOCIAL_CHAN_1) && @@ -1406,8 +1448,11 @@ wl_run_escan(struct wl_priv *wl, struct net_device *ndev, /* If you are already a GO, then do SEARCH only */ WL_INFO(("Already a GO. Do SEARCH Only")); search_state = WL_P2P_DISC_ST_SEARCH; + num_chans = n_nodfs; + } else { WL_INFO(("P2P SCAN STATE START \n")); + num_chans = n_nodfs; } } @@ -1459,6 +1504,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct wl_priv *wl = wiphy_priv(wiphy); struct cfg80211_ssid *ssids; struct wl_scan_req *sr = wl_to_sr(wl); + struct ether_addr primary_mac; wpa_ie_fixed_t *wps_ie; s32 passive_scan; bool iscan_req; @@ -1513,6 +1559,9 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, /* p2p on at the first time */ p2p_on(wl) = true; wl_cfgp2p_set_firm_p2p(wl); + get_primary_mac(wl, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, + &wl->p2p->dev_addr, &wl->p2p->int_addr); } p2p_scan(wl) = true; } @@ -2655,9 +2704,9 @@ wl_cfg80211_del_key(struct wiphy *wiphy, struct net_device *dev, CHECK_SYS_UP(wl); memset(&key, 0, sizeof(key)); - key.index = (u32) key_idx; key.flags = WL_PRIMARY_KEY; key.algo = CRYPTO_ALGO_OFF; + key.index = (u32) key_idx; WL_DBG(("key index (%d)\n", key_idx)); /* Set the new key/index */ @@ -3312,7 +3361,6 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, bool channel_type_valid, unsigned int wait, const u8* buf, size_t len, u64 *cookie) { - struct ether_addr primary_mac; wl_action_frame_t *action_frame; wl_af_params_t *af_params; wifi_p2p_ie_t *p2p_ie; @@ -3328,7 +3376,9 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, u32 id; u32 retry = 0; bool ack = false; - wifi_p2p_pub_act_frame_t *act_frm; + wifi_p2p_pub_act_frame_t *act_frm = NULL; + wifi_p2p_action_frame_t *p2p_act_frm = NULL; + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; s8 eabuf[ETHER_ADDR_STR_LEN]; WL_DBG(("Enter \n")); @@ -3348,8 +3398,6 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, return -ENODEV; } if (p2p_is_on(wl)) { - get_primary_mac(wl, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, &wl->p2p->dev_addr, &wl->p2p->int_addr); /* Suspend P2P discovery search-listen to prevent it from changing the * channel. */ @@ -3400,11 +3448,12 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, goto exit; } else if (ieee80211_is_action(mgmt->frame_control)) { - /* Abort the dwell time of any previous off-channel action frame that may - * be still in effect. Sending off-channel action frames relies on the - * driver's scan engine. If a previous off-channel action frame tx is - * still in progress (including the dwell time), then this new action - * frame will not be sent out. + /* Abort the dwell time of any previous off-channel + * action frame that may be still in effect. Sending + * off-channel action frames relies on the driver's + * scan engine. If a previous off-channel action frame + * tx is still in progress (including the dwell time), + * then this new action frame will not be sent out. */ wl_cfg80211_scan_abort(wl, dev); @@ -3455,50 +3504,80 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, af_params->dwell_time = WL_DWELL_TIME; memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], action_frame->len); + if (wl_cfgp2p_is_pub_action(action_frame->data, action_frame->len)) { + act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data); + WL_DBG(("P2P PUB action_frame->len: %d chan %d category %d subtype %d\n", + action_frame->len, af_params->channel, + act_frm->category, act_frm->subtype)); + } else if (wl_cfgp2p_is_p2p_action(action_frame->data, action_frame->len)) { + p2p_act_frm = (wifi_p2p_action_frame_t *) (action_frame->data); + WL_DBG(("P2P action_frame->len: %d chan %d category %d subtype %d\n", + action_frame->len, af_params->channel, + p2p_act_frm->category, p2p_act_frm->subtype)); + } else if (wl_cfgp2p_is_gas_action(action_frame->data, action_frame->len)) { + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) (action_frame->data); + WL_DBG(("Service Discovery action_frame->len: %d chan %d category %d action %d\n", + action_frame->len, af_params->channel, + sd_act_frm->category, sd_act_frm->action)); + + } + wl_cfgp2p_print_actframe(true, action_frame->data, action_frame->len); + /* + * To make sure to send successfully action frame, we have to turn off mpc + */ - act_frm = (wifi_p2p_pub_act_frame_t *) (action_frame->data); - WL_DBG(("action_frame->len: %d chan %d category %d subtype %d\n", - action_frame->len, af_params->channel, - act_frm->category, act_frm->subtype)); - /* - * To make sure to send successfully action frame, we have to turn off mpc - */ - if ((IS_PUB_ACT_FRAME(act_frm->category)) && - ((act_frm->subtype == P2P_PAF_GON_REQ) || + if (act_frm && ((act_frm->subtype == P2P_PAF_GON_REQ) || (act_frm->subtype == P2P_PAF_GON_RSP) || (act_frm->subtype == P2P_PAF_GON_CONF) || (act_frm->subtype == P2P_PAF_PROVDIS_REQ))) { wldev_iovar_setint(dev, "mpc", 0); } - if (IS_PUB_ACT_FRAME(act_frm->category)) { - if (act_frm->subtype == P2P_PAF_DEVDIS_REQ) { - af_params->dwell_time = WL_LONG_DWELL_TIME; - } else if ((act_frm->subtype == P2P_PAF_PROVDIS_REQ) || - (act_frm->subtype == P2P_PAF_PROVDIS_RSP)) { - af_params->dwell_time = WL_MED_DWELL_TIME; - } + if (act_frm && act_frm->subtype == P2P_PAF_DEVDIS_REQ) { + af_params->dwell_time = WL_LONG_DWELL_TIME; + } else if (act_frm && + (act_frm->subtype == P2P_PAF_PROVDIS_REQ || + act_frm->subtype == P2P_PAF_PROVDIS_RSP || + act_frm->subtype == P2P_PAF_GON_RSP)) { + af_params->dwell_time = WL_MED_DWELL_TIME; } + if (IS_P2P_SOCIAL(af_params->channel) && - (IS_P2P_ACT_REQ(act_frm->category, act_frm->subtype) || - IS_GAS_REQ(act_frm->category, act_frm->action)) && + (IS_P2P_PUB_ACT_REQ(act_frm, action_frame->len) || + IS_GAS_REQ(sd_act_frm, action_frame->len)) && wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { /* channel offload require P2P IE for Probe request * otherwise, we will use wl_cfgp2p_tx_action_frame directly. * channel offload for action request frame - */ + */ + + /* channel offload for action request frame */ ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params); } else { - for (retry = 0; retry < WL_CHANNEL_SYNC_RETRY; retry++) { - ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? - false : true; - if (ack) - break; + ack = (wl_cfgp2p_tx_action_frame(wl, dev, af_params, bssidx)) ? false : true; + if (!ack) { + if (wl_to_p2p_bss_saved_ie(wl, P2PAPI_BSSCFG_DEVICE).p2p_probe_req_ie_len) { + /* if the NO ACK occurs, the peer device will be on + * listen channel of the peer + * So, we have to find the peer and send action frame on + * that channel. + */ + ack = wl_cfg80211_send_at_common_channel(wl, dev, af_params); + } else { + for (retry = 0; retry < WL_CHANNEL_SYNC_RETRY; retry++) { + ack = (wl_cfgp2p_tx_action_frame(wl, dev, + af_params, bssidx)) ? false : true; + if (ack) + break; + } + + } + } + } cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, ack, GFP_KERNEL); - if (IS_PUB_ACT_FRAME(act_frm->category) && - (act_frm->subtype == P2P_PAF_GON_CONF)) { + if (act_frm && act_frm->subtype == P2P_PAF_GON_CONF) { wldev_iovar_setint(dev, "mpc", 1); } kfree(af_params); @@ -4235,7 +4314,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev #endif WIPHY_FLAG_4ADDR_STATION; #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) - wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; + wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; #endif WL_DBG(("Registering custom regulatory)\n")); wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; @@ -4355,7 +4434,8 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) signal = notif_bss_info->rssi * 100; #if defined(WLP2P) && ENABLE_P2P_INTERFACE - if (wl->p2p_net && wl->scan_request && wl->scan_request->dev == wl->p2p_net) { + if (wl->p2p_net && wl->scan_request && + wl->scan_request->dev == wl->p2p_net) { #else if (p2p_is_on(wl) && p2p_scan(wl)) { #endif @@ -5054,7 +5134,9 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, s32 err = 0; s32 freq; struct net_device *dev = NULL; - wifi_p2p_pub_act_frame_t *act_frm; + wifi_p2p_pub_act_frame_t *act_frm = NULL; + wifi_p2p_action_frame_t *p2p_act_frm = NULL; + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm = NULL; wl_event_rx_frame_data_t *rxframe = (wl_event_rx_frame_data_t*)data; u32 event = ntoh32(e->event_type); @@ -5096,23 +5178,30 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, goto exit; } isfree = true; - act_frm = - (wifi_p2p_pub_act_frame_t *) (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + if (wl_cfgp2p_is_pub_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { + act_frm = (wifi_p2p_pub_act_frame_t *) + (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + } else if (wl_cfgp2p_is_p2p_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { + p2p_act_frm = (wifi_p2p_action_frame_t *) + (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + (void) p2p_act_frm; + } else if (wl_cfgp2p_is_gas_action(&mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN)) { + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *) + (&mgmt_frame[DOT11_MGMT_HDR_LEN]); + (void) sd_act_frm; + } + wl_cfgp2p_print_actframe(false, &mgmt_frame[DOT11_MGMT_HDR_LEN], + mgmt_frame_len - DOT11_MGMT_HDR_LEN); /* * After complete GO Negotiation, roll back to mpc mode */ - if (IS_PUB_ACT_FRAME(act_frm->category) && - ((act_frm->subtype == P2P_PAF_GON_CONF)|| - (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { + if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) || + (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { wldev_iovar_setint(dev, "mpc", 1); } - - if (IS_P2P_ACT_FRAME(act_frm->category) && - (act_frm->subtype == P2P_AF_PRESENCE_REQ)) { - /* TODO Do not submit these frames to supplicant, - * we will handle it in the driver - */ - } } else { mgmt_frame = (u8 *)((wl_event_rx_frame_data_t *)rxframe + 1); } @@ -6592,13 +6681,19 @@ static void wl_delay(u32 ms) s32 wl_cfg80211_get_p2p_dev_addr(struct net_device *net, struct ether_addr *p2pdev_addr) { - struct wl_priv *wl; + struct wl_priv *wl = wlcfg_drv_priv; struct ether_addr p2pif_addr; struct ether_addr primary_mac; - wl = wlcfg_drv_priv; - get_primary_mac(wl, &primary_mac); - wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr); + if (!wl->p2p) + return -1; + if (!p2p_is_on(wl)) { + get_primary_mac(wl, &primary_mac); + wl_cfgp2p_generate_bss_mac(&primary_mac, p2pdev_addr, &p2pif_addr); + } else { + memcpy(p2pdev_addr->octet, + wl->p2p->dev_addr.octet, ETHER_ADDR_LEN); + } return 0; } diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c index 6991a9d7855..880123e067d 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.c +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.c @@ -67,6 +67,170 @@ static const struct net_device_ops wl_cfgp2p_if_ops = { .ndo_start_xmit = wl_cfgp2p_start_xmit, }; +bool wl_cfgp2p_is_pub_action(void *frame, u32 frame_len) +{ + wifi_p2p_pub_act_frame_t *pact_frm; + + if (frame == NULL) + return false; + pact_frm = (wifi_p2p_pub_act_frame_t *)frame; + if (frame_len < sizeof(wifi_p2p_pub_act_frame_t) -1) + return false; + + if (pact_frm->category == P2P_PUB_AF_CATEGORY && + pact_frm->action == P2P_PUB_AF_ACTION && + pact_frm->oui_type == P2P_VER && + memcmp(pact_frm->oui, P2P_OUI, sizeof(pact_frm->oui)) == 0) { + return true; + } + + return false; +} + +bool wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len) +{ + wifi_p2p_action_frame_t *act_frm; + + if (frame == NULL) + return false; + act_frm = (wifi_p2p_action_frame_t *)frame; + if (frame_len < sizeof(wifi_p2p_action_frame_t) -1) + return false; + + if (act_frm->category == P2P_AF_CATEGORY && + act_frm->type == P2P_VER && + memcmp(act_frm->OUI, P2P_OUI, DOT11_OUI_LEN) == 0) { + return true; + } + + return false; +} +bool wl_cfgp2p_is_gas_action(void *frame, u32 frame_len) +{ + + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; + + if (frame == NULL) + return false; + + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; + if (frame_len < sizeof(wifi_p2psd_gas_pub_act_frame_t) - 1) + return false; + if (sd_act_frm->category != P2PSD_ACTION_CATEGORY) + return false; + + if (sd_act_frm->action == P2PSD_ACTION_ID_GAS_IREQ || + sd_act_frm->action == P2PSD_ACTION_ID_GAS_IRESP || + sd_act_frm->action == P2PSD_ACTION_ID_GAS_CREQ || + sd_act_frm->action == P2PSD_ACTION_ID_GAS_CRESP) + return true; + else + return false; + +} +void wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len) +{ + wifi_p2p_pub_act_frame_t *pact_frm; + wifi_p2p_action_frame_t *act_frm; + wifi_p2psd_gas_pub_act_frame_t *sd_act_frm; + if (!frame || frame_len <= 2) + return; + + if (wl_cfgp2p_is_pub_action(frame, frame_len)) { + pact_frm = (wifi_p2p_pub_act_frame_t *)frame; + switch (pact_frm->subtype) { + case P2P_PAF_GON_REQ: + CFGP2P_DBG(("%s P2P Group Owner Negotiation Req Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_GON_RSP: + CFGP2P_DBG(("%s P2P Group Owner Negotiation Rsp Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_GON_CONF: + CFGP2P_DBG(("%s P2P Group Owner Negotiation Confirm Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_INVITE_REQ: + CFGP2P_DBG(("%s P2P Invitation Request Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_INVITE_RSP: + CFGP2P_DBG(("%s P2P Invitation Response Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_DEVDIS_REQ: + CFGP2P_DBG(("%s P2P Device Discoverability Request Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_DEVDIS_RSP: + CFGP2P_DBG(("%s P2P Device Discoverability Response Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_PROVDIS_REQ: + CFGP2P_DBG(("%s P2P Provision Discovery Request Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_PAF_PROVDIS_RSP: + CFGP2P_DBG(("%s P2P Provision Discovery Response Frame\n", + (tx)? "TX": "RX")); + break; + default: + CFGP2P_DBG(("%s Unknown P2P Public Action Frame\n", + (tx)? "TX": "RX")); + + } + + } else if (wl_cfgp2p_is_p2p_action(frame, frame_len)) { + act_frm = (wifi_p2p_action_frame_t *)frame; + switch (act_frm->subtype) { + case P2P_AF_NOTICE_OF_ABSENCE: + CFGP2P_DBG(("%s P2P Notice of Absence Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_AF_PRESENCE_REQ: + CFGP2P_DBG(("%s P2P Presence Request Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_AF_PRESENCE_RSP: + CFGP2P_DBG(("%s P2P Presence Response Frame\n", + (tx)? "TX": "RX")); + break; + case P2P_AF_GO_DISC_REQ: + CFGP2P_DBG(("%s P2P Discoverability Request Frame\n", + (tx)? "TX": "RX")); + break; + default: + CFGP2P_DBG(("%s Unknown P2P Action Frame\n", + (tx)? "TX": "RX")); + } + + } else if (wl_cfgp2p_is_gas_action(frame, frame_len)) { + sd_act_frm = (wifi_p2psd_gas_pub_act_frame_t *)frame; + switch (sd_act_frm->action) { + case P2PSD_ACTION_ID_GAS_IREQ: + CFGP2P_DBG(("%s P2P GAS Initial Request\n", + (tx)? "TX" : "RX")); + break; + case P2PSD_ACTION_ID_GAS_IRESP: + CFGP2P_DBG(("%s P2P GAS Initial Response\n", + (tx)? "TX" : "RX")); + break; + case P2PSD_ACTION_ID_GAS_CREQ: + CFGP2P_DBG(("%s P2P GAS Comback Request\n", + (tx)? "TX" : "RX")); + break; + case P2PSD_ACTION_ID_GAS_CRESP: + CFGP2P_DBG(("%s P2P GAS Comback Response\n", + (tx)? "TX" : "RX")); + break; + default: + CFGP2P_DBG(("%s Unknown P2P GAS Frame\n", + (tx)? "TX" : "RX")); + } + } +} + /* * Initialize variables related to P2P * @@ -1373,7 +1537,8 @@ wl_cfgp2p_down(struct wl_priv *wl) return 0; } -s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) +s32 +wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) { s32 ret = -1; int count, start, duration; @@ -1446,7 +1611,8 @@ s32 wl_cfgp2p_set_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf return ret; } -s32 wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len) +s32 +wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf, int buf_len) { wifi_p2p_noa_desc_t *noa_desc; int len = 0, i; @@ -1488,7 +1654,8 @@ s32 wl_cfgp2p_get_p2p_noa(struct wl_priv *wl, struct net_device *ndev, char* buf return len * 2; } -s32 wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) +s32 +wl_cfgp2p_set_p2p_ps(struct wl_priv *wl, struct net_device *ndev, char* buf, int len) { int ps, ctw; int ret = -1; @@ -1552,7 +1719,7 @@ wl_cfgp2p_retreive_p2pattrib(void *buf, u8 element_id) len -= 4; /* exclude OUI + OUI_TYPE */ while (len >= 3) { - /* attribute id */ + /* attribute id */ subelt_id = *subel; subel += 1; len -= 1; diff --git a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h index d50b00f8394..1e5b1197e92 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfgp2p.h +++ b/drivers/net/wireless/bcmdhd/wl_cfgp2p.h @@ -101,13 +101,13 @@ enum wl_cfgp2p_status { #define wl_to_p2p_bss_saved_ie(w, type) ((wl)->p2p->bss_idx[type].saved_ie) #define wl_to_p2p_bss_private(w, type) ((wl)->p2p->bss_idx[type].private_data) #define wl_to_p2p_bss(wl, type) ((wl)->p2p->bss_idx[type]) -#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : test_bit(WLP2P_STATUS_ ## stat, \ +#define wl_get_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:test_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) -#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : set_bit(WLP2P_STATUS_ ## stat, \ +#define wl_set_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:set_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) -#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0 : clear_bit(WLP2P_STATUS_ ## stat, \ +#define wl_clr_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:clear_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) -#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0: change_bit(WLP2P_STATUS_ ## stat, \ +#define wl_chg_p2p_status(wl, stat) ((!(wl)->p2p_supported) ? 0:change_bit(WLP2P_STATUS_ ## stat, \ &(wl)->p2p->status)) #define p2p_on(wl) ((wl)->p2p->on) #define p2p_scan(wl) ((wl)->p2p->scan) @@ -140,7 +140,14 @@ enum wl_cfgp2p_status { } \ } while (0) - +extern bool +wl_cfgp2p_is_pub_action(void *frame, u32 frame_len); +extern bool +wl_cfgp2p_is_p2p_action(void *frame, u32 frame_len); +extern bool +wl_cfgp2p_is_gas_action(void *frame, u32 frame_len); +extern void +wl_cfgp2p_print_actframe(bool tx, void *frame, u32 frame_len); extern s32 wl_cfgp2p_init_priv(struct wl_priv *wl); extern void @@ -260,17 +267,15 @@ wl_cfgp2p_unregister_ndev(struct wl_priv *wl); #define WL_P2P_WILDCARD_SSID_LEN 7 #define WL_P2P_INTERFACE_PREFIX "p2p" #define WL_P2P_TEMP_CHAN "11" -#define IS_PUB_ACT_FRAME(category) ((category == P2P_PUB_AF_CATEGORY)) -#define IS_P2P_ACT_FRAME(category) ((category == P2P_AF_CATEGORY)) - -#define IS_P2P_ACTION(categry, action) (IS_PUB_ACT_FRAME(category) && (action == P2P_PUB_AF_ACTION)) -#define IS_GAS_REQ(category, action) (IS_PUB_ACT_FRAME(category) && \ - ((action == P2PSD_ACTION_ID_GAS_IREQ) || \ - (action == P2PSD_ACTION_ID_GAS_CREQ))) -#define IS_P2P_ACT_REQ(category, subtype) (IS_PUB_ACT_FRAME(category) && \ - ((subtype == P2P_PAF_GON_REQ) || \ - (subtype == P2P_PAF_INVITE_REQ) || \ - (subtype == P2P_PAF_PROVDIS_REQ))) + + +#define IS_GAS_REQ(frame, len) (wl_cfgp2p_is_gas_action(frame, len) && \ + ((frame->action == P2PSD_ACTION_ID_GAS_IREQ) || \ + (frame->action == P2PSD_ACTION_ID_GAS_CREQ))) +#define IS_P2P_PUB_ACT_REQ(frame, len) (wl_cfgp2p_is_pub_action(frame, len) && \ + ((frame->subtype == P2P_PAF_GON_REQ) || \ + (frame->subtype == P2P_PAF_INVITE_REQ) || \ + (frame->subtype == P2P_PAF_PROVDIS_REQ))) #define IS_P2P_SOCIAL(ch) ((ch == SOCIAL_CHAN_1) || (ch == SOCIAL_CHAN_2) || (ch == SOCIAL_CHAN_3)) #define IS_P2P_SSID(ssid) (memcmp(ssid, WL_P2P_WILDCARD_SSID, WL_P2P_WILDCARD_SSID_LEN) == 0) #endif /* _wl_cfgp2p_h_ */ From 47771afc77173e4d87f67cd11c792b92e8578e72 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 30 Jan 2012 13:03:19 -0800 Subject: [PATCH 0755/4025] net: wireless: bcmdhd: Daemonize wl_event_handler Daemonizing makes thread (besides other things) NON-FREEZABLE, and it will not get fake signal on suspend to quicl down_interruptible() Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_linux.c | 13 ------------- drivers/net/wireless/bcmdhd/include/linuxver.h | 12 ++++++++++++ drivers/net/wireless/bcmdhd/wl_cfg80211.c | 3 +++ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index d4cc56f4043..0cae5d87b88 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -352,19 +352,6 @@ uint dhd_radio_up = 1; char iface_name[IFNAMSIZ] = {'\0'}; module_param_string(iface_name, iface_name, IFNAMSIZ, 0); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define DAEMONIZE(a) daemonize(a); \ - allow_signal(SIGKILL); \ - allow_signal(SIGTERM); -#else /* Linux 2.4 (w/o preemption patch) */ -#define RAISE_RX_SOFTIRQ() \ - cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) -#define DAEMONIZE(a) daemonize(); \ - do { if (a) \ - strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \ - } while (0); -#endif /* LINUX_VERSION_CODE */ - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) #define BLOCKABLE() (!in_atomic()) #else diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h index 96844db2f05..c6ea5e25d6c 100644 --- a/drivers/net/wireless/bcmdhd/include/linuxver.h +++ b/drivers/net/wireless/bcmdhd/include/linuxver.h @@ -507,6 +507,18 @@ typedef struct { (tsk_ctl)->thr_pid = -1; \ } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define DAEMONIZE(a) daemonize(a); \ + allow_signal(SIGKILL); \ + allow_signal(SIGTERM); +#else /* Linux 2.4 (w/o preemption patch) */ +#define RAISE_RX_SOFTIRQ() \ + cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) +#define DAEMONIZE(a) daemonize(); \ + do { if (a) \ + strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \ + } while (0); +#endif /* LINUX_VERSION_CODE */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 32241d52add..6eeb46c05fd 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -5722,6 +5722,9 @@ static s32 wl_event_handler(void *data) tsk_ctl_t *tsk = (tsk_ctl_t *)data; wl = (struct wl_priv *)tsk->parent; + + DAEMONIZE("wl_event_handler"); + complete(&tsk->completed); while (down_interruptible (&tsk->sema) == 0) { From 256a6b23be368f708672eb5929e961afc872f610 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 30 Jan 2012 13:03:19 -0800 Subject: [PATCH 0756/4025] net: wireless: bcmdhd: Daemonize wl_event_handler Daemonizing makes thread (besides other things) NON-FREEZABLE, and it will not get fake signal on suspend to quicl down_interruptible() Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_linux.c | 13 ------------- drivers/net/wireless/bcmdhd/include/linuxver.h | 12 ++++++++++++ drivers/net/wireless/bcmdhd/wl_cfg80211.c | 3 +++ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 53c507acb7b..f3c98a11669 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -359,19 +359,6 @@ uint dhd_radio_up = 1; char iface_name[IFNAMSIZ] = {'\0'}; module_param_string(iface_name, iface_name, IFNAMSIZ, 0); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define DAEMONIZE(a) daemonize(a); \ - allow_signal(SIGKILL); \ - allow_signal(SIGTERM); -#else /* Linux 2.4 (w/o preemption patch) */ -#define RAISE_RX_SOFTIRQ() \ - cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) -#define DAEMONIZE(a) daemonize(); \ - do { if (a) \ - strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \ - } while (0); -#endif /* LINUX_VERSION_CODE */ - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) #define BLOCKABLE() (!in_atomic()) #else diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h index e5189821b4c..d269e66f7fb 100644 --- a/drivers/net/wireless/bcmdhd/include/linuxver.h +++ b/drivers/net/wireless/bcmdhd/include/linuxver.h @@ -511,6 +511,18 @@ typedef struct { (tsk_ctl)->thr_pid = -1; \ } +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define DAEMONIZE(a) daemonize(a); \ + allow_signal(SIGKILL); \ + allow_signal(SIGTERM); +#else /* Linux 2.4 (w/o preemption patch) */ +#define RAISE_RX_SOFTIRQ() \ + cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) +#define DAEMONIZE(a) daemonize(); \ + do { if (a) \ + strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \ + } while (0); +#endif /* LINUX_VERSION_CODE */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 455c43c30cd..125888d028f 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -6135,6 +6135,9 @@ static s32 wl_event_handler(void *data) tsk_ctl_t *tsk = (tsk_ctl_t *)data; wl = (struct wl_priv *)tsk->parent; + + DAEMONIZE("wl_event_handler"); + complete(&tsk->completed); while (down_interruptible (&tsk->sema) == 0) { From dfc896e1c833916ef5062294e2d675d66294ac68 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 30 Jan 2012 15:43:31 -0800 Subject: [PATCH 0757/4025] net: wireless: bcmdhd: Fix crash on dhdsdio_probe_attach() failure Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_linux.c | 17 ++++++++++++++--- drivers/net/wireless/bcmdhd/dhd_sdio.c | 8 +++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index f3c98a11669..95f3a91242a 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -2345,7 +2345,12 @@ dhd_open(struct net_device *net) * We keep WEXT's wl_control_wl_start to provide backward compatibility * This should be removed in the future */ - wl_control_wl_start(net); + ret = wl_control_wl_start(net); + if (ret != 0) { + DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + ret = -1; + goto exit; + } #endif ifidx = dhd_net2idx(dhd, net); @@ -2367,8 +2372,14 @@ dhd_open(struct net_device *net) atomic_set(&dhd->pend_8021x_cnt, 0); #if defined(WL_CFG80211) DHD_ERROR(("\n%s\n", dhd_version)); - if (!dhd_download_fw_on_driverload) - wl_android_wifi_on(net); + if (!dhd_download_fw_on_driverload) { + ret = wl_android_wifi_on(net); + if (ret != 0) { + DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); + ret = -1; + goto exit; + } + } #endif /* defined(WL_CFG80211) */ if (dhd->pub.busstate != DHD_BUS_DATA) { diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index ff5a75ef165..d7823167cca 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -2785,6 +2785,9 @@ dhdsdio_download_state(dhd_bus_t *bus, bool enter) uint retries; int bcmerror = 0; + if (!bus->sih) + return BCME_ERROR; + /* To enter download state, disable ARM and reset SOCRAM. * To exit download state, simply reset ARM (default is RAM boot). */ @@ -5555,8 +5558,10 @@ dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, return TRUE; fail: - if (bus->sih != NULL) + if (bus->sih != NULL) { si_detach(bus->sih); + bus->sih = NULL; + } return FALSE; } @@ -5789,6 +5794,7 @@ dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool r dhdsdio_clkctl(bus, CLK_NONE, FALSE); } si_detach(bus->sih); + bus->sih = NULL; if (bus->vars && bus->varsz) MFREE(osh, bus->vars, bus->varsz); bus->vars = NULL; From 0e80804a2e8134e31d4d32679bdfff070fc64bca Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 31 Jan 2012 11:06:23 -0800 Subject: [PATCH 0758/4025] net: wireless: bcmdhd: Increase pm_notify callback priority Make pm_notify callback to be called the first on suspend/resume path to ensure it will always be called. Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 95f3a91242a..233c8912830 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -495,7 +495,7 @@ static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long actio static struct notifier_block dhd_sleep_pm_notifier = { .notifier_call = dhd_sleep_pm_callback, - .priority = 0 + .priority = 10 }; extern int register_pm_notifier(struct notifier_block *nb); extern int unregister_pm_notifier(struct notifier_block *nb); From 7cc846069a8a9116d8c81526c459070eed0e3477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Mon, 23 Jan 2012 17:15:45 -0800 Subject: [PATCH 0759/4025] Input: evdev - Don't hold wakelock when no data is available to user-space MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If there is no SYN_REPORT event in the buffer the buffer data is invisible to user-space. The wakelock should not be held in this case. Change-Id: Idae890ff0da8eb46a2cfce61a95b3a97252551ad Signed-off-by: Arve Hjønnevåg --- drivers/input/evdev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 5c5f9db2807..23f5545367b 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -62,7 +62,6 @@ static void evdev_pass_event(struct evdev_client *client, /* Interrupts are disabled, just acquire the lock. */ spin_lock(&client->buffer_lock); - wake_lock_timeout(&client->wake_lock, 5 * HZ); client->buffer[client->head++] = *event; client->head &= client->bufsize - 1; @@ -79,10 +78,12 @@ static void evdev_pass_event(struct evdev_client *client, client->buffer[client->tail].value = 0; client->packet_head = client->tail; + wake_unlock(&client->wake_lock); } if (event->type == EV_SYN && event->code == SYN_REPORT) { client->packet_head = client->head; + wake_lock_timeout(&client->wake_lock, 5 * HZ); kill_fasync(&client->fasync, SIGIO, POLL_IN); } @@ -385,7 +386,7 @@ static int evdev_fetch_next_event(struct evdev_client *client, if (have_event) { *event = client->buffer[client->tail++]; client->tail &= client->bufsize - 1; - if (client->head == client->tail) + if (client->packet_head == client->tail) wake_unlock(&client->wake_lock); } From 4dc43d7079bdae572212368e1d29abea0177c932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Fri, 17 Oct 2008 15:20:55 -0700 Subject: [PATCH 0760/4025] Input: evdev - Add ioctl to block suspend while event queue is not empty. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an ioctl, EVIOCSSUSPENDBLOCK, to enable a wakelock that will block suspend while the event queue is not empty. This allows userspace code to process input events while the device appears to be asleep. The current code holds the wakelock for up 5 seconds for every input device and client. This can prevent suspend if sensor with a high data rate is active, even when that sensor is not capable of waking the device once it is suspended. Change-Id: I624d66ef30a0b3abb543685c343382b8419b42b9 Signed-off-by: Arve Hjønnevåg --- drivers/input/evdev.c | 53 ++++++++++++++++++++++++++++++++++++++----- include/linux/input.h | 3 +++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 23f5545367b..d497c972e71 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -45,6 +45,7 @@ struct evdev_client { unsigned int packet_head; /* [future] position of the first element of next packet */ spinlock_t buffer_lock; /* protects access to buffer, head and tail */ struct wake_lock wake_lock; + bool use_wake_lock; char name[28]; struct fasync_struct *fasync; struct evdev *evdev; @@ -78,12 +79,14 @@ static void evdev_pass_event(struct evdev_client *client, client->buffer[client->tail].value = 0; client->packet_head = client->tail; - wake_unlock(&client->wake_lock); + if (client->use_wake_lock) + wake_unlock(&client->wake_lock); } if (event->type == EV_SYN && event->code == SYN_REPORT) { client->packet_head = client->head; - wake_lock_timeout(&client->wake_lock, 5 * HZ); + if (client->use_wake_lock) + wake_lock(&client->wake_lock); kill_fasync(&client->fasync, SIGIO, POLL_IN); } @@ -263,7 +266,8 @@ static int evdev_release(struct inode *inode, struct file *file) mutex_unlock(&evdev->mutex); evdev_detach_client(evdev, client); - wake_lock_destroy(&client->wake_lock); + if (client->use_wake_lock) + wake_lock_destroy(&client->wake_lock); kfree(client); evdev_close_device(evdev); @@ -317,7 +321,6 @@ static int evdev_open(struct inode *inode, struct file *file) spin_lock_init(&client->buffer_lock); snprintf(client->name, sizeof(client->name), "%s-%d", dev_name(&evdev->dev), task_tgid_vnr(current)); - wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name); client->evdev = evdev; evdev_attach_client(evdev, client); @@ -332,7 +335,6 @@ static int evdev_open(struct inode *inode, struct file *file) err_free_client: evdev_detach_client(evdev, client); - wake_lock_destroy(&client->wake_lock); kfree(client); err_put_evdev: put_device(&evdev->dev); @@ -386,7 +388,8 @@ static int evdev_fetch_next_event(struct evdev_client *client, if (have_event) { *event = client->buffer[client->tail++]; client->tail &= client->bufsize - 1; - if (client->packet_head == client->tail) + if (client->use_wake_lock && + client->packet_head == client->tail) wake_unlock(&client->wake_lock); } @@ -636,6 +639,35 @@ static int evdev_handle_set_keycode_v2(struct input_dev *dev, void __user *p) return input_set_keycode(dev, &ke); } +static int evdev_enable_suspend_block(struct evdev *evdev, + struct evdev_client *client) +{ + if (client->use_wake_lock) + return 0; + + spin_lock_irq(&client->buffer_lock); + wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name); + client->use_wake_lock = true; + if (client->packet_head != client->tail) + wake_lock(&client->wake_lock); + spin_unlock_irq(&client->buffer_lock); + return 0; +} + +static int evdev_disable_suspend_block(struct evdev *evdev, + struct evdev_client *client) +{ + if (!client->use_wake_lock) + return 0; + + spin_lock_irq(&client->buffer_lock); + client->use_wake_lock = false; + wake_lock_destroy(&client->wake_lock); + spin_unlock_irq(&client->buffer_lock); + + return 0; +} + static long evdev_do_ioctl(struct file *file, unsigned int cmd, void __user *p, int compat_mode) { @@ -709,6 +741,15 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, case EVIOCSKEYCODE_V2: return evdev_handle_set_keycode_v2(dev, p); + + case EVIOCGSUSPENDBLOCK: + return put_user(client->use_wake_lock, ip); + + case EVIOCSSUSPENDBLOCK: + if (p) + return evdev_enable_suspend_block(evdev, client); + else + return evdev_disable_suspend_block(evdev, client); } size = _IOC_SIZE(cmd); diff --git a/include/linux/input.h b/include/linux/input.h index 771d6d85667..a207923f361 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -129,6 +129,9 @@ struct input_keymap_entry { #define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ +#define EVIOCGSUSPENDBLOCK _IOR('E', 0x91, int) /* get suspend block enable */ +#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int) /* set suspend block enable */ + /* * Device properties and quirks */ From 1f8c5cecfe44994cd617ba2803f41fb56d53e91c Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Wed, 1 Feb 2012 10:33:01 -0800 Subject: [PATCH 0761/4025] Input: evdev - fix variable initialisation Commit 509f87c5f564 (evdev - do not block waiting for an event if fd is nonblock) created a code path were it was possible to use retval uninitialized. This could lead to the xorg evdev input driver getting corrupt data and refusing to work with log messages like AUO-Pixcir touchscreen: Read error: Success sg060_keys: Read error: Success AUO-Pixcir touchscreen: Read error: Success sg060_keys: Read error: Success (for drivers auo-pixcir-ts and gpio-keys). Signed-off-by: Heiko Stuebner --- drivers/input/evdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index d497c972e71..6288d7d84fa 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -404,7 +404,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; struct input_event event; - int retval; + int retval = 0; if (count < input_event_size()) return -EINVAL; From 665612374970f5dba43b65510b52b72130818541 Mon Sep 17 00:00:00 2001 From: Simon Wilson Date: Thu, 2 Feb 2012 16:43:05 -0800 Subject: [PATCH 0762/4025] ARM: s5pv210: herring: don't disable prox sensor during suspend A previous change caused the proximity sensor to become disabled during suspend to reduce power consumption , but this needs to remain on if activated. Change-Id: Idf5ac8df7d1e62f1644820d6590e28eb702ca83b Signed-off-by: Simon Wilson --- arch/arm/mach-s5pv210/mach-herring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c index be33104846f..29d77ddb73a 100755 --- a/arch/arm/mach-s5pv210/mach-herring.c +++ b/arch/arm/mach-s5pv210/mach-herring.c @@ -4904,7 +4904,7 @@ static unsigned int herring_cdma_wimax_sleep_gpio_table[][3] = { { S5PV210_GPJ1(1), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, { S5PV210_GPJ1(2), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, { S5PV210_GPJ1(3), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, - { S5PV210_GPJ1(4), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, + { S5PV210_GPJ1(4), S3C_GPIO_SLP_PREV, S3C_GPIO_PULL_NONE}, { S5PV210_GPJ1(5), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, { S5PV210_GPJ2(0), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, From a3c9ccb3e13812e13be045a97ab309a4e23d9ac4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 23 Jan 2012 18:23:36 +0100 Subject: [PATCH 0763/4025] ALSA: hda - Fix silent outputs from docking-station jacks of Dell laptops commit b4ead019afc201f71c39cd0dfcaafed4a97b3dd2 upstream. The recent change of the power-widget handling for IDT codecs caused the silent output from the docking-station line-out jack. This was partially fixed by the commit f2cbba7602383cd9cdd21f0a5d0b8bd1aad47b33 "ALSA: hda - Fix the lost power-setup of seconary pins after PM resume". But the line-out on the docking-station is still silent when booted with the jack plugged even by this fix. The remainig bug is that the power-widget is set off in stac92xx_init() because the pins in cfg->line_out_pins[] aren't checked there properly but only hp_pins[] are checked in is_nid_hp_pin(). This patch fixes the problem by checking both HP and line-out pins and leaving the power-map correctly. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=42637 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_sigmatel.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 0d8db75535d..43d88c72493 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4162,13 +4162,15 @@ static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, return 1; } -static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) +static int is_nid_out_jack_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) { int i; for (i = 0; i < cfg->hp_outs; i++) if (cfg->hp_pins[i] == nid) return 1; /* nid is a HP-Out */ - + for (i = 0; i < cfg->line_outs; i++) + if (cfg->line_out_pins[i] == nid) + return 1; /* nid is a line-Out */ return 0; /* nid is not a HP-Out */ }; @@ -4354,7 +4356,7 @@ static int stac92xx_init(struct hda_codec *codec) continue; } - if (is_nid_hp_pin(cfg, nid)) + if (is_nid_out_jack_pin(cfg, nid)) continue; /* already has an unsol event */ pinctl = snd_hda_codec_read(codec, nid, 0, From cdce30003c234575bbcfddb0980adc04b82408c7 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Thu, 12 Jan 2012 11:30:44 +0100 Subject: [PATCH 0764/4025] eCryptfs: Sanitize write counts of /dev/ecryptfs commit db10e556518eb9d21ee92ff944530d84349684f4 upstream. A malicious count value specified when writing to /dev/ecryptfs may result in a a very large kernel memory allocation. This patch peeks at the specified packet payload size, adds that to the size of the packet headers and compares the result with the write count value. The resulting maximum memory allocation size is approximately 532 bytes. Signed-off-by: Tyler Hicks Reported-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/miscdev.c | 56 +++++++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c index 940a82e63dc..0dc5a3d554a 100644 --- a/fs/ecryptfs/miscdev.c +++ b/fs/ecryptfs/miscdev.c @@ -409,11 +409,47 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf, ssize_t sz = 0; char *data; uid_t euid = current_euid(); + unsigned char packet_size_peek[3]; int rc; - if (count == 0) + if (count == 0) { goto out; + } else if (count == (1 + 4)) { + /* Likely a harmless MSG_HELO or MSG_QUIT - no packet length */ + goto memdup; + } else if (count < (1 + 4 + 1) + || count > (1 + 4 + 2 + sizeof(struct ecryptfs_message) + 4 + + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES)) { + printk(KERN_WARNING "%s: Acceptable packet size range is " + "[%d-%lu], but amount of data written is [%zu].", + __func__, (1 + 4 + 1), + (1 + 4 + 2 + sizeof(struct ecryptfs_message) + 4 + + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES), count); + return -EINVAL; + } + + if (copy_from_user(packet_size_peek, (buf + 1 + 4), + sizeof(packet_size_peek))) { + printk(KERN_WARNING "%s: Error while inspecting packet size\n", + __func__); + return -EFAULT; + } + + rc = ecryptfs_parse_packet_length(packet_size_peek, &packet_size, + &packet_size_length); + if (rc) { + printk(KERN_WARNING "%s: Error parsing packet length; " + "rc = [%d]\n", __func__, rc); + return rc; + } + + if ((1 + 4 + packet_size_length + packet_size) != count) { + printk(KERN_WARNING "%s: Invalid packet size [%zu]\n", __func__, + packet_size); + return -EINVAL; + } +memdup: data = memdup_user(buf, count); if (IS_ERR(data)) { printk(KERN_ERR "%s: memdup_user returned error [%ld]\n", @@ -435,23 +471,7 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf, } memcpy(&counter_nbo, &data[i], 4); seq = be32_to_cpu(counter_nbo); - i += 4; - rc = ecryptfs_parse_packet_length(&data[i], &packet_size, - &packet_size_length); - if (rc) { - printk(KERN_WARNING "%s: Error parsing packet length; " - "rc = [%d]\n", __func__, rc); - goto out_free; - } - i += packet_size_length; - if ((1 + 4 + packet_size_length + packet_size) != count) { - printk(KERN_WARNING "%s: (1 + packet_size_length([%zd])" - " + packet_size([%zd]))([%zd]) != " - "count([%zd]). Invalid packet format.\n", - __func__, packet_size_length, packet_size, - (1 + packet_size_length + packet_size), count); - goto out_free; - } + i += 4 + packet_size_length; rc = ecryptfs_miscdev_response(&data[i], packet_size, euid, current_user_ns(), task_pid(current), seq); From 9b9f40e785724a265fb6027216fb2bd1e97894f7 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Thu, 12 Jan 2012 16:31:55 +0100 Subject: [PATCH 0765/4025] ecryptfs: Improve metadata read failure logging commit 30373dc0c87ffef68d5628e77d56ffb1fa22e1ee upstream. Print inode on metadata read failure. The only real way of dealing with metadata read failures is to delete the underlying file system file. Having the inode allows one to 'find . -inum INODE`. [tyhicks@canonical.com: Removed some minor not-for-stable parts] Signed-off-by: Tim Gardner Reviewed-by: Kees Cook Signed-off-by: Tyler Hicks Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/crypto.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 7cf5c3e9c17..cfcd0211e12 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -1618,7 +1618,8 @@ int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry) rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_inode); if (rc) { printk(KERN_DEBUG "Valid eCryptfs headers not found in " - "file header region or xattr region\n"); + "file header region or xattr region, inode %lu\n", + ecryptfs_inode->i_ino); rc = -EINVAL; goto out; } @@ -1627,7 +1628,8 @@ int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry) ECRYPTFS_DONT_VALIDATE_HEADER_SIZE); if (rc) { printk(KERN_DEBUG "Valid eCryptfs headers not found in " - "file xattr region either\n"); + "file xattr region either, inode %lu\n", + ecryptfs_inode->i_ino); rc = -EINVAL; } if (crypt_stat->mount_crypt_stat->flags @@ -1638,7 +1640,8 @@ int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry) "crypto metadata only in the extended attribute " "region, but eCryptfs was mounted without " "xattr support enabled. eCryptfs will not treat " - "this like an encrypted file.\n"); + "this like an encrypted file, inode %lu\n", + ecryptfs_inode->i_ino); rc = -EINVAL; } } From a8d66a0b58b353d47b05891fd20b3bdc4c8a8015 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Wed, 18 Jan 2012 18:30:04 -0600 Subject: [PATCH 0766/4025] eCryptfs: Make truncate path killable commit 5e6f0d769017cc49207ef56996e42363ec26c1f0 upstream. ecryptfs_write() handles the truncation of eCryptfs inodes. It grabs a page, zeroes out the appropriate portions, and then encrypts the page before writing it to the lower filesystem. It was unkillable and due to the lack of sparse file support could result in tying up a large portion of system resources, while encrypting pages of zeros, with no way for the truncate operation to be stopped from userspace. This patch adds the ability for ecryptfs_write() to detect a pending fatal signal and return as gracefully as possible. The intent is to leave the lower file in a useable state, while still allowing a user to break out of the encryption loop. If a pending fatal signal is detected, the eCryptfs inode size is updated to reflect the modified inode size and then -EINTR is returned. Signed-off-by: Tyler Hicks Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/read_write.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c index 3745f7c2b9c..54eb14caad7 100644 --- a/fs/ecryptfs/read_write.c +++ b/fs/ecryptfs/read_write.c @@ -132,6 +132,11 @@ int ecryptfs_write(struct inode *ecryptfs_inode, char *data, loff_t offset, size_t num_bytes = (PAGE_CACHE_SIZE - start_offset_in_page); size_t total_remaining_bytes = ((offset + size) - pos); + if (fatal_signal_pending(current)) { + rc = -EINTR; + break; + } + if (num_bytes > total_remaining_bytes) num_bytes = total_remaining_bytes; if (pos < offset) { @@ -193,15 +198,19 @@ int ecryptfs_write(struct inode *ecryptfs_inode, char *data, loff_t offset, } pos += num_bytes; } - if ((offset + size) > ecryptfs_file_size) { - i_size_write(ecryptfs_inode, (offset + size)); + if (pos > ecryptfs_file_size) { + i_size_write(ecryptfs_inode, pos); if (crypt_stat->flags & ECRYPTFS_ENCRYPTED) { - rc = ecryptfs_write_inode_size_to_metadata( + int rc2; + + rc2 = ecryptfs_write_inode_size_to_metadata( ecryptfs_inode); - if (rc) { + if (rc2) { printk(KERN_ERR "Problem with " "ecryptfs_write_inode_size_to_metadata; " - "rc = [%d]\n", rc); + "rc = [%d]\n", rc2); + if (!rc) + rc = rc2; goto out; } } From 714ca4ef28276f142b00ff2e1893f472cc30b07b Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Thu, 19 Jan 2012 20:33:44 -0600 Subject: [PATCH 0767/4025] eCryptfs: Check inode changes in setattr commit a261a03904849c3df50bd0300efb7fb3f865137d upstream. Most filesystems call inode_change_ok() very early in ->setattr(), but eCryptfs didn't call it at all. It allowed the lower filesystem to make the call in its ->setattr() function. Then, eCryptfs would copy the appropriate inode attributes from the lower inode to the eCryptfs inode. This patch changes that and actually calls inode_change_ok() on the eCryptfs inode, fairly early in ecryptfs_setattr(). Ideally, the call would happen earlier in ecryptfs_setattr(), but there are some possible inode initialization steps that must happen first. Since the call was already being made on the lower inode, the change in functionality should be minimal, except for the case of a file extending truncate call. In that case, inode_newsize_ok() was never being called on the eCryptfs inode. Rather than inode_newsize_ok() catching maximum file size errors early on, eCryptfs would encrypt zeroed pages and write them to the lower filesystem until the lower filesystem's write path caught the error in generic_write_checks(). This patch introduces a new function, called ecryptfs_inode_newsize_ok(), which checks if the new lower file size is within the appropriate limits when the truncate operation will be growing the lower file. In summary this change prevents eCryptfs truncate operations (and the resulting page encryptions), which would exceed the lower filesystem limits or FSIZE rlimits, from ever starting. Signed-off-by: Tyler Hicks Reviewed-by: Li Wang Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/inode.c | 48 +++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 4a4fad7fb85..e3562f2a59d 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -854,18 +854,6 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia, size_t num_zeros = (PAGE_CACHE_SIZE - (ia->ia_size & ~PAGE_CACHE_MASK)); - - /* - * XXX(truncate) this should really happen at the begginning - * of ->setattr. But the code is too messy to that as part - * of a larger patch. ecryptfs is also totally missing out - * on the inode_change_ok check at the beginning of - * ->setattr while would include this. - */ - rc = inode_newsize_ok(inode, ia->ia_size); - if (rc) - goto out; - if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { truncate_setsize(inode, ia->ia_size); lower_ia->ia_size = ia->ia_size; @@ -915,6 +903,28 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia, return rc; } +static int ecryptfs_inode_newsize_ok(struct inode *inode, loff_t offset) +{ + struct ecryptfs_crypt_stat *crypt_stat; + loff_t lower_oldsize, lower_newsize; + + crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; + lower_oldsize = upper_size_to_lower_size(crypt_stat, + i_size_read(inode)); + lower_newsize = upper_size_to_lower_size(crypt_stat, offset); + if (lower_newsize > lower_oldsize) { + /* + * The eCryptfs inode and the new *lower* size are mixed here + * because we may not have the lower i_mutex held and/or it may + * not be appropriate to call inode_newsize_ok() with inodes + * from other filesystems. + */ + return inode_newsize_ok(inode, lower_newsize); + } + + return 0; +} + /** * ecryptfs_truncate * @dentry: The ecryptfs layer dentry @@ -931,6 +941,10 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) struct iattr lower_ia = { .ia_valid = 0 }; int rc; + rc = ecryptfs_inode_newsize_ok(dentry->d_inode, new_length); + if (rc) + return rc; + rc = truncate_upper(dentry, &ia, &lower_ia); if (!rc && lower_ia.ia_valid & ATTR_SIZE) { struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); @@ -1012,6 +1026,16 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) } } mutex_unlock(&crypt_stat->cs_mutex); + + rc = inode_change_ok(inode, ia); + if (rc) + goto out; + if (ia->ia_valid & ATTR_SIZE) { + rc = ecryptfs_inode_newsize_ok(inode, ia->ia_size); + if (rc) + goto out; + } + if (S_ISREG(inode->i_mode)) { rc = filemap_write_and_wait(inode->i_mapping); if (rc) From df29ca6c2b93813c987b35972b215d9b2a0a9159 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Tue, 24 Jan 2012 10:02:22 -0600 Subject: [PATCH 0768/4025] eCryptfs: Fix oops when printing debug info in extent crypto functions commit 58ded24f0fcb85bddb665baba75892f6ad0f4b8a upstream. If pages passed to the eCryptfs extent-based crypto functions are not mapped and the module parameter ecryptfs_verbosity=1 was specified at loading time, a NULL pointer dereference will occur. Note that this wouldn't happen on a production system, as you wouldn't pass ecryptfs_verbosity=1 on a production system. It leaks private information to the system logs and is for debugging only. The debugging info printed in these messages is no longer very useful and rather than doing a kmap() in these debugging paths, it will be better to simply remove the debugging paths completely. https://launchpad.net/bugs/913651 Signed-off-by: Tyler Hicks Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/crypto.c | 40 ---------------------------------------- 1 file changed, 40 deletions(-) diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index cfcd0211e12..c6602d24517 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -417,17 +417,6 @@ static int ecryptfs_encrypt_extent(struct page *enc_extent_page, (unsigned long long)(extent_base + extent_offset), rc); goto out; } - if (unlikely(ecryptfs_verbosity > 0)) { - ecryptfs_printk(KERN_DEBUG, "Encrypting extent " - "with iv:\n"); - ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes); - ecryptfs_printk(KERN_DEBUG, "First 8 bytes before " - "encryption:\n"); - ecryptfs_dump_hex((char *) - (page_address(page) - + (extent_offset * crypt_stat->extent_size)), - 8); - } rc = ecryptfs_encrypt_page_offset(crypt_stat, enc_extent_page, 0, page, (extent_offset * crypt_stat->extent_size), @@ -440,14 +429,6 @@ static int ecryptfs_encrypt_extent(struct page *enc_extent_page, goto out; } rc = 0; - if (unlikely(ecryptfs_verbosity > 0)) { - ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16llx]; " - "rc = [%d]\n", - (unsigned long long)(extent_base + extent_offset), rc); - ecryptfs_printk(KERN_DEBUG, "First 8 bytes after " - "encryption:\n"); - ecryptfs_dump_hex((char *)(page_address(enc_extent_page)), 8); - } out: return rc; } @@ -543,17 +524,6 @@ static int ecryptfs_decrypt_extent(struct page *page, (unsigned long long)(extent_base + extent_offset), rc); goto out; } - if (unlikely(ecryptfs_verbosity > 0)) { - ecryptfs_printk(KERN_DEBUG, "Decrypting extent " - "with iv:\n"); - ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes); - ecryptfs_printk(KERN_DEBUG, "First 8 bytes before " - "decryption:\n"); - ecryptfs_dump_hex((char *) - (page_address(enc_extent_page) - + (extent_offset * crypt_stat->extent_size)), - 8); - } rc = ecryptfs_decrypt_page_offset(crypt_stat, page, (extent_offset * crypt_stat->extent_size), @@ -567,16 +537,6 @@ static int ecryptfs_decrypt_extent(struct page *page, goto out; } rc = 0; - if (unlikely(ecryptfs_verbosity > 0)) { - ecryptfs_printk(KERN_DEBUG, "Decrypt extent [0x%.16llx]; " - "rc = [%d]\n", - (unsigned long long)(extent_base + extent_offset), rc); - ecryptfs_printk(KERN_DEBUG, "First 8 bytes after " - "decryption:\n"); - ecryptfs_dump_hex((char *)(page_address(page) - + (extent_offset - * crypt_stat->extent_size)), 8); - } out: return rc; } From c196878589eb5f88e244a557a55b229a3c285b3b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Sun, 15 Jan 2012 08:51:12 -0500 Subject: [PATCH 0769/4025] drm/radeon/kms: Add an MSI quirk for Dell RS690 commit 44517c44496062180a6376cc704b33129441ce60 upstream. Interrupts only work with MSIs. https://bugs.freedesktop.org/show_bug.cgi?id=37679 Reported-by: Dmitry Podgorny Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_irq_kms.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index fecc1aae382..5feb6e9edd8 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -131,6 +131,12 @@ static bool radeon_msi_ok(struct radeon_device *rdev) (rdev->pdev->subsystem_device == 0x30c2)) return true; + /* Dell RS690 only seems to work with MSIs. */ + if ((rdev->pdev->device == 0x791f) && + (rdev->pdev->subsystem_vendor == 0x1028) && + (rdev->pdev->subsystem_device == 0x01fc)) + return true; + /* Dell RS690 only seems to work with MSIs. */ if ((rdev->pdev->device == 0x791f) && (rdev->pdev->subsystem_vendor == 0x1028) && From 90af660bec3b2d47e17cb3caae742810656e2d4f Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 24 Jan 2012 18:54:21 +0100 Subject: [PATCH 0770/4025] drm: Fix authentication kernel crash commit 598781d71119827b454fd75d46f84755bca6f0c6 upstream. If the master tries to authenticate a client using drm_authmagic and that client has already closed its drm file descriptor, either wilfully or because it was terminated, the call to drm_authmagic will dereference a stale pointer into kmalloc'ed memory and corrupt it. Typically this results in a hard system hang. This patch fixes that problem by removing any authentication tokens (struct drm_magic_entry) open for a file descriptor when that file descriptor is closed. Signed-off-by: Thomas Hellstrom Reviewed-by: Daniel Vetter Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_auth.c | 6 +++++- drivers/gpu/drm/drm_fops.c | 5 +++++ include/drm/drmP.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index 3f46772f0cb..ba23790450e 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -101,7 +101,7 @@ static int drm_add_magic(struct drm_master *master, struct drm_file *priv, * Searches and unlinks the entry in drm_device::magiclist with the magic * number hash key, while holding the drm_device::struct_mutex lock. */ -static int drm_remove_magic(struct drm_master *master, drm_magic_t magic) +int drm_remove_magic(struct drm_master *master, drm_magic_t magic) { struct drm_magic_entry *pt; struct drm_hash_item *hash; @@ -136,6 +136,8 @@ static int drm_remove_magic(struct drm_master *master, drm_magic_t magic) * If there is a magic number in drm_file::magic then use it, otherwise * searches an unique non-zero magic number and add it associating it with \p * file_priv. + * This ioctl needs protection by the drm_global_mutex, which protects + * struct drm_file::magic and struct drm_magic_entry::priv. */ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) { @@ -173,6 +175,8 @@ int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) * \return zero if authentication successed, or a negative number otherwise. * * Checks if \p file_priv is associated with the magic number passed in \arg. + * This ioctl needs protection by the drm_global_mutex, which protects + * struct drm_file::magic and struct drm_magic_entry::priv. */ int drm_authmagic(struct drm_device *dev, void *data, struct drm_file *file_priv) diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 2ec7d48fc4a..c42e12cc2dd 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -486,6 +486,11 @@ int drm_release(struct inode *inode, struct file *filp) (long)old_encode_dev(file_priv->minor->device), dev->open_count); + /* Release any auth tokens that might point to this file_priv, + (do that under the drm_global_mutex) */ + if (file_priv->magic) + (void) drm_remove_magic(file_priv->master, file_priv->magic); + /* if the master has gone away we can't do anything with the lock */ if (file_priv->minor->master) drm_master_release(dev, filp); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 738b3a5faa1..40aaebf50af 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1323,6 +1323,7 @@ extern int drm_getmagic(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_authmagic(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_remove_magic(struct drm_master *master, drm_magic_t magic); /* Cache management (drm_cache.c) */ void drm_clflush_pages(struct page *pages[], unsigned long num_pages); From 2fbe11fed22ed2751aaf4b4926f27730aaac5470 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 11 Jan 2012 18:52:10 +0000 Subject: [PATCH 0771/4025] xfs: Fix missing xfs_iunlock() on error recovery path in xfs_readlink() commit 9b025eb3a89e041bab6698e3858706be2385d692 upstream. Commit b52a360b forgot to call xfs_iunlock() when it detected corrupted symplink and bailed out. Fix it by jumping to 'out' instead of doing return. CC: Carlos Maiolino Signed-off-by: Jan Kara Reviewed-by: Alex Elder Reviewed-by: Dave Chinner Signed-off-by: Ben Myers Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_vnodeops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 6cc4d41fb0d..59509ae0b27 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -554,7 +554,8 @@ xfs_readlink( __func__, (unsigned long long) ip->i_ino, (long long) pathlen); ASSERT(0); - return XFS_ERROR(EFSCORRUPTED); + error = XFS_ERROR(EFSCORRUPTED); + goto out; } From 7ca6029f1a492528e65bc676113eeb1acf3779e4 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 14 Jan 2012 21:27:37 +0300 Subject: [PATCH 0772/4025] crypto: sha512 - make it work, undo percpu message schedule commit 84e31fdb7c797a7303e0cc295cb9bc8b73fb872d upstream. commit f9e2bca6c22d75a289a349f869701214d63b5060 aka "crypto: sha512 - Move message schedule W[80] to static percpu area" created global message schedule area. If sha512_update will ever be entered twice, hash will be silently calculated incorrectly. Probably the easiest way to notice incorrect hashes being calculated is to run 2 ping floods over AH with hmac(sha512): #!/usr/sbin/setkey -f flush; spdflush; add IP1 IP2 ah 25 -A hmac-sha512 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025; add IP2 IP1 ah 52 -A hmac-sha512 0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000052; spdadd IP1 IP2 any -P out ipsec ah/transport//require; spdadd IP2 IP1 any -P in ipsec ah/transport//require; XfrmInStateProtoError will start ticking with -EBADMSG being returned from ah_input(). This never happens with, say, hmac(sha1). With patch applied (on BOTH sides), XfrmInStateProtoError does not tick with multiple bidirectional ping flood streams like it doesn't tick with SHA-1. After this patch sha512_transform() will start using ~750 bytes of stack on x86_64. This is OK for simple loads, for something more heavy, stack reduction will be done separatedly. Signed-off-by: Alexey Dobriyan Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/sha512_generic.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c index 9ed9f60316e..8b9035b0189 100644 --- a/crypto/sha512_generic.c +++ b/crypto/sha512_generic.c @@ -21,8 +21,6 @@ #include #include -static DEFINE_PER_CPU(u64[80], msg_schedule); - static inline u64 Ch(u64 x, u64 y, u64 z) { return z ^ (x & (y ^ z)); @@ -89,7 +87,7 @@ sha512_transform(u64 *state, const u8 *input) u64 a, b, c, d, e, f, g, h, t1, t2; int i; - u64 *W = get_cpu_var(msg_schedule); + u64 W[80]; /* load the input */ for (i = 0; i < 16; i++) @@ -128,8 +126,6 @@ sha512_transform(u64 *state, const u8 *input) /* erase our data */ a = b = c = d = e = f = g = h = t1 = t2 = 0; - memset(W, 0, sizeof(__get_cpu_var(msg_schedule))); - put_cpu_var(msg_schedule); } static int From 3ce5564096c4444197e6f7dc83a9dbc63392b084 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 14 Jan 2012 21:40:57 +0300 Subject: [PATCH 0773/4025] crypto: sha512 - reduce stack usage to safe number commit 51fc6dc8f948047364f7d42a4ed89b416c6cc0a3 upstream. For rounds 16--79, W[i] only depends on W[i - 2], W[i - 7], W[i - 15] and W[i - 16]. Consequently, keeping all W[80] array on stack is unnecessary, only 16 values are really needed. Using W[16] instead of W[80] greatly reduces stack usage (~750 bytes to ~340 bytes on x86_64). Line by line explanation: * BLEND_OP array is "circular" now, all indexes have to be modulo 16. Round number is positive, so remainder operation should be without surprises. * initial full message scheduling is trimmed to first 16 values which come from data block, the rest is calculated before it's needed. * original loop body is unrolled version of new SHA512_0_15 and SHA512_16_79 macros, unrolling was done to not do explicit variable renaming. Otherwise it's the very same code after preprocessing. See sha1_transform() code which does the same trick. Patch survives in-tree crypto test and original bugreport test (ping flood with hmac(sha512). See FIPS 180-2 for SHA-512 definition http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf Signed-off-by: Alexey Dobriyan Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/sha512_generic.c | 58 ++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c index 8b9035b0189..88f160b77b1 100644 --- a/crypto/sha512_generic.c +++ b/crypto/sha512_generic.c @@ -78,7 +78,7 @@ static inline void LOAD_OP(int I, u64 *W, const u8 *input) static inline void BLEND_OP(int I, u64 *W) { - W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16]; + W[I % 16] += s1(W[(I-2) % 16]) + W[(I-7) % 16] + s0(W[(I-15) % 16]); } static void @@ -87,38 +87,48 @@ sha512_transform(u64 *state, const u8 *input) u64 a, b, c, d, e, f, g, h, t1, t2; int i; - u64 W[80]; + u64 W[16]; /* load the input */ for (i = 0; i < 16; i++) LOAD_OP(i, W, input); - for (i = 16; i < 80; i++) { - BLEND_OP(i, W); - } - /* load the state into our registers */ a=state[0]; b=state[1]; c=state[2]; d=state[3]; e=state[4]; f=state[5]; g=state[6]; h=state[7]; - /* now iterate */ - for (i=0; i<80; i+=8) { - t1 = h + e1(e) + Ch(e,f,g) + sha512_K[i ] + W[i ]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + sha512_K[i+1] + W[i+1]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + sha512_K[i+2] + W[i+2]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + sha512_K[i+3] + W[i+3]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + sha512_K[i+4] + W[i+4]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + sha512_K[i+5] + W[i+5]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + sha512_K[i+6] + W[i+6]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + sha512_K[i+7] + W[i+7]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; +#define SHA512_0_15(i, a, b, c, d, e, f, g, h) \ + t1 = h + e1(e) + Ch(e, f, g) + sha512_K[i] + W[i]; \ + t2 = e0(a) + Maj(a, b, c); \ + d += t1; \ + h = t1 + t2 + +#define SHA512_16_79(i, a, b, c, d, e, f, g, h) \ + BLEND_OP(i, W); \ + t1 = h + e1(e) + Ch(e, f, g) + sha512_K[i] + W[(i)%16]; \ + t2 = e0(a) + Maj(a, b, c); \ + d += t1; \ + h = t1 + t2 + + for (i = 0; i < 16; i += 8) { + SHA512_0_15(i, a, b, c, d, e, f, g, h); + SHA512_0_15(i + 1, h, a, b, c, d, e, f, g); + SHA512_0_15(i + 2, g, h, a, b, c, d, e, f); + SHA512_0_15(i + 3, f, g, h, a, b, c, d, e); + SHA512_0_15(i + 4, e, f, g, h, a, b, c, d); + SHA512_0_15(i + 5, d, e, f, g, h, a, b, c); + SHA512_0_15(i + 6, c, d, e, f, g, h, a, b); + SHA512_0_15(i + 7, b, c, d, e, f, g, h, a); + } + for (i = 16; i < 80; i += 8) { + SHA512_16_79(i, a, b, c, d, e, f, g, h); + SHA512_16_79(i + 1, h, a, b, c, d, e, f, g); + SHA512_16_79(i + 2, g, h, a, b, c, d, e, f); + SHA512_16_79(i + 3, f, g, h, a, b, c, d, e); + SHA512_16_79(i + 4, e, f, g, h, a, b, c, d); + SHA512_16_79(i + 5, d, e, f, g, h, a, b, c); + SHA512_16_79(i + 6, c, d, e, f, g, h, a, b); + SHA512_16_79(i + 7, b, c, d, e, f, g, h, a); } state[0] += a; state[1] += b; state[2] += c; state[3] += d; From f935e6192f9e068da8f8395f032ff4b721fe8510 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 13 Jul 2011 15:03:44 -0400 Subject: [PATCH 0774/4025] ftrace: Balance records when updating the hash commit 41fb61c2d08107ce96a5dcb3a6289b2afd3e135c upstream. Whenever the hash of the ftrace_ops is updated, the record counts must be balance. This requires disabling the records that are set in the original hash, and then enabling the records that are set in the updated hash. Moving the update into ftrace_hash_move() removes the bug where the hash was updated but the records were not, which results in ftrace triggering a warning and disabling itself because the ftrace_ops filter is updated while the ftrace_ops was registered, and then the failure happens when the ftrace_ops is unregistered. The current code will not trigger this bug, but new code will. Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- kernel/trace/ftrace.c | 49 +++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index ef9271b69b4..1eef6cf38d5 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1182,8 +1182,14 @@ alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash) return NULL; } +static void +ftrace_hash_rec_disable(struct ftrace_ops *ops, int filter_hash); +static void +ftrace_hash_rec_enable(struct ftrace_ops *ops, int filter_hash); + static int -ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) +ftrace_hash_move(struct ftrace_ops *ops, int enable, + struct ftrace_hash **dst, struct ftrace_hash *src) { struct ftrace_func_entry *entry; struct hlist_node *tp, *tn; @@ -1193,8 +1199,15 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) unsigned long key; int size = src->count; int bits = 0; + int ret; int i; + /* + * Remove the current set, update the hash and add + * them back. + */ + ftrace_hash_rec_disable(ops, enable); + /* * If the new source is empty, just free dst and assign it * the empty_hash. @@ -1215,9 +1228,10 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) if (bits > FTRACE_HASH_MAX_BITS) bits = FTRACE_HASH_MAX_BITS; + ret = -ENOMEM; new_hash = alloc_ftrace_hash(bits); if (!new_hash) - return -ENOMEM; + goto out; size = 1 << src->size_bits; for (i = 0; i < size; i++) { @@ -1236,7 +1250,16 @@ ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src) rcu_assign_pointer(*dst, new_hash); free_ftrace_hash_rcu(old_hash); - return 0; + ret = 0; + out: + /* + * Enable regardless of ret: + * On success, we enable the new hash. + * On failure, we re-enable the original hash. + */ + ftrace_hash_rec_enable(ops, enable); + + return ret; } /* @@ -2877,7 +2900,7 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, ftrace_match_records(hash, buf, len); mutex_lock(&ftrace_lock); - ret = ftrace_hash_move(orig_hash, hash); + ret = ftrace_hash_move(ops, enable, orig_hash, hash); mutex_unlock(&ftrace_lock); mutex_unlock(&ftrace_regex_lock); @@ -3060,18 +3083,12 @@ ftrace_regex_release(struct inode *inode, struct file *file) orig_hash = &iter->ops->notrace_hash; mutex_lock(&ftrace_lock); - /* - * Remove the current set, update the hash and add - * them back. - */ - ftrace_hash_rec_disable(iter->ops, filter_hash); - ret = ftrace_hash_move(orig_hash, iter->hash); - if (!ret) { - ftrace_hash_rec_enable(iter->ops, filter_hash); - if (iter->ops->flags & FTRACE_OPS_FL_ENABLED - && ftrace_enabled) - ftrace_run_update_code(FTRACE_ENABLE_CALLS); - } + ret = ftrace_hash_move(iter->ops, filter_hash, + orig_hash, iter->hash); + if (!ret && (iter->ops->flags & FTRACE_OPS_FL_ENABLED) + && ftrace_enabled) + ftrace_run_update_code(FTRACE_ENABLE_CALLS); + mutex_unlock(&ftrace_lock); } free_ftrace_hash(iter->hash); From 2ffe3ccf80eba0ac9ca71c41e7357d92f1c08fc3 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 13 Jul 2011 15:08:31 -0400 Subject: [PATCH 0775/4025] ftrace: Update filter when tracing enabled in set_ftrace_filter() commit 072126f4529196f71a97960248bca54fd4554c2d upstream. Currently, if set_ftrace_filter() is called when the ftrace_ops is active, the function filters will not be updated. They will only be updated when tracing is disabled and re-enabled. Update the functions immediately during set_ftrace_filter(). Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- kernel/trace/ftrace.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 1eef6cf38d5..6b1e596bd3a 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2901,6 +2901,10 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, mutex_lock(&ftrace_lock); ret = ftrace_hash_move(ops, enable, orig_hash, hash); + if (!ret && ops->flags & FTRACE_OPS_FL_ENABLED + && ftrace_enabled) + ftrace_run_update_code(FTRACE_ENABLE_CALLS); + mutex_unlock(&ftrace_lock); mutex_unlock(&ftrace_regex_lock); From da8ae089a79cdc37589cab581a2ca9cf48f98904 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 5 Dec 2011 18:22:48 +0100 Subject: [PATCH 0776/4025] ftrace: Fix unregister ftrace_ops accounting commit 30fb6aa74011dcf595f306ca2727254d708b786e upstream. Multiple users of the function tracer can register their functions with the ftrace_ops structure. The accounting within ftrace will update the counter on each function record that is being traced. When the ftrace_ops filtering adds or removes functions, the function records will be updated accordingly if the ftrace_ops is still registered. When a ftrace_ops is removed, the counter of the function records, that the ftrace_ops traces, are decremented. When they reach zero the functions that they represent are modified to stop calling the mcount code. When changes are made, the code is updated via stop_machine() with a command passed to the function to tell it what to do. There is an ENABLE and DISABLE command that tells the called function to enable or disable the functions. But the ENABLE is really a misnomer as it should just update the records, as records that have been enabled and now have a count of zero should be disabled. The DISABLE command is used to disable all functions regardless of their counter values. This is the big off switch and is not the complement of the ENABLE command. To make matters worse, when a ftrace_ops is unregistered and there is another ftrace_ops registered, neither the DISABLE nor the ENABLE command are set when calling into the stop_machine() function and the records will not be updated to match their counter. A command is passed to that function that will update the mcount code to call the registered callback directly if it is the only one left. This means that the ftrace_ops that is still registered will have its callback called by all functions that have been set for it as well as the ftrace_ops that was just unregistered. Here's a way to trigger this bug. Compile the kernel with CONFIG_FUNCTION_PROFILER set and with CONFIG_FUNCTION_GRAPH not set: CONFIG_FUNCTION_PROFILER=y # CONFIG_FUNCTION_GRAPH is not set This will force the function profiler to use the function tracer instead of the function graph tracer. # cd /sys/kernel/debug/tracing # echo schedule > set_ftrace_filter # echo function > current_tracer # cat set_ftrace_filter schedule # cat trace # tracer: nop # # entries-in-buffer/entries-written: 692/68108025 #P:4 # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / delay # TASK-PID CPU# |||| TIMESTAMP FUNCTION # | | | |||| | | kworker/0:2-909 [000] .... 531.235574: schedule <-worker_thread -0 [001] .N.. 531.235575: schedule <-cpu_idle kworker/0:2-909 [000] .... 531.235597: schedule <-worker_thread sshd-2563 [001] .... 531.235647: schedule <-schedule_hrtimeout_range_clock # echo 1 > function_profile_enabled # echo 0 > function_porfile_enabled # cat set_ftrace_filter schedule # cat trace # tracer: function # # entries-in-buffer/entries-written: 159701/118821262 #P:4 # # _-----=> irqs-off # / _----=> need-resched # | / _---=> hardirq/softirq # || / _--=> preempt-depth # ||| / delay # TASK-PID CPU# |||| TIMESTAMP FUNCTION # | | | |||| | | -0 [002] ...1 604.870655: local_touch_nmi <-cpu_idle -0 [002] d..1 604.870655: enter_idle <-cpu_idle -0 [002] d..1 604.870656: atomic_notifier_call_chain <-enter_idle -0 [002] d..1 604.870656: __atomic_notifier_call_chain <-atomic_notifier_call_chain The same problem could have happened with the trace_probe_ops, but they are modified with the set_frace_filter file which does the update at closure of the file. The simple solution is to change ENABLE to UPDATE and call it every time an ftrace_ops is unregistered. Link: http://lkml.kernel.org/r/1323105776-26961-3-git-send-email-jolsa@redhat.com Signed-off-by: Jiri Olsa Signed-off-by: Steven Rostedt Signed-off-by: Greg Kroah-Hartman --- kernel/trace/ftrace.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 6b1e596bd3a..9f8e2e11020 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -952,7 +952,7 @@ struct ftrace_func_probe { }; enum { - FTRACE_ENABLE_CALLS = (1 << 0), + FTRACE_UPDATE_CALLS = (1 << 0), FTRACE_DISABLE_CALLS = (1 << 1), FTRACE_UPDATE_TRACE_FUNC = (1 << 2), FTRACE_START_FUNC_RET = (1 << 3), @@ -1521,7 +1521,7 @@ int ftrace_text_reserved(void *start, void *end) static int -__ftrace_replace_code(struct dyn_ftrace *rec, int enable) +__ftrace_replace_code(struct dyn_ftrace *rec, int update) { unsigned long ftrace_addr; unsigned long flag = 0UL; @@ -1529,17 +1529,17 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable) ftrace_addr = (unsigned long)FTRACE_ADDR; /* - * If we are enabling tracing: + * If we are updating calls: * * If the record has a ref count, then we need to enable it * because someone is using it. * * Otherwise we make sure its disabled. * - * If we are disabling tracing, then disable all records that + * If we are disabling calls, then disable all records that * are enabled. */ - if (enable && (rec->flags & ~FTRACE_FL_MASK)) + if (update && (rec->flags & ~FTRACE_FL_MASK)) flag = FTRACE_FL_ENABLED; /* If the state of this record hasn't changed, then do nothing */ @@ -1555,7 +1555,7 @@ __ftrace_replace_code(struct dyn_ftrace *rec, int enable) return ftrace_make_nop(NULL, rec, ftrace_addr); } -static void ftrace_replace_code(int enable) +static void ftrace_replace_code(int update) { struct dyn_ftrace *rec; struct ftrace_page *pg; @@ -1569,7 +1569,7 @@ static void ftrace_replace_code(int enable) if (rec->flags & FTRACE_FL_FREE) continue; - failed = __ftrace_replace_code(rec, enable); + failed = __ftrace_replace_code(rec, update); if (failed) { ftrace_bug(failed, rec->ip); /* Stop processing */ @@ -1619,7 +1619,7 @@ static int __ftrace_modify_code(void *data) { int *command = data; - if (*command & FTRACE_ENABLE_CALLS) + if (*command & FTRACE_UPDATE_CALLS) ftrace_replace_code(1); else if (*command & FTRACE_DISABLE_CALLS) ftrace_replace_code(0); @@ -1675,7 +1675,7 @@ static int ftrace_startup(struct ftrace_ops *ops, int command) return -ENODEV; ftrace_start_up++; - command |= FTRACE_ENABLE_CALLS; + command |= FTRACE_UPDATE_CALLS; /* ops marked global share the filter hashes */ if (ops->flags & FTRACE_OPS_FL_GLOBAL) { @@ -1727,8 +1727,7 @@ static void ftrace_shutdown(struct ftrace_ops *ops, int command) if (ops != &global_ops || !global_start_up) ops->flags &= ~FTRACE_OPS_FL_ENABLED; - if (!ftrace_start_up) - command |= FTRACE_DISABLE_CALLS; + command |= FTRACE_UPDATE_CALLS; if (saved_ftrace_func != ftrace_trace_function) { saved_ftrace_func = ftrace_trace_function; @@ -1750,7 +1749,7 @@ static void ftrace_startup_sysctl(void) saved_ftrace_func = NULL; /* ftrace_start_up is true if we want ftrace running */ if (ftrace_start_up) - ftrace_run_update_code(FTRACE_ENABLE_CALLS); + ftrace_run_update_code(FTRACE_UPDATE_CALLS); } static void ftrace_shutdown_sysctl(void) @@ -2903,7 +2902,7 @@ ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len, ret = ftrace_hash_move(ops, enable, orig_hash, hash); if (!ret && ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled) - ftrace_run_update_code(FTRACE_ENABLE_CALLS); + ftrace_run_update_code(FTRACE_UPDATE_CALLS); mutex_unlock(&ftrace_lock); @@ -3091,7 +3090,7 @@ ftrace_regex_release(struct inode *inode, struct file *file) orig_hash, iter->hash); if (!ret && (iter->ops->flags & FTRACE_OPS_FL_ENABLED) && ftrace_enabled) - ftrace_run_update_code(FTRACE_ENABLE_CALLS); + ftrace_run_update_code(FTRACE_UPDATE_CALLS); mutex_unlock(&ftrace_lock); } From ffee9a18f29a0645c2d117083e025f557c738018 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Thu, 10 Nov 2011 09:01:27 +0000 Subject: [PATCH 0777/4025] ah: Don't return NET_XMIT_DROP on input. commit 4b90a603a1b21d63cf743cc833680cb195a729f6 upstream. When the ahash driver returns -EBUSY, AH4/6 input functions return NET_XMIT_DROP, presumably copied from the output code path. But returning transmit codes on input doesn't make a lot of sense. Since NET_XMIT_DROP is a positive int, this gets interpreted as the next header type (i.e., success). As that can only end badly, remove the check. Signed-off-by: Nick Bowler Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ah4.c | 2 -- net/ipv6/ah6.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index c7056b2e831..36d14406261 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -369,8 +369,6 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) if (err == -EINPROGRESS) goto out; - if (err == -EBUSY) - err = NET_XMIT_DROP; goto out_free; } diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 7a33aaa0022..4c0f894d084 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -581,8 +581,6 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) if (err == -EINPROGRESS) goto out; - if (err == -EBUSY) - err = NET_XMIT_DROP; goto out_free; } From 810b80a70cd24a682239d82370725cc3b847bab8 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Thu, 26 Jan 2012 13:47:42 -0600 Subject: [PATCH 0778/4025] xfs: fix endian conversion issue in discard code commit b1c770c273a4787069306fc82aab245e9ac72e9d upstream When finding the longest extent in an AG, we read the value directly out of the AGF buffer without endian conversion. This will give an incorrect length, resulting in FITRIM operations potentially not trimming everything that it should. Note, for 3.0-stable this has been modified to apply to fs/xfs/linux-2.6/xfs_discard.c instead of fs/xfs/xfs_discard.c. -bpm Signed-off-by: Dave Chinner Reviewed-by: Christoph Hellwig Signed-off-by: Ben Myers Signed-off-by: Greg Kroah-Hartman --- fs/xfs/linux-2.6/xfs_discard.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_discard.c b/fs/xfs/linux-2.6/xfs_discard.c index 244e797dae3..572494faf26 100644 --- a/fs/xfs/linux-2.6/xfs_discard.c +++ b/fs/xfs/linux-2.6/xfs_discard.c @@ -68,7 +68,7 @@ xfs_trim_extents( * Look up the longest btree in the AGF and start with it. */ error = xfs_alloc_lookup_le(cur, 0, - XFS_BUF_TO_AGF(agbp)->agf_longest, &i); + be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_longest), &i); if (error) goto out_del_cursor; @@ -84,7 +84,7 @@ xfs_trim_extents( if (error) goto out_del_cursor; XFS_WANT_CORRUPTED_GOTO(i == 1, out_del_cursor); - ASSERT(flen <= XFS_BUF_TO_AGF(agbp)->agf_longest); + ASSERT(flen <= be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_longest)); /* * Too small? Give up. From 8c6f009ebfcdae4196be7e456c99ad44eb013420 Mon Sep 17 00:00:00 2001 From: Russ Anderson Date: Wed, 18 Jan 2012 20:07:54 -0600 Subject: [PATCH 0779/4025] x86/uv: Fix uv_gpa_to_soc_phys_ram() shift commit 5a51467b146ab7948d2f6812892eac120a30529c upstream. uv_gpa_to_soc_phys_ram() was inadvertently ignoring the shift values. This fix takes the shift into account. Signed-off-by: Russ Anderson Link: http://lkml.kernel.org/r/20120119020753.GA7228@sgi.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/uv/uv_hub.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index 54a13aaebc4..21f7385badb 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h @@ -318,13 +318,13 @@ uv_gpa_in_mmr_space(unsigned long gpa) /* UV global physical address --> socket phys RAM */ static inline unsigned long uv_gpa_to_soc_phys_ram(unsigned long gpa) { - unsigned long paddr = gpa & uv_hub_info->gpa_mask; + unsigned long paddr; unsigned long remap_base = uv_hub_info->lowmem_remap_base; unsigned long remap_top = uv_hub_info->lowmem_remap_top; gpa = ((gpa << uv_hub_info->m_shift) >> uv_hub_info->m_shift) | ((gpa >> uv_hub_info->n_lshift) << uv_hub_info->m_val); - gpa = gpa & uv_hub_info->gpa_mask; + paddr = gpa & uv_hub_info->gpa_mask; if (paddr >= remap_base && paddr < remap_base + remap_top) paddr -= remap_base; return paddr; From 231f0496129d5d41ae77cc2410e3cea97540cd7b Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 20 Jan 2012 17:44:12 +0100 Subject: [PATCH 0780/4025] x86/microcode_amd: Add support for CPU family specific container files commit 5b68edc91cdc972c46f76f85eded7ffddc3ff5c2 upstream. We've decided to provide CPU family specific container files (starting with CPU family 15h). E.g. for family 15h we have to load microcode_amd_fam15h.bin instead of microcode_amd.bin Rationale is that starting with family 15h patch size is larger than 2KB which was hard coded as maximum patch size in various microcode loaders (not just Linux). Container files which include patches larger than 2KB cause different kinds of trouble with such old patch loaders. Thus we have to ensure that the default container file provides only patches with size less than 2KB. Signed-off-by: Andreas Herrmann Cc: Borislav Petkov Cc: Link: http://lkml.kernel.org/r/20120120164412.GD24508@alberich.amd.com [ documented the naming convention and tidied the code a bit. ] Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/microcode_amd.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/microcode_amd.c b/arch/x86/kernel/microcode_amd.c index c5610384ab1..b727450f5d7 100644 --- a/arch/x86/kernel/microcode_amd.c +++ b/arch/x86/kernel/microcode_amd.c @@ -298,13 +298,33 @@ generic_load_microcode(int cpu, const u8 *data, size_t size) return state; } +/* + * AMD microcode firmware naming convention, up to family 15h they are in + * the legacy file: + * + * amd-ucode/microcode_amd.bin + * + * This legacy file is always smaller than 2K in size. + * + * Starting at family 15h they are in family specific firmware files: + * + * amd-ucode/microcode_amd_fam15h.bin + * amd-ucode/microcode_amd_fam16h.bin + * ... + * + * These might be larger than 2K. + */ static enum ucode_state request_microcode_amd(int cpu, struct device *device) { - const char *fw_name = "amd-ucode/microcode_amd.bin"; + char fw_name[36] = "amd-ucode/microcode_amd.bin"; const struct firmware *fw; enum ucode_state ret = UCODE_NFOUND; + struct cpuinfo_x86 *c = &cpu_data(cpu); + + if (c->x86 >= 0x15) + snprintf(fw_name, sizeof(fw_name), "amd-ucode/microcode_amd_fam%.2xh.bin", c->x86); - if (request_firmware(&fw, fw_name, device)) { + if (request_firmware(&fw, (const char *)fw_name, device)) { pr_err("failed to load file %s\n", fw_name); goto out; } From 2fd55451aab99558e8b3ccefd88a1c14ed888c75 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 25 Jan 2012 09:55:46 +0100 Subject: [PATCH 0781/4025] ALSA: hda - Fix silent output on ASUS A6Rp commit 3b25eb690e8c7424eecffe1458c02b87b32aa001 upstream. The refactoring of Realtek codec driver in 3.2 kernel caused a regression for ASUS A6Rp laptop; it doesn't give any output. The reason was that this machine has a secret master mute (or EAPD) control via NID 0x0f VREF. Setting VREF50 on this node makes the sound working again. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=42588 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index eb0a141966a..e683017b943 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -16419,6 +16419,7 @@ static const struct alc_config_preset alc861_presets[] = { /* Pin config fixes */ enum { PINFIX_FSC_AMILO_PI1505, + PINFIX_ASUS_A6RP, }; static const struct alc_fixup alc861_fixups[] = { @@ -16430,9 +16431,18 @@ static const struct alc_fixup alc861_fixups[] = { { } } }, + [PINFIX_ASUS_A6RP] = { + .type = ALC_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* node 0x0f VREF seems controlling the master output */ + { 0x0f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, + { } + }, + }, }; static const struct snd_pci_quirk alc861_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", PINFIX_ASUS_A6RP), SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505), {} }; From 80f1aff93c34feff6ad229ff2a1307e82cb5b132 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Jan 2012 15:56:16 +0100 Subject: [PATCH 0782/4025] ALSA: hda - Fix silent output on Haier W18 laptop commit b3a81520bd37a28f77cb0f7002086fb14061824d upstream. The very same problem is seen on Haier W18 laptop with ALC861 as seen on ASUS A6Rp, which was fixed by the commit 3b25eb69. Now we just need to add a new SSID entry pointing to the same fixup. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=42656 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e683017b943..51412e1296f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -16443,6 +16443,7 @@ static const struct alc_fixup alc861_fixups[] = { static const struct snd_pci_quirk alc861_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", PINFIX_ASUS_A6RP), + SND_PCI_QUIRK(0x1584, 0x2b01, "Haier W18", PINFIX_ASUS_A6RP), SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505), {} }; From 7e2d7afcbacf7683c72e98980c6a9284a5a2a01c Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 6 Jan 2012 19:45:34 -0200 Subject: [PATCH 0783/4025] drm/i915/sdvo: always set positive sync polarity commit ba68e086223a5f149f37bf8692c8cdbf1b0ba3ef upstream. This is a revert of 81a14b46846fea0741902e8d8dfcc6c6c78154c8. We already set the mode polarity using the SDVO commands with struct intel_sdvo_dtd. We have at least 3 bugs that get fixed with this patch. The documentation, despite not clear, can also be interpreted in a way that suggests this patch is needed. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=15766 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=42174 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=43333 Reviewed-by: Eric Anholt Reviewed-by: Jesse Barnes Signed-off-by: Paulo Zanoni Signed-off-by: Keith Packard Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_sdvo.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 30fe554d893..bdda08e33c3 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1059,15 +1059,13 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, /* Set the SDVO control regs. */ if (INTEL_INFO(dev)->gen >= 4) { - sdvox = 0; + /* The real mode polarity is set by the SDVO commands, using + * struct intel_sdvo_dtd. */ + sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH; if (intel_sdvo->is_hdmi) sdvox |= intel_sdvo->color_range; if (INTEL_INFO(dev)->gen < 5) sdvox |= SDVO_BORDER_ENABLE; - if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) - sdvox |= SDVO_VSYNC_ACTIVE_HIGH; - if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) - sdvox |= SDVO_HSYNC_ACTIVE_HIGH; } else { sdvox = I915_READ(intel_sdvo->sdvo_reg); switch (intel_sdvo->sdvo_reg) { From e21ed1cebed09df11b4bf7809fd6d69b25457127 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Mon, 8 Aug 2011 06:22:43 +0200 Subject: [PATCH 0784/4025] cap_syslog: don't use WARN_ONCE for CAP_SYS_ADMIN deprecation warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f2c0d0266cc5eb36a4aa44944b4096ec121490aa upstream. syslog-ng versions before 3.3.0beta1 (2011-05-12) assume that CAP_SYS_ADMIN is sufficient to access syslog, so ever since CAP_SYSLOG was introduced (2010-11-25) they have triggered a warning. Commit ee24aebffb75 ("cap_syslog: accept CAP_SYS_ADMIN for now") improved matters a little by making syslog-ng work again, just keeping the WARN_ONCE(). But still, this is a warning that writes a stack trace we don't care about to syslog, sets a taint flag, and alarms sysadmins when nothing worse has happened than use of an old userspace with a recent kernel. Convert the WARN_ONCE to a printk_once to avoid that while continuing to give userspace developers a hint that this is an unwanted backward-compatibility feature and won't be around forever. Reported-by: Ralf Hildebrandt Reported-by: Niels Reported-by: Paweł Sikora Signed-off-by: Jonathan Nieder Liked-by: Gergely Nagy Acked-by: Serge Hallyn Acked-by: James Morris Signed-off-by: Linus Torvalds Cc: Christoph Biedl Signed-off-by: Greg Kroah-Hartman --- kernel/printk.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/printk.c b/kernel/printk.c index 084982f61de..3fc470872a6 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -318,8 +318,10 @@ static int check_syslog_permissions(int type, bool from_file) return 0; /* For historical reasons, accept CAP_SYS_ADMIN too, with a warning */ if (capable(CAP_SYS_ADMIN)) { - WARN_ONCE(1, "Attempt to access syslog with CAP_SYS_ADMIN " - "but no CAP_SYSLOG (deprecated).\n"); + printk_once(KERN_WARNING "%s (%d): " + "Attempt to access syslog with CAP_SYS_ADMIN " + "but no CAP_SYSLOG (deprecated).\n", + current->comm, task_pid_nr(current)); return 0; } return -EPERM; From 4e29fa93520b401b81a719fe053f06c6937d5b66 Mon Sep 17 00:00:00 2001 From: Srinidhi KASAGAR Date: Thu, 12 Jan 2012 11:07:43 +0530 Subject: [PATCH 0785/4025] mach-ux500: enable ARM errata 764369 commit d65015f7c5c5be9fd3f5e567889c844ba81bdc9c upstream. This applies ARM errata 764369 for all ux500 platforms. Signed-off-by: Srinidhi Kasagar Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-ux500/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig index 9a9706cf149..6ebdb0d0382 100644 --- a/arch/arm/mach-ux500/Kconfig +++ b/arch/arm/mach-ux500/Kconfig @@ -7,6 +7,7 @@ config UX500_SOC_COMMON select HAS_MTU select ARM_ERRATA_753970 select ARM_ERRATA_754322 + select ARM_ERRATA_764369 menu "Ux500 SoC" From 95086de856ca703588967f63cc54b8059db55888 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 20 Jan 2012 12:10:18 +0100 Subject: [PATCH 0786/4025] ARM: 7296/1: proc-v7.S: remove HARVARD_CACHE preprocessor guards commit 612539e81f655f6ac73c7af1da8701c1ee618aee upstream. On v7, we use the same cache maintenance instructions for data lines as for unified lines. This was not the case for v6, where HARVARD_CACHE was defined to indicate the L1 cache topology. This patch removes the erroneous compile-time check for HARVARD_CACHE in proc-v7.S, ensuring that we perform I-side invalidation at boot. Reported-and-Acked-by: Shawn Guo Acked-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/mm/proc-v7.S | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 089c0b5e454..b6ba1032a98 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -270,10 +270,6 @@ cpu_resume_l1_flags: * Initialise TLB, Caches, and MMU state ready to switch the MMU * on. Return in r0 the new CP15 C1 control register setting. * - * We automatically detect if we have a Harvard cache, and use the - * Harvard cache control instructions insead of the unified cache - * control instructions. - * * This should be able to cover all ARMv7 cores. * * It is assumed that: @@ -363,9 +359,7 @@ __v7_setup: #endif 3: mov r10, #0 -#ifdef HARVARD_CACHE mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate -#endif dsb #ifdef CONFIG_MMU mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs From 163071a2a0d661eb3b8abe14d892a88e6dedc77f Mon Sep 17 00:00:00 2001 From: Kentaro Matsuyama Date: Thu, 12 Jan 2012 23:07:51 +0900 Subject: [PATCH 0787/4025] USB: option: Add LG docomo L-02C commit e423d7401fd0717cb56a6cf51dd8341cc3e800d2 upstream. Add vendor and product ID for USB 3G/LTE modem of docomo L-02C Signed-off-by: Kentaro Matsuyama Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index c96b6b6509f..2a9ed6ec8cb 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -480,6 +480,10 @@ static void option_instat_callback(struct urb *urb); #define ZD_VENDOR_ID 0x0685 #define ZD_PRODUCT_7000 0x7000 +/* LG products */ +#define LG_VENDOR_ID 0x1004 +#define LG_PRODUCT_L02C 0x618f + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -1183,6 +1187,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) }, { USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZD_VENDOR_ID, ZD_PRODUCT_7000, 0xff, 0xff, 0xff) }, + { USB_DEVICE(LG_VENDOR_ID, LG_PRODUCT_L02C) }, /* docomo L-02C modem */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); From 38a464d3f7a94a7bd3cac9d8cd18474385e27633 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 10 Jan 2012 23:33:37 +0100 Subject: [PATCH 0788/4025] USB: ftdi_sio: fix TIOCSSERIAL baud_base handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit eb833a9e0972f60beb4ab8104ad7ef6bf30f02fc upstream. Return EINVAL if new baud_base does not match the current one. The baud_base is device specific and can not be changed. This restores the old (pre-2005) behaviour which was changed due to a misunderstanding regarding this fact (see https://lkml.org/lkml/2005/1/20/84). Reported-by: Torbjörn Lofterud Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index b02fd5027cc..0e4b6a93493 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1326,8 +1326,7 @@ static int set_serial_info(struct tty_struct *tty, goto check_and_exit; } - if ((new_serial.baud_base != priv->baud_base) && - (new_serial.baud_base < 9600)) { + if (new_serial.baud_base != priv->baud_base) { mutex_unlock(&priv->cfg_lock); return -EINVAL; } From b89a3229080c1464ab892cc413cc806b06d4ffa3 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 18 Jan 2012 01:46:00 +0100 Subject: [PATCH 0789/4025] USB: ftdi_sio: fix initial baud rate commit 108e02b12921078a59dcacd048079ece48a4a983 upstream. Fix regression introduced by commit b1ffb4c851f1 ("USB: Fix Corruption issue in USB ftdi driver ftdi_sio.c") which caused the termios settings to no longer be initialised at open. Consequently it was no longer possible to set the port to the default speed of 9600 baud without first changing to another baud rate and back again. Reported-by: Roland Ramthun Signed-off-by: Johan Hovold Tested-by: Roland Ramthun Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 0e4b6a93493..506971f49b3 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1815,6 +1815,7 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port) static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) { + struct ktermios dummy; struct usb_device *dev = port->serial->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); int result; @@ -1833,8 +1834,10 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) This is same behaviour as serial.c/rs_open() - Kuba */ /* ftdi_set_termios will send usb control messages */ - if (tty) - ftdi_set_termios(tty, port, tty->termios); + if (tty) { + memset(&dummy, 0, sizeof(dummy)); + ftdi_set_termios(tty, port, &dummy); + } /* Start reading from the device */ result = usb_serial_generic_open(tty, port); From ab9ef74e2580b4909bd9fb0c381027f54cb6d3de Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Wed, 18 Jan 2012 23:43:45 +0100 Subject: [PATCH 0790/4025] USB: ftdi_sio: add PID for TI XDS100v2 / BeagleBone A3 commit 55f13aeae0346f0c89bfface91ad9a97653dc433 upstream. Port A for JTAG, port B for serial. Signed-off-by: Peter Korsgaard Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 2 ++ drivers/usb/serial/ftdi_sio_ids.h | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 506971f49b3..a0a95311fc5 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -804,6 +804,8 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(FTDI_VID, TI_XDS100V2_PID), + .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) }, { USB_DEVICE(FTDI_VID, HAMEG_HO720_PID) }, { USB_DEVICE(FTDI_VID, HAMEG_HO730_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 055b64ef0bb..b67bee20345 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -39,6 +39,13 @@ /* www.candapter.com Ewert Energy Systems CANdapter device */ #define FTDI_CANDAPTER_PID 0x9F80 /* Product Id */ +/* + * Texas Instruments XDS100v2 JTAG / BeagleBone A3 + * http://processors.wiki.ti.com/index.php/XDS100 + * http://beagleboard.org/bone + */ +#define TI_XDS100V2_PID 0xa6d0 + #define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */ /* US Interface Navigator (http://www.usinterface.com/) */ From f43828eb93fe27108df3e81090bcf0cdbfe882e3 Mon Sep 17 00:00:00 2001 From: Peter Naulls Date: Tue, 17 Jan 2012 18:27:09 -0800 Subject: [PATCH 0791/4025] USB: serial: ftdi additional IDs commit fc216ec363f4d174932df90bbf35c77d0540e561 upstream. I tested this against 2.6.39 in the Ubuntu kernel, however I see the IDs are not in latest 3.2 git. This adds IDs for the FTDI controller in the Rainforest Automation Zigbee dongle. Signed-off-by: Peter Naulls Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index a0a95311fc5..6942551feda 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -842,6 +842,7 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(ST_VID, ST_STMCLT1030_PID), .driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk }, + { USB_DEVICE(FTDI_VID, FTDI_RF_R106) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index b67bee20345..79c596771cd 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1175,3 +1175,9 @@ */ /* TagTracer MIFARE*/ #define FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID 0xF7C0 + +/* + * Rainforest Automation + */ +/* ZigBee controller */ +#define FTDI_RF_R106 0x8A28 From 3b09a4eb286bdc9dbc4c9620faa562c8470b2366 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 26 Jan 2012 17:41:34 +0000 Subject: [PATCH 0792/4025] USB: ftdi_sio: Add more identifiers commit 2353f806c97020d4c7709f15eebb49b591f7306d upstream. 0x04d8, 0x000a: Hornby Elite Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 6942551feda..a872cc2c93a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -796,6 +796,7 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, + { USB_DEVICE(HORNBY_VID, HORNBY_ELITE_PID) }, { USB_DEVICE(JETI_VID, JETI_SPC1201_PID) }, { USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 79c596771cd..76d4f31b38c 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -531,6 +531,12 @@ #define ADI_GNICE_PID 0xF000 #define ADI_GNICEPLUS_PID 0xF001 +/* + * Hornby Elite + */ +#define HORNBY_VID 0x04D8 +#define HORNBY_ELITE_PID 0x000A + /* * RATOC REX-USB60F */ From 906e114c35cd8f98be1f672a2f32c0cf9800296b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Mon, 16 Jan 2012 12:41:47 +0100 Subject: [PATCH 0793/4025] USB: cdc-wdm: updating desc->length must be protected by spin_lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c428b70c1e115c5649707a602742e34130d19428 upstream. wdm_in_callback() will also touch this field, so we cannot change it without locking Signed-off-by: Bjørn Mork Acked-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 2b9ff518b50..bac7478f517 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -467,7 +467,9 @@ static ssize_t wdm_read for (i = 0; i < desc->length - cntr; i++) desc->ubuf[i] = desc->ubuf[i + cntr]; + spin_lock_irq(&desc->iuspin); desc->length -= cntr; + spin_unlock_irq(&desc->iuspin); /* in case we had outstanding data */ if (!desc->length) clear_bit(WDM_READ, &desc->flags); From c40c07af28b365175593f69a7391a3b6cfd8ac12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Mon, 16 Jan 2012 12:41:48 +0100 Subject: [PATCH 0794/4025] USB: cdc-wdm: use two mutexes to allow simultaneous read and write MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit e8537bd2c4f325a4796da33564ddcef9489b7feb upstream. using a separate read and write mutex for locking is sufficient to make the driver accept simultaneous read and write. This improves useability a lot. Signed-off-by: Bjørn Mork Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 49 +++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index bac7478f517..bdfa96d6005 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -88,7 +88,8 @@ struct wdm_device { int count; dma_addr_t shandle; dma_addr_t ihandle; - struct mutex lock; + struct mutex wlock; + struct mutex rlock; wait_queue_head_t wait; struct work_struct rxwork; int werr; @@ -323,7 +324,7 @@ static ssize_t wdm_write } /* concurrent writes and disconnect */ - r = mutex_lock_interruptible(&desc->lock); + r = mutex_lock_interruptible(&desc->wlock); rv = -ERESTARTSYS; if (r) { kfree(buf); @@ -386,7 +387,7 @@ static ssize_t wdm_write out: usb_autopm_put_interface(desc->intf); outnp: - mutex_unlock(&desc->lock); + mutex_unlock(&desc->wlock); outnl: return rv < 0 ? rv : count; } @@ -399,7 +400,7 @@ static ssize_t wdm_read struct wdm_device *desc = file->private_data; - rv = mutex_lock_interruptible(&desc->lock); /*concurrent reads */ + rv = mutex_lock_interruptible(&desc->rlock); /*concurrent reads */ if (rv < 0) return -ERESTARTSYS; @@ -476,7 +477,7 @@ static ssize_t wdm_read rv = cntr; err: - mutex_unlock(&desc->lock); + mutex_unlock(&desc->rlock); return rv; } @@ -542,7 +543,8 @@ static int wdm_open(struct inode *inode, struct file *file) } intf->needs_remote_wakeup = 1; - mutex_lock(&desc->lock); + /* using write lock to protect desc->count */ + mutex_lock(&desc->wlock); if (!desc->count++) { desc->werr = 0; desc->rerr = 0; @@ -555,7 +557,7 @@ static int wdm_open(struct inode *inode, struct file *file) } else { rv = 0; } - mutex_unlock(&desc->lock); + mutex_unlock(&desc->wlock); usb_autopm_put_interface(desc->intf); out: mutex_unlock(&wdm_mutex); @@ -567,9 +569,11 @@ static int wdm_release(struct inode *inode, struct file *file) struct wdm_device *desc = file->private_data; mutex_lock(&wdm_mutex); - mutex_lock(&desc->lock); + + /* using write lock to protect desc->count */ + mutex_lock(&desc->wlock); desc->count--; - mutex_unlock(&desc->lock); + mutex_unlock(&desc->wlock); if (!desc->count) { dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); @@ -667,7 +671,8 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL); if (!desc) goto out; - mutex_init(&desc->lock); + mutex_init(&desc->rlock); + mutex_init(&desc->wlock); spin_lock_init(&desc->iuspin); init_waitqueue_head(&desc->wait); desc->wMaxCommand = maxcom; @@ -781,10 +786,12 @@ static void wdm_disconnect(struct usb_interface *intf) /* to terminate pending flushes */ clear_bit(WDM_IN_USE, &desc->flags); spin_unlock_irqrestore(&desc->iuspin, flags); - mutex_lock(&desc->lock); + mutex_lock(&desc->rlock); + mutex_lock(&desc->wlock); kill_urbs(desc); cancel_work_sync(&desc->rxwork); - mutex_unlock(&desc->lock); + mutex_unlock(&desc->wlock); + mutex_unlock(&desc->rlock); wake_up_all(&desc->wait); if (!desc->count) cleanup(desc); @@ -800,8 +807,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor); /* if this is an autosuspend the caller does the locking */ - if (!(message.event & PM_EVENT_AUTO)) - mutex_lock(&desc->lock); + if (!(message.event & PM_EVENT_AUTO)) { + mutex_lock(&desc->rlock); + mutex_lock(&desc->wlock); + } spin_lock_irq(&desc->iuspin); if ((message.event & PM_EVENT_AUTO) && @@ -817,8 +826,10 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message) kill_urbs(desc); cancel_work_sync(&desc->rxwork); } - if (!(message.event & PM_EVENT_AUTO)) - mutex_unlock(&desc->lock); + if (!(message.event & PM_EVENT_AUTO)) { + mutex_unlock(&desc->wlock); + mutex_unlock(&desc->rlock); + } return rv; } @@ -856,7 +867,8 @@ static int wdm_pre_reset(struct usb_interface *intf) { struct wdm_device *desc = usb_get_intfdata(intf); - mutex_lock(&desc->lock); + mutex_lock(&desc->rlock); + mutex_lock(&desc->wlock); kill_urbs(desc); /* @@ -878,7 +890,8 @@ static int wdm_post_reset(struct usb_interface *intf) int rv; rv = recover_from_urb_loss(desc); - mutex_unlock(&desc->lock); + mutex_unlock(&desc->wlock); + mutex_unlock(&desc->rlock); return 0; } From 06434d3275a9d6ae3ca39f114523f015e003d8ea Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 24 Jan 2012 17:16:54 -0600 Subject: [PATCH 0795/4025] qcaux: add more Pantech UML190 and UML290 ports commit 074cc73506f529f39fef32ad1c9e1d4cdd8acf6c upstream. More ports we now know how to talk to. Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/qcaux.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c index 30b73e68a90..a34819884c1 100644 --- a/drivers/usb/serial/qcaux.c +++ b/drivers/usb/serial/qcaux.c @@ -36,6 +36,7 @@ #define UTSTARCOM_PRODUCT_UM175_V1 0x3712 #define UTSTARCOM_PRODUCT_UM175_V2 0x3714 #define UTSTARCOM_PRODUCT_UM175_ALLTEL 0x3715 +#define PANTECH_PRODUCT_UML190_VZW 0x3716 #define PANTECH_PRODUCT_UML290_VZW 0x3718 /* CMOTECH devices */ @@ -67,7 +68,11 @@ static struct usb_device_id id_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(LG_VENDOR_ID, LG_PRODUCT_VX4400_6000, 0xff, 0xff, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(SANYO_VENDOR_ID, SANYO_PRODUCT_KATANA_LX, 0xff, 0xff, 0x00) }, { USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_U520, 0xff, 0x00, 0x00) }, - { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML190_VZW, 0xff, 0xfe, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfd, 0xff) }, /* NMEA */ + { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xfe, 0xff) }, /* WMC */ + { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, PANTECH_PRODUCT_UML290_VZW, 0xff, 0xff, 0xff) }, /* DIAG */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); From 74a6015d2ba393187bbfddcc910afb9e239a3e35 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 13 Jan 2012 21:32:06 -0800 Subject: [PATCH 0796/4025] usb: io_ti: Make edge_remove_sysfs_attrs the port_remove method. commit 6d443d8499e4e59ffb949759cdded32730f8d2f6 upstream. Calling edge_remove_sysfs_attrs from edge_disconnect is too late as the device has already been removed from sysfs. Do the simple and obvious thing and make edge_remove_sysfs_attrs the port_remove method. Signed-off-by: Eric W. Biederman Reported-by: Wolfgang Frisch Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/io_ti.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 0aac00afb5c..8a90d58ee96 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2677,15 +2677,7 @@ static int edge_startup(struct usb_serial *serial) static void edge_disconnect(struct usb_serial *serial) { - int i; - struct edgeport_port *edge_port; - dbg("%s", __func__); - - for (i = 0; i < serial->num_ports; ++i) { - edge_port = usb_get_serial_port_data(serial->port[i]); - edge_remove_sysfs_attrs(edge_port->port); - } } static void edge_release(struct usb_serial *serial) @@ -2764,6 +2756,7 @@ static struct usb_serial_driver edgeport_1port_device = { .disconnect = edge_disconnect, .release = edge_release, .port_probe = edge_create_sysfs_attrs, + .port_remove = edge_remove_sysfs_attrs, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, @@ -2795,6 +2788,7 @@ static struct usb_serial_driver edgeport_2port_device = { .disconnect = edge_disconnect, .release = edge_release, .port_probe = edge_create_sysfs_attrs, + .port_remove = edge_remove_sysfs_attrs, .ioctl = edge_ioctl, .set_termios = edge_set_termios, .tiocmget = edge_tiocmget, From 47f7a05bd076caf9bc2d60555a1282517c6eca31 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 12 Jan 2012 22:55:15 +0100 Subject: [PATCH 0797/4025] TTY: fix UV serial console regression commit 0eee50af5b13e00b3fb7a5fe8480419a71b8235d upstream. Commit 74c2107759d (serial: Use block_til_ready helper) and its fixup 3f582b8c110 (serial: fix termios settings in open) introduced a regression on UV systems. The serial eventually freezes while being used. It's completely unpredictable and sometimes needs a heap of traffic to happen first. To reproduce this, yast installation was used as it turned out to be pretty reliable in reproducing. Especially during installation process where one doesn't have an SSH daemon running. And no monitor as the HW is completely headless. So this was fun to find. Given the machine doesn't boot on vanilla before 2.6.36 final. (And the commits above are older.) Unless there is some bad race in the code, the hardware seems to be pretty broken. Otherwise pure MSR read should not cause such a bug, or? So to prevent the bug, revert to the old behavior. I.e. read modem status only if we really have to -- for non-CLOCAL set serials. Non-CLOCAL works on this hardware OK, I tried. See? I don't. And document that shit. Signed-off-by: Jiri Slaby References: https://lkml.org/lkml/2011/12/6/573 References: https://bugzilla.novell.com/show_bug.cgi?id=718518 Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_port.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 33d37d230f8..a4aaca0e014 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -227,7 +227,6 @@ int tty_port_block_til_ready(struct tty_port *port, int do_clocal = 0, retval; unsigned long flags; DEFINE_WAIT(wait); - int cd; /* block if port is in the process of being closed */ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { @@ -284,11 +283,14 @@ int tty_port_block_til_ready(struct tty_port *port, retval = -ERESTARTSYS; break; } - /* Probe the carrier. For devices with no carrier detect this - will always return true */ - cd = tty_port_carrier_raised(port); + /* + * Probe the carrier. For devices with no carrier detect + * tty_port_carrier_raised will always return true. + * Never ask drivers if CLOCAL is set, this causes troubles + * on some hardware. + */ if (!(port->flags & ASYNC_CLOSING) && - (do_clocal || cd)) + (do_clocal || tty_port_carrier_raised(port))) break; if (signal_pending(current)) { retval = -ERESTARTSYS; From f0661faa597be0c7fb7612e8968c2f508e168adf Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Tue, 17 Jan 2012 11:52:28 +0100 Subject: [PATCH 0798/4025] serial: amba-pl011: lock console writes against interrupts commit ef605fdb33883d687cff5ba75095a91b313b4966 upstream. Protect against pl011_console_write() and the interrupt for the console UART running concurrently on different CPUs. Otherwise the console_write could spin for a long time waiting for the UART to become not busy, while the other CPU continuously services UART interrupts and keeps the UART busy. The checks for sysrq and oops_in_progress are taken from 8250.c. Signed-off-by: Rabin Vincent Reviewed-by: Srinidhi Kasagar Reviewed-by: Bibek Basu Reviewed-by: Shreshtha Kumar Sahu Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index f5f6831b0a6..4a4733e601d 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1733,9 +1733,19 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) { struct uart_amba_port *uap = amba_ports[co->index]; unsigned int status, old_cr, new_cr; + unsigned long flags; + int locked = 1; clk_enable(uap->clk); + local_irq_save(flags); + if (uap->port.sysrq) + locked = 0; + else if (oops_in_progress) + locked = spin_trylock(&uap->port.lock); + else + spin_lock(&uap->port.lock); + /* * First save the CR then disable the interrupts */ @@ -1755,6 +1765,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) } while (status & UART01x_FR_BUSY); writew(old_cr, uap->port.membase + UART011_CR); + if (locked) + spin_unlock(&uap->port.lock); + local_irq_restore(flags); + clk_disable(uap->clk); } From d5f0416d678ccf6e903002637c3bd9ce82ddb30f Mon Sep 17 00:00:00 2001 From: Lucas Kannebley Tavares Date: Mon, 9 Jan 2012 10:58:06 -0200 Subject: [PATCH 0799/4025] jsm: Fixed EEH recovery error commit 26aa38cafae0dbef3b2fe75ea487c83313c36d45 upstream. There was an error on the jsm driver that would cause it to be unable to recover after a second error is detected. At the first error, the device recovers properly: [72521.485691] EEH: Detected PCI bus error on device 0003:02:00.0 [72521.485695] EEH: This PCI device has failed 1 times in the last hour: ... [72532.035693] ttyn3 at MMIO 0x0 (irq = 49) is a jsm [72532.105689] jsm: Port 3 added However, at the second error, it cascades until EEH disables the device: [72631.229549] Call Trace: ... [72641.725687] jsm: Port 3 added [72641.725695] EEH: Detected PCI bus error on device 0003:02:00.0 [72641.725698] EEH: This PCI device has failed 3 times in the last hour: It was caused because the PCI state was not being saved after the first restore. Therefore, at the second recovery the PCI state would not be restored. Signed-off-by: Lucas Kannebley Tavares Signed-off-by: Breno Leitao Acked-by: Thadeu Lima de Souza Cascardo Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/jsm/jsm_driver.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c index 2aaafa9c58a..6c12d94e6d3 100644 --- a/drivers/tty/serial/jsm/jsm_driver.c +++ b/drivers/tty/serial/jsm/jsm_driver.c @@ -269,6 +269,7 @@ static void jsm_io_resume(struct pci_dev *pdev) struct jsm_board *brd = pci_get_drvdata(pdev); pci_restore_state(pdev); + pci_save_state(pdev); jsm_uart_port_init(brd); } From 3fc6b6671559d947f3f9a6d8829d3481a17934f4 Mon Sep 17 00:00:00 2001 From: Ryan Mallon Date: Sat, 28 Jan 2012 08:51:40 +1100 Subject: [PATCH 0800/4025] vmwgfx: Fix assignment in vmw_framebuffer_create_handle commit bf9c05d5b6d19b3e4c9fe21047694e94f48db89b upstream. The assignment of handle in vmw_framebuffer_create_handle doesn't actually do anything useful and is incorrectly assigning an integer value to a pointer argument. It appears that this is a typo and should be dereferencing handle rather than assigning to it directly. This fixes a bug where an undefined handle value is potentially returned to user-space. Signed-off-by: Ryan Mallon Reviewed-by: Jakob Bornecrantz Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index dfe32e62bd9..8a38c91f4c9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -313,7 +313,7 @@ int vmw_framebuffer_create_handle(struct drm_framebuffer *fb, unsigned int *handle) { if (handle) - handle = 0; + *handle = 0; return 0; } From a607902f65e6d425f8d115ac891a3c89f3b36d33 Mon Sep 17 00:00:00 2001 From: Harrison Metzger Date: Sun, 15 Jan 2012 08:43:24 -0600 Subject: [PATCH 0801/4025] USB: usbsevseg: fix max length commit 1097ccebe630170080c41df0edcf88e0626e9c75 upstream. This changes the max length for the usb seven segment delcom device to 8 from 6. Delcom has both 6 and 8 variants and having 8 works fine with devices which are only 6. Signed-off-by: Harrison Metzger Signed-off-by: Stuart Pook Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/usbsevseg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c index 417b8f207e8..59689fa2f7c 100644 --- a/drivers/usb/misc/usbsevseg.c +++ b/drivers/usb/misc/usbsevseg.c @@ -24,7 +24,7 @@ #define VENDOR_ID 0x0fc5 #define PRODUCT_ID 0x1227 -#define MAXLEN 6 +#define MAXLEN 8 /* table of devices that work with this driver */ static const struct usb_device_id id_table[] = { From 6a1d0b0af0dcb47bab73e4aa95b4b6afaee4a75c Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 12 Jan 2012 10:55:13 +0100 Subject: [PATCH 0802/4025] drivers/usb/host/ehci-fsl.c: add missing iounmap commit 2492c6e6454ff3edb11e273b071a6ea80a199c71 upstream. Add missing iounmap in error handling code, in a case where the function already preforms iounmap on some other execution path. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression e; statement S,S1; int ret; @@ e = \(ioremap\|ioremap_nocache\)(...) ... when != iounmap(e) if (<+...e...+>) S ... when any when != iounmap(e) *if (...) { ... when != iounmap(e) return ...; } ... when any iounmap(e); // Signed-off-by: Julia Lawall Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-fsl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index f380bf97e5a..bc7f166395a 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -125,7 +125,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, */ if (pdata->init && pdata->init(pdev)) { retval = -ENODEV; - goto err3; + goto err4; } /* Enable USB controller, 83xx or 8536 */ From a5c55d20f4251bcc22ce82ff82add9839027e818 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 14 Nov 2011 17:51:39 -0800 Subject: [PATCH 0803/4025] xhci: Fix USB 3.0 device restart on resume. commit d0cd5d482b8a6dc92c6c69a5387baf72ea84f23a upstream. The xHCI hub port code gets passed a zero-based port number by the USB core. It then adds one to in order to find a device slot by port number and device speed by calling xhci_find_slot_id_by_port. That function clearly states it requires a one-based port number. The xHCI port status change event handler was using a zero-based port number that it got from find_faked_portnum_from_hw_portnum, not a one-based port number. This lead to the doorbells never being rung for a device after a resume, or worse, a different device with the same speed having its doorbell rung (which could lead to bad power management in the xHCI host controller). This patch should be backported to kernels as old as 2.6.39. Signed-off-by: Sarah Sharp Acked-by: Andiry Xu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index c0c5d6c7cb6..8784ab01041 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1218,6 +1218,7 @@ static void handle_vendor_event(struct xhci_hcd *xhci, * * Returns a zero-based port number, which is suitable for indexing into each of * the split roothubs' port arrays and bus state arrays. + * Add one to it in order to call xhci_find_slot_id_by_port. */ static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd, struct xhci_hcd *xhci, u32 port_id) @@ -1340,7 +1341,7 @@ static void handle_port_status(struct xhci_hcd *xhci, temp |= PORT_LINK_STROBE | XDEV_U0; xhci_writel(xhci, temp, port_array[faked_port_index]); slot_id = xhci_find_slot_id_by_port(hcd, xhci, - faked_port_index); + faked_port_index + 1); if (!slot_id) { xhci_dbg(xhci, "slot_id is zero\n"); goto cleanup; From dd5a1b14d8c2f6ca3692aa4d829aa4afb1319f0e Mon Sep 17 00:00:00 2001 From: Andiry Xu Date: Wed, 18 Jan 2012 17:47:12 +0800 Subject: [PATCH 0804/4025] xHCI: Cleanup isoc transfer ring when TD length mismatch found commit cf840551a884360841bd3d3ce1ad0868ff0b759a upstream. When a TD length mismatch is found during isoc TRB enqueue, it directly returns -EINVAL. However, isoc transfer is partially enqueued at this time, and the ring should be cleared. This should be backported to kernels as old as 2.6.36, which contain the commit 522989a27c7badb608155b1f1dea3487ed431f74 "xhci: Fix failed enqueue in the middle of isoch TD." Signed-off-by: Andiry Xu Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-ring.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 8784ab01041..edcedc4e978 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3382,7 +3382,8 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, /* Check TD length */ if (running_total != td_len) { xhci_err(xhci, "ISOC TD length unmatch\n"); - return -EINVAL; + ret = -EINVAL; + goto cleanup; } } From c39714f1da06b21e4d4250d030448099912ae79f Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 20 Jan 2012 10:09:23 -0500 Subject: [PATCH 0805/4025] hwmon: (f71805f) Fix clamping of temperature limits commit 86b2bbfdbd1fcc4a3aa62ccd3f245c40c5ad5b85 upstream. Properly clamp temperature limits set by the user. Without this fix, attempts to write temperature limits above the maximum supported by the chip (255 degrees Celsius) would arbitrarily and unexpectedly result in the limit being set to 0 degree Celsius. Signed-off-by: Jean Delvare Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/f71805f.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index 92f949767ec..6dbfd3e516e 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -283,11 +283,11 @@ static inline long temp_from_reg(u8 reg) static inline u8 temp_to_reg(long val) { - if (val < 0) - val = 0; - else if (val > 1000 * 0xff) - val = 0xff; - return ((val + 500) / 1000); + if (val <= 0) + return 0; + if (val >= 1000 * 0xff) + return 0xff; + return (val + 500) / 1000; } /* From 70c3e9e41475dd3d7dbd816130ff8c21e6e1f745 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 27 Jan 2012 17:56:06 -0800 Subject: [PATCH 0806/4025] hwmon: (w83627ehf) Disable setting DC mode for pwm2, pwm3 on NCT6776F commit ad77c3e1808f07fa70f707b1c92a683b7c7d3f85 upstream. NCT6776F only supports pwm mode for pwm2 and pwm3. Return error if an attempt is made to set those pwm channels to DC mode. Signed-off-by: Guenter Roeck Acked-by: Jean Delvare Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83627ehf.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 4b2fc50c84f..62845157245 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1295,6 +1295,7 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, { struct w83627ehf_data *data = dev_get_drvdata(dev); struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); + struct w83627ehf_sio_data *sio_data = dev->platform_data; int nr = sensor_attr->index; unsigned long val; int err; @@ -1306,6 +1307,11 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, if (val > 1) return -EINVAL; + + /* On NCT67766F, DC mode is only supported for pwm1 */ + if (sio_data->kind == nct6776 && nr && val != 1) + return -EINVAL; + mutex_lock(&data->update_lock); reg = w83627ehf_read_value(data, W83627EHF_REG_PWM_ENABLE[nr]); data->pwm_mode[nr] = val; From 0b4e97269313969faf20f4c341af10d734d6d00d Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Thu, 26 Jan 2012 15:59:00 -0500 Subject: [PATCH 0807/4025] hwmon: (sht15) fix bad error code commit 6edf3c30af01854c416f8654d3d5d2652470afd4 upstream. When no platform data was supplied, returned error code was 0. Signed-off-by: Vivien Didelot Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/sht15.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index cf4330b352e..9594cdb1cd0 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -883,7 +883,7 @@ static int sht15_invalidate_voltage(struct notifier_block *nb, static int __devinit sht15_probe(struct platform_device *pdev) { - int ret = 0; + int ret; struct sht15_data *data = kzalloc(sizeof(*data), GFP_KERNEL); u8 status = 0; @@ -901,6 +901,7 @@ static int __devinit sht15_probe(struct platform_device *pdev) init_waitqueue_head(&data->wait_queue); if (pdev->dev.platform_data == NULL) { + ret = -EINVAL; dev_err(&pdev->dev, "no platform data supplied\n"); goto err_free_data; } From f1abac982c49f35615f47ff1f94a8ca5ba962bd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Mon, 16 Jan 2012 15:11:57 +0100 Subject: [PATCH 0808/4025] USB: cdc-wdm: call wake_up_all to allow driver to shutdown on device removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 62aaf24dc125d7c55c93e313d15611f152b030c7 upstream. wdm_disconnect() waits for the mutex held by wdm_read() before calling wake_up_all(). This causes a deadlock, preventing device removal to complete. Do the wake_up_all() before we start waiting for the locks. Signed-off-by: Bjørn Mork Cc: Oliver Neukum Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index bdfa96d6005..ed4317365fa 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -786,13 +786,13 @@ static void wdm_disconnect(struct usb_interface *intf) /* to terminate pending flushes */ clear_bit(WDM_IN_USE, &desc->flags); spin_unlock_irqrestore(&desc->iuspin, flags); + wake_up_all(&desc->wait); mutex_lock(&desc->rlock); mutex_lock(&desc->wlock); kill_urbs(desc); cancel_work_sync(&desc->rxwork); mutex_unlock(&desc->wlock); mutex_unlock(&desc->rlock); - wake_up_all(&desc->wait); if (!desc->count) cleanup(desc); mutex_unlock(&wdm_mutex); From 5256ca41663c848ac24783a5161a97730a21696c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Mon, 16 Jan 2012 15:11:59 +0100 Subject: [PATCH 0809/4025] USB: cdc-wdm: better allocate a buffer that is at least as big as we tell the USB core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 655e247daf52b202a6c2d0f8a06dd2051e756ce4 upstream. As it turns out, there was a mismatch between the allocated inbuf size (desc->bMaxPacketSize0, typically something like 64) and the length we specified in the URB (desc->wMaxCommand, typically something like 2048) Signed-off-by: Bjørn Mork Cc: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index ed4317365fa..854615ca37a 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -723,7 +723,7 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) goto err; desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf), - desc->bMaxPacketSize0, + desc->wMaxCommand, GFP_KERNEL, &desc->response->transfer_dma); if (!desc->inbuf) From 4df9c291640da8992e146076f57a8e563c449e31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Fri, 20 Jan 2012 01:49:57 +0100 Subject: [PATCH 0810/4025] USB: cdc-wdm: Avoid hanging on interface with no USB_CDC_DMM_TYPE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 15699e6fafc3a90e5fdc2ef30555a04dee62286f upstream. The probe does not strictly require the USB_CDC_DMM_TYPE descriptor, which is a good thing as it makes the driver usable on non-conforming interfaces. A user could e.g. bind to it to a CDC ECM interface by using the new_id and bind sysfs files. But this would fail with a 0 buffer length due to the missing descriptor. Fix by defining a reasonable fallback size: The minimum device receive buffer size required by the CDC WMC standard, revision 1.1 Signed-off-by: Bjørn Mork Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-wdm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 854615ca37a..90581a85134 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -57,6 +57,8 @@ MODULE_DEVICE_TABLE (usb, wdm_ids); #define WDM_MAX 16 +/* CDC-WMC r1.1 requires wMaxCommand to be "at least 256 decimal (0x100)" */ +#define WDM_DEFAULT_BUFSIZE 256 static DEFINE_MUTEX(wdm_mutex); @@ -636,7 +638,7 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) struct usb_cdc_dmm_desc *dmhd; u8 *buffer = intf->altsetting->extra; int buflen = intf->altsetting->extralen; - u16 maxcom = 0; + u16 maxcom = WDM_DEFAULT_BUFSIZE; if (!buffer) goto out; From 561331eae0a03d0c4cf60f3cf485aa3e8aa5ab48 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 26 Jan 2012 00:41:38 +0000 Subject: [PATCH 0811/4025] netns: fix net_alloc_generic() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 073862ba5d249c20bd5c49fc6d904ff0e1f6a672 ] When a new net namespace is created, we should attach to it a "struct net_generic" with enough slots (even empty), or we can hit the following BUG_ON() : [ 200.752016] kernel BUG at include/net/netns/generic.h:40! ... [ 200.752016] [] ? get_cfcnfg+0x3a/0x180 [ 200.752016] [] ? lockdep_rtnl_is_held+0x10/0x20 [ 200.752016] [] caif_device_notify+0x2e/0x530 [ 200.752016] [] notifier_call_chain+0x67/0x110 [ 200.752016] [] raw_notifier_call_chain+0x11/0x20 [ 200.752016] [] call_netdevice_notifiers+0x32/0x60 [ 200.752016] [] register_netdevice+0x196/0x300 [ 200.752016] [] register_netdev+0x19/0x30 [ 200.752016] [] loopback_net_init+0x4a/0xa0 [ 200.752016] [] ops_init+0x42/0x180 [ 200.752016] [] setup_net+0x6b/0x100 [ 200.752016] [] copy_net_ns+0x86/0x110 [ 200.752016] [] create_new_namespaces+0xd9/0x190 net_alloc_generic() should take into account the maximum index into the ptr array, as a subsystem might use net_generic() anytime. This also reduces number of reallocations in net_assign_generic() Reported-by: Sasha Levin Tested-by: Sasha Levin Signed-off-by: Eric Dumazet Cc: Sjur Brændeland Cc: Eric W. Biederman Cc: Pavel Emelyanov Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/net_namespace.c | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index ea489db1bc2..0b0211d7fc3 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -29,6 +29,20 @@ EXPORT_SYMBOL(init_net); #define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ +static unsigned int max_gen_ptrs = INITIAL_NET_GEN_PTRS; + +static struct net_generic *net_alloc_generic(void) +{ + struct net_generic *ng; + size_t generic_size = offsetof(struct net_generic, ptr[max_gen_ptrs]); + + ng = kzalloc(generic_size, GFP_KERNEL); + if (ng) + ng->len = max_gen_ptrs; + + return ng; +} + static int net_assign_generic(struct net *net, int id, void *data) { struct net_generic *ng, *old_ng; @@ -42,8 +56,7 @@ static int net_assign_generic(struct net *net, int id, void *data) if (old_ng->len >= id) goto assign; - ng = kzalloc(sizeof(struct net_generic) + - id * sizeof(void *), GFP_KERNEL); + ng = net_alloc_generic(); if (ng == NULL) return -ENOMEM; @@ -58,7 +71,6 @@ static int net_assign_generic(struct net *net, int id, void *data) * the old copy for kfree after a grace period. */ - ng->len = id; memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*)); rcu_assign_pointer(net->gen, ng); @@ -159,18 +171,6 @@ static __net_init int setup_net(struct net *net) goto out; } -static struct net_generic *net_alloc_generic(void) -{ - struct net_generic *ng; - size_t generic_size = sizeof(struct net_generic) + - INITIAL_NET_GEN_PTRS * sizeof(void *); - - ng = kzalloc(generic_size, GFP_KERNEL); - if (ng) - ng->len = INITIAL_NET_GEN_PTRS; - - return ng; -} #ifdef CONFIG_NET_NS static struct kmem_cache *net_cachep; @@ -481,6 +481,7 @@ static int register_pernet_operations(struct list_head *list, } return error; } + max_gen_ptrs = max_t(unsigned int, max_gen_ptrs, *ops->id); } error = __register_pernet_operations(list, ops); if (error) { From cc1be3611bae365c2399f5208732ddd0969cf46d Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 26 Jan 2012 14:02:55 +0000 Subject: [PATCH 0812/4025] netns: Fail conspicously if someone uses net_generic at an inappropriate time. [ Upstream commit 5ee4433efe99b9f39f6eff5052a177bbcfe72cea ] By definition net_generic should never be called when it can return NULL. Fail conspicously with a BUG_ON to make it clear when people mess up that a NULL return should never happen. Recently there was a bug in the CAIF subsystem where it was registered with register_pernet_device instead of register_pernet_subsys. It was erroneously concluded that net_generic could validly return NULL and that net_assign_generic was buggy (when it was just inefficient). Hopefully this BUG_ON will prevent people to coming to similar erroneous conclusions in the futrue. Signed-off-by: Eric W. Biederman Tested-by: Sasha Levin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/netns/generic.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/net/netns/generic.h b/include/net/netns/generic.h index 3419bf5cd15..d55f4344333 100644 --- a/include/net/netns/generic.h +++ b/include/net/netns/generic.h @@ -41,6 +41,7 @@ static inline void *net_generic(const struct net *net, int id) ptr = ng->ptr[id - 1]; rcu_read_unlock(); + BUG_ON(!ptr); return ptr; } #endif From 62252cba2867cec7cc484ebb2d3ec705c41d9684 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 26 Jan 2012 14:04:53 +0000 Subject: [PATCH 0813/4025] net caif: Register properly as a pernet subsystem. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 8a8ee9aff6c3077dd9c2c7a77478e8ed362b96c6 ] caif is a subsystem and as such it needs to register with register_pernet_subsys instead of register_pernet_device. Among other problems using register_pernet_device was resulting in net_generic being called before the caif_net structure was allocated. Which has been causing net_generic to fail with either BUG_ON's or by return NULL pointers. A more ugly problem that could be caused is packets in flight why the subsystem is shutting down. To remove confusion also remove the cruft cause by inappropriately trying to fix this bug. With the aid of the previous patch I have tested this patch and confirmed that using register_pernet_subsys makes the failure go away as it should. Signed-off-by: Eric W. Biederman Acked-by: Sjur Brændeland Tested-by: Sasha Levin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/caif/caif_dev.c | 11 ++++------- net/caif/cfcnfg.c | 1 - 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/net/caif/caif_dev.c b/net/caif/caif_dev.c index dbdaa95b800..5ba4366a220 100644 --- a/net/caif/caif_dev.c +++ b/net/caif/caif_dev.c @@ -53,7 +53,6 @@ struct cfcnfg *get_cfcnfg(struct net *net) struct caif_net *caifn; BUG_ON(!net); caifn = net_generic(net, caif_net_id); - BUG_ON(!caifn); return caifn->cfg; } EXPORT_SYMBOL(get_cfcnfg); @@ -63,7 +62,6 @@ static struct caif_device_entry_list *caif_device_list(struct net *net) struct caif_net *caifn; BUG_ON(!net); caifn = net_generic(net, caif_net_id); - BUG_ON(!caifn); return &caifn->caifdevs; } @@ -92,7 +90,6 @@ static struct caif_device_entry *caif_device_alloc(struct net_device *dev) struct caif_device_entry *caifd; caifdevs = caif_device_list(dev_net(dev)); - BUG_ON(!caifdevs); caifd = kzalloc(sizeof(*caifd), GFP_ATOMIC); if (!caifd) @@ -108,7 +105,7 @@ static struct caif_device_entry *caif_get(struct net_device *dev) struct caif_device_entry_list *caifdevs = caif_device_list(dev_net(dev)); struct caif_device_entry *caifd; - BUG_ON(!caifdevs); + list_for_each_entry_rcu(caifd, &caifdevs->list, list) { if (caifd->netdev == dev) return caifd; @@ -349,7 +346,7 @@ static struct notifier_block caif_device_notifier = { static int caif_init_net(struct net *net) { struct caif_net *caifn = net_generic(net, caif_net_id); - BUG_ON(!caifn); + INIT_LIST_HEAD(&caifn->caifdevs.list); mutex_init(&caifn->caifdevs.lock); @@ -414,7 +411,7 @@ static int __init caif_device_init(void) { int result; - result = register_pernet_device(&caif_net_ops); + result = register_pernet_subsys(&caif_net_ops); if (result) return result; @@ -427,7 +424,7 @@ static int __init caif_device_init(void) static void __exit caif_device_exit(void) { - unregister_pernet_device(&caif_net_ops); + unregister_pernet_subsys(&caif_net_ops); unregister_netdevice_notifier(&caif_device_notifier); dev_remove_pack(&caif_packet_type); } diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c index 52fe33bee02..bca32d7c15c 100644 --- a/net/caif/cfcnfg.c +++ b/net/caif/cfcnfg.c @@ -313,7 +313,6 @@ int caif_connect_client(struct net *net, struct caif_connect_request *conn_req, int err; struct cfctrl_link_param param; struct cfcnfg *cfg = get_cfcnfg(net); - caif_assert(cfg != NULL); rcu_read_lock(); err = caif_connect_req_to_link_param(cfg, conn_req, ¶m); From 03024e3d2d6705443980f956abb56d4453319e95 Mon Sep 17 00:00:00 2001 From: Jiri Bohac Date: Wed, 18 Jan 2012 12:24:54 +0000 Subject: [PATCH 0814/4025] bonding: fix enslaving in alb mode when link down [ Upstream commit b924551bed09f61b64f21bffe241afc5526b091a ] bond_alb_init_slave() is called from bond_enslave() and sets the slave's MAC address. This is done differently for TLB and ALB modes. bond->alb_info.rlb_enabled is used to discriminate between the two modes but this flag may be uninitialized if the slave is being enslaved prior to calling bond_open() -> bond_alb_initialize() on the master. It turns out all the callers of alb_set_slave_mac_addr() pass bond->alb_info.rlb_enabled as the hw parameter. This patch cleans up the unnecessary parameter of alb_set_slave_mac_addr() and makes the function decide based on the bonding mode instead, which fixes the above problem. Reported-by: Narendra K Signed-off-by: Jiri Bohac Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_alb.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 2df9276720a..5e725e07d61 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -871,16 +871,12 @@ static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]) } } -/* hw is a boolean parameter that determines whether we should try and - * set the hw address of the device as well as the hw address of the - * net_device - */ -static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[], int hw) +static int alb_set_slave_mac_addr(struct slave *slave, u8 addr[]) { struct net_device *dev = slave->dev; struct sockaddr s_addr; - if (!hw) { + if (slave->bond->params.mode == BOND_MODE_TLB) { memcpy(dev->dev_addr, addr, dev->addr_len); return 0; } @@ -910,8 +906,8 @@ static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct u8 tmp_mac_addr[ETH_ALEN]; memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN); - alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr, bond->alb_info.rlb_enabled); - alb_set_slave_mac_addr(slave2, tmp_mac_addr, bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr); + alb_set_slave_mac_addr(slave2, tmp_mac_addr); } @@ -1058,8 +1054,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav /* Try setting slave mac to bond address and fall-through to code handling that situation below... */ - alb_set_slave_mac_addr(slave, bond->dev->dev_addr, - bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(slave, bond->dev->dev_addr); } /* The slave's address is equal to the address of the bond. @@ -1095,8 +1090,7 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav } if (free_mac_slave) { - alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr, - bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr); pr_warning("%s: Warning: the hw address of slave %s is in use by the bond; giving it the hw address of %s\n", bond->dev->name, slave->dev->name, @@ -1452,8 +1446,7 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave) { int res; - res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr, - bond->alb_info.rlb_enabled); + res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr); if (res) { return res; } @@ -1604,8 +1597,7 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave alb_swap_mac_addr(bond, swap_slave, new_slave); } else { /* set the new_slave to the bond mac address */ - alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr, - bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(new_slave, bond->dev->dev_addr); } if (swap_slave) { @@ -1665,8 +1657,7 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) alb_swap_mac_addr(bond, swap_slave, bond->curr_active_slave); alb_fasten_mac_swap(bond, swap_slave, bond->curr_active_slave); } else { - alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr, - bond->alb_info.rlb_enabled); + alb_set_slave_mac_addr(bond->curr_active_slave, bond_dev->dev_addr); read_lock(&bond->lock); alb_send_learning_packets(bond->curr_active_slave, bond_dev->dev_addr); From 1334533665277ccc5568c5104cd2358788a02e02 Mon Sep 17 00:00:00 2001 From: James Chapman Date: Wed, 25 Jan 2012 02:39:05 +0000 Subject: [PATCH 0815/4025] l2tp: l2tp_ip - fix possible oops on packet receive [ Upstream commit 68315801dbf3ab2001679fd2074c9dc5dcf87dfa ] When a packet is received on an L2TP IP socket (L2TPv3 IP link encapsulation), the l2tpip socket's backlog_rcv function calls xfrm4_policy_check(). This is not necessary, since it was called before the skb was added to the backlog. With CONFIG_NET_NS enabled, xfrm4_policy_check() will oops if skb->dev is null, so this trivial patch removes the call. This bug has always been present, but only when CONFIG_NET_NS is enabled does it cause problems. Most users are probably using UDP encapsulation for L2TP, hence the problem has only recently surfaced. EIP: 0060:[] EFLAGS: 00210246 CPU: 0 EIP is at l2tp_ip_recvmsg+0xd4/0x2a7 EAX: 00000001 EBX: d77b5180 ECX: 00000000 EDX: 00200246 ESI: 00000000 EDI: d63cbd30 EBP: d63cbd18 ESP: d63cbcf4 DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 Call Trace: [] sock_common_recvmsg+0x31/0x46 [] __sock_recvmsg_nosec+0x45/0x4d [] __sock_recvmsg+0x31/0x3b [] sock_recvmsg+0x96/0xab [] ? might_fault+0x47/0x81 [] ? might_fault+0x47/0x81 [] ? _copy_from_user+0x31/0x115 [] ? copy_from_user+0x8/0xa [] ? verify_iovec+0x3e/0x78 [] __sys_recvmsg+0x10a/0x1aa [] ? sock_recvmsg+0x0/0xab [] ? __lock_acquire+0xbdf/0xbee [] ? do_page_fault+0x193/0x375 [] ? fcheck_files+0x9b/0xca [] ? fget_light+0x2a/0x9c [] sys_recvmsg+0x2b/0x43 [] sys_socketcall+0x16d/0x1a5 [] ? trace_hardirqs_on_thunk+0xc/0x10 [] sysenter_do_call+0x12/0x38 Code: c6 05 8c ea a8 c1 01 e8 0c d4 d9 ff 85 f6 74 07 3e ff 86 80 00 00 00 b9 17 b6 2b c1 ba 01 00 00 00 b8 78 ed 48 c1 e8 23 f6 d9 ff 76 0c 68 28 e3 30 c1 68 2d 44 41 c1 e8 89 57 01 00 83 c4 0c Signed-off-by: James Chapman Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_ip.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/net/l2tp/l2tp_ip.c b/net/l2tp/l2tp_ip.c index b6466e71f5e..858ca23aa6d 100644 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@ -393,11 +393,6 @@ static int l2tp_ip_backlog_recv(struct sock *sk, struct sk_buff *skb) { int rc; - if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) - goto drop; - - nf_reset(skb); - /* Charge it to the socket, dropping if the queue is full. */ rc = sock_queue_rcv_skb(sk, skb); if (rc < 0) From d020b1d3d3379d183d0649cdc2f6de9131268419 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 18 Jan 2012 07:21:42 +0000 Subject: [PATCH 0816/4025] net: bpf_jit: fix divide by 0 generation [ Upstream commit d00a9dd21bdf7908b70866794c8313ee8a5abd5c ] Several problems fixed in this patch : 1) Target of the conditional jump in case a divide by 0 is performed by a bpf is wrong. 2) Must 'generate' the full function prologue/epilogue at pass=0, or else we can stop too early in pass=1 if the proglen doesnt change. (if the increase of prologue/epilogue equals decrease of all instructions length because some jumps are converted to near jumps) 3) Change the wrong length detection at the end of code generation to issue a more explicit message, no need for a full stack trace. Reported-by: Phil Oester Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- arch/x86/net/bpf_jit_comp.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 7b65f752c5f..7c1b765ecc5 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -151,17 +151,18 @@ void bpf_jit_compile(struct sk_filter *fp) cleanup_addr = proglen; /* epilogue address */ for (pass = 0; pass < 10; pass++) { + u8 seen_or_pass0 = (pass == 0) ? (SEEN_XREG | SEEN_DATAREF | SEEN_MEM) : seen; /* no prologue/epilogue for trivial filters (RET something) */ proglen = 0; prog = temp; - if (seen) { + if (seen_or_pass0) { EMIT4(0x55, 0x48, 0x89, 0xe5); /* push %rbp; mov %rsp,%rbp */ EMIT4(0x48, 0x83, 0xec, 96); /* subq $96,%rsp */ /* note : must save %rbx in case bpf_error is hit */ - if (seen & (SEEN_XREG | SEEN_DATAREF)) + if (seen_or_pass0 & (SEEN_XREG | SEEN_DATAREF)) EMIT4(0x48, 0x89, 0x5d, 0xf8); /* mov %rbx, -8(%rbp) */ - if (seen & SEEN_XREG) + if (seen_or_pass0 & SEEN_XREG) CLEAR_X(); /* make sure we dont leek kernel memory */ /* @@ -170,7 +171,7 @@ void bpf_jit_compile(struct sk_filter *fp) * r9 = skb->len - skb->data_len * r8 = skb->data */ - if (seen & SEEN_DATAREF) { + if (seen_or_pass0 & SEEN_DATAREF) { if (offsetof(struct sk_buff, len) <= 127) /* mov off8(%rdi),%r9d */ EMIT4(0x44, 0x8b, 0x4f, offsetof(struct sk_buff, len)); @@ -260,9 +261,14 @@ void bpf_jit_compile(struct sk_filter *fp) case BPF_S_ALU_DIV_X: /* A /= X; */ seen |= SEEN_XREG; EMIT2(0x85, 0xdb); /* test %ebx,%ebx */ - if (pc_ret0 != -1) - EMIT_COND_JMP(X86_JE, addrs[pc_ret0] - (addrs[i] - 4)); - else { + if (pc_ret0 > 0) { + /* addrs[pc_ret0 - 1] is start address of target + * (addrs[i] - 4) is the address following this jmp + * ("xor %edx,%edx; div %ebx" being 4 bytes long) + */ + EMIT_COND_JMP(X86_JE, addrs[pc_ret0 - 1] - + (addrs[i] - 4)); + } else { EMIT_COND_JMP(X86_JNE, 2 + 5); CLEAR_A(); EMIT1_off32(0xe9, cleanup_addr - (addrs[i] - 4)); /* jmp .+off32 */ @@ -335,12 +341,12 @@ void bpf_jit_compile(struct sk_filter *fp) } /* fallinto */ case BPF_S_RET_A: - if (seen) { + if (seen_or_pass0) { if (i != flen - 1) { EMIT_JMP(cleanup_addr - addrs[i]); break; } - if (seen & SEEN_XREG) + if (seen_or_pass0 & SEEN_XREG) EMIT4(0x48, 0x8b, 0x5d, 0xf8); /* mov -8(%rbp),%rbx */ EMIT1(0xc9); /* leaveq */ } @@ -483,8 +489,9 @@ common_load: seen |= SEEN_DATAREF; goto common_load; case BPF_S_LDX_B_MSH: if ((int)K < 0) { - if (pc_ret0 != -1) { - EMIT_JMP(addrs[pc_ret0] - addrs[i]); + if (pc_ret0 > 0) { + /* addrs[pc_ret0 - 1] is the start address */ + EMIT_JMP(addrs[pc_ret0 - 1] - addrs[i]); break; } CLEAR_A(); @@ -599,13 +606,14 @@ cond_branch: f_offset = addrs[i + filter[i].jf] - addrs[i]; * use it to give the cleanup instruction(s) addr */ cleanup_addr = proglen - 1; /* ret */ - if (seen) + if (seen_or_pass0) cleanup_addr -= 1; /* leaveq */ - if (seen & SEEN_XREG) + if (seen_or_pass0 & SEEN_XREG) cleanup_addr -= 4; /* mov -8(%rbp),%rbx */ if (image) { - WARN_ON(proglen != oldproglen); + if (proglen != oldproglen) + pr_err("bpb_jit_compile proglen=%u != oldproglen=%u\n", proglen, oldproglen); break; } if (proglen == oldproglen) { From f217c4711d71aa6811b6e71d219b9efafa5d55a6 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 24 Jan 2012 17:03:44 -0500 Subject: [PATCH 0817/4025] rds: Make rds_sock_lock BH rather than IRQ safe. [ Upstream commit efc3dbc37412c027e363736b4f4c74ee5e8ecffc ] rds_sock_info() triggers locking warnings because we try to perform a local_bh_enable() (via sock_i_ino()) while hardware interrupts are disabled (via taking rds_sock_lock). There is no reason for rds_sock_lock to be a hardware IRQ disabling lock, none of these access paths run in hardware interrupt context. Therefore making it a BH disabling lock is safe and sufficient to fix this bug. Reported-by: Kumar Sanghvi Reported-by: Josh Boyer Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/rds/af_rds.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index bb6ad81b671..424ff622ab5 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -68,7 +68,6 @@ static int rds_release(struct socket *sock) { struct sock *sk = sock->sk; struct rds_sock *rs; - unsigned long flags; if (!sk) goto out; @@ -94,10 +93,10 @@ static int rds_release(struct socket *sock) rds_rdma_drop_keys(rs); rds_notify_queue_get(rs, NULL); - spin_lock_irqsave(&rds_sock_lock, flags); + spin_lock_bh(&rds_sock_lock); list_del_init(&rs->rs_item); rds_sock_count--; - spin_unlock_irqrestore(&rds_sock_lock, flags); + spin_unlock_bh(&rds_sock_lock); rds_trans_put(rs->rs_transport); @@ -409,7 +408,6 @@ static const struct proto_ops rds_proto_ops = { static int __rds_create(struct socket *sock, struct sock *sk, int protocol) { - unsigned long flags; struct rds_sock *rs; sock_init_data(sock, sk); @@ -426,10 +424,10 @@ static int __rds_create(struct socket *sock, struct sock *sk, int protocol) spin_lock_init(&rs->rs_rdma_lock); rs->rs_rdma_keys = RB_ROOT; - spin_lock_irqsave(&rds_sock_lock, flags); + spin_lock_bh(&rds_sock_lock); list_add_tail(&rs->rs_item, &rds_sock_list); rds_sock_count++; - spin_unlock_irqrestore(&rds_sock_lock, flags); + spin_unlock_bh(&rds_sock_lock); return 0; } @@ -471,12 +469,11 @@ static void rds_sock_inc_info(struct socket *sock, unsigned int len, { struct rds_sock *rs; struct rds_incoming *inc; - unsigned long flags; unsigned int total = 0; len /= sizeof(struct rds_info_message); - spin_lock_irqsave(&rds_sock_lock, flags); + spin_lock_bh(&rds_sock_lock); list_for_each_entry(rs, &rds_sock_list, rs_item) { read_lock(&rs->rs_recv_lock); @@ -492,7 +489,7 @@ static void rds_sock_inc_info(struct socket *sock, unsigned int len, read_unlock(&rs->rs_recv_lock); } - spin_unlock_irqrestore(&rds_sock_lock, flags); + spin_unlock_bh(&rds_sock_lock); lens->nr = total; lens->each = sizeof(struct rds_info_message); @@ -504,11 +501,10 @@ static void rds_sock_info(struct socket *sock, unsigned int len, { struct rds_info_socket sinfo; struct rds_sock *rs; - unsigned long flags; len /= sizeof(struct rds_info_socket); - spin_lock_irqsave(&rds_sock_lock, flags); + spin_lock_bh(&rds_sock_lock); if (len < rds_sock_count) goto out; @@ -529,7 +525,7 @@ static void rds_sock_info(struct socket *sock, unsigned int len, lens->nr = rds_sock_count; lens->each = sizeof(struct rds_info_socket); - spin_unlock_irqrestore(&rds_sock_lock, flags); + spin_unlock_bh(&rds_sock_lock); } static void rds_exit(void) From 8b4bb350e120fe0b32a0b1b8d227e65af03e3993 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Sat, 28 Jan 2012 17:29:46 +0000 Subject: [PATCH 0818/4025] tcp: fix tcp_trim_head() to adjust segment count with skb MSS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 5b35e1e6e9ca651e6b291c96d1106043c9af314a ] This commit fixes tcp_trim_head() to recalculate the number of segments in the skb with the skb's existing MSS, so trimming the head causes the skb segment count to be monotonically non-increasing - it should stay the same or go down, but not increase. Previously tcp_trim_head() used the current MSS of the connection. But if there was a decrease in MSS between original transmission and ACK (e.g. due to PMTUD), this could cause tcp_trim_head() to counter-intuitively increase the segment count when trimming bytes off the head of an skb. This violated assumptions in tcp_tso_acked() that tcp_trim_head() only decreases the packet count, so that packets_acked in tcp_tso_acked() could underflow, leading tcp_clean_rtx_queue() to pass u32 pkts_acked values as large as 0xffffffff to ca_ops->pkts_acked(). As an aside, if tcp_trim_head() had really wanted the skb to reflect the current MSS, it should have called tcp_set_skb_tso_segs() unconditionally, since a decrease in MSS would mean that a single-packet skb should now be sliced into multiple segments. Signed-off-by: Neal Cardwell Acked-by: Nandita Dukkipati Acked-by: Ilpo Järvinen Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_output.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 882e0b0964d..faf257b9415 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1134,11 +1134,9 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) sk_mem_uncharge(sk, len); sock_set_flag(sk, SOCK_QUEUE_SHRUNK); - /* Any change of skb->len requires recalculation of tso - * factor and mss. - */ + /* Any change of skb->len requires recalculation of tso factor. */ if (tcp_skb_pcount(skb) > 1) - tcp_set_skb_tso_segs(sk, skb, tcp_current_mss(sk)); + tcp_set_skb_tso_segs(sk, skb, tcp_skb_mss(skb)); return 0; } From 81ecd154d0b07bd5dab6e4f09336cb068b70bcb9 Mon Sep 17 00:00:00 2001 From: shawnlu Date: Fri, 20 Jan 2012 12:22:04 +0000 Subject: [PATCH 0819/4025] tcp: md5: using remote adress for md5 lookup in rst packet [ Upstream commit 8a622e71f58ec9f092fc99eacae0e6cf14f6e742 ] md5 key is added in socket through remote address. remote address should be used in finding md5 key when sending out reset packet. Signed-off-by: shawnlu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/tcp_ipv6.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 69790aa3198..53b01258945 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -630,7 +630,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.iov[0].iov_len = sizeof(rep.th); #ifdef CONFIG_TCP_MD5SIG - key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->daddr) : NULL; + key = sk ? tcp_v4_md5_do_lookup(sk, ip_hdr(skb)->saddr) : NULL; if (key) { rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 296510a82c3..51587a01627 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1096,7 +1096,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) #ifdef CONFIG_TCP_MD5SIG if (sk) - key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr); + key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr); #endif if (th->ack) From e4148500eefcc1b84a1985e9f8835a330d25f051 Mon Sep 17 00:00:00 2001 From: Renato Caldas Date: Fri, 6 Jan 2012 15:20:51 +0000 Subject: [PATCH 0820/4025] USB: serial: CP210x: Added USB-ID for the Link Instruments MSO-19 commit 791b7d7cf69de11275e4dccec2f538eec02cbff6 upstream. This device is a Oscilloscope/Logic Analizer/Pattern Generator/TDR, using a Silabs CP2103 USB to UART Bridge. Signed-off-by: Renato Caldas Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index a1a324b30d2..3b43d9b6668 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -138,6 +138,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ { USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */ + { USB_DEVICE(0x3195, 0xF190) }, /* Link Instruments MSO-19 */ { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */ { } /* Terminating Entry */ }; From ea453b01d323ab09758a56c06e808420b63b5a1a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 16 Jan 2012 00:36:48 +0100 Subject: [PATCH 0821/4025] USB: cp210x: call generic open last in open commit 55b2afbb92ad92e9f6b0aa4354eb1c94589280c3 upstream. Make sure port is fully initialised before calling generic open. Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 3b43d9b6668..cbcaddb1bf4 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -393,8 +393,6 @@ static unsigned int cp210x_quantise_baudrate(unsigned int baud) { static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) { - int result; - dbg("%s - port %d", __func__, port->number); if (cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE)) { @@ -403,13 +401,10 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) return -EPROTO; } - result = usb_serial_generic_open(tty, port); - if (result) - return result; - /* Configure the termios structure */ cp210x_get_termios(tty, port); - return 0; + + return usb_serial_generic_open(tty, port); } static void cp210x_close(struct usb_serial_port *port) From e23f5bd613d19b6ad224bd8e4768a1963a42330c Mon Sep 17 00:00:00 2001 From: Preston Fick Date: Mon, 16 Jan 2012 18:14:09 -0600 Subject: [PATCH 0822/4025] USB: cp210x: fix CP2104 baudrate usage commit 7f482fc88ac47662228d6b1f05759797c8936a30 upstream. This fix changes the way baudrates are set on the CP210x devices from Silicon Labs. The CP2101/2/3 will respond to both a GET/SET_BAUDDIV command, and GET/SET_BAUDRATE command, while CP2104 and higher devices only respond to GET/SET_BAUDRATE. The current cp210x.ko driver in kernel version 3.2.0 only implements the GET/SET_BAUDDIV command. This patch implements the two new codes for the GET/SET_BAUDRATE commands. Then there is a change in the way that the baudrate is assigned or retrieved. This is done according to the CP210x USB specification in AN571. This document can be found here: http://www.silabs.com/pages/DownloadDoc.aspx?FILEURL=Support%20Documents/TechnicalDocs/AN571.pdf&src=DocumentationWebPart Sections 5.3/5.4 describe the USB packets for the old baudrate method. Sections 5.5/5.6 describe the USB packets for the new method. This patch also implements the new request scheme, and eliminates the unnecessary baudrate calculations since it uses the "actual baudrate" method. This patch solves the problem reported for the CP2104 in bug 42586, and also keeps support for all other devices (CP2101/2/3). This patchfile is also attached to the bug report on bugzilla.kernel.org. This patch has been developed and test on the 3.2.0 mainline kernel version under Ubuntu 10.11. Signed-off-by: Preston Fick [duplicate patch also sent by Johan - gregkh] Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index cbcaddb1bf4..60993dc7eb8 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -202,6 +202,8 @@ static struct usb_serial_driver cp210x_device = { #define CP210X_EMBED_EVENTS 0x15 #define CP210X_GET_EVENTSTATE 0x16 #define CP210X_SET_CHARS 0x19 +#define CP210X_GET_BAUDRATE 0x1D +#define CP210X_SET_BAUDRATE 0x1E /* CP210X_IFC_ENABLE */ #define UART_ENABLE 0x0001 @@ -456,10 +458,7 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, dbg("%s - port %d", __func__, port->number); - cp210x_get_config(port, CP210X_GET_BAUDDIV, &baud, 2); - /* Convert to baudrate */ - if (baud) - baud = cp210x_quantise_baudrate((BAUD_RATE_GEN_FREQ + baud/2)/ baud); + cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4); dbg("%s - baud rate = %d", __func__, baud); *baudp = baud; @@ -594,8 +593,7 @@ static void cp210x_set_termios(struct tty_struct *tty, if (baud != tty_termios_baud_rate(old_termios) && baud != 0) { dbg("%s - Setting baud rate to %d baud", __func__, baud); - if (cp210x_set_config_single(port, CP210X_SET_BAUDDIV, - ((BAUD_RATE_GEN_FREQ + baud/2) / baud))) { + if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud, 4)) { dbg("Baud rate requested not supported by device"); baud = tty_termios_baud_rate(old_termios); } From bb04bab862c91d0bd75e5c5339039e5444973d16 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 16 Jan 2012 00:36:50 +0100 Subject: [PATCH 0823/4025] USB: cp210x: do not map baud rates to B0 commit be125d9c8d59560e7cc2d6e2b65c8fd233498ab7 upstream. We do not implement B0 hangup yet so map low baudrates to 300bps. Signed-off-by: Johan Hovold Cc: Preston Fick Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 60993dc7eb8..1bac7b9223f 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -357,8 +357,8 @@ static inline int cp210x_set_config_single(struct usb_serial_port *port, * Quantises the baud rate as per AN205 Table 1 */ static unsigned int cp210x_quantise_baudrate(unsigned int baud) { - if (baud <= 56) baud = 0; - else if (baud <= 300) baud = 300; + if (baud <= 300) + baud = 300; else if (baud <= 600) baud = 600; else if (baud <= 1200) baud = 1200; else if (baud <= 1800) baud = 1800; From 193aec6a3db750e58f5aac26e68dbb124b7328e9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 16 Jan 2012 00:36:49 +0100 Subject: [PATCH 0824/4025] USB: cp210x: fix up set_termios variables commit 34b76fcaee574017862ea3fa0efdcd77a9d0e57d upstream. [Based on a patch from Johan, mangled by gregkh to keep things in line] Fix up the variable usage in the set_termios call. Signed-off-by: Johan Hovold Cc: Preston Fick Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 1bac7b9223f..5c3b7d1c25a 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -576,7 +576,8 @@ static void cp210x_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { unsigned int cflag, old_cflag; - unsigned int baud = 0, bits; + u32 baud; + unsigned int bits; unsigned int modem_ctl[4]; dbg("%s - port %d", __func__, port->number); @@ -593,7 +594,7 @@ static void cp210x_set_termios(struct tty_struct *tty, if (baud != tty_termios_baud_rate(old_termios) && baud != 0) { dbg("%s - Setting baud rate to %d baud", __func__, baud); - if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud, 4)) { + if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud, sizeof(baud))) { dbg("Baud rate requested not supported by device"); baud = tty_termios_baud_rate(old_termios); } From f9dbd22994fae588903b99c328f81870e09795b8 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 16 Jan 2012 00:36:51 +0100 Subject: [PATCH 0825/4025] USB: cp210x: clean up, refactor and document speed handling commit e5990874e511d5bbca23b3396419480cb2ca0ee7 upstream. Clean up and refactor speed handling. Document baud rate handling for CP210{1,2,4,5,10}. Signed-off-by: Johan Hovold Cc: Preston Fick Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 71 +++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 5c3b7d1c25a..d2c40801ed8 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -39,6 +39,8 @@ static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *port); static void cp210x_get_termios_port(struct usb_serial_port *port, unsigned int *cflagp, unsigned int *baudp); +static void cp210x_change_speed(struct tty_struct *, struct usb_serial_port *, + struct ktermios *); static void cp210x_set_termios(struct tty_struct *, struct usb_serial_port *, struct ktermios*); static int cp210x_tiocmget(struct tty_struct *); @@ -572,11 +574,62 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, *cflagp = cflag; } +/* + * CP2101 supports the following baud rates: + * + * 300, 600, 1200, 1800, 2400, 4800, 7200, 9600, 14400, 19200, 28800, + * 38400, 56000, 57600, 115200, 128000, 230400, 460800, 921600 + * + * CP2102 and CP2103 support the following additional rates: + * + * 4000, 16000, 51200, 64000, 76800, 153600, 250000, 256000, 500000, + * 576000 + * + * The device will map a requested rate to a supported one, but the result + * of requests for rates greater than 1053257 is undefined (see AN205). + * + * CP2104, CP2105 and CP2110 support most rates up to 2M, 921k and 1M baud, + * respectively, with an error less than 1%. The actual rates are determined + * by + * + * div = round(freq / (2 x prescale x request)) + * actual = freq / (2 x prescale x div) + * + * For CP2104 and CP2105 freq is 48Mhz and prescale is 4 for request <= 365bps + * or 1 otherwise. + * For CP2110 freq is 24Mhz and prescale is 4 for request <= 300bps or 1 + * otherwise. + */ +static void cp210x_change_speed(struct tty_struct *tty, + struct usb_serial_port *port, struct ktermios *old_termios) +{ + u32 baud; + + baud = tty->termios->c_ospeed; + + /* This maps the requested rate to a rate valid on cp2102 or cp2103. + * + * NOTE: B0 is not implemented. + */ + baud = cp210x_quantise_baudrate(baud); + + dbg("%s - setting baud rate to %u", __func__, baud); + if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud, + sizeof(baud))) { + dev_warn(&port->dev, "failed to set baud rate to %u\n", baud); + if (old_termios) + baud = old_termios->c_ospeed; + else + baud = 9600; + } + + tty_encode_baud_rate(tty, baud, baud); +} + static void cp210x_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { unsigned int cflag, old_cflag; - u32 baud; unsigned int bits; unsigned int modem_ctl[4]; @@ -588,19 +641,9 @@ static void cp210x_set_termios(struct tty_struct *tty, tty->termios->c_cflag &= ~CMSPAR; cflag = tty->termios->c_cflag; old_cflag = old_termios->c_cflag; - baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty)); - - /* If the baud rate is to be updated*/ - if (baud != tty_termios_baud_rate(old_termios) && baud != 0) { - dbg("%s - Setting baud rate to %d baud", __func__, - baud); - if (cp210x_set_config(port, CP210X_SET_BAUDRATE, &baud, sizeof(baud))) { - dbg("Baud rate requested not supported by device"); - baud = tty_termios_baud_rate(old_termios); - } - } - /* Report back the resulting baud rate */ - tty_encode_baud_rate(tty, baud, baud); + + if (tty->termios->c_ospeed != old_termios->c_ospeed) + cp210x_change_speed(tty, port, old_termios); /* If the number of data bits is to be updated */ if ((cflag & CSIZE) != (old_cflag & CSIZE)) { From 872a9a09233a2ff601bf3449cdd2be9e9b2c0ac2 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 16 Jan 2012 00:36:52 +0100 Subject: [PATCH 0826/4025] USB: cp210x: initialise baud rate at open commit cdc32fd6f7b2b2580d7f1b74563f888e4dd9eb8a upstream. The newer cp2104 devices require the baud rate to be initialised after power on. Make sure it is set when port is opened. Signed-off-by: Johan Hovold Cc: Preston Fick Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index d2c40801ed8..07d297f5fe4 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -408,6 +408,10 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) /* Configure the termios structure */ cp210x_get_termios(tty, port); + /* The baud rate must be initialised on cp2104 */ + if (tty) + cp210x_change_speed(tty, port, NULL); + return usb_serial_generic_open(tty, port); } From 614a5aed26447b940748514f77b5487cdba2c5d6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 16 Jan 2012 00:36:53 +0100 Subject: [PATCH 0827/4025] USB: cp210x: allow more baud rates above 1Mbaud commit d1620ca9e7bb0030068c3b45b653defde8839dac upstream. Allow more baud rates to be set in [1M,2M] baud. Signed-off-by: Johan Hovold Cc: Preston Fick Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 07d297f5fe4..a5152379cb4 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -388,10 +388,10 @@ static unsigned int cp210x_quantise_baudrate(unsigned int baud) { else if (baud <= 491520) baud = 460800; else if (baud <= 567138) baud = 500000; else if (baud <= 670254) baud = 576000; - else if (baud <= 1053257) baud = 921600; - else if (baud <= 1474560) baud = 1228800; - else if (baud <= 2457600) baud = 1843200; - else baud = 3686400; + else if (baud < 1000000) + baud = 921600; + else if (baud > 2000000) + baud = 2000000; return baud; } @@ -611,7 +611,8 @@ static void cp210x_change_speed(struct tty_struct *tty, baud = tty->termios->c_ospeed; - /* This maps the requested rate to a rate valid on cp2102 or cp2103. + /* This maps the requested rate to a rate valid on cp2102 or cp2103, + * or to an arbitrary rate in [1M,2M]. * * NOTE: B0 is not implemented. */ From 5d14e472c60de8791259a0dbb8ba5252d0862a63 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 3 Feb 2012 09:19:48 -0800 Subject: [PATCH 0828/4025] Linux 3.0.19 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 581b8e9bb35..1e57901450c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 18 +SUBLEVEL = 19 EXTRAVERSION = NAME = Sneaky Weasel From 6cac12dfab9c57a4f76821412224b226a9b08dff Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 10 Nov 2011 16:38:33 -0500 Subject: [PATCH 0829/4025] PCI: Rework ASPM disable code commit 3c076351c4027a56d5005a39a0b518a4ba393ce2 upstream. Right now we forcibly clear ASPM state on all devices if the BIOS indicates that the feature isn't supported. Based on the Microsoft presentation "PCI Express In Depth for Windows Vista and Beyond", I'm starting to think that this may be an error. The implication is that unless the platform grants full control via _OSC, Windows will not touch any PCIe features - including ASPM. In that case clearing ASPM state would be an error unless the platform has granted us that control. This patch reworks the ASPM disabling code such that the actual clearing of state is triggered by a successful handoff of PCIe control to the OS. The general ASPM code undergoes some changes in order to ensure that the ability to clear the bits isn't overridden by ASPM having already been disabled. Further, this theoretically now allows for situations where only a subset of PCIe roots hand over control, leaving the others in the BIOS state. It's difficult to know for sure that this is the right thing to do - there's zero public documentation on the interaction between all of these components. But enough vendors enable ASPM on platforms and then set this bit that it seems likely that they're expecting the OS to leave them alone. Measured to save around 5W on an idle Thinkpad X220. Signed-off-by: Matthew Garrett Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/pci_root.c | 7 +++++ drivers/pci/pci-acpi.c | 1 - drivers/pci/pcie/aspm.c | 58 +++++++++++++++++++++++++--------------- include/linux/pci-aspm.h | 4 +-- 4 files changed, 46 insertions(+), 24 deletions(-) diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index d06078d660a..dfafecbddb5 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -595,6 +595,13 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device) if (ACPI_SUCCESS(status)) { dev_info(root->bus->bridge, "ACPI _OSC control (0x%02x) granted\n", flags); + if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { + /* + * We have ASPM control, but the FADT indicates + * that it's unsupported. Clear it. + */ + pcie_clear_aspm(root->bus); + } } else { dev_info(root->bus->bridge, "ACPI _OSC request failed (%s), " diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index d36f41ea8cb..56b04bc80a1 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -393,7 +393,6 @@ static int __init acpi_pci_init(void) if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n"); - pcie_clear_aspm(); pcie_no_aspm(); } diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 6892601fc76..e25af67f685 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -68,7 +68,7 @@ struct pcie_link_state { struct aspm_latency acceptable[8]; }; -static int aspm_disabled, aspm_force, aspm_clear_state; +static int aspm_disabled, aspm_force; static bool aspm_support_enabled = true; static DEFINE_MUTEX(aspm_lock); static LIST_HEAD(link_list); @@ -500,9 +500,6 @@ static int pcie_aspm_sanity_check(struct pci_dev *pdev) int pos; u32 reg32; - if (aspm_clear_state) - return -EINVAL; - /* * Some functions in a slot might not all be PCIe functions, * very strange. Disable ASPM for the whole slot @@ -574,9 +571,6 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) return; - if (aspm_disabled && !aspm_clear_state) - return; - /* VIA has a strange chipset, root port is under a bridge */ if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT && pdev->bus->self) @@ -608,7 +602,7 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) * the BIOS's expectation, we'll do so once pci_enable_device() is * called. */ - if (aspm_policy != POLICY_POWERSAVE || aspm_clear_state) { + if (aspm_policy != POLICY_POWERSAVE) { pcie_config_aspm_path(link); pcie_set_clkpm(link, policy_to_clkpm_state(link)); } @@ -649,8 +643,7 @@ void pcie_aspm_exit_link_state(struct pci_dev *pdev) struct pci_dev *parent = pdev->bus->self; struct pcie_link_state *link, *root, *parent_link; - if ((aspm_disabled && !aspm_clear_state) || !pci_is_pcie(pdev) || - !parent || !parent->link_state) + if (!pci_is_pcie(pdev) || !parent || !parent->link_state) return; if ((parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT) && (parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) @@ -734,13 +727,18 @@ void pcie_aspm_powersave_config_link(struct pci_dev *pdev) * pci_disable_link_state - disable pci device's link state, so the link will * never enter specific states */ -static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) +static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem, + bool force) { struct pci_dev *parent = pdev->bus->self; struct pcie_link_state *link; - if (aspm_disabled || !pci_is_pcie(pdev)) + if (aspm_disabled && !force) + return; + + if (!pci_is_pcie(pdev)) return; + if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT || pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) parent = pdev; @@ -768,16 +766,31 @@ static void __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem) void pci_disable_link_state_locked(struct pci_dev *pdev, int state) { - __pci_disable_link_state(pdev, state, false); + __pci_disable_link_state(pdev, state, false, false); } EXPORT_SYMBOL(pci_disable_link_state_locked); void pci_disable_link_state(struct pci_dev *pdev, int state) { - __pci_disable_link_state(pdev, state, true); + __pci_disable_link_state(pdev, state, true, false); } EXPORT_SYMBOL(pci_disable_link_state); +void pcie_clear_aspm(struct pci_bus *bus) +{ + struct pci_dev *child; + + /* + * Clear any ASPM setup that the firmware has carried out on this bus + */ + list_for_each_entry(child, &bus->devices, bus_list) { + __pci_disable_link_state(child, PCIE_LINK_STATE_L0S | + PCIE_LINK_STATE_L1 | + PCIE_LINK_STATE_CLKPM, + false, true); + } +} + static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) { int i; @@ -935,6 +948,7 @@ void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) static int __init pcie_aspm_disable(char *str) { if (!strcmp(str, "off")) { + aspm_policy = POLICY_DEFAULT; aspm_disabled = 1; aspm_support_enabled = false; printk(KERN_INFO "PCIe ASPM is disabled\n"); @@ -947,16 +961,18 @@ static int __init pcie_aspm_disable(char *str) __setup("pcie_aspm=", pcie_aspm_disable); -void pcie_clear_aspm(void) -{ - if (!aspm_force) - aspm_clear_state = 1; -} - void pcie_no_aspm(void) { - if (!aspm_force) + /* + * Disabling ASPM is intended to prevent the kernel from modifying + * existing hardware state, not to clear existing state. To that end: + * (a) set policy to POLICY_DEFAULT in order to avoid changing state + * (b) prevent userspace from changing policy + */ + if (!aspm_force) { + aspm_policy = POLICY_DEFAULT; aspm_disabled = 1; + } } /** diff --git a/include/linux/pci-aspm.h b/include/linux/pci-aspm.h index 7cea7b6c141..c8320144fe7 100644 --- a/include/linux/pci-aspm.h +++ b/include/linux/pci-aspm.h @@ -29,7 +29,7 @@ extern void pcie_aspm_pm_state_change(struct pci_dev *pdev); extern void pcie_aspm_powersave_config_link(struct pci_dev *pdev); extern void pci_disable_link_state(struct pci_dev *pdev, int state); extern void pci_disable_link_state_locked(struct pci_dev *pdev, int state); -extern void pcie_clear_aspm(void); +extern void pcie_clear_aspm(struct pci_bus *bus); extern void pcie_no_aspm(void); #else static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) @@ -47,7 +47,7 @@ static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) static inline void pci_disable_link_state(struct pci_dev *pdev, int state) { } -static inline void pcie_clear_aspm(void) +static inline void pcie_clear_aspm(struct pci_bus *bus) { } static inline void pcie_no_aspm(void) From bcac798f6c44e21a6bdb2c5f8b056b364e246a35 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 6 Feb 2012 09:31:45 -0800 Subject: [PATCH 0830/4025] Linux 3.0.20 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1e57901450c..c060c58ad0d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 19 +SUBLEVEL = 20 EXTRAVERSION = NAME = Sneaky Weasel From 5ec390edb672597cb245ee8341441d3bc818f326 Mon Sep 17 00:00:00 2001 From: Adam Kent Date: Wed, 8 Jun 2011 14:40:32 +1000 Subject: [PATCH 0831/4025] Generic BLN with in-kernel blink --- arch/arm/mach-s5pv210/herring-touchkey-led.c | 31 +- arch/arm/mach-s5pv210/mach-herring.c | 18 ++ drivers/input/keyboard/cypress-touchkey.c | 73 +++++ drivers/misc/Kconfig | 7 + drivers/misc/Makefile | 1 + drivers/misc/bln.c | 313 +++++++++++++++++++ include/linux/bln.h | 13 + include/linux/input/cypress-touchkey.h | 1 + 8 files changed, 454 insertions(+), 3 deletions(-) create mode 100644 drivers/misc/bln.c create mode 100644 include/linux/bln.h diff --git a/arch/arm/mach-s5pv210/herring-touchkey-led.c b/arch/arm/mach-s5pv210/herring-touchkey-led.c index b36e0f0e740..91d86234fda 100644 --- a/arch/arm/mach-s5pv210/herring-touchkey-led.c +++ b/arch/arm/mach-s5pv210/herring-touchkey-led.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "herring.h" @@ -29,6 +30,23 @@ static void herring_touchkey_led_onoff(int onoff) gpio_direction_output(S5PV210_GPJ3(led_gpios[i]), !!onoff); } +#ifdef CONFIG_GENERIC_BLN +static void herring_touchkey_bln_enable(void) +{ + herring_touchkey_led_onoff(1); +} + +static void herring_touchkey_bln_disable(void) +{ + herring_touchkey_led_onoff(0); +} + +static struct bln_implementation herring_touchkey_bln = { + .enable = herring_touchkey_bln_enable, + .disable = herring_touchkey_bln_disable, +}; +#endif + static void herring_touchkey_led_early_suspend(struct early_suspend *h) { herring_touchkey_led_onoff(0); @@ -49,24 +67,31 @@ static int __init herring_init_touchkey_led(void) { int i; int ret = 0; + u32 gpio; if (!machine_is_herring() || !herring_is_tft_dev()) return 0; for (i = 0; i < ARRAY_SIZE(led_gpios); i++) { - ret = gpio_request(S5PV210_GPJ3(led_gpios[i]), "touchkey led"); + gpio = S5PV210_GPJ3(led_gpios[i]); + ret = gpio_request(gpio, "touchkey led"); if (ret) { pr_err("Failed to request touchkey led gpio %d\n", i); goto err_req; } - s3c_gpio_setpull(S5PV210_GPJ3(led_gpios[i]), - S3C_GPIO_PULL_NONE); + s3c_gpio_setpull(gpio, S3C_GPIO_PULL_NONE); + s3c_gpio_slp_cfgpin(gpio, S3C_GPIO_SLP_PREV); + s3c_gpio_slp_setpull_updown(gpio, S3C_GPIO_PULL_NONE); } herring_touchkey_led_onoff(1); register_early_suspend(&early_suspend); +#ifdef CONFIG_GENERIC_BLN + register_bln_implementation(&herring_touchkey_bln); +#endif + return 0; err_req: diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c index a1f157c852e..7341e76afd6 100755 --- a/arch/arm/mach-s5pv210/mach-herring.c +++ b/arch/arm/mach-s5pv210/mach-herring.c @@ -2008,6 +2008,23 @@ static void touch_keypad_onoff(int onoff) msleep(50); } +static void touch_keypad_gpio_sleep(int onoff) +{ + if (onoff == TOUCHKEY_ON) { + /* + * reconfigure gpio to activate touchkey controller vdd in sleep mode + */ + s3c_gpio_slp_cfgpin(_3_GPIO_TOUCH_EN, S3C_GPIO_SLP_OUT1); + } else { + /* + * reconfigure gpio to deactivate touchkey vdd in sleep mode, + * this is the default + */ + s3c_gpio_slp_cfgpin(_3_GPIO_TOUCH_EN, S3C_GPIO_SLP_OUT0); + } + +} + static const int touch_keypad_code[] = { KEY_MENU, KEY_HOME, @@ -2019,6 +2036,7 @@ static struct touchkey_platform_data touchkey_data = { .keycode_cnt = ARRAY_SIZE(touch_keypad_code), .keycode = touch_keypad_code, .touchkey_onoff = touch_keypad_onoff, + .touchkey_sleep_onoff = touch_keypad_gpio_sleep, .fw_name = "cypress-touchkey.bin", .scl_pin = _3_TOUCH_SCL_28V, .sda_pin = _3_TOUCH_SDA_28V, diff --git a/drivers/input/keyboard/cypress-touchkey.c b/drivers/input/keyboard/cypress-touchkey.c index 296c0f44ff5..bf1a02eab56 100755 --- a/drivers/input/keyboard/cypress-touchkey.c +++ b/drivers/input/keyboard/cypress-touchkey.c @@ -1,6 +1,7 @@ /* * Copyright 2006-2010, Cypress Semiconductor Corporation. * Copyright (C) 2010, Samsung Electronics Co. Ltd. All Rights Reserved. + * Copyright 2011, Michael Richter (alias neldar) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -28,6 +29,7 @@ #include #include #include +#include #define SCANCODE_MASK 0x07 #define UPDOWN_EVENT_MASK 0x08 @@ -55,6 +57,8 @@ struct cypress_touchkey_devdata { bool has_legacy_keycode; }; +static struct cypress_touchkey_devdata *blndevdata; + static int i2c_touchkey_read_byte(struct cypress_touchkey_devdata *devdata, u8 *val) { @@ -209,6 +213,14 @@ static void cypress_touchkey_early_suspend(struct early_suspend *h) return; disable_irq(devdata->client->irq); + +#ifdef CONFIG_GENERIC_BLN + /* + * Disallow powering off the touchkey controller + * while a led notification is ongoing + */ + if(!bln_is_ongoing()) +#endif devdata->pdata->touchkey_onoff(TOUCHKEY_OFF); all_keys_up(devdata); @@ -292,6 +304,14 @@ static int update_firmware(struct cypress_touchkey_devdata *devdata) return ret; } +static void enable_touchkey_backlights(void){ + i2c_touchkey_write_byte(blndevdata, blndevdata->backlight_on); +} + +static void disable_touchkey_backlights(void){ + i2c_touchkey_write_byte(blndevdata, blndevdata->backlight_off); +} + static int cypress_touchkey_open(struct input_dev *input_dev) { struct device *dev = &input_dev->dev; @@ -330,6 +350,54 @@ static int cypress_touchkey_open(struct input_dev *input_dev) return 0; } +static void cypress_touchkey_enable_led_notification(void){ + /* is_powering_on signals whether touchkey lights are used for touchmode */ + if (blndevdata->is_powering_on){ + /* reconfigure gpio for sleep mode */ + blndevdata->pdata->touchkey_sleep_onoff(TOUCHKEY_ON); + + /* + * power on the touchkey controller + * This is actually not needed, but it is intentionally + * left for the case that the early_resume() function + * did not power on the touchkey controller for some reasons + */ + blndevdata->pdata->touchkey_onoff(TOUCHKEY_ON); + + /* write to i2cbus, enable backlights */ + enable_touchkey_backlights(); + } + else + pr_info("%s: cannot set notification led, touchkeys are enabled\n",__FUNCTION__); +} + +static void cypress_touchkey_disable_led_notification(void){ + /* + * reconfigure gpio for sleep mode, this has to be done + * independently from the power status + */ + blndevdata->pdata->touchkey_sleep_onoff(TOUCHKEY_OFF); + + /* if touchkeys lights are not used for touchmode */ + if (blndevdata->is_powering_on){ + disable_touchkey_backlights(); + + #if 0 + /* + * power off the touchkey controller + * This is actually not needed, the early_suspend function + * should take care of powering off the touchkey controller + */ + blndevdata->pdata->touchkey_onoff(TOUCHKEY_OFF); + #endif + } +} + +static struct bln_implementation cypress_touchkey_bln = { + .enable = cypress_touchkey_enable_led_notification, + .disable = cypress_touchkey_disable_led_notification, +}; + static int cypress_touchkey_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -429,8 +497,13 @@ static int cypress_touchkey_probe(struct i2c_client *client, devdata->is_powering_on = false; +#ifdef CONFIG_GENERIC_BLN + blndevdata = devdata; + register_bln_implementation(&cypress_touchkey_bln); +#endif return 0; + err_req_irq: err_backlight_on: input_unregister_device(input_dev); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index c3dc7dfe725..0a503a4a62d 100755 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -593,4 +593,11 @@ config PN544 help NXP PN544 Near Field Communication controller support. +config GENERIC_BLN + bool "Generic BLN support for backlight notification" + default y + help + Say Y here to enable the backlight notification + for android led-notification (modified liblight needed) + endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 3794953b37a..260e71e15b3 100755 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -57,3 +57,4 @@ obj-$(CONFIG_PN544) += pn544.o obj-$(CONFIG_SAMSUNG_JACK) += sec_jack.o obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o obj-$(CONFIG_SAMSUNG_MODEMCTL) += samsung_modemctl/ +obj-$(CONFIG_GENERIC_BLN) += bln.o diff --git a/drivers/misc/bln.c b/drivers/misc/bln.c new file mode 100644 index 00000000000..85300efc360 --- /dev/null +++ b/drivers/misc/bln.c @@ -0,0 +1,313 @@ +/* drivers/misc/bln.c + * + * Copyright 2011 Michael Richter (alias neldar) + * Copyright 2011 Adam Kent + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool bln_enabled = true; /* is BLN function is enabled */ +static bool bln_ongoing = false; /* ongoing LED Notification */ +static int bln_blink_state = 0; +static bool bln_suspended = false; /* is system suspended */ +static struct bln_implementation *bln_imp = NULL; +static bool in_kernel_blink = false; +static uint32_t blink_count; + +static struct wake_lock bln_wake_lock; + +void bl_timer_callback(unsigned long data); +static struct timer_list blink_timer = + TIMER_INITIALIZER(bl_timer_callback, 0, 0); +static void blink_callback(struct work_struct *blink_work); +static DECLARE_WORK(blink_work, blink_callback); + +#define BLINK_INTERVAL 500 /* on / off every 500ms */ +#define MAX_BLINK_COUNT 600 /* 10 minutes */ +#define BACKLIGHTNOTIFICATION_VERSION 9 + +static void bln_enable_backlights(void) +{ + if (bln_imp) + bln_imp->enable(); +} + +static void bln_disable_backlights(void) +{ + if (bln_imp) + bln_imp->disable(); +} + +static void bln_early_suspend(struct early_suspend *h) +{ + bln_suspended = true; +} + +static void bln_late_resume(struct early_suspend *h) +{ + bln_suspended = false; +} + +static struct early_suspend bln_suspend_data = { + .level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1, + .suspend = bln_early_suspend, + .resume = bln_late_resume, +}; + +static void enable_led_notification(void) +{ + if (!bln_enabled) + return; + + if (in_kernel_blink) { + wake_lock(&bln_wake_lock); + + /* Start timer */ + blink_timer.expires = jiffies + + msecs_to_jiffies(BLINK_INTERVAL); + blink_count = MAX_BLINK_COUNT; + add_timer(&blink_timer); + } + + bln_enable_backlights(); + pr_info("%s: notification led enabled\n", __FUNCTION__); + bln_ongoing = true; +} + +static void disable_led_notification(void) +{ + pr_info("%s: notification led disabled\n", __FUNCTION__); + + bln_blink_state = 0; + bln_ongoing = false; + + if (bln_suspended) + bln_disable_backlights(); + + if (in_kernel_blink) + del_timer(&blink_timer); + + wake_unlock(&bln_wake_lock); + +} + +static ssize_t backlightnotification_status_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", (bln_enabled ? 1 : 0)); +} + +static ssize_t backlightnotification_status_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned int data; + if(sscanf(buf, "%u\n", &data) == 1) { + pr_devel("%s: %u \n", __FUNCTION__, data); + if (data == 1) { + pr_info("%s: BLN function enabled\n", __FUNCTION__); + bln_enabled = true; + } else if (data == 0) { + pr_info("%s: BLN function disabled\n", __FUNCTION__); + bln_enabled = false; + if (bln_ongoing) + disable_led_notification(); + } else { + pr_info("%s: invalid input range %u\n", __FUNCTION__, + data); + } + } else { + pr_info("%s: invalid input\n", __FUNCTION__); + } + + return size; +} + +static ssize_t notification_led_status_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%u\n", (bln_ongoing ? 1 : 0)); +} + +static ssize_t notification_led_status_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned int data; + + if (sscanf(buf, "%u\n", &data) == 1) { + if (data == 1) + enable_led_notification(); + else if (data == 0) + disable_led_notification(); + else + pr_info("%s: wrong input %u\n", __FUNCTION__, data); + } else { + pr_info("%s: input error\n", __FUNCTION__); + } + + return size; +} + +static ssize_t in_kernel_blink_status_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf,"%u\n", (in_kernel_blink ? 1 : 0)); +} + +static ssize_t in_kernel_blink_status_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned int data; + + if (sscanf(buf, "%u\n", &data) == 1) + in_kernel_blink = !!(data); + else + pr_info("%s: input error\n", __FUNCTION__); + + return size; +} +static ssize_t blink_control_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", bln_blink_state); +} + +static ssize_t blink_control_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + unsigned int data; + + if (!bln_ongoing) + return size; + + if (sscanf(buf, "%u\n", &data) == 1) { + if (data == 1) { + bln_blink_state = 1; + bln_disable_backlights(); + } else if (data == 0) { + bln_blink_state = 0; + bln_enable_backlights(); + } else { + pr_info("%s: wrong input %u\n", __FUNCTION__, data); + } + } else { + pr_info("%s: input error\n", __FUNCTION__); + } + + return size; +} + +static ssize_t backlightnotification_version(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", BACKLIGHTNOTIFICATION_VERSION); +} + +static DEVICE_ATTR(blink_control, S_IRUGO | S_IWUGO, blink_control_read, + blink_control_write); +static DEVICE_ATTR(enabled, S_IRUGO | S_IWUGO, + backlightnotification_status_read, + backlightnotification_status_write); +static DEVICE_ATTR(notification_led, S_IRUGO | S_IWUGO, + notification_led_status_read, + notification_led_status_write); +static DEVICE_ATTR(in_kernel_blink, S_IRUGO | S_IWUGO, + in_kernel_blink_status_read, + in_kernel_blink_status_write); +static DEVICE_ATTR(version, S_IRUGO , backlightnotification_version, NULL); + +static struct attribute *bln_notification_attributes[] = { + &dev_attr_blink_control.attr, + &dev_attr_enabled.attr, + &dev_attr_notification_led.attr, + &dev_attr_in_kernel_blink.attr, + &dev_attr_version.attr, + NULL +}; + +static struct attribute_group bln_notification_group = { + .attrs = bln_notification_attributes, +}; + +static struct miscdevice bln_device = { + .minor = MISC_DYNAMIC_MINOR, + .name = "backlightnotification", +}; + +void register_bln_implementation(struct bln_implementation *imp) +{ + bln_imp = imp; +} +EXPORT_SYMBOL(register_bln_implementation); + +bool bln_is_ongoing() +{ + return bln_ongoing; +} +EXPORT_SYMBOL(bln_is_ongoing); + + +static void blink_callback(struct work_struct *blink_work) +{ + if (--blink_count == 0) { + pr_info("%s: notification timed out\n", __FUNCTION__); + bln_enable_backlights(); + del_timer(&blink_timer); + wake_unlock(&bln_wake_lock); + return; + } + + if (bln_blink_state) + bln_enable_backlights(); + else + bln_disable_backlights(); + + bln_blink_state = !bln_blink_state; +} + +void bl_timer_callback(unsigned long data) +{ + schedule_work(&blink_work); + mod_timer(&blink_timer, jiffies + msecs_to_jiffies(BLINK_INTERVAL)); +} + +static int __init bln_control_init(void) +{ + int ret; + + pr_info("%s misc_register(%s)\n", __FUNCTION__, bln_device.name); + ret = misc_register(&bln_device); + if (ret) { + pr_err("%s misc_register(%s) fail\n", __FUNCTION__, + bln_device.name); + return 1; + } + + /* add the bln attributes */ + if (sysfs_create_group(&bln_device.this_device->kobj, + &bln_notification_group) < 0) { + pr_err("%s sysfs_create_group fail\n", __FUNCTION__); + pr_err("Failed to create sysfs group for device (%s)!\n", + bln_device.name); + } + + register_early_suspend(&bln_suspend_data); + + /* Initialize wake locks */ + wake_lock_init(&bln_wake_lock, WAKE_LOCK_SUSPEND, "bln_wake"); + + return 0; +} + +device_initcall(bln_control_init); diff --git a/include/linux/bln.h b/include/linux/bln.h new file mode 100644 index 00000000000..a5de5e45dfd --- /dev/null +++ b/include/linux/bln.h @@ -0,0 +1,13 @@ +/* include/linux/bln.h */ + +#ifndef _LINUX_BLN_H +#define _LINUX_BLN_H + +struct bln_implementation { + void (*enable)(void); + void (*disable)(void); +}; + +void register_bln_implementation(struct bln_implementation *imp); +bool bln_is_ongoing(void); +#endif diff --git a/include/linux/input/cypress-touchkey.h b/include/linux/input/cypress-touchkey.h index ca65472f1e7..cd4ff4d57f6 100755 --- a/include/linux/input/cypress-touchkey.h +++ b/include/linux/input/cypress-touchkey.h @@ -25,6 +25,7 @@ struct touchkey_platform_data { int keycode_cnt; const int *keycode; void (*touchkey_onoff) (int); + void (*touchkey_sleep_onoff) (int); const char *fw_name; int scl_pin; int sda_pin; From c5ef0ba3e77bcc4f5473459f8d96f2936e5f4f72 Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Sat, 17 Dec 2011 23:06:21 +0100 Subject: [PATCH 0832/4025] Remove blink from LED notification control This is done to encrease stability and more to preserve bettery --- drivers/input/keyboard/cypress-touchkey.c | 5 +- drivers/misc/bln.c | 111 +--------------------- 2 files changed, 7 insertions(+), 109 deletions(-) diff --git a/drivers/input/keyboard/cypress-touchkey.c b/drivers/input/keyboard/cypress-touchkey.c index bf1a02eab56..71e748dd3f7 100755 --- a/drivers/input/keyboard/cypress-touchkey.c +++ b/drivers/input/keyboard/cypress-touchkey.c @@ -219,7 +219,10 @@ static void cypress_touchkey_early_suspend(struct early_suspend *h) * Disallow powering off the touchkey controller * while a led notification is ongoing */ - if(!bln_is_ongoing()) + if(!bln_is_ongoing()) { + devdata->pdata->touchkey_onoff(TOUCHKEY_OFF); + devdata->pdata->touchkey_sleep_onoff(TOUCHKEY_OFF); + } #endif devdata->pdata->touchkey_onoff(TOUCHKEY_OFF); diff --git a/drivers/misc/bln.c b/drivers/misc/bln.c index 85300efc360..ce63bd921e3 100644 --- a/drivers/misc/bln.c +++ b/drivers/misc/bln.c @@ -20,22 +20,11 @@ static bool bln_enabled = true; /* is BLN function is enabled */ static bool bln_ongoing = false; /* ongoing LED Notification */ -static int bln_blink_state = 0; static bool bln_suspended = false; /* is system suspended */ static struct bln_implementation *bln_imp = NULL; -static bool in_kernel_blink = false; -static uint32_t blink_count; static struct wake_lock bln_wake_lock; -void bl_timer_callback(unsigned long data); -static struct timer_list blink_timer = - TIMER_INITIALIZER(bl_timer_callback, 0, 0); -static void blink_callback(struct work_struct *blink_work); -static DECLARE_WORK(blink_work, blink_callback); - -#define BLINK_INTERVAL 500 /* on / off every 500ms */ -#define MAX_BLINK_COUNT 600 /* 10 minutes */ #define BACKLIGHTNOTIFICATION_VERSION 9 static void bln_enable_backlights(void) @@ -71,16 +60,6 @@ static void enable_led_notification(void) if (!bln_enabled) return; - if (in_kernel_blink) { - wake_lock(&bln_wake_lock); - - /* Start timer */ - blink_timer.expires = jiffies + - msecs_to_jiffies(BLINK_INTERVAL); - blink_count = MAX_BLINK_COUNT; - add_timer(&blink_timer); - } - bln_enable_backlights(); pr_info("%s: notification led enabled\n", __FUNCTION__); bln_ongoing = true; @@ -90,15 +69,11 @@ static void disable_led_notification(void) { pr_info("%s: notification led disabled\n", __FUNCTION__); - bln_blink_state = 0; bln_ongoing = false; if (bln_suspended) bln_disable_backlights(); - if (in_kernel_blink) - del_timer(&blink_timer); - wake_unlock(&bln_wake_lock); } @@ -159,79 +134,23 @@ static ssize_t notification_led_status_write(struct device *dev, return size; } -static ssize_t in_kernel_blink_status_read(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf,"%u\n", (in_kernel_blink ? 1 : 0)); -} - -static ssize_t in_kernel_blink_status_write(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned int data; - - if (sscanf(buf, "%u\n", &data) == 1) - in_kernel_blink = !!(data); - else - pr_info("%s: input error\n", __FUNCTION__); - - return size; -} -static ssize_t blink_control_read(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%u\n", bln_blink_state); -} - -static ssize_t blink_control_write(struct device *dev, - struct device_attribute *attr, const char *buf, size_t size) -{ - unsigned int data; - - if (!bln_ongoing) - return size; - - if (sscanf(buf, "%u\n", &data) == 1) { - if (data == 1) { - bln_blink_state = 1; - bln_disable_backlights(); - } else if (data == 0) { - bln_blink_state = 0; - bln_enable_backlights(); - } else { - pr_info("%s: wrong input %u\n", __FUNCTION__, data); - } - } else { - pr_info("%s: input error\n", __FUNCTION__); - } - - return size; -} - static ssize_t backlightnotification_version(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%u\n", BACKLIGHTNOTIFICATION_VERSION); } -static DEVICE_ATTR(blink_control, S_IRUGO | S_IWUGO, blink_control_read, - blink_control_write); static DEVICE_ATTR(enabled, S_IRUGO | S_IWUGO, backlightnotification_status_read, backlightnotification_status_write); -static DEVICE_ATTR(notification_led, S_IRUGO | S_IWUGO, +static DEVICE_ATTR(led, S_IRUGO | S_IWUGO, notification_led_status_read, notification_led_status_write); -static DEVICE_ATTR(in_kernel_blink, S_IRUGO | S_IWUGO, - in_kernel_blink_status_read, - in_kernel_blink_status_write); static DEVICE_ATTR(version, S_IRUGO , backlightnotification_version, NULL); static struct attribute *bln_notification_attributes[] = { - &dev_attr_blink_control.attr, &dev_attr_enabled.attr, - &dev_attr_notification_led.attr, - &dev_attr_in_kernel_blink.attr, + &dev_attr_led.attr, &dev_attr_version.attr, NULL }; @@ -242,7 +161,7 @@ static struct attribute_group bln_notification_group = { static struct miscdevice bln_device = { .minor = MISC_DYNAMIC_MINOR, - .name = "backlightnotification", + .name = "notification", }; void register_bln_implementation(struct bln_implementation *imp) @@ -258,30 +177,6 @@ bool bln_is_ongoing() EXPORT_SYMBOL(bln_is_ongoing); -static void blink_callback(struct work_struct *blink_work) -{ - if (--blink_count == 0) { - pr_info("%s: notification timed out\n", __FUNCTION__); - bln_enable_backlights(); - del_timer(&blink_timer); - wake_unlock(&bln_wake_lock); - return; - } - - if (bln_blink_state) - bln_enable_backlights(); - else - bln_disable_backlights(); - - bln_blink_state = !bln_blink_state; -} - -void bl_timer_callback(unsigned long data) -{ - schedule_work(&blink_work); - mod_timer(&blink_timer, jiffies + msecs_to_jiffies(BLINK_INTERVAL)); -} - static int __init bln_control_init(void) { int ret; From 99d430d13030bf9471294b20c0b43a5258af4556 Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Sun, 9 Oct 2011 10:54:32 +0200 Subject: [PATCH 0833/4025] Change battery percentage calculation. Compensate for chipset inaccuracies in returning battery percentage the way Samsung did it in its Froyo rom. This allows the battery to reach 100% (may require bump charging) and no visible battery drop is noticable (even after a reboot). The precision is also increased (no 2% jump) from the current method of calculation because the calculation is done where we have extra precision information from the chipset. added this pawitp implementation to joing more kernel work on CM devices. Change-Id: Id7f15dd3906f7a12949683c0d921ce7a8498e70a Conflicts: drivers/power/s5pc110_battery.c --- drivers/power/max17040_battery.c | 30 +++++++++++++++++++++++++++++- drivers/power/s5pc110_battery.c | 9 +++++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c index 54905b1ae49..aedb539abe2 100755 --- a/drivers/power/max17040_battery.c +++ b/drivers/power/max17040_battery.c @@ -129,11 +129,39 @@ static void max17040_get_soc(struct i2c_client *client) struct max17040_chip *chip = i2c_get_clientdata(client); u8 msb; u8 lsb; + u32 soc = 0; + u32 temp = 0; + u32 temp_soc = 0; msb = max17040_read_reg(client, MAX17040_SOC_MSB); lsb = max17040_read_reg(client, MAX17040_SOC_LSB); - chip->soc = min(msb, (u8)100); + temp = msb * 100 + ((lsb * 100) / 256); + + if (temp >= 100) + temp_soc = temp; + else { + if (temp >= 70) + temp_soc = 100; + else + temp_soc = 0; + } + + /* rounding off and Changing to percentage */ + soc = temp_soc / 100; + + if (temp_soc % 100 >= 50) + soc += 1; + + if (soc >= 26) + soc += 4; + else + soc = (30 * temp_soc) / 26 / 100; + + if (soc >= 100) + soc = 100; + + chip->soc = soc; } static void max17040_get_version(struct i2c_client *client) diff --git a/drivers/power/s5pc110_battery.c b/drivers/power/s5pc110_battery.c index 6cb3e9092ea..0da972310fb 100755 --- a/drivers/power/s5pc110_battery.c +++ b/drivers/power/s5pc110_battery.c @@ -199,10 +199,11 @@ static int s3c_bat_get_property(struct power_supply *bat_ps, break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: case POWER_SUPPLY_PROP_CAPACITY: - if (chg->pdata && chg->pdata->psy_fuelgauge && - chg->pdata->psy_fuelgauge->get_property && - chg->pdata->psy_fuelgauge->get_property(chg->pdata->psy_fuelgauge, - psp, (union power_supply_propval *)&val->intval) < 0) + if (chg->pdata && + chg->pdata->psy_fuelgauge && + chg->pdata->psy_fuelgauge->get_property && + chg->pdata->psy_fuelgauge->get_property( + chg->pdata->psy_fuelgauge, psp, val) < 0) return -EINVAL; break; case POWER_SUPPLY_PROP_TECHNOLOGY: From 5e70e53b53b0a6014068d1ffb657d1888c3a266c Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Thu, 22 Dec 2011 15:56:53 +0100 Subject: [PATCH 0834/4025] Add overclock to kernel More than 1200 is not safe since bus is also encreased on ics --- arch/arm/mach-s5pv210/cpufreq.c | 82 ++++++++++++------- .../mach-s5pv210/include/mach/cpu-freq-v210.h | 6 ++ arch/arm/mach-s5pv210/mach-herring.c | 4 +- 3 files changed, 59 insertions(+), 33 deletions(-) diff --git a/arch/arm/mach-s5pv210/cpufreq.c b/arch/arm/mach-s5pv210/cpufreq.c index 4e11f997a96..2c641b39723 100755 --- a/arch/arm/mach-s5pv210/cpufreq.c +++ b/arch/arm/mach-s5pv210/cpufreq.c @@ -32,10 +32,11 @@ static struct clk *dmc1_clk; static struct cpufreq_freqs freqs; static DEFINE_MUTEX(set_freq_lock); -/* APLL M,P,S values for 1G/800Mhz */ +/* APLL M,P,S values for 1.2G/800Mhz */ +#define APLL_VAL_1200 ((1 << 31) | (150 << 16) | (3 << 8) | 1) #define APLL_VAL_1000 ((1 << 31) | (125 << 16) | (3 << 8) | 1) +#define APLL_VAL_1100 ((1 << 31) | (275 << 16) | (6 << 8) | 1) #define APLL_VAL_800 ((1 << 31) | (100 << 16) | (3 << 8) | 1) - #define SLEEP_FREQ (800 * 1000) /* Use 800MHz when entering sleep */ /* @@ -62,7 +63,7 @@ struct dram_conf { static struct dram_conf s5pv210_dram_conf[2]; enum perf_level { - L0, L1, L2, L3, L4, + L0, L1, L2, L3, L4, L5, L6, }; enum s5pv210_mem_type { @@ -77,11 +78,13 @@ enum s5pv210_dmc_port { }; static struct cpufreq_frequency_table s5pv210_freq_table[] = { - {L0, 1000*1000}, - {L1, 800*1000}, - {L2, 400*1000}, - {L3, 200*1000}, - {L4, 100*1000}, + {L0, 1200*1000}, + {L1, 1100*1000}, + {L2, 1000*1000}, + {L3, 800*1000}, + {L4, 400*1000}, + {L5, 200*1000}, + {L6, 100*1000}, {0, CPUFREQ_TABLE_END}, }; @@ -93,33 +96,41 @@ struct s5pv210_dvs_conf { unsigned long int_volt; /* uV */ }; -const unsigned long arm_volt_max = 1350000; +const unsigned long arm_volt_max = 1550000; const unsigned long int_volt_max = 1250000; static struct s5pv210_dvs_conf dvs_conf[] = { [L0] = { + .arm_volt = 1350000, + .int_volt = 1175000, + }, + [L1] = { + .arm_volt = 1300000, + .int_volt = 1175000, + }, + [L2] = { .arm_volt = 1250000, .int_volt = 1100000, }, - [L1] = { + [L3] = { .arm_volt = 1200000, .int_volt = 1100000, }, - [L2] = { + [L4] = { .arm_volt = 1050000, .int_volt = 1100000, }, - [L3] = { + [L5] = { .arm_volt = 950000, .int_volt = 1100000, }, - [L4] = { + [L6] = { .arm_volt = 950000, .int_volt = 1000000, }, }; -static u32 clkdiv_val[5][11] = { +static u32 clkdiv_val[7][11] = { /* * Clock divider value for following * { APLL, A2M, HCLK_MSYS, PCLK_MSYS, @@ -127,19 +138,25 @@ static u32 clkdiv_val[5][11] = { * ONEDRAM, MFC, G3D } */ - /* L0 : [1000/200/100][166/83][133/66][200/200] */ + /* L0 : [1200/200/200/100][166/83][133/66][200/200] */ + {0, 5, 5, 1, 3, 1, 4, 1, 3, 0, 0}, + + /* L1 : [1100/200/200/100][166/83][133/66][200/200] */ + {0, 4, 4, 1, 3, 1, 4, 1, 3, 0, 0}, + + /* L2 : [1000/200/100][166/83][133/66][200/200] */ {0, 4, 4, 1, 3, 1, 4, 1, 3, 0, 0}, - /* L1 : [800/200/100][166/83][133/66][200/200] */ + /* L3 : [800/200/100][166/83][133/66][200/200] */ {0, 3, 3, 1, 3, 1, 4, 1, 3, 0, 0}, - /* L2 : [400/200/100][166/83][133/66][200/200] */ + /* L4 : [400/200/100][166/83][133/66][200/200] */ {1, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0}, - /* L3 : [200/200/100][166/83][133/66][200/200] */ + /* L5 : [200/200/100][166/83][133/66][200/200] */ {3, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0}, - /* L4 : [100/100/100][83/83][66/66][100/100] */ + /* L6 : [100/100/100][83/83][66/66][100/100] */ {7, 7, 0, 0, 7, 0, 9, 0, 7, 0, 0}, }; @@ -260,11 +277,11 @@ static int s5pv210_target(struct cpufreq_policy *policy, cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); /* Check if there need to change PLL */ - if ((index == L0) || (priv_index == L0)) + if ((index <= L2) || (priv_index <= L2)) pll_changing = 1; /* Check if there need to change System bus clock */ - if ((index == L4) || (priv_index == L4)) + if ((index == L6) || (priv_index == L6)) bus_speed_changing = 1; if (bus_speed_changing) { @@ -273,11 +290,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, * temporary clock while changing divider. * expected clock is 83Mhz : 7.8usec/(1/83Mhz) = 0x287 */ - if (pll_changing) - s5pv210_set_refresh(DMC1, 83000); - else - s5pv210_set_refresh(DMC1, 100000); - + s5pv210_set_refresh(DMC1, 100000); s5pv210_set_refresh(DMC0, 83000); } @@ -363,7 +376,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, /* ARM MCS value changed */ reg = __raw_readl(S5P_ARM_MCS_CON); reg &= ~0x3; - if (index >= L3) + if (index >= L6) reg |= 0x3; else reg |= 0x1; @@ -380,8 +393,10 @@ static int s5pv210_target(struct cpufreq_policy *policy, * 6-2. Wait untile the PLL is locked */ if (index == L0) - __raw_writel(APLL_VAL_1000, S5P_APLL_CON); - else + __raw_writel(APLL_VAL_1200, S5P_APLL_CON); + else if (index == L1) + __raw_writel(APLL_VAL_1100, S5P_APLL_CON); + else __raw_writel(APLL_VAL_800, S5P_APLL_CON); do { @@ -452,7 +467,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, } while (reg & (1 << 15)); /* Reconfigure DRAM refresh counter value */ - if (index != L4) { + if (index != L6) { /* * DMC0 : 166Mhz * DMC1 : 200Mhz @@ -558,7 +573,11 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = 40000; - return cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table); + cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table); + /* set default min and max policies to safe speeds */ + policy->max = 1000000; + policy->min = 200000; + return 0; } static int s5pv210_cpufreq_notifier_event(struct notifier_block *this, @@ -602,6 +621,7 @@ static struct cpufreq_driver s5pv210_driver = { .get = s5pv210_getspeed, .init = s5pv210_cpu_init, .name = "s5pv210", + .attr = s5pv210_cpufreq_attr, #ifdef CONFIG_PM .suspend = s5pv210_cpufreq_suspend, .resume = s5pv210_cpufreq_resume, diff --git a/arch/arm/mach-s5pv210/include/mach/cpu-freq-v210.h b/arch/arm/mach-s5pv210/include/mach/cpu-freq-v210.h index 8274a01e4ce..449c75321b4 100644 --- a/arch/arm/mach-s5pv210/include/mach/cpu-freq-v210.h +++ b/arch/arm/mach-s5pv210/include/mach/cpu-freq-v210.h @@ -26,6 +26,12 @@ struct s5pv210_cpufreq_data { unsigned int size; }; +/* Make sure we have the scaling_available_freqs sysfs file */ +static struct freq_attr *s5pv210_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + extern void s5pv210_cpufreq_set_platdata(struct s5pv210_cpufreq_data *pdata); #endif /* __ASM_ARCH_CPU_FREQ_H */ diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c index 7341e76afd6..2c3286d93f3 100755 --- a/arch/arm/mach-s5pv210/mach-herring.c +++ b/arch/arm/mach-s5pv210/mach-herring.c @@ -710,7 +710,7 @@ static struct regulator_init_data herring_buck1_data = { .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, .state_mem = { - .uV = 1250000, + .uV = 1472000, .mode = REGULATOR_MODE_NORMAL, .disabled = 1, }, @@ -728,7 +728,7 @@ static struct regulator_init_data herring_buck2_data = { .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, .state_mem = { - .uV = 1100000, + .uV = 1250000, .mode = REGULATOR_MODE_NORMAL, .disabled = 1, }, From c0e689d923be363f250a26efd21b5d2fe23d7b0f Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Sat, 11 Feb 2012 12:24:52 +0100 Subject: [PATCH 0835/4025] Change and optimize colors to avoid flickering at on/off --- drivers/video/samsung/s3cfb_tl2796.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/video/samsung/s3cfb_tl2796.c b/drivers/video/samsung/s3cfb_tl2796.c index 300798184b5..b491bd7ad54 100755 --- a/drivers/video/samsung/s3cfb_tl2796.c +++ b/drivers/video/samsung/s3cfb_tl2796.c @@ -77,7 +77,7 @@ struct s5p_lcd *lcd_; u32 original_color_adj_mults[3]; unsigned int panel_config_sequence = 0; -int hacky_v1_offset[3] = {-14, -17, -18}; +u32 hacky_v1_offset[3] = {0, 0, 0}; static const u16 s6e63m0_SEQ_ETC_SETTING_SAMSUNG[] = { /* ETC Condition Set Command */ @@ -278,7 +278,7 @@ static void setup_gamma_regs(struct s5p_lcd *lcd, u16 gamma_regs[]) // terrible shameful hack allowing to get back standard // colors without fixing the real thing properly (gamma table) // it consist on a simple (negative) offset applied on v0 - gamma_regs[c] = ((adj + hacky_v1_offset[c]) > 0 && (adj <=255)) ? (adj + hacky_v1_offset[c]) | 0x100 : adj | 0x100; + gamma_regs[c] = (adj > hacky_v1_offset[c] && (adj <=255)) ? (adj - hacky_v1_offset[c]) | 0x100 : adj | 0x100; #else gamma_regs[c] = adj | 0x100; #endif @@ -991,13 +991,13 @@ static ssize_t panel_config_sequence_store(struct device *dev, struct device_att static ssize_t red_v1_offset_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", hacky_v1_offset[0]); + return sprintf(buf, "%u\n", hacky_v1_offset[0]); } static ssize_t red_v1_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - int value; - if (sscanf(buf, "%d", &value) == 1) + u32 value; + if (sscanf(buf, "%u", &value) == 1) { hacky_v1_offset[0] = value; update_brightness(lcd_); @@ -1007,13 +1007,13 @@ static ssize_t red_v1_offset_store(struct device *dev, struct device_attribute * static ssize_t green_v1_offset_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", hacky_v1_offset[1]); + return sprintf(buf, "%u\n", hacky_v1_offset[1]); } static ssize_t green_v1_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - int value; - if (sscanf(buf, "%d", &value) == 1) + u32 value; + if (sscanf(buf, "%u", &value) == 1) { hacky_v1_offset[1] = value; update_brightness(lcd_); @@ -1023,13 +1023,13 @@ static ssize_t green_v1_offset_store(struct device *dev, struct device_attribute static ssize_t blue_v1_offset_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%d\n", hacky_v1_offset[2]); + return sprintf(buf, "%u\n", hacky_v1_offset[2]); } static ssize_t blue_v1_offset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { int value; - if (sscanf(buf, "%d", &value) == 1) + if (sscanf(buf, "%u", &value) == 1) { hacky_v1_offset[2] = value; update_brightness(lcd_); @@ -1079,7 +1079,7 @@ static struct attribute_group voodoo_color_group = { static struct miscdevice voodoo_color_device = { .minor = MISC_DYNAMIC_MINOR, - .name = "voodoo_color", + .name = "samoled_color", }; #endif From 7e9ea84d44cbe5dd65a9e24db9135cdfe8f4f9b8 Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Fri, 13 Jan 2012 15:22:30 +0100 Subject: [PATCH 0836/4025] Rename voodoo sound control to default chip name --- sound/soc/codecs/wm8994_voodoo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm8994_voodoo.c b/sound/soc/codecs/wm8994_voodoo.c index 750702f950a..15f097c8dc5 100644 --- a/sound/soc/codecs/wm8994_voodoo.c +++ b/sound/soc/codecs/wm8994_voodoo.c @@ -1593,13 +1593,13 @@ static struct attribute_group voodoo_sound_control_group = { static struct miscdevice voodoo_sound_device = { .minor = MISC_DYNAMIC_MINOR, - .name = "voodoo_sound", + .name = "wm8994_sound", }; #ifndef MODULE static struct miscdevice voodoo_sound_control_device = { .minor = MISC_DYNAMIC_MINOR, - .name = "voodoo_sound_control", + .name = "wm8994_sound_control", }; #endif From d0d399a8e31343f495c9c0878c07b66530f6a093 Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Sun, 8 Jan 2012 18:33:20 +0100 Subject: [PATCH 0837/4025] Add option to remomve scaling colors --- arch/arm/mach-s5pv210/herring-panel.c | 2 ++ drivers/video/samsung/Kconfig | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/arch/arm/mach-s5pv210/herring-panel.c b/arch/arm/mach-s5pv210/herring-panel.c index ed619c23e12..e84d6e8debe 100755 --- a/arch/arm/mach-s5pv210/herring-panel.c +++ b/arch/arm/mach-s5pv210/herring-panel.c @@ -357,6 +357,7 @@ struct s5p_panel_data herring_panel_data = { 0x0b8, 0x0fc, }, +#ifdef CONFIG_TL2796_CONVERT_COLORS_RES .color_adj = { /* Convert from 8500K to D65, assuming: * Rx 0.66950, Ry 0.33100 @@ -370,6 +371,7 @@ struct s5p_panel_data herring_panel_data = { }, .rshift = 31, }, +#endif .gamma_adj_points = &gamma_adj_points, .gamma_table = gamma_table, diff --git a/drivers/video/samsung/Kconfig b/drivers/video/samsung/Kconfig index 7d389b926e7..5a1122b2ff1 100755 --- a/drivers/video/samsung/Kconfig +++ b/drivers/video/samsung/Kconfig @@ -159,6 +159,13 @@ config FB_S3C_MDNIE ---help--- This enables support for Samsung MDNIE feature +config TL2796_CONVERT_COLORS_RES + bool "TL2796 6500K Colors" + depends on FB_S3C_TL2796 + default y + ---help--- + This scales from 8500K colors to 6500K colors + config FB_S3C_CMC623 bool "Samsung CMC623" depends on FB_S3C && (ARCH_S5PV210) From 04e99107b0db07334c670cc4b4fbd43cd007cd9a Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Wed, 11 Jan 2012 15:14:04 +0100 Subject: [PATCH 0838/4025] Dissable fimc clock on resume Only if is not fimc 0 --- drivers/media/video/samsung/fimc/fimc_dev.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/media/video/samsung/fimc/fimc_dev.c b/drivers/media/video/samsung/fimc/fimc_dev.c index 1441367d749..39bb53012a0 100644 --- a/drivers/media/video/samsung/fimc/fimc_dev.c +++ b/drivers/media/video/samsung/fimc/fimc_dev.c @@ -1619,12 +1619,14 @@ int fimc_resume(struct platform_device *pdev) { struct fimc_control *ctrl; struct s3c_platform_fimc *pdata; - int id = pdev->id; + int in_use, id = pdev->id; ctrl = get_fimc_ctrl(id); pdata = to_fimc_plat(ctrl->dev); - if (atomic_read(&ctrl->in_use)) + in_use = atomic_read(&ctrl->in_use); + + if (in_use) fimc_clk_en(ctrl, true); if (ctrl->out) @@ -1635,6 +1637,9 @@ int fimc_resume(struct platform_device *pdev) else ctrl->status = FIMC_STREAMOFF; + if (in_use && 0 != ctrl->id) + fimc_clk_en(ctrl, false); + return 0; } #else From 77cfd64f6becfb4c49fe1d7f7adabc8818325fd4 Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Wed, 11 Jan 2012 16:03:16 +0100 Subject: [PATCH 0839/4025] Rebuild CPU overclock code --- arch/arm/mach-s5pv210/cpufreq.c | 102 ++++++++++-------- .../mach-s5pv210/include/mach/cpu-freq-v210.h | 6 -- arch/arm/mach-s5pv210/mach-herring.c | 30 ++++-- 3 files changed, 80 insertions(+), 58 deletions(-) mode change 100755 => 100644 arch/arm/mach-s5pv210/cpufreq.c diff --git a/arch/arm/mach-s5pv210/cpufreq.c b/arch/arm/mach-s5pv210/cpufreq.c old mode 100755 new mode 100644 index 2c641b39723..0e5150cc53d --- a/arch/arm/mach-s5pv210/cpufreq.c +++ b/arch/arm/mach-s5pv210/cpufreq.c @@ -32,11 +32,12 @@ static struct clk *dmc1_clk; static struct cpufreq_freqs freqs; static DEFINE_MUTEX(set_freq_lock); -/* APLL M,P,S values for 1.2G/800Mhz */ -#define APLL_VAL_1200 ((1 << 31) | (150 << 16) | (3 << 8) | 1) +/* APLL M,P,S values for 1.4GHz/1.2GHz/1.0GHz/800MHz */ +#define APLL_VAL_1400 ((1 << 31) | (175 << 16) | (3 << 8) | 1) +#define APLL_VAL_1200 ((1 << 31) | (150 << 16) | (3 << 8) | 1) #define APLL_VAL_1000 ((1 << 31) | (125 << 16) | (3 << 8) | 1) -#define APLL_VAL_1100 ((1 << 31) | (275 << 16) | (6 << 8) | 1) #define APLL_VAL_800 ((1 << 31) | (100 << 16) | (3 << 8) | 1) + #define SLEEP_FREQ (800 * 1000) /* Use 800MHz when entering sleep */ /* @@ -63,7 +64,7 @@ struct dram_conf { static struct dram_conf s5pv210_dram_conf[2]; enum perf_level { - L0, L1, L2, L3, L4, L5, L6, + L0, L1, L2, L3, L4, L5, L6 }; enum s5pv210_mem_type { @@ -78,8 +79,8 @@ enum s5pv210_dmc_port { }; static struct cpufreq_frequency_table s5pv210_freq_table[] = { - {L0, 1200*1000}, - {L1, 1100*1000}, + {L0, 1400*1000}, + {L1, 1200*1000}, {L2, 1000*1000}, {L3, 800*1000}, {L4, 400*1000}, @@ -88,6 +89,17 @@ static struct cpufreq_frequency_table s5pv210_freq_table[] = { {0, CPUFREQ_TABLE_END}, }; +static u32 sAPLL_confs[] = { + APLL_VAL_1400, + APLL_VAL_1200, + APLL_VAL_1000, + APLL_VAL_800, + APLL_VAL_800, + APLL_VAL_800, + APLL_VAL_800, + APLL_VAL_800, +}; + static struct regulator *arm_regulator; static struct regulator *internal_regulator; @@ -96,17 +108,22 @@ struct s5pv210_dvs_conf { unsigned long int_volt; /* uV */ }; -const unsigned long arm_volt_max = 1550000; +#ifdef CONFIG_CUSTOM_VOLTAGE +unsigned long arm_volt_max = 1450000; +unsigned long int_volt_max = 1250000; +#else +const unsigned long arm_volt_max = 1450000; const unsigned long int_volt_max = 1250000; +#endif static struct s5pv210_dvs_conf dvs_conf[] = { [L0] = { - .arm_volt = 1350000, - .int_volt = 1175000, + .arm_volt = 1450000, + .int_volt = 1250000, }, [L1] = { - .arm_volt = 1300000, - .int_volt = 1175000, + .arm_volt = 1350000, + .int_volt = 1150000, }, [L2] = { .arm_volt = 1250000, @@ -138,11 +155,11 @@ static u32 clkdiv_val[7][11] = { * ONEDRAM, MFC, G3D } */ - /* L0 : [1200/200/200/100][166/83][133/66][200/200] */ - {0, 5, 5, 1, 3, 1, 4, 1, 3, 0, 0}, + /* L0 : [1400/200/100][166/83][133/66][200/200] */ + {0, 6, 6, 1, 3, 1, 4, 1, 3, 0, 0}, - /* L1 : [1100/200/200/100][166/83][133/66][200/200] */ - {0, 4, 4, 1, 3, 1, 4, 1, 3, 0, 0}, + /* L1 : [1200/200/100][166/83][133/66][200/200] */ + {0, 5, 5, 1, 3, 1, 4, 1, 3, 0, 0}, /* L2 : [1000/200/100][166/83][133/66][200/200] */ {0, 4, 4, 1, 3, 1, 4, 1, 3, 0, 0}, @@ -213,7 +230,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int relation) { unsigned long reg; - unsigned int index, priv_index; + unsigned int index; unsigned int pll_changing = 0; unsigned int bus_speed_changing = 0; unsigned int arm_volt, int_volt; @@ -249,13 +266,6 @@ static int s5pv210_target(struct cpufreq_policy *policy, if (freqs.new == freqs.old) goto out; - /* Finding current running level index */ - if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, - freqs.old, relation, &priv_index)) { - ret = -EINVAL; - goto out; - } - arm_volt = dvs_conf[index].arm_volt; int_volt = dvs_conf[index].int_volt; @@ -277,11 +287,11 @@ static int s5pv210_target(struct cpufreq_policy *policy, cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); /* Check if there need to change PLL */ - if ((index <= L2) || (priv_index <= L2)) + if ((index <= L2) || (freqs.old >= s5pv210_freq_table[L2].frequency)) pll_changing = 1; /* Check if there need to change System bus clock */ - if ((index == L6) || (priv_index == L6)) + if ((index == L6) || (freqs.old == s5pv210_freq_table[L6].frequency)) bus_speed_changing = 1; if (bus_speed_changing) { @@ -290,7 +300,11 @@ static int s5pv210_target(struct cpufreq_policy *policy, * temporary clock while changing divider. * expected clock is 83Mhz : 7.8usec/(1/83Mhz) = 0x287 */ - s5pv210_set_refresh(DMC1, 100000); + if (pll_changing) + s5pv210_set_refresh(DMC1, 83000); + else + s5pv210_set_refresh(DMC1, 100000); + s5pv210_set_refresh(DMC0, 83000); } @@ -331,7 +345,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, } while (reg & ((1 << 7) | (1 << 3))); /* - * 3. DMC1 refresh count for 133Mhz if (index == L4) is + * 3. DMC1 refresh count for 133Mhz if (index == L6) is * true refresh counter is already programed in upper * code. 0x287@83Mhz */ @@ -376,7 +390,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, /* ARM MCS value changed */ reg = __raw_readl(S5P_ARM_MCS_CON); reg &= ~0x3; - if (index >= L6) + if (index >= L5) reg |= 0x3; else reg |= 0x1; @@ -392,12 +406,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, * 6-1. Set PMS values * 6-2. Wait untile the PLL is locked */ - if (index == L0) - __raw_writel(APLL_VAL_1200, S5P_APLL_CON); - else if (index == L1) - __raw_writel(APLL_VAL_1100, S5P_APLL_CON); - else - __raw_writel(APLL_VAL_800, S5P_APLL_CON); + __raw_writel(sAPLL_confs[index], S5P_APLL_CON); do { reg = __raw_readl(S5P_APLL_CON); @@ -445,7 +454,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, /* * 10. DMC1 refresh counter - * L4 : DMC1 = 100Mhz 7.8us/(1/100) = 0x30c + * L6 : DMC1 = 100Mhz 7.8us/(1/100) = 0x30c * Others : DMC1 = 200Mhz 7.8us/(1/200) = 0x618 */ if (!bus_speed_changing) @@ -453,7 +462,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, } /* - * L4 level need to change memory bus speed, hence onedram clock divier + * L6 level need to change memory bus speed, hence onedram clock divier * and memory refresh parameter should be changed */ if (bus_speed_changing) { @@ -529,6 +538,8 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) { unsigned long mem_type; + int ret; + cpu_clk = clk_get(NULL, "armclk"); if (IS_ERR(cpu_clk)) return PTR_ERR(cpu_clk); @@ -573,11 +584,12 @@ static int __init s5pv210_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = 40000; - cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table); - /* set default min and max policies to safe speeds */ - policy->max = 1000000; - policy->min = 200000; - return 0; + ret = cpufreq_frequency_table_cpuinfo(policy, s5pv210_freq_table); + + if (!ret) + policy->max = 1000000; + + return ret; } static int s5pv210_cpufreq_notifier_event(struct notifier_block *this, @@ -608,12 +620,18 @@ static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this, ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, DISABLE_FURTHER_CPUFREQ); + if (ret < 0) return NOTIFY_BAD; return NOTIFY_DONE; } +static struct freq_attr *s5pv210_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + static struct cpufreq_driver s5pv210_driver = { .flags = CPUFREQ_STICKY, .verify = s5pv210_verify_speed, @@ -621,7 +639,7 @@ static struct cpufreq_driver s5pv210_driver = { .get = s5pv210_getspeed, .init = s5pv210_cpu_init, .name = "s5pv210", - .attr = s5pv210_cpufreq_attr, + .attr = s5pv210_cpufreq_attr, #ifdef CONFIG_PM .suspend = s5pv210_cpufreq_suspend, .resume = s5pv210_cpufreq_resume, diff --git a/arch/arm/mach-s5pv210/include/mach/cpu-freq-v210.h b/arch/arm/mach-s5pv210/include/mach/cpu-freq-v210.h index 449c75321b4..8274a01e4ce 100644 --- a/arch/arm/mach-s5pv210/include/mach/cpu-freq-v210.h +++ b/arch/arm/mach-s5pv210/include/mach/cpu-freq-v210.h @@ -26,12 +26,6 @@ struct s5pv210_cpufreq_data { unsigned int size; }; -/* Make sure we have the scaling_available_freqs sysfs file */ -static struct freq_attr *s5pv210_cpufreq_attr[] = { - &cpufreq_freq_attr_scaling_available_freqs, - NULL, -}; - extern void s5pv210_cpufreq_set_platdata(struct s5pv210_cpufreq_data *pdata); #endif /* __ASM_ARCH_CPU_FREQ_H */ diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c index 2c3286d93f3..b12da951f4f 100755 --- a/arch/arm/mach-s5pv210/mach-herring.c +++ b/arch/arm/mach-s5pv210/mach-herring.c @@ -295,7 +295,7 @@ static struct s3cfb_lcd s6e63m0 = { .p_width = 52, .p_height = 86, .bpp = 24, - .freq = 60, + .freq = 72, .timing = { .h_fp = 16, @@ -321,14 +321,14 @@ static struct s3cfb_lcd nt35580 = { .p_width = 52, .p_height = 86, .bpp = 24, - .freq = 60, + .freq = 72, .timing = { - .h_fp = 10, - .h_bp = 20, - .h_sw = 10, - .v_fp = 6, + .h_fp = 16, + .h_bp = 16, + .h_sw = 2, + .v_fp = 28, .v_fpe = 1, - .v_bp = 8, + .v_bp = 1, .v_bpe = 1, .v_sw = 2, }, @@ -346,7 +346,7 @@ static struct s3cfb_lcd r61408 = { .p_width = 52, .p_height = 86, .bpp = 24, - .freq = 60, + .freq = 72, .timing = { .h_fp = 100, .h_bp = 2, @@ -432,6 +432,14 @@ static struct s5p_media_device herring_media_devs[] = { #ifdef CONFIG_CPU_FREQ static struct s5pv210_cpufreq_voltage smdkc110_cpufreq_volt[] = { { + .freq = 1400000, + .varm = 1450000, + .vint = 1250000, + }, { + .freq = 1200000, + .varm = 1350000, + .vint = 1150000, + }, { .freq = 1000000, .varm = 1275000, .vint = 1100000, @@ -705,12 +713,12 @@ static struct regulator_init_data herring_buck1_data = { .constraints = { .name = "VDD_ARM", .min_uV = 750000, - .max_uV = 1500000, + .max_uV = 1600000, .apply_uV = 1, .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | REGULATOR_CHANGE_STATUS, .state_mem = { - .uV = 1472000, + .uV = 1600000, .mode = REGULATOR_MODE_NORMAL, .disabled = 1, }, @@ -2015,12 +2023,14 @@ static void touch_keypad_gpio_sleep(int onoff) * reconfigure gpio to activate touchkey controller vdd in sleep mode */ s3c_gpio_slp_cfgpin(_3_GPIO_TOUCH_EN, S3C_GPIO_SLP_OUT1); + //s3c_gpio_slp_setpull_updown(_3_GPIO_TOUCH_EN, S3C_GPIO_PULL_NONE); } else { /* * reconfigure gpio to deactivate touchkey vdd in sleep mode, * this is the default */ s3c_gpio_slp_cfgpin(_3_GPIO_TOUCH_EN, S3C_GPIO_SLP_OUT0); + //s3c_gpio_slp_setpull_updown(_3_GPIO_TOUCH_EN, S3C_GPIO_PULL_NONE); } } From 99067d691614385f824b42f9a02da9708e66dbb6 Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Fri, 3 Feb 2012 15:37:17 -0800 Subject: [PATCH 0840/4025] readahead: fix pipeline break caused by block plug commit 3deaa7190a8da38453c4fabd9dec7f66d17fff67 upstream. Herbert Poetzl reported a performance regression since 2.6.39. The test is a simple dd read, but with big block size. The reason is: T1: ra (A, A+128k), (A+128k, A+256k) T2: lock_page for page A, submit the 256k T3: hit page A+128K, ra (A+256k, A+384). the range isn't submitted because of plug and there isn't any lock_page till we hit page A+256k because all pages from A to A+256k is in memory T4: hit page A+256k, ra (A+384, A+ 512). Because of plug, the range isn't submitted again. T5: lock_page A+256k, so (A+256k, A+512k) will be submitted. The task is waitting for (A+256k, A+512k) finish. There is no request to disk in T3 and T4, so readahead pipeline breaks. We really don't need block plug for generic_file_aio_read() for buffered I/O. The readahead already has plug and has fine grained control when I/O should be submitted. Deleting plug for buffered I/O fixes the regression. One side effect is plug makes the request size 256k, the size is 128k without it. This is because default ra size is 128k and not a reason we need plug here. Vivek said: : We submit some readahead IO to device request queue but because of nested : plug, queue never gets unplugged. When read logic reaches a page which is : not in page cache, it waits for page to be read from the disk : (lock_page_killable()) and that time we flush the plug list. : : So effectively read ahead logic is kind of broken in parts because of : nested plugging. Removing top level plug (generic_file_aio_read()) for : buffered reads, will allow unplugging queue earlier for readahead. Signed-off-by: Shaohua Li Signed-off-by: Wu Fengguang Reported-by: Herbert Poetzl Tested-by: Eric Dumazet Cc: Christoph Hellwig Cc: Jens Axboe Cc: Vivek Goyal Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/filemap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mm/filemap.c b/mm/filemap.c index 3c981baadb7..b7d860390f3 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1379,15 +1379,12 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long seg = 0; size_t count; loff_t *ppos = &iocb->ki_pos; - struct blk_plug plug; count = 0; retval = generic_segment_checks(iov, &nr_segs, &count, VERIFY_WRITE); if (retval) return retval; - blk_start_plug(&plug); - /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */ if (filp->f_flags & O_DIRECT) { loff_t size; @@ -1403,8 +1400,12 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, retval = filemap_write_and_wait_range(mapping, pos, pos + iov_length(iov, nr_segs) - 1); if (!retval) { + struct blk_plug plug; + + blk_start_plug(&plug); retval = mapping->a_ops->direct_IO(READ, iocb, iov, pos, nr_segs); + blk_finish_plug(&plug); } if (retval > 0) { *ppos = pos + retval; @@ -1460,7 +1461,6 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov, break; } out: - blk_finish_plug(&plug); return retval; } EXPORT_SYMBOL(generic_file_aio_read); From 3fe10cf8e23ed6e32c09c05303df7e66abdb7e39 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 1 Feb 2012 12:05:41 +0100 Subject: [PATCH 0841/4025] ALSA: HDA: Fix duplicated output to more than one codec commit 54c2a89f60fd71b924d0f848ac892442951401a6 upstream. This typo caused the wrong codec's nid to be checked for wcaps type. As a result, sometimes speakers would duplicate the output sent to HDMI output. BugLink: https://bugs.launchpad.net/bugs/924320 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 21958518467..67d341fa7d1 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1328,7 +1328,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, for (i = 0; i < c->cvt_setups.used; i++) { p = snd_array_elem(&c->cvt_setups, i); if (!p->active && p->stream_tag == stream_tag && - get_wcaps_type(get_wcaps(codec, p->nid)) == type) + get_wcaps_type(get_wcaps(c, p->nid)) == type) p->dirty = 1; } } From 2cf7d6f29728c367ac742e7e17d89d8d9b6caeba Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 20 Jan 2012 12:19:43 +0000 Subject: [PATCH 0842/4025] ASoC: wm_hubs: Enable line out VMID buffer for single ended line outputs commit 77231abe55433aa17eca712718745275853fa66d upstream. For optimal performance the single ended line outputs require that the line output VMID buffer be enabled. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm_hubs.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 9e370d14ad8..1c2a47dcbea 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -589,6 +589,8 @@ SND_SOC_DAPM_INPUT("IN2RP:VXRP"), SND_SOC_DAPM_MICBIAS("MICBIAS2", WM8993_POWER_MANAGEMENT_1, 5, 0), SND_SOC_DAPM_MICBIAS("MICBIAS1", WM8993_POWER_MANAGEMENT_1, 4, 0), +SND_SOC_DAPM_SUPPLY("LINEOUT_VMID_BUF", WM8993_ANTIPOP1, 7, 0, NULL, 0), + SND_SOC_DAPM_MIXER("IN1L PGA", WM8993_POWER_MANAGEMENT_2, 6, 0, in1l_pga, ARRAY_SIZE(in1l_pga)), SND_SOC_DAPM_MIXER("IN1R PGA", WM8993_POWER_MANAGEMENT_2, 4, 0, @@ -794,9 +796,11 @@ static const struct snd_soc_dapm_route lineout1_diff_routes[] = { }; static const struct snd_soc_dapm_route lineout1_se_routes[] = { + { "LINEOUT1N Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT1N Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT1N Mixer", "Right Output Switch", "Right Output PGA" }, + { "LINEOUT1P Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT1P Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT1N Driver", NULL, "LINEOUT1N Mixer" }, @@ -813,9 +817,11 @@ static const struct snd_soc_dapm_route lineout2_diff_routes[] = { }; static const struct snd_soc_dapm_route lineout2_se_routes[] = { + { "LINEOUT2N Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT2N Mixer", "Left Output Switch", "Left Output PGA" }, { "LINEOUT2N Mixer", "Right Output Switch", "Right Output PGA" }, + { "LINEOUT2P Mixer", NULL, "LINEOUT_VMID_BUF" }, { "LINEOUT2P Mixer", "Right Output Switch", "Right Output PGA" }, { "LINEOUT2N Driver", NULL, "LINEOUT2N Mixer" }, From a2eeb4b984210336662a9ebdbecb96efd8823ff2 Mon Sep 17 00:00:00 2001 From: UK KIM Date: Sat, 28 Jan 2012 01:52:22 +0900 Subject: [PATCH 0843/4025] ASoC: wm_hubs: fix wrong bits for LINEOUT2 N/P mixer commit 114395c61ad2eb5a7a5cd163fcadb2414e48245a upstream. Signed-off-by: UK KIM Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm_hubs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 1c2a47dcbea..b85539482ec 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -568,8 +568,8 @@ SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0), }; static const struct snd_kcontrol_new line2n_mix[] = { -SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 6, 1, 0), -SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 5, 1, 0), +SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER2, 5, 1, 0), +SOC_DAPM_SINGLE("Right Output Switch", WM8993_LINE_MIXER2, 6, 1, 0), }; static const struct snd_kcontrol_new line2p_mix[] = { From 886d462b0c92357a2f0ca0fc19f5877efbb1f638 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 30 Jan 2012 20:21:42 +0100 Subject: [PATCH 0844/4025] ARM: 7306/1: vfp: flush thread hwstate before restoring context from sigframe commit 2af276dfb1722e97b190bd2e646b079a2aa674db upstream. Following execution of a signal handler, we currently restore the VFP context from the ucontext in the signal frame. This involves copying from the user stack into the current thread's vfp_hard_struct and then flushing the new data out to the hardware registers. This is problematic when using a preemptible kernel because we could be context switched whilst updating the vfp_hard_struct. If the current thread has made use of VFP since the last context switch, the VFP notifier will copy from the hardware registers into the vfp_hard_struct, overwriting any data that had been partially copied by the signal code. Disabling preemption across copy_from_user calls is a terrible idea, so instead we move the VFP thread flush *before* we update the vfp_hard_struct. Since the flushing is performed lazily, this has the effect of disabling VFP and clearing the CPU's VFP state pointer, therefore preventing the thread from being updated with stale data on the next context switch. Tested-by: Peter Maydell Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/signal.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 0340224cf73..9e617bd4a14 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -227,6 +227,8 @@ static int restore_vfp_context(struct vfp_sigframe __user *frame) if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE) return -EINVAL; + vfp_flush_hwstate(thread); + /* * Copy the floating point registers. There can be unused * registers see asm/hwcap.h for details. @@ -251,9 +253,6 @@ static int restore_vfp_context(struct vfp_sigframe __user *frame) __get_user_error(h->fpinst, &frame->ufp_exc.fpinst, err); __get_user_error(h->fpinst2, &frame->ufp_exc.fpinst2, err); - if (!err) - vfp_flush_hwstate(thread); - return err ? -EFAULT : 0; } From ae3939e12cc597be0ba28d5f3b3d8f158f2d6d70 Mon Sep 17 00:00:00 2001 From: Dave Martin Date: Mon, 30 Jan 2012 20:22:28 +0100 Subject: [PATCH 0845/4025] ARM: 7307/1: vfp: fix ptrace regset modification race commit 247f4993a5974e6759606c4d380748eecfd273ff upstream. In a preemptible kernel, vfp_set() can be preempted, causing the hardware VFP context to be switched while the thread vfp state is being read and modified. This leads to a race condition which can cause the thread vfp state to become corrupted if lazy VFP context save occurs due to preemption in between the time thread->vfpstate is read and the time the modified state is written back. This may occur if preemption occurs during the execution of a ptrace() call which modifies the VFP register state of a thread. Such instances should be very rare in most realistic scenarios -- none has been reported, so far as I am aware. Only uniprocessor systems should be affected, since VFP context save is not currently lazy in SMP kernels. The problem was introduced by my earlier patch migrating to use regsets to implement ptrace. This patch does a vfp_sync_hwstate() before reading thread->vfpstate, to make sure that the thread's VFP state is not live in the hardware registers while the registers are modified. Thanks to Will Deacon for spotting this. Signed-off-by: Dave Martin Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/ptrace.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 97260060bf2..7f1e1338e4d 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -719,10 +719,13 @@ static int vfp_set(struct task_struct *target, { int ret; struct thread_info *thread = task_thread_info(target); - struct vfp_hard_struct new_vfp = thread->vfpstate.hard; + struct vfp_hard_struct new_vfp; const size_t user_fpregs_offset = offsetof(struct user_vfp, fpregs); const size_t user_fpscr_offset = offsetof(struct user_vfp, fpscr); + vfp_sync_hwstate(thread); + new_vfp = thread->vfpstate.hard; + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &new_vfp.fpregs, user_fpregs_offset, @@ -743,7 +746,6 @@ static int vfp_set(struct task_struct *target, if (ret) return ret; - vfp_sync_hwstate(thread); thread->vfpstate.hard = new_vfp; vfp_flush_hwstate(thread); From e358073331debaab9e14b3139bc469184288aa48 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 30 Jan 2012 20:23:29 +0100 Subject: [PATCH 0846/4025] ARM: 7308/1: vfp: flush thread hwstate before copying ptrace registers commit 8130b9d7b9d858aa04ce67805e8951e3cb6e9b2f upstream. If we are context switched whilst copying into a thread's vfp_hard_struct then the partial copy may be corrupted by the VFP context switching code (see "ARM: vfp: flush thread hwstate before restoring context from sigframe"). This patch updates the ptrace VFP set code so that the thread state is flushed before the copy, therefore disabling VFP and preventing corruption from occurring. Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/ptrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 7f1e1338e4d..172ae01c26e 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -746,8 +746,8 @@ static int vfp_set(struct task_struct *target, if (ret) return ret; - thread->vfpstate.hard = new_vfp; vfp_flush_hwstate(thread); + thread->vfpstate.hard = new_vfp; return 0; } From 17f272d8e4349543de855ea63e4eea4a67a7abc5 Mon Sep 17 00:00:00 2001 From: Yegor Yefremov Date: Mon, 23 Jan 2012 08:32:23 +0100 Subject: [PATCH 0847/4025] ARM: OMAP2+: GPMC: fix device size setup commit 8ef5d844cc3a644ea6f7665932a4307e9fad01fa upstream. following statement can only change device size from 8-bit(0) to 16-bit(1), but not vice versa: regval |= GPMC_CONFIG1_DEVICESIZE(wval); so as this field has 1 reserved bit, that could be used in future, just clear both bits and then OR with the desired value Signed-off-by: Yegor Yefremov Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/gpmc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c index 130034bf01d..dfffbbf4c00 100644 --- a/arch/arm/mach-omap2/gpmc.c +++ b/arch/arm/mach-omap2/gpmc.c @@ -528,7 +528,13 @@ int gpmc_cs_configure(int cs, int cmd, int wval) case GPMC_CONFIG_DEV_SIZE: regval = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); + + /* clear 2 target bits */ + regval &= ~GPMC_CONFIG1_DEVICESIZE(3); + + /* set the proper value */ regval |= GPMC_CONFIG1_DEVICESIZE(wval); + gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, regval); break; From 344d390bcb4c796b4b7797395cfc07e2c43d935d Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Fri, 3 Feb 2012 15:37:15 -0800 Subject: [PATCH 0848/4025] drivers/tty/vt/vt_ioctl.c: fix KDFONTOP 32bit compatibility layer commit cbcb8346054073d000ecac324763372d6abd44ac upstream. KDFONTOP(GET) currently fails with EIO when being run in a 32bit userland with a 64bit kernel if the font width is not 8. This is because of the setting of the KD_FONT_FLAG_OLD flag, which makes con_font_get return EIO in such case. This flag should *not* be set for KDFONTOP, since it's actually the whole point of this flag (see comment in con_font_set for instance). Signed-off-by: Samuel Thibault Reviewed-by: Arnd Bergmann Cc: Arthur Taylor Cc: Jiri Slaby Cc: Jiri Olsa Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt_ioctl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 5e096f43bce..65447c5f91d 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -1463,7 +1463,6 @@ compat_kdfontop_ioctl(struct compat_console_font_op __user *fontop, if (!perm && op->op != KD_FONT_OP_GET) return -EPERM; op->data = compat_ptr(((struct compat_console_font_op *)op)->data); - op->flags |= KD_FONT_FLAG_OLD; i = con_font_op(vc, op); if (i) return i; From 401f63716ca0bca1728e55ccf2132fb3785cf5da Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 31 Jan 2012 17:14:38 +0100 Subject: [PATCH 0849/4025] proc: mem_release() should check mm != NULL commit 71879d3cb3dd8f2dfdefb252775c1b3ea04a3dd4 upstream. mem_release() can hit mm == NULL, add the necessary check. Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/proc/base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 7b28f27ad80..b3e298f2942 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -886,8 +886,8 @@ loff_t mem_lseek(struct file *file, loff_t offset, int orig) static int mem_release(struct inode *inode, struct file *file) { struct mm_struct *mm = file->private_data; - - mmput(mm); + if (mm) + mmput(mm); return 0; } From b49767a65a6454f7d546068a785e25dbb0eabbcd Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 31 Jan 2012 17:14:54 +0100 Subject: [PATCH 0850/4025] proc: unify mem_read() and mem_write() commit 572d34b946bae070debd42db1143034d9687e13f upstream. No functional changes, cleanup and preparation. mem_read() and mem_write() are very similar. Move this code into the new common helper, mem_rw(), which takes the additional "int write" argument. Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/proc/base.c | 90 ++++++++++++++++++-------------------------------- 1 file changed, 32 insertions(+), 58 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index b3e298f2942..49b82beec31 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -782,57 +782,13 @@ static int mem_open(struct inode* inode, struct file* file) return 0; } -static ssize_t mem_read(struct file * file, char __user * buf, - size_t count, loff_t *ppos) +static ssize_t mem_rw(struct file *file, char __user *buf, + size_t count, loff_t *ppos, int write) { - int ret; - char *page; - unsigned long src = *ppos; struct mm_struct *mm = file->private_data; - - if (!mm) - return 0; - - page = (char *)__get_free_page(GFP_TEMPORARY); - if (!page) - return -ENOMEM; - - ret = 0; - - while (count > 0) { - int this_len, retval; - - this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; - retval = access_remote_vm(mm, src, page, this_len, 0); - if (!retval) { - if (!ret) - ret = -EIO; - break; - } - - if (copy_to_user(buf, page, retval)) { - ret = -EFAULT; - break; - } - - ret += retval; - src += retval; - buf += retval; - count -= retval; - } - *ppos = src; - - free_page((unsigned long) page); - return ret; -} - -static ssize_t mem_write(struct file * file, const char __user *buf, - size_t count, loff_t *ppos) -{ - int copied; + unsigned long addr = *ppos; + ssize_t copied; char *page; - unsigned long dst = *ppos; - struct mm_struct *mm = file->private_data; if (!mm) return 0; @@ -843,30 +799,48 @@ static ssize_t mem_write(struct file * file, const char __user *buf, copied = 0; while (count > 0) { - int this_len, retval; + int this_len = min_t(int, count, PAGE_SIZE); - this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; - if (copy_from_user(page, buf, this_len)) { + if (write && copy_from_user(page, buf, this_len)) { copied = -EFAULT; break; } - retval = access_remote_vm(mm, dst, page, this_len, 1); - if (!retval) { + + this_len = access_remote_vm(mm, addr, page, this_len, write); + if (!this_len) { if (!copied) copied = -EIO; break; } - copied += retval; - buf += retval; - dst += retval; - count -= retval; + + if (!write && copy_to_user(buf, page, this_len)) { + copied = -EFAULT; + break; + } + + buf += this_len; + addr += this_len; + copied += this_len; + count -= this_len; } - *ppos = dst; + *ppos = addr; free_page((unsigned long) page); return copied; } +static ssize_t mem_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + return mem_rw(file, buf, count, ppos, 0); +} + +static ssize_t mem_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + return mem_rw(file, (char __user*)buf, count, ppos, 1); +} + loff_t mem_lseek(struct file *file, loff_t offset, int orig) { switch (orig) { From 0053779e04bbfabe31287245d89ad10bb66e758a Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 31 Jan 2012 17:15:11 +0100 Subject: [PATCH 0851/4025] proc: make sure mem_open() doesn't pin the target's memory commit 6d08f2c7139790c268820a2e590795cb8333181a upstream. Once /proc/pid/mem is opened, the memory can't be released until mem_release() even if its owner exits. Change mem_open() to do atomic_inc(mm_count) + mmput(), this only pins mm_struct. Change mem_rw() to do atomic_inc_not_zero(mm_count) before access_remote_vm(), this verifies that this mm is still alive. I am not sure what should mem_rw() return if atomic_inc_not_zero() fails. With this patch it returns zero to match the "mm == NULL" case, may be it should return -EINVAL like it did before e268337d. Perhaps it makes sense to add the additional fatal_signal_pending() check into the main loop, to ensure we do not hold this memory if the target task was oom-killed. Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/proc/base.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 49b82beec31..22794e8ab99 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -775,6 +775,13 @@ static int mem_open(struct inode* inode, struct file* file) if (IS_ERR(mm)) return PTR_ERR(mm); + if (mm) { + /* ensure this mm_struct can't be freed */ + atomic_inc(&mm->mm_count); + /* but do not pin its memory */ + mmput(mm); + } + /* OK to pass negative loff_t, we can catch out-of-range */ file->f_mode |= FMODE_UNSIGNED_OFFSET; file->private_data = mm; @@ -798,6 +805,9 @@ static ssize_t mem_rw(struct file *file, char __user *buf, return -ENOMEM; copied = 0; + if (!atomic_inc_not_zero(&mm->mm_users)) + goto free; + while (count > 0) { int this_len = min_t(int, count, PAGE_SIZE); @@ -825,6 +835,8 @@ static ssize_t mem_rw(struct file *file, char __user *buf, } *ppos = addr; + mmput(mm); +free: free_page((unsigned long) page); return copied; } @@ -861,7 +873,7 @@ static int mem_release(struct inode *inode, struct file *file) { struct mm_struct *mm = file->private_data; if (mm) - mmput(mm); + mmdrop(mm); return 0; } From 914dcd6a7120a034c515605ca509cb7e6767f52c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 26 Jan 2012 22:05:58 +0100 Subject: [PATCH 0852/4025] firewire: ohci: add reset packet quirk for SB Audigy commit d1bb399ad03c11e792f6dea198d3b1e23061f094 upstream. The Audigy's SB1394 controller is actually from Texas Instruments and has the same bus reset packet generation bug, so it needs the same quirk entry. Signed-off-by: Clemens Ladisch Signed-off-by: Stefan Richter Signed-off-by: Greg Kroah-Hartman --- drivers/firewire/ohci.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index ee76c8ec72f..f2dfd4c49f8 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -262,6 +262,7 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card) static char ohci_driver_name[] = KBUILD_MODNAME; #define PCI_DEVICE_ID_AGERE_FW643 0x5901 +#define PCI_DEVICE_ID_CREATIVE_SB1394 0x4001 #define PCI_DEVICE_ID_JMICRON_JMB38X_FW 0x2380 #define PCI_DEVICE_ID_TI_TSB12LV22 0x8009 #define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd @@ -285,6 +286,9 @@ static const struct { {PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_AGERE_FW643, 6, QUIRK_NO_MSI}, + {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_SB1394, PCI_ANY_ID, + QUIRK_RESET_PACKET}, + {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, PCI_ANY_ID, QUIRK_NO_MSI}, From c2f8080ae4ebf8d860addf050536b1ec71c53e19 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 29 Jan 2012 12:41:15 +0100 Subject: [PATCH 0853/4025] firewire: ohci: disable MSI on Ricoh controllers commit 320cfa6ce0b3dc794fedfa4bae54c0f65077234d upstream. The PCIe device FireWire (IEEE 1394) [0c00]: Ricoh Co Ltd FireWire Host Controller [1180:e832] (prog-if 10 [OHCI]) is unable to access attached FireWire devices when MSI is enabled but works if MSI is disabled. http://www.mail-archive.com/alsa-user@lists.sourceforge.net/msg28251.html Hence add the "disable MSI" quirks flag for this device, or in fact for safety and simplicity for all current (R5U230, R5U231, R5U240) and future Ricoh PCIe 1394 controllers. Reported-by: Stefan Thomas Signed-off-by: Stefan Richter Signed-off-by: Greg Kroah-Hartman --- drivers/firewire/ohci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index f2dfd4c49f8..7f97c309790 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -299,7 +299,7 @@ static const struct { QUIRK_NO_MSI}, {PCI_VENDOR_ID_RICOH, PCI_ANY_ID, PCI_ANY_ID, - QUIRK_CYCLE_TIMER}, + QUIRK_CYCLE_TIMER | QUIRK_NO_MSI}, {PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_TSB12LV22, PCI_ANY_ID, QUIRK_CYCLE_TIMER | QUIRK_RESET_PACKET | QUIRK_NO_1394A}, From 55d9f089521b1355cdd6914d1186ae02ddc0f74f Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 26 Jan 2012 16:41:33 +0200 Subject: [PATCH 0854/4025] IB/mlx4: pass SMP vendor-specific attribute MADs to firmware commit a6f7feae6d19e84253918d88b04153af09d3a243 upstream. In the current code, vendor-specific MADs (e.g with the FDR-10 attribute) are silently dropped by the driver, resulting in timeouts at the sending side and inability to query/configure the relevant feature. However, the ConnectX firmware is able to handle such MADs. For unsupported attributes, the firmware returns a GET_RESPONSE MAD containing an error status. For example, for a FDR-10 node with LID 11: # ibstat mlx4_0 1 CA: 'mlx4_0' Port 1: State: Active Physical state: LinkUp Rate: 40 (FDR10) Base lid: 11 LMC: 0 SM lid: 24 Capability mask: 0x02514868 Port GUID: 0x0002c903002e65d1 Link layer: InfiniBand Extended Port Query (EPI) vendor mad timeouts before the patch: # smpquery MEPI 11 -d ibwarn: [4196] smp_query_via: attr 0xff90 mod 0x0 route Lid 11 ibwarn: [4196] _do_madrpc: retry 1 (timeout 1000 ms) ibwarn: [4196] _do_madrpc: retry 2 (timeout 1000 ms) ibwarn: [4196] _do_madrpc: timeout after 3 retries, 3000 ms ibwarn: [4196] mad_rpc: _do_madrpc failed; dport (Lid 11) smpquery: iberror: [pid 4196] main: failed: operation EPI: ext port info query failed EPI query works OK with the patch: # smpquery MEPI 11 -d ibwarn: [6548] smp_query_via: attr 0xff90 mod 0x0 route Lid 11 ibwarn: [6548] mad_rpc: data offs 64 sz 64 mad data 0000 0000 0000 0001 0000 0001 0000 0001 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 # Ext Port info: Lid 11 port 0 StateChangeEnable:...............0x00 LinkSpeedSupported:..............0x01 LinkSpeedEnabled:................0x01 LinkSpeedActive:.................0x01 Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Acked-by: Ira Weiny Signed-off-by: Roland Dreier Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx4/mad.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index 57ffa50f509..44fc3104e91 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -255,12 +255,9 @@ int mlx4_ib_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num, return IB_MAD_RESULT_SUCCESS; /* - * Don't process SMInfo queries or vendor-specific - * MADs -- the SMA can't handle them. + * Don't process SMInfo queries -- the SMA can't handle them. */ - if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO || - ((in_mad->mad_hdr.attr_id & IB_SMP_ATTR_VENDOR_MASK) == - IB_SMP_ATTR_VENDOR_MASK)) + if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_SM_INFO) return IB_MAD_RESULT_SUCCESS; } else if (in_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_PERF_MGMT || in_mad->mad_hdr.mgmt_class == MLX4_IB_VENDOR_CLASS1 || From 603b63484725a6e88e4ae5da58716efd88154b1e Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Fri, 3 Feb 2012 15:37:16 -0800 Subject: [PATCH 0855/4025] kprobes: fix a memory leak in function pre_handler_kretprobe() commit 55ca6140e9bb307efc97a9301a4f501de02a6fd6 upstream. In function pre_handler_kretprobe(), the allocated kretprobe_instance object will get leaked if the entry_handler callback returns non-zero. This may cause all the preallocated kretprobe_instance objects exhausted. This issue can be reproduced by changing samples/kprobes/kretprobe_example.c to probe "mutex_unlock". And the fix is straightforward: just put the allocated kretprobe_instance object back onto the free_instances list. [akpm@linux-foundation.org: use raw_spin_lock/unlock] Signed-off-by: Jiang Liu Acked-by: Jim Keniston Acked-by: Ananth N Mavinakayanahalli Cc: Masami Hiramatsu Cc: Anil S Keshavamurthy Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/kprobes.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index e0f0bdd92ca..749340c1e6f 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1660,8 +1660,12 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p, ri->rp = rp; ri->task = current; - if (rp->entry_handler && rp->entry_handler(ri, regs)) + if (rp->entry_handler && rp->entry_handler(ri, regs)) { + raw_spin_lock_irqsave(&rp->lock, flags); + hlist_add_head(&ri->hlist, &rp->free_instances); + raw_spin_unlock_irqrestore(&rp->lock, flags); return 0; + } arch_prepare_kretprobe(ri, regs); From 73632d80356dcadfcacc8e20a319850b112abb9b Mon Sep 17 00:00:00 2001 From: Nikolaus Voss Date: Tue, 17 Jan 2012 10:28:33 +0100 Subject: [PATCH 0856/4025] at_hdmac: bugfix for enabling channel irq commit bda3a47c886664e86ee14eb79e9072b9e341f575 upstream. commit 463894705e4089d0ff69e7d877312d496ac70e5b deleted redundant chan_id and chancnt initialization in dma drivers as this is done in dma_async_device_register(). However, atc_enable_irq() relied on chan_id set before registering the device, what left only channel 0 functional for this driver. This patch introduces atc_enable/disable_chan_irq() as a variant of atc_enable/disable_irq() with the channel as explicit argument. Signed-off-by: Nikolaus Voss Signed-off-by: Nicolas Ferre Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/at_hdmac.c | 4 ++-- drivers/dma/at_hdmac_regs.h | 17 ++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 36144f88d71..9e9318abc51 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -1279,7 +1279,7 @@ static int __init at_dma_probe(struct platform_device *pdev) tasklet_init(&atchan->tasklet, atc_tasklet, (unsigned long)atchan); - atc_enable_irq(atchan); + atc_enable_chan_irq(atdma, i); } /* set base routines */ @@ -1348,7 +1348,7 @@ static int __exit at_dma_remove(struct platform_device *pdev) struct at_dma_chan *atchan = to_at_dma_chan(chan); /* Disable interrupts */ - atc_disable_irq(atchan); + atc_disable_chan_irq(atdma, chan->chan_id); tasklet_disable(&atchan->tasklet); tasklet_kill(&atchan->tasklet); diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index 087dbf1dd39..19ed47056da 100644 --- a/drivers/dma/at_hdmac_regs.h +++ b/drivers/dma/at_hdmac_regs.h @@ -319,28 +319,27 @@ static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli) } -static void atc_setup_irq(struct at_dma_chan *atchan, int on) +static void atc_setup_irq(struct at_dma *atdma, int chan_id, int on) { - struct at_dma *atdma = to_at_dma(atchan->chan_common.device); - u32 ebci; + u32 ebci; /* enable interrupts on buffer transfer completion & error */ - ebci = AT_DMA_BTC(atchan->chan_common.chan_id) - | AT_DMA_ERR(atchan->chan_common.chan_id); + ebci = AT_DMA_BTC(chan_id) + | AT_DMA_ERR(chan_id); if (on) dma_writel(atdma, EBCIER, ebci); else dma_writel(atdma, EBCIDR, ebci); } -static inline void atc_enable_irq(struct at_dma_chan *atchan) +static void atc_enable_chan_irq(struct at_dma *atdma, int chan_id) { - atc_setup_irq(atchan, 1); + atc_setup_irq(atdma, chan_id, 1); } -static inline void atc_disable_irq(struct at_dma_chan *atchan) +static void atc_disable_chan_irq(struct at_dma *atdma, int chan_id) { - atc_setup_irq(atchan, 0); + atc_setup_irq(atdma, chan_id, 0); } From c713decb179258db83fd048c09ec55d521d864d4 Mon Sep 17 00:00:00 2001 From: Carsten Otte Date: Fri, 3 Feb 2012 15:37:14 -0800 Subject: [PATCH 0857/4025] mm/filemap_xip.c: fix race condition in xip_file_fault() commit 99f02ef1f18631eb0a4e0ea0a3d56878dbcb4b90 upstream. Fix a race condition that shows in conjunction with xip_file_fault() when two threads of the same user process fault on the same memory page. In this case, the race winner will install the page table entry and the unlucky loser will cause an oops: xip_file_fault calls vm_insert_pfn (via vm_insert_mixed) which drops out at this check: retval = -EBUSY; if (!pte_none(*pte)) goto out_unlock; The resulting -EBUSY return value will trigger a BUG_ON() in xip_file_fault. This fix simply considers the fault as fixed in this case, because the race winner has successfully installed the pte. [akpm@linux-foundation.org: use conventional (and consistent) comment layout] Reported-by: David Sadler Signed-off-by: Carsten Otte Reported-by: Louis Alex Eisner Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/filemap_xip.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c index 93356cd1282..dee94297f39 100644 --- a/mm/filemap_xip.c +++ b/mm/filemap_xip.c @@ -263,7 +263,12 @@ static int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf) xip_pfn); if (err == -ENOMEM) return VM_FAULT_OOM; - BUG_ON(err); + /* + * err == -EBUSY is fine, we've raced against another thread + * that faulted-in the same page + */ + if (err != -EBUSY) + BUG_ON(err); return VM_FAULT_NOPAGE; } else { int err, ret = VM_FAULT_OOM; From 77650df5a701fb3a7acadfb347ebfb0e95cffe09 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Fri, 3 Feb 2012 15:37:18 -0800 Subject: [PATCH 0858/4025] mm: compaction: check pfn_valid when entering a new MAX_ORDER_NR_PAGES block during isolation for migration commit 0bf380bc70ecba68cb4d74dc656cc2fa8c4d801a upstream. When isolating for migration, migration starts at the start of a zone which is not necessarily pageblock aligned. Further, it stops isolating when COMPACT_CLUSTER_MAX pages are isolated so migrate_pfn is generally not aligned. This allows isolate_migratepages() to call pfn_to_page() on an invalid PFN which can result in a crash. This was originally reported against a 3.0-based kernel with the following trace in a crash dump. PID: 9902 TASK: d47aecd0 CPU: 0 COMMAND: "memcg_process_s" #0 [d72d3ad0] crash_kexec at c028cfdb #1 [d72d3b24] oops_end at c05c5322 #2 [d72d3b38] __bad_area_nosemaphore at c0227e60 #3 [d72d3bec] bad_area at c0227fb6 #4 [d72d3c00] do_page_fault at c05c72ec #5 [d72d3c80] error_code (via page_fault) at c05c47a4 EAX: 00000000 EBX: 000c0000 ECX: 00000001 EDX: 00000807 EBP: 000c0000 DS: 007b ESI: 00000001 ES: 007b EDI: f3000a80 GS: 6f50 CS: 0060 EIP: c030b15a ERR: ffffffff EFLAGS: 00010002 #6 [d72d3cb4] isolate_migratepages at c030b15a #7 [d72d3d14] zone_watermark_ok at c02d26cb #8 [d72d3d2c] compact_zone at c030b8de #9 [d72d3d68] compact_zone_order at c030bba1 #10 [d72d3db4] try_to_compact_pages at c030bc84 #11 [d72d3ddc] __alloc_pages_direct_compact at c02d61e7 #12 [d72d3e08] __alloc_pages_slowpath at c02d66c7 #13 [d72d3e78] __alloc_pages_nodemask at c02d6a97 #14 [d72d3eb8] alloc_pages_vma at c030a845 #15 [d72d3ed4] do_huge_pmd_anonymous_page at c03178eb #16 [d72d3f00] handle_mm_fault at c02f36c6 #17 [d72d3f30] do_page_fault at c05c70ed #18 [d72d3fb0] error_code (via page_fault) at c05c47a4 EAX: b71ff000 EBX: 00000001 ECX: 00001600 EDX: 00000431 DS: 007b ESI: 08048950 ES: 007b EDI: bfaa3788 SS: 007b ESP: bfaa36e0 EBP: bfaa3828 GS: 6f50 CS: 0073 EIP: 080487c8 ERR: ffffffff EFLAGS: 00010202 It was also reported by Herbert van den Bergh against 3.1-based kernel with the following snippet from the console log. BUG: unable to handle kernel paging request at 01c00008 IP: [] isolate_migratepages+0x119/0x390 *pdpt = 000000002f7ce001 *pde = 0000000000000000 It is expected that it also affects 3.2.x and current mainline. The problem is that pfn_valid is only called on the first PFN being checked and that PFN is not necessarily aligned. Lets say we have a case like this H = MAX_ORDER_NR_PAGES boundary | = pageblock boundary m = cc->migrate_pfn f = cc->free_pfn o = memory hole H------|------H------|----m-Hoooooo|ooooooH-f----|------H The migrate_pfn is just below a memory hole and the free scanner is beyond the hole. When isolate_migratepages started, it scans from migrate_pfn to migrate_pfn+pageblock_nr_pages which is now in a memory hole. It checks pfn_valid() on the first PFN but then scans into the hole where there are not necessarily valid struct pages. This patch ensures that isolate_migratepages calls pfn_valid when necessary. Reported-by: Herbert van den Bergh Tested-by: Herbert van den Bergh Signed-off-by: Mel Gorman Acked-by: Michal Nazarewicz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/compaction.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mm/compaction.c b/mm/compaction.c index 6cc604bd564..7ca6842c665 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -320,6 +320,19 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone, } else if (!locked) spin_lock_irq(&zone->lru_lock); + /* + * migrate_pfn does not necessarily start aligned to a + * pageblock. Ensure that pfn_valid is called when moving + * into a new MAX_ORDER_NR_PAGES range in case of large + * memory holes within the zone + */ + if ((low_pfn & (MAX_ORDER_NR_PAGES - 1)) == 0) { + if (!pfn_valid(low_pfn)) { + low_pfn += MAX_ORDER_NR_PAGES - 1; + continue; + } + } + if (!pfn_valid_within(low_pfn)) continue; nr_scanned++; From f5e9a83833c2effd51bb138b598636f4ed661498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 1 Feb 2012 12:09:55 +0100 Subject: [PATCH 0859/4025] drm/radeon: Set DESKTOP_HEIGHT register to the framebuffer (not mode) height. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 1b61925061660009f5b8047f93c5297e04541273 upstream. The value of this register is transferred to the V_COUNTER register at the beginning of vertical blank. V_COUNTER is the reference for VLINE waits and goes from VIEWPORT_Y_START to VIEWPORT_Y_START+VIEWPORT_HEIGHT during scanout, so if VIEWPORT_Y_START is not 0, V_COUNTER actually went backwards at the beginning of vertical blank, and VLINE waits excluding the whole scanout area could never finish (possibly only if VIEWPORT_Y_START is larger than the length of vertical blank in scanlines). Setting DESKTOP_HEIGHT to the framebuffer height should prevent this for any kind of VLINE wait. Fixes https://bugs.freedesktop.org/show_bug.cgi?id=45329 . Signed-off-by: Michel Dänzer Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/atombios_crtc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index 9541995e4b2..071ded119eb 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1173,7 +1173,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, WREG32(EVERGREEN_GRPH_ENABLE + radeon_crtc->crtc_offset, 1); WREG32(EVERGREEN_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, - crtc->mode.vdisplay); + target_fb->height); x &= ~3; y &= ~1; WREG32(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, @@ -1342,7 +1342,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, WREG32(AVIVO_D1GRPH_ENABLE + radeon_crtc->crtc_offset, 1); WREG32(AVIVO_D1MODE_DESKTOP_HEIGHT + radeon_crtc->crtc_offset, - crtc->mode.vdisplay); + target_fb->height); x &= ~3; y &= ~1; WREG32(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, From e1cf4ad959d7b2644f2be70ff38030d6cd3cbede Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 10 Jan 2012 10:18:28 +1000 Subject: [PATCH 0860/4025] drm/nouveau/gem: fix fence_sync race / oops commit 525895ba388c949aa906f26e3ec5cb1ab041f56b upstream. Due to a race it was possible for a fence to be destroyed while another thread was trying to synchronise with it. If this happened in the fallback non-semaphore path, it lead to the following oops due to fence->channel being NULL. BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] nouveau_fence_update+0xe/0xe0 [nouveau] *pde = a649c067 SMP Modules linked in: fuse nouveau(O) ttm(O) drm_kms_helper(O) drm(O) mxm_wmi video wmi netconsole configfs lockd bnep bluetooth rfkill ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 nf_conntrack_ipv4 nf_defrag_ipv4 xt_state nf_conntrack ip6table_filter ip6_tables snd_hda_codec_realtek snd_hda_intel snd_hda_cobinfmt_misc uinput ata_generic pata_acpi pata_aet2c_algo_bit i2c_core [last unloaded: wmi] Pid: 2255, comm: gnome-shell Tainted: G O 3.2.0-0.rc5.git0.1.fc17.i686 #1 System manufacturer System Product Name/M2A-VM EIP: 0060:[] EFLAGS: 00010296 CPU: 1 EIP is at nouveau_fence_update+0xe/0xe0 [nouveau] EAX: 00000000 EBX: ddfc6dd0 ECX: dd111580 EDX: 00000000 ESI: 00003e80 EDI: dd111580 EBP: dd121d00 ESP: dd121ce8 DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068 Process gnome-shell (pid: 2255, ti=dd120000 task=dd111580 task.ti=dd120000) Stack: 7dc86c76 00000000 00003e80 ddfc6dd0 00003e80 dd111580 dd121d0c fa96371f 00000000 dd121d3c fa963773 dd111580 01000246 000ec53d 00000000 ddfc6dd0 00001f40 00000000 ddfc6dd0 00000010 dc7df840 dd121d6c fa9639a0 00000000 Call Trace: [] __nouveau_fence_signalled+0x1f/0x30 [nouveau] [] __nouveau_fence_wait+0x43/0xd0 [nouveau] [] nouveau_fence_sync+0x1a0/0x1c0 [nouveau] [] validate_list+0x176/0x300 [nouveau] [] ? ttm_bo_mem_put+0x30/0x30 [ttm] [] nouveau_gem_ioctl_pushbuf+0x48a/0xfd0 [nouveau] [] ? die+0x31/0x80 [] drm_ioctl+0x388/0x490 [drm] [] ? die+0x31/0x80 [] ? nouveau_gem_ioctl_new+0x150/0x150 [nouveau] [] ? file_has_perm+0xcb/0xe0 [] ? drm_copy_field+0x80/0x80 [drm] [] do_vfs_ioctl+0x86/0x5b0 [] ? die+0x31/0x80 [] ? selinux_file_ioctl+0x62/0x130 [] ? fget_light+0x30/0x340 [] sys_ioctl+0x6f/0x80 [] syscall_call+0x7/0xb [] ? die+0x31/0x80 [] ? die+0x31/0x80 Signed-off-by: Ben Skeggs Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nouveau_gem.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index b52e4601824..cee78b26f60 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -314,6 +314,25 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv, return 0; } +static int +validate_sync(struct nouveau_channel *chan, struct nouveau_bo *nvbo) +{ + struct nouveau_fence *fence = NULL; + int ret = 0; + + spin_lock(&nvbo->bo.bdev->fence_lock); + if (nvbo->bo.sync_obj) + fence = nouveau_fence_ref(nvbo->bo.sync_obj); + spin_unlock(&nvbo->bo.bdev->fence_lock); + + if (fence) { + ret = nouveau_fence_sync(fence, chan); + nouveau_fence_unref(&fence); + } + + return ret; +} + static int validate_list(struct nouveau_channel *chan, struct list_head *list, struct drm_nouveau_gem_pushbuf_bo *pbbo, uint64_t user_pbbo_ptr) @@ -327,7 +346,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, list_for_each_entry(nvbo, list, entry) { struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index]; - ret = nouveau_fence_sync(nvbo->bo.sync_obj, chan); + ret = validate_sync(chan, nvbo); if (unlikely(ret)) { NV_ERROR(dev, "fail pre-validate sync\n"); return ret; @@ -350,7 +369,7 @@ validate_list(struct nouveau_channel *chan, struct list_head *list, return ret; } - ret = nouveau_fence_sync(nvbo->bo.sync_obj, chan); + ret = validate_sync(chan, nvbo); if (unlikely(ret)) { NV_ERROR(dev, "fail post-validate sync\n"); return ret; From 32c4490a6ffbe3de604581f5fdce361eb049acff Mon Sep 17 00:00:00 2001 From: Seth Forshee Date: Tue, 31 Jan 2012 19:06:25 -0600 Subject: [PATCH 0861/4025] drm/radeon/kms: disable output polling when suspended commit 86698c20f71d488b32c49ed4687fb3cf8a88a5ca upstream. Polling the outputs when the device is suspended can result in erroneous status updates. Disable output polling during suspend to prevent this from happening. Signed-off-by: Seth Forshee Reviewed-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_device.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 5d0c1236dd4..e87893c2c88 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -857,6 +857,8 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state) if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; + drm_kms_helper_poll_disable(dev); + /* turn off display hw */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); @@ -943,6 +945,8 @@ int radeon_resume_kms(struct drm_device *dev) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); } + + drm_kms_helper_poll_enable(dev); return 0; } From c27711dc7f2cff89cee6a47026d936672cb29350 Mon Sep 17 00:00:00 2001 From: Chanho Min Date: Thu, 5 Jan 2012 20:00:19 +0900 Subject: [PATCH 0862/4025] sched/rt: Fix task stack corruption under __ARCH_WANT_INTERRUPTS_ON_CTXSW commit cb297a3e433dbdcf7ad81e0564e7b804c941ff0d upstream. This issue happens under the following conditions: 1. preemption is off 2. __ARCH_WANT_INTERRUPTS_ON_CTXSW is defined 3. RT scheduling class 4. SMP system Sequence is as follows: 1.suppose current task is A. start schedule() 2.task A is enqueued pushable task at the entry of schedule() __schedule prev = rq->curr; ... put_prev_task put_prev_task_rt enqueue_pushable_task 4.pick the task B as next task. next = pick_next_task(rq); 3.rq->curr set to task B and context_switch is started. rq->curr = next; 4.At the entry of context_swtich, release this cpu's rq->lock. context_switch prepare_task_switch prepare_lock_switch raw_spin_unlock_irq(&rq->lock); 5.Shortly after rq->lock is released, interrupt is occurred and start IRQ context 6.try_to_wake_up() which called by ISR acquires rq->lock try_to_wake_up ttwu_remote rq = __task_rq_lock(p) ttwu_do_wakeup(rq, p, wake_flags); task_woken_rt 7.push_rt_task picks the task A which is enqueued before. task_woken_rt push_rt_tasks(rq) next_task = pick_next_pushable_task(rq) 8.At find_lock_lowest_rq(), If double_lock_balance() returns 0, lowest_rq can be the remote rq. (But,If preemption is on, double_lock_balance always return 1 and it does't happen.) push_rt_task find_lock_lowest_rq if (double_lock_balance(rq, lowest_rq)).. 9.find_lock_lowest_rq return the available rq. task A is migrated to the remote cpu/rq. push_rt_task ... deactivate_task(rq, next_task, 0); set_task_cpu(next_task, lowest_rq->cpu); activate_task(lowest_rq, next_task, 0); 10. But, task A is on irq context at this cpu. So, task A is scheduled by two cpus at the same time until restore from IRQ. Task A's stack is corrupted. To fix it, don't migrate an RT task if it's still running. Signed-off-by: Chanho Min Signed-off-by: Peter Zijlstra Acked-by: Steven Rostedt Link: http://lkml.kernel.org/r/CAOAMb1BHA=5fm7KTewYyke6u-8DP0iUuJMpgQw54vNeXFsGpoQ@mail.gmail.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/sched_rt.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index 17f2319d5e4..ac79f9e34fd 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -1390,6 +1390,11 @@ static int push_rt_task(struct rq *rq) if (!next_task) return 0; +#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW + if (unlikely(task_running(rq, next_task))) + return 0; +#endif + retry: if (unlikely(next_task == rq->curr)) { WARN_ON(1); From 10f672f1a199240bc2a77d6f81e1d37f33ba743e Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 20 Sep 2011 11:41:54 +0100 Subject: [PATCH 0863/4025] ASoC: Ensure we generate a driver name commit f0e8ed858edb327802ee65fd695cc1538286226f upstream. Commit 873bd4c (ASoC: Don't set invalid name string to snd_card->driver field) broke generation of a driver name for all ASoC cards relying on the automatic generation of one. Fix this by using the old default with spaces replaced by underscores. Signed-off-by: Mark Brown Acked-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/soc/soc-core.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 493ae7c4c04..e2bfe1d69e7 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -1931,9 +1932,20 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) "%s", card->name); snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), "%s", card->long_name ? card->long_name : card->name); - if (card->driver_name) - strlcpy(card->snd_card->driver, card->driver_name, - sizeof(card->snd_card->driver)); + snprintf(card->snd_card->driver, sizeof(card->snd_card->driver), + "%s", card->driver_name ? card->driver_name : card->name); + for (i = 0; i < ARRAY_SIZE(card->snd_card->driver); i++) { + switch (card->snd_card->driver[i]) { + case '_': + case '-': + case '\0': + break; + default: + if (!isalnum(card->snd_card->driver[i])) + card->snd_card->driver[i] = '_'; + break; + } + } if (card->late_probe) { ret = card->late_probe(card); From 1357ed0b4b9db30846377febb40a847d6103c991 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 23 Dec 2011 11:53:07 +0100 Subject: [PATCH 0864/4025] udf: Mark LVID buffer as uptodate before marking it dirty commit 853a0c25baf96b028de1654bea1e0c8857eadf3d upstream. When we hit EIO while writing LVID, the buffer uptodate bit is cleared. This then results in an anoying warning from mark_buffer_dirty() when we write the buffer again. So just set uptodate flag unconditionally. Reviewed-by: Namjae Jeon Signed-off-by: Jan Kara Cc: Dave Jones Signed-off-by: Greg Kroah-Hartman --- fs/udf/super.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/udf/super.c b/fs/udf/super.c index 7b27b063ff6..7f0e18aa25d 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1830,6 +1830,12 @@ static void udf_close_lvid(struct super_block *sb) le16_to_cpu(lvid->descTag.descCRCLength))); lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); + /* + * We set buffer uptodate unconditionally here to avoid spurious + * warnings from mark_buffer_dirty() when previous EIO has marked + * the buffer as !uptodate + */ + set_buffer_uptodate(bh); mark_buffer_dirty(bh); sbi->s_lvid_dirty = 0; mutex_unlock(&sbi->s_alloc_mutex); From 032aa01c0b53e12b3ac46db8e7202a3230a83a89 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 9 Dec 2011 20:42:20 +0800 Subject: [PATCH 0865/4025] drm/i915: HDMI hot remove notification to audio driver commit 2deed761188d7480eb5f7efbfe7aa77f09322ed8 upstream. On HDMI monitor hot remove, clear SDVO_AUDIO_ENABLE accordingly, so that the audio driver will receive hot plug events and take action to refresh its device state and ELD contents. The cleared SDVO_AUDIO_ENABLE bit needs to be restored to prevent losing HDMI audio after DPMS on. CC: Wang Zhenyu Signed-off-by: Wu Fengguang Signed-off-by: Keith Packard Signed-off-by: Eugeni Dodonov Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_hdmi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index aa0a8e83142..236bbe09abd 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -158,6 +158,10 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); u32 temp; + u32 enable_bits = SDVO_ENABLE; + + if (intel_hdmi->has_audio) + enable_bits |= SDVO_AUDIO_ENABLE; temp = I915_READ(intel_hdmi->sdvox_reg); @@ -170,9 +174,9 @@ static void intel_hdmi_dpms(struct drm_encoder *encoder, int mode) } if (mode != DRM_MODE_DPMS_ON) { - temp &= ~SDVO_ENABLE; + temp &= ~enable_bits; } else { - temp |= SDVO_ENABLE; + temp |= enable_bits; } I915_WRITE(intel_hdmi->sdvox_reg, temp); From 1f8991ccf771442ae2423971798a6ca9d6db6343 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 9 Dec 2011 20:42:21 +0800 Subject: [PATCH 0866/4025] drm/i915: DisplayPort hot remove notification to audio driver commit 832afda6a7d7235ef0e09f4ec46736861540da6d upstream. On DP monitor hot remove, clear DP_AUDIO_OUTPUT_ENABLE accordingly, so that the audio driver will receive hot plug events and take action to refresh its device state and ELD contents. Note that the DP_AUDIO_OUTPUT_ENABLE bit may be enabled or disabled only when the link training is complete and set to "Normal". Tested OK for both hot plug/remove and DPMS on/off. Signed-off-by: Wu Fengguang Signed-off-by: Keith Packard Signed-off-by: Eugeni Dodonov Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_dp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 14264a8c03e..bf9fea94161 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1554,6 +1554,7 @@ intel_dp_link_down(struct intel_dp *intel_dp) intel_wait_for_vblank(dev, to_intel_crtc(crtc)->pipe); } + DP &= ~DP_AUDIO_OUTPUT_ENABLE; I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); POSTING_READ(intel_dp->output_reg); } From 5b19005c6230e6a65d3fe3de8f514feac7d2eebb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Sun, 27 Nov 2011 18:58:17 +0100 Subject: [PATCH 0867/4025] drm/i915: check ACTHD of all rings commit 097354eb14fa94d31a09c64d640643f58e4a5a9a upstream. Otherwise hangcheck spuriously fires when running blitter/bsd-only workloads. Contrary to a similar patch by Ben Widawsky this does not check INSTDONE of the other rings. Chris Wilson implied that in a failure to detect a hang, most likely because INSTDONE was fluctuating. Thus only check ACTHD, which as far as I know is rather reliable. Also, blitter and bsd rings can't launch complex tasks from a single instruction (like 3D_PRIM on the render with complex or even infinite shaders). This fixes spurious gpu hang detection when running tests/gem_hangcheck_forcewake on snb/ivb. Signed-Off-by: Daniel Vetter Reviewed-by: Chris Wilson Signed-off-by: Keith Packard Signed-off-by: Eugeni Dodonov Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_irq.c | 13 ++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 335564e35c3..b570415c3fd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -325,6 +325,8 @@ typedef struct drm_i915_private { struct timer_list hangcheck_timer; int hangcheck_count; uint32_t last_acthd; + uint32_t last_acthd_bsd; + uint32_t last_acthd_blt; uint32_t last_instdone; uint32_t last_instdone1; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 363564704b1..997db7fab21 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1665,7 +1665,7 @@ void i915_hangcheck_elapsed(unsigned long data) { struct drm_device *dev = (struct drm_device *)data; drm_i915_private_t *dev_priv = dev->dev_private; - uint32_t acthd, instdone, instdone1; + uint32_t acthd, instdone, instdone1, acthd_bsd, acthd_blt; bool err = false; /* If all work is done then ACTHD clearly hasn't advanced. */ @@ -1679,16 +1679,21 @@ void i915_hangcheck_elapsed(unsigned long data) } if (INTEL_INFO(dev)->gen < 4) { - acthd = I915_READ(ACTHD); instdone = I915_READ(INSTDONE); instdone1 = 0; } else { - acthd = I915_READ(ACTHD_I965); instdone = I915_READ(INSTDONE_I965); instdone1 = I915_READ(INSTDONE1); } + acthd = intel_ring_get_active_head(&dev_priv->ring[RCS]); + acthd_bsd = HAS_BSD(dev) ? + intel_ring_get_active_head(&dev_priv->ring[VCS]) : 0; + acthd_blt = HAS_BLT(dev) ? + intel_ring_get_active_head(&dev_priv->ring[BCS]) : 0; if (dev_priv->last_acthd == acthd && + dev_priv->last_acthd_bsd == acthd_bsd && + dev_priv->last_acthd_blt == acthd_blt && dev_priv->last_instdone == instdone && dev_priv->last_instdone1 == instdone1) { if (dev_priv->hangcheck_count++ > 1) { @@ -1720,6 +1725,8 @@ void i915_hangcheck_elapsed(unsigned long data) dev_priv->hangcheck_count = 0; dev_priv->last_acthd = acthd; + dev_priv->last_acthd_bsd = acthd_bsd; + dev_priv->last_acthd_blt = acthd_blt; dev_priv->last_instdone = instdone; dev_priv->last_instdone1 = instdone1; } From bd26f229584ab3c0470410550d3c69bf3c9d29ee Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 14 Dec 2011 21:10:06 -0200 Subject: [PATCH 0868/4025] drm/i915: Fix TV Out refresh rate. commit 23bd15ec662344dc10e9918fdd0dbc58bc71526d upstream. TV Out refresh rate was half of the specification for almost all modes. Due to this reason pixel clock was so low for some modes causing flickering screen. Signed-off-by: Rodrigo Vivi Reviewed-by: Jesse Barnes Signed-off-by: Keith Packard Signed-off-by: Eugeni Dodonov Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_tv.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 113e4e7264c..f57b08bd8c6 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -417,7 +417,7 @@ static const struct tv_mode tv_modes[] = { { .name = "NTSC-M", .clock = 108000, - .refresh = 29970, + .refresh = 59940, .oversample = TV_OVERSAMPLE_8X, .component_only = 0, /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 3.580MHz */ @@ -460,7 +460,7 @@ static const struct tv_mode tv_modes[] = { { .name = "NTSC-443", .clock = 108000, - .refresh = 29970, + .refresh = 59940, .oversample = TV_OVERSAMPLE_8X, .component_only = 0, /* 525 Lines, 60 Fields, 15.734KHz line, Sub-Carrier 4.43MHz */ @@ -502,7 +502,7 @@ static const struct tv_mode tv_modes[] = { { .name = "NTSC-J", .clock = 108000, - .refresh = 29970, + .refresh = 59940, .oversample = TV_OVERSAMPLE_8X, .component_only = 0, @@ -545,7 +545,7 @@ static const struct tv_mode tv_modes[] = { { .name = "PAL-M", .clock = 108000, - .refresh = 29970, + .refresh = 59940, .oversample = TV_OVERSAMPLE_8X, .component_only = 0, @@ -589,7 +589,7 @@ static const struct tv_mode tv_modes[] = { /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */ .name = "PAL-N", .clock = 108000, - .refresh = 25000, + .refresh = 50000, .oversample = TV_OVERSAMPLE_8X, .component_only = 0, @@ -634,7 +634,7 @@ static const struct tv_mode tv_modes[] = { /* 625 Lines, 50 Fields, 15.625KHz line, Sub-Carrier 4.434MHz */ .name = "PAL", .clock = 108000, - .refresh = 25000, + .refresh = 50000, .oversample = TV_OVERSAMPLE_8X, .component_only = 0, @@ -821,7 +821,7 @@ static const struct tv_mode tv_modes[] = { { .name = "1080i@50Hz", .clock = 148800, - .refresh = 25000, + .refresh = 50000, .oversample = TV_OVERSAMPLE_2X, .component_only = 1, @@ -847,7 +847,7 @@ static const struct tv_mode tv_modes[] = { { .name = "1080i@60Hz", .clock = 148800, - .refresh = 30000, + .refresh = 60000, .oversample = TV_OVERSAMPLE_2X, .component_only = 1, From dade9ad146b19c22141032d84190d2220623d2ca Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Sat, 7 Jan 2012 23:40:35 -0200 Subject: [PATCH 0869/4025] drm/i915: handle 3rd pipe commit 07c1e8c1462fa7324de4c36ae9e55da2abd79cee upstream. We don't need to check 3rd pipe specifically, as it shares PLL with some other one. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=41977 Signed-off-by: Eugeni Dodonov Reviewed-by: Jesse Barnes Signed-off-by: Keith Packard Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_suspend.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index cf15533aabf..bc7dcaa1c68 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -34,6 +34,10 @@ static bool i915_pipe_enabled(struct drm_device *dev, enum pipe pipe) struct drm_i915_private *dev_priv = dev->dev_private; u32 dpll_reg; + /* On IVB, 3rd pipe shares PLL with another one */ + if (pipe > 1) + return false; + if (HAS_PCH_SPLIT(dev)) dpll_reg = (pipe == PIPE_A) ? _PCH_DPLL_A : _PCH_DPLL_B; else From 1a11d5d7fb7988a92e798dfbed7cdd350c0701cc Mon Sep 17 00:00:00 2001 From: Li Wang Date: Thu, 19 Jan 2012 09:44:36 +0800 Subject: [PATCH 0870/4025] eCryptfs: Infinite loop due to overflow in ecryptfs_write() commit 684a3ff7e69acc7c678d1a1394fe9e757993fd34 upstream. ecryptfs_write() can enter an infinite loop when truncating a file to a size larger than 4G. This only happens on architectures where size_t is represented by 32 bits. This was caused by a size_t overflow due to it incorrectly being used to store the result of a calculation which uses potentially large values of type loff_t. [tyhicks@canonical.com: rewrite subject and commit message] Signed-off-by: Li Wang Signed-off-by: Yunchuan Wen Reviewed-by: Cong Wang Signed-off-by: Tyler Hicks Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/read_write.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c index 54eb14caad7..608c1c3fde1 100644 --- a/fs/ecryptfs/read_write.c +++ b/fs/ecryptfs/read_write.c @@ -130,7 +130,7 @@ int ecryptfs_write(struct inode *ecryptfs_inode, char *data, loff_t offset, pgoff_t ecryptfs_page_idx = (pos >> PAGE_CACHE_SHIFT); size_t start_offset_in_page = (pos & ~PAGE_CACHE_MASK); size_t num_bytes = (PAGE_CACHE_SIZE - start_offset_in_page); - size_t total_remaining_bytes = ((offset + size) - pos); + loff_t total_remaining_bytes = ((offset + size) - pos); if (fatal_signal_pending(current)) { rc = -EINTR; @@ -141,7 +141,7 @@ int ecryptfs_write(struct inode *ecryptfs_inode, char *data, loff_t offset, num_bytes = total_remaining_bytes; if (pos < offset) { /* remaining zeros to write, up to destination offset */ - size_t total_remaining_zeros = (offset - pos); + loff_t total_remaining_zeros = (offset - pos); if (num_bytes > total_remaining_zeros) num_bytes = total_remaining_zeros; From 7a415a8da853b0724413680a769d89affc8b5be5 Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Thu, 2 Feb 2012 15:28:28 -0600 Subject: [PATCH 0871/4025] cifs: Fix oops in session setup code for null user mounts commit de47a4176c532ef5961b8a46a2d541a3517412d3 upstream. For null user mounts, do not invoke string length function during session setup. Reported-and-Tested-by: Chris Clayton Acked-by: Jeff Layton Signed-off-by: Shirish Pargaonkar Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/sess.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index d3e619692ee..0cfae19129b 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -244,16 +244,15 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses, /* copy user */ /* BB what about null user mounts - check that we do this BB */ /* copy user */ - if (ses->user_name != NULL) + if (ses->user_name != NULL) { strncpy(bcc_ptr, ses->user_name, MAX_USERNAME_SIZE); + bcc_ptr += strnlen(ses->user_name, MAX_USERNAME_SIZE); + } /* else null user mount */ - - bcc_ptr += strnlen(ses->user_name, MAX_USERNAME_SIZE); *bcc_ptr = 0; bcc_ptr++; /* account for null termination */ /* copy domain */ - if (ses->domainName != NULL) { strncpy(bcc_ptr, ses->domainName, 256); bcc_ptr += strnlen(ses->domainName, 256); From e02c339f506e10fadf8a5f00f1c932035596ed8e Mon Sep 17 00:00:00 2001 From: Hubert Feurstein Date: Mon, 9 Jan 2012 17:23:57 +0100 Subject: [PATCH 0872/4025] atmel_lcdfb: fix usage of CONTRAST_CTR in suspend/resume commit 9f1065032ceb7e86c7c9f16bb86518857e88a172 upstream. An error was existing in the saving of CONTRAST_CTR register across suspend/resume. Signed-off-by: Hubert Feurstein Signed-off-by: Nicolas Ferre Acked-by: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Florian Tobias Schandinat Signed-off-by: Greg Kroah-Hartman --- drivers/video/atmel_lcdfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index 4484c721f0f..c2ceae4bb6c 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -1085,7 +1085,7 @@ static int atmel_lcdfb_suspend(struct platform_device *pdev, pm_message_t mesg) */ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); - sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); + sinfo->saved_lcdcon = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_CTR); lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, 0); if (sinfo->atmel_lcdfb_power_control) sinfo->atmel_lcdfb_power_control(0); From d378b2d044139f88384d278bd5830669c44c789b Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 14 Nov 2011 13:13:49 +0100 Subject: [PATCH 0873/4025] lockdep, bug: Exclude TAINT_FIRMWARE_WORKAROUND from disabling lockdep commit df754e6af2f237a6c020c0daff55a1a609338e31 upstream. It's unlikely that TAINT_FIRMWARE_WORKAROUND causes false lockdep messages, so do not disable lockdep in that case. We still want to keep lockdep disabled in the TAINT_OOT_MODULE case: - bin-only modules can cause various instabilities in their and in unrelated kernel code - they are impossible to debug for kernel developers - they also typically do not have the copyright license permission to link to the GPL-ed lockdep code. Suggested-by: Ben Hutchings Signed-off-by: Peter Zijlstra Link: http://lkml.kernel.org/n/tip-xopopjjens57r0i13qnyh2yo@git.kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/panic.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/kernel/panic.c b/kernel/panic.c index 69231670eb9..8e48cf6ab56 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -236,8 +236,16 @@ void add_taint(unsigned flag) * Also we want to keep up lockdep for staging development and * post-warning case. */ - if (flag != TAINT_CRAP && flag != TAINT_WARN && __debug_locks_off()) - printk(KERN_WARNING "Disabling lock debugging due to kernel taint\n"); + switch (flag) { + case TAINT_CRAP: + case TAINT_WARN: + case TAINT_FIRMWARE_WORKAROUND: + break; + + default: + if (__debug_locks_off()) + printk(KERN_WARNING "Disabling lock debugging due to kernel taint\n"); + } set_bit(flag, &tainted_mask); } From eb521fbb338f21b2de12fe8f7e4fa5b7e4f9fb2a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 27 Jan 2012 05:43:59 -0800 Subject: [PATCH 0874/4025] hwmon: (w83627ehf) Fix number of fans for NCT6776F commit 585c0fd8216e0c9f98e2434092af7ec0f999522d upstream. NCT6776F can select fan input pins for fans 3 to 5 with a secondary set of chip register bits. Check that second set of bits in addition to the first set to detect if fans 3..5 are monitored. Signed-off-by: Guenter Roeck Acked-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/w83627ehf.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 62845157245..359bb1e23ac 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -2104,9 +2104,29 @@ static int __devinit w83627ehf_probe(struct platform_device *pdev) fan4min = 0; fan5pin = 0; } else if (sio_data->kind == nct6776) { - fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40); - fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x01); - fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) & 0x02); + bool gpok = superio_inb(sio_data->sioreg, 0x27) & 0x80; + u8 regval; + + superio_select(sio_data->sioreg, W83627EHF_LD_HWM); + regval = superio_inb(sio_data->sioreg, SIO_REG_ENABLE); + + if (regval & 0x80) + fan3pin = gpok; + else + fan3pin = !(superio_inb(sio_data->sioreg, 0x24) & 0x40); + + if (regval & 0x40) + fan4pin = gpok; + else + fan4pin = !!(superio_inb(sio_data->sioreg, 0x1C) + & 0x01); + + if (regval & 0x20) + fan5pin = gpok; + else + fan5pin = !!(superio_inb(sio_data->sioreg, 0x1C) + & 0x02); + fan4min = fan4pin; } else if (sio_data->kind == w83667hg || sio_data->kind == w83667hg_b) { fan3pin = 1; From 30b4b3a54fc6ca34c6f8a18b56c83680ad0a7fa9 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 31 Jan 2012 11:55:32 +0000 Subject: [PATCH 0875/4025] ASoC: wm_hubs: Fix routing of input PGAs to line output mixer commit ee76744c51ec342df9822b4a85dbbfc3887b6d60 upstream. IN1L/R is routed to both line output mixers, we don't route IN1 to LINEOUT1 and IN2 to LINEOUT2. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm_hubs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index b85539482ec..f2e07b50b90 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -562,8 +562,8 @@ SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0), }; static const struct snd_kcontrol_new line2_mix[] = { -SOC_DAPM_SINGLE("IN2R Switch", WM8993_LINE_MIXER2, 2, 1, 0), -SOC_DAPM_SINGLE("IN2L Switch", WM8993_LINE_MIXER2, 1, 1, 0), +SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER2, 2, 1, 0), +SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER2, 1, 1, 0), SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0), }; @@ -808,8 +808,8 @@ static const struct snd_soc_dapm_route lineout1_se_routes[] = { }; static const struct snd_soc_dapm_route lineout2_diff_routes[] = { - { "LINEOUT2 Mixer", "IN2L Switch", "IN2L PGA" }, - { "LINEOUT2 Mixer", "IN2R Switch", "IN2R PGA" }, + { "LINEOUT2 Mixer", "IN1L Switch", "IN1L PGA" }, + { "LINEOUT2 Mixer", "IN1R Switch", "IN1R PGA" }, { "LINEOUT2 Mixer", "Output Switch", "Right Output PGA" }, { "LINEOUT2N Driver", NULL, "LINEOUT2 Mixer" }, From b855f76b5f217bd6d03c7dfa38a64b51143338ac Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 1 Feb 2012 23:46:58 +0000 Subject: [PATCH 0876/4025] ASoC: wm_hubs: Correct line input to line output 2 paths commit 43b6cec27e1e50a1de3eff47e66e502f3fe7e66e upstream. The second line output mixer has the controls for the line input bypasses in the opposite order. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm_hubs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index f2e07b50b90..8712a9f6d6e 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -562,8 +562,8 @@ SOC_DAPM_SINGLE("Left Output Switch", WM8993_LINE_MIXER1, 0, 1, 0), }; static const struct snd_kcontrol_new line2_mix[] = { -SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER2, 2, 1, 0), -SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER2, 1, 1, 0), +SOC_DAPM_SINGLE("IN1L Switch", WM8993_LINE_MIXER2, 2, 1, 0), +SOC_DAPM_SINGLE("IN1R Switch", WM8993_LINE_MIXER2, 1, 1, 0), SOC_DAPM_SINGLE("Output Switch", WM8993_LINE_MIXER2, 0, 1, 0), }; From 2b42237845c6c1f94479320b012664bbf07bb989 Mon Sep 17 00:00:00 2001 From: Susan Gao Date: Mon, 30 Jan 2012 13:57:04 -0800 Subject: [PATCH 0877/4025] ASoC: wm8962: Fix word length configuration commit 2b6712b19531e22455e7fa18371c5ba9eec76699 upstream. Signed-off-by: Susan Gao Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8962.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 4a0f666a90b..6d0cae4681b 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -2975,13 +2975,13 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_S16_LE: break; case SNDRV_PCM_FORMAT_S20_3LE: - aif0 |= 0x40; + aif0 |= 0x4; break; case SNDRV_PCM_FORMAT_S24_LE: - aif0 |= 0x80; + aif0 |= 0x8; break; case SNDRV_PCM_FORMAT_S32_LE: - aif0 |= 0xc0; + aif0 |= 0xc; break; default: return -EINVAL; From a5e2ba3e021e7a3135a7dbb8e188d21971a59f49 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 8 Feb 2012 17:13:41 -0800 Subject: [PATCH 0878/4025] pcmcia: fix socket refcount decrementing on each resume commit 025e4ab3db07fcbf62c01e4f30d1012234beb980 upstream. This fixes a memory-corrupting bug: not only does it cause the warning, but as a result of dropping the refcount to zero, it causes the pcmcia_socket0 device structure to be freed while it still has references, causing slab caches corruption. A fatal oops quickly follows this warning - often even just a 'dmesg' following the warning causes the kernel to oops. While testing suspend/resume on an ARM device with PCMCIA support, and a CF card inserted, I found that after five suspend and resumes, the kernel would complain, and shortly die after with slab corruption. WARNING: at include/linux/kref.h:41 kobject_get+0x28/0x50() As the message doesn't give a clue about which kobject, and the built-in debugging in drivers/base/power/main.c happens too late, this was added right before each get_device(): printk("%s: %p [%s] %u\n", __func__, dev, kobject_name(&dev->kobj), atomic_read(&dev->kobj.kref.refcount)); and on the 3rd s2ram cycle, the following behaviour observed: On the 3rd suspend/resume cycle: dpm_prepare: c1a0d998 [pcmcia_socket0] 3 dpm_suspend: c1a0d998 [pcmcia_socket0] 3 dpm_suspend_noirq: c1a0d998 [pcmcia_socket0] 3 dpm_resume_noirq: c1a0d998 [pcmcia_socket0] 3 dpm_resume: c1a0d998 [pcmcia_socket0] 3 dpm_complete: c1a0d998 [pcmcia_socket0] 2 4th: dpm_prepare: c1a0d998 [pcmcia_socket0] 2 dpm_suspend: c1a0d998 [pcmcia_socket0] 2 dpm_suspend_noirq: c1a0d998 [pcmcia_socket0] 2 dpm_resume_noirq: c1a0d998 [pcmcia_socket0] 2 dpm_resume: c1a0d998 [pcmcia_socket0] 2 dpm_complete: c1a0d998 [pcmcia_socket0] 1 5th: dpm_prepare: c1a0d998 [pcmcia_socket0] 1 dpm_suspend: c1a0d998 [pcmcia_socket0] 1 dpm_suspend_noirq: c1a0d998 [pcmcia_socket0] 1 dpm_resume_noirq: c1a0d998 [pcmcia_socket0] 1 dpm_resume: c1a0d998 [pcmcia_socket0] 1 dpm_complete: c1a0d998 [pcmcia_socket0] 0 ------------[ cut here ]------------ WARNING: at include/linux/kref.h:41 kobject_get+0x28/0x50() Modules linked in: ucb1x00_core Backtrace: [] (dump_backtrace+0x0/0x110) from [] (dump_stack+0x18/0x1c) [] (dump_stack+0x0/0x1c) from [] (warn_slowpath_common+0x50/0x68) [] (warn_slowpath_common+0x0/0x68) from [] (warn_slowpath_null+0x24/0x28) [] (warn_slowpath_null+0x0/0x28) from [] (kobject_get+0x28/0x50) [] (kobject_get+0x0/0x50) from [] (get_device+0x1c/0x24) [] (dpm_complete+0x0/0x1a0) from [] (dpm_resume_end+0x1c/0x20) ... Looking at commit 7b24e7988263 ("pcmcia: split up central event handler"), the following change was made to cs.c: return 0; } #endif - - send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW); + if (!(skt->state & SOCKET_CARDBUS) && (skt->callback)) + skt->callback->early_resume(skt); return 0; } And the corresponding change in ds.c is from: -static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) -{ - struct pcmcia_socket *s = pcmcia_get_socket(skt); ... - switch (event) { ... - case CS_EVENT_PM_RESUME: - if (verify_cis_cache(skt) != 0) { - dev_dbg(&skt->dev, "cis mismatch - different card\n"); - /* first, remove the card */ - ds_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); - mutex_lock(&s->ops_mutex); - destroy_cis_cache(skt); - kfree(skt->fake_cis); - skt->fake_cis = NULL; - s->functions = 0; - mutex_unlock(&s->ops_mutex); - /* now, add the new card */ - ds_event(skt, CS_EVENT_CARD_INSERTION, - CS_EVENT_PRI_LOW); - } - break; ... - } - pcmcia_put_socket(s); - return 0; -} /* ds_event */ to: +static int pcmcia_bus_early_resume(struct pcmcia_socket *skt) +{ + if (!verify_cis_cache(skt)) { + pcmcia_put_socket(skt); + return 0; + } + dev_dbg(&skt->dev, "cis mismatch - different card\n"); + /* first, remove the card */ + pcmcia_bus_remove(skt); + mutex_lock(&skt->ops_mutex); + destroy_cis_cache(skt); + kfree(skt->fake_cis); + skt->fake_cis = NULL; + skt->functions = 0; + mutex_unlock(&skt->ops_mutex); + /* now, add the new card */ + pcmcia_bus_add(skt); + return 0; +} As can be seen, the original function called pcmcia_get_socket() and pcmcia_put_socket() around the guts, whereas the replacement code calls pcmcia_put_socket() only in one path. This creates an imbalance in the refcounting. Testing with pcmcia_put_socket() put removed shows that the bug is gone: dpm_suspend: c1a10998 [pcmcia_socket0] 5 dpm_suspend_noirq: c1a10998 [pcmcia_socket0] 5 dpm_resume_noirq: c1a10998 [pcmcia_socket0] 5 dpm_resume: c1a10998 [pcmcia_socket0] 5 dpm_complete: c1a10998 [pcmcia_socket0] 5 Tested-by: Russell King Signed-off-by: Russell King Cc: Dominik Brodowski Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/pcmcia/ds.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 749c2a16012..1932029de48 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -1269,10 +1269,8 @@ static int pcmcia_bus_add(struct pcmcia_socket *skt) static int pcmcia_bus_early_resume(struct pcmcia_socket *skt) { - if (!verify_cis_cache(skt)) { - pcmcia_put_socket(skt); + if (!verify_cis_cache(skt)) return 0; - } dev_dbg(&skt->dev, "cis mismatch - different card\n"); From b9134812300fd0e3c242c50af5c563065d2f1b1e Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Wed, 8 Feb 2012 17:13:38 -0800 Subject: [PATCH 0879/4025] mm: compaction: check for overlapping nodes during isolation for migration commit dc9086004b3d5db75997a645b3fe08d9138b7ad0 upstream. When isolating pages for migration, migration starts at the start of a zone while the free scanner starts at the end of the zone. Migration avoids entering a new zone by never going beyond the free scanned. Unfortunately, in very rare cases nodes can overlap. When this happens, migration isolates pages without the LRU lock held, corrupting lists which will trigger errors in reclaim or during page free such as in the following oops BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 IP: [] free_pcppages_bulk+0xcc/0x450 PGD 1dda554067 PUD 1e1cb58067 PMD 0 Oops: 0000 [#1] SMP CPU 37 Pid: 17088, comm: memcg_process_s Tainted: G X RIP: free_pcppages_bulk+0xcc/0x450 Process memcg_process_s (pid: 17088, threadinfo ffff881c2926e000, task ffff881c2926c0c0) Call Trace: free_hot_cold_page+0x17e/0x1f0 __pagevec_free+0x90/0xb0 release_pages+0x22a/0x260 pagevec_lru_move_fn+0xf3/0x110 putback_lru_page+0x66/0xe0 unmap_and_move+0x156/0x180 migrate_pages+0x9e/0x1b0 compact_zone+0x1f3/0x2f0 compact_zone_order+0xa2/0xe0 try_to_compact_pages+0xdf/0x110 __alloc_pages_direct_compact+0xee/0x1c0 __alloc_pages_slowpath+0x370/0x830 __alloc_pages_nodemask+0x1b1/0x1c0 alloc_pages_vma+0x9b/0x160 do_huge_pmd_anonymous_page+0x160/0x270 do_page_fault+0x207/0x4c0 page_fault+0x25/0x30 The "X" in the taint flag means that external modules were loaded but but is unrelated to the bug triggering. The real problem was because the PFN layout looks like this Zone PFN ranges: DMA 0x00000010 -> 0x00001000 DMA32 0x00001000 -> 0x00100000 Normal 0x00100000 -> 0x01e80000 Movable zone start PFN for each node early_node_map[14] active PFN ranges 0: 0x00000010 -> 0x0000009b 0: 0x00000100 -> 0x0007a1ec 0: 0x0007a354 -> 0x0007a379 0: 0x0007f7ff -> 0x0007f800 0: 0x00100000 -> 0x00680000 1: 0x00680000 -> 0x00e80000 0: 0x00e80000 -> 0x01080000 1: 0x01080000 -> 0x01280000 0: 0x01280000 -> 0x01480000 1: 0x01480000 -> 0x01680000 0: 0x01680000 -> 0x01880000 1: 0x01880000 -> 0x01a80000 0: 0x01a80000 -> 0x01c80000 1: 0x01c80000 -> 0x01e80000 The fix is straight-forward. isolate_migratepages() has to make a similar check to isolate_freepage to ensure that it never isolates pages from a zone it does not hold the LRU lock for. This was discovered in a 3.0-based kernel but it affects 3.1.x, 3.2.x and current mainline. Signed-off-by: Mel Gorman Acked-by: Michal Nazarewicz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/compaction.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mm/compaction.c b/mm/compaction.c index 7ca6842c665..c4bc5acf865 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -337,8 +337,17 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone, continue; nr_scanned++; - /* Get the page and skip if free */ + /* + * Get the page and ensure the page is within the same zone. + * See the comment in isolate_freepages about overlapping + * nodes. It is deliberate that the new zone lock is not taken + * as memory compaction should not move pages between nodes. + */ page = pfn_to_page(low_pfn); + if (page_zone(page) != zone) + continue; + + /* Skip if free */ if (PageBuddy(page)) continue; From 91b08ca08c8f5fbad289950086d6fb7ab0642d63 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Wed, 8 Feb 2012 17:13:40 -0800 Subject: [PATCH 0880/4025] mm: fix UP THP spin_is_locked BUGs commit b9980cdcf2524c5fe15d8cbae9c97b3ed6385563 upstream. Fix CONFIG_TRANSPARENT_HUGEPAGE=y CONFIG_SMP=n CONFIG_DEBUG_VM=y CONFIG_DEBUG_SPINLOCK=n kernel: spin_is_locked() is then always false, and so triggers some BUGs in Transparent HugePage codepaths. asm-generic/bug.h mentions this problem, and provides a WARN_ON_SMP(x); but being too lazy to add VM_BUG_ON_SMP, BUG_ON_SMP, WARN_ON_SMP_ONCE, VM_WARN_ON_SMP_ONCE, just test NR_CPUS != 1 in the existing VM_BUG_ONs. Signed-off-by: Hugh Dickins Cc: Andrea Arcangeli Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/huge_memory.c | 4 ++-- mm/swap.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index cc5acf9998b..78a83e71699 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2020,7 +2020,7 @@ static void collect_mm_slot(struct mm_slot *mm_slot) { struct mm_struct *mm = mm_slot->mm; - VM_BUG_ON(!spin_is_locked(&khugepaged_mm_lock)); + VM_BUG_ON(NR_CPUS != 1 && !spin_is_locked(&khugepaged_mm_lock)); if (khugepaged_test_exit(mm)) { /* free mm_slot */ @@ -2048,7 +2048,7 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages, int progress = 0; VM_BUG_ON(!pages); - VM_BUG_ON(!spin_is_locked(&khugepaged_mm_lock)); + VM_BUG_ON(NR_CPUS != 1 && !spin_is_locked(&khugepaged_mm_lock)); if (khugepaged_scan.mm_slot) mm_slot = khugepaged_scan.mm_slot; diff --git a/mm/swap.c b/mm/swap.c index 87627f181c3..4a1fc6db89e 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -667,7 +667,7 @@ void lru_add_page_tail(struct zone* zone, VM_BUG_ON(!PageHead(page)); VM_BUG_ON(PageCompound(page_tail)); VM_BUG_ON(PageLRU(page_tail)); - VM_BUG_ON(!spin_is_locked(&zone->lru_lock)); + VM_BUG_ON(NR_CPUS != 1 && !spin_is_locked(&zone->lru_lock)); SetPageLRU(page_tail); From b96473a25fa375b08c9bf0c1c0dbf47ca826eaec Mon Sep 17 00:00:00 2001 From: Marco Sanvido Date: Tue, 3 Jan 2012 17:12:57 -0800 Subject: [PATCH 0881/4025] target: Use correct preempted registration sense code commit 9e08e34e3735ae057eb3834da3570995811b7eb9 upstream. The comments quote the right parts of the spec: * d) Establish a unit attention condition for the * initiator port associated with every I_T nexus * that lost its registration other than the I_T * nexus on which the PERSISTENT RESERVE OUT command * was received, with the additional sense code set * to REGISTRATIONS PREEMPTED. and * e) Establish a unit attention condition for the initiator * port associated with every I_T nexus that lost its * persistent reservation and/or registration, with the * additional sense code set to REGISTRATIONS PREEMPTED; but the actual code accidentally uses ASCQ_2AH_RESERVATIONS_PREEMPTED instead of ASCQ_2AH_REGISTRATIONS_PREEMPTED. Fix this. Signed-off-by: Marco Sanvido Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_pr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index b662db3a320..025d5c7e56e 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -3079,7 +3079,7 @@ static int core_scsi3_pro_preempt( if (!(calling_it_nexus)) core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, 0x2A, - ASCQ_2AH_RESERVATIONS_PREEMPTED); + ASCQ_2AH_REGISTRATIONS_PREEMPTED); } spin_unlock(&pr_tmpl->registration_lock); /* @@ -3191,7 +3191,7 @@ static int core_scsi3_pro_preempt( * additional sense code set to REGISTRATIONS PREEMPTED; */ core_scsi3_ua_allocate(pr_reg_nacl, pr_res_mapped_lun, 0x2A, - ASCQ_2AH_RESERVATIONS_PREEMPTED); + ASCQ_2AH_REGISTRATIONS_PREEMPTED); } spin_unlock(&pr_tmpl->registration_lock); /* From b8a8c4aa9e22c2de7af17ea48b7cc868f5bc79ad Mon Sep 17 00:00:00 2001 From: Marco Sanvido Date: Tue, 3 Jan 2012 17:12:58 -0800 Subject: [PATCH 0882/4025] target: Allow PERSISTENT RESERVE IN for non-reservation holder commit 6816966a8418b980481b4dced7eddd1796b145e8 upstream. Initiators that aren't the active reservation holder should be able to do a PERSISTENT RESERVE IN command in all cases, so add it to the list of allowed CDBs in core_scsi3_pr_seq_non_holder(). Signed-off-by: Marco Sanvido Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_pr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 025d5c7e56e..98e12d31c9c 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -471,6 +471,7 @@ static int core_scsi3_pr_seq_non_holder( case READ_MEDIA_SERIAL_NUMBER: case REPORT_LUNS: case REQUEST_SENSE: + case PERSISTENT_RESERVE_IN: ret = 0; /*/ Allowed CDBs */ break; default: From 967a6f42d195569b596f9af39cd878803a0d1f8b Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 9 Jan 2012 17:54:00 -0800 Subject: [PATCH 0883/4025] target: Correct sense key for INVALID FIELD IN {PARAMETER LIST,CDB} commit 9fbc8909876a2160044e71d376848973b9bfdc3f upstream. According to SPC-4, the sense key for commands that are failed with INVALID FIELD IN PARAMETER LIST and INVALID FIELD IN CDB should be ILLEGAL REQUEST (5h) rather than ABORTED COMMAND (Bh). Without this patch, a tcm_loop LUN incorrectly gives: # sg_raw -r 1 -v /dev/sda 3 1 0 0 ff 0 Sense Information: Fixed format, current; Sense key: Aborted Command Additional sense: Invalid field in cdb Raw sense data (in hex): 70 00 0b 00 00 00 00 0a 00 00 00 00 24 00 00 00 00 00 While a real SCSI disk gives: Sense Information: Fixed format, current; Sense key: Illegal Request Additional sense: Invalid field in cdb Raw sense data (in hex): 70 00 05 00 00 00 00 18 00 00 00 00 24 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 with the main point being that the real disk gives a sense key of ILLEGAL REQUEST (5h). Signed-off-by: Roland Dreier Signed-off-by: Nicholas Bellinger Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_transport.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index bb86655dd40..d3a7342317e 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -5709,8 +5709,8 @@ int transport_send_check_condition_and_sense( /* CURRENT ERROR */ buffer[offset] = 0x70; buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ABORTED COMMAND */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + /* ILLEGAL REQUEST */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* INVALID FIELD IN CDB */ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x24; break; @@ -5718,8 +5718,8 @@ int transport_send_check_condition_and_sense( /* CURRENT ERROR */ buffer[offset] = 0x70; buffer[offset+SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ABORTED COMMAND */ - buffer[offset+SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; + /* ILLEGAL REQUEST */ + buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; /* INVALID FIELD IN PARAMETER LIST */ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x26; break; From 3f64466ca0f04dc2b138a3c1e348a7e15b91ebba Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Sun, 22 Jan 2012 16:33:46 +0200 Subject: [PATCH 0884/4025] Staging: asus_oled: fix image processing commit 635032cb397b396241372fa0ff36ae758e658b23 upstream. Programming an image was broken, because odev->buf_offs was not advanced for val == 0 in append_values(). This regression was introduced in: commit 1ff12a4aa354bed093a0240d5e6347b1e27601bc Author: Kevin A. Granade Date: Sat Sep 5 01:03:39 2009 -0500 Staging: asus_oled: Cleaned up checkpatch issues. Fix the image processing by special-casing val == 0. I have tested this change on an Asus G50V laptop only. Cc: Jakub Schmidtke Cc: Kevin A. Granade Signed-off-by: Pekka Paalanen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/asus_oled/asus_oled.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c index 7bb7da7959a..8894bd5f7d8 100644 --- a/drivers/staging/asus_oled/asus_oled.c +++ b/drivers/staging/asus_oled/asus_oled.c @@ -355,7 +355,14 @@ static void send_data(struct asus_oled_dev *odev) static int append_values(struct asus_oled_dev *odev, uint8_t val, size_t count) { - while (count-- > 0 && val) { + odev->last_val = val; + + if (val == 0) { + odev->buf_offs += count; + return 0; + } + + while (count-- > 0) { size_t x = odev->buf_offs % odev->width; size_t y = odev->buf_offs / odev->width; size_t i; @@ -406,7 +413,6 @@ static int append_values(struct asus_oled_dev *odev, uint8_t val, size_t count) ; } - odev->last_val = val; odev->buf_offs++; } From 946972e6ab9c59142f5cb51f31ea36a090f2ce16 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Sun, 22 Jan 2012 16:33:47 +0200 Subject: [PATCH 0885/4025] Staging: asus_oled: fix NULL-ptr crash on unloading commit 3589e74595a4332ebf77b5ed006f3c6686071ecd upstream. Asus_oled triggers the following bug on module unloading: usbcore: deregistering interface driver asus-oled BUG: unable to handle kernel NULL pointer dereference at 0000000000000038 IP: [] sysfs_delete_link+0x30/0x66 Call Trace: [] device_remove_class_symlinks+0x6b/0x70 [] device_del+0x9f/0x1ab [] device_unregister+0x11/0x1e [] asus_oled_disconnect+0x4f/0x9e [asus_oled] [] usb_unbind_interface+0x54/0x103 [] __device_release_driver+0xa2/0xeb [] driver_detach+0x87/0xad [] bus_remove_driver+0x91/0xc1 [] driver_unregister+0x66/0x6e [] usb_deregister+0xbb/0xc4 [] asus_oled_exit+0x2f/0x31 [asus_oled] [] sys_delete_module+0x1b8/0x21b [] ? do_munmap+0x2ef/0x313 [] system_call_fastpath+0x16/0x1b This is due to an incorrect destruction sequence in asus_oled_exit(). Fix the order, fixes the bug. Tested on an Asus G50V laptop only. Cc: Jakub Schmidtke Signed-off-by: Pekka Paalanen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/asus_oled/asus_oled.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c index 8894bd5f7d8..63bafbb0980 100644 --- a/drivers/staging/asus_oled/asus_oled.c +++ b/drivers/staging/asus_oled/asus_oled.c @@ -811,10 +811,9 @@ static int __init asus_oled_init(void) static void __exit asus_oled_exit(void) { + usb_deregister(&oled_driver); class_remove_file(oled_class, &class_attr_version.attr); class_destroy(oled_class); - - usb_deregister(&oled_driver); } module_init(asus_oled_init); From fc2286972bd426b03fe64d79d39d9ff9ac1c4cc3 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Sat, 7 Jan 2012 10:07:03 -0600 Subject: [PATCH 0886/4025] staging: r8712u: Add new Sitecom UsB ID commit 1793bf1deddc8ce25dc41925d5dbe64536c841b6 upstream. Add USB ID for SITECOM WLA-1000 V1 001 WLAN Reported-and-tested-by: Roland Gruber Reported-and-tested-by: Dario Lucia Signed-off-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/usb_intf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index 6cb7e28c99a..6d88d1a45f1 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -86,6 +86,7 @@ static struct usb_device_id rtl871x_usb_id_tbl[] = { {USB_DEVICE(0x0DF6, 0x0045)}, {USB_DEVICE(0x0DF6, 0x0059)}, /* 11n mode disable */ {USB_DEVICE(0x0DF6, 0x004B)}, + {USB_DEVICE(0x0DF6, 0x005B)}, {USB_DEVICE(0x0DF6, 0x005D)}, {USB_DEVICE(0x0DF6, 0x0063)}, /* Sweex */ From d6adb709398ee159ab2ef26d51760041ca5e8262 Mon Sep 17 00:00:00 2001 From: Timo Juhani Lindfors Date: Sun, 29 Jan 2012 16:12:13 +0200 Subject: [PATCH 0887/4025] usb: gadget: zero: fix bug in loopback autoresume handling commit 683da59d7b8ae04891636d4b59893cd4e9b0b7e5 upstream. ab943a2e125b (USB: gadget: gadget zero uses new suspend/resume hooks) introduced a copy-paste error where f_loopback.c writes to a variable declared in f_sourcesink.c. This prevents one from creating gadgets that only have a loopback function. Signed-off-by: Timo Juhani Lindfors Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/f_loopback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index b37960f9e75..0e64a47cd6b 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -373,7 +373,7 @@ int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume) /* support autoresume for remote wakeup testing */ if (autoresume) - sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; /* support OTG systems */ if (gadget_is_otg(cdev->gadget)) { From 20ef4883ff2c65f96da1617446ebc58c0a707970 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Fri, 27 Jan 2012 20:27:32 +0530 Subject: [PATCH 0888/4025] usb: Skip PCI USB quirk handling for Netlogic XLP commit e4436a7c17ac2b5e138f93f83a541cba9b311685 upstream. The Netlogic XLP SoC's on-chip USB controller appears as a PCI USB device, but does not need the EHCI/OHCI handoff done in usb/host/pci-quirks.c. The pci-quirks.c is enabled for all vendors and devices, and is enabled if USB and PCI are configured. If we do not skip the qurik handling on XLP, the readb() call in ehci_bios_handoff() will cause a crash since byte access is not supported for EHCI registers in XLP. Signed-off-by: Jayachandran C Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 23e04fb038b..20f2f216347 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -866,6 +866,12 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev) static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) { + /* Skip Netlogic mips SoC's internal PCI USB controller. + * This device does not need/support EHCI/OHCI handoff + */ + if (pdev->vendor == 0x184e) /* vendor Netlogic */ + return; + if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI) quirk_usb_handoff_uhci(pdev); else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI) From 71f1a6a81350c7bf75141e183c1d5e310f264622 Mon Sep 17 00:00:00 2001 From: Milan Kocian Date: Fri, 3 Feb 2012 14:28:00 +0100 Subject: [PATCH 0889/4025] USB: usbserial: add new PID number (0xa951) to the ftdi driver commit 90451e6973a5da155c6f315a409ca0a8d3ce6b76 upstream. Signed-off-by: Milan Kocian Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index a872cc2c93a..78c7d420bdd 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -838,6 +838,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LOGBOOKML_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) }, { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 76d4f31b38c..4eb77150f03 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1187,3 +1187,10 @@ */ /* ZigBee controller */ #define FTDI_RF_R106 0x8A28 + +/* + * Product: HCP HIT GPRS modem + * Manufacturer: HCP d.o.o. + * ATI command output: Cinterion MC55i + */ +#define FTDI_CINTERION_MC55I_PID 0xA951 From 27939dafb1bd1053fda96d69d4b693f29f2389b6 Mon Sep 17 00:00:00 2001 From: Rui li Date: Tue, 31 Jan 2012 15:27:33 +0800 Subject: [PATCH 0890/4025] USB: add new zte 3g-dongle's pid to option.c commit 1608ea5f4b5d6262cd6e808839491cfb2a67405a upstream. As ZTE have and will use more pid for new products this year, so we need to add some new zte 3g-dongle's pid on option.c , and delete one pid 0x0154 because it use for mass-storage port. Signed-off-by: Rui li Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 129 +++++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 2a9ed6ec8cb..338d082525b 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -855,6 +855,18 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0083, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0086, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0087, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0088, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0089, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0090, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0091, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0092, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0093, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0094, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0095, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0096, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0097, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0098, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0099, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0105, 0xff, 0xff, 0xff) }, @@ -883,7 +895,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0151, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0153, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0154, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0155, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff) }, @@ -892,6 +903,12 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0160, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0164, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0168, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0170, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0176, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) }, @@ -1066,6 +1083,116 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1401, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1403, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1404, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1405, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1406, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1407, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1408, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1409, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1410, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1411, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1412, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1413, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1414, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1415, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1416, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1417, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1418, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1419, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1420, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1421, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1422, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1423, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1424, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1425, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1426, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1427, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1428, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1429, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1430, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1431, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1432, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1433, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1434, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1435, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1436, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1437, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1438, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1439, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1440, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1441, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1442, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1443, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1444, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1445, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1446, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1447, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1448, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1449, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1450, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1451, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1452, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1453, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1454, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1455, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1456, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1457, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1458, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1459, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1460, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1461, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1462, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1463, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1464, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1465, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1466, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1467, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1468, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1469, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1470, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1471, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1472, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1473, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1474, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1475, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1476, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1477, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1478, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1479, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1480, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1481, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1482, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1483, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1484, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1485, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1486, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1487, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1488, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1489, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1490, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1491, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1492, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1493, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1494, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1495, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1496, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1497, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1498, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1499, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1500, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1501, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1502, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1503, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1504, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1505, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1506, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1507, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1508, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1509, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1510, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0027, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) }, From ebc5010892742064d7436a1c1ff91b3189c4b8c7 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 1 Feb 2012 12:31:47 +0800 Subject: [PATCH 0891/4025] mmc: cb710 core: Add missing spin_lock_init for irq_lock of struct cb710_chip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b5266ea675c5a041e2852c7ccec4cf2d4f5e0cf4 upstream. Signed-off-by: Axel Lin Acked-by: Michał Mirosław Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cb710/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/cb710/core.c b/drivers/misc/cb710/core.c index efec4139c3f..b1f16d6084a 100644 --- a/drivers/misc/cb710/core.c +++ b/drivers/misc/cb710/core.c @@ -244,6 +244,7 @@ static int __devinit cb710_probe(struct pci_dev *pdev, if (err) return err; + spin_lock_init(&chip->irq_lock); chip->pdev = pdev; chip->iobase = pcim_iomap_table(pdev)[0]; From 2d8a3a209b35f8301c86e7962f636a372a0d7cad Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 6 Jan 2012 15:56:31 +0100 Subject: [PATCH 0892/4025] powernow-k8: Avoid Pstate MSR accesses on systems supporting CPB commit 201bf0f129e1715a33568d1563d9a75b840ab4d3 upstream. Due to CPB we can't directly map SW Pstates to Pstate MSRs. Get rid of the paranoia check. (assuming that the ACPI Pstate information is correct.) Signed-off-by: Andreas Herrmann Signed-off-by: Dave Jones Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/powernow-k8.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index bce576d7478..e0329f9fa40 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -926,23 +926,24 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data, invalidate_entry(powernow_table, i); continue; } - rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi); - if (!(hi & HW_PSTATE_VALID_MASK)) { - pr_debug("invalid pstate %d, ignoring\n", index); - invalidate_entry(powernow_table, i); - continue; - } - - powernow_table[i].index = index; - /* Frequency may be rounded for these */ if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10) || boot_cpu_data.x86 == 0x11) { + + rdmsr(MSR_PSTATE_DEF_BASE + index, lo, hi); + if (!(hi & HW_PSTATE_VALID_MASK)) { + pr_debug("invalid pstate %d, ignoring\n", index); + invalidate_entry(powernow_table, i); + continue; + } + powernow_table[i].frequency = freq_from_fid_did(lo & 0x3f, (lo >> 6) & 7); } else powernow_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000; + + powernow_table[i].index = index; } return 0; } From 323a479328cbc2fb5cf647790f7414ca570a577b Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 6 Jan 2012 15:57:55 +0100 Subject: [PATCH 0893/4025] powernow-k8: Fix indexing issue commit a8eb28480e9b637cc78b9aa5e08612ba97e1317a upstream. The driver uses the pstate number from the status register as index in its table of ACPI pstates (powernow_table). This is wrong as this is not a 1-to-1 mapping. For example we can have _PSS information to just utilize Pstate 0 and Pstate 4, ie. powernow-k8: Core Performance Boosting: on. powernow-k8: 0 : pstate 0 (2200 MHz) powernow-k8: 1 : pstate 4 (1400 MHz) In this example the driver's powernow_table has just 2 entries. Using the pstate number (4) as index into this table is just plain wrong. Signed-off-by: Andreas Herrmann Signed-off-by: Dave Jones Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/powernow-k8.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index e0329f9fa40..ad683ec2c57 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -54,6 +54,9 @@ static DEFINE_PER_CPU(struct powernow_k8_data *, powernow_data); static int cpu_family = CPU_OPTERON; +/* array to map SW pstate number to acpi state */ +static u32 ps_to_as[8]; + /* core performance boost */ static bool cpb_capable, cpb_enabled; static struct msr __percpu *msrs; @@ -80,9 +83,9 @@ static u32 find_khz_freq_from_fid(u32 fid) } static u32 find_khz_freq_from_pstate(struct cpufreq_frequency_table *data, - u32 pstate) + u32 pstate) { - return data[pstate].frequency; + return data[ps_to_as[pstate]].frequency; } /* Return the vco fid for an input fid @@ -926,6 +929,9 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data, invalidate_entry(powernow_table, i); continue; } + + ps_to_as[index] = i; + /* Frequency may be rounded for these */ if ((boot_cpu_data.x86 == 0x10 && boot_cpu_data.x86_model < 10) || boot_cpu_data.x86 == 0x11) { @@ -1190,7 +1196,8 @@ static int powernowk8_target(struct cpufreq_policy *pol, powernow_k8_acpi_pst_values(data, newstate); if (cpu_family == CPU_HW_PSTATE) - ret = transition_frequency_pstate(data, newstate); + ret = transition_frequency_pstate(data, + data->powernow_table[newstate].index); else ret = transition_frequency_fidvid(data, newstate); if (ret) { @@ -1203,7 +1210,7 @@ static int powernowk8_target(struct cpufreq_policy *pol, if (cpu_family == CPU_HW_PSTATE) pol->cur = find_khz_freq_from_pstate(data->powernow_table, - newstate); + data->powernow_table[newstate].index); else pol->cur = find_khz_freq_from_fid(data->currfid); ret = 0; From 8a533666d1591cf4ea596c6bd710e2fe682cb56a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 9 Feb 2012 16:13:19 -0500 Subject: [PATCH 0894/4025] net: fix NULL dereferences in check_peer_redir() [ Upstream commit d3aaeb38c40e5a6c08dd31a1b64da65c4352be36, along with dependent backports of commits: 69cce1d1404968f78b177a0314f5822d5afdbbfb 9de79c127cccecb11ae6a21ab1499e87aa222880 218fa90f072e4aeff9003d57e390857f4f35513e 580da35a31f91a594f3090b7a2c39b85cb051a12 f7e57044eeb1841847c24aa06766c8290c202583 e049f28883126c689cf95859480d9ee4ab23b7fa ] Gergely Kalman reported crashes in check_peer_redir(). It appears commit f39925dbde778 (ipv4: Cache learned redirect information in inetpeer.) added a race, leading to possible NULL ptr dereference. Since we can now change dst neighbour, we should make sure a reader can safely use a neighbour. Add RCU protection to dst neighbour, and make sure check_peer_redir() can be called safely by different cpus in parallel. As neighbours are already freed after one RCU grace period, this patch should not add typical RCU penalty (cache cold effects) Many thanks to Gergely for providing a pretty report pointing to the bug. Reported-by: Gergely Kalman Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/addr.c | 16 +++-- drivers/infiniband/hw/cxgb3/iwch_cm.c | 16 +++-- drivers/infiniband/hw/cxgb4/cm.c | 46 ++++++++------- drivers/infiniband/hw/mlx4/qp.c | 2 +- drivers/infiniband/hw/nes/nes_cm.c | 8 ++- drivers/infiniband/ulp/ipoib/ipoib_main.c | 59 ++++++++++++------- .../infiniband/ulp/ipoib/ipoib_multicast.c | 24 +++++--- drivers/net/cxgb3/cxgb3_offload.c | 8 +-- drivers/s390/net/qeth_l3_main.c | 25 +++++--- drivers/scsi/cxgbi/cxgb3i/cxgb3i.c | 2 +- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 2 +- drivers/scsi/cxgbi/libcxgbi.c | 4 +- include/net/arp.h | 1 + include/net/dst.h | 27 ++++++++- net/atm/clip.c | 16 +++-- net/bridge/br_netfilter.c | 6 +- net/core/dst.c | 15 +++-- net/core/neighbour.c | 19 +++--- net/decnet/dn_neigh.c | 8 +-- net/decnet/dn_route.c | 18 +++--- net/ipv4/arp.c | 28 +++++---- net/ipv4/ip_gre.c | 2 +- net/ipv4/ip_output.c | 22 +++++-- net/ipv4/route.c | 31 ++++++---- net/ipv6/addrconf.c | 2 +- net/ipv6/ip6_fib.c | 2 +- net/ipv6/ip6_output.c | 40 ++++++++++--- net/ipv6/ndisc.c | 4 +- net/ipv6/route.c | 59 ++++++++++++------- net/ipv6/sit.c | 4 +- net/sched/sch_teql.c | 31 ++++++---- net/xfrm/xfrm_policy.c | 2 +- 32 files changed, 359 insertions(+), 190 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 8e21d457b89..f2a84c6f854 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -215,7 +215,9 @@ static int addr4_resolve(struct sockaddr_in *src_in, neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->dst.dev); if (!neigh || !(neigh->nud_state & NUD_VALID)) { - neigh_event_send(rt->dst.neighbour, NULL); + rcu_read_lock(); + neigh_event_send(dst_get_neighbour(&rt->dst), NULL); + rcu_read_unlock(); ret = -ENODATA; if (neigh) goto release; @@ -273,14 +275,16 @@ static int addr6_resolve(struct sockaddr_in6 *src_in, goto put; } - neigh = dst->neighbour; + rcu_read_lock(); + neigh = dst_get_neighbour(dst); if (!neigh || !(neigh->nud_state & NUD_VALID)) { - neigh_event_send(dst->neighbour, NULL); + if (neigh) + neigh_event_send(neigh, NULL); ret = -ENODATA; - goto put; + } else { + ret = rdma_copy_addr(addr, dst->dev, neigh->ha); } - - ret = rdma_copy_addr(addr, dst->dev, neigh->ha); + rcu_read_unlock(); put: dst_release(dst); return ret; diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 2332dc22aa0..e55ce7a428b 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -1328,6 +1328,7 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) struct iwch_ep *child_ep, *parent_ep = ctx; struct cpl_pass_accept_req *req = cplhdr(skb); unsigned int hwtid = GET_TID(req); + struct neighbour *neigh; struct dst_entry *dst; struct l2t_entry *l2t; struct rtable *rt; @@ -1364,7 +1365,10 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) goto reject; } dst = &rt->dst; - l2t = t3_l2t_get(tdev, dst->neighbour, dst->neighbour->dev); + rcu_read_lock(); + neigh = dst_get_neighbour(dst); + l2t = t3_l2t_get(tdev, neigh, neigh->dev); + rcu_read_unlock(); if (!l2t) { printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n", __func__); @@ -1874,10 +1878,11 @@ static int is_loopback_dst(struct iw_cm_id *cm_id) int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) { - int err = 0; struct iwch_dev *h = to_iwch_dev(cm_id->device); + struct neighbour *neigh; struct iwch_ep *ep; struct rtable *rt; + int err = 0; if (is_loopback_dst(cm_id)) { err = -ENOSYS; @@ -1933,9 +1938,12 @@ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) } ep->dst = &rt->dst; + rcu_read_lock(); + neigh = dst_get_neighbour(ep->dst); + /* get a l2t entry */ - ep->l2t = t3_l2t_get(ep->com.tdev, ep->dst->neighbour, - ep->dst->neighbour->dev); + ep->l2t = t3_l2t_get(ep->com.tdev, neigh, neigh->dev); + rcu_read_unlock(); if (!ep->l2t) { printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__); err = -ENOMEM; diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 31fb44085c9..daa93e942e1 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -1325,6 +1325,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) unsigned int stid = GET_POPEN_TID(ntohl(req->tos_stid)); struct tid_info *t = dev->rdev.lldi.tids; unsigned int hwtid = GET_TID(req); + struct neighbour *neigh; struct dst_entry *dst; struct l2t_entry *l2t; struct rtable *rt; @@ -1357,11 +1358,12 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) goto reject; } dst = &rt->dst; - if (dst->neighbour->dev->flags & IFF_LOOPBACK) { + rcu_read_lock(); + neigh = dst_get_neighbour(dst); + if (neigh->dev->flags & IFF_LOOPBACK) { pdev = ip_dev_find(&init_net, peer_ip); BUG_ON(!pdev); - l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, dst->neighbour, - pdev, 0); + l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh, pdev, 0); mtu = pdev->mtu; tx_chan = cxgb4_port_chan(pdev); smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1; @@ -1372,18 +1374,18 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) rss_qid = dev->rdev.lldi.rxq_ids[cxgb4_port_idx(pdev) * step]; dev_put(pdev); } else { - l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, dst->neighbour, - dst->neighbour->dev, 0); + l2t = cxgb4_l2t_get(dev->rdev.lldi.l2t, neigh, neigh->dev, 0); mtu = dst_mtu(dst); - tx_chan = cxgb4_port_chan(dst->neighbour->dev); - smac_idx = (cxgb4_port_viid(dst->neighbour->dev) & 0x7F) << 1; + tx_chan = cxgb4_port_chan(neigh->dev); + smac_idx = (cxgb4_port_viid(neigh->dev) & 0x7F) << 1; step = dev->rdev.lldi.ntxq / dev->rdev.lldi.nchan; - txq_idx = cxgb4_port_idx(dst->neighbour->dev) * step; - ctrlq_idx = cxgb4_port_idx(dst->neighbour->dev); + txq_idx = cxgb4_port_idx(neigh->dev) * step; + ctrlq_idx = cxgb4_port_idx(neigh->dev); step = dev->rdev.lldi.nrxq / dev->rdev.lldi.nchan; rss_qid = dev->rdev.lldi.rxq_ids[ - cxgb4_port_idx(dst->neighbour->dev) * step]; + cxgb4_port_idx(neigh->dev) * step]; } + rcu_read_unlock(); if (!l2t) { printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n", __func__); @@ -1847,6 +1849,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) struct c4iw_ep *ep; struct rtable *rt; struct net_device *pdev; + struct neighbour *neigh; int step; if ((conn_param->ord > c4iw_max_read_depth) || @@ -1908,14 +1911,16 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) } ep->dst = &rt->dst; + rcu_read_lock(); + neigh = dst_get_neighbour(ep->dst); + /* get a l2t entry */ - if (ep->dst->neighbour->dev->flags & IFF_LOOPBACK) { + if (neigh->dev->flags & IFF_LOOPBACK) { PDBG("%s LOOPBACK\n", __func__); pdev = ip_dev_find(&init_net, cm_id->remote_addr.sin_addr.s_addr); ep->l2t = cxgb4_l2t_get(ep->com.dev->rdev.lldi.l2t, - ep->dst->neighbour, - pdev, 0); + neigh, pdev, 0); ep->mtu = pdev->mtu; ep->tx_chan = cxgb4_port_chan(pdev); ep->smac_idx = (cxgb4_port_viid(pdev) & 0x7F) << 1; @@ -1930,21 +1935,20 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) dev_put(pdev); } else { ep->l2t = cxgb4_l2t_get(ep->com.dev->rdev.lldi.l2t, - ep->dst->neighbour, - ep->dst->neighbour->dev, 0); + neigh, neigh->dev, 0); ep->mtu = dst_mtu(ep->dst); - ep->tx_chan = cxgb4_port_chan(ep->dst->neighbour->dev); - ep->smac_idx = (cxgb4_port_viid(ep->dst->neighbour->dev) & - 0x7F) << 1; + ep->tx_chan = cxgb4_port_chan(neigh->dev); + ep->smac_idx = (cxgb4_port_viid(neigh->dev) & 0x7F) << 1; step = ep->com.dev->rdev.lldi.ntxq / ep->com.dev->rdev.lldi.nchan; - ep->txq_idx = cxgb4_port_idx(ep->dst->neighbour->dev) * step; - ep->ctrlq_idx = cxgb4_port_idx(ep->dst->neighbour->dev); + ep->txq_idx = cxgb4_port_idx(neigh->dev) * step; + ep->ctrlq_idx = cxgb4_port_idx(neigh->dev); step = ep->com.dev->rdev.lldi.nrxq / ep->com.dev->rdev.lldi.nchan; ep->rss_qid = ep->com.dev->rdev.lldi.rxq_ids[ - cxgb4_port_idx(ep->dst->neighbour->dev) * step]; + cxgb4_port_idx(neigh->dev) * step]; } + rcu_read_unlock(); if (!ep->l2t) { printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__); err = -ENOMEM; diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 2001f20a436..23c04ff6519 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1301,7 +1301,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, int is_eth; int is_vlan = 0; int is_grh; - u16 vlan; + u16 vlan = 0; send_size = 0; for (i = 0; i < wr->num_sge; ++i) diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index e74cdf9ef47..a1f74f6381b 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -1150,9 +1150,11 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi neigh_release(neigh); } - if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID))) - neigh_event_send(rt->dst.neighbour, NULL); - + if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID))) { + rcu_read_lock(); + neigh_event_send(dst_get_neighbour(&rt->dst), NULL); + rcu_read_unlock(); + } ip_rt_put(rt); return rc; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 86addca9ddf..a98c414978e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -555,14 +555,17 @@ static int path_rec_start(struct net_device *dev, return 0; } +/* called with rcu_read_lock */ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_path *path; struct ipoib_neigh *neigh; + struct neighbour *n; unsigned long flags; - neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour, skb->dev); + n = dst_get_neighbour(skb_dst(skb)); + neigh = ipoib_neigh_alloc(n, skb->dev); if (!neigh) { ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); @@ -571,9 +574,9 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&priv->lock, flags); - path = __path_find(dev, skb_dst(skb)->neighbour->ha + 4); + path = __path_find(dev, n->ha + 4); if (!path) { - path = path_rec_create(dev, skb_dst(skb)->neighbour->ha + 4); + path = path_rec_create(dev, n->ha + 4); if (!path) goto err_path; @@ -607,7 +610,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) } } else { spin_unlock_irqrestore(&priv->lock, flags); - ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha)); + ipoib_send(dev, skb, path->ah, IPOIB_QPN(n->ha)); return; } } else { @@ -634,20 +637,24 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&priv->lock, flags); } +/* called with rcu_read_lock */ static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(skb->dev); + struct dst_entry *dst = skb_dst(skb); + struct neighbour *n; /* Look up path record for unicasts */ - if (skb_dst(skb)->neighbour->ha[4] != 0xff) { + n = dst_get_neighbour(dst); + if (n->ha[4] != 0xff) { neigh_add_path(skb, dev); return; } /* Add in the P_Key for multicasts */ - skb_dst(skb)->neighbour->ha[8] = (priv->pkey >> 8) & 0xff; - skb_dst(skb)->neighbour->ha[9] = priv->pkey & 0xff; - ipoib_mcast_send(dev, skb_dst(skb)->neighbour->ha + 4, skb); + n->ha[8] = (priv->pkey >> 8) & 0xff; + n->ha[9] = priv->pkey & 0xff; + ipoib_mcast_send(dev, n->ha + 4, skb); } static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, @@ -712,18 +719,23 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_neigh *neigh; + struct neighbour *n = NULL; unsigned long flags; - if (likely(skb_dst(skb) && skb_dst(skb)->neighbour)) { - if (unlikely(!*to_ipoib_neigh(skb_dst(skb)->neighbour))) { + rcu_read_lock(); + if (likely(skb_dst(skb))) + n = dst_get_neighbour(skb_dst(skb)); + + if (likely(n)) { + if (unlikely(!*to_ipoib_neigh(n))) { ipoib_path_lookup(skb, dev); - return NETDEV_TX_OK; + goto unlock; } - neigh = *to_ipoib_neigh(skb_dst(skb)->neighbour); + neigh = *to_ipoib_neigh(n); if (unlikely((memcmp(&neigh->dgid.raw, - skb_dst(skb)->neighbour->ha + 4, + n->ha + 4, sizeof(union ib_gid))) || (neigh->dev != dev))) { spin_lock_irqsave(&priv->lock, flags); @@ -740,17 +752,17 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) ipoib_neigh_free(dev, neigh); spin_unlock_irqrestore(&priv->lock, flags); ipoib_path_lookup(skb, dev); - return NETDEV_TX_OK; + goto unlock; } if (ipoib_cm_get(neigh)) { if (ipoib_cm_up(neigh)) { ipoib_cm_send(dev, skb, ipoib_cm_get(neigh)); - return NETDEV_TX_OK; + goto unlock; } } else if (neigh->ah) { - ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb_dst(skb)->neighbour->ha)); - return NETDEV_TX_OK; + ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(n->ha)); + goto unlock; } if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { @@ -784,13 +796,14 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) phdr->hwaddr + 4); dev_kfree_skb_any(skb); ++dev->stats.tx_dropped; - return NETDEV_TX_OK; + goto unlock; } unicast_arp_send(skb, dev, phdr); } } - +unlock: + rcu_read_unlock(); return NETDEV_TX_OK; } @@ -812,6 +825,8 @@ static int ipoib_hard_header(struct sk_buff *skb, const void *daddr, const void *saddr, unsigned len) { struct ipoib_header *header; + struct dst_entry *dst; + struct neighbour *n; header = (struct ipoib_header *) skb_push(skb, sizeof *header); @@ -823,7 +838,11 @@ static int ipoib_hard_header(struct sk_buff *skb, * destination address onto the front of the skb so we can * figure out where to send the packet later. */ - if ((!skb_dst(skb) || !skb_dst(skb)->neighbour) && daddr) { + dst = skb_dst(skb); + n = NULL; + if (dst) + n = dst_get_neighbour_raw(dst); + if ((!dst || !n) && daddr) { struct ipoib_pseudoheader *phdr = (struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr); memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 3871ac66355..a8d2a891b84 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -258,11 +258,15 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, netif_tx_lock_bh(dev); while (!skb_queue_empty(&mcast->pkt_queue)) { struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue); + struct dst_entry *dst = skb_dst(skb); + struct neighbour *n = NULL; + netif_tx_unlock_bh(dev); skb->dev = dev; - - if (!skb_dst(skb) || !skb_dst(skb)->neighbour) { + if (dst) + n = dst_get_neighbour_raw(dst); + if (!dst || !n) { /* put pseudoheader back on for next time */ skb_push(skb, sizeof (struct ipoib_pseudoheader)); } @@ -715,11 +719,15 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) out: if (mcast && mcast->ah) { - if (skb_dst(skb) && - skb_dst(skb)->neighbour && - !*to_ipoib_neigh(skb_dst(skb)->neighbour)) { - struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb_dst(skb)->neighbour, - skb->dev); + struct dst_entry *dst = skb_dst(skb); + struct neighbour *n = NULL; + + rcu_read_lock(); + if (dst) + n = dst_get_neighbour(dst); + if (n && !*to_ipoib_neigh(n)) { + struct ipoib_neigh *neigh = ipoib_neigh_alloc(n, + skb->dev); if (neigh) { kref_get(&mcast->ah->ref); @@ -727,7 +735,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) list_add_tail(&neigh->list, &mcast->neigh_list); } } - + rcu_read_unlock(); spin_unlock_irqrestore(&priv->lock, flags); ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN); return; diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index 3f2e12c3ac1..015b5152b0d 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -971,7 +971,7 @@ static int nb_callback(struct notifier_block *self, unsigned long event, case (NETEVENT_REDIRECT):{ struct netevent_redirect *nr = ctx; cxgb_redirect(nr->old, nr->new); - cxgb_neigh_update(nr->new->neighbour); + cxgb_neigh_update(dst_get_neighbour(nr->new)); break; } default: @@ -1116,8 +1116,8 @@ static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new) struct l2t_entry *e; struct t3c_tid_entry *te; - olddev = old->neighbour->dev; - newdev = new->neighbour->dev; + olddev = dst_get_neighbour(old)->dev; + newdev = dst_get_neighbour(new)->dev; if (!is_offloading(olddev)) return; if (!is_offloading(newdev)) { @@ -1134,7 +1134,7 @@ static void cxgb_redirect(struct dst_entry *old, struct dst_entry *new) } /* Add new L2T entry */ - e = t3_l2t_get(tdev, new->neighbour, newdev); + e = t3_l2t_get(tdev, dst_get_neighbour(new), newdev); if (!e) { printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n", __func__); diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index fd69da3fa6b..e2c9ac5fcb3 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2742,9 +2742,14 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb) { int cast_type = RTN_UNSPEC; - - if (skb_dst(skb) && skb_dst(skb)->neighbour) { - cast_type = skb_dst(skb)->neighbour->type; + struct neighbour *n = NULL; + struct dst_entry *dst; + + dst = skb_dst(skb); + if (dst) + n = dst_get_neighbour(dst); + if (n) { + cast_type = n->type; if ((cast_type == RTN_BROADCAST) || (cast_type == RTN_MULTICAST) || (cast_type == RTN_ANYCAST)) @@ -2787,6 +2792,9 @@ int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb) static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb, int ipv, int cast_type) { + struct neighbour *n = NULL; + struct dst_entry *dst; + memset(hdr, 0, sizeof(struct qeth_hdr)); hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; hdr->hdr.l3.ext_flags = 0; @@ -2804,13 +2812,16 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, } hdr->hdr.l3.length = skb->len - sizeof(struct qeth_hdr); + dst = skb_dst(skb); + if (dst) + n = dst_get_neighbour(dst); if (ipv == 4) { /* IPv4 */ hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags4(cast_type); memset(hdr->hdr.l3.dest_addr, 0, 12); - if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) { + if (n) { *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = - *((u32 *) skb_dst(skb)->neighbour->primary_key); + *((u32 *) n->primary_key); } else { /* fill in destination address used in ip header */ *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = @@ -2821,9 +2832,9 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, hdr->hdr.l3.flags = qeth_l3_get_qeth_hdr_flags6(cast_type); if (card->info.type == QETH_CARD_TYPE_IQD) hdr->hdr.l3.flags &= ~QETH_HDR_PASSTHRU; - if ((skb_dst(skb)) && (skb_dst(skb)->neighbour)) { + if (n) { memcpy(hdr->hdr.l3.dest_addr, - skb_dst(skb)->neighbour->primary_key, 16); + n->primary_key, 16); } else { /* fill in destination address used in ip header */ memcpy(hdr->hdr.l3.dest_addr, diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c index b2d661147a4..143f2682bda 100644 --- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c @@ -985,7 +985,7 @@ static int init_act_open(struct cxgbi_sock *csk) csk->saddr.sin_addr.s_addr = chba->ipv4addr; csk->rss_qid = 0; - csk->l2t = t3_l2t_get(t3dev, dst->neighbour, ndev); + csk->l2t = t3_l2t_get(t3dev, dst_get_neighbour(dst), ndev); if (!csk->l2t) { pr_err("NO l2t available.\n"); return -EINVAL; diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index f3a4cd7cf78..ae13c4993aa 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -1160,7 +1160,7 @@ static int init_act_open(struct cxgbi_sock *csk) cxgbi_sock_set_flag(csk, CTPF_HAS_ATID); cxgbi_sock_get(csk); - csk->l2t = cxgb4_l2t_get(lldi->l2t, csk->dst->neighbour, ndev, 0); + csk->l2t = cxgb4_l2t_get(lldi->l2t, dst_get_neighbour(csk->dst), ndev, 0); if (!csk->l2t) { pr_err("%s, cannot alloc l2t.\n", ndev->name); goto rel_resource; diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index a2a9c7c6c64..77ac217ad5c 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -492,7 +492,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) goto err_out; } dst = &rt->dst; - ndev = dst->neighbour->dev; + ndev = dst_get_neighbour(dst)->dev; if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { pr_info("multi-cast route %pI4, port %u, dev %s.\n", @@ -506,7 +506,7 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) ndev = ip_dev_find(&init_net, daddr->sin_addr.s_addr); mtu = ndev->mtu; pr_info("rt dev %s, loopback -> %s, mtu %u.\n", - dst->neighbour->dev->name, ndev->name, mtu); + dst_get_neighbour(dst)->dev->name, ndev->name, mtu); } cdev = cxgbi_device_find_by_netdev(ndev, &port); diff --git a/include/net/arp.h b/include/net/arp.h index 91f0568a04e..fb0eb9048b1 100644 --- a/include/net/arp.h +++ b/include/net/arp.h @@ -16,6 +16,7 @@ extern void arp_send(int type, int ptype, __be32 dest_ip, const unsigned char *dest_hw, const unsigned char *src_hw, const unsigned char *th); extern int arp_bind_neighbour(struct dst_entry *dst); +extern struct neighbour *__arp_bind_neighbour(struct dst_entry *dst, __be32 nexthop); extern int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir); extern void arp_ifdown(struct net_device *dev); diff --git a/include/net/dst.h b/include/net/dst.h index e12ddfb9eb1..d0201340bee 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -37,7 +37,7 @@ struct dst_entry { unsigned long _metrics; unsigned long expires; struct dst_entry *path; - struct neighbour *neighbour; + struct neighbour __rcu *_neighbour; struct hh_cache *hh; #ifdef CONFIG_XFRM struct xfrm_state *xfrm; @@ -86,6 +86,21 @@ struct dst_entry { }; }; +static inline struct neighbour *dst_get_neighbour(struct dst_entry *dst) +{ + return rcu_dereference(dst->_neighbour); +} + +static inline struct neighbour *dst_get_neighbour_raw(struct dst_entry *dst) +{ + return rcu_dereference_raw(dst->_neighbour); +} + +static inline void dst_set_neighbour(struct dst_entry *dst, struct neighbour *neigh) +{ + rcu_assign_pointer(dst->_neighbour, neigh); +} + extern u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old); extern const u32 dst_default_metrics[RTAX_MAX]; @@ -371,8 +386,14 @@ static inline void dst_rcu_free(struct rcu_head *head) static inline void dst_confirm(struct dst_entry *dst) { - if (dst) - neigh_confirm(dst->neighbour); + if (dst) { + struct neighbour *n; + + rcu_read_lock(); + n = dst_get_neighbour(dst); + neigh_confirm(n); + rcu_read_unlock(); + } } static inline void dst_link_failure(struct sk_buff *skb) diff --git a/net/atm/clip.c b/net/atm/clip.c index 1d4be60e139..5889074e971 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -364,33 +364,37 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct clip_priv *clip_priv = PRIV(dev); + struct dst_entry *dst = skb_dst(skb); struct atmarp_entry *entry; + struct neighbour *n; struct atm_vcc *vcc; int old; unsigned long flags; pr_debug("(skb %p)\n", skb); - if (!skb_dst(skb)) { + if (!dst) { pr_err("skb_dst(skb) == NULL\n"); dev_kfree_skb(skb); dev->stats.tx_dropped++; return NETDEV_TX_OK; } - if (!skb_dst(skb)->neighbour) { + n = dst_get_neighbour(dst); + if (!n) { #if 0 - skb_dst(skb)->neighbour = clip_find_neighbour(skb_dst(skb), 1); - if (!skb_dst(skb)->neighbour) { + n = clip_find_neighbour(skb_dst(skb), 1); + if (!n) { dev_kfree_skb(skb); /* lost that one */ dev->stats.tx_dropped++; return 0; } + dst_set_neighbour(dst, n); #endif pr_err("NO NEIGHBOUR !\n"); dev_kfree_skb(skb); dev->stats.tx_dropped++; return NETDEV_TX_OK; } - entry = NEIGH2ENTRY(skb_dst(skb)->neighbour); + entry = NEIGH2ENTRY(n); if (!entry->vccs) { if (time_after(jiffies, entry->expires)) { /* should be resolved */ @@ -407,7 +411,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb, } pr_debug("neigh %p, vccs %p\n", entry, entry->vccs); ATM_SKB(skb)->vcc = vcc = entry->vccs->vcc; - pr_debug("using neighbour %p, vcc %p\n", skb_dst(skb)->neighbour, vcc); + pr_debug("using neighbour %p, vcc %p\n", n, vcc); if (entry->vccs->encap) { void *here; diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 56149ec36d7..3dc7f5446a9 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -343,24 +343,26 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) static int br_nf_pre_routing_finish_bridge(struct sk_buff *skb) { struct nf_bridge_info *nf_bridge = skb->nf_bridge; + struct neighbour *neigh; struct dst_entry *dst; skb->dev = bridge_parent(skb->dev); if (!skb->dev) goto free_skb; dst = skb_dst(skb); + neigh = dst_get_neighbour(dst); if (dst->hh) { neigh_hh_bridge(dst->hh, skb); skb->dev = nf_bridge->physindev; return br_handle_frame_finish(skb); - } else if (dst->neighbour) { + } else if (neigh) { /* the neighbour function below overwrites the complete * MAC header, so we save the Ethernet source address and * protocol number. */ skb_copy_from_linear_data_offset(skb, -(ETH_HLEN-ETH_ALEN), skb->nf_bridge->data, ETH_HLEN-ETH_ALEN); /* tell br_dev_xmit to continue with forwarding */ nf_bridge->mask |= BRNF_BRIDGED_DNAT; - return dst->neighbour->output(skb); + return neigh->output(skb); } free_skb: kfree_skb(skb); diff --git a/net/core/dst.c b/net/core/dst.c index 6135f367169..8246d47a218 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -171,7 +171,7 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev, dst_init_metrics(dst, dst_default_metrics, true); dst->expires = 0UL; dst->path = dst; - dst->neighbour = NULL; + RCU_INIT_POINTER(dst->_neighbour, NULL); dst->hh = NULL; #ifdef CONFIG_XFRM dst->xfrm = NULL; @@ -231,7 +231,7 @@ struct dst_entry *dst_destroy(struct dst_entry * dst) smp_rmb(); again: - neigh = dst->neighbour; + neigh = rcu_dereference_protected(dst->_neighbour, 1); hh = dst->hh; child = dst->child; @@ -240,7 +240,7 @@ struct dst_entry *dst_destroy(struct dst_entry * dst) hh_cache_put(hh); if (neigh) { - dst->neighbour = NULL; + RCU_INIT_POINTER(dst->_neighbour, NULL); neigh_release(neigh); } @@ -367,14 +367,19 @@ static void dst_ifdown(struct dst_entry *dst, struct net_device *dev, if (!unregister) { dst->input = dst->output = dst_discard; } else { + struct neighbour *neigh; + dst->dev = dev_net(dst->dev)->loopback_dev; dev_hold(dst->dev); dev_put(dev); - if (dst->neighbour && dst->neighbour->dev == dev) { - dst->neighbour->dev = dst->dev; + rcu_read_lock(); + neigh = dst_get_neighbour(dst); + if (neigh && neigh->dev == dev) { + neigh->dev = dst->dev; dev_hold(dst->dev); dev_put(dev); } + rcu_read_unlock(); } } diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 16db8870780..8c54aff0b0c 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1173,12 +1173,17 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, while (neigh->nud_state & NUD_VALID && (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) { - struct neighbour *n1 = neigh; + struct dst_entry *dst = skb_dst(skb); + struct neighbour *n2, *n1 = neigh; write_unlock_bh(&neigh->lock); + + rcu_read_lock(); /* On shaper/eql skb->dst->neighbour != neigh :( */ - if (skb_dst(skb) && skb_dst(skb)->neighbour) - n1 = skb_dst(skb)->neighbour; + if (dst && (n2 = dst_get_neighbour(dst)) != NULL) + n1 = n2; n1->output(skb); + rcu_read_unlock(); + write_lock_bh(&neigh->lock); } skb_queue_purge(&neigh->arp_queue); @@ -1300,10 +1305,10 @@ EXPORT_SYMBOL(neigh_compat_output); int neigh_resolve_output(struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); - struct neighbour *neigh; + struct neighbour *neigh = dst_get_neighbour(dst); int rc = 0; - if (!dst || !(neigh = dst->neighbour)) + if (!dst) goto discard; __skb_pull(skb, skb_network_offset(skb)); @@ -1333,7 +1338,7 @@ int neigh_resolve_output(struct sk_buff *skb) return rc; discard: NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n", - dst, dst ? dst->neighbour : NULL); + dst, neigh); out_kfree_skb: rc = -EINVAL; kfree_skb(skb); @@ -1347,7 +1352,7 @@ int neigh_connected_output(struct sk_buff *skb) { int err; struct dst_entry *dst = skb_dst(skb); - struct neighbour *neigh = dst->neighbour; + struct neighbour *neigh = dst_get_neighbour(dst); struct net_device *dev = neigh->dev; unsigned int seq; diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index 602dade7e9a..9810610d26c 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -208,7 +208,7 @@ static int dn_neigh_output_packet(struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); struct dn_route *rt = (struct dn_route *)dst; - struct neighbour *neigh = dst->neighbour; + struct neighbour *neigh = dst_get_neighbour(dst); struct net_device *dev = neigh->dev; char mac_addr[ETH_ALEN]; @@ -227,7 +227,7 @@ static int dn_neigh_output_packet(struct sk_buff *skb) static int dn_long_output(struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); - struct neighbour *neigh = dst->neighbour; + struct neighbour *neigh = dst_get_neighbour(dst); struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_long_packet) + 3; unsigned char *data; @@ -274,7 +274,7 @@ static int dn_long_output(struct sk_buff *skb) static int dn_short_output(struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); - struct neighbour *neigh = dst->neighbour; + struct neighbour *neigh = dst_get_neighbour(dst); struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2; struct dn_short_packet *sp; @@ -318,7 +318,7 @@ static int dn_short_output(struct sk_buff *skb) static int dn_phase3_output(struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); - struct neighbour *neigh = dst->neighbour; + struct neighbour *neigh = dst_get_neighbour(dst); struct net_device *dev = neigh->dev; int headroom = dev->hard_header_len + sizeof(struct dn_short_packet) + 2; struct dn_short_packet *sp; diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 74544bc6fde..b91b60363c3 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -241,9 +241,11 @@ static int dn_dst_gc(struct dst_ops *ops) */ static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu) { + struct neighbour *n = dst_get_neighbour(dst); u32 min_mtu = 230; - struct dn_dev *dn = dst->neighbour ? - rcu_dereference_raw(dst->neighbour->dev->dn_ptr) : NULL; + struct dn_dev *dn; + + dn = n ? rcu_dereference_raw(n->dev->dn_ptr) : NULL; if (dn && dn->use_long == 0) min_mtu -= 6; @@ -715,7 +717,7 @@ static int dn_output(struct sk_buff *skb) int err = -EINVAL; - if ((neigh = dst->neighbour) == NULL) + if ((neigh = dst_get_neighbour(dst)) == NULL) goto error; skb->dev = dev; @@ -750,7 +752,7 @@ static int dn_forward(struct sk_buff *skb) struct dst_entry *dst = skb_dst(skb); struct dn_dev *dn_db = rcu_dereference(dst->dev->dn_ptr); struct dn_route *rt; - struct neighbour *neigh = dst->neighbour; + struct neighbour *neigh = dst_get_neighbour(dst); int header_len; #ifdef CONFIG_NETFILTER struct net_device *dev = skb->dev; @@ -833,11 +835,11 @@ static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res) } rt->rt_type = res->type; - if (dev != NULL && rt->dst.neighbour == NULL) { + if (dev != NULL && dst_get_neighbour(&rt->dst) == NULL) { n = __neigh_lookup_errno(&dn_neigh_table, &rt->rt_gateway, dev); if (IS_ERR(n)) return PTR_ERR(n); - rt->dst.neighbour = n; + dst_set_neighbour(&rt->dst, n); } if (dst_metric(&rt->dst, RTAX_MTU) > rt->dst.dev->mtu) @@ -1144,7 +1146,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowidn *o rt->rt_dst_map = fld.daddr; rt->rt_src_map = fld.saddr; - rt->dst.neighbour = neigh; + dst_set_neighbour(&rt->dst, neigh); neigh = NULL; rt->dst.lastuse = jiffies; @@ -1416,7 +1418,7 @@ static int dn_route_input_slow(struct sk_buff *skb) rt->fld.flowidn_iif = in_dev->ifindex; rt->fld.flowidn_mark = fld.flowidn_mark; - rt->dst.neighbour = neigh; + dst_set_neighbour(&rt->dst, neigh); rt->dst.lastuse = jiffies; rt->dst.output = dn_rt_bug; switch(res.type) { diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 1b74d3b6437..1d5675efcfb 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -518,26 +518,32 @@ EXPORT_SYMBOL(arp_find); /* END OF OBSOLETE FUNCTIONS */ +struct neighbour *__arp_bind_neighbour(struct dst_entry *dst, __be32 nexthop) +{ + struct net_device *dev = dst->dev; + + if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) + nexthop = 0; + return __neigh_lookup_errno( +#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) + dev->type == ARPHRD_ATM ? + clip_tbl_hook : +#endif + &arp_tbl, &nexthop, dev); +} + int arp_bind_neighbour(struct dst_entry *dst) { struct net_device *dev = dst->dev; - struct neighbour *n = dst->neighbour; + struct neighbour *n = dst_get_neighbour(dst); if (dev == NULL) return -EINVAL; if (n == NULL) { - __be32 nexthop = ((struct rtable *)dst)->rt_gateway; - if (dev->flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) - nexthop = 0; - n = __neigh_lookup_errno( -#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE) - dev->type == ARPHRD_ATM ? - clip_tbl_hook : -#endif - &arp_tbl, &nexthop, dev); + n = __arp_bind_neighbour(dst, ((struct rtable *)dst)->rt_gateway); if (IS_ERR(n)) return PTR_ERR(n); - dst->neighbour = n; + dst_set_neighbour(dst, n); } return 0; } diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 8871067560d..d7bb94c4834 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -731,9 +731,9 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) else if (skb->protocol == htons(ETH_P_IPV6)) { + struct neighbour *neigh = dst_get_neighbour(skb_dst(skb)); const struct in6_addr *addr6; int addr_type; - struct neighbour *neigh = skb_dst(skb)->neighbour; if (neigh == NULL) goto tx_error; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 0c99db4c80b..51a3eec2c70 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -182,6 +182,8 @@ static inline int ip_finish_output2(struct sk_buff *skb) struct rtable *rt = (struct rtable *)dst; struct net_device *dev = dst->dev; unsigned int hh_len = LL_RESERVED_SPACE(dev); + struct neighbour *neigh; + int res; if (rt->rt_type == RTN_MULTICAST) { IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTMCAST, skb->len); @@ -203,10 +205,22 @@ static inline int ip_finish_output2(struct sk_buff *skb) skb = skb2; } - if (dst->hh) - return neigh_hh_output(dst->hh, skb); - else if (dst->neighbour) - return dst->neighbour->output(skb); + rcu_read_lock(); + if (dst->hh) { + int res = neigh_hh_output(dst->hh, skb); + + rcu_read_unlock(); + return res; + } else { + neigh = dst_get_neighbour(dst); + if (neigh) { + res = neigh->output(skb); + + rcu_read_unlock(); + return res; + } + rcu_read_unlock(); + } if (net_ratelimit()) printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n"); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 4845bfe02d2..65ff2e52a14 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -416,7 +416,13 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v) "HHUptod\tSpecDst"); else { struct rtable *r = v; - int len; + struct neighbour *n; + int len, HHUptod; + + rcu_read_lock(); + n = dst_get_neighbour(&r->dst); + HHUptod = (n && (n->nud_state & NUD_CONNECTED)) ? 1 : 0; + rcu_read_unlock(); seq_printf(seq, "%s\t%08X\t%08X\t%8X\t%d\t%u\t%d\t" "%08X\t%d\t%u\t%u\t%02X\t%d\t%1d\t%08X%n", @@ -431,8 +437,7 @@ static int rt_cache_seq_show(struct seq_file *seq, void *v) dst_metric(&r->dst, RTAX_RTTVAR)), r->rt_key_tos, r->dst.hh ? atomic_read(&r->dst.hh->hh_refcnt) : -1, - r->dst.hh ? (r->dst.hh->hh_output == - dev_queue_xmit) : 0, + HHUptod, r->rt_spec_dst, &len); seq_printf(seq, "%*s\n", 127 - len, ""); @@ -1688,23 +1693,25 @@ static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) { struct rtable *rt = (struct rtable *) dst; __be32 orig_gw = rt->rt_gateway; + struct neighbour *n, *old_n; dst_confirm(&rt->dst); - neigh_release(rt->dst.neighbour); - rt->dst.neighbour = NULL; - rt->rt_gateway = peer->redirect_learned.a4; - if (arp_bind_neighbour(&rt->dst) || - !(rt->dst.neighbour->nud_state & NUD_VALID)) { - if (rt->dst.neighbour) - neigh_event_send(rt->dst.neighbour, NULL); + n = __arp_bind_neighbour(&rt->dst, rt->rt_gateway); + if (IS_ERR(n)) + return PTR_ERR(n); + old_n = xchg(&rt->dst._neighbour, n); + if (old_n) + neigh_release(old_n); + if (!n || !(n->nud_state & NUD_VALID)) { + if (n) + neigh_event_send(n, NULL); rt->rt_gateway = orig_gw; return -EAGAIN; } else { rt->rt_flags |= RTCF_REDIRECTED; - call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, - rt->dst.neighbour); + call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); } return 0; } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 498b927f68b..0f335c67eb8 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -656,7 +656,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, * layer address of our nexhop router */ - if (rt->rt6i_nexthop == NULL) + if (dst_get_neighbour_raw(&rt->dst) == NULL) ifa->flags &= ~IFA_F_OPTIMISTIC; ifa->idev = idev; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 4076a0b14b2..0f9b37a1c1d 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1455,7 +1455,7 @@ static int fib6_age(struct rt6_info *rt, void *arg) RT6_TRACE("aging clone %p\n", rt); return -1; } else if ((rt->rt6i_flags & RTF_GATEWAY) && - (!(rt->rt6i_nexthop->flags & NTF_ROUTER))) { + (!(dst_get_neighbour_raw(&rt->dst)->flags & NTF_ROUTER))) { RT6_TRACE("purging route %p via non-router but gateway\n", rt); return -1; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index e17596b8407..9cbf17686a1 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -100,6 +100,8 @@ static int ip6_finish_output2(struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); struct net_device *dev = dst->dev; + struct neighbour *neigh; + int res; skb->protocol = htons(ETH_P_IPV6); skb->dev = dev; @@ -134,10 +136,22 @@ static int ip6_finish_output2(struct sk_buff *skb) skb->len); } - if (dst->hh) - return neigh_hh_output(dst->hh, skb); - else if (dst->neighbour) - return dst->neighbour->output(skb); + rcu_read_lock(); + if (dst->hh) { + res = neigh_hh_output(dst->hh, skb); + + rcu_read_unlock(); + return res; + } else { + neigh = dst_get_neighbour(dst); + if (neigh) { + res = neigh->output(skb); + + rcu_read_unlock(); + return res; + } + rcu_read_unlock(); + } IP6_INC_STATS_BH(dev_net(dst->dev), ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); @@ -385,6 +399,7 @@ int ip6_forward(struct sk_buff *skb) struct ipv6hdr *hdr = ipv6_hdr(skb); struct inet6_skb_parm *opt = IP6CB(skb); struct net *net = dev_net(dst->dev); + struct neighbour *n; u32 mtu; if (net->ipv6.devconf_all->forwarding == 0) @@ -459,11 +474,10 @@ int ip6_forward(struct sk_buff *skb) send redirects to source routed frames. We don't send redirects to frames decapsulated from IPsec. */ - if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0 && - !skb_sec_path(skb)) { + n = dst_get_neighbour(dst); + if (skb->dev == dst->dev && n && opt->srcrt == 0 && !skb_sec_path(skb)) { struct in6_addr *target = NULL; struct rt6_info *rt; - struct neighbour *n = dst->neighbour; /* * incoming and outgoing devices are the same @@ -949,8 +963,11 @@ static struct dst_entry *ip6_sk_dst_check(struct sock *sk, static int ip6_dst_lookup_tail(struct sock *sk, struct dst_entry **dst, struct flowi6 *fl6) { - int err; struct net *net = sock_net(sk); +#ifdef CONFIG_IPV6_OPTIMISTIC_DAD + struct neighbour *n; +#endif + int err; if (*dst == NULL) *dst = ip6_route_output(net, sk, fl6); @@ -976,11 +993,14 @@ static int ip6_dst_lookup_tail(struct sock *sk, * dst entry and replace it instead with the * dst entry of the nexthop router */ - if ((*dst)->neighbour && !((*dst)->neighbour->nud_state & NUD_VALID)) { + rcu_read_lock(); + n = dst_get_neighbour(*dst); + if (n && !(n->nud_state & NUD_VALID)) { struct inet6_ifaddr *ifp; struct flowi6 fl_gw6; int redirect; + rcu_read_unlock(); ifp = ipv6_get_ifaddr(net, &fl6->saddr, (*dst)->dev, 1); @@ -1000,6 +1020,8 @@ static int ip6_dst_lookup_tail(struct sock *sk, if ((err = (*dst)->error)) goto out_err_release; } + } else { + rcu_read_unlock(); } #endif diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 7596f071d30..10a8d411707 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1244,7 +1244,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev); if (rt) - neigh = rt->rt6i_nexthop; + neigh = dst_get_neighbour(&rt->dst); if (rt && lifetime == 0) { neigh_clone(neigh); @@ -1265,7 +1265,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } - neigh = rt->rt6i_nexthop; + neigh = dst_get_neighbour(&rt->dst); if (neigh == NULL) { ND_PRINTK0(KERN_ERR "ICMPv6 RA: %s() got default router without neighbour.\n", diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0ef1f086feb..e70e902a5d0 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -356,7 +356,7 @@ static inline struct rt6_info *rt6_device_match(struct net *net, #ifdef CONFIG_IPV6_ROUTER_PREF static void rt6_probe(struct rt6_info *rt) { - struct neighbour *neigh = rt ? rt->rt6i_nexthop : NULL; + struct neighbour *neigh; /* * Okay, this does not seem to be appropriate * for now, however, we need to check if it @@ -365,8 +365,10 @@ static void rt6_probe(struct rt6_info *rt) * Router Reachability Probe MUST be rate-limited * to no more than one per minute. */ + rcu_read_lock(); + neigh = rt ? dst_get_neighbour(&rt->dst) : NULL; if (!neigh || (neigh->nud_state & NUD_VALID)) - return; + goto out; read_lock_bh(&neigh->lock); if (!(neigh->nud_state & NUD_VALID) && time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { @@ -379,8 +381,11 @@ static void rt6_probe(struct rt6_info *rt) target = (struct in6_addr *)&neigh->primary_key; addrconf_addr_solict_mult(target, &mcaddr); ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL); - } else + } else { read_unlock_bh(&neigh->lock); + } +out: + rcu_read_unlock(); } #else static inline void rt6_probe(struct rt6_info *rt) @@ -404,8 +409,11 @@ static inline int rt6_check_dev(struct rt6_info *rt, int oif) static inline int rt6_check_neigh(struct rt6_info *rt) { - struct neighbour *neigh = rt->rt6i_nexthop; + struct neighbour *neigh; int m; + + rcu_read_lock(); + neigh = dst_get_neighbour(&rt->dst); if (rt->rt6i_flags & RTF_NONEXTHOP || !(rt->rt6i_flags & RTF_GATEWAY)) m = 1; @@ -422,6 +430,7 @@ static inline int rt6_check_neigh(struct rt6_info *rt) read_unlock_bh(&neigh->lock); } else m = 0; + rcu_read_unlock(); return m; } @@ -745,8 +754,7 @@ static struct rt6_info *rt6_alloc_cow(struct rt6_info *ort, const struct in6_add dst_free(&rt->dst); return NULL; } - rt->rt6i_nexthop = neigh; - + dst_set_neighbour(&rt->dst, neigh); } return rt; @@ -760,7 +768,7 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, const struct in6_a rt->rt6i_dst.plen = 128; rt->rt6i_flags |= RTF_CACHE; rt->dst.flags |= DST_HOST; - rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop); + dst_set_neighbour(&rt->dst, neigh_clone(dst_get_neighbour_raw(&ort->dst))); } return rt; } @@ -794,7 +802,7 @@ static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, dst_hold(&rt->dst); read_unlock_bh(&table->tb6_lock); - if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) + if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) nrt = rt6_alloc_cow(rt, &fl6->daddr, &fl6->saddr); else if (!(rt->dst.flags & DST_HOST)) nrt = rt6_alloc_clone(rt, &fl6->daddr); @@ -1058,7 +1066,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, } rt->rt6i_idev = idev; - rt->rt6i_nexthop = neigh; + dst_set_neighbour(&rt->dst, neigh); atomic_set(&rt->dst.__refcnt, 1); dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255); rt->dst.output = ip6_output; @@ -1338,12 +1346,12 @@ int ip6_route_add(struct fib6_config *cfg) rt->rt6i_prefsrc.plen = 0; if (cfg->fc_flags & (RTF_GATEWAY | RTF_NONEXTHOP)) { - rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); - if (IS_ERR(rt->rt6i_nexthop)) { - err = PTR_ERR(rt->rt6i_nexthop); - rt->rt6i_nexthop = NULL; + struct neighbour *neigh = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev); + if (IS_ERR(neigh)) { + err = PTR_ERR(neigh); goto out; } + dst_set_neighbour(&rt->dst, neigh); } rt->rt6i_flags = cfg->fc_flags; @@ -1574,7 +1582,7 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src, dst_confirm(&rt->dst); /* Duplicate redirect: silently ignore. */ - if (neigh == rt->dst.neighbour) + if (neigh == dst_get_neighbour_raw(&rt->dst)) goto out; nrt = ip6_rt_copy(rt); @@ -1590,7 +1598,7 @@ void rt6_redirect(const struct in6_addr *dest, const struct in6_addr *src, nrt->dst.flags |= DST_HOST; ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); - nrt->rt6i_nexthop = neigh_clone(neigh); + dst_set_neighbour(&nrt->dst, neigh_clone(neigh)); if (ip6_ins_rt(nrt)) goto out; @@ -1670,7 +1678,7 @@ static void rt6_do_pmtu_disc(const struct in6_addr *daddr, const struct in6_addr 1. It is connected route. Action: COW 2. It is gatewayed route or NONEXTHOP route. Action: clone it. */ - if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) + if (!dst_get_neighbour_raw(&rt->dst) && !(rt->rt6i_flags & RTF_NONEXTHOP)) nrt = rt6_alloc_cow(rt, daddr, saddr); else nrt = rt6_alloc_clone(rt, daddr); @@ -2035,7 +2043,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, return ERR_CAST(neigh); } - rt->rt6i_nexthop = neigh; + dst_set_neighbour(&rt->dst, neigh); ipv6_addr_copy(&rt->rt6i_dst.addr, addr); rt->rt6i_dst.plen = 128; @@ -2312,6 +2320,7 @@ static int rt6_fill_node(struct net *net, struct nlmsghdr *nlh; long expires; u32 table; + struct neighbour *n; if (prefix) { /* user wants prefix routes only */ if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { @@ -2400,8 +2409,11 @@ static int rt6_fill_node(struct net *net, if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0) goto nla_put_failure; - if (rt->dst.neighbour) - NLA_PUT(skb, RTA_GATEWAY, 16, &rt->dst.neighbour->primary_key); + rcu_read_lock(); + n = dst_get_neighbour(&rt->dst); + if (n) + NLA_PUT(skb, RTA_GATEWAY, 16, &n->primary_key); + rcu_read_unlock(); if (rt->dst.dev) NLA_PUT_U32(skb, RTA_OIF, rt->rt6i_dev->ifindex); @@ -2585,6 +2597,7 @@ struct rt6_proc_arg static int rt6_info_route(struct rt6_info *rt, void *p_arg) { struct seq_file *m = p_arg; + struct neighbour *n; seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen); @@ -2593,12 +2606,14 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) #else seq_puts(m, "00000000000000000000000000000000 00 "); #endif - - if (rt->rt6i_nexthop) { - seq_printf(m, "%pi6", rt->rt6i_nexthop->primary_key); + rcu_read_lock(); + n = dst_get_neighbour(&rt->dst); + if (n) { + seq_printf(m, "%pi6", n->primary_key); } else { seq_puts(m, "00000000000000000000000000000000"); } + rcu_read_unlock(); seq_printf(m, " %08x %08x %08x %08x %8s\n", rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), rt->dst.__use, rt->rt6i_flags, diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 38490d5c7e1..f56acd09659 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -679,7 +679,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, struct neighbour *neigh = NULL; if (skb_dst(skb)) - neigh = skb_dst(skb)->neighbour; + neigh = dst_get_neighbour(skb_dst(skb)); if (neigh == NULL) { if (net_ratelimit()) @@ -704,7 +704,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, struct neighbour *neigh = NULL; if (skb_dst(skb)) - neigh = skb_dst(skb)->neighbour; + neigh = dst_get_neighbour(skb_dst(skb)); if (neigh == NULL) { if (net_ratelimit()) diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index 45cd30098e3..4f4c52c0eeb 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -225,11 +225,11 @@ static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt) static int -__teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device *dev) +__teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, + struct net_device *dev, struct netdev_queue *txq, + struct neighbour *mn) { - struct netdev_queue *dev_queue = netdev_get_tx_queue(dev, 0); - struct teql_sched_data *q = qdisc_priv(dev_queue->qdisc); - struct neighbour *mn = skb_dst(skb)->neighbour; + struct teql_sched_data *q = qdisc_priv(txq->qdisc); struct neighbour *n = q->ncache; if (mn->tbl == NULL) @@ -262,17 +262,26 @@ __teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res, struct net_device * } static inline int teql_resolve(struct sk_buff *skb, - struct sk_buff *skb_res, struct net_device *dev) + struct sk_buff *skb_res, + struct net_device *dev, + struct netdev_queue *txq) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); + struct dst_entry *dst = skb_dst(skb); + struct neighbour *mn; + int res; + if (txq->qdisc == &noop_qdisc) return -ENODEV; - if (dev->header_ops == NULL || - skb_dst(skb) == NULL || - skb_dst(skb)->neighbour == NULL) + if (!dev->header_ops || !dst) return 0; - return __teql_resolve(skb, skb_res, dev); + + rcu_read_lock(); + mn = dst_get_neighbour(dst); + res = mn ? __teql_resolve(skb, skb_res, dev, txq, mn) : 0; + rcu_read_unlock(); + + return res; } static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) @@ -307,7 +316,7 @@ static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev) continue; } - switch (teql_resolve(skb, skb_res, slave)) { + switch (teql_resolve(skb, skb_res, slave, slave_txq)) { case 0: if (__netif_tx_trylock(slave_txq)) { unsigned int length = qdisc_pkt_len(skb); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 5ce74a38552..7803eb6af41 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1497,7 +1497,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, goto free_dst; /* Copy neighbour for reachability confirmation */ - dst0->neighbour = neigh_clone(dst->neighbour); + dst_set_neighbour(dst0, neigh_clone(dst_get_neighbour(dst))); xfrm_init_path((struct xfrm_dst *)dst0, dst, nfheader_len); xfrm_init_pmtu(dst_prev); From 1d05f993784973189395051cc711fdd6dd5eb389 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 13 Feb 2012 11:15:52 -0800 Subject: [PATCH 0895/4025] Linux 3.0.21 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c060c58ad0d..d5f0598c253 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 20 +SUBLEVEL = 21 EXTRAVERSION = NAME = Sneaky Weasel From 4863c2c407f75bd9aa108160a1999405e1018138 Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Tue, 14 Feb 2012 16:00:25 +0100 Subject: [PATCH 0896/4025] Add teamhacksung script to compile --- arch/arm/configs/crespo_defconfig | 2534 +++++++++++++++++++++++++++++ build.sh | 74 + 2 files changed, 2608 insertions(+) create mode 100644 arch/arm/configs/crespo_defconfig create mode 100755 build.sh diff --git a/arch/arm/configs/crespo_defconfig b/arch/arm/configs/crespo_defconfig new file mode 100644 index 00000000000..b3da60cfbc0 --- /dev/null +++ b/arch/arm/configs/crespo_defconfig @@ -0,0 +1,2534 @@ +# +# Automatically generated make config: don't edit +# Linux/arm 3.0.20 Kernel Configuration +# +CONFIG_ARM=y +CONFIG_HAVE_PWM=y +CONFIG_SYS_SUPPORTS_APM_EMULATION=y +CONFIG_GENERIC_GPIO=y +# CONFIG_ARCH_USES_GETTIMEOFFSET is not set +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_KTIME_SCALAR=y +CONFIG_HAVE_PROC_CPU=y +CONFIG_NO_IOPORT=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_HAVE_LATENCYTOP_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +CONFIG_HARDIRQS_SW_RESEND=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_ARCH_HAS_CPUFREQ=y +CONFIG_ARCH_HAS_CPU_IDLE_WAIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_NEED_DMA_MAP_STATE=y +CONFIG_FIQ=y +CONFIG_VECTORS_BASE=0xffff0000 +# CONFIG_ARM_PATCH_PHYS_VIRT is not set +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" +CONFIG_HAVE_IRQ_WORK=y + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_CROSS_COMPILE="" +CONFIG_LOCALVERSION="-Cyanogenmod" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_HAVE_KERNEL_GZIP=y +CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_LZO=y +# CONFIG_KERNEL_GZIP is not set +CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_LZO is not set +CONFIG_DEFAULT_HOSTNAME="(none)" +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_FHANDLE is not set +# CONFIG_TASKSTATS is not set +# CONFIG_AUDIT is not set +CONFIG_HAVE_GENERIC_HARDIRQS=y + +# +# IRQ subsystem +# +CONFIG_GENERIC_HARDIRQS=y +CONFIG_HAVE_SPARSE_IRQ=y +CONFIG_GENERIC_IRQ_SHOW=y +CONFIG_GENERIC_IRQ_CHIP=y +# CONFIG_SPARSE_IRQ is not set + +# +# RCU Subsystem +# +# CONFIG_TREE_PREEMPT_RCU is not set +# CONFIG_TINY_RCU is not set +CONFIG_TINY_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y +# CONFIG_RCU_TRACE is not set +# CONFIG_TREE_RCU_TRACE is not set +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=1 +CONFIG_RCU_BOOST_DELAY=500 +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=17 +CONFIG_CGROUPS=y +# CONFIG_CGROUP_DEBUG is not set +CONFIG_CGROUP_FREEZER=y +# CONFIG_CGROUP_DEVICE is not set +# CONFIG_CPUSETS is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_RESOURCE_COUNTERS=y +# CONFIG_CGROUP_MEM_RES_CTLR is not set +CONFIG_CGROUP_SCHED=y +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +# CONFIG_BLK_CGROUP is not set +# CONFIG_NAMESPACES is not set +# CONFIG_SCHED_AUTOGROUP is not set +# CONFIG_SYSFS_DEPRECATED is not set +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +CONFIG_RD_GZIP=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_ANON_INODES=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_EXPERT=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +# CONFIG_BUG is not set +# CONFIG_ELF_CORE is not set +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_ASHMEM=y +# CONFIG_AIO is not set +CONFIG_EMBEDDED=y +CONFIG_HAVE_PERF_EVENTS=y +CONFIG_PERF_USE_VMALLOC=y + +# +# Kernel Performance Events And Counters +# +# CONFIG_PERF_EVENTS is not set +# CONFIG_PERF_COUNTERS is not set +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLUB_DEBUG=y +CONFIG_COMPAT_BRK=y +# CONFIG_SLAB is not set +CONFIG_SLUB=y +# CONFIG_SLOB is not set +# CONFIG_PROFILING is not set +CONFIG_HAVE_OPROFILE=y +# CONFIG_KPROBES is not set +CONFIG_HAVE_KPROBES=y +CONFIG_HAVE_KRETPROBES=y +CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y +CONFIG_HAVE_CLK=y +CONFIG_HAVE_DMA_API_DEBUG=y + +# +# GCOV-based kernel profiling +# +CONFIG_HAVE_GENERIC_DMA_COHERENT=y +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +CONFIG_BLOCK=y +CONFIG_LBDAF=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_BLK_DEV_INTEGRITY is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_DEADLINE=y +# CONFIG_IOSCHED_CFQ is not set +CONFIG_DEFAULT_DEADLINE=y +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="deadline" +# CONFIG_INLINE_SPIN_TRYLOCK is not set +# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK is not set +# CONFIG_INLINE_SPIN_LOCK_BH is not set +# CONFIG_INLINE_SPIN_LOCK_IRQ is not set +# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set +# CONFIG_INLINE_SPIN_UNLOCK is not set +# CONFIG_INLINE_SPIN_UNLOCK_BH is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set +# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_READ_TRYLOCK is not set +# CONFIG_INLINE_READ_LOCK is not set +# CONFIG_INLINE_READ_LOCK_BH is not set +# CONFIG_INLINE_READ_LOCK_IRQ is not set +# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set +# CONFIG_INLINE_READ_UNLOCK is not set +# CONFIG_INLINE_READ_UNLOCK_BH is not set +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set +# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set +# CONFIG_INLINE_WRITE_TRYLOCK is not set +# CONFIG_INLINE_WRITE_LOCK is not set +# CONFIG_INLINE_WRITE_LOCK_BH is not set +# CONFIG_INLINE_WRITE_LOCK_IRQ is not set +# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set +# CONFIG_INLINE_WRITE_UNLOCK is not set +# CONFIG_INLINE_WRITE_UNLOCK_BH is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set +# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set +# CONFIG_MUTEX_SPIN_ON_OWNER is not set +CONFIG_FREEZER=y + +# +# System Type +# +CONFIG_MMU=y +# CONFIG_ARCH_INTEGRATOR is not set +# CONFIG_ARCH_REALVIEW is not set +# CONFIG_ARCH_VERSATILE is not set +# CONFIG_ARCH_VEXPRESS is not set +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_BCMRING is not set +# CONFIG_ARCH_CLPS711X is not set +# CONFIG_ARCH_CNS3XXX is not set +# CONFIG_ARCH_GEMINI is not set +# CONFIG_ARCH_EBSA110 is not set +# CONFIG_ARCH_EP93XX is not set +# CONFIG_ARCH_FOOTBRIDGE is not set +# CONFIG_ARCH_MXC is not set +# CONFIG_ARCH_MXS is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_H720X is not set +# CONFIG_ARCH_IOP13XX is not set +# CONFIG_ARCH_IOP32X is not set +# CONFIG_ARCH_IOP33X is not set +# CONFIG_ARCH_IXP23XX is not set +# CONFIG_ARCH_IXP2000 is not set +# CONFIG_ARCH_IXP4XX is not set +# CONFIG_ARCH_DOVE is not set +# CONFIG_ARCH_KIRKWOOD is not set +# CONFIG_ARCH_LOKI is not set +# CONFIG_ARCH_LPC32XX is not set +# CONFIG_ARCH_MV78XX0 is not set +# CONFIG_ARCH_ORION5X is not set +# CONFIG_ARCH_MMP is not set +# CONFIG_ARCH_KS8695 is not set +# CONFIG_ARCH_W90X900 is not set +# CONFIG_ARCH_NUC93X is not set +# CONFIG_ARCH_TEGRA is not set +# CONFIG_ARCH_PNX4008 is not set +# CONFIG_ARCH_PXA is not set +# CONFIG_ARCH_MSM is not set +# CONFIG_ARCH_SHMOBILE is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_S3C2410 is not set +# CONFIG_ARCH_S3C64XX is not set +# CONFIG_ARCH_S5P64X0 is not set +# CONFIG_ARCH_S5PC100 is not set +CONFIG_ARCH_S5PV210=y +# CONFIG_ARCH_EXYNOS4 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_TCC_926 is not set +# CONFIG_ARCH_U300 is not set +# CONFIG_ARCH_U8500 is not set +# CONFIG_ARCH_NOMADIK is not set +# CONFIG_ARCH_DAVINCI is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_PLAT_SPEAR is not set +# CONFIG_ARCH_VT8500 is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_KEYBOARD_GPIO_POLLED is not set +CONFIG_PLAT_SAMSUNG=y + +# +# Boot options +# +# CONFIG_S3C_BOOT_ERROR_RESET is not set +CONFIG_S3C_BOOT_UART_FORCE_FIFO=y +CONFIG_S3C_LOWLEVEL_UART_PORT=2 +CONFIG_SAMSUNG_CLKSRC=y +CONFIG_SAMSUNG_IRQ_VIC_TIMER=y +CONFIG_SAMSUNG_IRQ_UART=y +CONFIG_SAMSUNG_GPIOLIB_4BIT=y +CONFIG_S3C_GPIO_CFG_S3C24XX=y +CONFIG_S3C_GPIO_CFG_S3C64XX=y +CONFIG_S3C_GPIO_PULL_UPDOWN=y +CONFIG_S5P_GPIO_DRVSTR=y +CONFIG_SAMSUNG_GPIO_EXTRA=0 +CONFIG_S3C_GPIO_SPACE=0 +CONFIG_S3C_GPIO_TRACK=y +# CONFIG_S3C_ADC is not set +CONFIG_S3C_DEV_HSMMC=y +CONFIG_S3C_DEV_HSMMC2=y +CONFIG_S3C_DEV_HSMMC3=y +CONFIG_S3C_DEV_I2C1=y +CONFIG_S3C_DEV_I2C2=y +CONFIG_S3C_DEV_WDT=y +CONFIG_SAMSUNG_DEV_PWM=y +# CONFIG_S3C24XX_PWM is not set +CONFIG_S3C_PL330_DMA=y + +# +# Power management +# +# CONFIG_SAMSUNG_PM_DEBUG is not set +# CONFIG_SAMSUNG_PM_CHECK is not set + +# +# Power Domain +# +CONFIG_PLAT_S5P=y +CONFIG_S5P_EXT_INT=y +CONFIG_S5P_HRT=y + +# +# System MMU +# +CONFIG_S5P_DEV_ONENAND=y +CONFIG_S5P_DEV_CSIS0=y +CONFIG_S5P_SETUP_MIPIPHY=y +CONFIG_S5P_DEV_FB=y +CONFIG_S5P_HIGH_RES_TIMERS=y +CONFIG_HRT_RTC=y +CONFIG_S5P_DEV_MFC=y +CONFIG_S5P_SETUP_MFC=y +CONFIG_CPU_S5PV210=y +CONFIG_CPU_DIDLE=y +CONFIG_S5PV210_SETUP_I2C1=y +CONFIG_S5PV210_SETUP_I2C2=y +CONFIG_S5PV210_SETUP_SDHCI=y +CONFIG_S5PV210_SETUP_SDHCI_GPIO=y +CONFIG_S5PV210_POWER_DOMAIN=y +# CONFIG_S5PV210_CORESIGHT is not set + +# +# MMC/SD slot setup +# + +# +# Use 8-bit bus width +# +CONFIG_S5PV210_SD_CH0_8BIT=y +# CONFIG_S5PV210_SD_CH2_8BIT is not set + +# +# S5PC110 Machines +# +# CONFIG_MACH_AQUILA is not set +# CONFIG_MACH_GONI is not set +# CONFIG_MACH_SMDKC110 is not set + +# +# S5PV210 Machines +# +# CONFIG_MACH_SMDKV210 is not set +# CONFIG_MACH_TORBRECK is not set +CONFIG_S5PV210_PM=y +CONFIG_MACH_HERRING=y +CONFIG_S5PV210_SETUP_FB=y +CONFIG_S5P_ADC=y +CONFIG_S5PV210_SETUP_FIMC0=y +CONFIG_S5PV210_SETUP_FIMC1=y +CONFIG_S5PV210_SETUP_FIMC2=y +CONFIG_WIFI_CONTROL_FUNC=y + +# +# Processor Type +# +CONFIG_CPU_V7=y +CONFIG_CPU_32v6K=y +CONFIG_CPU_32v7=y +CONFIG_CPU_ABRT_EV7=y +CONFIG_CPU_PABRT_V7=y +CONFIG_CPU_CACHE_V7=y +CONFIG_CPU_CACHE_VIPT=y +CONFIG_CPU_COPY_V6=y +CONFIG_CPU_TLB_V7=y +CONFIG_CPU_HAS_ASID=y +CONFIG_CPU_CP15=y +CONFIG_CPU_CP15_MMU=y + +# +# Processor Features +# +CONFIG_ARM_THUMB=y +CONFIG_ARM_THUMBEE=y +# CONFIG_SWP_EMULATE is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +# CONFIG_CPU_BPREDICT_DISABLE is not set +CONFIG_ARM_L1_CACHE_SHIFT_6=y +CONFIG_ARM_L1_CACHE_SHIFT=6 +CONFIG_ARM_DMA_MEM_BUFFERABLE=y +CONFIG_CPU_HAS_PMU=y +# CONFIG_ARM_ERRATA_430973 is not set +# CONFIG_ARM_ERRATA_458693 is not set +# CONFIG_ARM_ERRATA_460075 is not set +# CONFIG_ARM_ERRATA_743622 is not set +# CONFIG_ARM_ERRATA_754322 is not set +CONFIG_ARM_VIC=y +CONFIG_ARM_VIC_NR=4 +CONFIG_PL330=y +CONFIG_FIQ_GLUE=y +CONFIG_FIQ_DEBUGGER=y +# CONFIG_FIQ_DEBUGGER_NO_SLEEP is not set +# CONFIG_FIQ_DEBUGGER_WAKEUP_IRQ_ALWAYS_ON is not set +CONFIG_FIQ_DEBUGGER_CONSOLE=y +# CONFIG_FIQ_DEBUGGER_CONSOLE_DEFAULT_ENABLE is not set + +# +# Bus support +# +# CONFIG_PCI_SYSCALL is not set +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Kernel Features +# +CONFIG_TICK_ONESHOT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y +CONFIG_VMSPLIT_3G=y +# CONFIG_VMSPLIT_2G is not set +# CONFIG_VMSPLIT_1G is not set +CONFIG_PAGE_OFFSET=0xC0000000 +# CONFIG_PREEMPT_NONE is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y +CONFIG_HZ=256 +# CONFIG_THUMB2_KERNEL is not set +CONFIG_AEABI=y +CONFIG_OABI_COMPAT=y +CONFIG_ARCH_HAS_HOLES_MEMORYMODEL=y +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_HAVE_ARCH_PFN_VALID=y +# CONFIG_HIGHMEM is not set +CONFIG_SELECT_MEMORY_MODEL=y +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_SPARSEMEM_EXTREME=y +CONFIG_HAVE_MEMBLOCK=y +CONFIG_SPLIT_PTLOCK_CPUS=4 +CONFIG_COMPACTION=y +CONFIG_MIGRATION=y +# CONFIG_PHYS_ADDR_T_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_VIRT_TO_BUS=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=4096 +CONFIG_NEED_PER_CPU_KM=y +# CONFIG_CLEANCACHE is not set +CONFIG_FORCE_MAX_ZONEORDER=11 +CONFIG_ALIGNMENT_TRAP=y +# CONFIG_UACCESS_WITH_MEMCPY is not set +# CONFIG_SECCOMP is not set +# CONFIG_CC_STACKPROTECTOR is not set +# CONFIG_DEPRECATED_PARAM_STRUCT is not set +# CONFIG_ARM_FLUSH_CONSOLE_ON_RESTART is not set + +# +# Boot options +# +# CONFIG_USE_OF is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_CMDLINE="console=ttyFIQ0" +CONFIG_CMDLINE_FROM_BOOTLOADER=y +# CONFIG_CMDLINE_EXTEND is not set +# CONFIG_CMDLINE_FORCE is not set +# CONFIG_XIP_KERNEL is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +# CONFIG_AUTO_ZRELADDR is not set + +# +# CPU Power Management +# + +# +# CPU Frequency scaling +# +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_TABLE=y +CONFIG_CPU_FREQ_STAT=y +# CONFIG_CPU_FREQ_STAT_DETAILS is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set +# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set +CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_PERFORMANCE=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_CPU_FREQ_GOV_INTERACTIVE=y +CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y +CONFIG_CPU_IDLE=y +CONFIG_CPU_IDLE_GOV_LADDER=y +CONFIG_CPU_IDLE_GOV_MENU=y + +# +# Floating point emulation +# + +# +# At least one emulation must be selected +# +# CONFIG_FPE_NWFPE is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_VFP=y +CONFIG_VFPv3=y +CONFIG_NEON=y + +# +# Userspace binary formats +# +CONFIG_BINFMT_ELF=y +CONFIG_HAVE_AOUT=y +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_MISC=y + +# +# Power management options +# +CONFIG_SUSPEND=y +CONFIG_SUSPEND_FREEZER=y +CONFIG_HAS_WAKELOCK=y +CONFIG_HAS_EARLYSUSPEND=y +CONFIG_WAKELOCK=y +CONFIG_WAKELOCK_STAT=y +CONFIG_USER_WAKELOCK=y +CONFIG_EARLYSUSPEND=y +# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set +CONFIG_FB_EARLYSUSPEND=y +CONFIG_PM_SLEEP=y +# CONFIG_PM_RUNTIME is not set +CONFIG_PM=y +# CONFIG_PM_DEBUG is not set +CONFIG_APM_EMULATION=y +# CONFIG_SUSPEND_TIME is not set +CONFIG_ARCH_SUSPEND_POSSIBLE=y +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +CONFIG_XFRM_IPCOMP=y +CONFIG_NET_KEY=y +# CONFIG_NET_KEY_MIGRATE is not set +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_FIB_TRIE_STATS is not set +CONFIG_IP_MULTIPLE_TABLES=y +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE_DEMUX is not set +# CONFIG_IP_MROUTE is not set +# CONFIG_ARPD is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_INET_AH is not set +CONFIG_INET_ESP=y +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +CONFIG_INET_TUNNEL=y +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_CUBIC is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_HTCP is not set +# CONFIG_TCP_CONG_HSTCP is not set +# CONFIG_TCP_CONG_HYBLA is not set +# CONFIG_TCP_CONG_VEGAS is not set +# CONFIG_TCP_CONG_SCALABLE is not set +# CONFIG_TCP_CONG_LP is not set +CONFIG_TCP_CONG_VENO=y +# CONFIG_TCP_CONG_YEAH is not set +# CONFIG_TCP_CONG_ILLINOIS is not set +CONFIG_DEFAULT_VENO=y +# CONFIG_DEFAULT_RENO is not set +CONFIG_DEFAULT_TCP_CONG="veno" +# CONFIG_TCP_MD5SIG is not set +CONFIG_IPV6=y +CONFIG_IPV6_PRIVACY=y +CONFIG_IPV6_ROUTER_PREF=y +# CONFIG_IPV6_ROUTE_INFO is not set +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_INET6_XFRM_TUNNEL=y +CONFIG_INET6_TUNNEL=y +CONFIG_INET6_XFRM_MODE_TRANSPORT=y +CONFIG_INET6_XFRM_MODE_TUNNEL=y +CONFIG_INET6_XFRM_MODE_BEET=y +# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set +CONFIG_IPV6_SIT=y +# CONFIG_IPV6_SIT_6RD is not set +CONFIG_IPV6_NDISC_NODETYPE=y +CONFIG_IPV6_TUNNEL=y +CONFIG_IPV6_MULTIPLE_TABLES=y +# CONFIG_IPV6_SUBTREES is not set +# CONFIG_IPV6_MROUTE is not set +CONFIG_ANDROID_PARANOID_NETWORK=y +CONFIG_NET_ACTIVITY_STATS=y +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETWORK_PHY_TIMESTAMPING is not set +CONFIG_NETFILTER=y +# CONFIG_NETFILTER_DEBUG is not set +CONFIG_NETFILTER_ADVANCED=y + +# +# Core Netfilter Configuration +# +CONFIG_NETFILTER_NETLINK=y +CONFIG_NETFILTER_NETLINK_QUEUE=y +CONFIG_NETFILTER_NETLINK_LOG=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_MARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CONNTRACK_TIMESTAMP is not set +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_GRE=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_BROADCAST=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +# CONFIG_NF_CONNTRACK_SNMP is not set +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +# CONFIG_NF_CONNTRACK_SIP is not set +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_TPROXY=y +CONFIG_NETFILTER_XTABLES=y + +# +# Xtables combined modules +# +CONFIG_NETFILTER_XT_MARK=y +CONFIG_NETFILTER_XT_CONNMARK=y + +# +# Xtables targets +# +# CONFIG_NETFILTER_XT_TARGET_CHECKSUM is not set +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +# CONFIG_NETFILTER_XT_TARGET_CT is not set +# CONFIG_NETFILTER_XT_TARGET_DSCP is not set +# CONFIG_NETFILTER_XT_TARGET_HL is not set +# CONFIG_NETFILTER_XT_TARGET_IDLETIMER is not set +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set +# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set +# CONFIG_NETFILTER_XT_TARGET_TEE is not set +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set +# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set + +# +# Xtables matches +# +# CONFIG_NETFILTER_XT_MATCH_ADDRTYPE is not set +# CONFIG_NETFILTER_XT_MATCH_CLUSTER is not set +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +# CONFIG_NETFILTER_XT_MATCH_CPU is not set +# CONFIG_NETFILTER_XT_MATCH_DCCP is not set +# CONFIG_NETFILTER_XT_MATCH_DEVGROUP is not set +# CONFIG_NETFILTER_XT_MATCH_DSCP is not set +# CONFIG_NETFILTER_XT_MATCH_ESP is not set +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_HL=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set +# CONFIG_NETFILTER_XT_MATCH_OSF is not set +# CONFIG_NETFILTER_XT_MATCH_OWNER is not set +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set +# CONFIG_NETFILTER_XT_MATCH_REALM is not set +# CONFIG_NETFILTER_XT_MATCH_RECENT is not set +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +# CONFIG_IP_SET is not set +# CONFIG_IP_VS is not set + +# +# IP: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV4=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_CONNTRACK_PROC_COMPAT=y +# CONFIG_IP_NF_QUEUE is not set +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_TARGET_REJECT_SKERR=y +CONFIG_IP_NF_TARGET_LOG=y +# CONFIG_IP_NF_TARGET_ULOG is not set +CONFIG_NF_NAT=y +CONFIG_NF_NAT_NEEDED=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_NF_NAT_PROTO_DCCP=y +CONFIG_NF_NAT_PROTO_GRE=y +CONFIG_NF_NAT_PROTO_UDPLITE=y +CONFIG_NF_NAT_PROTO_SCTP=y +CONFIG_NF_NAT_FTP=y +CONFIG_NF_NAT_IRC=y +CONFIG_NF_NAT_TFTP=y +CONFIG_NF_NAT_AMANDA=y +CONFIG_NF_NAT_PPTP=y +CONFIG_NF_NAT_H323=y +# CONFIG_NF_NAT_SIP is not set +CONFIG_IP_NF_MANGLE=y +# CONFIG_IP_NF_TARGET_CLUSTERIP is not set +# CONFIG_IP_NF_TARGET_ECN is not set +# CONFIG_IP_NF_TARGET_TTL is not set +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y + +# +# IPv6: Netfilter Configuration +# +CONFIG_NF_DEFRAG_IPV6=y +CONFIG_NF_CONNTRACK_IPV6=y +# CONFIG_IP6_NF_QUEUE is not set +CONFIG_IP6_NF_IPTABLES=y +# CONFIG_IP6_NF_MATCH_AH is not set +# CONFIG_IP6_NF_MATCH_EUI64 is not set +# CONFIG_IP6_NF_MATCH_FRAG is not set +# CONFIG_IP6_NF_MATCH_OPTS is not set +# CONFIG_IP6_NF_MATCH_HL is not set +# CONFIG_IP6_NF_MATCH_IPV6HEADER is not set +# CONFIG_IP6_NF_MATCH_MH is not set +# CONFIG_IP6_NF_MATCH_RT is not set +# CONFIG_IP6_NF_TARGET_HL is not set +CONFIG_IP6_NF_TARGET_LOG=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_TARGET_REJECT_SKERR=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_RDS is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_L2TP is not set +# CONFIG_BRIDGE is not set +# CONFIG_NET_DSA is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +CONFIG_PHONET=y +# CONFIG_IEEE802154 is not set +CONFIG_NET_SCHED=y + +# +# Queueing/Scheduling +# +# CONFIG_NET_SCH_CBQ is not set +# CONFIG_NET_SCH_HTB is not set +# CONFIG_NET_SCH_HFSC is not set +# CONFIG_NET_SCH_PRIO is not set +# CONFIG_NET_SCH_MULTIQ is not set +# CONFIG_NET_SCH_RED is not set +CONFIG_NET_SCH_SFB=y +# CONFIG_NET_SCH_SFQ is not set +# CONFIG_NET_SCH_TEQL is not set +# CONFIG_NET_SCH_TBF is not set +# CONFIG_NET_SCH_GRED is not set +# CONFIG_NET_SCH_DSMARK is not set +# CONFIG_NET_SCH_NETEM is not set +# CONFIG_NET_SCH_DRR is not set +# CONFIG_NET_SCH_MQPRIO is not set +# CONFIG_NET_SCH_CHOKE is not set +# CONFIG_NET_SCH_QFQ is not set +# CONFIG_NET_SCH_INGRESS is not set + +# +# Classification +# +CONFIG_NET_CLS=y +# CONFIG_NET_CLS_BASIC is not set +# CONFIG_NET_CLS_TCINDEX is not set +# CONFIG_NET_CLS_ROUTE4 is not set +# CONFIG_NET_CLS_FW is not set +CONFIG_NET_CLS_U32=y +# CONFIG_CLS_U32_PERF is not set +# CONFIG_CLS_U32_MARK is not set +# CONFIG_NET_CLS_RSVP is not set +# CONFIG_NET_CLS_RSVP6 is not set +# CONFIG_NET_CLS_FLOW is not set +# CONFIG_NET_CLS_CGROUP is not set +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_STACK=32 +# CONFIG_NET_EMATCH_CMP is not set +# CONFIG_NET_EMATCH_NBYTE is not set +CONFIG_NET_EMATCH_U32=y +# CONFIG_NET_EMATCH_META is not set +# CONFIG_NET_EMATCH_TEXT is not set +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +# CONFIG_GACT_PROB is not set +CONFIG_NET_ACT_MIRRED=y +# CONFIG_NET_ACT_IPT is not set +# CONFIG_NET_ACT_NAT is not set +# CONFIG_NET_ACT_PEDIT is not set +# CONFIG_NET_ACT_SIMP is not set +# CONFIG_NET_ACT_SKBEDIT is not set +# CONFIG_NET_ACT_CSUM is not set +# CONFIG_NET_CLS_IND is not set +CONFIG_NET_SCH_FIFO=y +# CONFIG_DCB is not set +# CONFIG_BATMAN_ADV is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +CONFIG_BT=y +CONFIG_BT_L2CAP=y +CONFIG_BT_SCO=y +CONFIG_BT_RFCOMM=y +CONFIG_BT_RFCOMM_TTY=y +CONFIG_BT_BNEP=y +# CONFIG_BT_BNEP_MC_FILTER is not set +# CONFIG_BT_BNEP_PROTO_FILTER is not set +CONFIG_BT_HIDP=y + +# +# Bluetooth device drivers +# +# CONFIG_BT_HCIBTUSB is not set +# CONFIG_BT_HCIBTSDIO is not set +CONFIG_BT_HCIUART=y +CONFIG_BT_HCIUART_H4=y +# CONFIG_BT_HCIUART_BCSP is not set +# CONFIG_BT_HCIUART_ATH3K is not set +# CONFIG_BT_HCIUART_LL is not set +# CONFIG_BT_HCIBCM203X is not set +# CONFIG_BT_HCIBPA10X is not set +# CONFIG_BT_HCIBFUSB is not set +# CONFIG_BT_HCIVHCI is not set +# CONFIG_BT_MRVL is not set +# CONFIG_AF_RXRPC is not set +CONFIG_FIB_RULES=y +CONFIG_WIRELESS=y +CONFIG_WIRELESS_EXT=y +CONFIG_WEXT_CORE=y +CONFIG_WEXT_PROC=y +CONFIG_WEXT_PRIV=y +# CONFIG_CFG80211 is not set +CONFIG_WIRELESS_EXT_SYSFS=y +# CONFIG_LIB80211 is not set + +# +# CFG80211 needs to be enabled for MAC80211 +# +CONFIG_WIMAX=y +CONFIG_WIMAX_DEBUG_LEVEL=8 +CONFIG_RFKILL=y +CONFIG_RFKILL_PM=y +CONFIG_RFKILL_INPUT=y +# CONFIG_RFKILL_REGULATOR is not set +# CONFIG_RFKILL_GPIO is not set +# CONFIG_NET_9P is not set +# CONFIG_CAIF is not set +# CONFIG_CEPH_LIB is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="" +# CONFIG_DEVTMPFS is not set +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=y +CONFIG_FIRMWARE_IN_KERNEL=y +CONFIG_EXTRA_FIRMWARE="" +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +# CONFIG_MTD_TESTS is not set +# CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set +# CONFIG_MTD_AFS_PARTS is not set +# CONFIG_MTD_AR7_PARTS is not set + +# +# User Modules And Translation Layers +# +CONFIG_MTD_CHAR=y +CONFIG_MTD_BLKDEVS=y +CONFIG_MTD_BLOCK=y +# CONFIG_FTL is not set +# CONFIG_NFTL is not set +# CONFIG_INFTL is not set +# CONFIG_RFD_FTL is not set +# CONFIG_SSFDC is not set +# CONFIG_SM_FTL is not set +# CONFIG_MTD_OOPS is not set + +# +# RAM/ROM/Flash chip drivers +# +# CONFIG_MTD_CFI is not set +# CONFIG_MTD_JEDECPROBE is not set +CONFIG_MTD_MAP_BANK_WIDTH_1=y +CONFIG_MTD_MAP_BANK_WIDTH_2=y +CONFIG_MTD_MAP_BANK_WIDTH_4=y +# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set +# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set +CONFIG_MTD_CFI_I1=y +CONFIG_MTD_CFI_I2=y +# CONFIG_MTD_CFI_I4 is not set +# CONFIG_MTD_CFI_I8 is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_COMPLEX_MAPPINGS is not set +# CONFIG_MTD_PLATRAM is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_DATAFLASH is not set +# CONFIG_MTD_M25P80 is not set +# CONFIG_MTD_SST25L is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_PHRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLOCK2MTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOC2001PLUS is not set +# CONFIG_MTD_NAND_IDS is not set +# CONFIG_MTD_NAND is not set +CONFIG_MTD_ONENAND=y +# CONFIG_MTD_ONENAND_VERIFY_WRITE is not set +# CONFIG_MTD_ONENAND_GENERIC is not set +CONFIG_MTD_ONENAND_SAMSUNG=y +# CONFIG_MTD_ONENAND_OTP is not set +# CONFIG_MTD_ONENAND_2X_PROGRAM is not set +# CONFIG_MTD_ONENAND_SIM is not set + +# +# LPDDR flash memory drivers +# +# CONFIG_MTD_LPDDR is not set +# CONFIG_MTD_UBI is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +CONFIG_BLK_DEV_LOOP=y +# CONFIG_BLK_DEV_CRYPTOLOOP is not set + +# +# DRBD disabled because PROC_FS, INET or CONNECTOR not selected +# +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_UB is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=8192 +# CONFIG_BLK_DEV_XIP is not set +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +# CONFIG_MG_DISK is not set +# CONFIG_BLK_DEV_RBD is not set +# CONFIG_SENSORS_LIS3LV02D is not set +CONFIG_MISC_DEVICES=y +# CONFIG_AD525X_DPOT is not set +# CONFIG_ANDROID_PMEM is not set +# CONFIG_INTEL_MID_PTI is not set +# CONFIG_ICS932S401 is not set +# CONFIG_ENCLOSURE_SERVICES is not set +# CONFIG_APDS9802ALS is not set +# CONFIG_ISL29003 is not set +# CONFIG_ISL29020 is not set +# CONFIG_SENSORS_TSL2550 is not set +# CONFIG_SENSORS_BH1780 is not set +# CONFIG_SENSORS_BH1770 is not set +# CONFIG_SENSORS_APDS990X is not set +# CONFIG_HMC6352 is not set +CONFIG_SENSORS_AK8973=y +# CONFIG_SENSORS_AK8975 is not set +CONFIG_SENSORS_KR3DM=y +# CONFIG_DS1682 is not set +# CONFIG_TI_DAC7512 is not set +CONFIG_UID_STAT=y +# CONFIG_BMP085 is not set +# CONFIG_WL127X_RFKILL is not set +# CONFIG_APANIC is not set +CONFIG_SAMSUNG_JACK=y +CONFIG_USB_SWITCH_FSA9480=y +# CONFIG_C2PORT is not set + +# +# EEPROM support +# +# CONFIG_EEPROM_AT24 is not set +# CONFIG_EEPROM_AT25 is not set +# CONFIG_EEPROM_LEGACY is not set +# CONFIG_EEPROM_MAX6875 is not set +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IWMC3200TOP is not set + +# +# Texas Instruments shared transport line discipline +# +# CONFIG_TI_ST is not set +# CONFIG_SENSORS_LIS3_SPI is not set +# CONFIG_SENSORS_LIS3_I2C is not set +CONFIG_SAMSUNG_MODEMCTL=y +CONFIG_PN544=y +CONFIG_GENERIC_BLN=y +CONFIG_HAVE_IDE=y +# CONFIG_IDE is not set + +# +# SCSI device support +# +CONFIG_SCSI_MOD=y +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +CONFIG_CHR_DEV_SG=y +# CONFIG_CHR_DEV_SCH is not set +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_ISCSI_BOOT_SYSFS is not set +# CONFIG_LIBFC is not set +# CONFIG_LIBFCOE is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_SCSI_DH is not set +# CONFIG_SCSI_OSD_INITIATOR is not set +# CONFIG_ATA is not set +CONFIG_MD=y +# CONFIG_BLK_DEV_MD is not set +CONFIG_BLK_DEV_DM=y +# CONFIG_DM_DEBUG is not set +CONFIG_DM_CRYPT=y +# CONFIG_DM_SNAPSHOT is not set +# CONFIG_DM_MIRROR is not set +# CONFIG_DM_RAID is not set +# CONFIG_DM_ZERO is not set +# CONFIG_DM_MULTIPATH is not set +# CONFIG_DM_DELAY is not set +CONFIG_DM_UEVENT=y +# CONFIG_DM_FLAKEY is not set +# CONFIG_TARGET_CORE is not set +CONFIG_NETDEVICES=y +CONFIG_IFB=y +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +CONFIG_TUN=y +# CONFIG_VETH is not set +# CONFIG_MII is not set +# CONFIG_PHYLIB is not set +# CONFIG_NET_ETHERNET is not set +CONFIG_NETDEV_1000=y +# CONFIG_STMMAC_ETH is not set +CONFIG_NETDEV_10000=y +CONFIG_WLAN=y +# CONFIG_USB_ZD1201 is not set +CONFIG_BCM4329=m +CONFIG_BCM4329_FW_PATH="/vendor/firmware/fw_bcm4329.bin" +CONFIG_BCM4329_NVRAM_PATH="/vendor/firmware/nvram_net.txt" +# CONFIG_BCMDHD is not set +# CONFIG_HOSTAP is not set + +# +# WiMAX Wireless Broadband devices +# +# CONFIG_WIMAX_I2400M_USB is not set +# CONFIG_WIMAX_I2400M_SDIO is not set +CONFIG_WIMAX_CMC7XX=y +# CONFIG_WIMAX_CMC7XX_DEBUG is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set +# CONFIG_USB_HSO is not set +# CONFIG_USB_CDC_PHONET is not set +# CONFIG_USB_IPHETH is not set +# CONFIG_WAN is not set + +# +# CAIF transport drivers +# +CONFIG_PPP=y +# CONFIG_PPP_MULTILINK is not set +# CONFIG_PPP_FILTER is not set +# CONFIG_PPP_ASYNC is not set +# CONFIG_PPP_SYNC_TTY is not set +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_MPPE=y +# CONFIG_PPPOE is not set +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +# CONFIG_SLIP is not set +CONFIG_SLHC=y +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +CONFIG_INPUT_FF_MEMLESS=y +# CONFIG_INPUT_POLLDEV is not set +# CONFIG_INPUT_SPARSEKMAP is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_APMPOWER is not set +# CONFIG_INPUT_KEYRESET is not set + +# +# Input Device Drivers +# +CONFIG_INPUT_KEYBOARD=y +# CONFIG_KEYBOARD_ADP5588 is not set +# CONFIG_KEYBOARD_ADP5589 is not set +# CONFIG_KEYBOARD_ATKBD is not set +# CONFIG_KEYBOARD_QT1070 is not set +# CONFIG_KEYBOARD_QT2160 is not set +# CONFIG_KEYBOARD_LKKBD is not set +# CONFIG_KEYBOARD_GPIO is not set +# CONFIG_KEYBOARD_TCA6416 is not set +# CONFIG_KEYBOARD_MATRIX is not set +# CONFIG_KEYBOARD_MAX7359 is not set +# CONFIG_KEYBOARD_MCS is not set +# CONFIG_KEYBOARD_MPR121 is not set +# CONFIG_KEYBOARD_NEWTON is not set +# CONFIG_KEYBOARD_OPENCORES is not set +# CONFIG_KEYBOARD_STOWAWAY is not set +# CONFIG_KEYBOARD_SUNKBD is not set +# CONFIG_KEYBOARD_XTKBD is not set +CONFIG_KEYPAD_CYPRESS_TOUCH=y +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +CONFIG_INPUT_TOUCHSCREEN=y +# CONFIG_TOUCHSCREEN_ADS7846 is not set +# CONFIG_TOUCHSCREEN_AD7877 is not set +# CONFIG_TOUCHSCREEN_AD7879 is not set +# CONFIG_TOUCHSCREEN_ATMEL_MXT is not set +# CONFIG_TOUCHSCREEN_BU21013 is not set +# CONFIG_TOUCHSCREEN_CY8CTMG110 is not set +# CONFIG_TOUCHSCREEN_DYNAPRO is not set +# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set +# CONFIG_TOUCHSCREEN_EETI is not set +# CONFIG_TOUCHSCREEN_FUJITSU is not set +# CONFIG_TOUCHSCREEN_GUNZE is not set +# CONFIG_TOUCHSCREEN_ELO is not set +# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set +# CONFIG_TOUCHSCREEN_MAX11801 is not set +# CONFIG_TOUCHSCREEN_MCS5000 is not set +# CONFIG_TOUCHSCREEN_MTOUCH is not set +# CONFIG_TOUCHSCREEN_INEXIO is not set +# CONFIG_TOUCHSCREEN_MK712 is not set +CONFIG_TOUCHSCREEN_MXT224=y +# CONFIG_TOUCHSCREEN_PENMOUNT is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set +# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set +# CONFIG_TOUCHSCREEN_TOUCHWIN is not set +# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set +# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set +# CONFIG_TOUCHSCREEN_TSC2005 is not set +# CONFIG_TOUCHSCREEN_TSC2007 is not set +# CONFIG_TOUCHSCREEN_W90X900 is not set +# CONFIG_TOUCHSCREEN_ST1232 is not set +# CONFIG_TOUCHSCREEN_TPS6507X is not set +CONFIG_INPUT_MISC=y +CONFIG_GYRO_K3G=y +# CONFIG_INPUT_AD714X is not set +# CONFIG_INPUT_ATI_REMOTE is not set +# CONFIG_INPUT_ATI_REMOTE2 is not set +CONFIG_INPUT_KEYCHORD=y +# CONFIG_INPUT_KEYSPAN_REMOTE is not set +# CONFIG_INPUT_POWERMATE is not set +# CONFIG_INPUT_YEALINK is not set +# CONFIG_INPUT_CM109 is not set +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_INPUT_PCF8574 is not set +# CONFIG_INPUT_PWM_BEEPER is not set +# CONFIG_INPUT_GPIO_ROTARY_ENCODER is not set +# CONFIG_INPUT_ADXL34X is not set +# CONFIG_INPUT_CMA3000 is not set +CONFIG_OPTICAL_GP2A=y + +# +# Hardware I/O ports +# +CONFIG_SERIO=y +CONFIG_SERIO_SERPORT=y +CONFIG_SERIO_LIBPS2=y +# CONFIG_SERIO_RAW is not set +# CONFIG_SERIO_ALTERA_PS2 is not set +# CONFIG_SERIO_PS2MULT is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +# CONFIG_VT is not set +CONFIG_UNIX98_PTYS=y +# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_N_GSM is not set +# CONFIG_TRACE_SINK is not set +CONFIG_DEVMEM=y +CONFIG_DEVKMEM=y + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SAMSUNG=y +CONFIG_SERIAL_SAMSUNG_UARTS_4=y +CONFIG_SERIAL_SAMSUNG_UARTS=4 +CONFIG_SERIAL_SAMSUNG_CONSOLE=y +CONFIG_SERIAL_S5PV210=y +# CONFIG_SERIAL_MAX3100 is not set +# CONFIG_SERIAL_MAX3107 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +# CONFIG_SERIAL_TIMBERDALE is not set +# CONFIG_SERIAL_ALTERA_JTAGUART is not set +# CONFIG_SERIAL_ALTERA_UART is not set +# CONFIG_SERIAL_IFX6X60 is not set +# CONFIG_SERIAL_XILINX_PS_UART is not set +# CONFIG_TTY_PRINTK is not set +# CONFIG_HVC_DCC is not set +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_TIMERIOMEM is not set +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_DCC_TTY is not set +# CONFIG_RAMOOPS is not set +CONFIG_I2C=y +CONFIG_I2C_BOARDINFO=y +CONFIG_I2C_COMPAT=y +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_MUX is not set +CONFIG_I2C_HELPER_AUTO=y +CONFIG_I2C_ALGOBIT=y + +# +# I2C Hardware Bus support +# + +# +# I2C system bus drivers (mostly embedded / system-on-chip) +# +# CONFIG_I2C_DESIGNWARE is not set +CONFIG_I2C_GPIO=y +# CONFIG_I2C_OCORES is not set +# CONFIG_I2C_PCA_PLATFORM is not set +# CONFIG_I2C_PXA_PCI is not set +CONFIG_HAVE_S3C2410_I2C=y +CONFIG_I2C_S3C2410=y +# CONFIG_I2C_SIMTEC is not set +# CONFIG_I2C_XILINX is not set + +# +# External I2C/SMBus adapter drivers +# +# CONFIG_I2C_DIOLAN_U2C is not set +# CONFIG_I2C_PARPORT_LIGHT is not set +# CONFIG_I2C_TAOS_EVM is not set +# CONFIG_I2C_TINY_USB is not set + +# +# Other I2C/SMBus bus drivers +# +# CONFIG_I2C_STUB is not set +# CONFIG_I2C_DEBUG_CORE is not set +# CONFIG_I2C_DEBUG_ALGO is not set +# CONFIG_I2C_DEBUG_BUS is not set +CONFIG_SPI=y +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +# CONFIG_SPI_ALTERA is not set +CONFIG_SPI_BITBANG=y +CONFIG_SPI_GPIO=y +# CONFIG_SPI_OC_TINY is not set +# CONFIG_SPI_PXA2XX_PCI is not set +# CONFIG_SPI_XILINX is not set +# CONFIG_SPI_DESIGNWARE is not set + +# +# SPI Protocol Masters +# +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set + +# +# PPS support +# +# CONFIG_PPS is not set + +# +# PPS generators support +# + +# +# PTP clock support +# + +# +# Enable Device Drivers -> PPS to see the PTP clock options. +# +CONFIG_ARCH_REQUIRE_GPIOLIB=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y + +# +# Memory mapped GPIO drivers: +# +# CONFIG_GPIO_BASIC_MMIO is not set +# CONFIG_GPIO_IT8761E is not set +CONFIG_GPIO_PLAT_SAMSUNG=y +CONFIG_GPIO_S5PV210=y + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX7300 is not set +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCF857X is not set +# CONFIG_GPIO_SX150X is not set +# CONFIG_GPIO_ADP5588 is not set + +# +# PCI GPIO expanders: +# + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set +# CONFIG_GPIO_MC33880 is not set +# CONFIG_GPIO_74X164 is not set + +# +# AC97 GPIO expanders: +# + +# +# MODULbus GPIO expanders: +# +# CONFIG_W1 is not set +CONFIG_POWER_SUPPLY=y +# CONFIG_POWER_SUPPLY_DEBUG is not set +# CONFIG_PDA_POWER is not set +# CONFIG_APM_POWER is not set +# CONFIG_TEST_POWER is not set +# CONFIG_BATTERY_DS2780 is not set +# CONFIG_BATTERY_DS2782 is not set +# CONFIG_BATTERY_BQ20Z75 is not set +# CONFIG_BATTERY_BQ27x00 is not set +CONFIG_BATTERY_MAX17040=y +# CONFIG_BATTERY_MAX17042 is not set +# CONFIG_BATTERY_S3C is not set +CONFIG_BATTERY_S5PC110=y +# CONFIG_CHARGER_MAX8903 is not set +# CONFIG_CHARGER_GPIO is not set +# CONFIG_HWMON is not set +# CONFIG_THERMAL is not set +# CONFIG_WATCHDOG is not set +CONFIG_SSB_POSSIBLE=y + +# +# Sonics Silicon Backplane +# +# CONFIG_SSB is not set +CONFIG_BCMA_POSSIBLE=y + +# +# Broadcom specific AMBA +# +# CONFIG_BCMA is not set +CONFIG_MFD_SUPPORT=y +CONFIG_MFD_CORE=y +# CONFIG_MFD_88PM860X is not set +# CONFIG_MFD_SM501 is not set +# CONFIG_MFD_ASIC3 is not set +# CONFIG_HTC_EGPIO is not set +# CONFIG_HTC_PASIC3 is not set +# CONFIG_HTC_I2CPLD is not set +# CONFIG_TPS6105X is not set +# CONFIG_TPS65010 is not set +# CONFIG_TPS6507X is not set +# CONFIG_MFD_TPS6586X is not set +# CONFIG_TWL4030_CORE is not set +# CONFIG_MFD_STMPE is not set +# CONFIG_MFD_TC3589X is not set +# CONFIG_MFD_TMIO is not set +# CONFIG_MFD_T7L66XB is not set +# CONFIG_MFD_TC6387XB is not set +# CONFIG_MFD_TC6393XB is not set +# CONFIG_PMIC_DA903X is not set +# CONFIG_PMIC_ADP5520 is not set +# CONFIG_MFD_MAX8925 is not set +# CONFIG_MFD_MAX8997 is not set +CONFIG_MFD_MAX8998=y +# CONFIG_MFD_WM8400 is not set +# CONFIG_MFD_WM831X_I2C is not set +# CONFIG_MFD_WM831X_SPI is not set +# CONFIG_MFD_WM8350_I2C is not set +# CONFIG_MFD_WM8994 is not set +# CONFIG_MFD_PCF50633 is not set +# CONFIG_MFD_MC13XXX is not set +# CONFIG_ABX500_CORE is not set +# CONFIG_EZX_PCAP is not set +# CONFIG_MFD_WL1273_CORE is not set +# CONFIG_MFD_TPS65910 is not set +CONFIG_REGULATOR=y +# CONFIG_REGULATOR_DEBUG is not set +# CONFIG_REGULATOR_DUMMY is not set +# CONFIG_REGULATOR_FIXED_VOLTAGE is not set +# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set +# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set +# CONFIG_REGULATOR_BQ24022 is not set +# CONFIG_REGULATOR_MAX1586 is not set +# CONFIG_REGULATOR_MAX8649 is not set +# CONFIG_REGULATOR_MAX8660 is not set +CONFIG_REGULATOR_MAX8893=y +# CONFIG_REGULATOR_MAX8952 is not set +CONFIG_REGULATOR_MAX8998=y +# CONFIG_REGULATOR_LP3971 is not set +# CONFIG_REGULATOR_LP3972 is not set +# CONFIG_REGULATOR_TPS65023 is not set +# CONFIG_REGULATOR_TPS6507X is not set +# CONFIG_REGULATOR_ISL6271A is not set +# CONFIG_REGULATOR_AD5398 is not set +# CONFIG_REGULATOR_TPS6524X is not set +CONFIG_MEDIA_SUPPORT=y + +# +# Multimedia core support +# +# CONFIG_MEDIA_CONTROLLER is not set +CONFIG_VIDEO_DEV=y +CONFIG_VIDEO_V4L2_COMMON=y +# CONFIG_DVB_CORE is not set +CONFIG_VIDEO_MEDIA=y + +# +# Multimedia drivers +# +# CONFIG_RC_CORE is not set +# CONFIG_MEDIA_ATTACH is not set +CONFIG_MEDIA_TUNER=y +# CONFIG_MEDIA_TUNER_CUSTOMISE is not set +CONFIG_MEDIA_TUNER_SIMPLE=y +CONFIG_MEDIA_TUNER_TDA8290=y +CONFIG_MEDIA_TUNER_TDA827X=y +CONFIG_MEDIA_TUNER_TDA18271=y +CONFIG_MEDIA_TUNER_TDA9887=y +CONFIG_MEDIA_TUNER_TEA5761=y +CONFIG_MEDIA_TUNER_TEA5767=y +CONFIG_MEDIA_TUNER_MT20XX=y +CONFIG_MEDIA_TUNER_XC2028=y +CONFIG_MEDIA_TUNER_XC5000=y +CONFIG_MEDIA_TUNER_MC44S803=y +CONFIG_VIDEO_V4L2=y +CONFIG_VIDEO_CAPTURE_DRIVERS=y +# CONFIG_VIDEO_ADV_DEBUG is not set +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set + +# +# Encoders, decoders, sensors and other helper chips +# + +# +# Audio decoders, processors and mixers +# +# CONFIG_VIDEO_TVAUDIO is not set +# CONFIG_VIDEO_TDA7432 is not set +# CONFIG_VIDEO_TDA9840 is not set +# CONFIG_VIDEO_TEA6415C is not set +# CONFIG_VIDEO_TEA6420 is not set +# CONFIG_VIDEO_MSP3400 is not set +# CONFIG_VIDEO_CS5345 is not set +# CONFIG_VIDEO_CS53L32A is not set +# CONFIG_VIDEO_TLV320AIC23B is not set +# CONFIG_VIDEO_WM8775 is not set +# CONFIG_VIDEO_WM8739 is not set +# CONFIG_VIDEO_VP27SMPX is not set + +# +# RDS decoders +# +# CONFIG_VIDEO_SAA6588 is not set + +# +# Video decoders +# +# CONFIG_VIDEO_ADV7180 is not set +# CONFIG_VIDEO_BT819 is not set +# CONFIG_VIDEO_BT856 is not set +# CONFIG_VIDEO_BT866 is not set +# CONFIG_VIDEO_KS0127 is not set +# CONFIG_VIDEO_SAA7110 is not set +# CONFIG_VIDEO_SAA711X is not set +# CONFIG_VIDEO_SAA7191 is not set +# CONFIG_VIDEO_TVP514X is not set +# CONFIG_VIDEO_TVP5150 is not set +# CONFIG_VIDEO_TVP7002 is not set +# CONFIG_VIDEO_VPX3220 is not set + +# +# Video and audio decoders +# +# CONFIG_VIDEO_SAA717X is not set +# CONFIG_VIDEO_CX25840 is not set + +# +# MPEG video encoders +# +# CONFIG_VIDEO_CX2341X is not set + +# +# Video encoders +# +# CONFIG_VIDEO_SAA7127 is not set +# CONFIG_VIDEO_SAA7185 is not set +# CONFIG_VIDEO_ADV7170 is not set +# CONFIG_VIDEO_ADV7175 is not set +# CONFIG_VIDEO_ADV7343 is not set +# CONFIG_VIDEO_AK881X is not set + +# +# Camera sensor devices +# +# CONFIG_VIDEO_OV7670 is not set +# CONFIG_VIDEO_MT9V011 is not set +# CONFIG_VIDEO_TCM825X is not set + +# +# Video improvement chips +# +# CONFIG_VIDEO_UPD64031A is not set +# CONFIG_VIDEO_UPD64083 is not set + +# +# Miscelaneous helper chips +# +# CONFIG_VIDEO_THS7303 is not set +# CONFIG_VIDEO_M52790 is not set +# CONFIG_VIDEO_CPIA2 is not set +# CONFIG_VIDEO_SR030PC30 is not set +# CONFIG_VIDEO_NOON010PC30 is not set +# CONFIG_SOC_CAMERA is not set +# CONFIG_VIDEO_SAMSUNG_S5P_FIMC is not set +# CONFIG_V4L_USB_DRIVERS is not set +CONFIG_VIDEO_S5KA3DFX=y +CONFIG_VIDEO_S5K4ECGX=y +# CONFIG_VIDEO_S5K4ECGX_DEBUG is not set +CONFIG_VIDEO_S5K4ECGX_V_1_0=y +CONFIG_VIDEO_S5K4ECGX_V_1_1=y +CONFIG_VIDEO_SAMSUNG=y +CONFIG_VIDEO_SAMSUNG_V4L2=y +CONFIG_VIDEO_FIMC=y +CONFIG_VIDEO_FIMC_RANGE_NARROW=y +# CONFIG_VIDEO_FIMC_RANGE_WIDE is not set +# CONFIG_VIDEO_FIMC_DEBUG is not set +# CONFIG_VIDEO_FIMC_MIPI is not set +CONFIG_VIDEO_MFC50=y +CONFIG_VIDEO_MFC_MAX_INSTANCE=4 +# CONFIG_VIDEO_MFC50_DEBUG is not set +CONFIG_VIDEO_JPEG_V2=y +# CONFIG_VIDEO_JPEG_DEBUG is not set +# CONFIG_V4L_MEM2MEM_DRIVERS is not set +# CONFIG_RADIO_ADAPTERS is not set + +# +# Graphics support +# +# CONFIG_DRM is not set +# CONFIG_ION is not set +CONFIG_PVR_SGX=y +CONFIG_PVR_BUILD_RELEASE=y +# CONFIG_PVR_BUILD_DEBUG is not set +CONFIG_PVR_NEED_PVR_DPF=y +CONFIG_PVR_NEED_PVR_ASSERT=y +CONFIG_PVR_PERCONTEXT_PB=y +CONFIG_PVR_ACTIVE_POWER_MANAGEMENT=y +CONFIG_PVR_ACTIVE_POWER_LATENCY_MS=100 +CONFIG_PVR_SGX_LOW_LATENCY_SCHEDULING=y +CONFIG_PVR_USSE_EDM_STATUS_DEBUG=y +CONFIG_PVR_DUMP_MK_TRACE=y +# CONFIG_PVR_PDUMP is not set +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +CONFIG_FB=y +# CONFIG_FIRMWARE_EDID is not set +# CONFIG_FB_DDC is not set +# CONFIG_FB_BOOT_VESA_SUPPORT is not set +CONFIG_FB_CFB_FILLRECT=y +CONFIG_FB_CFB_COPYAREA=y +CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set +# CONFIG_FB_SYS_FILLRECT is not set +# CONFIG_FB_SYS_COPYAREA is not set +# CONFIG_FB_SYS_IMAGEBLIT is not set +# CONFIG_FB_FOREIGN_ENDIAN is not set +# CONFIG_FB_SYS_FOPS is not set +# CONFIG_FB_WMT_GE_ROPS is not set +# CONFIG_FB_SVGALIB is not set +# CONFIG_FB_MACMODES is not set +# CONFIG_FB_BACKLIGHT is not set +# CONFIG_FB_MODE_HELPERS is not set +# CONFIG_FB_TILEBLITTING is not set + +# +# Frame buffer hardware drivers +# +CONFIG_FB_S3C=y +# CONFIG_FB_S3C_SPLASH_SCREEN is not set +CONFIG_FB_S3C_LCD_INIT=y +# CONFIG_FB_S3C_DEBUG is not set +# CONFIG_FB_S3C_TRACE_UNDERRUN is not set +CONFIG_FB_S3C_DEFAULT_WINDOW=2 +CONFIG_FB_S3C_NR_BUFFERS=7 +CONFIG_FB_S3C_NUM_OVLY_WIN=1 +CONFIG_FB_S3C_NUM_BUF_OVLY_WIN=3 +# CONFIG_FB_S3C_VIRTUAL is not set +CONFIG_FB_S3C_TL2796=y +CONFIG_FB_VOODOO=y +# CONFIG_FB_VOODOO_DEBUG_LOG is not set +CONFIG_FB_S3C_NT35580=y +# CONFIG_FB_S3C_LVDS is not set +# CONFIG_FB_S3C_AMS701KA is not set +# CONFIG_FB_S3C_MDNIE is not set +# CONFIG_TL2796_CONVERT_COLORS_RES is not set +# CONFIG_FB_S3C_CMC623 is not set +# CONFIG_FB_S1D13XXX is not set +# CONFIG_FB_TMIO is not set +# CONFIG_FB_UDL is not set +# CONFIG_FB_VIRTUAL is not set +# CONFIG_FB_METRONOME is not set +# CONFIG_FB_BROADSHEET is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_L4F00242T03 is not set +# CONFIG_LCD_LMS283GF05 is not set +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_TDO24M is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +# CONFIG_LCD_S6E63M0 is not set +# CONFIG_LCD_LD9040 is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +# CONFIG_BACKLIGHT_PWM is not set +# CONFIG_BACKLIGHT_ADP8860 is not set +# CONFIG_BACKLIGHT_ADP8870 is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_LOGO is not set +CONFIG_SOUND=y +# CONFIG_SOUND_OSS_CORE is not set +CONFIG_SND=y +CONFIG_SND_TIMER=y +CONFIG_SND_PCM=y +CONFIG_SND_JACK=y +# CONFIG_SND_SEQUENCER is not set +# CONFIG_SND_MIXER_OSS is not set +# CONFIG_SND_PCM_OSS is not set +# CONFIG_SND_HRTIMER is not set +# CONFIG_SND_DYNAMIC_MINORS is not set +CONFIG_SND_SUPPORT_OLD_API=y +CONFIG_SND_VERBOSE_PROCFS=y +# CONFIG_SND_VERBOSE_PRINTK is not set +# CONFIG_SND_DEBUG is not set +# CONFIG_SND_RAWMIDI_SEQ is not set +# CONFIG_SND_OPL3_LIB_SEQ is not set +# CONFIG_SND_OPL4_LIB_SEQ is not set +# CONFIG_SND_SBAWE_SEQ is not set +# CONFIG_SND_EMU10K1_SEQ is not set +CONFIG_SND_DRIVERS=y +# CONFIG_SND_DUMMY is not set +# CONFIG_SND_ALOOP is not set +# CONFIG_SND_MTPAV is not set +# CONFIG_SND_SERIAL_U16550 is not set +# CONFIG_SND_MPU401 is not set +CONFIG_SND_ARM=y +CONFIG_SND_SPI=y +CONFIG_SND_USB=y +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_UA101 is not set +# CONFIG_SND_USB_CAIAQ is not set +# CONFIG_SND_USB_6FIRE is not set +CONFIG_SND_SOC=y +# CONFIG_SND_SOC_CACHE_LZO is not set +CONFIG_SND_SOC_SAMSUNG=y +CONFIG_SND_S5PC1XX_I2S=y +CONFIG_S5P_INTERNAL_DMA=y +CONFIG_SND_S5P_WM8994_MASTER=y +CONFIG_SND_SOC_SAMSUNG_HERRING_WM8994=y +CONFIG_SND_VOODOO=y +CONFIG_SND_VOODOO_HP_LEVEL_CONTROL=y +CONFIG_SND_VOODOO_HP_LEVEL=54 +CONFIG_SND_VOODOO_RECORD_PRESETS=y +# CONFIG_SND_VOODOO_DEVELOPMENT is not set +CONFIG_SND_SOC_I2C_AND_SPI=y +# CONFIG_SND_SOC_ALL_CODECS is not set +CONFIG_SND_SOC_WM8994_SAMSUNG=y +# CONFIG_SOUND_PRIME is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +# CONFIG_USB_HID is not set +# CONFIG_HID_PID is not set + +# +# USB HID Boot Protocol drivers +# +# CONFIG_USB_KBD is not set +# CONFIG_USB_MOUSE is not set + +# +# Special HID drivers +# +# CONFIG_HID_APPLE is not set +# CONFIG_HID_ELECOM is not set +# CONFIG_HID_MAGICMOUSE is not set +# CONFIG_HID_WACOM is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +CONFIG_USB_ARCH_HAS_EHCI=y +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG_WHITELIST is not set +# CONFIG_USB_OTG_BLACKLIST_HUB is not set +# CONFIG_USB_MON is not set +# CONFIG_USB_WUSB is not set +# CONFIG_USB_WUSB_CBAF is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_C67X00_HCD is not set +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_OXU210HP_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +# CONFIG_USB_ISP1760_HCD is not set +# CONFIG_USB_ISP1362_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set +# CONFIG_USB_HWA_HCD is not set +# CONFIG_USB_MUSB_HDRC is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set +# CONFIG_USB_WDM is not set +# CONFIG_USB_TMC is not set + +# +# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may +# + +# +# also be needed; see USB_STORAGE Help for more info +# +# CONFIG_USB_STORAGE is not set +# CONFIG_USB_UAS is not set +# CONFIG_USB_LIBUSUAL is not set + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers +# +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_SEVSEG is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set +# CONFIG_USB_TEST is not set +# CONFIG_USB_ISIGHTFW is not set +# CONFIG_USB_YUREX is not set +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG_FILES is not set +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_FUSB300 is not set +# CONFIG_USB_GADGET_R8A66597 is not set +CONFIG_USB_GADGET_S3C_OTGD=y +# CONFIG_USB_GADGET_PXA_U2O is not set +# CONFIG_USB_GADGET_M66592 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set + +# +# NOTE: S3C OTG device role enables the controller driver below +# +CONFIG_USB_S3C_OTGD=y +CONFIG_USB_GADGET_S3C_OTGD_DMA_MODE=y +# CONFIG_USB_GADGET_S3C_OTGD_SLAVE_MODE is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_AUDIO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_G_NCM is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FUNCTIONFS is not set +# CONFIG_USB_FILE_STORAGE is not set +# CONFIG_USB_MASS_STORAGE is not set +# CONFIG_USB_G_SERIAL is not set +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +CONFIG_USB_G_ANDROID=y +CONFIG_USB_ANDROID_RNDIS_DWORD_ALIGNED=y +# CONFIG_USB_CDC_COMPOSITE is not set +# CONFIG_USB_G_NOKIA is not set +# CONFIG_USB_G_MULTI is not set +# CONFIG_USB_G_HID is not set +# CONFIG_USB_G_DBGP is not set +# CONFIG_USB_G_WEBCAM is not set + +# +# OTG and related infrastructure +# +# CONFIG_USB_OTG_WAKELOCK is not set +# CONFIG_USB_GPIO_VBUS is not set +# CONFIG_USB_ULPI is not set +# CONFIG_NOP_USB_XCEIV is not set +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set +CONFIG_MMC_UNSAFE_RESUME=y +# CONFIG_MMC_CLKGATE is not set +# CONFIG_MMC_EMBEDDED_SDIO is not set +# CONFIG_MMC_PARANOID_SD_INIT is not set + +# +# MMC/SD/SDIO Card Drivers +# +CONFIG_MMC_BLOCK=y +CONFIG_MMC_BLOCK_MINORS=8 +CONFIG_MMC_BLOCK_BOUNCE=y +# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set +# CONFIG_SDIO_UART is not set +# CONFIG_MMC_TEST is not set + +# +# MMC/SD/SDIO Host Controller Drivers +# +CONFIG_MMC_SDHCI=y +# CONFIG_MMC_SDHCI_PLTFM is not set +CONFIG_MMC_SDHCI_S3C=y +CONFIG_MMC_SDHCI_S3C_DMA=y +# CONFIG_MMC_SPI is not set +# CONFIG_MMC_DW is not set +# CONFIG_MMC_VUB300 is not set +# CONFIG_MMC_USHC is not set +# CONFIG_MEMSTICK is not set +# CONFIG_NEW_LEDS is not set +# CONFIG_NFC_DEVICES is not set +CONFIG_SWITCH=y +# CONFIG_SWITCH_GPIO is not set +# CONFIG_ACCESSIBILITY is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +CONFIG_RTC_INTF_ALARM=y +CONFIG_RTC_INTF_ALARM_DEV=y +# CONFIG_RTC_DRV_TEST is not set + +# +# I2C RTC drivers +# +# CONFIG_RTC_DRV_DS1307 is not set +# CONFIG_RTC_DRV_DS1374 is not set +# CONFIG_RTC_DRV_DS1672 is not set +# CONFIG_RTC_DRV_DS3232 is not set +# CONFIG_RTC_DRV_MAX6900 is not set +# CONFIG_RTC_DRV_MAX8998 is not set +# CONFIG_RTC_DRV_RS5C372 is not set +# CONFIG_RTC_DRV_ISL1208 is not set +# CONFIG_RTC_DRV_ISL12022 is not set +# CONFIG_RTC_DRV_X1205 is not set +# CONFIG_RTC_DRV_PCF8563 is not set +# CONFIG_RTC_DRV_PCF8583 is not set +# CONFIG_RTC_DRV_M41T80 is not set +# CONFIG_RTC_DRV_BQ32K is not set +# CONFIG_RTC_DRV_S35390A is not set +# CONFIG_RTC_DRV_FM3130 is not set +# CONFIG_RTC_DRV_RX8581 is not set +# CONFIG_RTC_DRV_RX8025 is not set +# CONFIG_RTC_DRV_EM3027 is not set +# CONFIG_RTC_DRV_RV3029C2 is not set + +# +# SPI RTC drivers +# +# CONFIG_RTC_DRV_M41T93 is not set +# CONFIG_RTC_DRV_M41T94 is not set +# CONFIG_RTC_DRV_DS1305 is not set +# CONFIG_RTC_DRV_DS1390 is not set +# CONFIG_RTC_DRV_MAX6902 is not set +# CONFIG_RTC_DRV_R9701 is not set +# CONFIG_RTC_DRV_RS5C348 is not set +# CONFIG_RTC_DRV_DS3234 is not set +# CONFIG_RTC_DRV_PCF2123 is not set + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_CMOS is not set +# CONFIG_RTC_DRV_DS1286 is not set +# CONFIG_RTC_DRV_DS1511 is not set +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T35 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_MSM6242 is not set +# CONFIG_RTC_DRV_BQ4802 is not set +# CONFIG_RTC_DRV_RP5C01 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_HAVE_S3C_RTC=y +CONFIG_RTC_DRV_S3C=y +# CONFIG_DMADEVICES is not set +# CONFIG_AUXDISPLAY is not set +# CONFIG_UIO is not set +CONFIG_STAGING=y +# CONFIG_USBIP_CORE is not set +# CONFIG_ECHO is not set +# CONFIG_BRCMUTIL is not set +# CONFIG_ASUS_OLED is not set +# CONFIG_R8712U is not set +# CONFIG_TRANZPORT is not set + +# +# Android +# +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_LOGGER=y +CONFIG_ANDROID_RAM_CONSOLE=y +CONFIG_ANDROID_RAM_CONSOLE_ENABLE_VERBOSE=y +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION=y +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE=128 +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE=16 +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE=8 +CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL=0x11d +# CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT is not set +CONFIG_ANDROID_TIMED_OUTPUT=y +CONFIG_ANDROID_TIMED_GPIO=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +# CONFIG_POHMELFS is not set +# CONFIG_LINE6_USB is not set +# CONFIG_VT6656 is not set +# CONFIG_IIO is not set +CONFIG_XVMALLOC=y +CONFIG_ZRAM=y +# CONFIG_ZRAM_DEBUG is not set +# CONFIG_FB_SM7XX is not set +# CONFIG_EASYCAP is not set +CONFIG_MACH_NO_WESTBRIDGE=y +# CONFIG_USB_ENESTORAGE is not set +# CONFIG_BCM_WIMAX is not set +# CONFIG_FT1000 is not set + +# +# Speakup console speech +# +# CONFIG_TOUCHSCREEN_CLEARPAD_TM1217 is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4 is not set + +# +# Altera FPGA firmware download module +# +# CONFIG_ALTERA_STAPL is not set + +# +# File systems +# +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set +# CONFIG_EXT2_FS_XIP is not set +# CONFIG_EXT3_FS is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_USE_FOR_EXT23=y +# CONFIG_EXT4_FS_XATTR is not set +# CONFIG_EXT4_DEBUG is not set +CONFIG_JBD2=y +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_BTRFS_FS is not set +# CONFIG_NILFS2_FS is not set +CONFIG_FS_POSIX_ACL=y +CONFIG_EXPORTFS=y +CONFIG_FILE_LOCKING=y +CONFIG_FSNOTIFY=y +# CONFIG_DNOTIFY is not set +CONFIG_INOTIFY_USER=y +# CONFIG_FANOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_QUOTACTL is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set +CONFIG_GENERIC_ACL=y + +# +# Caches +# +# CONFIG_FSCACHE is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_FAT_DEFAULT_CODEPAGE=437 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_SYSCTL=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_TMPFS_XATTR=y +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set +CONFIG_MISC_FILESYSTEMS=y +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +CONFIG_YAFFS_FS=y +CONFIG_YAFFS_YAFFS1=y +# CONFIG_YAFFS_9BYTE_TAGS is not set +# CONFIG_YAFFS_DOES_ECC is not set +CONFIG_YAFFS_YAFFS2=y +CONFIG_YAFFS_AUTO_YAFFS2=y +# CONFIG_YAFFS_DISABLE_TAGS_ECC is not set +# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set +# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set +# CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING is not set +# CONFIG_YAFFS_DISABLE_BACKGROUND is not set +CONFIG_YAFFS_XATTR=y +# CONFIG_JFFS2_FS is not set +# CONFIG_LOGFS is not set +CONFIG_CRAMFS=y +# CONFIG_SQUASHFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_OMFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +CONFIG_ROMFS_FS=y +CONFIG_ROMFS_BACKED_BY_BLOCK=y +# CONFIG_ROMFS_BACKED_BY_MTD is not set +# CONFIG_ROMFS_BACKED_BY_BOTH is not set +CONFIG_ROMFS_ON_BLOCK=y +# CONFIG_PSTORE is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +CONFIG_NETWORK_FILESYSTEMS=y +CONFIG_NFS_FS=y +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set +CONFIG_NFSD=y +CONFIG_NFSD_DEPRECATED=y +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_V4 is not set +CONFIG_LOCKD=y +CONFIG_NFS_COMMON=y +CONFIG_SUNRPC=y +# CONFIG_CEPH_FS is not set +CONFIG_CIFS=y +# CONFIG_CIFS_STATS is not set +# CONFIG_CIFS_WEAK_PW_HASH is not set +# CONFIG_CIFS_XATTR is not set +# CONFIG_CIFS_DEBUG2 is not set +# CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_AFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +CONFIG_BSD_DISKLABEL=y +# CONFIG_MINIX_SUBPARTITION is not set +CONFIG_SOLARIS_X86_PARTITION=y +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_KARMA_PARTITION is not set +CONFIG_EFI_PARTITION=y +# CONFIG_SYSV68_PARTITION is not set +CONFIG_NLS=y +CONFIG_NLS_DEFAULT="iso8859-1" +CONFIG_NLS_CODEPAGE_437=y +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# CONFIG_NLS_CODEPAGE_852 is not set +# CONFIG_NLS_CODEPAGE_855 is not set +# CONFIG_NLS_CODEPAGE_857 is not set +# CONFIG_NLS_CODEPAGE_860 is not set +# CONFIG_NLS_CODEPAGE_861 is not set +# CONFIG_NLS_CODEPAGE_862 is not set +# CONFIG_NLS_CODEPAGE_863 is not set +# CONFIG_NLS_CODEPAGE_864 is not set +# CONFIG_NLS_CODEPAGE_865 is not set +# CONFIG_NLS_CODEPAGE_866 is not set +# CONFIG_NLS_CODEPAGE_869 is not set +# CONFIG_NLS_CODEPAGE_936 is not set +# CONFIG_NLS_CODEPAGE_950 is not set +# CONFIG_NLS_CODEPAGE_932 is not set +# CONFIG_NLS_CODEPAGE_949 is not set +# CONFIG_NLS_CODEPAGE_874 is not set +# CONFIG_NLS_ISO8859_8 is not set +# CONFIG_NLS_CODEPAGE_1250 is not set +# CONFIG_NLS_CODEPAGE_1251 is not set +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Kernel hacking +# +# CONFIG_PRINTK_TIME is not set +CONFIG_DEFAULT_MESSAGE_LOGLEVEL=4 +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +CONFIG_FRAME_WARN=1024 +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_STRIP_ASM_SYMS is not set +# CONFIG_UNUSED_SYMBOLS is not set +# CONFIG_DEBUG_FS is not set +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_SECTION_MISMATCH is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_HARDLOCKUP_DETECTOR is not set +# CONFIG_SLUB_DEBUG_ON is not set +# CONFIG_SLUB_STATS is not set +# CONFIG_SPARSE_RCU_POINTER is not set +# CONFIG_STACKTRACE is not set +# CONFIG_DEBUG_MEMORY_INIT is not set +CONFIG_FRAME_POINTER=y +# CONFIG_SYSCTL_SYSCALL_CHECK is not set +CONFIG_HAVE_FUNCTION_TRACER=y +CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y +CONFIG_HAVE_DYNAMIC_FTRACE=y +CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y +CONFIG_HAVE_C_RECORDMCOUNT=y +CONFIG_TRACING_SUPPORT=y +# CONFIG_FTRACE is not set +# CONFIG_DMA_API_DEBUG is not set +# CONFIG_ATOMIC64_SELFTEST is not set +# CONFIG_SAMPLES is not set +CONFIG_HAVE_ARCH_KGDB=y +# CONFIG_TEST_KSTRTOX is not set +# CONFIG_STRICT_DEVMEM is not set +# CONFIG_ARM_UNWIND is not set +# CONFIG_DEBUG_USER is not set +# CONFIG_OC_ETM is not set +CONFIG_DEBUG_S3C_UART=2 + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY_DMESG_RESTRICT is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITYFS is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_DEFAULT_SECURITY="" +CONFIG_CRYPTO=y + +# +# Crypto core or helper +# +CONFIG_CRYPTO_ALGAPI=y +CONFIG_CRYPTO_ALGAPI2=y +CONFIG_CRYPTO_AEAD=y +CONFIG_CRYPTO_AEAD2=y +CONFIG_CRYPTO_BLKCIPHER=y +CONFIG_CRYPTO_BLKCIPHER2=y +CONFIG_CRYPTO_HASH=y +CONFIG_CRYPTO_HASH2=y +CONFIG_CRYPTO_RNG=y +CONFIG_CRYPTO_RNG2=y +CONFIG_CRYPTO_PCOMP2=y +CONFIG_CRYPTO_MANAGER=y +CONFIG_CRYPTO_MANAGER2=y +CONFIG_CRYPTO_MANAGER_DISABLE_TESTS=y +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_NULL is not set +CONFIG_CRYPTO_WORKQUEUE=y +# CONFIG_CRYPTO_CRYPTD is not set +CONFIG_CRYPTO_AUTHENC=y +# CONFIG_CRYPTO_TEST is not set + +# +# Authenticated Encryption with Associated Data +# +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_SEQIV is not set + +# +# Block modes +# +CONFIG_CRYPTO_CBC=y +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_CTS is not set +CONFIG_CRYPTO_ECB=y +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_XTS is not set + +# +# Hash modes +# +CONFIG_CRYPTO_HMAC=y +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_VMAC is not set + +# +# Digest +# +CONFIG_CRYPTO_CRC32C=y +# CONFIG_CRYPTO_GHASH is not set +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_MD5=y +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_RMD128 is not set +# CONFIG_CRYPTO_RMD160 is not set +# CONFIG_CRYPTO_RMD256 is not set +# CONFIG_CRYPTO_RMD320 is not set +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_WP512 is not set + +# +# Ciphers +# +CONFIG_CRYPTO_AES=y +# CONFIG_CRYPTO_ANUBIS is not set +CONFIG_CRYPTO_ARC4=y +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +CONFIG_CRYPTO_DES=y +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_TEA is not set +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_TWOFISH_COMMON=y + +# +# Compression +# +CONFIG_CRYPTO_DEFLATE=y +# CONFIG_CRYPTO_ZLIB is not set +# CONFIG_CRYPTO_LZO is not set + +# +# Random Number Generation +# +CONFIG_CRYPTO_ANSI_CPRNG=y +# CONFIG_CRYPTO_USER_API_HASH is not set +# CONFIG_CRYPTO_USER_API_SKCIPHER is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_S5P is not set +# CONFIG_BINARY_PRINTF is not set + +# +# Library routines +# +CONFIG_BITREVERSE=y +CONFIG_CRC_CCITT=y +CONFIG_CRC16=y +# CONFIG_CRC_T10DIF is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +CONFIG_LIBCRC32C=y +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y +CONFIG_LZO_COMPRESS=y +CONFIG_LZO_DECOMPRESS=y +# CONFIG_XZ_DEC is not set +# CONFIG_XZ_DEC_BCJ is not set +CONFIG_DECOMPRESS_GZIP=y +CONFIG_REED_SOLOMON=y +CONFIG_REED_SOLOMON_ENC8=y +CONFIG_REED_SOLOMON_DEC8=y +CONFIG_TEXTSEARCH=y +CONFIG_TEXTSEARCH_KMP=y +CONFIG_TEXTSEARCH_BM=y +CONFIG_TEXTSEARCH_FSM=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_DMA=y +CONFIG_NLATTR=y +# CONFIG_AVERAGE is not set diff --git a/build.sh b/build.sh new file mode 100755 index 00000000000..0cd1f9b4e3d --- /dev/null +++ b/build.sh @@ -0,0 +1,74 @@ +#!/bin/bash + +BOARD=crespo + +setup () +{ + if [ x = "x$ANDROID_BUILD_TOP" ] ; then + echo "Android build environment must be configured" + exit 1 + fi + . "$ANDROID_BUILD_TOP"/build/envsetup.sh + + KERNEL_DIR="$(dirname "$(readlink -f "$0")")" + BUILD_DIR="$KERNEL_DIR/build" + # add modules which should be copied after build below + MODULES=("") + + if [ x = "x$NO_CCACHE" ] && ccache -V &>/dev/null ; then + CCACHE=ccache + CCACHE_BASEDIR="$KERNEL_DIR" + CCACHE_COMPRESS=1 + CCACHE_DIR="$BUILD_DIR/.ccache" + export CCACHE_DIR CCACHE_COMPRESS CCACHE_BASEDIR + else + CCACHE="" + fi + + CROSS_PREFIX="$ANDROID_BUILD_TOP/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-" +} + +build () +{ + local target=$1 + echo "Building for $target" + local target_dir="$BUILD_DIR/$target" + local module + [ x = "x$NO_RM" ] && rm -fr "$target_dir" + mkdir -p "$target_dir" + [ x = "x$NO_DEFCONFIG" ] && mka -C "$KERNEL_DIR" O="$target_dir" ARCH=arm ${BOARD}_defconfig HOSTCC="$CCACHE gcc" + if [ x = "x$NO_BUILD" ] ; then + mka -C "$KERNEL_DIR" O="$target_dir" ARCH=arm HOSTCC="$CCACHE gcc" CROSS_COMPILE="$CCACHE $CROSS_PREFIX" modules + mka -C "$KERNEL_DIR" O="$target_dir" ARCH=arm HOSTCC="$CCACHE gcc" CROSS_COMPILE="$CCACHE $CROSS_PREFIX" zImage + cp "$target_dir"/arch/arm/boot/zImage $ANDROID_BUILD_TOP/device/samsung/${BOARD}/kernel + for module in "${MODULES[@]}" ; do + cp "$target_dir/$module" $ANDROID_BUILD_TOP/device/samsung/${BOARD} + done + fi +} + +setup + +if [ "$1" = clean ] ; then + rm -fr "$BUILD_DIR"/* + exit 0 +fi + +targets=("$@") +if [ 0 = "${#targets[@]}" ] ; then + targets=(crespo) +fi + +START=$(date +%s) + +for target in "${targets[@]}" ; do + build $target +done + +END=$(date +%s) +ELAPSED=$((END - START)) +E_MIN=$((ELAPSED / 60)) +E_SEC=$((ELAPSED - E_MIN * 60)) +printf "Elapsed: " +[ $E_MIN != 0 ] && printf "%d min(s) " $E_MIN +printf "%d sec(s)\n" $E_SEC From e3dafabf3841b8669b1ed7abeabf30b017c029c0 Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Tue, 14 Feb 2012 16:00:40 +0100 Subject: [PATCH 0897/4025] update gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9dacde0a4b2..db76b09a43f 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ modules.builtin /System.map /Module.markers /Module.symvers +/build # # git files that we don't want to ignore even it they are dot-files From 90c9c1224e3440789d09c1306a52b88560b95ab4 Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Wed, 15 Feb 2012 13:39:59 +0100 Subject: [PATCH 0898/4025] Build Script now able to create a autonum. flashable kernel --- .gitignore | 3 + bin/META-INF/CERT.RSA | Bin 0 -> 1714 bytes bin/META-INF/CERT.SF | 1734 +++++++++++++++++ bin/META-INF/MANIFEST.MF | 1733 ++++++++++++++++ bin/META-INF/com/google/android/update-binary | Bin 0 -> 194596 bytes .../com/google/android/updater-script | 20 + bin/kernel/dump_image | Bin 0 -> 64012 bytes bin/kernel/mkbootimg | Bin 0 -> 59832 bytes bin/kernel/mkbootimg.sh | 8 + bin/kernel/unpackbootimg | Bin 0 -> 54696 bytes build.sh | 81 +- 11 files changed, 3572 insertions(+), 7 deletions(-) create mode 100644 bin/META-INF/CERT.RSA create mode 100644 bin/META-INF/CERT.SF create mode 100644 bin/META-INF/MANIFEST.MF create mode 100755 bin/META-INF/com/google/android/update-binary create mode 100644 bin/META-INF/com/google/android/updater-script create mode 100755 bin/kernel/dump_image create mode 100755 bin/kernel/mkbootimg create mode 100644 bin/kernel/mkbootimg.sh create mode 100755 bin/kernel/unpackbootimg diff --git a/.gitignore b/.gitignore index db76b09a43f..cf8e39dbcf3 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,9 @@ modules.builtin /Module.markers /Module.symvers /build +/bin/kernel.cyano.*.zip +/bin/kernel/zImage +/bin/kernel/system/modules # # git files that we don't want to ignore even it they are dot-files diff --git a/bin/META-INF/CERT.RSA b/bin/META-INF/CERT.RSA new file mode 100644 index 0000000000000000000000000000000000000000..72740fd6e6447768d73d1a4f40963ab6b3530342 GIT binary patch literal 1714 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

|Op$sg6ZA9Y&&;4ARlY#HsNZFe5lu~7eD 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 N{^(I_T~9r^{{a);no$4% literal 0 HcmV?d00001 diff --git a/bin/META-INF/com/google/android/updater-script b/bin/META-INF/com/google/android/updater-script new file mode 100644 index 00000000000..2ea65d1bf66 --- /dev/null +++ b/bin/META-INF/com/google/android/updater-script @@ -0,0 +1,20 @@ +ui_print("CyanogenMOD Team and Koush kernel instalation presents NEW Kernel."); +ui_print("CyanogenMOD & Teamhackung provided build auto tool (c) 2012"); +ui_print("Extracting System Files..."); +set_progress(1.000000); +mount("ext4", "EMMC", "/dev/block/platform/s3c-sdhci.0/by-name/system", "/system"); +package_extract_dir("system", "/system"); +set_perm(0, 0, 06755, "/system/xbin/su"); +unmount("/system"); +ui_print("Extracting Kernel files..."); +package_extract_dir("kernel", "/tmp"); +ui_print("Installing kernel..."); +set_perm(0, 0, 0777, "/tmp/dump_image"); +set_perm(0, 0, 0777, "/tmp/mkbootimg.sh"); +set_perm(0, 0, 0777, "/tmp/mkbootimg"); +set_perm(0, 0, 0777, "/tmp/unpackbootimg"); +run_program("/tmp/dump_image", "boot", "/tmp/boot.img"); +run_program("/tmp/unpackbootimg", "-i", "/tmp/boot.img", "-o", "/tmp/"); +run_program("/tmp/mkbootimg.sh"); +write_raw_image("/tmp/newboot.img", "boot"); +ui_print("Done!"); diff --git a/bin/kernel/dump_image b/bin/kernel/dump_image new file mode 100755 index 0000000000000000000000000000000000000000..75e6da0e866499026eb4f2cf1dfbec9e23cbc625 GIT binary patch literal 64012 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�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

)un|+N8?#~Uwykb# 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 YIoS`SSK5SBcWL}v$o*v+fT`U70jJ-hApigX literal 0 HcmV?d00001 diff --git a/bin/kernel/mkbootimg b/bin/kernel/mkbootimg new file mode 100755 index 0000000000000000000000000000000000000000..96352571f6eed04bb081646487c4cd1879693125 GIT binary patch literal 59832 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 UFL|5b?K`jh8RCw38T8`*3DI?eJpcdz literal 0 HcmV?d00001 diff --git a/bin/kernel/mkbootimg.sh b/bin/kernel/mkbootimg.sh new file mode 100644 index 00000000000..0649b08eb16 --- /dev/null +++ b/bin/kernel/mkbootimg.sh @@ -0,0 +1,8 @@ +#!/sbin/sh +echo \#!/sbin/sh > /tmp/createnewboot.sh +PAGESIZE_HEX=`cat /tmp/boot.img-pagesize` +PAGESIZE_DEC=`printf "%d" 0x$PAGESIZE_HEX` +echo /tmp/mkbootimg --kernel /tmp/zImage --ramdisk /tmp/boot.img-ramdisk.gz --cmdline \"$(cat /tmp/boot.img-cmdline)\" --base $(cat /tmp/boot.img-base) --pagesize $PAGESIZE_DEC --output /tmp/newboot.img >> /tmp/createnewboot.sh +chmod 777 /tmp/createnewboot.sh +/tmp/createnewboot.sh +return $? diff --git a/bin/kernel/unpackbootimg b/bin/kernel/unpackbootimg new file mode 100755 index 0000000000000000000000000000000000000000..9ca6a818e7fc1d6f92dee060075d11d69c7763ec GIT binary patch literal 54696 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 bnuhd-^aSAd6rrc>dLFGnyd6D(d*b~cW39Jx literal 0 HcmV?d00001 diff --git a/build.sh b/build.sh index 0cd1f9b4e3d..d2e48c0a7e8 100755 --- a/build.sh +++ b/build.sh @@ -1,6 +1,9 @@ #!/bin/bash BOARD=crespo +DEVICEDIR=/sdcard/AROM +KNAME=kernel.cyano.RELEASE +DEVICE_CM_DIR=$ANDROID_BUILD_TOP/device/samsung/${BOARD} setup () { @@ -13,7 +16,7 @@ setup () KERNEL_DIR="$(dirname "$(readlink -f "$0")")" BUILD_DIR="$KERNEL_DIR/build" # add modules which should be copied after build below - MODULES=("") + MODULES=("drivers/net/wireless/bcm4329/bcm4329.ko") if [ x = "x$NO_CCACHE" ] && ccache -V &>/dev/null ; then CCACHE=ccache @@ -28,6 +31,54 @@ setup () CROSS_PREFIX="$ANDROID_BUILD_TOP/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin/arm-eabi-" } +CheckVersion () +{ + if [ ! -f .Mayor ] + then + echo 1 > .Mayor + fi + if [ ! -f .Minor ] + then + echo 0 > .Minor + fi + sVersion=$(cat build/${BOARD}/include/config/kernel.release) + echo $sVersion + sVersionMerge=${sVersion:(-8)} + echo sVersionMerge + iMayor=$(cat .Mayor) + iMinor=$(cat .Minor) +} + +CreateKernelZip () +{ + cd bin + rm *.zip + KZIPNAME=$KNAME.v$iMayor.$iMinor.$sVersionMerge.zip + zip $KZIPNAME * -r + adb push $KZIPNAME $DEVICEDIR/$KZIPNAME + cd .. + echo $KZIPNAME +} + +UpgradeMinor () +{ + iMinor=$(($iMinor+1)) + echo $iMinor > .Minor +} + +CompileError () +{ + echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + echo ! COMPILACION FAILED + echo ! + echo ! + echo ! ---------------------- COMPILACION ERROR CODE: $RET + echo ! + echo ! + echo ! + echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +} + build () { local target=$1 @@ -38,12 +89,28 @@ build () mkdir -p "$target_dir" [ x = "x$NO_DEFCONFIG" ] && mka -C "$KERNEL_DIR" O="$target_dir" ARCH=arm ${BOARD}_defconfig HOSTCC="$CCACHE gcc" if [ x = "x$NO_BUILD" ] ; then - mka -C "$KERNEL_DIR" O="$target_dir" ARCH=arm HOSTCC="$CCACHE gcc" CROSS_COMPILE="$CCACHE $CROSS_PREFIX" modules - mka -C "$KERNEL_DIR" O="$target_dir" ARCH=arm HOSTCC="$CCACHE gcc" CROSS_COMPILE="$CCACHE $CROSS_PREFIX" zImage - cp "$target_dir"/arch/arm/boot/zImage $ANDROID_BUILD_TOP/device/samsung/${BOARD}/kernel - for module in "${MODULES[@]}" ; do - cp "$target_dir/$module" $ANDROID_BUILD_TOP/device/samsung/${BOARD} - done + C_OPTIONS="ARCH=arm HOSTCC=\""$CCACHE" gcc\" CROSS_COMPILE=\""$CCACHE $CROSS_PREFIX + mka -C "$KERNEL_DIR" O="$target_dir" ARCH=arm HOSTCC="$CCACHE gcc" CROSS_COMPILE="$CCACHE $CROSS_PREFIX" modules + RET=$? + if [[ $RET == 0 ]] ; then + mka -C "$KERNEL_DIR" O="$target_dir" ARCH=arm HOSTCC="$CCACHE gcc" CROSS_COMPILE="$CCACHE $CROSS_PREFIX" zImage + RET=$? + if [[ $RET == 0 ]] ; then + cp "$target_dir"/arch/arm/boot/zImage $DEVICE_CM_DIR/kernel + cp "$target_dir"/arch/arm/boot/zImage bin/kernel/zImage + for module in "${MODULES[@]}" ; do + cp "$target_dir/$module" $DEVICE_CM_DIR + cp "$target_dir/$module" bin/system/modules + done + CheckVersion + CreateKernelZip + UpgradeMinor + else + CompileError + fi + else + CompileError + fi fi } From 529907d16ca406a9a8ce1f9dae270fe5c198439a Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Thu, 16 Feb 2012 11:15:57 +0100 Subject: [PATCH 0899/4025] Add more overclock freq Added more freq for overclock ( 1320 taken from Steve Garon ) Changed to make easy to add/remove one feq. in code --- arch/arm/mach-s5pv210/cpufreq.c | 80 +++++++++++++++++++--------- arch/arm/mach-s5pv210/mach-herring.c | 8 +++ 2 files changed, 62 insertions(+), 26 deletions(-) diff --git a/arch/arm/mach-s5pv210/cpufreq.c b/arch/arm/mach-s5pv210/cpufreq.c index 0e5150cc53d..df38fa13398 100644 --- a/arch/arm/mach-s5pv210/cpufreq.c +++ b/arch/arm/mach-s5pv210/cpufreq.c @@ -34,7 +34,10 @@ static DEFINE_MUTEX(set_freq_lock); /* APLL M,P,S values for 1.4GHz/1.2GHz/1.0GHz/800MHz */ #define APLL_VAL_1400 ((1 << 31) | (175 << 16) | (3 << 8) | 1) +#define APLL_VAL_1320 ((1 << 31) | (330 << 16) | (6 << 8) | 1) +#define APLL_VAL_1300 ((1 << 31) | (325 << 16) | (6 << 8) | 0) #define APLL_VAL_1200 ((1 << 31) | (150 << 16) | (3 << 8) | 1) +#define APLL_VAL_1100 ((1 << 31) | (275 << 16) | (6 << 8) | 1) #define APLL_VAL_1000 ((1 << 31) | (125 << 16) | (3 << 8) | 1) #define APLL_VAL_800 ((1 << 31) | (100 << 16) | (3 << 8) | 1) @@ -64,7 +67,7 @@ struct dram_conf { static struct dram_conf s5pv210_dram_conf[2]; enum perf_level { - L0, L1, L2, L3, L4, L5, L6 + L0, L1, L2, L3, L4, L5, L6, L7, L8 }; enum s5pv210_mem_type { @@ -80,18 +83,29 @@ enum s5pv210_dmc_port { static struct cpufreq_frequency_table s5pv210_freq_table[] = { {L0, 1400*1000}, - {L1, 1200*1000}, - {L2, 1000*1000}, - {L3, 800*1000}, - {L4, 400*1000}, - {L5, 200*1000}, - {L6, 100*1000}, + {L1, 1320*1000}, + {L2, 1200*1000}, + {L3, 1100*1000}, + {L4, 1000*1000}, + {L5, 800*1000}, + {L6, 400*1000}, + {L7, 200*1000}, + {L8, 100*1000}, {0, CPUFREQ_TABLE_END}, }; +// Define the freqs affected on the code to reduce changes +// if we add or remove a new freq on the table +unsigned int L_100 = L8; +unsigned int L_1000 = L4; +unsigned int L_200 = L7; +#define SpeedSteeps 9 + static u32 sAPLL_confs[] = { APLL_VAL_1400, + APLL_VAL_1320, APLL_VAL_1200, + APLL_VAL_1100, APLL_VAL_1000, APLL_VAL_800, APLL_VAL_800, @@ -122,32 +136,40 @@ static struct s5pv210_dvs_conf dvs_conf[] = { .int_volt = 1250000, }, [L1] = { + .arm_volt = 1400000, + .int_volt = 1200000, + }, + [L2] = { .arm_volt = 1350000, .int_volt = 1150000, }, - [L2] = { + [L3] = { + .arm_volt = 1300000, + .int_volt = 1125000, + }, + [L4] = { .arm_volt = 1250000, .int_volt = 1100000, }, - [L3] = { + [L5] = { .arm_volt = 1200000, .int_volt = 1100000, }, - [L4] = { + [L6] = { .arm_volt = 1050000, .int_volt = 1100000, }, - [L5] = { + [L7] = { .arm_volt = 950000, .int_volt = 1100000, }, - [L6] = { + [L8] = { .arm_volt = 950000, .int_volt = 1000000, }, }; -static u32 clkdiv_val[7][11] = { +static u32 clkdiv_val[SpeedSteeps][11] = { /* * Clock divider value for following * { APLL, A2M, HCLK_MSYS, PCLK_MSYS, @@ -158,22 +180,28 @@ static u32 clkdiv_val[7][11] = { /* L0 : [1400/200/100][166/83][133/66][200/200] */ {0, 6, 6, 1, 3, 1, 4, 1, 3, 0, 0}, - /* L1 : [1200/200/100][166/83][133/66][200/200] */ + /* L0 : [1320/200/100][166/83][133/66][200/200] */ + {0, 5, 5, 1, 3, 1, 4, 1, 3, 0, 0}, + + /* L2 : [1200/200/100][166/83][133/66][200/200] */ {0, 5, 5, 1, 3, 1, 4, 1, 3, 0, 0}, - /* L2 : [1000/200/100][166/83][133/66][200/200] */ + /* L3 : [1100/200/100][166/83][133/66][200/200] */ + {0, 4, 4, 1, 3, 1, 4, 1, 3, 0, 0}, + + /* L4 : [1000/200/100][166/83][133/66][200/200] */ {0, 4, 4, 1, 3, 1, 4, 1, 3, 0, 0}, - /* L3 : [800/200/100][166/83][133/66][200/200] */ + /* L5 : [800/200/100][166/83][133/66][200/200] */ {0, 3, 3, 1, 3, 1, 4, 1, 3, 0, 0}, - /* L4 : [400/200/100][166/83][133/66][200/200] */ + /* L6 : [400/200/100][166/83][133/66][200/200] */ {1, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0}, - /* L5 : [200/200/100][166/83][133/66][200/200] */ + /* L7 : [200/200/100][166/83][133/66][200/200] */ {3, 3, 1, 1, 3, 1, 4, 1, 3, 0, 0}, - /* L6 : [100/100/100][83/83][66/66][100/100] */ + /* L8 : [100/100/100][83/83][66/66][100/100] */ {7, 7, 0, 0, 7, 0, 9, 0, 7, 0, 0}, }; @@ -287,11 +315,11 @@ static int s5pv210_target(struct cpufreq_policy *policy, cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); /* Check if there need to change PLL */ - if ((index <= L2) || (freqs.old >= s5pv210_freq_table[L2].frequency)) + if ((index <= L_1000) || (freqs.old >= s5pv210_freq_table[L_1000].frequency)) pll_changing = 1; /* Check if there need to change System bus clock */ - if ((index == L6) || (freqs.old == s5pv210_freq_table[L6].frequency)) + if ((index == L_100) || (freqs.old == s5pv210_freq_table[L_100].frequency)) bus_speed_changing = 1; if (bus_speed_changing) { @@ -345,7 +373,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, } while (reg & ((1 << 7) | (1 << 3))); /* - * 3. DMC1 refresh count for 133Mhz if (index == L6) is + * 3. DMC1 refresh count for 133Mhz if (index == L_100) is * true refresh counter is already programed in upper * code. 0x287@83Mhz */ @@ -390,7 +418,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, /* ARM MCS value changed */ reg = __raw_readl(S5P_ARM_MCS_CON); reg &= ~0x3; - if (index >= L5) + if (index >= L_200) reg |= 0x3; else reg |= 0x1; @@ -454,7 +482,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, /* * 10. DMC1 refresh counter - * L6 : DMC1 = 100Mhz 7.8us/(1/100) = 0x30c + * L_100 : DMC1 = 100Mhz 7.8us/(1/100) = 0x30c * Others : DMC1 = 200Mhz 7.8us/(1/200) = 0x618 */ if (!bus_speed_changing) @@ -462,7 +490,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, } /* - * L6 level need to change memory bus speed, hence onedram clock divier + * L_100 level need to change memory bus speed, hence onedram clock divier * and memory refresh parameter should be changed */ if (bus_speed_changing) { @@ -476,7 +504,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, } while (reg & (1 << 15)); /* Reconfigure DRAM refresh counter value */ - if (index != L6) { + if (index != L_100) { /* * DMC0 : 166Mhz * DMC1 : 200Mhz diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c index b12da951f4f..83edf1e1ceb 100755 --- a/arch/arm/mach-s5pv210/mach-herring.c +++ b/arch/arm/mach-s5pv210/mach-herring.c @@ -435,10 +435,18 @@ static struct s5pv210_cpufreq_voltage smdkc110_cpufreq_volt[] = { .freq = 1400000, .varm = 1450000, .vint = 1250000, + }, { + .freq = 1320000, + .varm = 1375000, + .vint = 1175000, }, { .freq = 1200000, .varm = 1350000, .vint = 1150000, + }, { + .freq = 1100000, + .varm = 1315000, + .vint = 1125000, }, { .freq = 1000000, .varm = 1275000, From 4d6f3d7209ffa828fad5d5495c1eb8c571d308ad Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Thu, 16 Feb 2012 16:27:59 -0800 Subject: [PATCH 0900/4025] cpufreq interactive governor: event tracing Change-Id: Ic13614a3da2faa2d4bd215ca3eb7191614f0cf66 Signed-off-by: Todd Poynor --- drivers/cpufreq/cpufreq_interactive.c | 19 ++++- include/trace/events/cpufreq_interactive.h | 87 ++++++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 include/trace/events/cpufreq_interactive.h diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index 45266d5b6cd..7b4efd55c89 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -28,6 +28,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + #include static atomic_t active_count = ATOMIC_INIT(0); @@ -183,7 +186,11 @@ static void cpufreq_interactive_timer(unsigned long data) new_freq = pcpu->freq_table[index].frequency; if (pcpu->target_freq == new_freq) + { + trace_cpufreq_interactive_already(data, cpu_load, + pcpu->target_freq, new_freq); goto rearm_if_notmax; + } /* * Do not scale down unless we have been at this frequency for the @@ -191,10 +198,16 @@ static void cpufreq_interactive_timer(unsigned long data) */ if (new_freq < pcpu->target_freq) { if (cputime64_sub(pcpu->timer_run_time, pcpu->freq_change_time) - < min_sample_time) + < min_sample_time) { + trace_cpufreq_interactive_notyet(data, cpu_load, + pcpu->target_freq, new_freq); goto rearm; + } } + trace_cpufreq_interactive_target(data, cpu_load, pcpu->target_freq, + new_freq); + if (new_freq < pcpu->target_freq) { pcpu->target_freq = new_freq; spin_lock_irqsave(&down_cpumask_lock, flags); @@ -382,6 +395,8 @@ static int cpufreq_interactive_up_task(void *data) pcpu->freq_change_time_in_idle = get_cpu_idle_time_us(cpu, &pcpu->freq_change_time); + trace_cpufreq_interactive_up(cpu, pcpu->target_freq, + pcpu->policy->cur); } } @@ -428,6 +443,8 @@ static void cpufreq_interactive_freq_down(struct work_struct *work) pcpu->freq_change_time_in_idle = get_cpu_idle_time_us(cpu, &pcpu->freq_change_time); + trace_cpufreq_interactive_down(cpu, pcpu->target_freq, + pcpu->policy->cur); } } diff --git a/include/trace/events/cpufreq_interactive.h b/include/trace/events/cpufreq_interactive.h new file mode 100644 index 00000000000..3a90d3d609b --- /dev/null +++ b/include/trace/events/cpufreq_interactive.h @@ -0,0 +1,87 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM cpufreq_interactive + +#if !defined(_TRACE_CPUFREQ_INTERACTIVE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_CPUFREQ_INTERACTIVE_H + +#include + +DECLARE_EVENT_CLASS(set, + TP_PROTO(u32 cpu_id, unsigned long targfreq, + unsigned long actualfreq), + TP_ARGS(cpu_id, targfreq, actualfreq), + + TP_STRUCT__entry( + __field( u32, cpu_id ) + __field(unsigned long, targfreq ) + __field(unsigned long, actualfreq ) + ), + + TP_fast_assign( + __entry->cpu_id = (u32) cpu_id; + __entry->targfreq = targfreq; + __entry->actualfreq = actualfreq; + ), + + TP_printk("cpu=%u targ=%lu actual=%lu", + __entry->cpu_id, __entry->targfreq, + __entry->actualfreq) +); + +DEFINE_EVENT(set, cpufreq_interactive_up, + TP_PROTO(u32 cpu_id, unsigned long targfreq, + unsigned long actualfreq), + TP_ARGS(cpu_id, targfreq, actualfreq) +); + +DEFINE_EVENT(set, cpufreq_interactive_down, + TP_PROTO(u32 cpu_id, unsigned long targfreq, + unsigned long actualfreq), + TP_ARGS(cpu_id, targfreq, actualfreq) +); + +DECLARE_EVENT_CLASS(loadeval, + TP_PROTO(unsigned long cpu_id, unsigned long load, + unsigned long curfreq, unsigned long targfreq), + TP_ARGS(cpu_id, load, curfreq, targfreq), + + TP_STRUCT__entry( + __field(unsigned long, cpu_id ) + __field(unsigned long, load ) + __field(unsigned long, curfreq ) + __field(unsigned long, targfreq ) + ), + + TP_fast_assign( + __entry->cpu_id = cpu_id; + __entry->load = load; + __entry->curfreq = curfreq; + __entry->targfreq = targfreq; + ), + + TP_printk("cpu=%lu load=%lu cur=%lu targ=%lu", + __entry->cpu_id, __entry->load, __entry->curfreq, + __entry->targfreq) +); + +DEFINE_EVENT(loadeval, cpufreq_interactive_target, + TP_PROTO(unsigned long cpu_id, unsigned long load, + unsigned long curfreq, unsigned long targfreq), + TP_ARGS(cpu_id, load, curfreq, targfreq) +); + +DEFINE_EVENT(loadeval, cpufreq_interactive_already, + TP_PROTO(unsigned long cpu_id, unsigned long load, + unsigned long curfreq, unsigned long targfreq), + TP_ARGS(cpu_id, load, curfreq, targfreq) +); + +DEFINE_EVENT(loadeval, cpufreq_interactive_notyet, + TP_PROTO(unsigned long cpu_id, unsigned long load, + unsigned long curfreq, unsigned long targfreq), + TP_ARGS(cpu_id, load, curfreq, targfreq) +); +#endif /* _TRACE_CPUFREQ_INTERACTIVE_H */ + +/* This part must be outside protection */ +#include From 795f18956b547f0cfbcaa6d907d2bb05726a6a3e Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Fri, 3 Feb 2012 22:31:13 +0530 Subject: [PATCH 0901/4025] perf evsel: Fix an issue where perf report fails to show the proper percentage commit a4a03fc7ef89020baca4f19174e6a43767c6d78a upstream. This patch fixes an issue where perf report shows nan% for certain perf.data files. The below is from a report for a do_fork probe: -nan% sshd [kernel.kallsyms] [k] do_fork -nan% packagekitd [kernel.kallsyms] [k] do_fork -nan% dbus-daemon [kernel.kallsyms] [k] do_fork -nan% bash [kernel.kallsyms] [k] do_fork A git bisect shows commit f3bda2c as the cause. However, looking back through the git history, I saw commit 640c03c which seems to have removed the required initialization for perf_sample->period. The problem only started showing after commit f3bda2c. The below patch re-introduces the initialization and it fixes the problem for me. With the below patch, for the same perf.data: 73.08% bash [kernel.kallsyms] [k] do_fork 8.97% 11-dhclient [kernel.kallsyms] [k] do_fork 6.41% sshd [kernel.kallsyms] [k] do_fork 3.85% 20-chrony [kernel.kallsyms] [k] do_fork 2.56% sendmail [kernel.kallsyms] [k] do_fork This patch applies over current linux-tip commit 9949284. Problem introduced in: $ git describe 640c03c v2.6.37-rc3-83-g640c03c Cc: Ananth N Mavinakayanahalli Cc: Ingo Molnar Cc: Robert Richter Cc: Srikar Dronamraju Link: http://lkml.kernel.org/r/20120203170113.5190.25558.stgit@localhost6.localdomain6 Signed-off-by: Naveen N. Rao Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/evsel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 0239eb87b23..ad2183c98ac 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -348,6 +348,7 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, data->cpu = data->pid = data->tid = -1; data->stream_id = data->id = data->time = -1ULL; + data->period = 1; if (event->header.type != PERF_RECORD_SAMPLE) { if (!sample_id_all) From f021e004b62bf213e3dfa70f747f1d3d6304fa6b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 6 Feb 2012 18:54:06 -0200 Subject: [PATCH 0902/4025] perf tools: Fix perf stack to non executable on x86_64 commit 7a0153ee15575a4d07b5da8c96b79e0b0fd41a12 upstream. By adding following objects: bench/mem-memcpy-x86-64-asm.o the x86_64 perf binary ended up with executable stack. The reason was that above object are assembler sourced and is missing the GNU-stack note section. In such case the linker assumes that the final binary should not be restricted at all and mark the stack as RWX. Adding section ".note.GNU-stack" definition to mentioned object, with all flags disabled, thus omiting this object from linker stack flags decision. Problem introduced in: $ git describe ea7872b v2.6.37-rc2-19-gea7872b Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=783570 Reported-by: Clark Williams Acked-by: Eric Dumazet Cc: Corey Ashford Cc: Ingo Molnar Cc: Paul Mackerras Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1328100848-5630-1-git-send-email-jolsa@redhat.com Signed-off-by: Jiri Olsa [ committer note: Backported fix to perf/urgent (3.3-rc2+) ] Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/bench/mem-memcpy-x86-64-asm.S | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/perf/bench/mem-memcpy-x86-64-asm.S b/tools/perf/bench/mem-memcpy-x86-64-asm.S index a57b66e853c..185a96d66dd 100644 --- a/tools/perf/bench/mem-memcpy-x86-64-asm.S +++ b/tools/perf/bench/mem-memcpy-x86-64-asm.S @@ -1,2 +1,8 @@ #include "../../../arch/x86/lib/memcpy_64.S" +/* + * We need to provide note.GNU-stack section, saying that we want + * NOT executable stack. Otherwise the final linking will assume that + * the ELF stack should not be restricted at all and set it RWX. + */ +.section .note.GNU-stack,"",@progbits From 0eac4fa19d910c7ce80e48b89eaec1f08bc816ef Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 8 Feb 2012 16:42:52 +0100 Subject: [PATCH 0903/4025] drm/i915: no lvds quirk for AOpen MP45 commit e57b6886f555ab57f40a01713304e2053efe51ec upstream. According to a bug report, it doesn't have one. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=44263 Acked-by: Chris Wilson Signed-Off-by: Daniel Vetter Signed-off-by: Keith Packard Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_lvds.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index b28f7bd9f88..21257f8232d 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -712,6 +712,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "AOpen i45GMx-I", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"), + DMI_MATCH(DMI_BOARD_NAME, "i45GMx-I"), + }, + }, { .callback = intel_no_lvds_dmi_callback, .ident = "Aopen i945GTt-VFA", From eafbec56be4c3cfd8f3b5098a0c5f7397a1e48b0 Mon Sep 17 00:00:00 2001 From: Nikolaus Schulz Date: Wed, 8 Feb 2012 18:56:10 +0100 Subject: [PATCH 0904/4025] hwmon: (f75375s) Fix bit shifting in f75375_write16 commit eb2f255b2d360df3f500042a2258dcf2fcbe89a2 upstream. In order to extract the high byte of the 16-bit word, shift the word to the right, not to the left. Signed-off-by: Nikolaus Schulz Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/f75375s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index 95cbfb3a707..dcfd9e1ff0e 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -159,7 +159,7 @@ static inline void f75375_write8(struct i2c_client *client, u8 reg, static inline void f75375_write16(struct i2c_client *client, u8 reg, u16 value) { - int err = i2c_smbus_write_byte_data(client, reg, (value << 8)); + int err = i2c_smbus_write_byte_data(client, reg, (value >> 8)); if (err) return; i2c_smbus_write_byte_data(client, reg + 1, (value & 0xFF)); From 9a3626a437ddbc0d8e60bda9480739cd850bb48f Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Mon, 9 Jan 2012 11:53:50 -0600 Subject: [PATCH 0905/4025] lib: proportion: lower PROP_MAX_SHIFT to 32 on 64-bit kernel commit 3310225dfc71a35a2cc9340c15c0e08b14b3c754 upstream. PROP_MAX_SHIFT should be set to <=32 on 64-bit box. This fixes two bugs in the below lines of bdi_dirty_limit(): bdi_dirty *= numerator; do_div(bdi_dirty, denominator); 1) divide error: do_div() only uses the lower 32 bit of the denominator, which may trimmed to be 0 when PROP_MAX_SHIFT > 32. 2) overflow: (bdi_dirty * numerator) could easily overflow if numerator used up to 48 bits, leaving only 16 bits to bdi_dirty Cc: Peter Zijlstra Reported-by: Ilya Tumaykin Tested-by: Ilya Tumaykin Signed-off-by: Wu Fengguang Signed-off-by: Greg Kroah-Hartman --- include/linux/proportions.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/proportions.h b/include/linux/proportions.h index cf793bbbd05..22653d7c3f8 100644 --- a/include/linux/proportions.h +++ b/include/linux/proportions.h @@ -81,7 +81,11 @@ void prop_inc_percpu(struct prop_descriptor *pd, struct prop_local_percpu *pl) * Limit the time part in order to ensure there are some bits left for the * cycle counter and fraction multiply. */ +#if BITS_PER_LONG == 32 #define PROP_MAX_SHIFT (3*BITS_PER_LONG/4) +#else +#define PROP_MAX_SHIFT (BITS_PER_LONG/2) +#endif #define PROP_FRAC_SHIFT (BITS_PER_LONG - PROP_MAX_SHIFT - 1) #define PROP_FRAC_BASE (1UL << PROP_FRAC_SHIFT) From 4ac2f3d3f1d4a08ad6a450127c4b0f590fe28bdf Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 10 Feb 2012 09:03:58 +0100 Subject: [PATCH 0906/4025] relay: prevent integer overflow in relay_open() commit f6302f1bcd75a042df69866d98b8d775a668f8f1 upstream. "subbuf_size" and "n_subbufs" come from the user and they need to be capped to prevent an integer overflow. Signed-off-by: Dan Carpenter Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- kernel/relay.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/kernel/relay.c b/kernel/relay.c index 859ea5a9605..2c242fb2368 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -164,10 +164,14 @@ static void *relay_alloc_buf(struct rchan_buf *buf, size_t *size) */ static struct rchan_buf *relay_create_buf(struct rchan *chan) { - struct rchan_buf *buf = kzalloc(sizeof(struct rchan_buf), GFP_KERNEL); - if (!buf) + struct rchan_buf *buf; + + if (chan->n_subbufs > UINT_MAX / sizeof(size_t *)) return NULL; + buf = kzalloc(sizeof(struct rchan_buf), GFP_KERNEL); + if (!buf) + return NULL; buf->padding = kmalloc(chan->n_subbufs * sizeof(size_t *), GFP_KERNEL); if (!buf->padding) goto free_buf; @@ -574,6 +578,8 @@ struct rchan *relay_open(const char *base_filename, if (!(subbuf_size && n_subbufs)) return NULL; + if (subbuf_size > UINT_MAX / n_subbufs) + return NULL; chan = kzalloc(sizeof(struct rchan), GFP_KERNEL); if (!chan) From 36935521cd67e3df9a1db71591cf224252d6082c Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 1 Feb 2012 18:48:09 +0200 Subject: [PATCH 0907/4025] mac80211: timeout a single frame in the rx reorder buffer commit 07ae2dfcf4f7143ce191c6436da1c33f179af0d6 upstream. The current code checks for stored_mpdu_num > 1, causing the reorder_timer to be triggered indefinitely, but the frame is never timed-out (until the next packet is received) Signed-off-by: Eliad Peller Acked-by: Johannes Berg Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 378bd67334b..41000650f4a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -610,7 +610,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; if (!tid_agg_rx->reorder_buf[index] && - tid_agg_rx->stored_mpdu_num > 1) { + tid_agg_rx->stored_mpdu_num) { /* * No buffers ready to be released, but check whether any * frames in the reorder buffer have timed out. From a5e2201319ef3c88cf8d777466c0e097625ba942 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 4 Feb 2012 20:54:03 -0600 Subject: [PATCH 0908/4025] writeback: fix dereferencing NULL bdi->dev on trace_writeback_queue commit 977b7e3a52a7421ad33a393a38ece59f3d41c2fa upstream. When a SD card is hot removed without umount, del_gendisk() will call bdi_unregister() without destroying/freeing it. This leaves the bdi in the bdi->dev = NULL, bdi->wb.task = NULL, bdi->bdi_list removed state. When sync(2) gets the bdi before bdi_unregister() and calls bdi_queue_work() after the unregister, trace_writeback_queue will be dereferencing the NULL bdi->dev. Fix it with a simple test for NULL. LKML-reference: http://lkml.org/lkml/2012/1/18/346 Reported-by: Rabin Vincent Tested-by: Namjae Jeon Signed-off-by: Wu Fengguang Signed-off-by: Greg Kroah-Hartman --- include/trace/events/writeback.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h index 4e249b927ea..9b60c6fc6df 100644 --- a/include/trace/events/writeback.h +++ b/include/trace/events/writeback.h @@ -23,7 +23,10 @@ DECLARE_EVENT_CLASS(writeback_work_class, __field(int, for_background) ), TP_fast_assign( - strncpy(__entry->name, dev_name(bdi->dev), 32); + struct device *dev = bdi->dev; + if (!dev) + dev = default_backing_dev_info.dev; + strncpy(__entry->name, dev_name(dev), 32); __entry->nr_pages = work->nr_pages; __entry->sb_dev = work->sb ? work->sb->s_dev : 0; __entry->sync_mode = work->sync_mode; From 8a6e41581a4537b53c038a328c558d455a6f3e3a Mon Sep 17 00:00:00 2001 From: David Jander Date: Wed, 8 Jun 2011 11:37:45 -0600 Subject: [PATCH 0909/4025] gpio/pca953x: Fix warning of enabled interrupts in handler commit 6dd599f8af0166805951f4421a78ba716d78321a upstream. When using nested threaded irqs, use handle_nested_irq(). This function does not call the chip handler, so no handler is set. Signed-off-by: David Jander Signed-off-by: Grant Likely Cc: Steven Rostedt Cc: Yong Zhang Cc: Manfred Gruber Cc: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/pca953x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index 0451d7ac94a..532f6900626 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -437,7 +437,7 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) do { level = __ffs(pending); - generic_handle_irq(level + chip->irq_base); + handle_nested_irq(level + chip->irq_base); pending &= ~(1 << level); } while (pending); @@ -481,8 +481,8 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq = lvl + chip->irq_base; irq_set_chip_data(irq, chip); - irq_set_chip_and_handler(irq, &pca953x_irq_chip, - handle_simple_irq); + irq_set_chip(irq, &pca953x_irq_chip); + irq_set_nested_thread(irq, true); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else From 0f74c152fd01e1070c141eb10c70cc0f6fb39e22 Mon Sep 17 00:00:00 2001 From: Nikolaus Schulz Date: Wed, 8 Feb 2012 18:56:08 +0100 Subject: [PATCH 0910/4025] hwmon: (f75375s) Fix automatic pwm mode setting for F75373 & F75375 commit 09e87e5c4f9af656af2a8a3afc03487c5d9287c3 upstream. In order to enable temperature mode aka automatic mode for the F75373 and F75375 chips, the two FANx_MODE bits in the fan configuration register need be set to 01, not 10. Signed-off-by: Nikolaus Schulz Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/f75375s.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index dcfd9e1ff0e..e4ab4918f63 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -311,7 +311,7 @@ static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val) fanmode |= (3 << FAN_CTRL_MODE(nr)); break; case 2: /* AUTOMATIC*/ - fanmode |= (2 << FAN_CTRL_MODE(nr)); + fanmode |= (1 << FAN_CTRL_MODE(nr)); break; case 3: /* fan speed */ break; From d122aed32ad780e0c337551121c36a5d5e1c2ee0 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 26 Jan 2012 15:03:16 +1100 Subject: [PATCH 0911/4025] crypto: sha512 - Use binary and instead of modulus commit 58d7d18b5268febb8b1391c6dffc8e2aaa751fcd upstream. The previous patch used the modulus operator over a power of 2 unnecessarily which may produce suboptimal binary code. This patch changes changes them to binary ands instead. Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/sha512_generic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c index 88f160b77b1..3edebfd4dbe 100644 --- a/crypto/sha512_generic.c +++ b/crypto/sha512_generic.c @@ -78,7 +78,7 @@ static inline void LOAD_OP(int I, u64 *W, const u8 *input) static inline void BLEND_OP(int I, u64 *W) { - W[I % 16] += s1(W[(I-2) % 16]) + W[(I-7) % 16] + s0(W[(I-15) % 16]); + W[I & 15] += s1(W[(I-2) & 15]) + W[(I-7) & 15] + s0(W[(I-15) & 15]); } static void @@ -105,7 +105,7 @@ sha512_transform(u64 *state, const u8 *input) #define SHA512_16_79(i, a, b, c, d, e, f, g, h) \ BLEND_OP(i, W); \ - t1 = h + e1(e) + Ch(e, f, g) + sha512_K[i] + W[(i)%16]; \ + t1 = h + e1(e) + Ch(e, f, g) + sha512_K[i] + W[(i)&15]; \ t2 = e0(a) + Maj(a, b, c); \ d += t1; \ h = t1 + t2 From c29e3ddfbd904f0b7cf600c04c4263c71c1f4830 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 5 Feb 2012 15:09:28 +1100 Subject: [PATCH 0912/4025] crypto: sha512 - Avoid stack bloat on i386 commit 3a92d687c8015860a19213e3c102cad6b722f83c upstream. Unfortunately in reducing W from 80 to 16 we ended up unrolling the loop twice. As gcc has issues dealing with 64-bit ops on i386 this means that we end up using even more stack space (>1K). This patch solves the W reduction by moving LOAD_OP/BLEND_OP into the loop itself, thus avoiding the need to duplicate it. While the stack space still isn't great (>0.5K) it is at least in the same ball park as the amount of stack used for our C sha1 implementation. Note that this patch basically reverts to the original code so the diff looks bigger than it really is. Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/sha512_generic.c | 68 +++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c index 3edebfd4dbe..f04af931a68 100644 --- a/crypto/sha512_generic.c +++ b/crypto/sha512_generic.c @@ -89,46 +89,42 @@ sha512_transform(u64 *state, const u8 *input) int i; u64 W[16]; - /* load the input */ - for (i = 0; i < 16; i++) - LOAD_OP(i, W, input); - /* load the state into our registers */ a=state[0]; b=state[1]; c=state[2]; d=state[3]; e=state[4]; f=state[5]; g=state[6]; h=state[7]; -#define SHA512_0_15(i, a, b, c, d, e, f, g, h) \ - t1 = h + e1(e) + Ch(e, f, g) + sha512_K[i] + W[i]; \ - t2 = e0(a) + Maj(a, b, c); \ - d += t1; \ - h = t1 + t2 - -#define SHA512_16_79(i, a, b, c, d, e, f, g, h) \ - BLEND_OP(i, W); \ - t1 = h + e1(e) + Ch(e, f, g) + sha512_K[i] + W[(i)&15]; \ - t2 = e0(a) + Maj(a, b, c); \ - d += t1; \ - h = t1 + t2 - - for (i = 0; i < 16; i += 8) { - SHA512_0_15(i, a, b, c, d, e, f, g, h); - SHA512_0_15(i + 1, h, a, b, c, d, e, f, g); - SHA512_0_15(i + 2, g, h, a, b, c, d, e, f); - SHA512_0_15(i + 3, f, g, h, a, b, c, d, e); - SHA512_0_15(i + 4, e, f, g, h, a, b, c, d); - SHA512_0_15(i + 5, d, e, f, g, h, a, b, c); - SHA512_0_15(i + 6, c, d, e, f, g, h, a, b); - SHA512_0_15(i + 7, b, c, d, e, f, g, h, a); - } - for (i = 16; i < 80; i += 8) { - SHA512_16_79(i, a, b, c, d, e, f, g, h); - SHA512_16_79(i + 1, h, a, b, c, d, e, f, g); - SHA512_16_79(i + 2, g, h, a, b, c, d, e, f); - SHA512_16_79(i + 3, f, g, h, a, b, c, d, e); - SHA512_16_79(i + 4, e, f, g, h, a, b, c, d); - SHA512_16_79(i + 5, d, e, f, g, h, a, b, c); - SHA512_16_79(i + 6, c, d, e, f, g, h, a, b); - SHA512_16_79(i + 7, b, c, d, e, f, g, h, a); + /* now iterate */ + for (i=0; i<80; i+=8) { + if (!(i & 8)) { + int j; + + if (i < 16) { + /* load the input */ + for (j = 0; j < 16; j++) + LOAD_OP(i + j, W, input); + } else { + for (j = 0; j < 16; j++) { + BLEND_OP(i + j, W); + } + } + } + + t1 = h + e1(e) + Ch(e,f,g) + sha512_K[i ] + W[(i & 15)]; + t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; + t1 = g + e1(d) + Ch(d,e,f) + sha512_K[i+1] + W[(i & 15) + 1]; + t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; + t1 = f + e1(c) + Ch(c,d,e) + sha512_K[i+2] + W[(i & 15) + 2]; + t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; + t1 = e + e1(b) + Ch(b,c,d) + sha512_K[i+3] + W[(i & 15) + 3]; + t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; + t1 = d + e1(a) + Ch(a,b,c) + sha512_K[i+4] + W[(i & 15) + 4]; + t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; + t1 = c + e1(h) + Ch(h,a,b) + sha512_K[i+5] + W[(i & 15) + 5]; + t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; + t1 = b + e1(g) + Ch(g,h,a) + sha512_K[i+6] + W[(i & 15) + 6]; + t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; + t1 = a + e1(f) + Ch(f,g,h) + sha512_K[i+7] + W[(i & 15) + 7]; + t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; } state[0] += a; state[1] += b; state[2] += c; state[3] += d; From c17b9573c236874b9a8a6c4c03c02accf70c9cd5 Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Mon, 13 Feb 2012 23:44:22 -0500 Subject: [PATCH 0913/4025] ALSA: intel8x0: Fix default inaudible sound on Gateway M520 commit 27c3afe6e1cf129faac90405121203962da08ff4 upstream. BugLink: https://bugs.launchpad.net/bugs/930842 The reporter states that audio is inaudible by default without muting 'External Amplifier'. Add a quirk to handle his SSID so that changing the control is not necessary. Reported-and-tested-by: Benjamin Carlson Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/intel8x0.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 6c896dbfd79..2e799a9a494 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2074,6 +2074,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .name = "MSI P4 ATX 645 Ultra", .type = AC97_TUNE_HP_ONLY }, + { + .subvendor = 0x161f, + .subdevice = 0x202f, + .name = "Gateway M520", + .type = AC97_TUNE_INV_EAPD + }, { .subvendor = 0x161f, .subdevice = 0x203a, From d3a6a79cfe7641d797ab74eea55b93e0f35f66d7 Mon Sep 17 00:00:00 2001 From: Stefano Stabellini Date: Mon, 30 Jan 2012 14:31:46 +0000 Subject: [PATCH 0914/4025] xen pvhvm: do not remap pirqs onto evtchns if !xen_have_vector_callback commit 207d543f472c1ac9552df79838dc807cbcaa9740 upstream. Signed-off-by: Stefano Stabellini Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Greg Kroah-Hartman --- arch/x86/pci/xen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index f567965c062..6e96e65e7ca 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -308,7 +308,7 @@ int __init pci_xen_init(void) int __init pci_xen_hvm_init(void) { - if (!xen_feature(XENFEAT_hvm_pirqs)) + if (!xen_have_vector_callback || !xen_feature(XENFEAT_hvm_pirqs)) return 0; #ifdef CONFIG_ACPI From 16c7560fcca939095d099da4316f2df66aebc3ba Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 13 Dec 2011 04:57:06 +0100 Subject: [PATCH 0915/4025] slub: fix a possible memleak in __slab_alloc() commit 73736e0387ba0e6d2b703407b4d26168d31516a7 upstream. Zhihua Che reported a possible memleak in slub allocator on CONFIG_PREEMPT=y builds. It is possible current thread migrates right before disabling irqs in __slab_alloc(). We must check again c->freelist, and perform a normal allocation instead of scratching c->freelist. Many thanks to Zhihua Che for spotting this bug, introduced in 2.6.39 V2: Its also possible an IRQ freed one (or several) object(s) and populated c->freelist, so its not a CONFIG_PREEMPT only problem. Reported-by: Zhihua Che Signed-off-by: Eric Dumazet Acked-by: Christoph Lameter Signed-off-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- mm/slub.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mm/slub.c b/mm/slub.c index 35f351f2619..0d0901ebaea 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1818,6 +1818,11 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, if (unlikely(!node_match(c, node))) goto another_slab; + /* must check again c->freelist in case of cpu migration or IRQ */ + object = c->freelist; + if (object) + goto update_freelist; + stat(s, ALLOC_REFILL); load_freelist: @@ -1827,6 +1832,7 @@ static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, if (kmem_cache_debug(s)) goto debug; +update_freelist: c->freelist = get_freepointer(s, object); page->inuse = page->objects; page->freelist = NULL; From 7b5644ec051e133d59249b7f19d2d8fef9a8d323 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 14 Jan 2012 21:44:49 +0300 Subject: [PATCH 0916/4025] crypto: sha512 - use standard ror64() commit f2ea0f5f04c97b48c88edccba52b0682fbe45087 upstream. Use standard ror64() instead of hand-written. There is no standard ror64, so create it. The difference is shift value being "unsigned int" instead of uint64_t (for which there is no reason). gcc starts to emit native ROR instructions which it doesn't do for some reason currently. This should make the code faster. Patch survives in-tree crypto test and ping flood with hmac(sha512) on. Signed-off-by: Alexey Dobriyan Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/sha512_generic.c | 13 ++++--------- include/linux/bitops.h | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/crypto/sha512_generic.c b/crypto/sha512_generic.c index f04af931a68..107f6f7be5e 100644 --- a/crypto/sha512_generic.c +++ b/crypto/sha512_generic.c @@ -31,11 +31,6 @@ static inline u64 Maj(u64 x, u64 y, u64 z) return (x & y) | (z & (x | y)); } -static inline u64 RORu64(u64 x, u64 y) -{ - return (x >> y) | (x << (64 - y)); -} - static const u64 sha512_K[80] = { 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, @@ -66,10 +61,10 @@ static const u64 sha512_K[80] = { 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL, }; -#define e0(x) (RORu64(x,28) ^ RORu64(x,34) ^ RORu64(x,39)) -#define e1(x) (RORu64(x,14) ^ RORu64(x,18) ^ RORu64(x,41)) -#define s0(x) (RORu64(x, 1) ^ RORu64(x, 8) ^ (x >> 7)) -#define s1(x) (RORu64(x,19) ^ RORu64(x,61) ^ (x >> 6)) +#define e0(x) (ror64(x,28) ^ ror64(x,34) ^ ror64(x,39)) +#define e1(x) (ror64(x,14) ^ ror64(x,18) ^ ror64(x,41)) +#define s0(x) (ror64(x, 1) ^ ror64(x, 8) ^ (x >> 7)) +#define s1(x) (ror64(x,19) ^ ror64(x,61) ^ (x >> 6)) static inline void LOAD_OP(int I, u64 *W, const u8 *input) { diff --git a/include/linux/bitops.h b/include/linux/bitops.h index a3ef66a2a08..fc8a3ffce32 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -49,6 +49,26 @@ static inline unsigned long hweight_long(unsigned long w) return sizeof(w) == 4 ? hweight32(w) : hweight64(w); } +/** + * rol64 - rotate a 64-bit value left + * @word: value to rotate + * @shift: bits to roll + */ +static inline __u64 rol64(__u64 word, unsigned int shift) +{ + return (word << shift) | (word >> (64 - shift)); +} + +/** + * ror64 - rotate a 64-bit value right + * @word: value to rotate + * @shift: bits to roll + */ +static inline __u64 ror64(__u64 word, unsigned int shift) +{ + return (word >> shift) | (word << (64 - shift)); +} + /** * rol32 - rotate a 32-bit value left * @word: value to rotate From a4a663513af05a98d6085d92f85c16bb64ac4050 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 20 Feb 2012 13:43:19 -0800 Subject: [PATCH 0917/4025] Linux 3.0.22 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d5f0598c253..a5b22532ef7 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 21 +SUBLEVEL = 22 EXTRAVERSION = NAME = Sneaky Weasel From 7af73db401730ad084a96eb6838f2f1ffe7975e7 Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Thu, 23 Feb 2012 05:52:41 +0100 Subject: [PATCH 0918/4025] Update BuildScript --- build.sh | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index d2e48c0a7e8..b0cc4790f6e 100755 --- a/build.sh +++ b/build.sh @@ -5,6 +5,19 @@ DEVICEDIR=/sdcard/AROM KNAME=kernel.cyano.RELEASE DEVICE_CM_DIR=$ANDROID_BUILD_TOP/device/samsung/${BOARD} +WaitForDevice() +{ + adb start-server + if [ $(adb get-state) != device -a $(adb shell busybox test -e /sbin/recovery 2> /dev/null; echo $?) != 0 ] ; then + echo "No device is online. Waiting for one..." + echo "Please connect USB and/or enable USB debugging" + until [ $(adb get-state) = device -o $(adb shell busybox test -e /sbin/recovery 2> /dev/null; echo $?) = 0 ];do + sleep 1 + done + echo "Device Found.." + fi +} + setup () { if [ x = "x$ANDROID_BUILD_TOP" ] ; then @@ -55,7 +68,30 @@ CreateKernelZip () rm *.zip KZIPNAME=$KNAME.v$iMayor.$iMinor.$sVersionMerge.zip zip $KZIPNAME * -r - adb push $KZIPNAME $DEVICEDIR/$KZIPNAME + WaitForDevice + echo Going into fastboot + if adb reboot-bootloader ; then + sleep 4 + echo Pushing kernel file + if fastboot flash zimage kernel/zImage ; then + sleep 1 + fastboot reboot + WaitForDevice + sleep 2 + adb root + sleep 4 + adb remount + sleep 2 + echo Sending modules + for filename in system/modules/* ; do + echo Sending $filename to /system/modules + if adb push $filename /system/modules ; then + echo "Rebooting again" + adb reboot + fi + done + fi + fi cd .. echo $KZIPNAME } @@ -89,7 +125,6 @@ build () mkdir -p "$target_dir" [ x = "x$NO_DEFCONFIG" ] && mka -C "$KERNEL_DIR" O="$target_dir" ARCH=arm ${BOARD}_defconfig HOSTCC="$CCACHE gcc" if [ x = "x$NO_BUILD" ] ; then - C_OPTIONS="ARCH=arm HOSTCC=\""$CCACHE" gcc\" CROSS_COMPILE=\""$CCACHE $CROSS_PREFIX mka -C "$KERNEL_DIR" O="$target_dir" ARCH=arm HOSTCC="$CCACHE gcc" CROSS_COMPILE="$CCACHE $CROSS_PREFIX" modules RET=$? if [[ $RET == 0 ]] ; then From b0293800181f91f5930075ccfc2ef7938cce1f8e Mon Sep 17 00:00:00 2001 From: Thomas Ryu Date: Tue, 13 Dec 2011 15:59:29 +0900 Subject: [PATCH 0919/4025] power: enable USB VBUS of cp and WiMAX Enable the VBUS of CP and WiMAX for debugging purpose. This change has no effect on the current implementation until USB path of CP or WiMAX is changed by the user. Signed-off-by: Thomas Ryu --- drivers/power/s5pc110_battery.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/power/s5pc110_battery.c b/drivers/power/s5pc110_battery.c index 6cb3e9092ea..ad106f7b372 100755 --- a/drivers/power/s5pc110_battery.c +++ b/drivers/power/s5pc110_battery.c @@ -469,7 +469,8 @@ static int max8998_charging_control(struct chg_data *chg) } ret = max8998_write_reg(i2c, MAX8998_REG_CHGR2, - (2 << MAX8998_SHIFT_ESAFEOUT) | + /* Enable USB VBUS of CP or WiMAX */ + (3 << MAX8998_SHIFT_ESAFEOUT) | (2 << MAX8998_SHIFT_FT) | (0 << MAX8998_SHIFT_CHGEN)); if (ret < 0) From bfebf726b0e0fd4a26096f9d7ddea8603aeaeac8 Mon Sep 17 00:00:00 2001 From: "Mike J. Chen" Date: Wed, 15 Feb 2012 21:54:57 -0800 Subject: [PATCH 0920/4025] net: wireless: bcmdhd: Fix driver hang when resetting bus->tx_max was not being initialized when we do a reset and the driver is statically linked. this led to about a 50% chance that it would be considered an illegal value when we send the mac address to the FW. add code to initialize it to a safe value until we receive the right value from the fw. Bug: 5974574 Change-Id: I28ab25d97203ef075e5354c25f85a25daaff5594 Signed-off-by: Mike J. Chen Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_sdio.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index d7823167cca..53eff583c38 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -3061,6 +3061,13 @@ dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) bus->rxskip = FALSE; bus->tx_seq = bus->rx_seq = 0; + /* Set to a safe default. It gets updated when we + * receive a packet from the fw but when we reset, + * we need a safe default to be able to send the + * initial mac address. + */ + bus->tx_max = 4; + if (enforce_mutex) dhd_os_sdunlock(bus->dhd); } From d93cdf396dfed7a7fc6d7c31b59538bf52378251 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Thu, 23 Feb 2012 10:36:40 -0800 Subject: [PATCH 0921/4025] net: wireless: bcmdhd: Turn interface down (only) in case of FW crash Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_linux.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 233c8912830..0c34e79bf2c 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -4390,17 +4390,23 @@ int net_os_send_hang_message(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); int ret = 0; + int need_unlock = 0; if (dhd) { if (!dhd->pub.hang_was_sent) { dhd->pub.hang_was_sent = 1; + if (!rtnl_is_locked()) { + need_unlock = 1; + rtnl_lock(); + } + dev_close(dev); + if (need_unlock) + rtnl_unlock(); #if defined(CONFIG_WIRELESS_EXT) ret = wl_iw_send_priv_event(dev, "HANG"); #endif #if defined(WL_CFG80211) ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); - dev_close(dev); - dev_open(dev); #endif } } From 0ef231500f50a3f9a9d8e282833b9cfc69d5173a Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Sat, 25 Feb 2012 01:55:36 +0100 Subject: [PATCH 0922/4025] Update build script Now ask if you want to send the kernel to the device --- build.sh | 53 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/build.sh b/build.sh index b0cc4790f6e..e3612d19bc7 100755 --- a/build.sh +++ b/build.sh @@ -68,28 +68,30 @@ CreateKernelZip () rm *.zip KZIPNAME=$KNAME.v$iMayor.$iMinor.$sVersionMerge.zip zip $KZIPNAME * -r - WaitForDevice - echo Going into fastboot - if adb reboot-bootloader ; then - sleep 4 - echo Pushing kernel file - if fastboot flash zimage kernel/zImage ; then - sleep 1 - fastboot reboot - WaitForDevice - sleep 2 - adb root + if [ "$responseSend" == "y" ] ; then + WaitForDevice + echo Going into fastboot + if adb reboot-bootloader ; then sleep 4 - adb remount - sleep 2 - echo Sending modules - for filename in system/modules/* ; do - echo Sending $filename to /system/modules - if adb push $filename /system/modules ; then - echo "Rebooting again" - adb reboot - fi - done + echo Pushing kernel file + if fastboot flash zimage kernel/zImage ; then + sleep 1 + fastboot reboot + WaitForDevice + sleep 2 + adb root + sleep 4 + adb remount + sleep 2 + echo Sending modules + for filename in system/modules/* ; do + echo Sending $filename to /system/modules + if adb push $filename /system/modules ; then + echo "Rebooting again" + adb reboot + fi + done + fi fi fi cd .. @@ -151,6 +153,15 @@ build () setup +echo Type y + \"intro\" to send kernel to your mobile: +read -t 10 responseSend; +if [ "$responseSend" == "y" ] ; then + echo Sending to device after build .. $responseSend +else + echo Only compile .. $responseSend +fi + + if [ "$1" = clean ] ; then rm -fr "$BUILD_DIR"/* exit 0 From eb46023aeeaa14f5cd1d04919eed564a8637b831 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 27 Feb 2012 11:17:04 -0800 Subject: [PATCH 0923/4025] mmc: sdhci: Allow mmc_suspend_host/mmc_resume_host for sdio devices Signed-off-by: Dmitry Shmidt --- drivers/mmc/host/sdhci.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 7baca39ce2a..46042f70656 100755 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2317,7 +2317,6 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state) { int ret = 0; - struct mmc_host *mmc = host->mmc; sdhci_disable_card_detection(host); @@ -2329,8 +2328,7 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state) host->tuning_count * HZ); } - if (mmc->card && (mmc->card->type != MMC_TYPE_SDIO)) - ret = mmc_suspend_host(host->mmc); + ret = mmc_suspend_host(host->mmc); sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); @@ -2350,7 +2348,6 @@ EXPORT_SYMBOL_GPL(sdhci_suspend_host); int sdhci_resume_host(struct sdhci_host *host) { int ret = 0; - struct mmc_host *mmc = host->mmc; if (host->vmmc) { int ret = regulator_enable(host->vmmc); @@ -2370,8 +2367,7 @@ int sdhci_resume_host(struct sdhci_host *host) sdhci_init(host, (host->mmc->pm_flags & MMC_PM_KEEP_POWER)); mmiowb(); - if (mmc->card && (mmc->card->type != MMC_TYPE_SDIO)) - ret = mmc_resume_host(host->mmc); + ret = mmc_resume_host(host->mmc); sdhci_enable_card_detection(host); From a31bec6d8f53e02a5ec8e5ae066b57ffb577ae6e Mon Sep 17 00:00:00 2001 From: Simon Wilson Date: Thu, 2 Feb 2012 16:43:05 -0800 Subject: [PATCH 0924/4025] ARM: s5pv210: herring: don't disable prox sensor during suspend A previous change caused the proximity sensor to become disabled during suspend to reduce power consumption , but this needs to remain on if activated. Change-Id: I74920c10b89c4dacd9688dc8db689fb097d64087 Signed-off-by: Simon Wilson --- arch/arm/mach-s5pv210/mach-herring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c index be33104846f..29d77ddb73a 100755 --- a/arch/arm/mach-s5pv210/mach-herring.c +++ b/arch/arm/mach-s5pv210/mach-herring.c @@ -4904,7 +4904,7 @@ static unsigned int herring_cdma_wimax_sleep_gpio_table[][3] = { { S5PV210_GPJ1(1), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, { S5PV210_GPJ1(2), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, { S5PV210_GPJ1(3), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, - { S5PV210_GPJ1(4), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, + { S5PV210_GPJ1(4), S3C_GPIO_SLP_PREV, S3C_GPIO_PULL_NONE}, { S5PV210_GPJ1(5), S3C_GPIO_SLP_OUT0, S3C_GPIO_PULL_NONE}, { S5PV210_GPJ2(0), S3C_GPIO_SLP_INPUT, S3C_GPIO_PULL_DOWN}, From 254c20edd7eeda7b0acc379cc30c0ecccce39a66 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 10 Aug 2011 19:00:33 -0600 Subject: [PATCH 0925/4025] cfg80211: fix a crash in nl80211_send_station mac80211 leaves sinfo->assoc_req_ies uninitialized, causing a random pointer memory access in nl80211_send_station. Instead of checking if the pointer is null, use sinfo->filled, like the rest of the fields. Signed-off-by: Felix Fietkau Signed-off-by: John W. Linville --- include/net/cfg80211.h | 4 +++- net/wireless/nl80211.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index e95d3acaff0..d048ed59647 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -426,6 +426,7 @@ struct station_parameters { * @STATION_INFO_RX_BITRATE: @rxrate fields are filled * @STATION_INFO_BSS_PARAM: @bss_param filled * @STATION_INFO_CONNECTED_TIME: @connected_time filled + * @STATION_INFO_ASSOC_REQ_IES: @assoc_req_ies filled */ enum station_info_flags { STATION_INFO_INACTIVE_TIME = 1<<0, @@ -444,7 +445,8 @@ enum station_info_flags { STATION_INFO_SIGNAL_AVG = 1<<13, STATION_INFO_RX_BITRATE = 1<<14, STATION_INFO_BSS_PARAM = 1<<15, - STATION_INFO_CONNECTED_TIME = 1<<16 + STATION_INFO_CONNECTED_TIME = 1<<16, + STATION_INFO_ASSOC_REQ_IES = 1<<17 }; /** diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 33115be4936..9d714f5213d 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2209,7 +2209,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, } nla_nest_end(msg, sinfoattr); - if (sinfo->assoc_req_ies) + if (sinfo->filled & STATION_INFO_ASSOC_REQ_IES) NLA_PUT(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len, sinfo->assoc_req_ies); From 1282ad1837801103f42b4a7b8de4f231907bd4ef Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 27 Feb 2012 12:35:15 -0800 Subject: [PATCH 0926/4025] net: wireless: bcmdhd: Update to Version 5.90.195.28 - Improve scan for p2p - Use use_rxchain support - Use WL_WIRELESS_EXT instead of CONFIG_WIRELESS_EXT - Initial sched_scan support Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/Makefile | 2 +- drivers/net/wireless/bcmdhd/aiutils.c | 2 +- drivers/net/wireless/bcmdhd/bcmsdh.c | 2 +- drivers/net/wireless/bcmdhd/bcmsdh_linux.c | 18 +- drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c | 204 ++++-- .../net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c | 6 +- drivers/net/wireless/bcmdhd/dhd_cfg80211.c | 2 +- drivers/net/wireless/bcmdhd/dhd_linux.c | 76 +-- drivers/net/wireless/bcmdhd/dhd_sdio.c | 2 +- .../wireless/bcmdhd/include/bcmsdh_sdmmc.h | 9 +- drivers/net/wireless/bcmdhd/include/epivers.h | 8 +- .../net/wireless/bcmdhd/include/linuxver.h | 7 +- drivers/net/wireless/bcmdhd/include/sbchipc.h | 5 +- drivers/net/wireless/bcmdhd/include/wlioctl.h | 4 +- drivers/net/wireless/bcmdhd/wl_android.c | 6 +- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 599 ++++++++++++++---- drivers/net/wireless/bcmdhd/wl_cfg80211.h | 4 + drivers/net/wireless/bcmdhd/wl_iw.c | 3 - 18 files changed, 695 insertions(+), 264 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index 17f07ca3a30..9828de6fad9 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -19,7 +19,7 @@ obj-$(CONFIG_BCMDHD) += bcmdhd.o bcmdhd-objs += $(DHDOFILES) ifneq ($(CONFIG_WIRELESS_EXT),) bcmdhd-objs += wl_iw.o -DHDCFLAGS += -DSOFTAP +DHDCFLAGS += -DSOFTAP -DWL_WIRELESS_EXT endif ifneq ($(CONFIG_CFG80211),) bcmdhd-objs += wl_cfg80211.o wl_cfgp2p.o wl_linux_mon.o diff --git a/drivers/net/wireless/bcmdhd/aiutils.c b/drivers/net/wireless/bcmdhd/aiutils.c index 059df890792..5ca0993c933 100644 --- a/drivers/net/wireless/bcmdhd/aiutils.c +++ b/drivers/net/wireless/bcmdhd/aiutils.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: aiutils.c,v 1.26.2.1 2010-03-09 18:41:21 Exp $ + * $Id: aiutils.c,v 1.26.2.1 2010-03-09 18:41:21 $ */ diff --git a/drivers/net/wireless/bcmdhd/bcmsdh.c b/drivers/net/wireless/bcmdhd/bcmsdh.c index 918c8e648f1..f67b13a03a1 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh.c 275784 2011-08-04 22:41:49Z $ + * $Id: bcmsdh.c 300445 2011-12-03 05:37:20Z $ */ /** diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c index e01b6f8a2d4..d257ddab84a 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_linux.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_linux.c 308641 2012-01-17 02:18:02Z $ + * $Id: bcmsdh_linux.c 312788 2012-02-03 23:06:32Z $ */ /** @@ -620,13 +620,6 @@ int bcmsdh_register_oob_intr(void * dhdp) return 0; } -void *bcmsdh_get_drvdata(void) -{ - if (!sdhcinfo) - return NULL; - return dev_get_drvdata(sdhcinfo->dev); -} - void bcmsdh_set_irq(int flag) { if (sdhcinfo->oob_irq_registered && sdhcinfo->oob_irq_enable_flag != flag) { @@ -654,6 +647,15 @@ void bcmsdh_unregister_oob_intr(void) } #endif /* defined(OOB_INTR_ONLY) */ +#if defined(BCMLXSDMMC) +void *bcmsdh_get_drvdata(void) +{ + if (!sdhcinfo) + return NULL; + return dev_get_drvdata(sdhcinfo->dev); +} +#endif + /* Module parameters specific to each host-controller driver */ extern uint sd_msglevel; /* Debug message level */ diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c index 6a8ff9431e9..b88e57a5203 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_sdmmc.c 301794 2011-12-08 20:41:35Z $ + * $Id: bcmsdh_sdmmc.c 314904 2012-02-14 21:36:04Z $ */ #include @@ -35,6 +35,7 @@ #include /* ioctl/iovars */ #include +#include #include #include @@ -148,6 +149,7 @@ sdioh_attach(osl_t *osh, void *bar0, uint irq) sd->sd_blockmode = TRUE; sd->use_client_ints = TRUE; sd->client_block_size[0] = 64; + sd->use_rxchain = FALSE; gInstance->sd = sd; @@ -512,7 +514,7 @@ sdioh_iovar_op(sdioh_info_t *si, const char *name, } case IOV_GVAL(IOV_RXCHAIN): - int_val = FALSE; + int_val = (int32)si->use_rxchain; bcopy(&int_val, arg, val_size); break; @@ -902,8 +904,12 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, bool fifo = (fix_inc == SDIOH_DATA_FIX); uint32 SGCount = 0; int err_ret = 0; - - void *pnext; + void *pnext, *pprev; + uint ttl_len, dma_len, lft_len, xfred_len, pkt_len; + uint blk_num; + struct mmc_request mmc_req; + struct mmc_command mmc_cmd; + struct mmc_data mmc_dat; sd_trace(("%s: Enter\n", __FUNCTION__)); @@ -911,66 +917,148 @@ sdioh_request_packet(sdioh_info_t *sd, uint fix_inc, uint write, uint func, DHD_PM_RESUME_WAIT(sdioh_request_packet_wait); DHD_PM_RESUME_RETURN_ERROR(SDIOH_API_RC_FAIL); - /* Claim host controller */ - sdio_claim_host(gInstance->func[func]); - for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { - uint pkt_len = PKTLEN(sd->osh, pnext); - pkt_len += 3; - pkt_len &= 0xFFFFFFFC; + ttl_len = xfred_len = 0; + /* at least 4 bytes alignment of skb buff is guaranteed */ + for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) + ttl_len += PKTLEN(sd->osh, pnext); -#ifdef CONFIG_MMC_MSM7X00A - if ((pkt_len % 64) == 32) { - sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__)); - pkt_len += 32; - } -#endif /* CONFIG_MMC_MSM7X00A */ - /* Make sure the packet is aligned properly. If it isn't, then this - * is the fault of sdioh_request_buffer() which is supposed to give - * us something we can work with. - */ - ASSERT(((uint32)(PKTDATA(sd->osh, pkt)) & DMA_ALIGN_MASK) == 0); - - if ((write) && (!fifo)) { - err_ret = sdio_memcpy_toio(gInstance->func[func], addr, - ((uint8*)PKTDATA(sd->osh, pnext)), - pkt_len); - } else if (write) { - err_ret = sdio_memcpy_toio(gInstance->func[func], addr, - ((uint8*)PKTDATA(sd->osh, pnext)), - pkt_len); - } else if (fifo) { - err_ret = sdio_readsb(gInstance->func[func], - ((uint8*)PKTDATA(sd->osh, pnext)), - addr, - pkt_len); - } else { - err_ret = sdio_memcpy_fromio(gInstance->func[func], - ((uint8*)PKTDATA(sd->osh, pnext)), - addr, + if (!sd->use_rxchain || ttl_len <= sd->client_block_size[func]) { + blk_num = 0; + dma_len = 0; + } else { + blk_num = ttl_len / sd->client_block_size[func]; + dma_len = blk_num * sd->client_block_size[func]; + } + lft_len = ttl_len - dma_len; + + sd_trace(("%s: %s %dB to func%d:%08x, %d blks with DMA, %dB leftover\n", + __FUNCTION__, write ? "W" : "R", + ttl_len, func, addr, blk_num, lft_len)); + + if (0 != dma_len) { + memset(&mmc_req, 0, sizeof(struct mmc_request)); + memset(&mmc_cmd, 0, sizeof(struct mmc_command)); + memset(&mmc_dat, 0, sizeof(struct mmc_data)); + + /* Set up DMA descriptors */ + pprev = pkt; + for (pnext = pkt; + pnext && dma_len; + pnext = PKTNEXT(sd->osh, pnext)) { + pkt_len = PKTLEN(sd->osh, pnext); + + if (dma_len > pkt_len) + dma_len -= pkt_len; + else { + pkt_len = xfred_len = dma_len; + dma_len = 0; + pkt = pnext; + } + + sg_set_buf(&sd->sg_list[SGCount++], + (uint8*)PKTDATA(sd->osh, pnext), pkt_len); - } - if (err_ret) { - sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=0x%08x\n", - __FUNCTION__, - (write) ? "TX" : "RX", - pnext, SGCount, addr, pkt_len, err_ret)); - } else { - sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n", - __FUNCTION__, - (write) ? "TX" : "RX", - pnext, SGCount, addr, pkt_len)); + if (SGCount >= SDIOH_SDMMC_MAX_SG_ENTRIES) { + sd_err(("%s: sg list entries exceed limit\n", + __FUNCTION__)); + return (SDIOH_API_RC_FAIL); + } } - if (!fifo) { - addr += pkt_len; - } - SGCount ++; + mmc_dat.sg = sd->sg_list; + mmc_dat.sg_len = SGCount; + mmc_dat.blksz = sd->client_block_size[func]; + mmc_dat.blocks = blk_num; + mmc_dat.flags = write ? MMC_DATA_WRITE : MMC_DATA_READ; + mmc_cmd.opcode = 53; /* SD_IO_RW_EXTENDED */ + mmc_cmd.arg = write ? 1<<31 : 0; + mmc_cmd.arg |= (func & 0x7) << 28; + mmc_cmd.arg |= 1<<27; + mmc_cmd.arg |= fifo ? 0 : 1<<26; + mmc_cmd.arg |= (addr & 0x1FFFF) << 9; + mmc_cmd.arg |= blk_num & 0x1FF; + mmc_cmd.flags = MMC_RSP_SPI_R5 | MMC_RSP_R5 | MMC_CMD_ADTC; + + mmc_req.cmd = &mmc_cmd; + mmc_req.data = &mmc_dat; + + sdio_claim_host(gInstance->func[func]); + mmc_set_data_timeout(&mmc_dat, gInstance->func[func]->card); + mmc_wait_for_req(gInstance->func[func]->card->host, &mmc_req); + sdio_release_host(gInstance->func[func]); + + err_ret = mmc_cmd.error? mmc_cmd.error : mmc_dat.error; + if (0 != err_ret) { + sd_err(("%s:CMD53 %s failed with code %d\n", + __FUNCTION__, + write ? "write" : "read", + err_ret)); + sd_err(("%s:Disabling rxchain and fire it with PIO\n", + __FUNCTION__)); + sd->use_rxchain = FALSE; + pkt = pprev; + lft_len = ttl_len; + } else if (!fifo) { + addr = addr + ttl_len - lft_len - dma_len; + } } - /* Release host controller */ - sdio_release_host(gInstance->func[func]); + /* PIO mode */ + if (0 != lft_len) { + /* Claim host controller */ + sdio_claim_host(gInstance->func[func]); + for (pnext = pkt; pnext; pnext = PKTNEXT(sd->osh, pnext)) { + uint8 *buf = (uint8*)PKTDATA(sd->osh, pnext) + + xfred_len; + pkt_len = PKTLEN(sd->osh, pnext); + if (0 != xfred_len) { + pkt_len -= xfred_len; + xfred_len = 0; + } + pkt_len = (pkt_len + 3) & 0xFFFFFFFC; +#ifdef CONFIG_MMC_MSM7X00A + if ((pkt_len % 64) == 32) { + sd_trace(("%s: Rounding up TX packet +=32\n", __FUNCTION__)); + pkt_len += 32; + } +#endif /* CONFIG_MMC_MSM7X00A */ + + if ((write) && (!fifo)) + err_ret = sdio_memcpy_toio( + gInstance->func[func], + addr, buf, pkt_len); + else if (write) + err_ret = sdio_memcpy_toio( + gInstance->func[func], + addr, buf, pkt_len); + else if (fifo) + err_ret = sdio_readsb( + gInstance->func[func], + buf, addr, pkt_len); + else + err_ret = sdio_memcpy_fromio( + gInstance->func[func], + buf, addr, pkt_len); + + if (err_ret) + sd_err(("%s: %s FAILED %p[%d], addr=0x%05x, pkt_len=%d, ERR=%d\n", + __FUNCTION__, + (write) ? "TX" : "RX", + pnext, SGCount, addr, pkt_len, err_ret)); + else + sd_trace(("%s: %s xfr'd %p[%d], addr=0x%05x, len=%d\n", + __FUNCTION__, + (write) ? "TX" : "RX", + pnext, SGCount, addr, pkt_len)); + + if (!fifo) + addr += pkt_len; + SGCount ++; + } + sdio_release_host(gInstance->func[func]); + } sd_trace(("%s: Exit\n", __FUNCTION__)); return ((err_ret == 0) ? SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL); @@ -1232,8 +1320,10 @@ sdioh_start(sdioh_info_t *si, int stage) 2.6.27. The implementation prior to that is buggy, and needs broadcom's patch for it */ - if ((ret = sdio_reset_comm(gInstance->func[0]->card))) + if ((ret = sdio_reset_comm(gInstance->func[0]->card))) { sd_err(("%s Failed, error = %d\n", __FUNCTION__, ret)); + return ret; + } else { sd->num_funcs = 2; sd->sd_blockmode = TRUE; diff --git a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c index 83f4d3df671..f296dd382b5 100644 --- a/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c +++ b/drivers/net/wireless/bcmdhd/bcmsdh_sdmmc_linux.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_sdmmc_linux.c 308645 2012-01-17 02:33:26Z $ + * $Id: bcmsdh_sdmmc_linux.c 312783 2012-02-03 22:53:56Z $ */ #include @@ -98,7 +98,6 @@ PBCMSDH_SDMMC_INSTANCE gInstance; extern int bcmsdh_probe(struct device *dev); extern int bcmsdh_remove(struct device *dev); - extern volatile bool dhd_mmc_suspend; static int bcmsdh_sdmmc_probe(struct sdio_func *func, @@ -194,8 +193,9 @@ static int bcmsdh_sdmmc_suspend(struct device *pdev) static int bcmsdh_sdmmc_resume(struct device *pdev) { +#if defined(OOB_INTR_ONLY) struct sdio_func *func = dev_to_sdio_func(pdev); - +#endif sd_trace(("%s Enter\n", __FUNCTION__)); dhd_mmc_suspend = FALSE; #if defined(OOB_INTR_ONLY) diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c index 800590cca65..917b09b35a3 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c @@ -467,7 +467,6 @@ void wl_cfg80211_btcoex_deinit(struct wl_priv *wl) kfree(wl->btcoex_info); wl->btcoex_info = NULL; } -#endif int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) { @@ -591,3 +590,4 @@ int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) return (strlen("OK")); } +#endif diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 0c34e79bf2c..597d12560c1 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c 308879 2012-01-17 22:03:47Z $ + * $Id: dhd_linux.c 314746 2012-02-14 03:45:02Z $ */ #include @@ -149,10 +149,10 @@ print_tainted() #endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ /* Linux wireless extension support */ -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) #include extern wl_iw_extra_params_t g_wl_iw_params; -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ #if defined(CONFIG_HAS_EARLYSUSPEND) #include @@ -212,9 +212,9 @@ static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; /* Local private structure (extension of pub) */ typedef struct dhd_info { -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) wl_iw_t iw; /* wireless extensions state (must be first) */ -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ dhd_pub_t pub; @@ -359,12 +359,6 @@ uint dhd_radio_up = 1; char iface_name[IFNAMSIZ] = {'\0'}; module_param_string(iface_name, iface_name, IFNAMSIZ, 0); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define BLOCKABLE() (!in_atomic()) -#else -#define BLOCKABLE() (!in_interrupt()) -#endif - /* The following are specific to the SDIO dongle */ /* IOCTL response timeout */ @@ -451,9 +445,9 @@ int dhd_monitor_init(void *dhd_pub); int dhd_monitor_uninit(void); -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ static void dhd_dpc(ulong data); /* forward decl */ @@ -2053,7 +2047,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) return -1; } -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) /* linux wireless extensions */ if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { /* may recurse, do NOT lock */ @@ -2061,7 +2055,7 @@ dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) DHD_OS_WAKE_UNLOCK(&dhd->pub); return ret; } -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) if (cmd == SIOCETHTOOL) { @@ -2338,7 +2332,6 @@ dhd_open(struct net_device *net) } dhd->pub.hang_was_sent = 0; - #if !defined(WL_CFG80211) /* * Force start if ifconfig_up gets called before START command @@ -2672,7 +2665,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) dhd_monitor_init(&dhd->pub); dhd_state |= DHD_ATTACH_STATE_CFG80211; #endif -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) /* Attach and link in the iw */ if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) { if (wl_iw_attach(net, (void *)&dhd->pub) != 0) { @@ -2681,7 +2674,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) } dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; } -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ /* Set up the watchdog timer */ @@ -2934,6 +2927,9 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if defined(ARP_OFFLOAD_SUPPORT) int arpoe = 1; #endif +#if defined(KEEP_ALIVE) + int res; +#endif /* defined(KEEP_ALIVE) */ int scan_assoc_time = DHD_SCAN_ACTIVE_TIME; int scan_unassoc_time = 40; int scan_passive_time = DHD_SCAN_PASSIVE_TIME; @@ -2946,14 +2942,12 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ #endif - #if defined(AP) || defined(WLP2P) uint32 apsta = 1; /* Enable APSTA mode */ #endif /* defined(AP) || defined(WLP2P) */ #ifdef GET_CUSTOM_MAC_ENABLE struct ether_addr ea_addr; #endif /* GET_CUSTOM_MAC_ENABLE */ - DHD_TRACE(("Enter %s\n", __FUNCTION__)); dhd->op_mode = 0; #ifdef GET_CUSTOM_MAC_ENABLE @@ -3083,6 +3077,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) /* Setup assoc_retry_max count to reconnect target AP in dongle */ bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf)); dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + #if defined(AP) && !defined(WLP2P) /* Turn off MPC in AP mode */ bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); @@ -3098,17 +3093,13 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) #endif #if defined(KEEP_ALIVE) - { /* Set Keep Alive : be sure to use FW with -keepalive */ - int res; - #if defined(SOFTAP) if (ap_fw_loaded == FALSE) #endif if ((res = dhd_keep_alive_onoff(dhd)) < 0) DHD_ERROR(("%s set keeplive failed %d\n", __FUNCTION__, res)); - } #endif /* defined(KEEP_ALIVE) */ /* Read event_msgs mask */ @@ -3471,14 +3462,14 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) net->ethtool_ops = &dhd_ethtool_ops; #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) #if WIRELESS_EXT < 19 net->get_wireless_stats = dhd_get_wireless_stats; #endif /* WIRELESS_EXT < 19 */ #if WIRELESS_EXT > 12 net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def; #endif /* WIRELESS_EXT > 12 */ -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); @@ -3494,7 +3485,7 @@ dhd_net_attach(dhd_pub_t *dhdp, int ifidx) net->dev_addr[0], net->dev_addr[1], net->dev_addr[2], net->dev_addr[3], net->dev_addr[4], net->dev_addr[5]); -#if defined(SOFTAP) && defined(CONFIG_WIRELESS_EXT) && !defined(WL_CFG80211) +#if defined(SOFTAP) && defined(WL_WIRELESS_EXT) && !defined(WL_CFG80211) wl_iw_iscan_set_scan_broadcast_prep(net, 1); #endif @@ -3579,12 +3570,12 @@ void dhd_detach(dhd_pub_t *dhdp) } #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) { /* Detatch and unlink in the iw */ wl_iw_detach(); } -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ if (dhd->thr_sysioc_ctl.thr_pid >= 0) { PROC_STOP(&dhd->thr_sysioc_ctl); @@ -3748,20 +3739,20 @@ dhd_module_init(void) } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - /* - * Wait till MMC sdio_register_driver callback called and made driver attach. - * It's needed to make sync up exit from dhd insmod and - * Kernel MMC sdio device callback registration - */ + /* + * Wait till MMC sdio_register_driver callback called and made driver attach. + * It's needed to make sync up exit from dhd insmod and + * Kernel MMC sdio device callback registration + */ if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) { - error = -EINVAL; + error = -ENODEV; DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__)); goto fail_2; } #endif #if defined(WL_CFG80211) wl_android_post_init(); -#endif +#endif /* defined(WL_CFG80211) */ return error; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && 1 @@ -4037,7 +4028,7 @@ void dhd_os_prefree(void *osh, void *addr, uint size) } #endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) struct iw_statistics * dhd_get_wireless_stats(struct net_device *dev) { @@ -4055,7 +4046,7 @@ dhd_get_wireless_stats(struct net_device *dev) else return NULL; } -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, @@ -4068,7 +4059,7 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, if (bcmerror != BCME_OK) return (bcmerror); -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) if (event->bsscfgidx == 0) { /* * Wireless ext is on primary interface only @@ -4081,7 +4072,7 @@ dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, wl_iw_event(dhd->iflist[*ifidx]->net, event, *data); } } -#endif /* defined(CONFIG_WIRELESS_EXT) */ +#endif /* defined(WL_WIRELESS_EXT) */ #ifdef WL_CFG80211 if ((ntoh32(event->event_type) == WLC_E_IF) && @@ -4386,6 +4377,8 @@ dhd_dev_get_pno_status(struct net_device *dev) #endif /* PNO_SUPPORT */ +struct work_struct work; + int net_os_send_hang_message(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); @@ -4402,7 +4395,7 @@ int net_os_send_hang_message(struct net_device *dev) dev_close(dev); if (need_unlock) rtnl_unlock(); -#if defined(CONFIG_WIRELESS_EXT) +#if defined(WL_WIRELESS_EXT) ret = wl_iw_send_priv_event(dev, "HANG"); #endif #if defined(WL_CFG80211) @@ -4421,7 +4414,6 @@ void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); } - void dhd_net_if_lock(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 53eff583c38..282a7179540 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_sdio.c 309234 2012-01-19 01:44:16Z $ + * $Id: dhd_sdio.c 314732 2012-02-14 03:22:42Z $ */ #include diff --git a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h index bea97b610a8..db8ea596304 100644 --- a/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h +++ b/drivers/net/wireless/bcmdhd/include/bcmsdh_sdmmc.h @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: bcmsdh_sdmmc.h 277737 2011-08-16 17:54:59Z $ + * $Id: bcmsdh_sdmmc.h 314048 2012-02-09 20:31:56Z $ */ #ifndef __BCMSDH_SDMMC_H__ @@ -82,9 +82,10 @@ struct sdioh_info { uint8 num_funcs; /* Supported funcs on client */ uint32 com_cis_ptr; uint32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; - uint max_dma_len; - uint max_dma_descriptors; /* DMA Descriptors supported by this controller. */ -// SDDMA_DESCRIPTOR SGList[32]; /* Scatter/Gather DMA List */ + +#define SDIOH_SDMMC_MAX_SG_ENTRIES 32 + struct scatterlist sg_list[SDIOH_SDMMC_MAX_SG_ENTRIES]; + bool use_rxchain; }; /************************************************************ diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index 53dd2f73673..0e720456f58 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -33,17 +33,17 @@ #define EPI_RC_NUMBER 195 -#define EPI_INCREMENTAL_NUMBER 23 +#define EPI_INCREMENTAL_NUMBER 28 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 5, 90, 195, 23 +#define EPI_VERSION 5, 90, 195, 28 -#define EPI_VERSION_NUM 0x055ac317 +#define EPI_VERSION_NUM 0x055ac31c #define EPI_VERSION_DEV 5.90.195 -#define EPI_VERSION_STR "5.90.195.23" +#define EPI_VERSION_STR "5.90.195.28" #endif diff --git a/drivers/net/wireless/bcmdhd/include/linuxver.h b/drivers/net/wireless/bcmdhd/include/linuxver.h index d269e66f7fb..54d88ee923b 100644 --- a/drivers/net/wireless/bcmdhd/include/linuxver.h +++ b/drivers/net/wireless/bcmdhd/include/linuxver.h @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: linuxver.h 280266 2011-08-28 04:18:20Z $ + * $Id: linuxver.h 312264 2012-02-02 00:49:43Z $ */ @@ -524,6 +524,11 @@ typedef struct { } while (0); #endif /* LINUX_VERSION_CODE */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) +#define BLOCKABLE() (!in_atomic()) +#else +#define BLOCKABLE() (!in_interrupt()) +#endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) #define KILL_PROC(nr, sig) \ diff --git a/drivers/net/wireless/bcmdhd/include/sbchipc.h b/drivers/net/wireless/bcmdhd/include/sbchipc.h index 3fe2a5a49d3..8f757509b95 100644 --- a/drivers/net/wireless/bcmdhd/include/sbchipc.h +++ b/drivers/net/wireless/bcmdhd/include/sbchipc.h @@ -5,7 +5,7 @@ * JTAG, 0/1/2 UARTs, clock frequency control, a watchdog interrupt timer, * GPIO interface, extbus, and support for serial and parallel flashes. * - * $Id: sbchipc.h 277737 2011-08-16 17:54:59Z $ + * $Id: sbchipc.h 311371 2012-01-28 05:47:25Z $ * * Copyright (C) 1999-2011, Broadcom Corporation * @@ -1659,6 +1659,9 @@ typedef volatile struct { #define CCTRL_4330_JTAG_DISABLE 0x00000008 +#define CCTRL_43239_GPIO_SEL 0x00000002 +#define CCTRL_43239_SDIO_HOST_WAKE 0x00000004 + #define RES4313_BB_PU_RSRC 0 #define RES4313_ILP_REQ_RSRC 1 #define RES4313_XTAL_PU_RSRC 2 diff --git a/drivers/net/wireless/bcmdhd/include/wlioctl.h b/drivers/net/wireless/bcmdhd/include/wlioctl.h index e31bfa94c00..91274a0c680 100644 --- a/drivers/net/wireless/bcmdhd/include/wlioctl.h +++ b/drivers/net/wireless/bcmdhd/include/wlioctl.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: wlioctl.h 307468 2012-01-11 18:29:27Z $ + * $Id: wlioctl.h 312596 2012-02-03 02:53:30Z $ */ @@ -1213,7 +1213,7 @@ typedef struct { #define WL_AUTH_OPEN_SYSTEM 0 #define WL_AUTH_SHARED_KEY 1 -#define WL_AUTH_OPEN_SHARED 3 +#define WL_AUTH_OPEN_SHARED 2 #define WL_RADIO_SW_DISABLE (1<<0) diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index 2cbe333b0dd..8f6b1988180 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -223,7 +223,7 @@ static int wl_android_get_band(struct net_device *dev, char *command, int total_ return bytes_written; } -#ifdef PNO_SUPPORT +#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN) static int wl_android_set_pno_setup(struct net_device *dev, char *command, int total_len) { wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; @@ -329,7 +329,7 @@ static int wl_android_set_pno_setup(struct net_device *dev, char *command, int t exit_proc: return res; } -#endif /* PNO_SUPPORT */ +#endif /* PNO_SUPPORT && !WL_SCHED_SCAN */ static int wl_android_get_p2p_dev_addr(struct net_device *ndev, char *command, int total_len) { @@ -516,7 +516,7 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) char *country_code = command + strlen(CMD_COUNTRY) + 1; bytes_written = wldev_set_country(net, country_code); } -#ifdef PNO_SUPPORT +#if defined(PNO_SUPPORT) && !defined(WL_SCHED_SCAN) else if (strnicmp(command, CMD_PNOSSIDCLR_SET, strlen(CMD_PNOSSIDCLR_SET)) == 0) { bytes_written = dhd_dev_pno_reset(net); } diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index 125888d028f..c910fc59407 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -202,7 +202,8 @@ static s32 wl_cfg80211_del_pmksa(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_pmksa *pmksa); static s32 wl_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *dev); -static void wl_notify_escan_complete(struct wl_priv *wl, struct net_device *ndev, bool aborted); +static s32 wl_notify_escan_complete(struct wl_priv *wl, + struct net_device *ndev, bool aborted, bool fw_abort); /* * event & event Q handlers for cfg80211 interfaces */ @@ -236,8 +237,15 @@ static s32 wl_bss_roaming_done(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); static s32 wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); +#ifdef WL_SCHED_SCAN +static s32 +wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data); +#endif /* WL_SCHED_SCAN */ +#ifdef PNO_SUPPORT static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data); +#endif /* PNO_SUPPORT */ /* * register/deregister parent device */ @@ -516,11 +524,11 @@ static struct ieee80211_supported_band __wl_band_2ghz = { * doesn't match with the IE present in the 3/4 EAPOL msg. */ .ht_cap = { - IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU, - .ht_supported = TRUE, - .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, - .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16 + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU, + .ht_supported = TRUE, + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16 } #endif }; @@ -530,7 +538,22 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = { .channels = __wl_5ghz_a_channels, .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), .bitrates = wl_a_rates, - .n_bitrates = wl_a_rates_size + .n_bitrates = wl_a_rates_size, +#if ENABLE_P2P_INTERFACE + /* wpa_supplicant sets wmm_enabled based on whether ht_cap + * is present or not. The wmm_enabled is inturn used to + * set the replay counters in the RSN IE. Without this + * the 4way handshake will fail complaining that IE in beacon + * doesn't match with the IE present in the 3/4 EAPOL msg. + */ + .ht_cap = { + IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU, + .ht_supported = TRUE, + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16 + } +#endif }; static const u32 __wl_cipher_suites[] = { @@ -918,8 +941,8 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) if (wl->p2p_supported) { memcpy(p2p_mac.octet, wl->p2p->int_addr.octet, ETHER_ADDR_LEN); if (wl->p2p->vif_created) { - if (wl_get_drv_status(wl, SCANNING, dev)) { - wl_cfg80211_scan_abort(wl, dev); + if (wl->scan_request) { + wl_notify_escan_complete(wl, dev, true, true); } wldev_iovar_setint(dev, "mpc", 1); wl_set_p2p_status(wl, IF_DELETING); @@ -1088,7 +1111,7 @@ wl_cfg80211_notify_ifdel(struct net_device *ndev) rollback_lock = true; } WL_DBG(("ESCAN COMPLETED\n")); - wl_notify_escan_complete(wl, ndev, true); + wl_notify_escan_complete(wl, ndev, true, false); if (rollback_lock) rtnl_unlock(); } @@ -1508,7 +1531,7 @@ __wl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, wpa_ie_fixed_t *wps_ie; s32 passive_scan; bool iscan_req; - bool escan_req; + bool escan_req = false; bool p2p_ssid; s32 err = 0; s32 i; @@ -1907,21 +1930,21 @@ wl_set_auth_type(struct net_device *dev, struct cfg80211_connect_params *sme) s32 bssidx = wl_cfgp2p_find_idx(wl, dev); switch (sme->auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: - val = 0; + val = WL_AUTH_OPEN_SYSTEM; WL_DBG(("open system\n")); break; case NL80211_AUTHTYPE_SHARED_KEY: - val = 1; + val = WL_AUTH_SHARED_KEY; WL_DBG(("shared key\n")); break; case NL80211_AUTHTYPE_AUTOMATIC: - val = 2; + val = WL_AUTH_OPEN_SHARED; WL_DBG(("automatic\n")); break; case NL80211_AUTHTYPE_NETWORK_EAP: WL_DBG(("network eap\n")); default: - val = 2; + val = WL_AUTH_OPEN_SHARED; WL_ERR(("invalid auth type (%d)\n", sme->auth_type)); break; } @@ -2119,9 +2142,9 @@ wl_set_set_sharedkey(struct net_device *dev, WL_ERR(("WLC_SET_KEY error (%d)\n", err)); return err; } - if (sec->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) { + if (sec->auth_type == NL80211_AUTHTYPE_SHARED_KEY) { WL_DBG(("set auth_type to shared key\n")); - val = 1; /* shared key */ + val = WL_AUTH_SHARED_KEY; /* shared key */ err = wldev_iovar_setint_bsscfg(dev, "auth", val, bssidx); if (unlikely(err)) { WL_ERR(("set auth failed (%d)\n", err)); @@ -2160,7 +2183,7 @@ wl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, * Cancel ongoing scan to sync up with sme state machine of cfg80211. */ if (wl->scan_request) { - wl_cfg80211_scan_abort(wl, dev); + wl_notify_escan_complete(wl, dev, true, true); } /* Clean BSSID */ bzero(&bssid, sizeof(bssid)); @@ -2382,7 +2405,7 @@ wl_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, * Cancel ongoing scan to sync up with sme state machine of cfg80211. */ if (wl->scan_request) { - wl_cfg80211_scan_abort(wl, dev); + wl_notify_escan_complete(wl, dev, true, true); } wl_set_drv_status(wl, DISCONNECTING, dev); scbval.val = reason_code; @@ -2581,9 +2604,6 @@ wl_add_keyext(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; } swap_key_from_BE(&key); -#if defined(CONFIG_WIRELESS_EXT) - dhd_wait_pend8021x(dev); -#endif wldev_iovar_setbuf_bsscfg(dev, "wsec_key", &key, sizeof(key), wl->ioctl_buf, WLC_IOCTL_MAXLEN, bssidx, &wl->ioctl_buf_sync); if (unlikely(err)) { @@ -2831,42 +2851,42 @@ wl_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, sta->idle * 1000)); #endif } else if (wl_get_mode_by_netdev(wl, dev) == WL_MODE_BSS) { - u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID); - if (!wl_get_drv_status(wl, CONNECTED, dev) || - (dhd_is_associated(dhd, NULL) == FALSE)) { - WL_ERR(("NOT assoc\n")); - err = -ENODEV; - goto get_station_err; - } - if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { - WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n", - MAC2STR(mac), MAC2STR(curmacp))); - } + u8 *curmacp = wl_read_prof(wl, dev, WL_PROF_BSSID); + if (!wl_get_drv_status(wl, CONNECTED, dev) || + (dhd_is_associated(dhd, NULL) == FALSE)) { - /* Report the current tx rate */ - err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false); - if (err) { - WL_ERR(("Could not get rate (%d)\n", err)); - } else { - rate = dtoh32(rate); - sinfo->filled |= STATION_INFO_TX_BITRATE; - sinfo->txrate.legacy = rate * 5; - WL_DBG(("Rate %d Mbps\n", (rate / 2))); - } + WL_ERR(("NOT assoc\n")); + err = -ENODEV; + goto get_station_err; + } + if (memcmp(mac, curmacp, ETHER_ADDR_LEN)) { + WL_ERR(("Wrong Mac address: "MACSTR" != "MACSTR"\n", + MAC2STR(mac), MAC2STR(curmacp))); + } - memset(&scb_val, 0, sizeof(scb_val)); - scb_val.val = 0; - err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, - sizeof(scb_val_t), false); - if (err) { - WL_ERR(("Could not get rssi (%d)\n", err)); - goto get_station_err; - } + /* Report the current tx rate */ + err = wldev_ioctl(dev, WLC_GET_RATE, &rate, sizeof(rate), false); + if (err) { + WL_ERR(("Could not get rate (%d)\n", err)); + } else { + rate = dtoh32(rate); + sinfo->filled |= STATION_INFO_TX_BITRATE; + sinfo->txrate.legacy = rate * 5; + WL_DBG(("Rate %d Mbps\n", (rate / 2))); + } - rssi = dtoh32(scb_val.val); - sinfo->filled |= STATION_INFO_SIGNAL; - sinfo->signal = rssi; - WL_DBG(("RSSI %d dBm\n", rssi)); + memset(&scb_val, 0, sizeof(scb_val)); + scb_val.val = 0; + err = wldev_ioctl(dev, WLC_GET_RSSI, &scb_val, + sizeof(scb_val_t), false); + if (err) { + WL_ERR(("Could not get rssi (%d)\n", err)); + goto get_station_err; + } + rssi = dtoh32(scb_val.val); + sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->signal = rssi; + WL_DBG(("RSSI %d dBm\n", rssi)); get_station_err: if (err) { @@ -3009,8 +3029,8 @@ wl_update_pmklist(struct net_device *dev, struct wl_pmk_list *pmk_list, return -EINVAL; } /* pmk list is supported only for STA interface i.e. primary interface - * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init - */ + * Refer code wlc_bsscfg.c->wlc_bsscfg_sta_init + */ if (primary_dev != dev) { WL_INFO(("Not supporting Flushing pmklist on virtual" " interfaces than primary interface\n")); @@ -3173,8 +3193,21 @@ wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev) s32 params_size = 0; s32 err = BCME_OK; unsigned long flags; + struct net_device *dev; WL_DBG(("Enter\n")); + if (wl->scan_request) { + if (wl->scan_request->dev == wl->p2p_net) + dev = wl_to_prmry_ndev(wl); + else + dev = wl->scan_request->dev; + } + else { + WL_ERR(("wl->scan_request is NULL did we already do scan_abort?" + "Now scan_abort for ndev %p primary %p p2p_net %p", + ndev, wl_to_prmry_ndev(wl), wl->p2p_net)); + dev = ndev; + } /* Our scan params only need space for 1 channel and 0 ssids */ params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); @@ -3183,18 +3216,26 @@ wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev) err = -ENOMEM; } else { /* Do a scan abort to stop the driver's scan engine */ - err = wldev_ioctl(ndev, WLC_SCAN, params, params_size, true); + err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); if (err < 0) { WL_ERR(("scan abort failed \n")); } } del_timer_sync(&wl->scan_timeout); spin_lock_irqsave(&wl->cfgdrv_lock, flags); + +#ifdef WL_SCHED_SCAN + if (wl->sched_scan_req && !wl->scan_request) { + cfg80211_sched_scan_stopped(wl_to_wiphy(wl)); + wl->sched_scan_req = NULL; + } +#endif /* WL_SCHED_SCAN */ + if (wl->scan_request) { cfg80211_scan_done(wl->scan_request, true); wl->scan_request = NULL; } - wl_clr_drv_status(wl, SCANNING, ndev); + wl_clr_drv_status(wl, SCANNING, dev); spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); if (params) kfree(params); @@ -3222,10 +3263,9 @@ wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, ndev = dev; } - if (wl_get_drv_status(wl, SCANNING, ndev)) { - wl_cfg80211_scan_abort(wl, ndev); + if (wl->scan_request) { + wl_notify_escan_complete(wl, ndev, true, true); } - target_channel = ieee80211_frequency_to_channel(channel->center_freq); memcpy(&wl->remain_on_chan, channel, sizeof(struct ieee80211_channel)); wl->remain_on_chan_type = channel_type; @@ -3288,7 +3328,7 @@ wl_cfg80211_send_pending_tx_act_frm(struct wl_priv *wl) */ wl_clr_drv_status(wl, SENDING_ACT_FRM, wl->afx_hdl->dev); wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); - wl_cfg80211_scan_abort(wl, dev); + wl_notify_escan_complete(wl, dev, true, true); wl_cfgp2p_discover_enable_search(wl, false); tx_act_frm->channel = wl->afx_hdl->peer_chan; wl->afx_hdl->ack_recv = (wl_cfgp2p_tx_action_frame(wl, dev, @@ -3442,8 +3482,8 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, scb_val.val = mgmt->u.disassoc.reason_code; wldev_ioctl(dev, WLC_SCB_DEAUTHENTICATE_FOR_REASON, &scb_val, sizeof(scb_val_t), true); - WL_DBG(("Disconnect STA : %s\n", - bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf))); + WL_DBG(("Disconnect STA : %s scb_val.val %d\n", + bcm_ether_ntoa((const struct ether_addr *)mgmt->da, eabuf), scb_val.val)); cfg80211_mgmt_tx_status(ndev, *cookie, buf, len, true, GFP_KERNEL); goto exit; @@ -3455,7 +3495,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, * tx is still in progress (including the dwell time), * then this new action frame will not be sent out. */ - wl_cfg80211_scan_abort(wl, dev); + wl_notify_escan_complete(wl, dev, true, true); } @@ -3490,6 +3530,7 @@ wl_cfg80211_mgmt_tx(struct wiphy *wiphy, struct net_device *ndev, ieee80211_frequency_to_channel(channel->center_freq); if (channel->band == IEEE80211_BAND_5GHZ) { + WL_DBG(("5GHz channel %d", af_params->channel)); err = wldev_ioctl(dev, WLC_SET_CHANNEL, &af_params->channel, sizeof(af_params->channel), true); if (err < 0) { @@ -3653,7 +3694,7 @@ wl_validate_wpa2ie(struct net_device *dev, bcm_tlv_t *wpa2ie, s32 bssidx) { s32 len = 0; s32 err = BCME_OK; - u16 auth = 0; /* d11 open authentication */ + u16 auth = WL_AUTH_OPEN_SYSTEM; /* d11 open authentication */ u32 wsec; u32 pval = 0; u32 gval = 0; @@ -3757,7 +3798,7 @@ wl_validate_wpaie(struct net_device *dev, wpa_ie_fixed_t *wpaie, s32 bssidx) wpa_suite_mcast_t *mcast; wpa_suite_ucast_t *ucast; wpa_suite_auth_key_mgmt_t *mgmt; - u16 auth = 0; /* d11 open authentication */ + u16 auth = WL_AUTH_OPEN_SYSTEM; /* d11 open authentication */ u16 count; s32 err = BCME_OK; s32 len = 0; @@ -4080,7 +4121,7 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, memcpy(beacon_ie, wps_ie, wpsie_len); wl_cfgp2p_set_management_ie(wl, dev, bssidx, VNDR_IE_BEACON_FLAG, beacon_ie, wpsie_len); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } else { @@ -4133,12 +4174,12 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, memcmp(wl->ap_info->wps_ie, wps_ie, wpsie_len)) { WL_DBG((" WPS IE is changed\n")); kfree(wl->ap_info->wps_ie); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } else if (wl->ap_info->wps_ie == NULL) { WL_DBG((" WPS IE is added\n")); - wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); + wl->ap_info->wps_ie = kmemdup(wps_ie, wpsie_len, GFP_KERNEL); /* add WLC_E_PROBREQ_MSG event to respose probe_request from STA */ wl_add_remove_eventmsg(dev, WLC_E_PROBREQ_MSG, pbc); } @@ -4224,6 +4265,105 @@ wl_cfg80211_add_set_beacon(struct wiphy *wiphy, struct net_device *dev, return err; } +#ifdef WL_SCHED_SCAN +#define PNO_TIME 30 +#define PNO_REPEAT 4 +#define PNO_FREQ_EXPO_MAX 3 +int wl_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request *request) +{ + ushort pno_time = PNO_TIME; + int pno_repeat = PNO_REPEAT; + int pno_freq_expo_max = PNO_FREQ_EXPO_MAX; + wlc_ssid_t ssids_local[MAX_PFN_LIST_COUNT]; + struct wl_priv *wl = wiphy_priv(wiphy); + struct cfg80211_ssid *ssid = NULL; + int ssid_count = 0; + int i; + int ret = 0; + + WL_DBG(("Enter n_match_sets:%d n_ssids:%d \n", + request->n_match_sets, request->n_ssids)); + WL_DBG(("ssids:%d pno_time:%d pno_repeat:%d pno_freq:%d \n", + request->n_ssids, pno_time, pno_repeat, pno_freq_expo_max)); + + if (wl_get_drv_status_all(wl, SCANNING)) { + WL_ERR(("Scanning already\n")); + return -EAGAIN; + } + + if (!request || !request->n_ssids || !request->n_match_sets) { + WL_ERR(("Invalid sched scan req!! n_ssids:%d \n", request->n_ssids)); + return -EINVAL; + } + + memset(&ssids_local, 0, sizeof(ssids_local)); + + if (request->n_match_sets > 0) { + for (i = 0; i < request->n_match_sets; i++) { + ssid = &request->match_sets[i].ssid; + memcpy(ssids_local[i].SSID, ssid->ssid, ssid->ssid_len); + ssids_local[i].SSID_len = ssid->ssid_len; + WL_DBG((">>> PNO filter set for ssid (%s) \n", ssid->ssid)); + ssid_count++; + } + } + + if (request->n_ssids > 0) { + for (i = 0; i < request->n_ssids; i++) { + /* Active scan req for ssids */ + WL_DBG((">>> Active scan req for ssid (%s) \n", request->ssids[i].ssid)); + + /* match_set ssids is a supert set of n_ssid list, so we need + * not add these set seperately + */ + } + } + + if (ssid_count) { + if ((ret = dhd_dev_pno_set(dev, ssids_local, request->n_match_sets, + pno_time, pno_repeat, pno_freq_expo_max)) < 0) { + WL_ERR(("PNO setup failed!! ret=%d \n", ret)); + return -EINVAL; + } + + /* Enable the PNO */ + if (dhd_dev_pno_enable(dev, 1) < 0) { + WL_ERR(("PNO enable failed!! ret=%d \n", ret)); + return -EINVAL; + } + wl->sched_scan_req = request; + } else { + return -EINVAL; + } + + return 0; +} + +int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) +{ + struct wl_priv *wl = wiphy_priv(wiphy); + + WL_DBG(("Enter \n")); + + if (dhd_dev_pno_enable(dev, 0) < 0) + WL_ERR(("PNO disable failed")); + + if (dhd_dev_pno_reset(dev) < 0) + WL_ERR(("PNO reset failed")); + + if (wl->scan_request && wl->sched_scan_running) { + wl_cfg80211_scan_abort(wl, dev); + } + + wl->sched_scan_req = NULL; + wl->sched_scan_running = FALSE; + + return 0; +} +#endif /* WL_SCHED_SCAN */ + static struct cfg80211_ops wl_cfg80211_ops = { .add_virtual_intf = wl_cfg80211_add_virtual_iface, .del_virtual_intf = wl_cfg80211_del_virtual_iface, @@ -4256,6 +4396,10 @@ static struct cfg80211_ops wl_cfg80211_ops = { .set_channel = wl_cfg80211_set_channel, .set_beacon = wl_cfg80211_add_set_beacon, .add_beacon = wl_cfg80211_add_set_beacon, +#ifdef WL_SCHED_SCAN + .sched_scan_start = wl_cfg80211_sched_scan_start, + .sched_scan_stop = wl_cfg80211_sched_scan_stop, +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) */ }; s32 wl_mode_to_nl80211_iftype(s32 mode) @@ -4291,12 +4435,18 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev /* Report how many SSIDs Driver can support per Scan request */ wdev->wiphy->max_scan_ssids = WL_SCAN_PARAMS_SSID_MAX; wdev->wiphy->max_num_pmkids = WL_NUM_PMKIDS_MAX; +#ifdef WL_SCHED_SCAN + wdev->wiphy->max_sched_scan_ssids = MAX_PFN_LIST_COUNT; + wdev->wiphy->max_match_sets = MAX_PFN_LIST_COUNT; + wdev->wiphy->max_sched_scan_ie_len = WL_SCAN_IE_LEN_MAX; + wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN; +#endif /* WL_SCHED_SCAN */ wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR); wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &__wl_band_2ghz; - wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; + /* wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; - set in runtime */ wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wdev->wiphy->cipher_suites = __wl_cipher_suites; wdev->wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); @@ -4314,7 +4464,7 @@ static s32 wl_setup_wiphy(struct wireless_dev *wdev, struct device *sdiofunc_dev #endif WIPHY_FLAG_4ADDR_STATION; #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0) - wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; + wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; #endif WL_DBG(("Registering custom regulatory)\n")); wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; @@ -4469,7 +4619,7 @@ static bool wl_is_linkup(struct wl_priv *wl, const wl_event_msg_t *e, struct net u32 status = ntoh32(e->status); u16 flags = ntoh16(e->flags); - WL_DBG(("event %d, status %d\n", event, status)); + WL_DBG(("event %d, status %d flags %x\n", event, status, flags)); if (event == WLC_E_SET_SSID) { if (status == WLC_E_STATUS_SUCCESS) { if (!wl_is_ibssmode(wl, ndev)) @@ -4552,7 +4702,7 @@ wl_notify_connect_status_ap(struct wl_priv *wl, struct net_device *ndev, #if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)) && !CFG80211_STA_EVENT_AVAILABLE memset(body, 0, sizeof(body)); memset(&bssid, 0, ETHER_ADDR_LEN); - WL_DBG(("Enter \n")); + WL_DBG(("Enter event %d ndev %p\n", event, ndev)); if (wl_get_mode_by_netdev(wl, ndev) == WL_INVALID) return WL_INVALID; @@ -4646,8 +4796,8 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, if (wl_get_mode_by_netdev(wl, ndev) == WL_MODE_AP) { wl_notify_connect_status_ap(wl, ndev, e, data); } else { - WL_DBG(("wl_notify_connect_status : event %d status : %d \n", - ntoh32(e->event_type), ntoh32(e->status))); + WL_DBG(("wl_notify_connect_status : event %d status : %d ndev %p\n", + ntoh32(e->event_type), ntoh32(e->status), ndev)); if (wl_is_linkup(wl, e, ndev)) { wl_link_up(wl); act = true; @@ -4670,30 +4820,34 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, } else if (wl_is_linkdown(wl, e)) { if (wl->scan_request) { - del_timer_sync(&wl->scan_timeout); if (wl->escan_on) { - wl_notify_escan_complete(wl, ndev, true); - } else + wl_notify_escan_complete(wl, ndev, true, true); + } else { + del_timer_sync(&wl->scan_timeout); wl_iscan_aborted(wl); + } } if (wl_get_drv_status(wl, CONNECTED, ndev)) { scb_val_t scbval; u8 *curbssid = wl_read_prof(wl, ndev, WL_PROF_BSSID); printk("link down, call cfg80211_disconnected\n"); wl_clr_drv_status(wl, CONNECTED, ndev); - /* To make sure disconnect, explictly send dissassoc - * for BSSID 00:00:00:00:00:00 issue - */ - scbval.val = WLAN_REASON_DEAUTH_LEAVING; - - memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); - scbval.val = htod32(scbval.val); - wldev_ioctl(ndev, WLC_DISASSOC, &scbval, - sizeof(scb_val_t), true); - cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); - wl_link_down(wl); - wl_init_prof(wl, ndev); - } else if (wl_get_drv_status(wl, CONNECTING, ndev)) { + if (! wl_get_drv_status(wl, DISCONNECTING, ndev)) { + /* To make sure disconnect, explictly send dissassoc + * for BSSID 00:00:00:00:00:00 issue + */ + scbval.val = WLAN_REASON_DEAUTH_LEAVING; + + memcpy(&scbval.ea, curbssid, ETHER_ADDR_LEN); + scbval.val = htod32(scbval.val); + wldev_ioctl(ndev, WLC_DISASSOC, &scbval, + sizeof(scb_val_t), true); + cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); + wl_link_down(wl); + wl_init_prof(wl, ndev); + } + } + else if (wl_get_drv_status(wl, CONNECTING, ndev)) { printk("link down, during connecting\n"); wl_bss_connect_done(wl, ndev, e, data, false); } @@ -4704,11 +4858,12 @@ wl_notify_connect_status(struct wl_priv *wl, struct net_device *ndev, event, (int)ntoh32(e->status)); /* Clean up any pending scan request */ if (wl->scan_request) { - del_timer_sync(&wl->scan_timeout); if (wl->escan_on) { - wl_notify_escan_complete(wl, ndev, true); - } else + wl_notify_escan_complete(wl, ndev, true, true); + } else { + del_timer_sync(&wl->scan_timeout); wl_iscan_aborted(wl); + } } if (wl_get_drv_status(wl, CONNECTING, ndev)) wl_bss_connect_done(wl, ndev, e, data, false); @@ -4857,6 +5012,7 @@ static s32 wl_update_bss_info(struct wl_priv *wl, struct net_device *ndev) u8 *curbssid; s32 err = 0; struct wiphy *wiphy; + wiphy = wl_to_wiphy(wl); if (wl_is_ibssmode(wl, ndev)) @@ -4960,7 +5116,7 @@ wl_bss_connect_done(struct wl_priv *wl, struct net_device *ndev, WL_DBG((" enter\n")); if (wl->scan_request) { - wl_cfg80211_scan_abort(wl, ndev); + wl_notify_escan_complete(wl, ndev, true, true); } if (wl_get_drv_status(wl, CONNECTING, ndev)) { wl_clr_drv_status(wl, CONNECTING, ndev); @@ -5008,6 +5164,7 @@ wl_notify_mic_status(struct wl_priv *wl, struct net_device *ndev, return 0; } +#ifdef PNO_SUPPORT static s32 wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, const wl_event_msg_t *e, void *data) @@ -5015,11 +5172,19 @@ wl_notify_pfn_status(struct wl_priv *wl, struct net_device *ndev, WL_ERR((" PNO Event\n")); mutex_lock(&wl->usr_sync); +#ifndef WL_SCHED_SCAN /* TODO: Use cfg80211_sched_scan_results(wiphy); */ cfg80211_disconnected(ndev, 0, NULL, 0, GFP_KERNEL); +#else + /* If cfg80211 scheduled scan is supported, report the pno results via sched + * scan results + */ + wl_notify_sched_scan_results(wl, ndev, e, data); +#endif /* WL_SCHED_SCAN */ mutex_unlock(&wl->usr_sync); return 0; } +#endif /* PNO_SUPPORT */ static s32 wl_notify_scan_status(struct wl_priv *wl, struct net_device *ndev, @@ -5199,7 +5364,7 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, * After complete GO Negotiation, roll back to mpc mode */ if (act_frm && ((act_frm->subtype == P2P_PAF_GON_CONF) || - (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { + (act_frm->subtype == P2P_PAF_PROVDIS_RSP))) { wldev_iovar_setint(dev, "mpc", 1); } } else { @@ -5217,6 +5382,127 @@ wl_notify_rx_mgmt_frame(struct wl_priv *wl, struct net_device *ndev, return 0; } +#ifdef WL_SCHED_SCAN +/* If target scan is not reliable, set the below define to "0" to do a + * full escan + */ +#define FULL_ESCAN_ON_PFN_NET_FOUND 1 +static s32 +wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, + const wl_event_msg_t *e, void *data) +{ + wl_pfn_net_info_t *netinfo, *pnetinfo; + struct cfg80211_scan_request request; + struct wiphy *wiphy = wl_to_wiphy(wl); + int err = 0; + struct cfg80211_ssid ssid[MAX_PFN_LIST_COUNT]; + struct ieee80211_channel *channel = NULL; + int channel_req = 0; + int band = 0; + struct wl_pfn_scanresults *pfn_result = (struct wl_pfn_scanresults *)data; + + WL_DBG(("Enter\n")); + + if (e->event_type == WLC_E_PFN_NET_LOST) { + WL_DBG(("PFN NET LOST event. Do Nothing \n")); + return 0; + } else { + WL_DBG(("PFN NET FOUND event. count:%d \n", pfn_result->count)); + + + if (pfn_result->count > 0) { + int i; + + memset(&request, 0x00, sizeof(struct cfg80211_scan_request)); + memset(&ssid, 0x00, sizeof(ssid)); + request.wiphy = wiphy; + + pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t) + - sizeof(wl_pfn_net_info_t)); + + channel = (struct ieee80211_channel *)kzalloc( + (sizeof(struct ieee80211_channel) * MAX_PFN_LIST_COUNT), + GFP_KERNEL); + if (!channel) { + WL_ERR(("No memory")); + err = -ENOMEM; + goto out_err; + } + + for (i = 0; i < pfn_result->count; i++) { + netinfo = &pnetinfo[i]; + if (!netinfo) { + WL_ERR(("Invalid netinfo ptr. index:%d", i)); + err = -EINVAL; + goto out_err; + } + + WL_DBG(("SSID:%s Channel:%d \n", + netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel)); + /* PFN result doesn't have all the info which are required by the supplicant + * (For e.g IEs) Do a target Escan so that sched scan results are reported + * via wl_inform_single_bss in the required format. Escan does require the + * scan request in the form of cfg80211_scan_request. For timebeing, create + * cfg80211_scan_request one out of the received PNO event. + */ + memcpy(ssid[i].ssid, netinfo->pfnsubnet.SSID, + netinfo->pfnsubnet.SSID_len); + ssid[i].ssid_len = netinfo->pfnsubnet.SSID_len; + request.n_ssids++; + + channel_req = netinfo->pfnsubnet.channel; + band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ + : NL80211_BAND_2GHZ; + channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band); + channel[i].band = band; + channel[i].flags |= IEEE80211_CHAN_NO_HT40; + request.channels[i] = &channel[i]; + request.n_channels++; + } + + /* assign parsed ssid array */ + if (request.n_ssids) + request.ssids = &ssid[0]; + + if (wl_get_drv_status_all(wl, SCANNING)) { + /* Abort any on-going scan */ + wl_cfg80211_scan_abort(wl, ndev); + } + + if (wl_get_p2p_status(wl, DISCOVERY_ON)) { + err = wl_cfgp2p_discover_enable_search(wl, false); + if (unlikely(err)) { + wl_clr_drv_status(wl, SCANNING, ndev); + goto out_err; + } + } + + wl_set_drv_status(wl, SCANNING, ndev); +#if FULL_ESCAN_ON_PFN_NET_FOUND + err = wl_do_escan(wl, wiphy, ndev, &request); +#else + err = wl_do_escan(wl, wiphy, ndev, NULL); +#endif + if (err) { + wl_clr_drv_status(wl, SCANNING, ndev); + goto out_err; + } + } else { + WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n")); + } + wl->sched_scan_running = TRUE; + } + + kfree(channel); + return 0; + +out_err: + if (channel) + kfree(channel); + return err; +} +#endif /* WL_SCHED_SCAN */ + static void wl_init_conf(struct wl_conf *conf) { WL_DBG(("Enter \n")); @@ -5257,7 +5543,9 @@ static void wl_init_event_handler(struct wl_priv *wl) wl->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; wl->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; wl->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; +#ifdef PNO_SUPPORT wl->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; +#endif /* PNO_SUPPORT */ } static s32 wl_init_priv_mem(struct wl_priv *wl) @@ -5559,7 +5847,7 @@ static void wl_scan_timeout(unsigned long data) if (wl->scan_request) { WL_ERR(("timer expired\n")); if (wl->escan_on) - wl_notify_escan_complete(wl, wl->escan_info.ndev, true); + wl_notify_escan_complete(wl, wl->escan_info.ndev, true, true); else wl_notify_iscan_complete(wl_to_iscan(wl), true); } @@ -5629,23 +5917,70 @@ static struct notifier_block wl_cfg80211_netdev_notifier = { .notifier_call = wl_cfg80211_netdev_notifier_call, }; -static void wl_notify_escan_complete(struct wl_priv *wl, +static s32 wl_notify_escan_complete(struct wl_priv *wl, struct net_device *ndev, - bool aborted) + bool aborted, bool fw_abort) { + wl_scan_params_t *params = NULL; + s32 params_size = 0; + s32 err = BCME_OK; unsigned long flags; + struct net_device *dev; WL_DBG(("Enter \n")); - wl_clr_drv_status(wl, SCANNING, ndev); - if (p2p_is_on(wl)) - wl_clr_p2p_status(wl, SCANNING); + + if (wl->scan_request) { + if (wl->scan_request->dev == wl->p2p_net) + dev = wl_to_prmry_ndev(wl); + else + dev = wl->scan_request->dev; + } + else { + WL_ERR(("wl->scan_request is NULL may be internal scan." + "doing scan_abort for ndev %p primary %p p2p_net %p", + ndev, wl_to_prmry_ndev(wl), wl->p2p_net)); + dev = ndev; + } + if (fw_abort) { + /* Our scan params only need space for 1 channel and 0 ssids */ + params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); + if (params == NULL) { + WL_ERR(("scan params allocation failed \n")); + err = -ENOMEM; + } else { + /* Do a scan abort to stop the driver's scan engine */ + err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); + if (err < 0) { + WL_ERR(("scan abort failed \n")); + } + } + } + del_timer_sync(&wl->scan_timeout); spin_lock_irqsave(&wl->cfgdrv_lock, flags); + +#ifdef WL_SCHED_SCAN + if (wl->sched_scan_req && wl->sched_scan_running && !wl->scan_request) { + WL_DBG((" REPORTING SCHED SCAN RESULTS \n")); + cfg80211_sched_scan_results(wl->sched_scan_req->wiphy); + wl->sched_scan_running = FALSE; + wl->sched_scan_req = NULL; + wl->scan_request = NULL; + } +#endif /* WL_SCHED_SCAN */ + if (likely(wl->scan_request)) { cfg80211_scan_done(wl->scan_request, aborted); wl->scan_request = NULL; } + if (p2p_is_on(wl)) + wl_clr_p2p_status(wl, SCANNING); + wl_clr_drv_status(wl, SCANNING, dev); spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); + if (params) + kfree(params); + + return err; } static s32 wl_escan_handler(struct wl_priv *wl, @@ -5769,13 +6104,12 @@ static s32 wl_escan_handler(struct wl_priv *wl, wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); if (wl->afx_hdl->peer_chan == WL_INVALID) complete(&wl->act_frm_scan); - } else if (likely(wl->scan_request)) { + } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { mutex_lock(&wl->usr_sync); - del_timer_sync(&wl->scan_timeout); WL_INFO(("ESCAN COMPLETED\n")); wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; wl_inform_bss(wl); - wl_notify_escan_complete(wl, ndev, false); + wl_notify_escan_complete(wl, ndev, false, false); mutex_unlock(&wl->usr_sync); } } @@ -5787,13 +6121,12 @@ static s32 wl_escan_handler(struct wl_priv *wl, wl_clr_p2p_status(wl, SCANNING); if (wl->afx_hdl->peer_chan == WL_INVALID) complete(&wl->act_frm_scan); - } else if (likely(wl->scan_request)) { + } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { mutex_lock(&wl->usr_sync); - del_timer_sync(&wl->scan_timeout); WL_INFO(("ESCAN ABORTED\n")); wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; wl_inform_bss(wl); - wl_notify_escan_complete(wl, ndev, true); + wl_notify_escan_complete(wl, ndev, true, false); mutex_unlock(&wl->usr_sync); } } @@ -5806,12 +6139,11 @@ static s32 wl_escan_handler(struct wl_priv *wl, wl_clr_drv_status(wl, SCANNING, wl->afx_hdl->dev); if (wl->afx_hdl->peer_chan == WL_INVALID) complete(&wl->act_frm_scan); - } else if (likely(wl->scan_request)) { + } else if ((likely(wl->scan_request)) || (wl->sched_scan_running)) { mutex_lock(&wl->usr_sync); - del_timer_sync(&wl->scan_timeout); wl->bss_list = (wl_scan_results_t *)wl->escan_info.escan_buf; wl_inform_bss(wl); - wl_notify_escan_complete(wl, ndev, true); + wl_notify_escan_complete(wl, ndev, true, false); mutex_unlock(&wl->usr_sync); } } @@ -6135,9 +6467,7 @@ static s32 wl_event_handler(void *data) tsk_ctl_t *tsk = (tsk_ctl_t *)data; wl = (struct wl_priv *)tsk->parent; - - DAEMONIZE("wl_event_handler"); - + DAEMONIZE("dhd_cfg80211_event"); complete(&tsk->completed); while (down_interruptible (&tsk->sema) == 0) { @@ -6166,7 +6496,7 @@ static s32 wl_event_handler(void *data) } DHD_OS_WAKE_UNLOCK(wl->pub); } - WL_DBG(("%s was terminated\n", __func__)); + WL_ERR(("%s was terminated\n", __func__)); complete_and_exit(&tsk->completed, 0); return 0; } @@ -6346,24 +6676,31 @@ static s32 wl_add_remove_eventmsg(struct net_device *ndev, u16 event, bool add) s32 wl_update_wiphybands(struct wl_priv *wl) { struct wiphy *wiphy; - s8 phylist_buf[128]; - s8 *phy; + u32 bandlist[3]; + u32 nband = 0; + u32 i = 0; s32 err = 0; - - err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_PHYLIST, phylist_buf, - sizeof(phylist_buf), false); + WL_DBG(("Entry")); + memset(bandlist, 0, sizeof(bandlist)); + err = wldev_ioctl(wl_to_prmry_ndev(wl), WLC_GET_BANDLIST, bandlist, + sizeof(bandlist), false); if (unlikely(err)) { WL_ERR(("error (%d)\n", err)); return err; } - phy = phylist_buf; - for (; *phy; phy++) { - if (*phy == 'a' || *phy == 'n') { - wiphy = wl_to_wiphy(wl); + wiphy = wl_to_wiphy(wl); + nband = bandlist[0]; + wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; + wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; + for (i = 1; i <= nband && i < sizeof(bandlist); i++) { + if (bandlist[i] == WLC_BAND_5G) wiphy->bands[IEEE80211_BAND_5GHZ] = &__wl_band_5ghz_a; - } + else if (bandlist[i] == WLC_BAND_2G) + wiphy->bands[IEEE80211_BAND_2GHZ] = + &__wl_band_2ghz; } + wiphy_apply_custom_regulatory(wiphy, &brcm_regdom); return err; } @@ -6373,7 +6710,7 @@ static s32 __wl_cfg80211_up(struct wl_priv *wl) struct net_device *ndev = wl_to_prmry_ndev(wl); struct wireless_dev *wdev = ndev->ieee80211_ptr; - WL_TRACE(("In\n")); + WL_DBG(("In\n")); err = dhd_config_dongle(wl, false); if (unlikely(err)) @@ -6401,7 +6738,7 @@ static s32 __wl_cfg80211_down(struct wl_priv *wl) struct net_info *iter, *next; struct net_device *ndev = wl_to_prmry_ndev(wl); - WL_TRACE(("In\n")); + WL_DBG(("In\n")); /* Check if cfg80211 interface is already down */ if (!wl_get_drv_status(wl, READY, ndev)) return err; /* it is even not ready */ @@ -6443,7 +6780,7 @@ s32 wl_cfg80211_up(void *para) struct wl_priv *wl; s32 err = 0; - WL_TRACE(("In\n")); + WL_DBG(("In\n")); wl = wlcfg_drv_priv; mutex_lock(&wl->usr_sync); wl_cfg80211_attach_post(wl_to_prmry_ndev(wl)); @@ -6473,7 +6810,7 @@ s32 wl_cfg80211_down(void *para) struct wl_priv *wl; s32 err = 0; - WL_TRACE(("In\n")); + WL_DBG(("In\n")); wl = wlcfg_drv_priv; mutex_lock(&wl->usr_sync); err = __wl_cfg80211_down(wl); diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index 2b8e66413f2..435d61833f1 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -442,6 +442,10 @@ struct wl_priv { bool p2p_supported; struct btcoex_info *btcoex_info; struct timer_list scan_timeout; /* Timer for catch scan event timeout */ +#ifdef WL_SCHED_SCAN + struct cfg80211_sched_scan_request *sched_scan_req; /* scheduled scan req */ +#endif /* WL_SCHED_SCAN */ + bool sched_scan_running; /* scheduled scan req status */ }; static inline struct wl_bss_info *next_bss(struct wl_scan_results *list, struct wl_bss_info *bss) diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c index d09448a7932..e724aa3ec72 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/bcmdhd/wl_iw.c @@ -162,11 +162,8 @@ uint wl_msg_level = WL_ERROR_VAL; #define htodchanspec(i) i #define dtohchanspec(i) i -#ifdef CONFIG_WIRELESS_EXT - extern struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); extern int dhd_wait_pend8021x(struct net_device *dev); -#endif #if WIRELESS_EXT < 19 #define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) From 2757c71245faeab5e6df08c33e7375389c9451f6 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 27 Feb 2012 14:02:51 -0800 Subject: [PATCH 0927/4025] net: wireless: bcmdhd: Update to Version 5.90.195.30 - Fix STA features if P2P FW is in use - Move ENABLE_P2P_INTERFACE to Makefile - Minor fixes in PNO scan Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/Makefile | 1 + drivers/net/wireless/bcmdhd/dhd.h | 15 +- drivers/net/wireless/bcmdhd/dhd_cfg80211.c | 23 +++ drivers/net/wireless/bcmdhd/dhd_cfg80211.h | 2 + drivers/net/wireless/bcmdhd/dhd_common.c | 16 ++- drivers/net/wireless/bcmdhd/dhd_linux.c | 4 +- drivers/net/wireless/bcmdhd/dhd_sdio.c | 5 +- drivers/net/wireless/bcmdhd/include/epivers.h | 8 +- drivers/net/wireless/bcmdhd/wl_cfg80211.c | 131 +++++------------- drivers/net/wireless/bcmdhd/wl_cfg80211.h | 4 - 10 files changed, 96 insertions(+), 113 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index 9828de6fad9..8fc004ce84a 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -8,6 +8,7 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ -DNEW_COMPAT_WIRELESS -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ -DKEEP_ALIVE -DCSCAN -DGET_CUSTOM_MAC_ENABLE -DPKT_FILTER_SUPPORT \ -DEMBEDDED_PLATFORM -DENABLE_INSMOD_NO_FW_LOAD -DPNO_SUPPORT \ + -DENABLE_P2P_INTERFACE \ -Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \ diff --git a/drivers/net/wireless/bcmdhd/dhd.h b/drivers/net/wireless/bcmdhd/dhd.h index 25e74f44a53..d0306176b16 100644 --- a/drivers/net/wireless/bcmdhd/dhd.h +++ b/drivers/net/wireless/bcmdhd/dhd.h @@ -24,7 +24,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd.h 306879 2012-01-09 21:33:03Z $ + * $Id: dhd.h 316856 2012-02-23 21:44:34Z $ */ /**************** @@ -76,9 +76,12 @@ enum dhd_bus_state { /* Firmware requested operation mode */ #define STA_MASK 0x0001 -#define HOSTAPD_MASK 0x0002 +#define HOSTAPD_MASK 0x0002 #define WFD_MASK 0x0004 -#define SOFTAP_FW_MASK 0x0008 +#define SOFTAP_FW_MASK 0x0008 +#define P2P_GO_ENABLED 0x0010 +#define P2P_GC_ENABLED 0x0020 +#define CONCURENT_MASK 0x00F0 /* max sequential rxcntl timeouts to set HANG event */ #define MAX_CNTL_TIMEOUT 2 @@ -205,6 +208,12 @@ typedef struct dhd_pub { char eventmask[WL_EVENTING_MASK_LEN]; int op_mode; /* STA, HostAPD, WFD, SoftAP */ +/* Set this to 1 to use a seperate interface (p2p0) for p2p operations. + * For ICS MR1 releases it should be disable to be compatable with ICS MR1 Framework + * see target dhd-cdc-sdmmc-panda-cfg80211-icsmr1-gpl-debug in Makefile + */ +/* #define ENABLE_P2P_INTERFACE 1 */ + #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) struct wake_lock wakelock[WAKE_LOCK_MAX]; #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c index 917b09b35a3..172f25fc578 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.c @@ -33,6 +33,12 @@ extern struct wl_priv *wlcfg_drv_priv; static int dhd_dongle_up = FALSE; +#include +#include +#include +#include +#include + static s32 wl_dongle_up(struct net_device *ndev, u32 up); /** @@ -57,6 +63,22 @@ s32 dhd_cfg80211_down(struct wl_priv *wl) return 0; } +s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val) +{ + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); + dhd->op_mode |= val; + WL_ERR(("Set : op_mode=%d\n", dhd->op_mode)); + return 0; +} + +s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl) +{ + dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); + dhd->op_mode &= ~CONCURENT_MASK; + WL_ERR(("Clean : op_mode=%d\n", dhd->op_mode)); + return 0; +} + static s32 wl_dongle_up(struct net_device *ndev, u32 up) { s32 err = 0; @@ -67,6 +89,7 @@ static s32 wl_dongle_up(struct net_device *ndev, u32 up) } return err; } + s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock) { #ifndef DHD_SDALIGN diff --git a/drivers/net/wireless/bcmdhd/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h index 8dab652c1a2..6c033259a8d 100644 --- a/drivers/net/wireless/bcmdhd/dhd_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/dhd_cfg80211.h @@ -34,6 +34,8 @@ s32 dhd_cfg80211_init(struct wl_priv *wl); s32 dhd_cfg80211_deinit(struct wl_priv *wl); s32 dhd_cfg80211_down(struct wl_priv *wl); +s32 dhd_cfg80211_set_p2p_info(struct wl_priv *wl, int val); +s32 dhd_cfg80211_clean_p2p_info(struct wl_priv *wl); s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock); int wl_cfg80211_btcoex_init(struct wl_priv *wl); diff --git a/drivers/net/wireless/bcmdhd/dhd_common.c b/drivers/net/wireless/bcmdhd/dhd_common.c index a54c39152e4..a99dd49af4c 100644 --- a/drivers/net/wireless/bcmdhd/dhd_common.c +++ b/drivers/net/wireless/bcmdhd/dhd_common.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_common.c 307573 2012-01-12 00:04:39Z $ + * $Id: dhd_common.c 316272 2012-02-21 22:35:51Z $ */ #include #include @@ -134,7 +134,7 @@ enum { }; const bcm_iovar_t dhd_iovars[] = { - {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) }, + {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) }, #ifdef DHD_DEBUG {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, #endif /* DHD_DEBUG */ @@ -1814,10 +1814,21 @@ dhd_get_dtim_skip(dhd_pub_t *dhd) bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd) { #ifdef WL_CFG80211 +#ifndef ENABLE_P2P_INTERFACE + /* To be back compatble with ICS MR1 release where p2p interface disable but wlan0 used for p2p */ if (((dhd->op_mode & HOSTAPD_MASK) == HOSTAPD_MASK) || ((dhd->op_mode & WFD_MASK) == WFD_MASK)) return TRUE; else +#else + /* concurent mode with p2p interface for wfd and wlan0 for sta */ + if (((dhd->op_mode & P2P_GO_ENABLED) == P2P_GO_ENABLED) || + ((dhd->op_mode & P2P_GC_ENABLED) == P2P_GC_ENABLED)) { + DHD_ERROR(("%s P2P enabled for mode=%d\n", __FUNCTION__, dhd->op_mode)); + return TRUE; + } + else +#endif #endif /* WL_CFG80211 */ return FALSE; } @@ -2059,6 +2070,7 @@ int dhd_keep_alive_onoff(dhd_pub_t *dhd) return res; } #endif /* defined(KEEP_ALIVE) */ + /* Android ComboSCAN support */ /* diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 597d12560c1..2285078c7ec 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -22,7 +22,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_linux.c 314746 2012-02-14 03:45:02Z $ + * $Id: dhd_linux.c 316856 2012-02-23 21:44:34Z $ */ #include @@ -2922,7 +2922,7 @@ dhd_preinit_ioctls(dhd_pub_t *dhd) uint power_mode = PM_FAST; uint32 dongle_align = DHD_SDALIGN; uint32 glom = 0; - uint bcn_timeout = 4; + uint bcn_timeout = 10; uint retry_max = 3; #if defined(ARP_OFFLOAD_SUPPORT) int arpoe = 1; diff --git a/drivers/net/wireless/bcmdhd/dhd_sdio.c b/drivers/net/wireless/bcmdhd/dhd_sdio.c index 282a7179540..89cd1460394 100644 --- a/drivers/net/wireless/bcmdhd/dhd_sdio.c +++ b/drivers/net/wireless/bcmdhd/dhd_sdio.c @@ -21,7 +21,7 @@ * software in any way with any other Broadcom software provided under a license * other than the GPL, without Broadcom's express prior written consent. * - * $Id: dhd_sdio.c 314732 2012-02-14 03:22:42Z $ + * $Id: dhd_sdio.c 315747 2012-02-18 00:16:06Z $ */ #include @@ -801,7 +801,8 @@ dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) #ifdef DHD_DEBUG if (dhd_console_ms == 0) #endif /* DHD_DEBUG */ - dhd_os_wd_timer(bus->dhd, 0); + if (bus->poll == 0) + dhd_os_wd_timer(bus->dhd, 0); break; } #ifdef DHD_DEBUG diff --git a/drivers/net/wireless/bcmdhd/include/epivers.h b/drivers/net/wireless/bcmdhd/include/epivers.h index 0e720456f58..ff386de6737 100644 --- a/drivers/net/wireless/bcmdhd/include/epivers.h +++ b/drivers/net/wireless/bcmdhd/include/epivers.h @@ -33,17 +33,17 @@ #define EPI_RC_NUMBER 195 -#define EPI_INCREMENTAL_NUMBER 28 +#define EPI_INCREMENTAL_NUMBER 30 #define EPI_BUILD_NUMBER 0 -#define EPI_VERSION 5, 90, 195, 28 +#define EPI_VERSION 5, 90, 195, 30 -#define EPI_VERSION_NUM 0x055ac31c +#define EPI_VERSION_NUM 0x055ac31e #define EPI_VERSION_DEV 5.90.195 -#define EPI_VERSION_STR "5.90.195.28" +#define EPI_VERSION_STR "5.90.195.30" #endif diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.c b/drivers/net/wireless/bcmdhd/wl_cfg80211.c index c910fc59407..c0b35b7a188 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.c +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.c @@ -76,11 +76,6 @@ u32 wl_dbg_level = WL_DBG_ERR; #define COEX_DHCP -/* Set this to 1 to use a seperate interface (p2p0) - * for p2p operations. - */ -#define ENABLE_P2P_INTERFACE 1 - /* This is to override regulatory domains defined in cfg80211 module (reg.c) * By default world regulatory domain defined in reg.c puts the flags NL80211_RRF_PASSIVE_SCAN * and NL80211_RRF_NO_IBSS for 5GHz channels (for 36..48 and 149..165). @@ -516,7 +511,7 @@ static struct ieee80211_supported_band __wl_band_2ghz = { .n_channels = ARRAY_SIZE(__wl_2ghz_channels), .bitrates = wl_g_rates, .n_bitrates = wl_g_rates_size, -#if ENABLE_P2P_INTERFACE +#if defined(ENABLE_P2P_INTERFACE) /* wpa_supplicant sets wmm_enabled based on whether ht_cap * is present or not. The wmm_enabled is inturn used to * set the replay counters in the RSN IE. Without this @@ -539,7 +534,7 @@ static struct ieee80211_supported_band __wl_band_5ghz_a = { .n_channels = ARRAY_SIZE(__wl_5ghz_a_channels), .bitrates = wl_a_rates, .n_bitrates = wl_a_rates_size, -#if ENABLE_P2P_INTERFACE +#if defined(ENABLE_P2P_INTERFACE) /* wpa_supplicant sets wmm_enabled based on whether ht_cap * is present or not. The wmm_enabled is inturn used to * set the replay counters in the RSN IE. Without this @@ -768,6 +763,7 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, s32 timeout = -1; s32 wlif_type = -1; s32 mode = 0; + s32 dhd_mode = 0; chanspec_t chspec; struct wl_priv *wl = wiphy_priv(wiphy); struct net_device *_ndev; @@ -898,8 +894,13 @@ wl_cfg80211_add_virtual_iface(struct wiphy *wiphy, char *name, } if (net_attach && !net_attach(wl->pub, _ndev->ifindex)) { wl_alloc_netinfo(wl, _ndev, vwdev, mode); - WL_DBG((" virtual interface(%s) is " + WL_ERR((" virtual interface(%s) is " "created net attach done\n", wl->p2p->vir_ifname)); + if (type == NL80211_IFTYPE_P2P_CLIENT) + dhd_mode = P2P_GC_ENABLED; + else if (type == NL80211_IFTYPE_P2P_GO) + dhd_mode = P2P_GO_ENABLED; + DNGL_FUNC(dhd_cfg80211_set_p2p_info, (wl, dhd_mode)); } else { /* put back the rtnl_lock again */ if (rollback_lock) @@ -967,6 +968,7 @@ wl_cfg80211_del_virtual_iface(struct wiphy *wiphy, struct net_device *dev) msecs_to_jiffies(MAX_WAIT_TIME)); if (timeout > 0 && !wl_get_p2p_status(wl, IF_DELETING)) { WL_DBG(("IFDEL operation done\n")); + DNGL_FUNC(dhd_cfg80211_clean_p2p_info, (wl)); } else { WL_ERR(("IFDEL didn't complete properly\n")); } @@ -3186,62 +3188,6 @@ wl_cfg80211_scan_alloc_params(int channel, int nprobes, int *out_params_size) return params; } -s32 -wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev) -{ - wl_scan_params_t *params = NULL; - s32 params_size = 0; - s32 err = BCME_OK; - unsigned long flags; - struct net_device *dev; - - WL_DBG(("Enter\n")); - if (wl->scan_request) { - if (wl->scan_request->dev == wl->p2p_net) - dev = wl_to_prmry_ndev(wl); - else - dev = wl->scan_request->dev; - } - else { - WL_ERR(("wl->scan_request is NULL did we already do scan_abort?" - "Now scan_abort for ndev %p primary %p p2p_net %p", - ndev, wl_to_prmry_ndev(wl), wl->p2p_net)); - dev = ndev; - } - - /* Our scan params only need space for 1 channel and 0 ssids */ - params = wl_cfg80211_scan_alloc_params(-1, 0, ¶ms_size); - if (params == NULL) { - WL_ERR(("scan params allocation failed \n")); - err = -ENOMEM; - } else { - /* Do a scan abort to stop the driver's scan engine */ - err = wldev_ioctl(dev, WLC_SCAN, params, params_size, true); - if (err < 0) { - WL_ERR(("scan abort failed \n")); - } - } - del_timer_sync(&wl->scan_timeout); - spin_lock_irqsave(&wl->cfgdrv_lock, flags); - -#ifdef WL_SCHED_SCAN - if (wl->sched_scan_req && !wl->scan_request) { - cfg80211_sched_scan_stopped(wl_to_wiphy(wl)); - wl->sched_scan_req = NULL; - } -#endif /* WL_SCHED_SCAN */ - - if (wl->scan_request) { - cfg80211_scan_done(wl->scan_request, true); - wl->scan_request = NULL; - } - wl_clr_drv_status(wl, SCANNING, dev); - spin_unlock_irqrestore(&wl->cfgdrv_lock, flags); - if (params) - kfree(params); - return err; -} - static s32 wl_cfg80211_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_channel * channel, @@ -4354,7 +4300,7 @@ int wl_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) WL_ERR(("PNO reset failed")); if (wl->scan_request && wl->sched_scan_running) { - wl_cfg80211_scan_abort(wl, dev); + wl_notify_escan_complete(wl, dev, true, true); } wl->sched_scan_req = NULL; @@ -4583,7 +4529,7 @@ static s32 wl_inform_single_bss(struct wl_priv *wl, struct wl_bss_info *bi) signal = notif_bss_info->rssi * 100; -#if defined(WLP2P) && ENABLE_P2P_INTERFACE +#if defined(WLP2P) && defined(ENABLE_P2P_INTERFACE) if (wl->p2p_net && wl->scan_request && wl->scan_request->dev == wl->p2p_net) { #else @@ -5406,10 +5352,8 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, if (e->event_type == WLC_E_PFN_NET_LOST) { WL_DBG(("PFN NET LOST event. Do Nothing \n")); return 0; - } else { - WL_DBG(("PFN NET FOUND event. count:%d \n", pfn_result->count)); - - + } + WL_DBG(("PFN NET FOUND event. count:%d \n", pfn_result->count)); if (pfn_result->count > 0) { int i; @@ -5419,15 +5363,14 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, pnetinfo = (wl_pfn_net_info_t *)(data + sizeof(wl_pfn_scanresults_t) - sizeof(wl_pfn_net_info_t)); - - channel = (struct ieee80211_channel *)kzalloc( + channel = (struct ieee80211_channel *)kzalloc( (sizeof(struct ieee80211_channel) * MAX_PFN_LIST_COUNT), GFP_KERNEL); - if (!channel) { - WL_ERR(("No memory")); - err = -ENOMEM; - goto out_err; - } + if (!channel) { + WL_ERR(("No memory")); + err = -ENOMEM; + goto out_err; + } for (i = 0; i < pfn_result->count; i++) { netinfo = &pnetinfo[i]; @@ -5436,9 +5379,8 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, err = -EINVAL; goto out_err; } - WL_DBG(("SSID:%s Channel:%d \n", - netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel)); + netinfo->pfnsubnet.SSID, netinfo->pfnsubnet.channel)); /* PFN result doesn't have all the info which are required by the supplicant * (For e.g IEs) Do a target Escan so that sched scan results are reported * via wl_inform_single_bss in the required format. Escan does require the @@ -5452,7 +5394,7 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, channel_req = netinfo->pfnsubnet.channel; band = (channel_req <= CH_MAX_2G_CHANNEL) ? NL80211_BAND_2GHZ - : NL80211_BAND_2GHZ; + : NL80211_BAND_5GHZ; channel[i].center_freq = ieee80211_channel_to_frequency(channel_req, band); channel[i].band = band; channel[i].flags |= IEEE80211_CHAN_NO_HT40; @@ -5466,7 +5408,7 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, if (wl_get_drv_status_all(wl, SCANNING)) { /* Abort any on-going scan */ - wl_cfg80211_scan_abort(wl, ndev); + wl_notify_escan_complete(wl, ndev, true, true); } if (wl_get_p2p_status(wl, DISCOVERY_ON)) { @@ -5487,15 +5429,11 @@ wl_notify_sched_scan_results(struct wl_priv *wl, struct net_device *ndev, wl_clr_drv_status(wl, SCANNING, ndev); goto out_err; } - } else { - WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n")); - } wl->sched_scan_running = TRUE; } - - kfree(channel); - return 0; - + else { + WL_ERR(("FALSE PNO Event. (pfn_count == 0) \n")); + } out_err: if (channel) kfree(channel); @@ -5929,7 +5867,6 @@ static s32 wl_notify_escan_complete(struct wl_priv *wl, WL_DBG(("Enter \n")); - if (wl->scan_request) { if (wl->scan_request->dev == wl->p2p_net) dev = wl_to_prmry_ndev(wl); @@ -5962,10 +5899,12 @@ static s32 wl_notify_escan_complete(struct wl_priv *wl, #ifdef WL_SCHED_SCAN if (wl->sched_scan_req && wl->sched_scan_running && !wl->scan_request) { WL_DBG((" REPORTING SCHED SCAN RESULTS \n")); - cfg80211_sched_scan_results(wl->sched_scan_req->wiphy); + if (aborted) + cfg80211_sched_scan_stopped(wl->sched_scan_req->wiphy); + else + cfg80211_sched_scan_results(wl->sched_scan_req->wiphy); wl->sched_scan_running = FALSE; wl->sched_scan_req = NULL; - wl->scan_request = NULL; } #endif /* WL_SCHED_SCAN */ @@ -6232,7 +6171,7 @@ static void wl_deinit_priv(struct wl_priv *wl) unregister_netdevice_notifier(&wl_cfg80211_netdev_notifier); } -#if defined(WLP2P) && ENABLE_P2P_INTERFACE +#if defined(WLP2P) && defined(ENABLE_P2P_INTERFACE) static s32 wl_cfg80211_attach_p2p(void) { struct wl_priv *wl = wlcfg_drv_priv; @@ -6282,7 +6221,7 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) if (wl && !wl_get_drv_status(wl, READY, ndev)) { if (wl->wdev && wl_cfgp2p_supported(wl, ndev)) { -#if !ENABLE_P2P_INTERFACE +#if !defined(ENABLE_P2P_INTERFACE) wl->wdev->wiphy->interface_modes |= (BIT(NL80211_IFTYPE_P2P_CLIENT)| BIT(NL80211_IFTYPE_P2P_GO)); @@ -6290,7 +6229,7 @@ s32 wl_cfg80211_attach_post(struct net_device *ndev) if ((err = wl_cfgp2p_init_priv(wl)) != 0) goto fail; -#if defined(WLP2P) && ENABLE_P2P_INTERFACE +#if defined(WLP2P) && defined(ENABLE_P2P_INTERFACE) if (wl->p2p_net) { /* Update MAC addr for p2p0 interface here. */ memcpy(wl->p2p_net->dev_addr, ndev->dev_addr, ETH_ALEN); @@ -6374,7 +6313,7 @@ s32 wl_cfg80211_attach(struct net_device *ndev, void *data) wlcfg_drv_priv = wl; -#if defined(WLP2P) && ENABLE_P2P_INTERFACE +#if defined(WLP2P) && defined(ENABLE_P2P_INTERFACE) err = wl_cfg80211_attach_p2p(); if (err) goto cfg80211_attach_out; @@ -6400,7 +6339,7 @@ void wl_cfg80211_detach(void *para) wl_cfg80211_btcoex_deinit(wl); #endif -#if defined(WLP2P) && ENABLE_P2P_INTERFACE +#if defined(WLP2P) && defined(ENABLE_P2P_INTERFACE) wl_cfg80211_detach_p2p(); #endif wl_setup_rfkill(wl, FALSE); diff --git a/drivers/net/wireless/bcmdhd/wl_cfg80211.h b/drivers/net/wireless/bcmdhd/wl_cfg80211.h index 435d61833f1..41e7c678e41 100644 --- a/drivers/net/wireless/bcmdhd/wl_cfg80211.h +++ b/drivers/net/wireless/bcmdhd/wl_cfg80211.h @@ -658,9 +658,5 @@ extern int wl_cfg80211_hang(struct net_device *dev, u16 reason); extern s32 wl_mode_to_nl80211_iftype(s32 mode); int wl_cfg80211_do_driver_init(struct net_device *net); void wl_cfg80211_enable_trace(int level); - -/* do scan abort */ -extern s32 wl_cfg80211_scan_abort(struct wl_priv *wl, struct net_device *ndev); - extern s32 wl_cfg80211_if_is_group_owner(void); #endif /* _wl_cfg80211_h_ */ From ee88a6c5e260219cd2b2c540fdaf714ad7d74ec8 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 27 Feb 2012 15:51:56 -0800 Subject: [PATCH 0928/4025] net: wireless: bcmdhd: Add SET_RANDOM_MAC_SOFTAP option Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index 8fc004ce84a..a8b135dba87 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -8,7 +8,7 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ -DNEW_COMPAT_WIRELESS -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ -DKEEP_ALIVE -DCSCAN -DGET_CUSTOM_MAC_ENABLE -DPKT_FILTER_SUPPORT \ -DEMBEDDED_PLATFORM -DENABLE_INSMOD_NO_FW_LOAD -DPNO_SUPPORT \ - -DENABLE_P2P_INTERFACE \ + -DSET_RANDOM_MAC_SOFTAP -DENABLE_P2P_INTERFACE \ -Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \ From 46ec987de3c3009cebc6e0735c4f865b71ae833b Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 28 Feb 2012 10:30:59 -0800 Subject: [PATCH 0929/4025] net: wireless: bcmdhd: Minor cleaning Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/dhd_linux.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 2285078c7ec..6418e38f3b7 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -3748,7 +3748,7 @@ dhd_module_init(void) error = -ENODEV; DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__)); goto fail_2; - } + } #endif #if defined(WL_CFG80211) wl_android_post_init(); @@ -4377,8 +4377,6 @@ dhd_dev_get_pno_status(struct net_device *dev) #endif /* PNO_SUPPORT */ -struct work_struct work; - int net_os_send_hang_message(struct net_device *dev) { dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); @@ -4411,7 +4409,7 @@ void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); if (dhd && dhd->pub.up) - memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); + memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); } void dhd_net_if_lock(struct net_device *dev) From e078a22b6f226ecf4cf3add7e5a7cb09b458bff1 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 28 Feb 2012 11:03:37 -0800 Subject: [PATCH 0930/4025] net: wireless: bcmdhd: Add SETSUSPENDMODE command Signed-off-by: Dmitry Shmidt --- drivers/net/wireless/bcmdhd/Makefile | 2 +- drivers/net/wireless/bcmdhd/dhd_linux.c | 131 +++++++++++++-------- drivers/net/wireless/bcmdhd/wl_android.c | 26 +++- drivers/net/wireless/bcmdhd/wl_iw.c | 39 +++++- drivers/net/wireless/bcmdhd/wl_iw.h | 5 +- drivers/net/wireless/bcmdhd/wldev_common.h | 2 +- 6 files changed, 142 insertions(+), 63 deletions(-) diff --git a/drivers/net/wireless/bcmdhd/Makefile b/drivers/net/wireless/bcmdhd/Makefile index a8b135dba87..ead28f5cfc7 100644 --- a/drivers/net/wireless/bcmdhd/Makefile +++ b/drivers/net/wireless/bcmdhd/Makefile @@ -8,7 +8,7 @@ DHDCFLAGS = -Wall -Wstrict-prototypes -Dlinux -DBCMDRIVER \ -DNEW_COMPAT_WIRELESS -DWIFI_ACT_FRAME -DARP_OFFLOAD_SUPPORT \ -DKEEP_ALIVE -DCSCAN -DGET_CUSTOM_MAC_ENABLE -DPKT_FILTER_SUPPORT \ -DEMBEDDED_PLATFORM -DENABLE_INSMOD_NO_FW_LOAD -DPNO_SUPPORT \ - -DSET_RANDOM_MAC_SOFTAP -DENABLE_P2P_INTERFACE \ + -DSET_RANDOM_MAC_SOFTAP -DENABLE_P2P_INTERFACE -DDHD_USE_EARLYSUSPEND \ -Idrivers/net/wireless/bcmdhd -Idrivers/net/wireless/bcmdhd/include DHDOFILES = aiutils.o bcmsdh_sdmmc_linux.o dhd_linux.o siutils.o bcmutils.o \ diff --git a/drivers/net/wireless/bcmdhd/dhd_linux.c b/drivers/net/wireless/bcmdhd/dhd_linux.c index 6418e38f3b7..9654719e428 100644 --- a/drivers/net/wireless/bcmdhd/dhd_linux.c +++ b/drivers/net/wireless/bcmdhd/dhd_linux.c @@ -154,11 +154,10 @@ print_tainted() extern wl_iw_extra_params_t g_wl_iw_params; #endif /* defined(WL_WIRELESS_EXT) */ -#if defined(CONFIG_HAS_EARLYSUSPEND) +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) #include -extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); -extern int dhd_get_dtim_skip(dhd_pub_t *dhd); #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ +extern int dhd_get_dtim_skip(dhd_pub_t *dhd); #ifdef PKT_FILTER_SUPPORT extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); @@ -259,6 +258,7 @@ typedef struct dhd_info { * calls and wifi_on or wifi_off */ struct mutex dhd_net_if_mutex; + struct mutex dhd_suspend_mutex; #endif spinlock_t wakelock_spinlock; int wakelock_counter; @@ -271,7 +271,7 @@ typedef struct dhd_info { atomic_t pend_8021x_cnt; dhd_attach_states_t dhd_state; -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) struct early_suspend early_suspend; #endif /* CONFIG_HAS_EARLYSUSPEND */ @@ -424,6 +424,8 @@ static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR ; static void dhd_net_if_lock_local(dhd_info_t *dhd); static void dhd_net_if_unlock_local(dhd_info_t *dhd); +static void dhd_suspend_lock(dhd_pub_t *dhdp); +static void dhd_suspend_unlock(dhd_pub_t *dhdp); #if !defined(AP) && defined(WLP2P) static u32 dhd_concurrent_fw(dhd_pub_t *dhd); #endif @@ -513,7 +515,6 @@ static void dhd_set_packet_filter(int value, dhd_pub_t *dhd) #endif } -#if defined(CONFIG_HAS_EARLYSUSPEND) static int dhd_set_suspend(int value, dhd_pub_t *dhd) { int power_mode = PM_MAX; @@ -525,70 +526,75 @@ static int dhd_set_suspend(int value, dhd_pub_t *dhd) DHD_TRACE(("%s: enter, value = %d in_suspend=%d\n", __FUNCTION__, value, dhd->in_suspend)); + dhd_suspend_lock(dhd); if (dhd && dhd->up) { if (value && dhd->in_suspend) { - /* Kernel suspended */ - DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__)); + /* Kernel suspended */ + DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, + sizeof(power_mode), TRUE, 0); - /* Enable packet filter, only allow unicast packet to send up */ - dhd_set_packet_filter(1, dhd); + /* Enable packet filter, only allow unicast packet to send up */ + dhd_set_packet_filter(1, dhd); - /* If DTIM skip is set up as default, force it to wake - * each third DTIM for better power savings. Note that - * one side effect is a chance to miss BC/MC packet. - */ - bcn_li_dtim = dhd_get_dtim_skip(dhd); - bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, - 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - - /* Disable firmware roaming during suspend */ - bcm_mkiovar("roam_off", (char *)&roamvar, 4, - iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - } else { + /* If DTIM skip is set up as default, force it to wake + * each third DTIM for better power savings. Note that + * one side effect is a chance to miss BC/MC packet. + */ + bcn_li_dtim = dhd_get_dtim_skip(dhd); + bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, + 4, iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + + /* Disable firmware roaming during suspend */ + bcm_mkiovar("roam_off", (char *)&roamvar, 4, + iovbuf, sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + } else { - /* Kernel resumed */ - DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__)); + /* Kernel resumed */ + DHD_TRACE(("%s: Remove extra suspend setting \n", __FUNCTION__)); - power_mode = PM_FAST; - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); + power_mode = PM_FAST; + dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, + sizeof(power_mode), TRUE, 0); - /* disable pkt filter */ - dhd_set_packet_filter(0, dhd); + /* disable pkt filter */ + dhd_set_packet_filter(0, dhd); - /* restore pre-suspend setting for dtim_skip */ - bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip, - 4, iovbuf, sizeof(iovbuf)); + /* restore pre-suspend setting for dtim_skip */ + bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip, + 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - roamvar = dhd_roam_disable; - bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, - sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - } + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + roamvar = dhd_roam_disable; + bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, + sizeof(iovbuf)); + dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); + } } - + dhd_suspend_unlock(dhd); return 0; } -static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val) +static int dhd_suspend_resume_helper(struct dhd_info *dhd, int val, int force) { dhd_pub_t *dhdp = &dhd->pub; + int ret = 0; DHD_OS_WAKE_LOCK(dhdp); /* Set flag when early suspend was called */ dhdp->in_suspend = val; - if ((!dhdp->suspend_disable_flag) && (dhd_check_ap_wfd_mode_set(dhdp) == FALSE)) - dhd_set_suspend(val, dhdp); + if ((force || !dhdp->suspend_disable_flag) && + (dhd_check_ap_wfd_mode_set(dhdp) == FALSE)) + ret = dhd_set_suspend(val, dhdp); DHD_OS_WAKE_UNLOCK(dhdp); + return ret; } +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) static void dhd_early_suspend(struct early_suspend *h) { struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); @@ -596,7 +602,7 @@ static void dhd_early_suspend(struct early_suspend *h) DHD_TRACE(("%s: enter\n", __FUNCTION__)); if (dhd) - dhd_suspend_resume_helper(dhd, 1); + dhd_suspend_resume_helper(dhd, 1, 0); } static void dhd_late_resume(struct early_suspend *h) @@ -606,7 +612,7 @@ static void dhd_late_resume(struct early_suspend *h) DHD_TRACE(("%s: enter\n", __FUNCTION__)); if (dhd) - dhd_suspend_resume_helper(dhd, 0); + dhd_suspend_resume_helper(dhd, 0, 0); } #endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ @@ -2645,6 +2651,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) #endif #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) mutex_init(&dhd->dhd_net_if_mutex); + mutex_init(&dhd->dhd_suspend_mutex); #endif dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; @@ -2730,7 +2737,7 @@ dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) register_pm_notifier(&dhd_sleep_pm_notifier); #endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ -#ifdef CONFIG_HAS_EARLYSUSPEND +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; dhd->early_suspend.suspend = dhd_early_suspend; dhd->early_suspend.resume = dhd_late_resume; @@ -3563,7 +3570,7 @@ void dhd_detach(dhd_pub_t *dhdp) unregister_inetaddr_notifier(&dhd_notifier); #endif /* ARP_OFFLOAD_SUPPORT */ -#if defined(CONFIG_HAS_EARLYSUSPEND) +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) { if (dhd->early_suspend.suspend) unregister_early_suspend(&dhd->early_suspend); @@ -4255,16 +4262,18 @@ int net_os_set_suspend_disable(struct net_device *dev, int val) return ret; } -int net_os_set_suspend(struct net_device *dev, int val) +int net_os_set_suspend(struct net_device *dev, int val, int force) { int ret = 0; -#if defined(CONFIG_HAS_EARLYSUSPEND) dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); if (dhd) { +#if defined(CONFIG_HAS_EARLYSUSPEND) && defined(DHD_USE_EARLYSUSPEND) ret = dhd_set_suspend(val, &dhd->pub); +#else + ret = dhd_suspend_resume_helper(dhd, val, force); +#endif } -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ return ret; } @@ -4440,6 +4449,24 @@ static void dhd_net_if_unlock_local(dhd_info_t *dhd) #endif } +static void dhd_suspend_lock(dhd_pub_t *pub) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + if (dhd) + mutex_lock(&dhd->dhd_suspend_mutex); +#endif +} + +static void dhd_suspend_unlock(dhd_pub_t *pub) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) + dhd_info_t *dhd = (dhd_info_t *)(pub->info); + if (dhd) + mutex_unlock(&dhd->dhd_suspend_mutex); +#endif +} + unsigned long dhd_os_spin_lock(dhd_pub_t *pub) { dhd_info_t *dhd = (dhd_info_t *)(pub->info); diff --git a/drivers/net/wireless/bcmdhd/wl_android.c b/drivers/net/wireless/bcmdhd/wl_android.c index 8f6b1988180..3b7544816ac 100644 --- a/drivers/net/wireless/bcmdhd/wl_android.c +++ b/drivers/net/wireless/bcmdhd/wl_android.c @@ -67,6 +67,7 @@ #define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP" #define CMD_BTCOEXMODE "BTCOEXMODE" #define CMD_SETSUSPENDOPT "SETSUSPENDOPT" +#define CMD_SETSUSPENDMODE "SETSUSPENDMODE" #define CMD_P2P_DEV_ADDR "P2P_DEV_ADDR" #define CMD_SETFWPATH "SETFWPATH" #define CMD_SETBAND "SETBAND" @@ -201,7 +202,7 @@ static int wl_android_set_suspendopt(struct net_device *dev, char *command, int ret_now = net_os_set_suspend_disable(dev, suspend_flag); if (ret_now != suspend_flag) { - if (!(ret = net_os_set_suspend(dev, ret_now))) + if (!(ret = net_os_set_suspend(dev, ret_now, 1))) DHD_INFO(("%s: Suspend Flag %d -> %d\n", __FUNCTION__, ret_now, suspend_flag)); else @@ -210,6 +211,26 @@ static int wl_android_set_suspendopt(struct net_device *dev, char *command, int return ret; } +static int wl_android_set_suspendmode(struct net_device *dev, char *command, int total_len) +{ + int ret = 0; + +#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND) + int suspend_flag; + + suspend_flag = *(command + strlen(CMD_SETSUSPENDMODE) + 1) - '0'; + + if (suspend_flag != 0) + suspend_flag = 1; + + if (!(ret = net_os_set_suspend(dev, suspend_flag, 0))) + DHD_INFO(("%s: Suspend Mode %d\n",__FUNCTION__,suspend_flag)); + else + DHD_ERROR(("%s: failed %d\n",__FUNCTION__,ret)); +#endif + return ret; +} + static int wl_android_get_band(struct net_device *dev, char *command, int total_len) { uint band; @@ -505,6 +526,9 @@ int wl_android_priv_cmd(struct net_device *net, struct ifreq *ifr, int cmd) else if (strnicmp(command, CMD_SETSUSPENDOPT, strlen(CMD_SETSUSPENDOPT)) == 0) { bytes_written = wl_android_set_suspendopt(net, command, priv_cmd.total_len); } + else if (strnicmp(command, CMD_SETSUSPENDMODE, strlen(CMD_SETSUSPENDMODE)) == 0) { + bytes_written = wl_android_set_suspendmode(net, command, priv_cmd.total_len); + } else if (strnicmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) == 0) { uint band = *(command + strlen(CMD_SETBAND) + 1) - '0'; bytes_written = wldev_set_band(net, band); diff --git a/drivers/net/wireless/bcmdhd/wl_iw.c b/drivers/net/wireless/bcmdhd/wl_iw.c index e724aa3ec72..f5494f3fd79 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.c +++ b/drivers/net/wireless/bcmdhd/wl_iw.c @@ -1119,7 +1119,7 @@ wl_iw_set_btcoex_dhcp( } static int -wl_iw_set_suspend( +wl_iw_set_suspend_opt( struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, @@ -1130,16 +1130,15 @@ char *extra int ret_now; int ret = 0; - suspend_flag = *(extra + strlen(SETSUSPEND_CMD) + 1) - '0'; + suspend_flag = *(extra + strlen(SETSUSPENDOPT_CMD) + 1) - '0'; if (suspend_flag != 0) suspend_flag = 1; ret_now = net_os_set_suspend_disable(dev, suspend_flag); - if (ret_now != suspend_flag) { - if (!(ret = net_os_set_suspend(dev, ret_now))) + if (!(ret = net_os_set_suspend(dev, ret_now, 1))) WL_ERROR(("%s: Suspend Flag %d -> %d\n", __FUNCTION__, ret_now, suspend_flag)); else @@ -1149,6 +1148,32 @@ char *extra return ret; } +static int +wl_iw_set_suspend_mode( +struct net_device *dev, +struct iw_request_info *info, +union iwreq_data *wrqu, +char *extra +) +{ + int ret = 0; + +#if !defined(CONFIG_HAS_EARLYSUSPEND) || !defined(DHD_USE_EARLYSUSPEND) + int suspend_flag; + + suspend_flag = *(extra + strlen(SETSUSPENDMODE_CMD) + 1) - '0'; + + if (suspend_flag != 0) + suspend_flag = 1; + + if (!(ret = net_os_set_suspend(dev, suspend_flag, 0))) + WL_ERROR(("%s: Suspend Mode %d\n",__FUNCTION__,suspend_flag)); + else + WL_ERROR(("%s: failed %d\n", __FUNCTION__, ret)); +#endif + return ret; +} + static int wl_format_ssid(char* ssid_buf, uint8* ssid, int ssid_len) { @@ -7601,8 +7626,10 @@ wl_iw_set_priv( ret = wl_iw_get_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra); else if (strnicmp(extra, DTIM_SKIP_SET_CMD, strlen(DTIM_SKIP_SET_CMD)) == 0) ret = wl_iw_set_dtim_skip(dev, info, (union iwreq_data *)dwrq, extra); - else if (strnicmp(extra, SETSUSPEND_CMD, strlen(SETSUSPEND_CMD)) == 0) - ret = wl_iw_set_suspend(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, SETSUSPENDOPT_CMD, strlen(SETSUSPENDOPT_CMD)) == 0) + ret = wl_iw_set_suspend_opt(dev, info, (union iwreq_data *)dwrq, extra); + else if (strnicmp(extra, SETSUSPENDMODE_CMD, strlen(SETSUSPENDMODE_CMD)) == 0) + ret = wl_iw_set_suspend_mode(dev, info, (union iwreq_data *)dwrq, extra); else if (strnicmp(extra, TXPOWER_SET_CMD, strlen(TXPOWER_SET_CMD)) == 0) ret = wl_iw_set_txpower(dev, info, (union iwreq_data *)dwrq, extra); #if defined(PNO_SUPPORT) diff --git a/drivers/net/wireless/bcmdhd/wl_iw.h b/drivers/net/wireless/bcmdhd/wl_iw.h index faca5f72e22..273dcf12b89 100644 --- a/drivers/net/wireless/bcmdhd/wl_iw.h +++ b/drivers/net/wireless/bcmdhd/wl_iw.h @@ -47,7 +47,8 @@ #define BAND_SET_CMD "SETBAND" #define DTIM_SKIP_GET_CMD "DTIMSKIPGET" #define DTIM_SKIP_SET_CMD "DTIMSKIPSET" -#define SETSUSPEND_CMD "SETSUSPENDOPT" +#define SETSUSPENDOPT_CMD "SETSUSPENDOPT" +#define SETSUSPENDMODE_CMD "SETSUSPENDMODE" #define PNOSSIDCLR_SET_CMD "PNOSSIDCLR" #define PNOSETUP_SET_CMD "PNOSETUP " @@ -206,7 +207,7 @@ extern int net_os_wake_unlock(struct net_device *dev); extern int net_os_wake_lock_timeout(struct net_device *dev); extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val); extern int net_os_set_suspend_disable(struct net_device *dev, int val); -extern int net_os_set_suspend(struct net_device *dev, int val); +extern int net_os_set_suspend(struct net_device *dev, int val, int force); extern int net_os_set_dtim_skip(struct net_device *dev, int val); extern int net_os_send_hang_message(struct net_device *dev); extern void get_customized_country_code(char *country_iso_code, wl_country_t *cspec); diff --git a/drivers/net/wireless/bcmdhd/wldev_common.h b/drivers/net/wireless/bcmdhd/wldev_common.h index 6a1ba153360..773235e4597 100644 --- a/drivers/net/wireless/bcmdhd/wldev_common.h +++ b/drivers/net/wireless/bcmdhd/wldev_common.h @@ -92,7 +92,7 @@ extern int net_os_wake_lock_timeout(struct net_device *dev); extern int net_os_wake_lock_timeout_enable(struct net_device *dev, int val); extern int net_os_set_dtim_skip(struct net_device *dev, int val); extern int net_os_set_suspend_disable(struct net_device *dev, int val); -extern int net_os_set_suspend(struct net_device *dev, int val); +extern int net_os_set_suspend(struct net_device *dev, int val, int force); extern int wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left); From 62797c459126d343df0e9095fe1aa9ae3ebb3f89 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 13 Feb 2012 22:00:47 -0800 Subject: [PATCH 0931/4025] ASoC: wm8962: Fix sidetone enumeration texts commit 31794bc37bf2db84f085da52b72bfba65739b2d2 upstream. The sidetone enumeration texts have left and right swapped. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/wm8962.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 6d0cae4681b..c850e3d84ed 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -2373,7 +2373,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, } } -static const char *st_text[] = { "None", "Right", "Left" }; +static const char *st_text[] = { "None", "Left", "Right" }; static const struct soc_enum str_enum = SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_1, 2, 3, st_text); From 251ebc7bb45c7e27b8868b13fb56fedeedfc1da4 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 23 Feb 2012 13:50:35 +0000 Subject: [PATCH 0932/4025] NOMMU: Lock i_mmap_mutex for access to the VMA prio list commit 918e556ec214ed2f584e4cac56d7b29e4bb6bf27 upstream. Lock i_mmap_mutex for access to the VMA prio list to prevent concurrent access. Currently, certain parts of the mmap handling are protected by the region mutex, but not all. Reported-by: Al Viro Signed-off-by: David Howells Acked-by: Al Viro Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/nommu.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mm/nommu.c b/mm/nommu.c index 9edc897a397..839775875e7 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -697,9 +697,11 @@ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma) if (vma->vm_file) { mapping = vma->vm_file->f_mapping; + mutex_lock(&mapping->i_mmap_mutex); flush_dcache_mmap_lock(mapping); vma_prio_tree_insert(vma, &mapping->i_mmap); flush_dcache_mmap_unlock(mapping); + mutex_unlock(&mapping->i_mmap_mutex); } /* add the VMA to the tree */ @@ -761,9 +763,11 @@ static void delete_vma_from_mm(struct vm_area_struct *vma) if (vma->vm_file) { mapping = vma->vm_file->f_mapping; + mutex_lock(&mapping->i_mmap_mutex); flush_dcache_mmap_lock(mapping); vma_prio_tree_remove(vma, &mapping->i_mmap); flush_dcache_mmap_unlock(mapping); + mutex_unlock(&mapping->i_mmap_mutex); } /* remove from the MM's tree and list */ @@ -2061,6 +2065,7 @@ int nommu_shrink_inode_mappings(struct inode *inode, size_t size, high = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; down_write(&nommu_region_sem); + mutex_lock(&inode->i_mapping->i_mmap_mutex); /* search for VMAs that fall within the dead zone */ vma_prio_tree_foreach(vma, &iter, &inode->i_mapping->i_mmap, @@ -2068,6 +2073,7 @@ int nommu_shrink_inode_mappings(struct inode *inode, size_t size, /* found one - only interested if it's shared out of the page * cache */ if (vma->vm_flags & VM_SHARED) { + mutex_unlock(&inode->i_mapping->i_mmap_mutex); up_write(&nommu_region_sem); return -ETXTBSY; /* not quite true, but near enough */ } @@ -2095,6 +2101,7 @@ int nommu_shrink_inode_mappings(struct inode *inode, size_t size, } } + mutex_unlock(&inode->i_mapping->i_mmap_mutex); up_write(&nommu_region_sem); return 0; } From e1efaccd1c67efe24e3708c916e51330bf770299 Mon Sep 17 00:00:00 2001 From: Chris D Schimp Date: Mon, 20 Feb 2012 16:59:24 -0500 Subject: [PATCH 0933/4025] hwmon: (max6639) Fix FAN_FROM_REG calculation commit b63d97a36edb1aecf8c13e5f5783feff4d64c24b upstream. RPM calculation from tachometer value does not depend on PPR. Also, do not report negative RPM values. Signed-off-by: Chris D Schimp [guenter.roeck@ericsson.com: do not report negative RPM values] Signed-off-by: Guenter Roeck Acked-by: Roland Stigge Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/max6639.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index f20d9978ee7..1b844dbd9f7 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -72,8 +72,8 @@ static unsigned short normal_i2c[] = { 0x2c, 0x2e, 0x2f, I2C_CLIENT_END }; static const int rpm_ranges[] = { 2000, 4000, 8000, 16000 }; -#define FAN_FROM_REG(val, div, rpm_range) ((val) == 0 ? -1 : \ - (val) == 255 ? 0 : (rpm_ranges[rpm_range] * 30) / ((div + 1) * (val))) +#define FAN_FROM_REG(val, rpm_range) ((val) == 0 || (val) == 255 ? \ + 0 : (rpm_ranges[rpm_range] * 30) / (val)) #define TEMP_LIMIT_TO_REG(val) SENSORS_LIMIT((val) / 1000, 0, 255) /* @@ -333,7 +333,7 @@ static ssize_t show_fan_input(struct device *dev, return PTR_ERR(data); return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index], - data->ppr, data->rpm_range)); + data->rpm_range)); } static ssize_t show_alarm(struct device *dev, From 5774b2eec1698c9647162a52431e514d6628471f Mon Sep 17 00:00:00 2001 From: Chris D Schimp Date: Mon, 20 Feb 2012 17:44:59 -0500 Subject: [PATCH 0934/4025] hwmon: (max6639) Fix PPR register initialization to set both channels commit 2f2da1ac0ba5b6cc6e1957c4da5ff20e67d8442b upstream. Initialize PPR register for both channels, and set correct PPR register bits. Also remove unnecessary variable initializations. Signed-off-by: Chris D Schimp [guenter.roeck@ericsson.com: Merged two patches into one] Signed-off-by: Guenter Roeck Acked-by: Roland Stigge Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/max6639.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/hwmon/max6639.c b/drivers/hwmon/max6639.c index 1b844dbd9f7..8c3df047e56 100644 --- a/drivers/hwmon/max6639.c +++ b/drivers/hwmon/max6639.c @@ -429,9 +429,9 @@ static int max6639_init_client(struct i2c_client *client) struct max6639_data *data = i2c_get_clientdata(client); struct max6639_platform_data *max6639_info = client->dev.platform_data; - int i = 0; + int i; int rpm_range = 1; /* default: 4000 RPM */ - int err = 0; + int err; /* Reset chip to default values, see below for GCONFIG setup */ err = i2c_smbus_write_byte_data(client, MAX6639_REG_GCONFIG, @@ -446,11 +446,6 @@ static int max6639_init_client(struct i2c_client *client) else data->ppr = 2; data->ppr -= 1; - err = i2c_smbus_write_byte_data(client, - MAX6639_REG_FAN_PPR(i), - data->ppr << 5); - if (err) - goto exit; if (max6639_info) rpm_range = rpm_range_to_reg(max6639_info->rpm_range); @@ -458,6 +453,13 @@ static int max6639_init_client(struct i2c_client *client) for (i = 0; i < 2; i++) { + /* Set Fan pulse per revolution */ + err = i2c_smbus_write_byte_data(client, + MAX6639_REG_FAN_PPR(i), + data->ppr << 6); + if (err) + goto exit; + /* Fans config PWM, RPM */ err = i2c_smbus_write_byte_data(client, MAX6639_REG_FAN_CONFIG1(i), From 8507fb05c966cdd3a808bb267d2595a41db87512 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 22 Feb 2012 08:13:52 -0800 Subject: [PATCH 0935/4025] hwmon: (ads1015) Fix file leak in probe function commit 363434b5dc352464ac7601547891e5fc9105f124 upstream. An error while creating sysfs attribute files in the driver's probe function results in an error abort, but already created files are not removed. This patch fixes the problem. Signed-off-by: Guenter Roeck Cc: Dirk Eibach Acked-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/ads1015.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c index e9beeda4cbe..9a5af38bffd 100644 --- a/drivers/hwmon/ads1015.c +++ b/drivers/hwmon/ads1015.c @@ -284,7 +284,7 @@ static int ads1015_probe(struct i2c_client *client, continue; err = device_create_file(&client->dev, &ads1015_in[k].dev_attr); if (err) - goto exit_free; + goto exit_remove; } data->hwmon_dev = hwmon_device_register(&client->dev); @@ -298,7 +298,6 @@ static int ads1015_probe(struct i2c_client *client, exit_remove: for (k = 0; k < ADS1015_CHANNELS; ++k) device_remove_file(&client->dev, &ads1015_in[k].dev_attr); -exit_free: kfree(data); exit: return err; From 49f936fe90802f0923f47d28f755c83d358feac9 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Wed, 15 Feb 2012 18:48:22 +0000 Subject: [PATCH 0936/4025] powerpc/perf: power_pmu_start restores incorrect values, breaking frequency events commit 9a45a9407c69d068500923480884661e2b9cc421 upstream. perf on POWER stopped working after commit e050e3f0a71b (perf: Fix broken interrupt rate throttling). That patch exposed a bug in the POWER perf_events code. Since the PMCs count upwards and take an exception when the top bit is set, we want to write 0x80000000 - left in power_pmu_start. We were instead programming in left which effectively disables the counter until we eventually hit 0x80000000. This could take seconds or longer. With the patch applied I get the expected number of samples: SAMPLE events: 9948 Signed-off-by: Anton Blanchard Acked-by: Paul Mackerras Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/perf_event.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c index 822f63008ae..5793c4ba5a0 100644 --- a/arch/powerpc/kernel/perf_event.c +++ b/arch/powerpc/kernel/perf_event.c @@ -865,6 +865,7 @@ static void power_pmu_start(struct perf_event *event, int ef_flags) { unsigned long flags; s64 left; + unsigned long val; if (!event->hw.idx || !event->hw.sample_period) return; @@ -880,7 +881,12 @@ static void power_pmu_start(struct perf_event *event, int ef_flags) event->hw.state = 0; left = local64_read(&event->hw.period_left); - write_pmc(event->hw.idx, left); + + val = 0; + if (left < 0x80000000L) + val = 0x80000000L - left; + + write_pmc(event->hw.idx, val); perf_event_update_userpage(event); perf_pmu_enable(event->pmu); From fe12043438bcd8c739e286977c8f44ff87483c62 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 13 Feb 2012 16:36:34 -0500 Subject: [PATCH 0937/4025] drm/radeon/kms: fix MSI re-arm on rv370+ commit b7f5b7dec3d539a84734f2bcb7e53fbb1532a40b upstream. MSI_REARM_EN register is a write only trigger register. There is no need RMW when re-arming. May fix: https://bugs.freedesktop.org/show_bug.cgi?id=41668 Signed-off-by: Alex Deucher Signed-off-by: Dave Airlie Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/r100.c | 4 +--- drivers/gpu/drm/radeon/rs600.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 764249587f1..d94f440f137 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -681,9 +681,7 @@ int r100_irq_process(struct radeon_device *rdev) WREG32(RADEON_AIC_CNTL, msi_rearm | RS400_MSI_REARM); break; default: - msi_rearm = RREG32(RADEON_MSI_REARM_EN) & ~RV370_MSI_REARM_EN; - WREG32(RADEON_MSI_REARM_EN, msi_rearm); - WREG32(RADEON_MSI_REARM_EN, msi_rearm | RV370_MSI_REARM_EN); + WREG32(RADEON_MSI_REARM_EN, RV370_MSI_REARM_EN); break; } } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 21acfb5449a..2026c2d52c5 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -698,9 +698,7 @@ int rs600_irq_process(struct radeon_device *rdev) WREG32(RADEON_BUS_CNTL, msi_rearm | RS600_MSI_REARM); break; default: - msi_rearm = RREG32(RADEON_MSI_REARM_EN) & ~RV370_MSI_REARM_EN; - WREG32(RADEON_MSI_REARM_EN, msi_rearm); - WREG32(RADEON_MSI_REARM_EN, msi_rearm | RV370_MSI_REARM_EN); + WREG32(RADEON_MSI_REARM_EN, RV370_MSI_REARM_EN); break; } } From e4907ec10117f491d4a5630994a04bc0d3a7d0f1 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Mon, 30 Jan 2012 12:25:24 +0100 Subject: [PATCH 0938/4025] PCI: workaround hard-wired bus number V2 commit 71f6bd4a23130cd2f4b036010c5790b1295290b9 upstream. Fixes PCI device detection on IBM xSeries IBM 3850 M2 / x3950 M2 when using ACPI resources (_CRS). This is default, a manual workaround (without this patch) would be pci=nocrs boot param. V2: Add dev_warn if the workaround is hit. This should reveal how common such setups are (via google) and point to possible problems if things are still not working as expected. -> Suggested by Jan Beulich. Tested-by: garyhade@us.ibm.com Signed-off-by: Yinghai Lu Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- drivers/pci/probe.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index bafb3c3d4a8..5b3771a7a41 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -657,6 +657,11 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, dev_dbg(&dev->dev, "scanning [bus %02x-%02x] behind bridge, pass %d\n", secondary, subordinate, pass); + if (!primary && (primary != bus->number) && secondary && subordinate) { + dev_warn(&dev->dev, "Primary bus is hard wired to 0\n"); + primary = bus->number; + } + /* Check if setup is sensible at all */ if (!pass && (primary != bus->number || secondary <= bus->number)) { From 0a3e045705af3ea9d61560d4f6ffe2ce62f81992 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 9 Feb 2012 19:59:43 +0530 Subject: [PATCH 0939/4025] mac80211: Fix a rwlock bad magic bug commit b57e6b560fc2a2742910ac5ca0eb2c46e45aeac2 upstream. read_lock(&tpt_trig->trig.leddev_list_lock) is accessed via the path ieee80211_open (->) ieee80211_do_open (->) ieee80211_mod_tpt_led_trig (->) ieee80211_start_tpt_led_trig (->) tpt_trig_timer before initializing it. the intilization of this read/write lock happens via the path ieee80211_led_init (->) led_trigger_register, but we are doing 'ieee80211_led_init' after 'ieeee80211_if_add' where we register netdev_ops. so we access leddev_list_lock before initializing it and causes the following bug in chrome laptops with AR928X cards with the following script while true do sudo modprobe -v ath9k sleep 3 sudo modprobe -r ath9k sleep 3 done BUG: rwlock bad magic on CPU#1, wpa_supplicant/358, f5b9eccc Pid: 358, comm: wpa_supplicant Not tainted 3.0.13 #1 Call Trace: [<8137b9df>] rwlock_bug+0x3d/0x47 [<81179830>] do_raw_read_lock+0x19/0x29 [<8137f063>] _raw_read_lock+0xd/0xf [] tpt_trig_timer+0xc3/0x145 [mac80211] [] ieee80211_mod_tpt_led_trig+0x152/0x174 [mac80211] [] ieee80211_do_open+0x11e/0x42e [mac80211] [] ? ieee80211_check_concurrent_iface+0x26/0x13c [mac80211] [] ieee80211_open+0x48/0x4c [mac80211] [<812dbed8>] __dev_open+0x82/0xab [<812dc0c9>] __dev_change_flags+0x9c/0x113 [<812dc1ae>] dev_change_flags+0x18/0x44 [<8132144f>] devinet_ioctl+0x243/0x51a [<81321ba9>] inet_ioctl+0x93/0xac [<812cc951>] sock_ioctl+0x1c6/0x1ea [<812cc78b>] ? might_fault+0x20/0x20 [<810b1ebb>] do_vfs_ioctl+0x46e/0x4a2 [<810a6ebb>] ? fget_light+0x2f/0x70 [<812ce549>] ? sys_recvmsg+0x3e/0x48 [<810b1f35>] sys_ioctl+0x46/0x69 [<8137fa77>] sysenter_do_call+0x12/0x2 Cc: Gary Morain Cc: Paul Stewart Cc: Abhijit Pradhan Cc: Vasanthakumar Thiagarajan Cc: Rajkumar Manoharan Acked-by: Johannes Berg Tested-by: Mohammed Shafi Shajakhan Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 866f269183c..1e36fb3318c 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -910,6 +910,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n", result); + ieee80211_led_init(local); + rtnl_lock(); result = ieee80211_init_rate_ctrl_alg(local, @@ -931,8 +933,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) rtnl_unlock(); - ieee80211_led_init(local); - local->network_latency_notifier.notifier_call = ieee80211_max_network_latency; result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY, From aa4e084812c0f03c0363bacdad6a0fff95826544 Mon Sep 17 00:00:00 2001 From: Tim Gardner Date: Wed, 15 Feb 2012 07:50:15 +0000 Subject: [PATCH 0940/4025] ipheth: Add iPhone 4S commit 72ba009b8a159e995e40d3b4e5d7d265acead983 upstream. BugLink: http://bugs.launchpad.net/bugs/900802 Signed-off-by: Till Kamppeter Signed-off-by: Tim Gardner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/ipheth.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index 8f9b7f76045..9cf4e47e55b 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -60,6 +60,7 @@ #define USB_PRODUCT_IPHONE_3GS 0x1294 #define USB_PRODUCT_IPHONE_4 0x1297 #define USB_PRODUCT_IPHONE_4_VZW 0x129c +#define USB_PRODUCT_IPHONE_4S 0x12a0 #define IPHETH_USBINTF_CLASS 255 #define IPHETH_USBINTF_SUBCLASS 253 @@ -103,6 +104,10 @@ static struct usb_device_id ipheth_table[] = { USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4_VZW, IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, IPHETH_USBINTF_PROTO) }, + { USB_DEVICE_AND_INTERFACE_INFO( + USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4S, + IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS, + IPHETH_USBINTF_PROTO) }, { } }; MODULE_DEVICE_TABLE(usb, ipheth_table); From d870401f171a25a362ae7ce1eeebafdd3fc080fd Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Tue, 7 Feb 2012 17:55:40 -0600 Subject: [PATCH 0941/4025] eCryptfs: Copy up lower inode attrs after setting lower xattr commit 545d680938be1e86a6c5250701ce9abaf360c495 upstream. After passing through a ->setxattr() call, eCryptfs needs to copy the inode attributes from the lower inode to the eCryptfs inode, as they may have changed in the lower filesystem's ->setxattr() path. One example is if an extended attribute containing a POSIX Access Control List is being set. The new ACL may cause the lower filesystem to modify the mode of the lower inode and the eCryptfs inode would need to be updated to reflect the new mode. https://launchpad.net/bugs/926292 Signed-off-by: Tyler Hicks Reported-by: Sebastien Bacher Cc: John Johansen Signed-off-by: Greg Kroah-Hartman --- fs/ecryptfs/inode.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index e3562f2a59d..2717329386d 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -1119,6 +1119,8 @@ ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value, } rc = vfs_setxattr(lower_dentry, name, value, size, flags); + if (!rc) + fsstack_copy_attr_all(dentry->d_inode, lower_dentry->d_inode); out: return rc; } From e8b827b4f14a1a25b909236a08a5fe63b92a658f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 22 Feb 2012 17:02:38 +0100 Subject: [PATCH 0942/4025] ALSA: hda - Fix redundant jack creations for cx5051 [Note that since the patch isn't applicable (and unnecessary) to 3.3-rc, there is no corresponding upstream fix.] The cx5051 parser calls snd_hda_input_jack_add() in the init callback to create and initialize the jack detection instances. Since the init callback is called at each time when the device gets woken up after suspend or power-saving mode, the duplicated instances are accumulated at each call. This ends up with the kernel warnings with the too large array size. The fix is simply to move the calls of snd_hda_input_jack_add() into the parser section instead of the init callback. The fix is needed only up to 3.2 kernel, since the HD-audio jack layer was redesigned in the 3.3 kernel. Reported-by: Russell King Tested-by: Russell King Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_conexant.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 3c2381ca372..81ecd6c0321 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1917,6 +1917,10 @@ static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | event); +} + +static void cxt5051_init_mic_jack(struct hda_codec *codec, hda_nid_t nid) +{ snd_hda_input_jack_add(codec, nid, SND_JACK_MICROPHONE, NULL); snd_hda_input_jack_report(codec, nid); } @@ -1934,7 +1938,6 @@ static int cxt5051_init(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; conexant_init(codec); - conexant_init_jacks(codec); if (spec->auto_mic & AUTO_MIC_PORTB) cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT); @@ -2067,6 +2070,12 @@ static int patch_cxt5051(struct hda_codec *codec) if (spec->beep_amp) snd_hda_attach_beep_device(codec, spec->beep_amp); + conexant_init_jacks(codec); + if (spec->auto_mic & AUTO_MIC_PORTB) + cxt5051_init_mic_jack(codec, 0x17); + if (spec->auto_mic & AUTO_MIC_PORTC) + cxt5051_init_mic_jack(codec, 0x18); + return 0; } From e9513216eb2c0276e227fbb9a6f754e16c9c7510 Mon Sep 17 00:00:00 2001 From: Johan Rudholm Date: Wed, 23 Nov 2011 09:05:58 +0100 Subject: [PATCH 0943/4025] mmc: core: check for zero length ioctl data commit 4d6144de8ba263eb3691a737c547e5b2fdc45287 upstream. If the read or write buffer size associated with the command sent through the mmc_blk_ioctl is zero, do not prepare data buffer. This enables a ioctl(2) call to for instance send a MMC_SWITCH to set a byte in the ext_csd. Signed-off-by: Johan Rudholm Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/card/block.c | 82 ++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index f85e4222455..c0839d48f6c 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -251,6 +251,9 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user( goto idata_err; } + if (!idata->buf_bytes) + return idata; + idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL); if (!idata->buf) { err = -ENOMEM; @@ -297,25 +300,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, if (IS_ERR(idata)) return PTR_ERR(idata); - cmd.opcode = idata->ic.opcode; - cmd.arg = idata->ic.arg; - cmd.flags = idata->ic.flags; - - data.sg = &sg; - data.sg_len = 1; - data.blksz = idata->ic.blksz; - data.blocks = idata->ic.blocks; - - sg_init_one(data.sg, idata->buf, idata->buf_bytes); - - if (idata->ic.write_flag) - data.flags = MMC_DATA_WRITE; - else - data.flags = MMC_DATA_READ; - - mrq.cmd = &cmd; - mrq.data = &data; - md = mmc_blk_get(bdev->bd_disk); if (!md) { err = -EINVAL; @@ -328,6 +312,48 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, goto cmd_done; } + cmd.opcode = idata->ic.opcode; + cmd.arg = idata->ic.arg; + cmd.flags = idata->ic.flags; + + if (idata->buf_bytes) { + data.sg = &sg; + data.sg_len = 1; + data.blksz = idata->ic.blksz; + data.blocks = idata->ic.blocks; + + sg_init_one(data.sg, idata->buf, idata->buf_bytes); + + if (idata->ic.write_flag) + data.flags = MMC_DATA_WRITE; + else + data.flags = MMC_DATA_READ; + + /* data.flags must already be set before doing this. */ + mmc_set_data_timeout(&data, card); + + /* Allow overriding the timeout_ns for empirical tuning. */ + if (idata->ic.data_timeout_ns) + data.timeout_ns = idata->ic.data_timeout_ns; + + if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { + /* + * Pretend this is a data transfer and rely on the + * host driver to compute timeout. When all host + * drivers support cmd.cmd_timeout for R1B, this + * can be changed to: + * + * mrq.data = NULL; + * cmd.cmd_timeout = idata->ic.cmd_timeout_ms; + */ + data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000; + } + + mrq.data = &data; + } + + mrq.cmd = &cmd; + mmc_claim_host(card->host); if (idata->ic.is_acmd) { @@ -336,24 +362,6 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev, goto cmd_rel_host; } - /* data.flags must already be set before doing this. */ - mmc_set_data_timeout(&data, card); - /* Allow overriding the timeout_ns for empirical tuning. */ - if (idata->ic.data_timeout_ns) - data.timeout_ns = idata->ic.data_timeout_ns; - - if ((cmd.flags & MMC_RSP_R1B) == MMC_RSP_R1B) { - /* - * Pretend this is a data transfer and rely on the host driver - * to compute timeout. When all host drivers support - * cmd.cmd_timeout for R1B, this can be changed to: - * - * mrq.data = NULL; - * cmd.cmd_timeout = idata->ic.cmd_timeout_ms; - */ - data.timeout_ns = idata->ic.cmd_timeout_ms * 1000000; - } - mmc_wait_for_req(card->host, &mrq); if (cmd.error) { From 2efb4f6b48f54918213f0b8c3f7135aca328f8f3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 9 Feb 2012 15:31:36 -0500 Subject: [PATCH 0944/4025] NFSv4: Ensure we throw out bad delegation stateids on NFS4ERR_BAD_STATEID commit b9f9a03150969e4bd9967c20bce67c4de769058f upstream. To ensure that we don't just reuse the bad delegation when we attempt to recover the nfs4_state that received the bad stateid error. Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4state.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 87822a32709..9e7e9a52416 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1065,6 +1065,8 @@ void nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4 { struct nfs_client *clp = server->nfs_client; + if (test_and_clear_bit(NFS_DELEGATED_STATE, &state->flags)) + nfs_async_inode_return_delegation(state->inode, &state->stateid); nfs4_state_mark_reclaim_nograce(clp, state); nfs4_schedule_state_manager(clp); } From ad15d5c6dc9f1272fe1dde3de87ab775f65a6d77 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 7 Feb 2012 19:42:07 +0100 Subject: [PATCH 0945/4025] ARM: 7321/1: cache-v7: Disable preemption when reading CCSIDR commit b46c0f74657d1fe1c1b0c1452631cc38a9e6987f upstream. armv7's flush_cache_all() flushes caches via set/way. To determine the cache attributes (line size, number of sets, etc.) the assembly first writes the CSSELR register to select a cache level and then reads the CCSIDR register. The CSSELR register is banked per-cpu and is used to determine which cache level CCSIDR reads. If the task is migrated between when the CSSELR is written and the CCSIDR is read the CCSIDR value may be for an unexpected cache level (for example L1 instead of L2) and incorrect cache flushing could occur. Disable interrupts across the write and read so that the correct cache attributes are read and used for the cache flushing routine. We disable interrupts instead of disabling preemption because the critical section is only 3 instructions and we want to call v7_dcache_flush_all from __v7_setup which doesn't have a full kernel stack with a struct thread_info. This fixes a problem we see in scm_call() when flush_cache_all() is called from preemptible context and sometimes the L2 cache is not properly flushed out. Signed-off-by: Stephen Boyd Acked-by: Catalin Marinas Reviewed-by: Nicolas Pitre Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/mm/cache-v7.S | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index 35931191c84..c3e4b863b24 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S @@ -54,9 +54,15 @@ loop1: and r1, r1, #7 @ mask of the bits for current cache only cmp r1, #2 @ see what cache we have at this level blt skip @ skip if no cache, or just i-cache +#ifdef CONFIG_PREEMPT + save_and_disable_irqs r9 @ make cssr&csidr read atomic +#endif mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr isb @ isb to sych the new cssr&csidr mrc p15, 1, r1, c0, c0, 0 @ read the new csidr +#ifdef CONFIG_PREEMPT + restore_irqs_notrace r9 +#endif and r2, r1, #7 @ extract the length of the cache lines add r2, r2, #4 @ add 4 (line length offset) ldr r4, =0x3ff From bbb8ae42eb210ba2bdff67450f3737e10cb042f3 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 15 Feb 2012 16:01:42 +0100 Subject: [PATCH 0946/4025] ARM: 7325/1: fix v7 boot with lockdep enabled commit 8e43a905dd574f54c5715d978318290ceafbe275 upstream. Bootup with lockdep enabled has been broken on v7 since b46c0f74657d ("ARM: 7321/1: cache-v7: Disable preemption when reading CCSIDR"). This is because v7_setup (which is called very early during boot) calls v7_flush_dcache_all, and the save_and_disable_irqs added by that patch ends up attempting to call into lockdep C code (trace_hardirqs_off()) when we are in no position to execute it (no stack, MMU off). Fix this by using a notrace variant of save_and_disable_irqs. The code already uses the notrace variant of restore_irqs. Reviewed-by: Nicolas Pitre Acked-by: Stephen Boyd Cc: Catalin Marinas Signed-off-by: Rabin Vincent Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/assembler.h | 5 +++++ arch/arm/mm/cache-v7.S | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 65c3f2474f5..4e25f188835 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -137,6 +137,11 @@ disable_irq .endm + .macro save_and_disable_irqs_notrace, oldcpsr + mrs \oldcpsr, cpsr + disable_irq_notrace + .endm + /* * Restore interrupt state previously stored in a register. We don't * guarantee that this will preserve the flags. diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S index c3e4b863b24..1ed1fd36130 100644 --- a/arch/arm/mm/cache-v7.S +++ b/arch/arm/mm/cache-v7.S @@ -55,7 +55,7 @@ loop1: cmp r1, #2 @ see what cache we have at this level blt skip @ skip if no cache, or just i-cache #ifdef CONFIG_PREEMPT - save_and_disable_irqs r9 @ make cssr&csidr read atomic + save_and_disable_irqs_notrace r9 @ make cssr&csidr read atomic #endif mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr isb @ isb to sych the new cssr&csidr From c3e8445f6ec4ad66c5143d6df8528f7440429b91 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 6 Feb 2012 15:14:37 -0500 Subject: [PATCH 0947/4025] net: Make qdisc_skb_cb upper size bound explicit. [ Upstream commit 16bda13d90c8d5da243e2cfa1677e62ecce26860 ] Just like skb->cb[], so that qdisc_skb_cb can be encapsulated inside of other data structures. This is intended to be used by IPoIB so that it can remember addressing information stored at hard_header_ops->create() time that it can fetch when the packet gets to the transmit routine. Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/sch_generic.h | 9 ++++++++- net/sched/sch_choke.c | 3 +-- net/sched/sch_netem.c | 3 +-- net/sched/sch_sfb.c | 3 +-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index b931f021d7a..f1fbe2d5e05 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -219,9 +219,16 @@ struct tcf_proto { struct qdisc_skb_cb { unsigned int pkt_len; - long data[]; + unsigned char data[24]; }; +static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz) +{ + struct qdisc_skb_cb *qcb; + BUILD_BUG_ON(sizeof(skb->cb) < sizeof(unsigned int) + sz); + BUILD_BUG_ON(sizeof(qcb->data) < sz); +} + static inline int qdisc_qlen(struct Qdisc *q) { return q->q.qlen; diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index 06afbaeb4c8..178ee83175a 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -225,8 +225,7 @@ struct choke_skb_cb { static inline struct choke_skb_cb *choke_skb_cb(const struct sk_buff *skb) { - BUILD_BUG_ON(sizeof(skb->cb) < - sizeof(struct qdisc_skb_cb) + sizeof(struct choke_skb_cb)); + qdisc_cb_private_validate(skb, sizeof(struct choke_skb_cb)); return (struct choke_skb_cb *)qdisc_skb_cb(skb)->data; } diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 69c35f6cd13..87b965811c2 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -117,8 +117,7 @@ struct netem_skb_cb { static inline struct netem_skb_cb *netem_skb_cb(struct sk_buff *skb) { - BUILD_BUG_ON(sizeof(skb->cb) < - sizeof(struct qdisc_skb_cb) + sizeof(struct netem_skb_cb)); + qdisc_cb_private_validate(skb, sizeof(struct netem_skb_cb)); return (struct netem_skb_cb *)qdisc_skb_cb(skb)->data; } diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index 0a833d0c1f6..47ee29fad35 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -93,8 +93,7 @@ struct sfb_skb_cb { static inline struct sfb_skb_cb *sfb_skb_cb(const struct sk_buff *skb) { - BUILD_BUG_ON(sizeof(skb->cb) < - sizeof(struct qdisc_skb_cb) + sizeof(struct sfb_skb_cb)); + qdisc_cb_private_validate(skb, sizeof(struct sfb_skb_cb)); return (struct sfb_skb_cb *)qdisc_skb_cb(skb)->data; } From aca5efd17c1a1ed6303537792517e7352cf74edd Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 7 Feb 2012 14:51:21 +0000 Subject: [PATCH 0948/4025] IPoIB: Stop lying about hard_header_len and use skb->cb to stash LL addresses [ Upstream commit 936d7de3d736e0737542641269436f4b5968e9ef ] Commit a0417fa3a18a ("net: Make qdisc_skb_cb upper size bound explicit.") made it possible for a netdev driver to use skb->cb between its header_ops.create method and its .ndo_start_xmit method. Use this in ipoib_hard_header() to stash away the LL address (GID + QPN), instead of the "ipoib_pseudoheader" hack. This allows IPoIB to stop lying about its hard_header_len, which will let us fix the L2 check for GRO. Signed-off-by: Roland Dreier Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/ipoib/ipoib.h | 6 +- drivers/infiniband/ulp/ipoib/ipoib_main.c | 55 +++++++------------ .../infiniband/ulp/ipoib/ipoib_multicast.c | 9 +-- 3 files changed, 24 insertions(+), 46 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 7b6985a2e65..936804efb77 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -44,6 +44,7 @@ #include #include +#include #include @@ -117,8 +118,9 @@ struct ipoib_header { u16 reserved; }; -struct ipoib_pseudoheader { - u8 hwaddr[INFINIBAND_ALEN]; +struct ipoib_cb { + struct qdisc_skb_cb qdisc_cb; + u8 hwaddr[INFINIBAND_ALEN]; }; /* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */ diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index a98c414978e..b811444dcdd 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -658,7 +658,7 @@ static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev) } static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, - struct ipoib_pseudoheader *phdr) + struct ipoib_cb *cb) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_path *path; @@ -666,17 +666,15 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, spin_lock_irqsave(&priv->lock, flags); - path = __path_find(dev, phdr->hwaddr + 4); + path = __path_find(dev, cb->hwaddr + 4); if (!path || !path->valid) { int new_path = 0; if (!path) { - path = path_rec_create(dev, phdr->hwaddr + 4); + path = path_rec_create(dev, cb->hwaddr + 4); new_path = 1; } if (path) { - /* put pseudoheader back on for next time */ - skb_push(skb, sizeof *phdr); __skb_queue_tail(&path->queue, skb); if (!path->query && path_rec_start(dev, path)) { @@ -700,12 +698,10 @@ static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, be16_to_cpu(path->pathrec.dlid)); spin_unlock_irqrestore(&priv->lock, flags); - ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr)); + ipoib_send(dev, skb, path->ah, IPOIB_QPN(cb->hwaddr)); return; } else if ((path->query || !path_rec_start(dev, path)) && skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { - /* put pseudoheader back on for next time */ - skb_push(skb, sizeof *phdr); __skb_queue_tail(&path->queue, skb); } else { ++dev->stats.tx_dropped; @@ -774,16 +770,14 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb_any(skb); } } else { - struct ipoib_pseudoheader *phdr = - (struct ipoib_pseudoheader *) skb->data; - skb_pull(skb, sizeof *phdr); + struct ipoib_cb *cb = (struct ipoib_cb *) skb->cb; - if (phdr->hwaddr[4] == 0xff) { + if (cb->hwaddr[4] == 0xff) { /* Add in the P_Key for multicast*/ - phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff; - phdr->hwaddr[9] = priv->pkey & 0xff; + cb->hwaddr[8] = (priv->pkey >> 8) & 0xff; + cb->hwaddr[9] = priv->pkey & 0xff; - ipoib_mcast_send(dev, phdr->hwaddr + 4, skb); + ipoib_mcast_send(dev, cb->hwaddr + 4, skb); } else { /* unicast GID -- should be ARP or RARP reply */ @@ -792,14 +786,14 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x %pI6\n", skb_dst(skb) ? "neigh" : "dst", be16_to_cpup((__be16 *) skb->data), - IPOIB_QPN(phdr->hwaddr), - phdr->hwaddr + 4); + IPOIB_QPN(cb->hwaddr), + cb->hwaddr + 4); dev_kfree_skb_any(skb); ++dev->stats.tx_dropped; goto unlock; } - unicast_arp_send(skb, dev, phdr); + unicast_arp_send(skb, dev, cb); } } unlock: @@ -825,8 +819,6 @@ static int ipoib_hard_header(struct sk_buff *skb, const void *daddr, const void *saddr, unsigned len) { struct ipoib_header *header; - struct dst_entry *dst; - struct neighbour *n; header = (struct ipoib_header *) skb_push(skb, sizeof *header); @@ -834,18 +826,13 @@ static int ipoib_hard_header(struct sk_buff *skb, header->reserved = 0; /* - * If we don't have a neighbour structure, stuff the - * destination address onto the front of the skb so we can - * figure out where to send the packet later. + * If we don't have a dst_entry structure, stuff the + * destination address into skb->cb so we can figure out where + * to send the packet later. */ - dst = skb_dst(skb); - n = NULL; - if (dst) - n = dst_get_neighbour_raw(dst); - if ((!dst || !n) && daddr) { - struct ipoib_pseudoheader *phdr = - (struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr); - memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); + if (!skb_dst(skb)) { + struct ipoib_cb *cb = (struct ipoib_cb *) skb->cb; + memcpy(cb->hwaddr, daddr, INFINIBAND_ALEN); } return 0; @@ -1021,11 +1008,7 @@ static void ipoib_setup(struct net_device *dev) dev->flags |= IFF_BROADCAST | IFF_MULTICAST; - /* - * We add in INFINIBAND_ALEN to allow for the destination - * address "pseudoheader" for skbs without neighbour struct. - */ - dev->hard_header_len = IPOIB_ENCAP_LEN + INFINIBAND_ALEN; + dev->hard_header_len = IPOIB_ENCAP_LEN; dev->addr_len = INFINIBAND_ALEN; dev->type = ARPHRD_INFINIBAND; dev->tx_queue_len = ipoib_sendq_size * 2; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index a8d2a891b84..8b6350606d5 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -258,21 +258,14 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, netif_tx_lock_bh(dev); while (!skb_queue_empty(&mcast->pkt_queue)) { struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue); - struct dst_entry *dst = skb_dst(skb); - struct neighbour *n = NULL; netif_tx_unlock_bh(dev); skb->dev = dev; - if (dst) - n = dst_get_neighbour_raw(dst); - if (!dst || !n) { - /* put pseudoheader back on for next time */ - skb_push(skb, sizeof (struct ipoib_pseudoheader)); - } if (dev_queue_xmit(skb)) ipoib_warn(priv, "dev_queue_xmit failed to requeue packet\n"); + netif_tx_lock_bh(dev); } netif_tx_unlock_bh(dev); From 32fa5d83232b026092505e9165e119e5806b930d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Feb 2012 08:51:50 +0000 Subject: [PATCH 0949/4025] gro: more generic L2 header check [ Upstream commit 5ca3b72c5da47d95b83857b768def6172fbc080a ] Shlomo Pongratz reported GRO L2 header check was suited for Ethernet only, and failed on IB/ipoib traffic. He provided a patch faking a zeroed header to let GRO aggregates frames. Roland Dreier, Herbert Xu, and others suggested we change GRO L2 header check to be more generic, ie not assuming L2 header is 14 bytes, but taking into account hard_header_len. __napi_gro_receive() has special handling for the common case (Ethernet) to avoid a memcmp() call and use an inline optimized function instead. Signed-off-by: Eric Dumazet Reported-by: Shlomo Pongratz Cc: Roland Dreier Cc: Or Gerlitz Cc: Herbert Xu Tested-by: Sean Hefty Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index f14f6015a7a..17fdbf8d478 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3434,14 +3434,20 @@ static inline gro_result_t __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { struct sk_buff *p; + unsigned int maclen = skb->dev->hard_header_len; for (p = napi->gro_list; p; p = p->next) { unsigned long diffs; diffs = (unsigned long)p->dev ^ (unsigned long)skb->dev; diffs |= p->vlan_tci ^ skb->vlan_tci; - diffs |= compare_ether_header(skb_mac_header(p), - skb_gro_mac_header(skb)); + if (maclen == ETH_HLEN) + diffs |= compare_ether_header(skb_mac_header(p), + skb_gro_mac_header(skb)); + else if (!diffs) + diffs = memcmp(skb_mac_header(p), + skb_gro_mac_header(skb), + maclen); NAPI_GRO_CB(p)->same_flow = !diffs; NAPI_GRO_CB(p)->flush = 0; } From 497f51fc64d0bce7f1a40ebed20b2ba5090777a3 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 15 Feb 2012 04:09:46 +0000 Subject: [PATCH 0950/4025] veth: Enforce minimum size of VETH_INFO_PEER [ Upstream commit 237114384ab22c174ec4641e809f8e6cbcfce774 ] VETH_INFO_PEER carries struct ifinfomsg plus optional IFLA attributes. A minimal size of sizeof(struct ifinfomsg) must be enforced or we may risk accessing that struct beyond the limits of the netlink message. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/veth.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 4bf7c6d4ab9..6c0a3b0f0af 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -421,7 +421,9 @@ static void veth_dellink(struct net_device *dev, struct list_head *head) unregister_netdevice_queue(peer, head); } -static const struct nla_policy veth_policy[VETH_INFO_MAX + 1]; +static const struct nla_policy veth_policy[VETH_INFO_MAX + 1] = { + [VETH_INFO_PEER] = { .len = sizeof(struct ifinfomsg) }, +}; static struct rtnl_link_ops veth_link_ops = { .kind = DRV_NAME, From d6be19f41ab91acca04abdca61353245d57d9ffc Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 14 Feb 2012 10:27:09 +0000 Subject: [PATCH 0951/4025] 3c59x: shorten timer period for slave devices [ Upstream commit 3013dc0cceb9baaf25d5624034eeaa259bf99004 ] Jean Delvare reported bonding on top of 3c59x adapters was not detecting network cable removal fast enough. 3c59x indeed uses a 60 seconds timer to check link status if carrier is on, and 5 seconds if carrier is off. This patch reduces timer period to 5 seconds if device is a bonding slave. Reported-by: Jean Delvare Acked-by: Jean Delvare Acked-by: Steffen Klassert Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/3c59x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 8cc22568ebd..41afc408077 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1842,7 +1842,7 @@ vortex_timer(unsigned long data) ok = 1; } - if (!netif_carrier_ok(dev)) + if (dev->flags & IFF_SLAVE || !netif_carrier_ok(dev)) next_tick = 5*HZ; if (vp->medialock) From 23b139ecf944b097a0493262cbc04886363bd8e6 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Tue, 27 Sep 2011 15:16:08 -0400 Subject: [PATCH 0952/4025] ipv6-multicast: Fix memory leak in input path. [ Upstream commit 2015de5fe2a47086a3260802275932bfd810884e ] Have to free the skb before returning if we fail the fib lookup. Signed-off-by: Ben Greear Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6mr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 82a809901f8..450a1ffdfe0 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -2051,8 +2051,10 @@ int ip6_mr_input(struct sk_buff *skb) int err; err = ip6mr_fib_lookup(net, &fl6, &mrt); - if (err < 0) + if (err < 0) { + kfree_skb(skb); return err; + } read_lock(&mrt_lock); cache = ip6mr_cache_find(mrt, From 24190a04c967d91e718bbe7a871e418edb9424aa Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 23 Sep 2011 13:11:01 +0000 Subject: [PATCH 0953/4025] ipv6-multicast: Fix memory leak in IPv6 multicast. [ Upstream commit 67928c4041606f02725f3c95c4c0404e4532df1b ] If reg_vif_xmit cannot find a routing entry, be sure to free the skb before returning the error. Signed-off-by: Ben Greear Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6mr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 450a1ffdfe0..86e3cc10fc2 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -696,8 +696,10 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, int err; err = ip6mr_fib_lookup(net, &fl6, &mrt); - if (err < 0) + if (err < 0) { + kfree_skb(skb); return err; + } read_lock(&mrt_lock); dev->stats.tx_bytes += skb->len; From c4f2403478002bdb0a46a62f87909aeda8058d8b Mon Sep 17 00:00:00 2001 From: Li Wei Date: Tue, 8 Nov 2011 21:39:28 +0000 Subject: [PATCH 0954/4025] ipv4: fix for ip_options_rcv_srr() daddr update. [ Upstream commit b12f62efb8ec0b9523bdb6c2d412c07193086de9 ] When opt->srr_is_hit is set skb_rtable(skb) has been updated for 'nexthop' and iph->daddr should always equals to skb_rtable->rt_dst holds, We need update iph->daddr either. Signed-off-by: Li Wei Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_options.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index ec93335901d..05d20cca9d6 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -640,6 +640,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) } if (srrptr <= srrspace) { opt->srr_is_hit = 1; + iph->daddr = nexthop; opt->is_changed = 1; } return 0; From 5805d4729059f578c8283ccc44021342fbe8c93d Mon Sep 17 00:00:00 2001 From: Li Wei Date: Tue, 22 Nov 2011 23:33:10 +0000 Subject: [PATCH 0955/4025] ipv4: Save nexthop address of LSRR/SSRR option to IPCB. [ Upstream commit ac8a48106be49c422575ddc7531b776f8eb49610 ] We can not update iph->daddr in ip_options_rcv_srr(), It is too early. When some exception ocurred later (eg. in ip_forward() when goto sr_failed) we need the ip header be identical to the original one as ICMP need it. Add a field 'nexthop' in struct ip_options to save nexthop of LSRR or SSRR option. Signed-off-by: Li Wei Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/inet_sock.h | 2 ++ net/ipv4/ip_forward.c | 2 +- net/ipv4/ip_options.c | 5 +++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index caaff5f5f39..14dd9c78992 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -31,6 +31,7 @@ /** struct ip_options - IP Options * * @faddr - Saved first hop address + * @nexthop - Saved nexthop address in LSRR and SSRR * @is_data - Options in __data, rather than skb * @is_strictroute - Strict source route * @srr_is_hit - Packet destination addr was our one @@ -41,6 +42,7 @@ */ struct ip_options { __be32 faddr; + __be32 nexthop; unsigned char optlen; unsigned char srr; unsigned char rr; diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 3b34d1c8627..29a07b6c716 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -84,7 +84,7 @@ int ip_forward(struct sk_buff *skb) rt = skb_rtable(skb); - if (opt->is_strictroute && ip_hdr(skb)->daddr != rt->rt_gateway) + if (opt->is_strictroute && opt->nexthop != rt->rt_gateway) goto sr_failed; if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) && diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 05d20cca9d6..1e60f767907 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -568,12 +568,13 @@ void ip_forward_options(struct sk_buff *skb) ) { if (srrptr + 3 > srrspace) break; - if (memcmp(&ip_hdr(skb)->daddr, &optptr[srrptr-1], 4) == 0) + if (memcmp(&opt->nexthop, &optptr[srrptr-1], 4) == 0) break; } if (srrptr + 3 <= srrspace) { opt->is_changed = 1; ip_rt_get_source(&optptr[srrptr-1], skb, rt); + ip_hdr(skb)->daddr = opt->nexthop; optptr[2] = srrptr+4; } else if (net_ratelimit()) printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n"); @@ -640,7 +641,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) } if (srrptr <= srrspace) { opt->srr_is_hit = 1; - iph->daddr = nexthop; + opt->nexthop = nexthop; opt->is_changed = 1; } return 0; From ab2fd30a38e23f0b6f2e331889b31f4f6fb2378a Mon Sep 17 00:00:00 2001 From: Li Wei Date: Thu, 9 Feb 2012 21:15:25 +0000 Subject: [PATCH 0956/4025] ipv4: Fix wrong order of ip_rt_get_source() and update iph->daddr. [ Upstream commit 5dc7883f2a7c25f8df40d7479687153558cd531b ] This patch fix a bug which introduced by commit ac8a4810 (ipv4: Save nexthop address of LSRR/SSRR option to IPCB.).In that patch, we saved the nexthop of SRR in ip_option->nexthop and update iph->daddr until we get to ip_forward_options(), but we need to update it before ip_rt_get_source(), otherwise we may get a wrong src. Signed-off-by: Li Wei Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_options.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 1e60f767907..42dd1a90ede 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -573,8 +573,8 @@ void ip_forward_options(struct sk_buff *skb) } if (srrptr + 3 <= srrspace) { opt->is_changed = 1; - ip_rt_get_source(&optptr[srrptr-1], skb, rt); ip_hdr(skb)->daddr = opt->nexthop; + ip_rt_get_source(&optptr[srrptr-1], skb, rt); optptr[2] = srrptr+4; } else if (net_ratelimit()) printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n"); From dbde1bae2933018c576abcc28daf082fcd17c8d3 Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Sat, 4 Feb 2012 13:04:46 +0000 Subject: [PATCH 0957/4025] ipv4: reset flowi parameters on route connect [ Upstream commit e6b45241c57a83197e5de9166b3b0d32ac562609 ] Eric Dumazet found that commit 813b3b5db83 (ipv4: Use caller's on-stack flowi as-is in output route lookups.) that comes in 3.0 added a regression. The problem appears to be that resulting flowi4_oif is used incorrectly as input parameter to some routing lookups. The result is that when connecting to local port without listener if the IP address that is used is not on a loopback interface we incorrectly assign RTN_UNICAST to the output route because no route is matched by oif=lo. The RST packet can not be sent immediately by tcp_v4_send_reset because it expects RTN_LOCAL. So, change ip_route_connect and ip_route_newports to update the flowi4 fields that are input parameters because we do not want unnecessary binding to oif. To make it clear what are the input parameters that can be modified during lookup and to show which fields of floiw4 are reused add a new function to update the flowi4 structure: flowi4_update_output. Thanks to Yurij M. Plotnikov for providing a bug report including a program to reproduce the problem. Thanks to Eric Dumazet for tracking the problem down to tcp_v4_send_reset and providing initial fix. Reported-by: Yurij M. Plotnikov Signed-off-by: Julian Anastasov Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/flow.h | 10 ++++++++++ include/net/route.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/include/net/flow.h b/include/net/flow.h index 32359fdc7e7..e37cfda9c0f 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -90,6 +90,16 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif, fl4->fl4_dport = dport; fl4->fl4_sport = sport; } + +/* Reset some input parameters after previous lookup */ +static inline void flowi4_update_output(struct flowi4 *fl4, int oif, __u8 tos, + __be32 daddr, __be32 saddr) +{ + fl4->flowi4_oif = oif; + fl4->flowi4_tos = tos; + fl4->daddr = daddr; + fl4->saddr = saddr; +} struct flowi6 { diff --git a/include/net/route.h b/include/net/route.h index db7b3432f07..5d7aae4ab2e 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -270,6 +270,7 @@ static inline struct rtable *ip_route_connect(struct flowi4 *fl4, if (IS_ERR(rt)) return rt; ip_rt_put(rt); + flowi4_update_output(fl4, oif, tos, fl4->daddr, fl4->saddr); } security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); return ip_route_output_flow(net, fl4, sk); @@ -284,6 +285,9 @@ static inline struct rtable *ip_route_newports(struct flowi4 *fl4, struct rtable fl4->fl4_dport = dport; fl4->fl4_sport = sport; ip_rt_put(rt); + flowi4_update_output(fl4, sk->sk_bound_dev_if, + RT_CONN_FLAGS(sk), fl4->daddr, + fl4->saddr); security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); return ip_route_output_flow(sock_net(sk), fl4, sk); } From 1831cd9e1fb43c2e700e795827cb9531e679b0ef Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Fri, 10 Feb 2012 04:07:11 +0000 Subject: [PATCH 0958/4025] net: Don't proxy arp respond if iif == rt->dst.dev if private VLAN is disabled [ Upstream commit 70620c46ac2b45c24b0f22002fdf5ddd1f7daf81 ] Commit 653241 (net: RFC3069, private VLAN proxy arp support) changed the behavior of arp proxy to send arp replies back out on the interface the request came in even if the private VLAN feature is disabled. Previously we checked rt->dst.dev != skb->dev for in scenarios, when proxy arp is enabled on for the netdevice and also when individual proxy neighbour entries have been added. This patch adds the check back for the pneigh_lookup() scenario. Signed-off-by: Thomas Graf Acked-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/arp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 1d5675efcfb..d8f852dbf66 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -906,7 +906,8 @@ static int arp_process(struct sk_buff *skb) if (addr_type == RTN_UNICAST && (arp_fwd_proxy(in_dev, dev, rt) || arp_fwd_pvlan(in_dev, dev, rt, sip, tip) || - pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) { + (rt->dst.dev != dev && + pneigh_lookup(&arp_tbl, net, &tip, dev, 0)))) { n = neigh_event_ns(&arp_tbl, sha, &sip, dev); if (n) neigh_release(n); From 9f8a28dca634c4aa13127ed2ea5de94c1e47dbb7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 14 Feb 2012 10:11:59 +0000 Subject: [PATCH 0959/4025] netpoll: netpoll_poll_dev() should access dev->flags [ Upstream commit 58e05f357a039a94aa36475f8c110256f693a239 ] commit 5a698af53f (bond: service netpoll arp queue on master device) tested IFF_SLAVE flag against dev->priv_flags instead of dev->flags Signed-off-by: Eric Dumazet Cc: WANG Cong Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/netpoll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 18d9cbda3a3..05db410fd13 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -193,7 +193,7 @@ void netpoll_poll_dev(struct net_device *dev) poll_napi(dev); - if (dev->priv_flags & IFF_SLAVE) { + if (dev->flags & IFF_SLAVE) { if (dev->npinfo) { struct net_device *bond_dev = dev->master; struct sk_buff *skb; From 1609e23b0c313d58664bcc0677eadd9464c8c2cc Mon Sep 17 00:00:00 2001 From: Hagen Paul Pfeifer Date: Wed, 4 Jan 2012 17:35:26 +0000 Subject: [PATCH 0960/4025] net_sched: Bug in netem reordering [ Upstream commit eb10192447370f19a215a8c2749332afa1199d46 ] Not now, but it looks you are correct. q->qdisc is NULL until another additional qdisc is attached (beside tfifo). See 50612537e9ab2969312. The following patch should work. From: Hagen Paul Pfeifer netem: catch NULL pointer by updating the real qdisc statistic Reported-by: Vijay Subramanian Signed-off-by: Hagen Paul Pfeifer Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_netem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 87b965811c2..2f684593f35 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -381,8 +381,8 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) q->counter = 0; __skb_queue_head(&q->qdisc->q, skb); - q->qdisc->qstats.backlog += qdisc_pkt_len(skb); - q->qdisc->qstats.requeues++; + sch->qstats.backlog += qdisc_pkt_len(skb); + sch->qstats.requeues++; ret = NET_XMIT_SUCCESS; } From d67f60702b0085eb2ad772b9f7ddf728fc42d7b8 Mon Sep 17 00:00:00 2001 From: Hagen Paul Pfeifer Date: Sat, 4 Feb 2012 23:22:26 +0000 Subject: [PATCH 0961/4025] via-velocity: S3 resume fix. [ Upstream commit b530b1930bbd9d005345133f0ff0c556d2a52b19 ] Initially diagnosed on Ubuntu 11.04 with kernel 2.6.38. velocity_close is not called during a suspend / resume cycle in this driver and it has no business playing directly with power states. Signed-off-by: David Lv Acked-by: Francois Romieu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/via-velocity.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 06daa9d6fee..c7e493461e0 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -2513,9 +2513,6 @@ static int velocity_close(struct net_device *dev) if (dev->irq != 0) free_irq(dev->irq, dev); - /* Power down the chip */ - pci_set_power_state(vptr->pdev, PCI_D3hot); - velocity_free_rings(vptr); vptr->flags &= (~VELOCITY_FLAGS_OPENED); From 39b73fb4fedd23980b720d0272e5e26510cd6940 Mon Sep 17 00:00:00 2001 From: Shawn Lu Date: Sat, 4 Feb 2012 12:38:09 +0000 Subject: [PATCH 0962/4025] tcp_v4_send_reset: binding oif to iif in no sock case [ Upstream commit e2446eaab5585555a38ea0df4e01ff313dbb4ac9 ] Binding RST packet outgoing interface to incoming interface for tcp v4 when there is no socket associate with it. when sk is not NULL, using sk->sk_bound_dev_if instead. (suggested by Eric Dumazet). This has few benefits: 1. tcp_v6_send_reset already did that. 2. This helps tcp connect with SO_BINDTODEVICE set. When connection is lost, we still able to sending out RST using same interface. 3. we are sending reply, it is most likely to be succeed if iif is used Signed-off-by: Shawn Lu Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_ipv4.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 53b01258945..04c6592255a 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -650,6 +650,11 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) arg.iov[0].iov_len, IPPROTO_TCP, 0); arg.csumoffset = offsetof(struct tcphdr, check) / 2; arg.flags = (sk && inet_sk(sk)->transparent) ? IP_REPLY_ARG_NOSRCCHECK : 0; + /* When socket is gone, all binding information is lost. + * routing might fail in this case. using iif for oif to + * make sure we can deliver it + */ + arg.bound_dev_if = sk ? sk->sk_bound_dev_if : inet_iif(skb); net = dev_net(skb_dst(skb)->dev); ip_send_reply(net->ipv4.tcp_sock, skb, ip_hdr(skb)->saddr, From 382e8f84cb3db5295aa2f142a11e42eac6544ab4 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Sun, 12 Feb 2012 18:37:09 +0000 Subject: [PATCH 0963/4025] tcp: allow tcp_sacktag_one() to tag ranges not aligned with skbs [ Upstream commit cc9a672ee522d4805495b98680f4a3db5d0a0af9 ] This commit allows callers of tcp_sacktag_one() to pass in sequence ranges that do not align with skb boundaries, as tcp_shifted_skb() needs to do in an upcoming fix in this patch series. In fact, now tcp_sacktag_one() does not need to depend on an input skb at all, which makes its semantics and dependencies more clear. Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c68040fe9cd..af41044c605 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1289,25 +1289,26 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb, return in_sack; } -static u8 tcp_sacktag_one(struct sk_buff *skb, struct sock *sk, - struct tcp_sacktag_state *state, +/* Mark the given newly-SACKed range as such, adjusting counters and hints. */ +static u8 tcp_sacktag_one(struct sock *sk, + struct tcp_sacktag_state *state, u8 sacked, + u32 start_seq, u32 end_seq, int dup_sack, int pcount) { struct tcp_sock *tp = tcp_sk(sk); - u8 sacked = TCP_SKB_CB(skb)->sacked; int fack_count = state->fack_count; /* Account D-SACK for retransmitted packet. */ if (dup_sack && (sacked & TCPCB_RETRANS)) { if (tp->undo_marker && tp->undo_retrans && - after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker)) + after(end_seq, tp->undo_marker)) tp->undo_retrans--; if (sacked & TCPCB_SACKED_ACKED) state->reord = min(fack_count, state->reord); } /* Nothing to do; acked frame is about to be dropped (was ACKed). */ - if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) + if (!after(end_seq, tp->snd_una)) return sacked; if (!(sacked & TCPCB_SACKED_ACKED)) { @@ -1326,13 +1327,13 @@ static u8 tcp_sacktag_one(struct sk_buff *skb, struct sock *sk, /* New sack for not retransmitted frame, * which was in hole. It is reordering. */ - if (before(TCP_SKB_CB(skb)->seq, + if (before(start_seq, tcp_highest_sack_seq(tp))) state->reord = min(fack_count, state->reord); /* SACK enhanced F-RTO (RFC4138; Appendix B) */ - if (!after(TCP_SKB_CB(skb)->end_seq, tp->frto_highmark)) + if (!after(end_seq, tp->frto_highmark)) state->flag |= FLAG_ONLY_ORIG_SACKED; } @@ -1350,8 +1351,7 @@ static u8 tcp_sacktag_one(struct sk_buff *skb, struct sock *sk, /* Lost marker hint past SACKed? Tweak RFC3517 cnt */ if (!tcp_is_fack(tp) && (tp->lost_skb_hint != NULL) && - before(TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(tp->lost_skb_hint)->seq)) + before(start_seq, TCP_SKB_CB(tp->lost_skb_hint)->seq)) tp->lost_cnt_hint += pcount; if (fack_count > tp->fackets_out) @@ -1407,7 +1407,11 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, } /* We discard results */ - tcp_sacktag_one(skb, sk, state, dup_sack, pcount); + tcp_sacktag_one(sk, state, + TCP_SKB_CB(skb)->sacked, + TCP_SKB_CB(skb)->seq, + TCP_SKB_CB(skb)->end_seq, + dup_sack, pcount); /* Difference in this won't matter, both ACKed by the same cumul. ACK */ TCP_SKB_CB(prev)->sacked |= (TCP_SKB_CB(skb)->sacked & TCPCB_EVER_RETRANS); @@ -1646,10 +1650,14 @@ static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk, break; if (in_sack) { - TCP_SKB_CB(skb)->sacked = tcp_sacktag_one(skb, sk, - state, - dup_sack, - tcp_skb_pcount(skb)); + TCP_SKB_CB(skb)->sacked = + tcp_sacktag_one(sk, + state, + TCP_SKB_CB(skb)->sacked, + TCP_SKB_CB(skb)->seq, + TCP_SKB_CB(skb)->end_seq, + dup_sack, + tcp_skb_pcount(skb)); if (!before(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(tp))) From dd31c1ce7ef7b363215081fde02f13bf3e50b5a1 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Sun, 12 Feb 2012 18:37:10 +0000 Subject: [PATCH 0964/4025] tcp: fix range tcp_shifted_skb() passes to tcp_sacktag_one() [ Upstream commit daef52bab1fd26e24e8e9578f8fb33ba1d0cb412 ] Fix the newly-SACKed range to be the range of newly-shifted bytes. Previously - since 832d11c5cd076abc0aa1eaf7be96c81d1a59ce41 - tcp_shifted_skb() incorrectly called tcp_sacktag_one() with the start and end sequence numbers of the skb it passes in set to the range just beyond the range that is newly-SACKed. This commit also removes a special-case adjustment to lost_cnt_hint in tcp_shifted_skb() since the pre-existing adjustment of lost_cnt_hint in tcp_sacktag_one() now properly handles this things now that the correct start sequence number is passed in. Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index af41044c605..78689e56936 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1370,6 +1370,9 @@ static u8 tcp_sacktag_one(struct sock *sk, return sacked; } +/* Shift newly-SACKed bytes from this skb to the immediately previous + * already-SACKed sk_buff. Mark the newly-SACKed bytes as such. + */ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, struct tcp_sacktag_state *state, unsigned int pcount, int shifted, int mss, @@ -1377,12 +1380,11 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *prev = tcp_write_queue_prev(sk, skb); + u32 start_seq = TCP_SKB_CB(skb)->seq; /* start of newly-SACKed */ + u32 end_seq = start_seq + shifted; /* end of newly-SACKed */ BUG_ON(!pcount); - if (skb == tp->lost_skb_hint) - tp->lost_cnt_hint += pcount; - TCP_SKB_CB(prev)->end_seq += shifted; TCP_SKB_CB(skb)->seq += shifted; @@ -1406,12 +1408,11 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, skb_shinfo(skb)->gso_type = 0; } - /* We discard results */ - tcp_sacktag_one(sk, state, - TCP_SKB_CB(skb)->sacked, - TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(skb)->end_seq, - dup_sack, pcount); + /* Adjust counters and hints for the newly sacked sequence range but + * discard the return value since prev is already marked. + */ + tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked, + start_seq, end_seq, dup_sack, pcount); /* Difference in this won't matter, both ACKed by the same cumul. ACK */ TCP_SKB_CB(prev)->sacked |= (TCP_SKB_CB(skb)->sacked & TCPCB_EVER_RETRANS); From 623f1904ef55789082259573bb6248df5fea3d92 Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Mon, 13 Feb 2012 20:22:08 +0000 Subject: [PATCH 0965/4025] tcp: fix tcp_shifted_skb() adjustment of lost_cnt_hint for FACK [ Upstream commit 0af2a0d0576205dda778d25c6c344fc6508fc81d ] This commit ensures that lost_cnt_hint is correctly updated in tcp_shifted_skb() for FACK TCP senders. The lost_cnt_hint adjustment in tcp_sacktag_one() only applies to non-FACK senders, so FACK senders need their own adjustment. This applies the spirit of 1e5289e121372a3494402b1b131b41bfe1cf9b7f - except now that the sequence range passed into tcp_sacktag_one() is correct we need only have a special case adjustment for FACK. Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 78689e56936..ee08f11ff21 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -1385,6 +1385,10 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, BUG_ON(!pcount); + /* Adjust hint for FACK. Non-FACK is handled in tcp_sacktag_one(). */ + if (tcp_is_fack(tp) && (skb == tp->lost_skb_hint)) + tp->lost_cnt_hint += pcount; + TCP_SKB_CB(prev)->end_seq += shifted; TCP_SKB_CB(skb)->seq += shifted; From bebee22bcbf0026f92141990972bd5863ef9b69c Mon Sep 17 00:00:00 2001 From: Flavio Leitner Date: Mon, 24 Oct 2011 02:56:38 -0400 Subject: [PATCH 0966/4025] route: fix ICMP redirect validation [ Upstream commit 7cc9150ebe8ec06cafea9f1c10d92ddacf88d8ae ] The commit f39925dbde7788cfb96419c0f092b086aa325c0f (ipv4: Cache learned redirect information in inetpeer.) removed some ICMP packet validations which are required by RFC 1122, section 3.2.2.2: ... A Redirect message SHOULD be silently discarded if the new gateway address it specifies is not on the same connected (sub-) net through which the Redirect arrived [INTRO:2, Appendix A], or if the source of the Redirect is not the current first-hop gateway for the specified destination (see Section 3.3.1). Signed-off-by: Flavio Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/route.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 65ff2e52a14..f881be2983c 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1373,7 +1373,12 @@ static void rt_del(unsigned hash, struct rtable *rt) void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, __be32 saddr, struct net_device *dev) { + int s, i; struct in_device *in_dev = __in_dev_get_rcu(dev); + struct rtable *rt; + __be32 skeys[2] = { saddr, 0 }; + int ikeys[2] = { dev->ifindex, 0 }; + struct flowi4 fl4; struct inet_peer *peer; struct net *net; @@ -1396,13 +1401,34 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, goto reject_redirect; } - peer = inet_getpeer_v4(daddr, 1); - if (peer) { - peer->redirect_learned.a4 = new_gw; + memset(&fl4, 0, sizeof(fl4)); + fl4.daddr = daddr; + for (s = 0; s < 2; s++) { + for (i = 0; i < 2; i++) { + fl4.flowi4_oif = ikeys[i]; + fl4.saddr = skeys[s]; + rt = __ip_route_output_key(net, &fl4); + if (IS_ERR(rt)) + continue; - inet_putpeer(peer); + if (rt->dst.error || rt->dst.dev != dev || + rt->rt_gateway != old_gw) { + ip_rt_put(rt); + continue; + } - atomic_inc(&__rt_peer_genid); + if (!rt->peer) + rt_bind_peer(rt, rt->rt_dst, 1); + + peer = rt->peer; + if (peer) { + peer->redirect_learned.a4 = new_gw; + atomic_inc(&__rt_peer_genid); + } + + ip_rt_put(rt); + return; + } } return; From 42ab5316ddcaa0de23e88e8a3d363c767b9ab0b3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 18 Nov 2011 15:24:32 -0500 Subject: [PATCH 0967/4025] ipv4: fix redirect handling [ Upstream commit 9cc20b268a5a14f5e57b8ad405a83513ab0d78dc ] commit f39925dbde77 (ipv4: Cache learned redirect information in inetpeer.) introduced a regression in ICMP redirect handling. It assumed ipv4_dst_check() would be called because all possible routes were attached to the inetpeer we modify in ip_rt_redirect(), but thats not true. commit 7cc9150ebe (route: fix ICMP redirect validation) tried to fix this but solution was not complete. (It fixed only one route) So we must lookup existing routes (including different TOS values) and call check_peer_redir() on them. Reported-by: Ivan Zahariev Signed-off-by: Eric Dumazet CC: Flavio Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/route.c | 109 +++++++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 51 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index f881be2983c..6b95f74a91d 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1369,16 +1369,41 @@ static void rt_del(unsigned hash, struct rtable *rt) spin_unlock_bh(rt_hash_lock_addr(hash)); } +static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) +{ + struct rtable *rt = (struct rtable *) dst; + __be32 orig_gw = rt->rt_gateway; + struct neighbour *n, *old_n; + + dst_confirm(&rt->dst); + + rt->rt_gateway = peer->redirect_learned.a4; + n = __arp_bind_neighbour(&rt->dst, rt->rt_gateway); + if (IS_ERR(n)) + return PTR_ERR(n); + old_n = xchg(&rt->dst._neighbour, n); + if (old_n) + neigh_release(old_n); + if (!n || !(n->nud_state & NUD_VALID)) { + if (n) + neigh_event_send(n, NULL); + rt->rt_gateway = orig_gw; + return -EAGAIN; + } else { + rt->rt_flags |= RTCF_REDIRECTED; + call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); + } + return 0; +} + /* called in rcu_read_lock() section */ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, __be32 saddr, struct net_device *dev) { int s, i; struct in_device *in_dev = __in_dev_get_rcu(dev); - struct rtable *rt; __be32 skeys[2] = { saddr, 0 }; int ikeys[2] = { dev->ifindex, 0 }; - struct flowi4 fl4; struct inet_peer *peer; struct net *net; @@ -1401,33 +1426,42 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, goto reject_redirect; } - memset(&fl4, 0, sizeof(fl4)); - fl4.daddr = daddr; for (s = 0; s < 2; s++) { for (i = 0; i < 2; i++) { - fl4.flowi4_oif = ikeys[i]; - fl4.saddr = skeys[s]; - rt = __ip_route_output_key(net, &fl4); - if (IS_ERR(rt)) - continue; - - if (rt->dst.error || rt->dst.dev != dev || - rt->rt_gateway != old_gw) { - ip_rt_put(rt); - continue; - } + unsigned int hash; + struct rtable __rcu **rthp; + struct rtable *rt; + + hash = rt_hash(daddr, skeys[s], ikeys[i], rt_genid(net)); + + rthp = &rt_hash_table[hash].chain; + + while ((rt = rcu_dereference(*rthp)) != NULL) { + rthp = &rt->dst.rt_next; + + if (rt->rt_key_dst != daddr || + rt->rt_key_src != skeys[s] || + rt->rt_oif != ikeys[i] || + rt_is_input_route(rt) || + rt_is_expired(rt) || + !net_eq(dev_net(rt->dst.dev), net) || + rt->dst.error || + rt->dst.dev != dev || + rt->rt_gateway != old_gw) + continue; - if (!rt->peer) - rt_bind_peer(rt, rt->rt_dst, 1); + if (!rt->peer) + rt_bind_peer(rt, rt->rt_dst, 1); - peer = rt->peer; - if (peer) { - peer->redirect_learned.a4 = new_gw; - atomic_inc(&__rt_peer_genid); + peer = rt->peer; + if (peer) { + if (peer->redirect_learned.a4 != new_gw) { + peer->redirect_learned.a4 = new_gw; + atomic_inc(&__rt_peer_genid); + } + check_peer_redir(&rt->dst, peer); + } } - - ip_rt_put(rt); - return; } } return; @@ -1715,33 +1749,6 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu) } } -static int check_peer_redir(struct dst_entry *dst, struct inet_peer *peer) -{ - struct rtable *rt = (struct rtable *) dst; - __be32 orig_gw = rt->rt_gateway; - struct neighbour *n, *old_n; - - dst_confirm(&rt->dst); - - rt->rt_gateway = peer->redirect_learned.a4; - n = __arp_bind_neighbour(&rt->dst, rt->rt_gateway); - if (IS_ERR(n)) - return PTR_ERR(n); - old_n = xchg(&rt->dst._neighbour, n); - if (old_n) - neigh_release(old_n); - if (!n || !(n->nud_state & NUD_VALID)) { - if (n) - neigh_event_send(n, NULL); - rt->rt_gateway = orig_gw; - return -EAGAIN; - } else { - rt->rt_flags |= RTCF_REDIRECTED; - call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); - } - return 0; -} - static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) { struct rtable *rt = (struct rtable *) dst; From f887e1ac4775bd066690fd7c64b68a18b0b70b19 Mon Sep 17 00:00:00 2001 From: Bruno Thomsen Date: Tue, 21 Feb 2012 23:41:37 +0100 Subject: [PATCH 0968/4025] USB: Added Kamstrup VID/PIDs to cp210x serial driver. commit c6c1e4491dc8d1ed2509fa6aacffa7f34614fc38 upstream. Signed-off-by: Bruno Thomsen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index a5152379cb4..33d25d4e680 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -136,6 +136,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x16DC, 0x0011) }, /* W-IE-NE-R Plein & Baus GmbH RCM Remote Control for MARATON Power Supply */ { USB_DEVICE(0x16DC, 0x0012) }, /* W-IE-NE-R Plein & Baus GmbH MPOD Multi Channel Power Supply */ { USB_DEVICE(0x16DC, 0x0015) }, /* W-IE-NE-R Plein & Baus GmbH CML Control, Monitoring and Data Logger */ + { USB_DEVICE(0x17A8, 0x0001) }, /* Kamstrup Optical Eye/3-wire */ + { USB_DEVICE(0x17A8, 0x0005) }, /* Kamstrup M-Bus Master MultiPort 250D */ { USB_DEVICE(0x17F4, 0xAAAA) }, /* Wavesense Jazz blood glucose meter */ { USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */ { USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */ From e4388320d16815d4495358a9b9950263ba052157 Mon Sep 17 00:00:00 2001 From: Rui li Date: Tue, 14 Feb 2012 10:35:01 +0800 Subject: [PATCH 0969/4025] USB: option: cleanup zte 3g-dongle's pid in option.c commit b9e44fe5ecda4158c22bc1ea4bffa378a4f83f65 upstream. 1. Remove all old mass-storage ids's pid: 0x0026,0x0053,0x0098,0x0099,0x0149,0x0150,0x0160; 2. As the pid from 0x1401 to 0x1510 which have not surely assigned to use for serial-port or mass-storage port,so i think it should be removed now, and will re-add after it have assigned in future; 3. sort the pid to WCDMA and CDMA. Signed-off-by: Rui li Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 143 ++++-------------------------------- 1 file changed, 13 insertions(+), 130 deletions(-) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 338d082525b..68fa8c7c162 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -788,7 +788,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0012, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0013, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0016, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0017, 0xff, 0xff, 0xff), @@ -803,7 +802,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0024, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0025, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, - /* { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0026, 0xff, 0xff, 0xff) }, */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0028, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0029, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0030, 0xff, 0xff, 0xff) }, @@ -828,7 +826,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0051, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0052, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - /* { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0053, 0xff, 0xff, 0xff) }, */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0054, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0055, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, @@ -836,7 +833,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0057, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0058, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0061, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0062, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0063, 0xff, 0xff, 0xff), @@ -846,7 +842,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0066, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0067, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0069, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0070, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0076, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0077, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0078, 0xff, 0xff, 0xff) }, @@ -865,8 +860,6 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0095, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0096, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0097, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0098, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0099, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0104, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0105, 0xff, 0xff, 0xff) }, @@ -887,28 +880,18 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0143, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0144, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0145, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0146, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0147, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0148, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0149, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0150, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0151, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0153, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0155, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0156, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0157, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0158, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0159, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0160, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0161, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0164, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0168, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0170, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0176, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) }, @@ -1083,127 +1066,27 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1298, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1299, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1300, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1401, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1402, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1403, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1404, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1405, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1406, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1407, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1408, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1409, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1410, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1411, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1412, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1413, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1414, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1415, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1416, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1417, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1418, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1419, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1420, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1421, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1422, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1423, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1424, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1425, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1426, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1427, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1428, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1429, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1430, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1431, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1432, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1433, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1434, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1435, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1436, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1437, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1438, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1439, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1440, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1441, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1442, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1443, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1444, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1445, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1446, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1447, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1448, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1449, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1450, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1451, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1452, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1453, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1454, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1455, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1456, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1457, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1458, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1459, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1460, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1461, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1462, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1463, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1464, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1465, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1466, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1467, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1468, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1469, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1470, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1471, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1472, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1473, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1474, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1475, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1476, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1477, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1478, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1479, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1480, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1481, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1482, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1483, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1484, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1485, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1486, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1487, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1488, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1489, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1490, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1491, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1492, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1493, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1494, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1495, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1496, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1497, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1498, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1499, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1500, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1501, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1502, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1503, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1504, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1505, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1506, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1507, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1508, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1509, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1510, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, + 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0014, 0xff, 0xff, 0xff) }, /* ZTE CDMA products */ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0027, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0059, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0060, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0070, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0073, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0094, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0130, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0133, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0141, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff, - 0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0147, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0152, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0168, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0170, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0176, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) }, From 4ee72bce4407abc34f5efbd70e6d61b857b9adbc Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 20 Feb 2012 09:31:57 +0100 Subject: [PATCH 0970/4025] USB: Serial: ti_usb_3410_5052: Add Abbot Diabetes Care cable id commit 7fd25702ba616d9ba56e2a625472f29e5aff25ee upstream. This USB-serial cable with mini stereo jack enumerates as: Bus 001 Device 004: ID 1a61:3410 Abbott Diabetes Care It is a TI3410 inside. Signed-off-by: Andrew Lunn Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ti_usb_3410_5052.c | 6 ++++-- drivers/usb/serial/ti_usb_3410_5052.h | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index ea8445689c8..21c82b043d1 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -165,7 +165,7 @@ static unsigned int product_5052_count; /* the array dimension is the number of default entries plus */ /* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */ /* null entry */ -static struct usb_device_id ti_id_table_3410[13+TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_3410[14+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -179,6 +179,7 @@ static struct usb_device_id ti_id_table_3410[13+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, + { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, }; static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { @@ -188,7 +189,7 @@ static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, }; -static struct usb_device_id ti_id_table_combined[17+2*TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_combined[18+2*TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -206,6 +207,7 @@ static struct usb_device_id ti_id_table_combined[17+2*TI_EXTRA_VID_PID_COUNT+1] { USB_DEVICE(IBM_VENDOR_ID, IBM_4543_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, + { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, { } }; diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h index 2aac1953993..f140f1b9d5c 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.h +++ b/drivers/usb/serial/ti_usb_3410_5052.h @@ -49,6 +49,10 @@ #define MTS_MT9234ZBA_PRODUCT_ID 0xF115 #define MTS_MT9234ZBAOLD_PRODUCT_ID 0x0319 +/* Abbott Diabetics vendor and product ids */ +#define ABBOTT_VENDOR_ID 0x1a61 +#define ABBOTT_PRODUCT_ID 0x3410 + /* Commands */ #define TI_GET_VERSION 0x01 #define TI_GET_PORT_STATUS 0x02 From 662785063f41640379bb9537b15074f8526f33be Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 5 Jan 2012 16:28:54 -0800 Subject: [PATCH 0971/4025] USB: Remove duplicate USB 3.0 hub feature #defines. commit d9f5343e35d9138432657202afa8e3ddb2ade360 upstream. Somehow we ended up with duplicate hub feature #defines in ch11.h. Tatyana Brokhman first created the USB 3.0 hub feature macros in 2.6.38 with commit 0eadcc09203349b11ca477ec367079b23d32ab91 "usb: USB3.0 ch11 definitions". In 2.6.39, I modified a patch from John Youn that added similar macros in a different place in the same file, and committed dbe79bbe9dcb22cb3651c46f18943477141ca452 "USB 3.0 Hub Changes". Some of the #defines used different names for the same values. Others used exactly the same names with the same values, like these gems: #define USB_PORT_FEAT_BH_PORT_RESET 28 ... #define USB_PORT_FEAT_BH_PORT_RESET 28 According to my very geeky husband (who looked it up in the C99 spec), it is allowed to have object-like macros with duplicate names as long as the replacement list is exactly the same. However, he recalled that some compilers will give warnings when they find duplicate macros. It's probably best to remove the duplicates in the stable tree, so that the code compiles for everyone. The macros are now fixed to move the feature requests that are specific to USB 3.0 hubs into a new section (out of the USB 2.0 hub feature section), and use the most common macro name. This patch should be backported to 2.6.39. Signed-off-by: Sarah Sharp Cc: Tatyana Brokhman Cc: John Youn Cc: Jamey Sharp Signed-off-by: Greg Kroah-Hartman --- include/linux/usb/ch11.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/include/linux/usb/ch11.h b/include/linux/usb/ch11.h index 4ebaf082417..1eb735b53fc 100644 --- a/include/linux/usb/ch11.h +++ b/include/linux/usb/ch11.h @@ -62,12 +62,6 @@ #define USB_PORT_FEAT_TEST 21 #define USB_PORT_FEAT_INDICATOR 22 #define USB_PORT_FEAT_C_PORT_L1 23 -#define USB_PORT_FEAT_C_PORT_LINK_STATE 25 -#define USB_PORT_FEAT_C_PORT_CONFIG_ERROR 26 -#define USB_PORT_FEAT_PORT_REMOTE_WAKE_MASK 27 -#define USB_PORT_FEAT_BH_PORT_RESET 28 -#define USB_PORT_FEAT_C_BH_PORT_RESET 29 -#define USB_PORT_FEAT_FORCE_LINKPM_ACCEPT 30 /* * Port feature selectors added by USB 3.0 spec. @@ -76,8 +70,8 @@ #define USB_PORT_FEAT_LINK_STATE 5 #define USB_PORT_FEAT_U1_TIMEOUT 23 #define USB_PORT_FEAT_U2_TIMEOUT 24 -#define USB_PORT_FEAT_C_LINK_STATE 25 -#define USB_PORT_FEAT_C_CONFIG_ERR 26 +#define USB_PORT_FEAT_C_PORT_LINK_STATE 25 +#define USB_PORT_FEAT_C_PORT_CONFIG_ERROR 26 #define USB_PORT_FEAT_REMOTE_WAKE_MASK 27 #define USB_PORT_FEAT_BH_PORT_RESET 28 #define USB_PORT_FEAT_C_BH_PORT_RESET 29 From cce0edb3ee6cdbbac6ef1bc013fe415401d820bd Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Tue, 7 Feb 2012 15:11:46 -0800 Subject: [PATCH 0972/4025] USB: Fix handoff when BIOS disables host PCI device. commit cab928ee1f221c9cc48d6615070fefe2e444384a upstream. On some systems with an Intel Panther Point xHCI host controller, the BIOS disables the xHCI PCI device during boot, and switches the xHCI ports over to EHCI. This allows the BIOS to access USB devices without having xHCI support. The downside is that the xHCI BIOS handoff mechanism will fail because memory mapped I/O is not enabled for the disabled PCI device. Jesse Barnes says this is expected behavior. The PCI core will enable BARs before quirks run, but it will leave it in an undefined state, and it may not have memory mapped I/O enabled. Make the generic USB quirk handler call pci_enable_device() to re-enable MMIO, and call pci_disable_device() once the host-specific BIOS handoff is finished. This will balance the ref counts in the PCI core. When the PCI probe function is called, usb_hcd_pci_probe() will call pci_enable_device() again. This should be back ported to kernels as old as 2.6.31. That was the first kernel with xHCI support, and no one has complained about BIOS handoffs failing due to memory mapped I/O being disabled on other hosts (EHCI, UHCI, or OHCI). Signed-off-by: Sarah Sharp Acked-by: Oliver Neukum Cc: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/pci-quirks.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 20f2f216347..3f387b832fe 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -871,7 +871,17 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) */ if (pdev->vendor == 0x184e) /* vendor Netlogic */ return; + if (pdev->class != PCI_CLASS_SERIAL_USB_UHCI && + pdev->class != PCI_CLASS_SERIAL_USB_OHCI && + pdev->class != PCI_CLASS_SERIAL_USB_EHCI && + pdev->class != PCI_CLASS_SERIAL_USB_XHCI) + return; + if (pci_enable_device(pdev) < 0) { + dev_warn(&pdev->dev, "Can't enable PCI device, " + "BIOS handoff failed.\n"); + return; + } if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI) quirk_usb_handoff_uhci(pdev); else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI) @@ -880,5 +890,6 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev) quirk_usb_disable_ehci(pdev); else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI) quirk_usb_handoff_xhci(pdev); + pci_disable_device(pdev); } DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); From afa0cb70236ea5023e3616edc95045f4742afb24 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 9 Feb 2012 14:43:44 -0800 Subject: [PATCH 0973/4025] xhci: Fix oops caused by more USB2 ports than USB3 ports. commit 3278a55a1aebe2bbd47fbb5196209e5326a88b56 upstream. The code to set the device removable bits in the USB 2.0 roothub descriptor was accidentally looking at the USB 3.0 port registers instead of the USB 2.0 registers. This can cause an oops if there are more USB 2.0 registers than USB 3.0 registers. This should be backported to kernels as old as 2.6.39, that contain the commit 4bbb0ace9a3de8392527e3c87926309d541d3b00 "xhci: Return a USB 3.0 hub descriptor for USB3 roothub." Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index ce9f974dac0..7520ebb4454 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -75,7 +75,7 @@ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, */ memset(port_removable, 0, sizeof(port_removable)); for (i = 0; i < ports; i++) { - portsc = xhci_readl(xhci, xhci->usb3_ports[i]); + portsc = xhci_readl(xhci, xhci->usb2_ports[i]); /* If a device is removable, PORTSC reports a 0, same as in the * hub descriptor DeviceRemovable bits. */ From 5652021f25ea82e6fc30d5b970e30aafe7a6f367 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Mon, 13 Feb 2012 14:42:11 -0800 Subject: [PATCH 0974/4025] xhci: Fix encoding for HS bulk/control NAK rate. commit 340a3504fd39dad753ba908fb6f894ee81fc3ae2 upstream. The xHCI 0.96 spec says that HS bulk and control endpoint NAK rate must be encoded as an exponent of two number of microframes. The endpoint descriptor has the NAK rate encoded in number of microframes. We were just copying the value from the endpoint descriptor into the endpoint context interval field, which was not correct. This lead to the VIA host rejecting the add of a bulk OUT endpoint from any USB 2.0 mass storage device. The fix is to use the correct encoding. Refactor the code to convert number of frames to an exponential number of microframes, and make sure we convert the number of microframes in HS bulk and control endpoints to an exponent. This should be back ported to kernels as old as 2.6.31, that contain the commit dfa49c4ad120a784ef1ff0717168aa79f55a483a "USB: xhci - fix math in xhci_get_endpoint_interval" Signed-off-by: Sarah Sharp Tested-by: Felipe Contreras Suggested-by: Andiry Xu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-mem.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index ffeee575fd2..64fbf6f26f9 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1002,26 +1002,42 @@ static unsigned int xhci_parse_exponent_interval(struct usb_device *udev, } /* - * Convert bInterval expressed in frames (in 1-255 range) to exponent of + * Convert bInterval expressed in microframes (in 1-255 range) to exponent of * microframes, rounded down to nearest power of 2. */ -static unsigned int xhci_parse_frame_interval(struct usb_device *udev, - struct usb_host_endpoint *ep) +static unsigned int xhci_microframes_to_exponent(struct usb_device *udev, + struct usb_host_endpoint *ep, unsigned int desc_interval, + unsigned int min_exponent, unsigned int max_exponent) { unsigned int interval; - interval = fls(8 * ep->desc.bInterval) - 1; - interval = clamp_val(interval, 3, 10); - if ((1 << interval) != 8 * ep->desc.bInterval) + interval = fls(desc_interval) - 1; + interval = clamp_val(interval, min_exponent, max_exponent); + if ((1 << interval) != desc_interval) dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes, ep desc says %d microframes\n", ep->desc.bEndpointAddress, 1 << interval, - 8 * ep->desc.bInterval); + desc_interval); return interval; } +static unsigned int xhci_parse_microframe_interval(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + return xhci_microframes_to_exponent(udev, ep, + ep->desc.bInterval, 0, 15); +} + + +static unsigned int xhci_parse_frame_interval(struct usb_device *udev, + struct usb_host_endpoint *ep) +{ + return xhci_microframes_to_exponent(udev, ep, + ep->desc.bInterval * 8, 3, 10); +} + /* Return the polling or NAK interval. * * The polling interval is expressed in "microframes". If xHCI's Interval field @@ -1040,7 +1056,7 @@ static unsigned int xhci_get_endpoint_interval(struct usb_device *udev, /* Max NAK rate */ if (usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_bulk(&ep->desc)) { - interval = ep->desc.bInterval; + interval = xhci_parse_microframe_interval(udev, ep); break; } /* Fall through - SS and HS isoc/int have same decoding */ From ac29c0aeddba8f83dd73ec8a51c72f268c9b7b81 Mon Sep 17 00:00:00 2001 From: Elric Fu Date: Sat, 18 Feb 2012 13:32:27 +0800 Subject: [PATCH 0975/4025] USB: Set hub depth after USB3 hub reset commit a45aa3b30583e7d54e7cf4fbcd0aa699348a6e5c upstream. The superspeed device attached to a USB 3.0 hub(such as VIA's) doesn't respond the address device command after resume. The root cause is the superspeed hub will miss the Hub Depth value that is used as an offset into the route string to locate the bits it uses to determine the downstream port number after reset, and all packets can't be routed to the device attached to the superspeed hub. Hub driver sends a Set Hub Depth request to the superspeed hub except for USB 3.0 root hub when the hub is initialized and doesn't send the request again after reset due to the resume process. So moving the code that sends the Set Hub Depth request to the superspeed hub from hub_configure() to hub_activate() is to cover those situations include initialization and reset. The patch should be backported to kernels as old as 2.6.39. Signed-off-by: Elric Fu Signed-off-by: Sarah Sharp Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hub.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 210e3597091..3776ddf0c75 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -705,10 +705,26 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) if (type == HUB_INIT3) goto init3; - /* After a resume, port power should still be on. + /* The superspeed hub except for root hub has to use Hub Depth + * value as an offset into the route string to locate the bits + * it uses to determine the downstream port number. So hub driver + * should send a set hub depth request to superspeed hub after + * the superspeed hub is set configuration in initialization or + * reset procedure. + * + * After a resume, port power should still be on. * For any other type of activation, turn it on. */ if (type != HUB_RESUME) { + if (hdev->parent && hub_is_superspeed(hdev)) { + ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), + HUB_SET_DEPTH, USB_RT_HUB, + hdev->level - 1, 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + if (ret < 0) + dev_err(hub->intfdev, + "set hub depth failed\n"); + } /* Speed up system boot by using a delayed_work for the * hub's initial power-up delays. This is pretty awkward @@ -987,18 +1003,6 @@ static int hub_configure(struct usb_hub *hub, goto fail; } - if (hub_is_superspeed(hdev) && (hdev->parent != NULL)) { - ret = usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), - HUB_SET_DEPTH, USB_RT_HUB, - hdev->level - 1, 0, NULL, 0, - USB_CTRL_SET_TIMEOUT); - - if (ret < 0) { - message = "can't set hub depth"; - goto fail; - } - } - /* Request the entire hub descriptor. * hub->descriptor can handle USB_MAXCHILDREN ports, * but the hub can/will return fewer bytes here. From 454d147172263d0b022f32b86336f92243f89158 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 13 Feb 2012 13:47:25 -0800 Subject: [PATCH 0976/4025] i387: math_state_restore() isn't called from asm commit be98c2cdb15ba26148cd2bd58a857d4f7759ed38 upstream. It was marked asmlinkage for some really old and stale legacy reasons. Fix that and the equally stale comment. Noticed when debugging the irq_fpu_usable() bugs. Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/i387.h | 2 +- arch/x86/kernel/traps.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index c9e09ea0564..cba14321078 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -29,7 +29,7 @@ extern unsigned int sig_xstate_size; extern void fpu_init(void); extern void mxcsr_feature_mask_init(void); extern int init_fpu(struct task_struct *child); -extern asmlinkage void math_state_restore(void); +extern void math_state_restore(void); extern void __math_state_restore(void); extern int dump_fpu(struct pt_regs *, struct user_i387_struct *); diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index b9b67166f9d..5878de3fb08 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -745,10 +745,10 @@ void __math_state_restore(void) * Careful.. There are problems with IBM-designed IRQ13 behaviour. * Don't touch unless you *really* know how it works. * - * Must be called with kernel preemption disabled (in this case, - * local interrupts are disabled at the call-site in entry.S). + * Must be called with kernel preemption disabled (eg with local + * local interrupts as in the case of do_device_not_available). */ -asmlinkage void math_state_restore(void) +void math_state_restore(void) { struct thread_info *thread = current_thread_info(); struct task_struct *tsk = thread->task; From 00717d1f238918b105ed561a466fcd4271206fb2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 13 Feb 2012 13:56:14 -0800 Subject: [PATCH 0977/4025] i387: make irq_fpu_usable() tests more robust commit 5b1cbac37798805c1fee18c8cebe5c0a13975b17 upstream. Some code - especially the crypto layer - wants to use the x86 FP/MMX/AVX register set in what may be interrupt (typically softirq) context. That *can* be ok, but the tests for when it was ok were somewhat suspect. We cannot touch the thread-specific status bits either, so we'd better check that we're not going to try to save FP state or anything like that. Now, it may be that the TS bit is always cleared *before* we set the USEDFPU bit (and only set when we had already cleared the USEDFP before), so the TS bit test may actually have been sufficient, but it certainly was not obviously so. So this explicitly verifies that we will not touch the TS_USEDFPU bit, and adds a few related sanity-checks. Because it seems that somehow AES-NI is corrupting user FP state. The cause is not clear, and this patch doesn't fix it, but while debugging it I really wanted the code to be more obviously correct and robust. Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/i387.h | 54 +++++++++++++++++++++++++++++++------ arch/x86/kernel/traps.c | 1 + 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index cba14321078..a4365829e38 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -307,9 +307,54 @@ static inline void __clear_fpu(struct task_struct *tsk) } } +/* + * Were we in an interrupt that interrupted kernel mode? + * + * We can do a kernel_fpu_begin/end() pair *ONLY* if that + * pair does nothing at all: TS_USEDFPU must be clear (so + * that we don't try to save the FPU state), and TS must + * be set (so that the clts/stts pair does nothing that is + * visible in the interrupted kernel thread). + */ +static inline bool interrupted_kernel_fpu_idle(void) +{ + return !(current_thread_info()->status & TS_USEDFPU) && + (read_cr0() & X86_CR0_TS); +} + +/* + * Were we in user mode (or vm86 mode) when we were + * interrupted? + * + * Doing kernel_fpu_begin/end() is ok if we are running + * in an interrupt context from user mode - we'll just + * save the FPU state as required. + */ +static inline bool interrupted_user_mode(void) +{ + struct pt_regs *regs = get_irq_regs(); + return regs && user_mode_vm(regs); +} + +/* + * Can we use the FPU in kernel mode with the + * whole "kernel_fpu_begin/end()" sequence? + * + * It's always ok in process context (ie "not interrupt") + * but it is sometimes ok even from an irq. + */ +static inline bool irq_fpu_usable(void) +{ + return !in_interrupt() || + interrupted_user_mode() || + interrupted_kernel_fpu_idle(); +} + static inline void kernel_fpu_begin(void) { struct thread_info *me = current_thread_info(); + + WARN_ON_ONCE(!irq_fpu_usable()); preempt_disable(); if (me->status & TS_USEDFPU) __save_init_fpu(me->task); @@ -323,14 +368,6 @@ static inline void kernel_fpu_end(void) preempt_enable(); } -static inline bool irq_fpu_usable(void) -{ - struct pt_regs *regs; - - return !in_interrupt() || !(regs = get_irq_regs()) || \ - user_mode(regs) || (read_cr0() & X86_CR0_TS); -} - /* * Some instructions like VIA's padlock instructions generate a spurious * DNA fault but don't modify SSE registers. And these instructions @@ -367,6 +404,7 @@ static inline void irq_ts_restore(int TS_state) */ static inline void save_init_fpu(struct task_struct *tsk) { + WARN_ON_ONCE(task_thread_info(tsk)->status & TS_USEDFPU); preempt_disable(); __save_init_fpu(tsk); stts(); diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 5878de3fb08..15903de0111 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -777,6 +777,7 @@ EXPORT_SYMBOL_GPL(math_state_restore); dotraplinkage void __kprobes do_device_not_available(struct pt_regs *regs, long error_code) { + WARN_ON_ONCE(!user_mode_vm(regs)); #ifdef CONFIG_MATH_EMULATION if (read_cr0() & X86_CR0_EM) { struct math_emu_info info = { }; From 09ffc93a8a1e8cf06547d20f5a0ddfe880179fe0 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 15 Feb 2012 08:05:18 -0800 Subject: [PATCH 0978/4025] i387: fix sense of sanity check commit c38e23456278e967f094b08247ffc3711b1029b2 upstream. The check for save_init_fpu() (introduced in commit 5b1cbac37798: "i387: make irq_fpu_usable() tests more robust") was the wrong way around, but I hadn't noticed, because my "tests" were bogus: the FPU exceptions are disabled by default, so even doing a divide by zero never actually triggers this code at all unless you do extra work to enable them. So if anybody did enable them, they'd get one spurious warning. Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/i387.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index a4365829e38..262bea981aa 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -404,7 +404,7 @@ static inline void irq_ts_restore(int TS_state) */ static inline void save_init_fpu(struct task_struct *tsk) { - WARN_ON_ONCE(task_thread_info(tsk)->status & TS_USEDFPU); + WARN_ON_ONCE(!(task_thread_info(tsk)->status & TS_USEDFPU)); preempt_disable(); __save_init_fpu(tsk); stts(); From c3cb6440304a2f9afd240bd860860d4a4955d409 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 16 Feb 2012 09:15:04 -0800 Subject: [PATCH 0979/4025] i387: fix x86-64 preemption-unsafe user stack save/restore commit 15d8791cae75dca27bfda8ecfe87dca9379d6bb0 upstream. Commit 5b1cbac37798 ("i387: make irq_fpu_usable() tests more robust") added a sanity check to the #NM handler to verify that we never cause the "Device Not Available" exception in kernel mode. However, that check actually pinpointed a (fundamental) race where we do cause that exception as part of the signal stack FPU state save/restore code. Because we use the floating point instructions themselves to save and restore state directly from user mode, we cannot do that atomically with testing the TS_USEDFPU bit: the user mode access itself may cause a page fault, which causes a task switch, which saves and restores the FP/MMX state from the kernel buffers. This kind of "recursive" FP state save is fine per se, but it means that when the signal stack save/restore gets restarted, it will now take the '#NM' exception we originally tried to avoid. With preemption this can happen even without the page fault - but because of the user access, we cannot just disable preemption around the save/restore instruction. There are various ways to solve this, including using the "enable/disable_page_fault()" helpers to not allow page faults at all during the sequence, and fall back to copying things by hand without the use of the native FP state save/restore instructions. However, the simplest thing to do is to just allow the #NM from kernel space, but fix the race in setting and clearing CR0.TS that this all exposed: the TS bit changes and the TS_USEDFPU bit absolutely have to be atomic wrt scheduling, so while the actual state save/restore can be interrupted and restarted, the act of actually clearing/setting CR0.TS and the TS_USEDFPU bit together must not. Instead of just adding random "preempt_disable/enable()" calls to what is already excessively ugly code, this introduces some helper functions that mostly mirror the "kernel_fpu_begin/end()" functionality, just for the user state instead. Those helper functions should probably eventually replace the other ad-hoc CR0.TS and TS_USEDFPU tests too, but I'll need to think about it some more: the task switching functionality in particular needs to expose the difference between the 'prev' and 'next' threads, while the new helper functions intentionally were written to only work with 'current'. Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/i387.h | 42 +++++++++++++++++++++++++++++++++++++ arch/x86/kernel/traps.c | 1 - arch/x86/kernel/xsave.c | 10 +++------ 3 files changed, 45 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index 262bea981aa..6e87fa43c35 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -399,6 +399,48 @@ static inline void irq_ts_restore(int TS_state) stts(); } +/* + * The question "does this thread have fpu access?" + * is slightly racy, since preemption could come in + * and revoke it immediately after the test. + * + * However, even in that very unlikely scenario, + * we can just assume we have FPU access - typically + * to save the FP state - we'll just take a #NM + * fault and get the FPU access back. + * + * The actual user_fpu_begin/end() functions + * need to be preemption-safe, though. + * + * NOTE! user_fpu_end() must be used only after you + * have saved the FP state, and user_fpu_begin() must + * be used only immediately before restoring it. + * These functions do not do any save/restore on + * their own. + */ +static inline int user_has_fpu(void) +{ + return current_thread_info()->status & TS_USEDFPU; +} + +static inline void user_fpu_end(void) +{ + preempt_disable(); + current_thread_info()->status &= ~TS_USEDFPU; + stts(); + preempt_enable(); +} + +static inline void user_fpu_begin(void) +{ + preempt_disable(); + if (!user_has_fpu()) { + clts(); + current_thread_info()->status |= TS_USEDFPU; + } + preempt_enable(); +} + /* * These disable preemption on their own and are safe */ diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 15903de0111..5878de3fb08 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -777,7 +777,6 @@ EXPORT_SYMBOL_GPL(math_state_restore); dotraplinkage void __kprobes do_device_not_available(struct pt_regs *regs, long error_code) { - WARN_ON_ONCE(!user_mode_vm(regs)); #ifdef CONFIG_MATH_EMULATION if (read_cr0() & X86_CR0_EM) { struct math_emu_info info = { }; diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index a3911343976..86f1f09a738 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c @@ -168,7 +168,7 @@ int save_i387_xstate(void __user *buf) if (!used_math()) return 0; - if (task_thread_info(tsk)->status & TS_USEDFPU) { + if (user_has_fpu()) { if (use_xsave()) err = xsave_user(buf); else @@ -176,8 +176,7 @@ int save_i387_xstate(void __user *buf) if (err) return err; - task_thread_info(tsk)->status &= ~TS_USEDFPU; - stts(); + user_fpu_end(); } else { sanitize_i387_state(tsk); if (__copy_to_user(buf, &tsk->thread.fpu.state->fxsave, @@ -292,10 +291,7 @@ int restore_i387_xstate(void __user *buf) return err; } - if (!(task_thread_info(current)->status & TS_USEDFPU)) { - clts(); - task_thread_info(current)->status |= TS_USEDFPU; - } + user_fpu_begin(); if (use_xsave()) err = restore_user_xstate(buf); else From 0affff96641db67d43092de85c3c4c54028d62e9 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 16 Feb 2012 12:22:48 -0800 Subject: [PATCH 0980/4025] i387: move TS_USEDFPU clearing out of __save_init_fpu and into callers commit b6c66418dcad0fcf83cd1d0a39482db37bf4fc41 upstream. Touching TS_USEDFPU without touching CR0.TS is confusing, so don't do it. By moving it into the callers, we always do the TS_USEDFPU next to the CR0.TS accesses in the source code, and it's much easier to see how the two go hand in hand. Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/i387.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index 6e87fa43c35..55fb3aa84b0 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -259,7 +259,6 @@ static inline void fpu_save_init(struct fpu *fpu) static inline void __save_init_fpu(struct task_struct *tsk) { fpu_save_init(&tsk->thread.fpu); - task_thread_info(tsk)->status &= ~TS_USEDFPU; } static inline int fpu_fxrstor_checking(struct fpu *fpu) @@ -290,6 +289,7 @@ static inline void __unlazy_fpu(struct task_struct *tsk) { if (task_thread_info(tsk)->status & TS_USEDFPU) { __save_init_fpu(tsk); + task_thread_info(tsk)->status &= ~TS_USEDFPU; stts(); } else tsk->fpu_counter = 0; @@ -356,9 +356,11 @@ static inline void kernel_fpu_begin(void) WARN_ON_ONCE(!irq_fpu_usable()); preempt_disable(); - if (me->status & TS_USEDFPU) + if (me->status & TS_USEDFPU) { __save_init_fpu(me->task); - else + me->status &= ~TS_USEDFPU; + /* We do 'stts()' in kernel_fpu_end() */ + } else clts(); } @@ -449,6 +451,7 @@ static inline void save_init_fpu(struct task_struct *tsk) WARN_ON_ONCE(!(task_thread_info(tsk)->status & TS_USEDFPU)); preempt_disable(); __save_init_fpu(tsk); + task_thread_info(tsk)->status &= ~TS_USEDFPU; stts(); preempt_enable(); } From 9221484f11c3902bfc84e18e6c6f50f8739134a7 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 16 Feb 2012 13:33:12 -0800 Subject: [PATCH 0981/4025] i387: don't ever touch TS_USEDFPU directly, use helper functions commit 6d59d7a9f5b723a7ac1925c136e93ec83c0c3043 upstream. This creates three helper functions that do the TS_USEDFPU accesses, and makes everybody that used to do it by hand use those helpers instead. In addition, there's a couple of helper functions for the "change both CR0.TS and TS_USEDFPU at the same time" case, and the places that do that together have been changed to use those. That means that we have fewer random places that open-code this situation. The intent is partly to clarify the code without actually changing any semantics yet (since we clearly still have some hard to reproduce bug in this area), but also to make it much easier to use another approach entirely to caching the CR0.TS bit for software accesses. Right now we use a bit in the thread-info 'status' variable (this patch does not change that), but we might want to make it a full field of its own or even make it a per-cpu variable. Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/i387.h | 75 +++++++++++++++++++++++++++---------- arch/x86/kernel/traps.c | 2 +- arch/x86/kernel/xsave.c | 2 +- arch/x86/kvm/vmx.c | 2 +- 4 files changed, 58 insertions(+), 23 deletions(-) diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index 55fb3aa84b0..730d7becc97 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -279,6 +279,47 @@ static inline int restore_fpu_checking(struct task_struct *tsk) return fpu_restore_checking(&tsk->thread.fpu); } +/* + * Software FPU state helpers. Careful: these need to + * be preemption protection *and* they need to be + * properly paired with the CR0.TS changes! + */ +static inline int __thread_has_fpu(struct thread_info *ti) +{ + return ti->status & TS_USEDFPU; +} + +/* Must be paired with an 'stts' after! */ +static inline void __thread_clear_has_fpu(struct thread_info *ti) +{ + ti->status &= ~TS_USEDFPU; +} + +/* Must be paired with a 'clts' before! */ +static inline void __thread_set_has_fpu(struct thread_info *ti) +{ + ti->status |= TS_USEDFPU; +} + +/* + * Encapsulate the CR0.TS handling together with the + * software flag. + * + * These generally need preemption protection to work, + * do try to avoid using these on their own. + */ +static inline void __thread_fpu_end(struct thread_info *ti) +{ + __thread_clear_has_fpu(ti); + stts(); +} + +static inline void __thread_fpu_begin(struct thread_info *ti) +{ + clts(); + __thread_set_has_fpu(ti); +} + /* * Signal frame handlers... */ @@ -287,23 +328,21 @@ extern int restore_i387_xstate(void __user *buf); static inline void __unlazy_fpu(struct task_struct *tsk) { - if (task_thread_info(tsk)->status & TS_USEDFPU) { + if (__thread_has_fpu(task_thread_info(tsk))) { __save_init_fpu(tsk); - task_thread_info(tsk)->status &= ~TS_USEDFPU; - stts(); + __thread_fpu_end(task_thread_info(tsk)); } else tsk->fpu_counter = 0; } static inline void __clear_fpu(struct task_struct *tsk) { - if (task_thread_info(tsk)->status & TS_USEDFPU) { + if (__thread_has_fpu(task_thread_info(tsk))) { /* Ignore delayed exceptions from user space */ asm volatile("1: fwait\n" "2:\n" _ASM_EXTABLE(1b, 2b)); - task_thread_info(tsk)->status &= ~TS_USEDFPU; - stts(); + __thread_fpu_end(task_thread_info(tsk)); } } @@ -311,14 +350,14 @@ static inline void __clear_fpu(struct task_struct *tsk) * Were we in an interrupt that interrupted kernel mode? * * We can do a kernel_fpu_begin/end() pair *ONLY* if that - * pair does nothing at all: TS_USEDFPU must be clear (so + * pair does nothing at all: the thread must not have fpu (so * that we don't try to save the FPU state), and TS must * be set (so that the clts/stts pair does nothing that is * visible in the interrupted kernel thread). */ static inline bool interrupted_kernel_fpu_idle(void) { - return !(current_thread_info()->status & TS_USEDFPU) && + return !__thread_has_fpu(current_thread_info()) && (read_cr0() & X86_CR0_TS); } @@ -356,9 +395,9 @@ static inline void kernel_fpu_begin(void) WARN_ON_ONCE(!irq_fpu_usable()); preempt_disable(); - if (me->status & TS_USEDFPU) { + if (__thread_has_fpu(me)) { __save_init_fpu(me->task); - me->status &= ~TS_USEDFPU; + __thread_clear_has_fpu(me); /* We do 'stts()' in kernel_fpu_end() */ } else clts(); @@ -422,24 +461,21 @@ static inline void irq_ts_restore(int TS_state) */ static inline int user_has_fpu(void) { - return current_thread_info()->status & TS_USEDFPU; + return __thread_has_fpu(current_thread_info()); } static inline void user_fpu_end(void) { preempt_disable(); - current_thread_info()->status &= ~TS_USEDFPU; - stts(); + __thread_fpu_end(current_thread_info()); preempt_enable(); } static inline void user_fpu_begin(void) { preempt_disable(); - if (!user_has_fpu()) { - clts(); - current_thread_info()->status |= TS_USEDFPU; - } + if (!user_has_fpu()) + __thread_fpu_begin(current_thread_info()); preempt_enable(); } @@ -448,11 +484,10 @@ static inline void user_fpu_begin(void) */ static inline void save_init_fpu(struct task_struct *tsk) { - WARN_ON_ONCE(!(task_thread_info(tsk)->status & TS_USEDFPU)); + WARN_ON_ONCE(!__thread_has_fpu(task_thread_info(tsk))); preempt_disable(); __save_init_fpu(tsk); - task_thread_info(tsk)->status &= ~TS_USEDFPU; - stts(); + __thread_fpu_end(task_thread_info(tsk)); preempt_enable(); } diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 5878de3fb08..326476d748b 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -734,7 +734,7 @@ void __math_state_restore(void) return; } - thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ + __thread_set_has_fpu(thread); /* clts in caller! */ tsk->fpu_counter++; } diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index 86f1f09a738..a0bcd0dbc95 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c @@ -47,7 +47,7 @@ void __sanitize_i387_state(struct task_struct *tsk) if (!fx) return; - BUG_ON(task_thread_info(tsk)->status & TS_USEDFPU); + BUG_ON(__thread_has_fpu(task_thread_info(tsk))); xstate_bv = tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv; diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index d48ec60ea42..6da2baea08c 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -948,7 +948,7 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx) #ifdef CONFIG_X86_64 wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base); #endif - if (current_thread_info()->status & TS_USEDFPU) + if (__thread_has_fpu(current_thread_info())) clts(); load_gdt(&__get_cpu_var(host_gdt)); } From 06f4bbda338e6aa42497b76a16cf38e2fdd29885 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 16 Feb 2012 15:45:23 -0800 Subject: [PATCH 0982/4025] i387: do not preload FPU state at task switch time commit b3b0870ef3ffed72b92415423da864f440f57ad6 upstream. Yes, taking the trap to re-load the FPU/MMX state is expensive, but so is spending several days looking for a bug in the state save/restore code. And the preload code has some rather subtle interactions with both paravirtualization support and segment state restore, so it's not nearly as simple as it should be. Also, now that we no longer necessarily depend on a single bit (ie TS_USEDFPU) for keeping track of the state of the FPU, we migth be able to do better. If we are really switching between two processes that keep touching the FP state, save/restore is inevitable, but in the case of having one process that does most of the FPU usage, we may actually be able to do much better than the preloading. In particular, we may be able to keep track of which CPU the process ran on last, and also per CPU keep track of which process' FP state that CPU has. For modern CPU's that don't destroy the FPU contents on save time, that would allow us to do a lazy restore by just re-enabling the existing FPU state - with no restore cost at all! Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/i387.h | 1 - arch/x86/kernel/process_32.c | 20 -------------------- arch/x86/kernel/process_64.c | 23 ----------------------- arch/x86/kernel/traps.c | 35 +++++++++++------------------------ 4 files changed, 11 insertions(+), 68 deletions(-) diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index 730d7becc97..3521c243434 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -30,7 +30,6 @@ extern void fpu_init(void); extern void mxcsr_feature_mask_init(void); extern int init_fpu(struct task_struct *child); extern void math_state_restore(void); -extern void __math_state_restore(void); extern int dump_fpu(struct pt_regs *, struct user_i387_struct *); extern user_regset_active_fn fpregs_active, xfpregs_active; diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index a3d0dc59067..74aa377081f 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -293,23 +293,11 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) *next = &next_p->thread; int cpu = smp_processor_id(); struct tss_struct *tss = &per_cpu(init_tss, cpu); - bool preload_fpu; /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ - /* - * If the task has used fpu the last 5 timeslices, just do a full - * restore of the math state immediately to avoid the trap; the - * chances of needing FPU soon are obviously high now - */ - preload_fpu = tsk_used_math(next_p) && next_p->fpu_counter > 5; - __unlazy_fpu(prev_p); - /* we're going to use this soon, after a few expensive things */ - if (preload_fpu) - prefetch(next->fpu.state); - /* * Reload esp0. */ @@ -348,11 +336,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) task_thread_info(next_p)->flags & _TIF_WORK_CTXSW_NEXT)) __switch_to_xtra(prev_p, next_p, tss); - /* If we're going to preload the fpu context, make sure clts - is run while we're batching the cpu state updates. */ - if (preload_fpu) - clts(); - /* * Leave lazy mode, flushing any hypercalls made here. * This must be done before restoring TLS segments so @@ -362,9 +345,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) */ arch_end_context_switch(next_p); - if (preload_fpu) - __math_state_restore(); - /* * Restore %gs if needed (which is common) */ diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index ca6f7ab8df3..789cc829f77 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -377,18 +377,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) int cpu = smp_processor_id(); struct tss_struct *tss = &per_cpu(init_tss, cpu); unsigned fsindex, gsindex; - bool preload_fpu; - - /* - * If the task has used fpu the last 5 timeslices, just do a full - * restore of the math state immediately to avoid the trap; the - * chances of needing FPU soon are obviously high now - */ - preload_fpu = tsk_used_math(next_p) && next_p->fpu_counter > 5; - - /* we're going to use this soon, after a few expensive things */ - if (preload_fpu) - prefetch(next->fpu.state); /* * Reload esp0, LDT and the page table pointer: @@ -421,10 +409,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) /* Must be after DS reload */ __unlazy_fpu(prev_p); - /* Make sure cpu is ready for new context */ - if (preload_fpu) - clts(); - /* * Leave lazy mode, flushing any hypercalls made here. * This must be done before restoring TLS segments so @@ -483,13 +467,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) task_thread_info(prev_p)->flags & _TIF_WORK_CTXSW_PREV)) __switch_to_xtra(prev_p, next_p, tss); - /* - * Preload the FPU context, now that we've determined that the - * task is likely to be using it. - */ - if (preload_fpu) - __math_state_restore(); - return prev_p; } diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 326476d748b..4536830b606 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -716,28 +716,6 @@ asmlinkage void __attribute__((weak)) smp_threshold_interrupt(void) { } -/* - * __math_state_restore assumes that cr0.TS is already clear and the - * fpu state is all ready for use. Used during context switch. - */ -void __math_state_restore(void) -{ - struct thread_info *thread = current_thread_info(); - struct task_struct *tsk = thread->task; - - /* - * Paranoid restore. send a SIGSEGV if we fail to restore the state. - */ - if (unlikely(restore_fpu_checking(tsk))) { - stts(); - force_sig(SIGSEGV, tsk); - return; - } - - __thread_set_has_fpu(thread); /* clts in caller! */ - tsk->fpu_counter++; -} - /* * 'math_state_restore()' saves the current math information in the * old math state array, and gets the new ones from the current task @@ -768,9 +746,18 @@ void math_state_restore(void) local_irq_disable(); } - clts(); /* Allow maths ops (or we recurse) */ + __thread_fpu_begin(thread); - __math_state_restore(); + /* + * Paranoid restore. send a SIGSEGV if we fail to restore the state. + */ + if (unlikely(restore_fpu_checking(tsk))) { + __thread_fpu_end(thread); + force_sig(SIGSEGV, tsk); + return; + } + + tsk->fpu_counter++; } EXPORT_SYMBOL_GPL(math_state_restore); From 70b5ef05d889e2be250fd1d963e89f7ca1dd1965 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 16 Feb 2012 19:11:15 -0800 Subject: [PATCH 0983/4025] i387: move AMD K7/K8 fpu fxsave/fxrstor workaround from save to restore commit 4903062b5485f0e2c286a23b44c9b59d9b017d53 upstream. The AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception is pending. In order to not leak FIP state from one process to another, we need to do a floating point load after the fxsave of the old process, and before the fxrstor of the new FPU state. That resets the state to the (uninteresting) kernel load, rather than some potentially sensitive user information. We used to do this directly after the FPU state save, but that is actually very inconvenient, since it (a) corrupts what is potentially perfectly good FPU state that we might want to lazy avoid restoring later and (b) on x86-64 it resulted in a very annoying ordering constraint, where "__unlazy_fpu()" in the task switch needs to be delayed until after the DS segment has been reloaded just to get the new DS value. Coupling it to the fxrstor instead of the fxsave automatically avoids both of these issues, and also ensures that we only do it when actually necessary (the FP state after a save may never actually get used). It's simply a much more natural place for the leaked state cleanup. Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/i387.h | 19 ------------------- arch/x86/kernel/process_64.c | 5 ++--- arch/x86/kernel/traps.c | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index 3521c243434..01b115d8677 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -211,15 +211,6 @@ static inline void fpu_fxsave(struct fpu *fpu) #endif /* CONFIG_X86_64 */ -/* We need a safe address that is cheap to find and that is already - in L1 during context switch. The best choices are unfortunately - different for UP and SMP */ -#ifdef CONFIG_SMP -#define safe_address (__per_cpu_offset[0]) -#else -#define safe_address (kstat_cpu(0).cpustat.user) -#endif - /* * These must be called with preempt disabled */ @@ -243,16 +234,6 @@ static inline void fpu_save_init(struct fpu *fpu) if (unlikely(fpu->state->fxsave.swd & X87_FSW_ES)) asm volatile("fnclex"); - - /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception - is pending. Clear the x87 state here by setting it to fixed - values. safe_address is a random variable that should be in L1 */ - alternative_input( - ASM_NOP8 ASM_NOP2, - "emms\n\t" /* clear stack tags */ - "fildl %P[addr]", /* set F?P to defined value */ - X86_FEATURE_FXSAVE_LEAK, - [addr] "m" (safe_address)); } static inline void __save_init_fpu(struct task_struct *tsk) diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index 789cc829f77..edb791c02c8 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -378,6 +378,8 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) struct tss_struct *tss = &per_cpu(init_tss, cpu); unsigned fsindex, gsindex; + __unlazy_fpu(prev_p); + /* * Reload esp0, LDT and the page table pointer: */ @@ -406,9 +408,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) load_TLS(next, cpu); - /* Must be after DS reload */ - __unlazy_fpu(prev_p); - /* * Leave lazy mode, flushing any hypercalls made here. * This must be done before restoring TLS segments so diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 4536830b606..1b8128a0f08 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -731,6 +731,10 @@ void math_state_restore(void) struct thread_info *thread = current_thread_info(); struct task_struct *tsk = thread->task; + /* We need a safe address that is cheap to find and that is already + in L1. We just brought in "thread->task", so use that */ +#define safe_address (thread->task) + if (!tsk_used_math(tsk)) { local_irq_enable(); /* @@ -748,6 +752,16 @@ void math_state_restore(void) __thread_fpu_begin(thread); + /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception + is pending. Clear the x87 state here by setting it to fixed + values. safe_address is a random variable that should be in L1 */ + alternative_input( + ASM_NOP8 ASM_NOP2, + "emms\n\t" /* clear stack tags */ + "fildl %P[addr]", /* set F?P to defined value */ + X86_FEATURE_FXSAVE_LEAK, + [addr] "m" (safe_address)); + /* * Paranoid restore. send a SIGSEGV if we fail to restore the state. */ From 0a9d89d976531bd5ea7fce618cee886c79b43e07 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 17 Feb 2012 21:48:54 -0800 Subject: [PATCH 0984/4025] i387: move TS_USEDFPU flag from thread_info to task_struct commit f94edacf998516ac9d849f7bc6949a703977a7f3 upstream. This moves the bit that indicates whether a thread has ownership of the FPU from the TS_USEDFPU bit in thread_info->status to a word of its own (called 'has_fpu') in task_struct->thread.has_fpu. This fixes two independent bugs at the same time: - changing 'thread_info->status' from the scheduler causes nasty problems for the other users of that variable, since it is defined to be thread-synchronous (that's what the "TS_" part of the naming was supposed to indicate). So perfectly valid code could (and did) do ti->status |= TS_RESTORE_SIGMASK; and the compiler was free to do that as separate load, or and store instructions. Which can cause problems with preemption, since a task switch could happen in between, and change the TS_USEDFPU bit. The change to TS_USEDFPU would be overwritten by the final store. In practice, this seldom happened, though, because the 'status' field was seldom used more than once, so gcc would generally tend to generate code that used a read-modify-write instruction and thus happened to avoid this problem - RMW instructions are naturally low fat and preemption-safe. - On x86-32, the current_thread_info() pointer would, during interrupts and softirqs, point to a *copy* of the real thread_info, because x86-32 uses %esp to calculate the thread_info address, and thus the separate irq (and softirq) stacks would cause these kinds of odd thread_info copy aliases. This is normally not a problem, since interrupts aren't supposed to look at thread information anyway (what thread is running at interrupt time really isn't very well-defined), but it confused the heck out of irq_fpu_usable() and the code that tried to squirrel away the FPU state. (It also caused untold confusion for us poor kernel developers). It also turns out that using 'task_struct' is actually much more natural for most of the call sites that care about the FPU state, since they tend to work with the task struct for other reasons anyway (ie scheduling). And the FPU data that we are going to save/restore is found there too. Thanks to Arjan Van De Ven for pointing us to the %esp issue. Cc: Arjan van de Ven Reported-and-tested-by: Raphael Prevost Acked-and-tested-by: Suresh Siddha Tested-by: Peter Anvin Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/i387.h | 44 +++++++++++++++--------------- arch/x86/include/asm/processor.h | 1 + arch/x86/include/asm/thread_info.h | 2 -- arch/x86/kernel/traps.c | 11 ++++---- arch/x86/kernel/xsave.c | 2 +- arch/x86/kvm/vmx.c | 2 +- 6 files changed, 30 insertions(+), 32 deletions(-) diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index 01b115d8677..f5376676f89 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -264,21 +264,21 @@ static inline int restore_fpu_checking(struct task_struct *tsk) * be preemption protection *and* they need to be * properly paired with the CR0.TS changes! */ -static inline int __thread_has_fpu(struct thread_info *ti) +static inline int __thread_has_fpu(struct task_struct *tsk) { - return ti->status & TS_USEDFPU; + return tsk->thread.has_fpu; } /* Must be paired with an 'stts' after! */ -static inline void __thread_clear_has_fpu(struct thread_info *ti) +static inline void __thread_clear_has_fpu(struct task_struct *tsk) { - ti->status &= ~TS_USEDFPU; + tsk->thread.has_fpu = 0; } /* Must be paired with a 'clts' before! */ -static inline void __thread_set_has_fpu(struct thread_info *ti) +static inline void __thread_set_has_fpu(struct task_struct *tsk) { - ti->status |= TS_USEDFPU; + tsk->thread.has_fpu = 1; } /* @@ -288,16 +288,16 @@ static inline void __thread_set_has_fpu(struct thread_info *ti) * These generally need preemption protection to work, * do try to avoid using these on their own. */ -static inline void __thread_fpu_end(struct thread_info *ti) +static inline void __thread_fpu_end(struct task_struct *tsk) { - __thread_clear_has_fpu(ti); + __thread_clear_has_fpu(tsk); stts(); } -static inline void __thread_fpu_begin(struct thread_info *ti) +static inline void __thread_fpu_begin(struct task_struct *tsk) { clts(); - __thread_set_has_fpu(ti); + __thread_set_has_fpu(tsk); } /* @@ -308,21 +308,21 @@ extern int restore_i387_xstate(void __user *buf); static inline void __unlazy_fpu(struct task_struct *tsk) { - if (__thread_has_fpu(task_thread_info(tsk))) { + if (__thread_has_fpu(tsk)) { __save_init_fpu(tsk); - __thread_fpu_end(task_thread_info(tsk)); + __thread_fpu_end(tsk); } else tsk->fpu_counter = 0; } static inline void __clear_fpu(struct task_struct *tsk) { - if (__thread_has_fpu(task_thread_info(tsk))) { + if (__thread_has_fpu(tsk)) { /* Ignore delayed exceptions from user space */ asm volatile("1: fwait\n" "2:\n" _ASM_EXTABLE(1b, 2b)); - __thread_fpu_end(task_thread_info(tsk)); + __thread_fpu_end(tsk); } } @@ -337,7 +337,7 @@ static inline void __clear_fpu(struct task_struct *tsk) */ static inline bool interrupted_kernel_fpu_idle(void) { - return !__thread_has_fpu(current_thread_info()) && + return !__thread_has_fpu(current) && (read_cr0() & X86_CR0_TS); } @@ -371,12 +371,12 @@ static inline bool irq_fpu_usable(void) static inline void kernel_fpu_begin(void) { - struct thread_info *me = current_thread_info(); + struct task_struct *me = current; WARN_ON_ONCE(!irq_fpu_usable()); preempt_disable(); if (__thread_has_fpu(me)) { - __save_init_fpu(me->task); + __save_init_fpu(me); __thread_clear_has_fpu(me); /* We do 'stts()' in kernel_fpu_end() */ } else @@ -441,13 +441,13 @@ static inline void irq_ts_restore(int TS_state) */ static inline int user_has_fpu(void) { - return __thread_has_fpu(current_thread_info()); + return __thread_has_fpu(current); } static inline void user_fpu_end(void) { preempt_disable(); - __thread_fpu_end(current_thread_info()); + __thread_fpu_end(current); preempt_enable(); } @@ -455,7 +455,7 @@ static inline void user_fpu_begin(void) { preempt_disable(); if (!user_has_fpu()) - __thread_fpu_begin(current_thread_info()); + __thread_fpu_begin(current); preempt_enable(); } @@ -464,10 +464,10 @@ static inline void user_fpu_begin(void) */ static inline void save_init_fpu(struct task_struct *tsk) { - WARN_ON_ONCE(!__thread_has_fpu(task_thread_info(tsk))); + WARN_ON_ONCE(!__thread_has_fpu(tsk)); preempt_disable(); __save_init_fpu(tsk); - __thread_fpu_end(task_thread_info(tsk)); + __thread_fpu_end(tsk); preempt_enable(); } diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index 219371546af..5d9c61d0b27 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h @@ -454,6 +454,7 @@ struct thread_struct { unsigned long trap_no; unsigned long error_code; /* floating point and extended processor state */ + unsigned long has_fpu; struct fpu fpu; #ifdef CONFIG_X86_32 /* Virtual 86 mode info */ diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 1f2e61e2898..278d3d5f906 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -242,8 +242,6 @@ static inline struct thread_info *current_thread_info(void) * ever touches our thread-synchronous status, so we don't * have to worry about atomic accesses. */ -#define TS_USEDFPU 0x0001 /* FPU was used by this task - this quantum (SMP) */ #define TS_COMPAT 0x0002 /* 32bit syscall active (64BIT)*/ #define TS_POLLING 0x0004 /* idle task polling need_resched, skip sending interrupt */ diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 1b8128a0f08..5622d4e115d 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -728,12 +728,11 @@ asmlinkage void __attribute__((weak)) smp_threshold_interrupt(void) */ void math_state_restore(void) { - struct thread_info *thread = current_thread_info(); - struct task_struct *tsk = thread->task; + struct task_struct *tsk = current; /* We need a safe address that is cheap to find and that is already - in L1. We just brought in "thread->task", so use that */ -#define safe_address (thread->task) + in L1. We're just bringing in "tsk->thread.has_fpu", so use that */ +#define safe_address (tsk->thread.has_fpu) if (!tsk_used_math(tsk)) { local_irq_enable(); @@ -750,7 +749,7 @@ void math_state_restore(void) local_irq_disable(); } - __thread_fpu_begin(thread); + __thread_fpu_begin(tsk); /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception is pending. Clear the x87 state here by setting it to fixed @@ -766,7 +765,7 @@ void math_state_restore(void) * Paranoid restore. send a SIGSEGV if we fail to restore the state. */ if (unlikely(restore_fpu_checking(tsk))) { - __thread_fpu_end(thread); + __thread_fpu_end(tsk); force_sig(SIGSEGV, tsk); return; } diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c index a0bcd0dbc95..71109111411 100644 --- a/arch/x86/kernel/xsave.c +++ b/arch/x86/kernel/xsave.c @@ -47,7 +47,7 @@ void __sanitize_i387_state(struct task_struct *tsk) if (!fx) return; - BUG_ON(__thread_has_fpu(task_thread_info(tsk))); + BUG_ON(__thread_has_fpu(tsk)); xstate_bv = tsk->thread.fpu.state->xsave.xsave_hdr.xstate_bv; diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 6da2baea08c..2ad060acc44 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -948,7 +948,7 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx) #ifdef CONFIG_X86_64 wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base); #endif - if (__thread_has_fpu(current_thread_info())) + if (__thread_has_fpu(current)) clts(); load_gdt(&__get_cpu_var(host_gdt)); } From f4def3f88dc57648d1603656f1ffdf498bfce1ee Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 18 Feb 2012 12:56:35 -0800 Subject: [PATCH 0985/4025] i387: re-introduce FPU state preloading at context switch time commit 34ddc81a230b15c0e345b6b253049db731499f7e upstream. After all the FPU state cleanups and finally finding the problem that caused all our FPU save/restore problems, this re-introduces the preloading of FPU state that was removed in commit b3b0870ef3ff ("i387: do not preload FPU state at task switch time"). However, instead of simply reverting the removal, this reimplements preloading with several fixes, most notably - properly abstracted as a true FPU state switch, rather than as open-coded save and restore with various hacks. In particular, implementing it as a proper FPU state switch allows us to optimize the CR0.TS flag accesses: there is no reason to set the TS bit only to then almost immediately clear it again. CR0 accesses are quite slow and expensive, don't flip the bit back and forth for no good reason. - Make sure that the same model works for both x86-32 and x86-64, so that there are no gratuitous differences between the two due to the way they save and restore segment state differently due to architectural differences that really don't matter to the FPU state. - Avoid exposing the "preload" state to the context switch routines, and in particular allow the concept of lazy state restore: if nothing else has used the FPU in the meantime, and the process is still on the same CPU, we can avoid restoring state from memory entirely, just re-expose the state that is still in the FPU unit. That optimized lazy restore isn't actually implemented here, but the infrastructure is set up for it. Of course, older CPU's that use 'fnsave' to save the state cannot take advantage of this, since the state saving also trashes the state. In other words, there is now an actual _design_ to the FPU state saving, rather than just random historical baggage. Hopefully it's easier to follow as a result. Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/i387.h | 110 +++++++++++++++++++++++++++++------ arch/x86/kernel/process_32.c | 5 +- arch/x86/kernel/process_64.c | 5 +- arch/x86/kernel/traps.c | 55 ++++++++++-------- 4 files changed, 133 insertions(+), 42 deletions(-) diff --git a/arch/x86/include/asm/i387.h b/arch/x86/include/asm/i387.h index f5376676f89..a850b4d8d14 100644 --- a/arch/x86/include/asm/i387.h +++ b/arch/x86/include/asm/i387.h @@ -29,6 +29,7 @@ extern unsigned int sig_xstate_size; extern void fpu_init(void); extern void mxcsr_feature_mask_init(void); extern int init_fpu(struct task_struct *child); +extern void __math_state_restore(struct task_struct *); extern void math_state_restore(void); extern int dump_fpu(struct pt_regs *, struct user_i387_struct *); @@ -212,9 +213,10 @@ static inline void fpu_fxsave(struct fpu *fpu) #endif /* CONFIG_X86_64 */ /* - * These must be called with preempt disabled + * These must be called with preempt disabled. Returns + * 'true' if the FPU state is still intact. */ -static inline void fpu_save_init(struct fpu *fpu) +static inline int fpu_save_init(struct fpu *fpu) { if (use_xsave()) { fpu_xsave(fpu); @@ -223,22 +225,33 @@ static inline void fpu_save_init(struct fpu *fpu) * xsave header may indicate the init state of the FP. */ if (!(fpu->state->xsave.xsave_hdr.xstate_bv & XSTATE_FP)) - return; + return 1; } else if (use_fxsr()) { fpu_fxsave(fpu); } else { asm volatile("fnsave %[fx]; fwait" : [fx] "=m" (fpu->state->fsave)); - return; + return 0; } - if (unlikely(fpu->state->fxsave.swd & X87_FSW_ES)) + /* + * If exceptions are pending, we need to clear them so + * that we don't randomly get exceptions later. + * + * FIXME! Is this perhaps only true for the old-style + * irq13 case? Maybe we could leave the x87 state + * intact otherwise? + */ + if (unlikely(fpu->state->fxsave.swd & X87_FSW_ES)) { asm volatile("fnclex"); + return 0; + } + return 1; } -static inline void __save_init_fpu(struct task_struct *tsk) +static inline int __save_init_fpu(struct task_struct *tsk) { - fpu_save_init(&tsk->thread.fpu); + return fpu_save_init(&tsk->thread.fpu); } static inline int fpu_fxrstor_checking(struct fpu *fpu) @@ -301,20 +314,79 @@ static inline void __thread_fpu_begin(struct task_struct *tsk) } /* - * Signal frame handlers... + * FPU state switching for scheduling. + * + * This is a two-stage process: + * + * - switch_fpu_prepare() saves the old state and + * sets the new state of the CR0.TS bit. This is + * done within the context of the old process. + * + * - switch_fpu_finish() restores the new state as + * necessary. */ -extern int save_i387_xstate(void __user *buf); -extern int restore_i387_xstate(void __user *buf); +typedef struct { int preload; } fpu_switch_t; + +/* + * FIXME! We could do a totally lazy restore, but we need to + * add a per-cpu "this was the task that last touched the FPU + * on this CPU" variable, and the task needs to have a "I last + * touched the FPU on this CPU" and check them. + * + * We don't do that yet, so "fpu_lazy_restore()" always returns + * false, but some day.. + */ +#define fpu_lazy_restore(tsk) (0) +#define fpu_lazy_state_intact(tsk) do { } while (0) + +static inline fpu_switch_t switch_fpu_prepare(struct task_struct *old, struct task_struct *new) +{ + fpu_switch_t fpu; + + fpu.preload = tsk_used_math(new) && new->fpu_counter > 5; + if (__thread_has_fpu(old)) { + if (__save_init_fpu(old)) + fpu_lazy_state_intact(old); + __thread_clear_has_fpu(old); + old->fpu_counter++; + + /* Don't change CR0.TS if we just switch! */ + if (fpu.preload) { + __thread_set_has_fpu(new); + prefetch(new->thread.fpu.state); + } else + stts(); + } else { + old->fpu_counter = 0; + if (fpu.preload) { + if (fpu_lazy_restore(new)) + fpu.preload = 0; + else + prefetch(new->thread.fpu.state); + __thread_fpu_begin(new); + } + } + return fpu; +} -static inline void __unlazy_fpu(struct task_struct *tsk) +/* + * By the time this gets called, we've already cleared CR0.TS and + * given the process the FPU if we are going to preload the FPU + * state - all we need to do is to conditionally restore the register + * state itself. + */ +static inline void switch_fpu_finish(struct task_struct *new, fpu_switch_t fpu) { - if (__thread_has_fpu(tsk)) { - __save_init_fpu(tsk); - __thread_fpu_end(tsk); - } else - tsk->fpu_counter = 0; + if (fpu.preload) + __math_state_restore(new); } +/* + * Signal frame handlers... + */ +extern int save_i387_xstate(void __user *buf); +extern int restore_i387_xstate(void __user *buf); + static inline void __clear_fpu(struct task_struct *tsk) { if (__thread_has_fpu(tsk)) { @@ -474,7 +546,11 @@ static inline void save_init_fpu(struct task_struct *tsk) static inline void unlazy_fpu(struct task_struct *tsk) { preempt_disable(); - __unlazy_fpu(tsk); + if (__thread_has_fpu(tsk)) { + __save_init_fpu(tsk); + __thread_fpu_end(tsk); + } else + tsk->fpu_counter = 0; preempt_enable(); } diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 74aa377081f..fcdb1b34aa1 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -293,10 +293,11 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) *next = &next_p->thread; int cpu = smp_processor_id(); struct tss_struct *tss = &per_cpu(init_tss, cpu); + fpu_switch_t fpu; /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ - __unlazy_fpu(prev_p); + fpu = switch_fpu_prepare(prev_p, next_p); /* * Reload esp0. @@ -351,6 +352,8 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) if (prev->gs | next->gs) lazy_load_gs(next->gs); + switch_fpu_finish(next_p, fpu); + percpu_write(current_task, next_p); return prev_p; diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c index edb791c02c8..b01898d2744 100644 --- a/arch/x86/kernel/process_64.c +++ b/arch/x86/kernel/process_64.c @@ -377,8 +377,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) int cpu = smp_processor_id(); struct tss_struct *tss = &per_cpu(init_tss, cpu); unsigned fsindex, gsindex; + fpu_switch_t fpu; - __unlazy_fpu(prev_p); + fpu = switch_fpu_prepare(prev_p, next_p); /* * Reload esp0, LDT and the page table pointer: @@ -448,6 +449,8 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) wrmsrl(MSR_KERNEL_GS_BASE, next->gs); prev->gsindex = gsindex; + switch_fpu_finish(next_p, fpu); + /* * Switch the PDA and FPU contexts. */ diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 5622d4e115d..1b26e01047b 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -716,6 +716,37 @@ asmlinkage void __attribute__((weak)) smp_threshold_interrupt(void) { } +/* + * This gets called with the process already owning the + * FPU state, and with CR0.TS cleared. It just needs to + * restore the FPU register state. + */ +void __math_state_restore(struct task_struct *tsk) +{ + /* We need a safe address that is cheap to find and that is already + in L1. We've just brought in "tsk->thread.has_fpu", so use that */ +#define safe_address (tsk->thread.has_fpu) + + /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception + is pending. Clear the x87 state here by setting it to fixed + values. safe_address is a random variable that should be in L1 */ + alternative_input( + ASM_NOP8 ASM_NOP2, + "emms\n\t" /* clear stack tags */ + "fildl %P[addr]", /* set F?P to defined value */ + X86_FEATURE_FXSAVE_LEAK, + [addr] "m" (safe_address)); + + /* + * Paranoid restore. send a SIGSEGV if we fail to restore the state. + */ + if (unlikely(restore_fpu_checking(tsk))) { + __thread_fpu_end(tsk); + force_sig(SIGSEGV, tsk); + return; + } +} + /* * 'math_state_restore()' saves the current math information in the * old math state array, and gets the new ones from the current task @@ -730,10 +761,6 @@ void math_state_restore(void) { struct task_struct *tsk = current; - /* We need a safe address that is cheap to find and that is already - in L1. We're just bringing in "tsk->thread.has_fpu", so use that */ -#define safe_address (tsk->thread.has_fpu) - if (!tsk_used_math(tsk)) { local_irq_enable(); /* @@ -750,25 +777,7 @@ void math_state_restore(void) } __thread_fpu_begin(tsk); - - /* AMD K7/K8 CPUs don't save/restore FDP/FIP/FOP unless an exception - is pending. Clear the x87 state here by setting it to fixed - values. safe_address is a random variable that should be in L1 */ - alternative_input( - ASM_NOP8 ASM_NOP2, - "emms\n\t" /* clear stack tags */ - "fildl %P[addr]", /* set F?P to defined value */ - X86_FEATURE_FXSAVE_LEAK, - [addr] "m" (safe_address)); - - /* - * Paranoid restore. send a SIGSEGV if we fail to restore the state. - */ - if (unlikely(restore_fpu_checking(tsk))) { - __thread_fpu_end(tsk); - force_sig(SIGSEGV, tsk); - return; - } + __math_state_restore(tsk); tsk->fpu_counter++; } From 721eaa34e5daf7b41458046649d8aee834a92b55 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 21 Feb 2012 13:16:32 -0500 Subject: [PATCH 0986/4025] usb-storage: fix freezing of the scanning thread commit bb94a406682770a35305daaa241ccdb7cab399de upstream. This patch (as1521b) fixes the interaction between usb-storage's scanning thread and the freezer. The current implementation has a race: If the device is unplugged shortly after being plugged in and just as a system sleep begins, the scanning thread may get frozen before the khubd task. Khubd won't be able to freeze until the disconnect processing is complete, and the disconnect processing can't proceed until the scanning thread finishes, so the sleep transition will fail. The implementation in the 3.2 kernel suffers from an additional problem. There the scanning thread calls set_freezable_with_signal(), and the signals sent by the freezer will mess up the thread's I/O delays, which are all interruptible. The solution to both problems is the same: Replace the kernel thread used for scanning with a delayed-work routine on the system freezable work queue. Freezable work queues have the nice property that you can cancel a work item even while the work queue is frozen, and no signals are needed. The 3.2 version of this patch solves the problem in Bugzilla #42730. Signed-off-by: Alan Stern Acked-by: Seth Forshee Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/usb.c | 89 ++++++++++++++------------------------- drivers/usb/storage/usb.h | 7 +-- 2 files changed, 35 insertions(+), 61 deletions(-) diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 9e069efeefe..db51ba16dc0 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -788,15 +788,19 @@ static void quiesce_and_remove_host(struct us_data *us) struct Scsi_Host *host = us_to_host(us); /* If the device is really gone, cut short reset delays */ - if (us->pusb_dev->state == USB_STATE_NOTATTACHED) + if (us->pusb_dev->state == USB_STATE_NOTATTACHED) { set_bit(US_FLIDX_DISCONNECTING, &us->dflags); + wake_up(&us->delay_wait); + } - /* Prevent SCSI-scanning (if it hasn't started yet) - * and wait for the SCSI-scanning thread to stop. + /* Prevent SCSI scanning (if it hasn't started yet) + * or wait for the SCSI-scanning routine to stop. */ - set_bit(US_FLIDX_DONT_SCAN, &us->dflags); - wake_up(&us->delay_wait); - wait_for_completion(&us->scanning_done); + cancel_delayed_work_sync(&us->scan_dwork); + + /* Balance autopm calls if scanning was cancelled */ + if (test_bit(US_FLIDX_SCAN_PENDING, &us->dflags)) + usb_autopm_put_interface_no_suspend(us->pusb_intf); /* Removing the host will perform an orderly shutdown: caches * synchronized, disks spun down, etc. @@ -823,52 +827,28 @@ static void release_everything(struct us_data *us) scsi_host_put(us_to_host(us)); } -/* Thread to carry out delayed SCSI-device scanning */ -static int usb_stor_scan_thread(void * __us) +/* Delayed-work routine to carry out SCSI-device scanning */ +static void usb_stor_scan_dwork(struct work_struct *work) { - struct us_data *us = (struct us_data *)__us; + struct us_data *us = container_of(work, struct us_data, + scan_dwork.work); struct device *dev = &us->pusb_intf->dev; - dev_dbg(dev, "device found\n"); + dev_dbg(dev, "starting scan\n"); - set_freezable_with_signal(); - /* - * Wait for the timeout to expire or for a disconnect - * - * We can't freeze in this thread or we risk causing khubd to - * fail to freeze, but we can't be non-freezable either. Nor can - * khubd freeze while waiting for scanning to complete as it may - * hold the device lock, causing a hang when suspending devices. - * So we request a fake signal when freezing and use - * interruptible sleep to kick us out of our wait early when - * freezing happens. - */ - if (delay_use > 0) { - dev_dbg(dev, "waiting for device to settle " - "before scanning\n"); - wait_event_interruptible_timeout(us->delay_wait, - test_bit(US_FLIDX_DONT_SCAN, &us->dflags), - delay_use * HZ); + /* For bulk-only devices, determine the max LUN value */ + if (us->protocol == USB_PR_BULK && !(us->fflags & US_FL_SINGLE_LUN)) { + mutex_lock(&us->dev_mutex); + us->max_lun = usb_stor_Bulk_max_lun(us); + mutex_unlock(&us->dev_mutex); } + scsi_scan_host(us_to_host(us)); + dev_dbg(dev, "scan complete\n"); - /* If the device is still connected, perform the scanning */ - if (!test_bit(US_FLIDX_DONT_SCAN, &us->dflags)) { - - /* For bulk-only devices, determine the max LUN value */ - if (us->protocol == USB_PR_BULK && - !(us->fflags & US_FL_SINGLE_LUN)) { - mutex_lock(&us->dev_mutex); - us->max_lun = usb_stor_Bulk_max_lun(us); - mutex_unlock(&us->dev_mutex); - } - scsi_scan_host(us_to_host(us)); - dev_dbg(dev, "scan complete\n"); - - /* Should we unbind if no devices were detected? */ - } + /* Should we unbind if no devices were detected? */ usb_autopm_put_interface(us->pusb_intf); - complete_and_exit(&us->scanning_done, 0); + clear_bit(US_FLIDX_SCAN_PENDING, &us->dflags); } static unsigned int usb_stor_sg_tablesize(struct usb_interface *intf) @@ -915,7 +895,7 @@ int usb_stor_probe1(struct us_data **pus, init_completion(&us->cmnd_ready); init_completion(&(us->notify)); init_waitqueue_head(&us->delay_wait); - init_completion(&us->scanning_done); + INIT_DELAYED_WORK(&us->scan_dwork, usb_stor_scan_dwork); /* Associate the us_data structure with the USB device */ result = associate_dev(us, intf); @@ -946,7 +926,6 @@ EXPORT_SYMBOL_GPL(usb_stor_probe1); /* Second part of general USB mass-storage probing */ int usb_stor_probe2(struct us_data *us) { - struct task_struct *th; int result; struct device *dev = &us->pusb_intf->dev; @@ -987,20 +966,14 @@ int usb_stor_probe2(struct us_data *us) goto BadDevice; } - /* Start up the thread for delayed SCSI-device scanning */ - th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan"); - if (IS_ERR(th)) { - dev_warn(dev, - "Unable to start the device-scanning thread\n"); - complete(&us->scanning_done); - quiesce_and_remove_host(us); - result = PTR_ERR(th); - goto BadDevice; - } - + /* Submit the delayed_work for SCSI-device scanning */ usb_autopm_get_interface_no_resume(us->pusb_intf); - wake_up_process(th); + set_bit(US_FLIDX_SCAN_PENDING, &us->dflags); + if (delay_use > 0) + dev_dbg(dev, "waiting for device to settle before scanning\n"); + queue_delayed_work(system_freezable_wq, &us->scan_dwork, + delay_use * HZ); return 0; /* We come here if there are any problems */ diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index 7b0f2113632..75f70f04f37 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -47,6 +47,7 @@ #include #include #include +#include #include struct us_data; @@ -72,7 +73,7 @@ struct us_unusual_dev { #define US_FLIDX_DISCONNECTING 3 /* disconnect in progress */ #define US_FLIDX_RESETTING 4 /* device reset in progress */ #define US_FLIDX_TIMED_OUT 5 /* SCSI midlayer timed out */ -#define US_FLIDX_DONT_SCAN 6 /* don't scan (disconnect) */ +#define US_FLIDX_SCAN_PENDING 6 /* scanning not yet done */ #define US_FLIDX_REDO_READ10 7 /* redo READ(10) command */ #define US_FLIDX_READ10_WORKED 8 /* previous READ(10) succeeded */ @@ -147,8 +148,8 @@ struct us_data { /* mutual exclusion and synchronization structures */ struct completion cmnd_ready; /* to sleep thread on */ struct completion notify; /* thread begin/end */ - wait_queue_head_t delay_wait; /* wait during scan, reset */ - struct completion scanning_done; /* wait for scan thread */ + wait_queue_head_t delay_wait; /* wait during reset */ + struct delayed_work scan_dwork; /* for async scanning */ /* subdriver information */ void *extra; /* Any extra data */ From 5fa70afe044fc0ede6c5ac99c60533e5867ea346 Mon Sep 17 00:00:00 2001 From: Sarah Sharp Date: Thu, 23 Feb 2012 13:20:13 -0800 Subject: [PATCH 0987/4025] USB: Don't fail USB3 probe on missing legacy PCI IRQ. commit 68d07f64b8a11a852d48d1b05b724c3e20c0d94b upstream Intel has a PCI USB xhci host controller on a new platform. It doesn't have a line IRQ definition in BIOS. The Linux driver refuses to initialize this controller, but Windows works well because it only depends on MSI. Actually, Linux also can work for MSI. This patch avoids the line IRQ checking for USB3 HCDs in usb core PCI probe. It allows the xHCI driver to try to enable MSI or MSI-X first. It will fail the probe if MSI enabling failed and there's no legacy PCI IRQ. This patch should be backported to kernels as old as 2.6.32. [Maintainer note: This patch is a backport of commit 68d07f64b8a11a852d48d1b05b724c3e20c0d94b "USB: Don't fail USB3 probe on missing legacy PCI IRQ." to the 3.0 kernel. Note, the original patch description was wrong. We should not back port this to kernels older than 2.6.36, since that was the first kernel to support MSI and MSI-X for xHCI hosts. These systems will just not work without MSI support, so the probe should fail on kernels older than 2.6.36.] Signed-off-by: Alex Shi Signed-off-by: Sarah Sharp Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd-pci.c | 5 ++++- drivers/usb/core/hcd.c | 6 ++++-- drivers/usb/host/xhci.c | 5 +++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index ce22f4a84ed..6c1642b382f 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -187,7 +187,10 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) return -ENODEV; dev->current_state = PCI_D0; - if (!dev->irq) { + /* The xHCI driver supports MSI and MSI-X, + * so don't fail if the BIOS doesn't provide a legacy IRQ. + */ + if (!dev->irq && (driver->flags & HCD_MASK) != HCD_USB3) { dev_err(&dev->dev, "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", pci_name(dev)); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 691d212cac4..45e090850c9 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2435,8 +2435,10 @@ int usb_add_hcd(struct usb_hcd *hcd, && device_can_wakeup(&hcd->self.root_hub->dev)) dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); - /* enable irqs just before we start the controller */ - if (usb_hcd_is_primary_hcd(hcd)) { + /* enable irqs just before we start the controller, + * if the BIOS provides legacy PCI irqs. + */ + if (usb_hcd_is_primary_hcd(hcd) && irqnum) { retval = usb_hcd_request_irqs(hcd, irqnum, irqflags); if (retval) goto err_request_irq; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 107438eca2b..b4416d8dd48 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -444,6 +444,11 @@ int xhci_run(struct usb_hcd *hcd) if (ret) { legacy_irq: + if (!pdev->irq) { + xhci_err(xhci, "No msi-x/msi found and " + "no IRQ in BIOS\n"); + return -EINVAL; + } /* fall back to legacy interrupt*/ ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, hcd->irq_descr, hcd); From 534b465e1cf6e3bbceebbc7866a204107b83eb95 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Wed, 8 Feb 2012 20:52:29 +0100 Subject: [PATCH 0988/4025] x86/amd: Fix L1i and L2 cache sharing information for AMD family 15h processors commit 32c3233885eb10ac9cb9410f2f8cd64b8df2b2a1 upstream. For L1 instruction cache and L2 cache the shared CPU information is wrong. On current AMD family 15h CPUs those caches are shared between both cores of a compute unit. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=42607 Signed-off-by: Andreas Herrmann Cc: Petkov Borislav Cc: Dave Jones Link: http://lkml.kernel.org/r/20120208195229.GA17523@alberich.amd.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/intel_cacheinfo.c | 44 ++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index c105c533ed9..fde44284cf2 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -330,8 +330,7 @@ static void __cpuinit amd_calc_l3_indices(struct amd_l3_cache *l3) l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1; } -static void __cpuinit amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, - int index) +static void __cpuinit amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf, int index) { static struct amd_l3_cache *__cpuinitdata l3_caches; int node; @@ -748,14 +747,16 @@ static DEFINE_PER_CPU(struct _cpuid4_info *, ici_cpuid4_info); #define CPUID4_INFO_IDX(x, y) (&((per_cpu(ici_cpuid4_info, x))[y])) #ifdef CONFIG_SMP -static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index) + +static int __cpuinit cache_shared_amd_cpu_map_setup(unsigned int cpu, int index) { - struct _cpuid4_info *this_leaf, *sibling_leaf; - unsigned long num_threads_sharing; - int index_msb, i, sibling; + struct _cpuid4_info *this_leaf; + int ret, i, sibling; struct cpuinfo_x86 *c = &cpu_data(cpu); - if ((index == 3) && (c->x86_vendor == X86_VENDOR_AMD)) { + ret = 0; + if (index == 3) { + ret = 1; for_each_cpu(i, cpu_llc_shared_mask(cpu)) { if (!per_cpu(ici_cpuid4_info, i)) continue; @@ -766,8 +767,35 @@ static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index) set_bit(sibling, this_leaf->shared_cpu_map); } } - return; + } else if ((c->x86 == 0x15) && ((index == 1) || (index == 2))) { + ret = 1; + for_each_cpu(i, cpu_sibling_mask(cpu)) { + if (!per_cpu(ici_cpuid4_info, i)) + continue; + this_leaf = CPUID4_INFO_IDX(i, index); + for_each_cpu(sibling, cpu_sibling_mask(cpu)) { + if (!cpu_online(sibling)) + continue; + set_bit(sibling, this_leaf->shared_cpu_map); + } + } } + + return ret; +} + +static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index) +{ + struct _cpuid4_info *this_leaf, *sibling_leaf; + unsigned long num_threads_sharing; + int index_msb, i; + struct cpuinfo_x86 *c = &cpu_data(cpu); + + if (c->x86_vendor == X86_VENDOR_AMD) { + if (cache_shared_amd_cpu_map_setup(cpu, index)) + return; + } + this_leaf = CPUID4_INFO_IDX(cpu, index); num_threads_sharing = 1 + this_leaf->eax.split.num_threads_sharing; From 6778e220c09cdfb19a326192fd25ee146755b95d Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Sat, 11 Feb 2012 10:01:53 -0500 Subject: [PATCH 0989/4025] ath9k: stop on rates with idx -1 in ath9k rate control's .tx_status commit 2504a6423b9ab4c36df78227055995644de19edb upstream. Rate control algorithms are supposed to stop processing when they encounter a rate with the index -1. Checking for rate->count not being zero is not enough. Allowing a rate with negative index leads to memory corruption in ath_debug_stat_rc(). One consequence of the bug is discussed at https://bugzilla.redhat.com/show_bug.cgi?id=768639 Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/rc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index ea35843dd38..9d965e37b00 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1328,7 +1328,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, fc = hdr->frame_control; for (i = 0; i < sc->hw->max_rates; i++) { struct ieee80211_tx_rate *rate = &tx_info->status.rates[i]; - if (!rate->count) + if (rate->idx < 0 || !rate->count) break; final_ts_idx = i; From b7f0787da3657100fe8fc8b3f0565b0bee341510 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 7 Feb 2012 17:58:03 +0100 Subject: [PATCH 0990/4025] genirq: Unmask oneshot irqs when thread was not woken commit ac5637611150281f398bb7a47e3fcb69a09e7803 upstream. When the primary handler of an interrupt which is marked IRQ_ONESHOT returns IRQ_HANDLED or IRQ_NONE, then the interrupt thread is not woken and the unmask logic of the interrupt line is never invoked. This keeps the interrupt masked forever. This was not noticed as most IRQ_ONESHOT users wake the thread unconditionally (usually because they cannot access the underlying device from hard interrupt context). Though this behaviour was nowhere documented and not necessarily intentional. Some drivers can avoid the thread wakeup in certain cases and run into the situation where the interrupt line s kept masked. Handle it gracefully. Reported-and-tested-by: Lothar Wassmann Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/irq/chip.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index dc5114b4c16..3322a34d9ee 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -312,6 +312,24 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc) } EXPORT_SYMBOL_GPL(handle_simple_irq); +/* + * Called unconditionally from handle_level_irq() and only for oneshot + * interrupts from handle_fasteoi_irq() + */ +static void cond_unmask_irq(struct irq_desc *desc) +{ + /* + * We need to unmask in the following cases: + * - Standard level irq (IRQF_ONESHOT is not set) + * - Oneshot irq which did not wake the thread (caused by a + * spurious interrupt or a primary handler handling it + * completely). + */ + if (!irqd_irq_disabled(&desc->irq_data) && + irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) + unmask_irq(desc); +} + /** * handle_level_irq - Level type irq handler * @irq: the interrupt number @@ -344,8 +362,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc) handle_irq_event(desc); - if (!irqd_irq_disabled(&desc->irq_data) && !(desc->istate & IRQS_ONESHOT)) - unmask_irq(desc); + cond_unmask_irq(desc); + out_unlock: raw_spin_unlock(&desc->lock); } @@ -399,6 +417,9 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc) preflow_handler(desc); handle_irq_event(desc); + if (desc->istate & IRQS_ONESHOT) + cond_unmask_irq(desc); + out_eoi: desc->irq_data.chip->irq_eoi(&desc->irq_data); out_unlock: From fd844dabebb45631b2e99a02ee6601ca136f10bd Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 8 Feb 2012 11:57:52 +0100 Subject: [PATCH 0991/4025] genirq: Handle pending irqs in irq_startup() commit b4bc724e82e80478cba5fe9825b62e71ddf78757 upstream. An interrupt might be pending when irq_startup() is called, but the startup code does not invoke the resend logic. In some cases this prevents the device from issuing another interrupt which renders the device non functional. Call the resend function in irq_startup() to keep things going. Reported-and-tested-by: Russell King Signed-off-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- kernel/irq/autoprobe.c | 4 ++-- kernel/irq/chip.c | 17 ++++++++++------- kernel/irq/internals.h | 2 +- kernel/irq/manage.c | 2 +- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/kernel/irq/autoprobe.c b/kernel/irq/autoprobe.c index 342d8f44e40..0119b9d467a 100644 --- a/kernel/irq/autoprobe.c +++ b/kernel/irq/autoprobe.c @@ -53,7 +53,7 @@ unsigned long probe_irq_on(void) if (desc->irq_data.chip->irq_set_type) desc->irq_data.chip->irq_set_type(&desc->irq_data, IRQ_TYPE_PROBE); - irq_startup(desc); + irq_startup(desc, false); } raw_spin_unlock_irq(&desc->lock); } @@ -70,7 +70,7 @@ unsigned long probe_irq_on(void) raw_spin_lock_irq(&desc->lock); if (!desc->action && irq_settings_can_probe(desc)) { desc->istate |= IRQS_AUTODETECT | IRQS_WAITING; - if (irq_startup(desc)) + if (irq_startup(desc, false)) desc->istate |= IRQS_PENDING; } raw_spin_unlock_irq(&desc->lock); diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index 3322a34d9ee..ca14f5dcabd 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -157,19 +157,22 @@ static void irq_state_set_masked(struct irq_desc *desc) irqd_set(&desc->irq_data, IRQD_IRQ_MASKED); } -int irq_startup(struct irq_desc *desc) +int irq_startup(struct irq_desc *desc, bool resend) { + int ret = 0; + irq_state_clr_disabled(desc); desc->depth = 0; if (desc->irq_data.chip->irq_startup) { - int ret = desc->irq_data.chip->irq_startup(&desc->irq_data); + ret = desc->irq_data.chip->irq_startup(&desc->irq_data); irq_state_clr_masked(desc); - return ret; + } else { + irq_enable(desc); } - - irq_enable(desc); - return 0; + if (resend) + check_irq_resend(desc, desc->irq_data.irq); + return ret; } void irq_shutdown(struct irq_desc *desc) @@ -596,7 +599,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, irq_settings_set_noprobe(desc); irq_settings_set_norequest(desc); irq_settings_set_nothread(desc); - irq_startup(desc); + irq_startup(desc, true); } out: irq_put_desc_busunlock(desc, flags); diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index 6546431447d..62efdc44b64 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h @@ -67,7 +67,7 @@ extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp); extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume); -extern int irq_startup(struct irq_desc *desc); +extern int irq_startup(struct irq_desc *desc, bool resend); extern void irq_shutdown(struct irq_desc *desc); extern void irq_enable(struct irq_desc *desc); extern void irq_disable(struct irq_desc *desc); diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index a1aadab09aa..def3406fb43 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1018,7 +1018,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) desc->istate |= IRQS_ONESHOT; if (irq_settings_can_autoenable(desc)) - irq_startup(desc); + irq_startup(desc, true); else /* Undo nested disables: */ desc->depth = 1; From bbfe8a71f0a352ffaf4b8e390024b0ebb90f1030 Mon Sep 17 00:00:00 2001 From: Huajun Li Date: Sun, 12 Feb 2012 19:59:14 +0800 Subject: [PATCH 0992/4025] scsi_scan: Fix 'Poison overwritten' warning caused by using freed 'shost' commit 267a6ad4aefaafbde607804c60945bcf97f91c1b upstream. In do_scan_async(), calling scsi_autopm_put_host(shost) may reference freed shost, and cause Posison overwitten warning. Yes, this case can happen, for example, an USB is disconnected just when do_scan_async() thread starts to run, then scsi_host_put() called in scsi_finish_async_scan() will lead to shost be freed(because the refcount of shost->shost_gendev decreases to 1 after USB disconnects), at this point, if references shost again, system will show following warning msg. To make scsi_autopm_put_host(shost) always reference a valid shost, put it just before scsi_host_put() in function scsi_finish_async_scan(). [ 299.281565] ============================================================================= [ 299.281634] BUG kmalloc-4096 (Tainted: G I ): Poison overwritten [ 299.281682] ----------------------------------------------------------------------------- [ 299.281684] [ 299.281752] INFO: 0xffff880056c305d0-0xffff880056c305d0. First byte 0x6a instead of 0x6b [ 299.281816] INFO: Allocated in scsi_host_alloc+0x4a/0x490 age=1688 cpu=1 pid=2004 [ 299.281870] __slab_alloc+0x617/0x6c1 [ 299.281901] __kmalloc+0x28c/0x2e0 [ 299.281931] scsi_host_alloc+0x4a/0x490 [ 299.281966] usb_stor_probe1+0x5b/0xc40 [usb_storage] [ 299.282010] storage_probe+0xa4/0xe0 [usb_storage] [ 299.282062] usb_probe_interface+0x172/0x330 [usbcore] [ 299.282105] driver_probe_device+0x257/0x3b0 [ 299.282138] __driver_attach+0x103/0x110 [ 299.282171] bus_for_each_dev+0x8e/0xe0 [ 299.282201] driver_attach+0x26/0x30 [ 299.282230] bus_add_driver+0x1c4/0x430 [ 299.282260] driver_register+0xb6/0x230 [ 299.282298] usb_register_driver+0xe5/0x270 [usbcore] [ 299.282337] 0xffffffffa04ab03d [ 299.282364] do_one_initcall+0x47/0x230 [ 299.282396] sys_init_module+0xa0f/0x1fe0 [ 299.282429] INFO: Freed in scsi_host_dev_release+0x18a/0x1d0 age=85 cpu=0 pid=2008 [ 299.282482] __slab_free+0x3c/0x2a1 [ 299.282510] kfree+0x296/0x310 [ 299.282536] scsi_host_dev_release+0x18a/0x1d0 [ 299.282574] device_release+0x74/0x100 [ 299.282606] kobject_release+0xc7/0x2a0 [ 299.282637] kobject_put+0x54/0xa0 [ 299.282668] put_device+0x27/0x40 [ 299.282694] scsi_host_put+0x1d/0x30 [ 299.282723] do_scan_async+0x1fc/0x2b0 [ 299.282753] kthread+0xdf/0xf0 [ 299.282782] kernel_thread_helper+0x4/0x10 [ 299.282817] INFO: Slab 0xffffea00015b0c00 objects=7 used=7 fp=0x (null) flags=0x100000000004080 [ 299.282882] INFO: Object 0xffff880056c30000 @offset=0 fp=0x (null) [ 299.282884] ... Signed-off-by: Huajun Li Acked-by: Alan Stern Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_scan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index b3c6d957fbd..6e7ea4a2b7a 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1815,6 +1815,7 @@ static void scsi_finish_async_scan(struct async_scan_data *data) } spin_unlock(&async_scan_lock); + scsi_autopm_put_host(shost); scsi_host_put(shost); kfree(data); } @@ -1841,7 +1842,6 @@ static int do_scan_async(void *_data) do_scsi_scan_host(shost); scsi_finish_async_scan(data); - scsi_autopm_put_host(shost); return 0; } @@ -1869,7 +1869,7 @@ void scsi_scan_host(struct Scsi_Host *shost) p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); if (IS_ERR(p)) do_scan_async(data); - /* scsi_autopm_put_host(shost) is called in do_scan_async() */ + /* scsi_autopm_put_host(shost) is called in scsi_finish_async_scan() */ } EXPORT_SYMBOL(scsi_scan_host); From 4b3b9e9efc80ceae3370e42009ec17b682776734 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 17 Feb 2012 16:25:08 -0500 Subject: [PATCH 0993/4025] scsi_pm: Fix bug in the SCSI power management handler commit fea6d607e154cf96ab22254ccb48addfd43d4cb5 upstream. This patch (as1520) fixes a bug in the SCSI layer's power management implementation. LUN scanning can be carried out asynchronously in do_scan_async(), and sd uses an asynchronous thread for the time-consuming parts of disk probing in sd_probe_async(). Currently nothing coordinates these async threads with system sleep transitions; they can and do attempt to continue scanning/probing SCSI devices even after the host adapter has been suspended. As one might expect, the outcome is not ideal. This is what the "prepare" stage of system suspend was created for. After the prepare callback has been called for a host, target, or device, drivers are not allowed to register any children underneath them. Currently the SCSI prepare callback is not implemented; this patch rectifies that omission. For SCSI hosts, the prepare routine calls scsi_complete_async_scans() to wait until async scanning is finished. It might be slightly more efficient to wait only until the host in question has been scanned, but there's currently no way to do that. Besides, during a sleep transition we will ultimately have to wait until all the host scanning has finished anyway. For SCSI devices, the prepare routine calls async_synchronize_full() to wait until sd probing is finished. The routine does nothing for SCSI targets, because asynchronous target scanning is done only as part of host scanning. Signed-off-by: Alan Stern Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_pm.c | 16 ++++++++++++++++ drivers/scsi/scsi_priv.h | 1 + 2 files changed, 17 insertions(+) diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c index d70e91ae60a..122a5a2020a 100644 --- a/drivers/scsi/scsi_pm.c +++ b/drivers/scsi/scsi_pm.c @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -68,6 +69,19 @@ static int scsi_bus_resume_common(struct device *dev) return err; } +static int scsi_bus_prepare(struct device *dev) +{ + if (scsi_is_sdev_device(dev)) { + /* sd probing uses async_schedule. Wait until it finishes. */ + async_synchronize_full(); + + } else if (scsi_is_host_device(dev)) { + /* Wait until async scanning is finished */ + scsi_complete_async_scans(); + } + return 0; +} + static int scsi_bus_suspend(struct device *dev) { return scsi_bus_suspend_common(dev, PMSG_SUSPEND); @@ -86,6 +100,7 @@ static int scsi_bus_poweroff(struct device *dev) #else /* CONFIG_PM_SLEEP */ #define scsi_bus_resume_common NULL +#define scsi_bus_prepare NULL #define scsi_bus_suspend NULL #define scsi_bus_freeze NULL #define scsi_bus_poweroff NULL @@ -194,6 +209,7 @@ void scsi_autopm_put_host(struct Scsi_Host *shost) #endif /* CONFIG_PM_RUNTIME */ const struct dev_pm_ops scsi_bus_pm_ops = { + .prepare = scsi_bus_prepare, .suspend = scsi_bus_suspend, .resume = scsi_bus_resume_common, .freeze = scsi_bus_freeze, diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 2a588955423..5b475d0832c 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -110,6 +110,7 @@ extern void scsi_exit_procfs(void); #endif /* CONFIG_PROC_FS */ /* scsi_scan.c */ +extern int scsi_complete_async_scans(void); extern int scsi_scan_host_selected(struct Scsi_Host *, unsigned int, unsigned int, unsigned int, int); extern void scsi_forget_host(struct Scsi_Host *); From 426f45680cc71385a8929f11654c789f5019315c Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 27 Jan 2012 10:45:27 +0900 Subject: [PATCH 0994/4025] ipvs: fix matching of fwmark templates during scheduling commit e0aac52e17a3db68fe2ceae281780a70fc69957f upstream. Commit f11017ec2d1859c661f4e2b12c4a8d250e1f47cf (2.6.37) moved the fwmark variable in subcontext that is invalidated before reaching the ip_vs_ct_in_get call. As vaddr is provided as pointer in the param structure make sure the fwmark variable is in same context. As the fwmark templates can not be matched, more and more template connections are created and the controlled connections can not go to single real server. Signed-off-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/ipvs/ip_vs_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 24c28d238dc..0787bed0418 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -233,6 +233,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc, __be16 dport = 0; /* destination port to forward */ unsigned int flags; struct ip_vs_conn_param param; + const union nf_inet_addr fwmark = { .ip = htonl(svc->fwmark) }; union nf_inet_addr snet; /* source network of the client, after masking */ @@ -268,7 +269,6 @@ ip_vs_sched_persist(struct ip_vs_service *svc, { int protocol = iph.protocol; const union nf_inet_addr *vaddr = &iph.daddr; - const union nf_inet_addr fwmark = { .ip = htonl(svc->fwmark) }; __be16 vport = 0; if (dst_port == svc->port) { From 405b695987efa52866d0df612cdb67d71daf055d Mon Sep 17 00:00:00 2001 From: Guo-Fu Tseng Date: Wed, 22 Feb 2012 08:58:10 +0000 Subject: [PATCH 0995/4025] jme: Fix FIFO flush issue commit ba9adbe67e288823ac1deb7f11576ab5653f833e upstream. Set the RX FIFO flush watermark lower. According to Federico and JMicron's reply, setting it to 16QW would be stable on most platforms. Otherwise, user might experience packet drop issue. Reported-by: Federico Quagliata Fixed-by: Federico Quagliata Signed-off-by: Guo-Fu Tseng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/jme.c | 10 +--------- drivers/net/jme.h | 2 +- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 19738143aa9..1d1ccec6072 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -2228,19 +2228,11 @@ jme_change_mtu(struct net_device *netdev, int new_mtu) ((new_mtu) < IPV6_MIN_MTU)) return -EINVAL; - if (new_mtu > 4000) { - jme->reg_rxcs &= ~RXCS_FIFOTHNP; - jme->reg_rxcs |= RXCS_FIFOTHNP_64QW; - jme_restart_rx_engine(jme); - } else { - jme->reg_rxcs &= ~RXCS_FIFOTHNP; - jme->reg_rxcs |= RXCS_FIFOTHNP_128QW; - jme_restart_rx_engine(jme); - } netdev->mtu = new_mtu; netdev_update_features(netdev); + jme_restart_rx_engine(jme); jme_reset_link(jme); return 0; diff --git a/drivers/net/jme.h b/drivers/net/jme.h index e9aaeca96ab..fff885e9274 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -734,7 +734,7 @@ enum jme_rxcs_values { RXCS_RETRYCNT_60 = 0x00000F00, RXCS_DEFAULT = RXCS_FIFOTHTP_128T | - RXCS_FIFOTHNP_128QW | + RXCS_FIFOTHNP_16QW | RXCS_DMAREQSZ_128B | RXCS_RETRYGAP_256ns | RXCS_RETRYCNT_32, From 841099b95f7490cb33f1af48aac8e619ba1712c7 Mon Sep 17 00:00:00 2001 From: Christian Riesch Date: Thu, 23 Feb 2012 01:14:17 +0000 Subject: [PATCH 0996/4025] davinci_emac: Do not free all rx dma descriptors during init commit 5d69703263d588dbb03f4e57091afd8942d96e6d upstream. This patch fixes a regression that was introduced by commit 0a5f38467765ee15478db90d81e40c269c8dda20 davinci_emac: Add Carrier Link OK check in Davinci RX Handler Said commit adds a check whether the carrier link is ok. If the link is not ok, the skb is freed and no new dma descriptor added to the rx dma channel. This causes trouble during initialization when the carrier status has not yet been updated. If a lot of packets are received while netif_carrier_ok returns false, all dma descriptors are freed and the rx dma transfer is stopped. The bug occurs when the board is connected to a network with lots of traffic and the ifconfig down/up is done, e.g., when reconfiguring the interface with DHCP. The bug can be reproduced by flood pinging the davinci board while doing ifconfig eth0 down ifconfig eth0 up on the board. After that, the rx path stops working and the overrun value reported by ifconfig is counting up. This patch reverts commit 0a5f38467765ee15478db90d81e40c269c8dda20 and instead issues warnings only if cpdma_chan_submit returns -ENOMEM. Signed-off-by: Christian Riesch Cc: Cc: Cyril Chemparathy Cc: Sascha Hauer Tested-by: Rajashekhara, Sudhakar Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/davinci_emac.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index dcc4a170b0f..e5efe3aec0f 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -1008,7 +1008,7 @@ static void emac_rx_handler(void *token, int len, int status) int ret; /* free and bail if we are shutting down */ - if (unlikely(!netif_running(ndev) || !netif_carrier_ok(ndev))) { + if (unlikely(!netif_running(ndev))) { dev_kfree_skb_any(skb); return; } @@ -1037,7 +1037,9 @@ static void emac_rx_handler(void *token, int len, int status) recycle: ret = cpdma_chan_submit(priv->rxchan, skb, skb->data, skb_tailroom(skb), GFP_KERNEL); - if (WARN_ON(ret < 0)) + + WARN_ON(ret == -ENOMEM); + if (unlikely(ret < 0)) dev_kfree_skb_any(skb); } From 674b8d57dbaaed07f3825584c856b977716ec3bd Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Wed, 15 Feb 2012 14:17:29 +0000 Subject: [PATCH 0997/4025] builddeb: Don't create files in /tmp with predictable names commit 6c635224602d760c1208ada337562f40d8ae93a5 upstream. The current use of /tmp for file lists is insecure. Put them under $objtree/debian instead. Signed-off-by: Ben Hutchings Acked-by: maximilian attems Signed-off-by: Michal Marek Signed-off-by: Greg Kroah-Hartman --- scripts/package/builddeb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/package/builddeb b/scripts/package/builddeb index f6cbc3ddb68..3c6c0b14c80 100644 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -238,14 +238,14 @@ EOF fi # Build header package -(cd $srctree; find . -name Makefile -o -name Kconfig\* -o -name \*.pl > /tmp/files$$) -(cd $srctree; find arch/$SRCARCH/include include scripts -type f >> /tmp/files$$) -(cd $objtree; find .config Module.symvers include scripts -type f >> /tmp/objfiles$$) +(cd $srctree; find . -name Makefile -o -name Kconfig\* -o -name \*.pl > "$objtree/debian/hdrsrcfiles") +(cd $srctree; find arch/$SRCARCH/include include scripts -type f >> "$objtree/debian/hdrsrcfiles") +(cd $objtree; find .config Module.symvers include scripts -type f >> "$objtree/debian/hdrobjfiles") destdir=$kernel_headers_dir/usr/src/linux-headers-$version mkdir -p "$destdir" -(cd $srctree; tar -c -f - -T /tmp/files$$) | (cd $destdir; tar -xf -) -(cd $objtree; tar -c -f - -T /tmp/objfiles$$) | (cd $destdir; tar -xf -) -rm -f /tmp/files$$ /tmp/objfiles$$ +(cd $srctree; tar -c -f - -T "$objtree/debian/hdrsrcfiles") | (cd $destdir; tar -xf -) +(cd $objtree; tar -c -f - -T "$objtree/debian/hdrobjfiles") | (cd $destdir; tar -xf -) +rm -f "$objtree/debian/hdrsrcfiles" "$objtree/debian/hdrobjfiles" arch=$(dpkg --print-architecture) cat <> debian/control From c79db0b57006fddace56ac038e7340bdea18077b Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Thu, 2 Feb 2012 13:35:21 -0300 Subject: [PATCH 0998/4025] hdpvr: fix race conditon during start of streaming commit afa159538af61f1a65d48927f4e949fe514fb4fc upstream. status has to be set to STREAMING before the streaming worker is queued. hdpvr_transmit_buffers() will exit immediately otherwise. Reported-by: Joerg Desch Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/video/hdpvr/hdpvr-video.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c index 514aea76eaa..4c0394a8afd 100644 --- a/drivers/media/video/hdpvr/hdpvr-video.c +++ b/drivers/media/video/hdpvr/hdpvr-video.c @@ -284,12 +284,13 @@ static int hdpvr_start_streaming(struct hdpvr_device *dev) hdpvr_config_call(dev, CTRL_START_STREAMING_VALUE, 0x00); + dev->status = STATUS_STREAMING; + INIT_WORK(&dev->worker, hdpvr_transmit_buffers); queue_work(dev->workqueue, &dev->worker); v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, "streaming started\n"); - dev->status = STATUS_STREAMING; return 0; } From 809a6d6fddb556579e651ad1fb652d6012f8a102 Mon Sep 17 00:00:00 2001 From: Nikolaus Schulz Date: Wed, 22 Feb 2012 23:18:44 +0100 Subject: [PATCH 0999/4025] hwmon: (f75375s) Fix register write order when setting fans to full speed commit c1c1a3d012fe5e82a9a025fb4b5a4f8ee67a53f6 upstream. By hwmon sysfs interface convention, setting pwm_enable to zero sets a fan to full speed. In the f75375s driver, this need be done by enabling manual fan control, plus duty mode for the F875387 chip, and then setting the maximum duty cycle. Fix a bug where the two necessary register writes were swapped, effectively discarding the setting to full-speed. Signed-off-by: Nikolaus Schulz Cc: Riku Voipio Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/f75375s.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index e4ab4918f63..040a820acd1 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -304,8 +304,6 @@ static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val) case 0: /* Full speed */ fanmode |= (3 << FAN_CTRL_MODE(nr)); data->pwm[nr] = 255; - f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), - data->pwm[nr]); break; case 1: /* PWM */ fanmode |= (3 << FAN_CTRL_MODE(nr)); @@ -318,6 +316,9 @@ static int set_pwm_enable_direct(struct i2c_client *client, int nr, int val) } f75375_write8(client, F75375_REG_FAN_TIMER, fanmode); data->pwm_enable[nr] = val; + if (val == 0) + f75375_write8(client, F75375_REG_FAN_PWM_DUTY(nr), + data->pwm[nr]); return 0; } From 391d7bfe9ce7a08a700f1ff3dc950a347b23e3cb Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 24 Feb 2012 20:07:11 +0100 Subject: [PATCH 1000/4025] epoll: introduce POLLFREE to flush ->signalfd_wqh before kfree() commit d80e731ecab420ddcb79ee9d0ac427acbc187b4b upstream. This patch is intentionally incomplete to simplify the review. It ignores ep_unregister_pollwait() which plays with the same wqh. See the next change. epoll assumes that the EPOLL_CTL_ADD'ed file controls everything f_op->poll() needs. In particular it assumes that the wait queue can't go away until eventpoll_release(). This is not true in case of signalfd, the task which does EPOLL_CTL_ADD uses its ->sighand which is not connected to the file. This patch adds the special event, POLLFREE, currently only for epoll. It expects that init_poll_funcptr()'ed hook should do the necessary cleanup. Perhaps it should be defined as EPOLLFREE in eventpoll. __cleanup_sighand() is changed to do wake_up_poll(POLLFREE) if ->signalfd_wqh is not empty, we add the new signalfd_cleanup() helper. ep_poll_callback(POLLFREE) simply does list_del_init(task_list). This make this poll entry inconsistent, but we don't care. If you share epoll fd which contains our sigfd with another process you should blame yourself. signalfd is "really special". I simply do not know how we can define the "right" semantics if it used with epoll. The main problem is, epoll calls signalfd_poll() once to establish the connection with the wait queue, after that signalfd_poll(NULL) returns the different/inconsistent results depending on who does EPOLL_CTL_MOD/signalfd_read/etc. IOW: apart from sigmask, signalfd has nothing to do with the file, it works with the current thread. In short: this patch is the hack which tries to fix the symptoms. It also assumes that nobody can take tasklist_lock under epoll locks, this seems to be true. Note: - we do not have wake_up_all_poll() but wake_up_poll() is fine, poll/epoll doesn't use WQ_FLAG_EXCLUSIVE. - signalfd_cleanup() uses POLLHUP along with POLLFREE, we need a couple of simple changes in eventpoll.c to make sure it can't be "lost". Reported-by: Maxime Bizon Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/eventpoll.c | 4 ++++ fs/signalfd.c | 11 +++++++++++ include/asm-generic/poll.h | 2 ++ include/linux/signalfd.h | 5 ++++- kernel/fork.c | 5 ++++- 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 2acaf60f4e4..2ce761cf920 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -827,6 +827,10 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k struct epitem *epi = ep_item_from_wait(wait); struct eventpoll *ep = epi->ep; + /* the caller holds eppoll_entry->whead->lock */ + if ((unsigned long)key & POLLFREE) + list_del_init(&wait->task_list); + spin_lock_irqsave(&ep->lock, flags); /* diff --git a/fs/signalfd.c b/fs/signalfd.c index 492465b451d..79c1eea98a3 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -30,6 +30,17 @@ #include #include +void signalfd_cleanup(struct sighand_struct *sighand) +{ + wait_queue_head_t *wqh = &sighand->signalfd_wqh; + + if (likely(!waitqueue_active(wqh))) + return; + + /* wait_queue_t->func(POLLFREE) should do remove_wait_queue() */ + wake_up_poll(wqh, POLLHUP | POLLFREE); +} + struct signalfd_ctx { sigset_t sigmask; }; diff --git a/include/asm-generic/poll.h b/include/asm-generic/poll.h index 44bce836d35..9ce7f44aebd 100644 --- a/include/asm-generic/poll.h +++ b/include/asm-generic/poll.h @@ -28,6 +28,8 @@ #define POLLRDHUP 0x2000 #endif +#define POLLFREE 0x4000 /* currently only for epoll */ + struct pollfd { int fd; short events; diff --git a/include/linux/signalfd.h b/include/linux/signalfd.h index 3ff4961da9b..247399b2979 100644 --- a/include/linux/signalfd.h +++ b/include/linux/signalfd.h @@ -61,13 +61,16 @@ static inline void signalfd_notify(struct task_struct *tsk, int sig) wake_up(&tsk->sighand->signalfd_wqh); } +extern void signalfd_cleanup(struct sighand_struct *sighand); + #else /* CONFIG_SIGNALFD */ static inline void signalfd_notify(struct task_struct *tsk, int sig) { } +static inline void signalfd_cleanup(struct sighand_struct *sighand) { } + #endif /* CONFIG_SIGNALFD */ #endif /* __KERNEL__ */ #endif /* _LINUX_SIGNALFD_H */ - diff --git a/kernel/fork.c b/kernel/fork.c index 0276c30401a..a4e453b14f7 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -67,6 +67,7 @@ #include #include #include +#include #include #include @@ -917,8 +918,10 @@ static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk) void __cleanup_sighand(struct sighand_struct *sighand) { - if (atomic_dec_and_test(&sighand->count)) + if (atomic_dec_and_test(&sighand->count)) { + signalfd_cleanup(sighand); kmem_cache_free(sighand_cachep, sighand); + } } From d10e3b2952f0df0f23896e32ed54a5a6c916058e Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 24 Feb 2012 20:07:29 +0100 Subject: [PATCH 1001/4025] epoll: ep_unregister_pollwait() can use the freed pwq->whead commit 971316f0503a5c50633d07b83b6db2f15a3a5b00 upstream. signalfd_cleanup() ensures that ->signalfd_wqh is not used, but this is not enough. eppoll_entry->whead still points to the memory we are going to free, ep_unregister_pollwait()->remove_wait_queue() is obviously unsafe. Change ep_poll_callback(POLLFREE) to set eppoll_entry->whead = NULL, change ep_unregister_pollwait() to check pwq->whead != NULL under rcu_read_lock() before remove_wait_queue(). We add the new helper, ep_remove_wait_queue(), for this. This works because sighand_cachep is SLAB_DESTROY_BY_RCU and because ->signalfd_wqh is initialized in sighand_ctor(), not in copy_sighand. ep_unregister_pollwait()->remove_wait_queue() can play with already freed and potentially reused ->sighand, but this is fine. This memory must have the valid ->signalfd_wqh until rcu_read_unlock(). Reported-by: Maxime Bizon Signed-off-by: Oleg Nesterov Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/eventpoll.c | 30 +++++++++++++++++++++++++++--- fs/signalfd.c | 6 +++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 2ce761cf920..a39cf4cfb9d 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -299,6 +299,11 @@ static inline int ep_is_linked(struct list_head *p) return !list_empty(p); } +static inline struct eppoll_entry *ep_pwq_from_wait(wait_queue_t *p) +{ + return container_of(p, struct eppoll_entry, wait); +} + /* Get the "struct epitem" from a wait queue pointer */ static inline struct epitem *ep_item_from_wait(wait_queue_t *p) { @@ -446,6 +451,18 @@ static void ep_poll_safewake(wait_queue_head_t *wq) put_cpu(); } +static void ep_remove_wait_queue(struct eppoll_entry *pwq) +{ + wait_queue_head_t *whead; + + rcu_read_lock(); + /* If it is cleared by POLLFREE, it should be rcu-safe */ + whead = rcu_dereference(pwq->whead); + if (whead) + remove_wait_queue(whead, &pwq->wait); + rcu_read_unlock(); +} + /* * This function unregisters poll callbacks from the associated file * descriptor. Must be called with "mtx" held (or "epmutex" if called from @@ -460,7 +477,7 @@ static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi) pwq = list_first_entry(lsthead, struct eppoll_entry, llink); list_del(&pwq->llink); - remove_wait_queue(pwq->whead, &pwq->wait); + ep_remove_wait_queue(pwq); kmem_cache_free(pwq_cache, pwq); } } @@ -827,9 +844,16 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k struct epitem *epi = ep_item_from_wait(wait); struct eventpoll *ep = epi->ep; - /* the caller holds eppoll_entry->whead->lock */ - if ((unsigned long)key & POLLFREE) + if ((unsigned long)key & POLLFREE) { + ep_pwq_from_wait(wait)->whead = NULL; + /* + * whead = NULL above can race with ep_remove_wait_queue() + * which can do another remove_wait_queue() after us, so we + * can't use __remove_wait_queue(). whead->lock is held by + * the caller. + */ list_del_init(&wait->task_list); + } spin_lock_irqsave(&ep->lock, flags); diff --git a/fs/signalfd.c b/fs/signalfd.c index 79c1eea98a3..7ae2a574cb2 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -33,7 +33,11 @@ void signalfd_cleanup(struct sighand_struct *sighand) { wait_queue_head_t *wqh = &sighand->signalfd_wqh; - + /* + * The lockless check can race with remove_wait_queue() in progress, + * but in this case its caller should run under rcu_read_lock() and + * sighand_cachep is SLAB_DESTROY_BY_RCU, we can safely return. + */ if (likely(!waitqueue_active(wqh))) return; From 547740231f76185aadbef34dfa83c3e7dba3b34b Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Thu, 12 Jan 2012 17:17:43 -0800 Subject: [PATCH 1002/4025] epoll: limit paths commit 28d82dc1c4edbc352129f97f4ca22624d1fe61de upstream. The current epoll code can be tickled to run basically indefinitely in both loop detection path check (on ep_insert()), and in the wakeup paths. The programs that tickle this behavior set up deeply linked networks of epoll file descriptors that cause the epoll algorithms to traverse them indefinitely. A couple of these sample programs have been previously posted in this thread: https://lkml.org/lkml/2011/2/25/297. To fix the loop detection path check algorithms, I simply keep track of the epoll nodes that have been already visited. Thus, the loop detection becomes proportional to the number of epoll file descriptor and links. This dramatically decreases the run-time of the loop check algorithm. In one diabolical case I tried it reduced the run-time from 15 mintues (all in kernel time) to .3 seconds. Fixing the wakeup paths could be done at wakeup time in a similar manner by keeping track of nodes that have already been visited, but the complexity is harder, since there can be multiple wakeups on different cpus...Thus, I've opted to limit the number of possible wakeup paths when the paths are created. This is accomplished, by noting that the end file descriptor points that are found during the loop detection pass (from the newly added link), are actually the sources for wakeup events. I keep a list of these file descriptors and limit the number and length of these paths that emanate from these 'source file descriptors'. In the current implemetation I allow 1000 paths of length 1, 500 of length 2, 100 of length 3, 50 of length 4 and 10 of length 5. Note that it is sufficient to check the 'source file descriptors' reachable from the newly added link, since no other 'source file descriptors' will have newly added links. This allows us to check only the wakeup paths that may have gotten too long, and not re-check all possible wakeup paths on the system. In terms of the path limit selection, I think its first worth noting that the most common case for epoll, is probably the model where you have 1 epoll file descriptor that is monitoring n number of 'source file descriptors'. In this case, each 'source file descriptor' has a 1 path of length 1. Thus, I believe that the limits I'm proposing are quite reasonable and in fact may be too generous. Thus, I'm hoping that the proposed limits will not prevent any workloads that currently work to fail. In terms of locking, I have extended the use of the 'epmutex' to all epoll_ctl add and remove operations. Currently its only used in a subset of the add paths. I need to hold the epmutex, so that we can correctly traverse a coherent graph, to check the number of paths. I believe that this additional locking is probably ok, since its in the setup/teardown paths, and doesn't affect the running paths, but it certainly is going to add some extra overhead. Also, worth noting is that the epmuex was recently added to the ep_ctl add operations in the initial path loop detection code using the argument that it was not on a critical path. Another thing to note here, is the length of epoll chains that is allowed. Currently, eventpoll.c defines: /* Maximum number of nesting allowed inside epoll sets */ #define EP_MAX_NESTS 4 This basically means that I am limited to a graph depth of 5 (EP_MAX_NESTS + 1). However, this limit is currently only enforced during the loop check detection code, and only when the epoll file descriptors are added in a certain order. Thus, this limit is currently easily bypassed. The newly added check for wakeup paths, stricly limits the wakeup paths to a length of 5, regardless of the order in which ep's are linked together. Thus, a side-effect of the new code is a more consistent enforcement of the graph depth. Thus far, I've tested this, using the sample programs previously mentioned, which now either return quickly or return -EINVAL. I've also testing using the piptest.c epoll tester, which showed no difference in performance. I've also created a number of different epoll networks and tested that they behave as expectded. I believe this solves the original diabolical test cases, while still preserving the sane epoll nesting. Signed-off-by: Jason Baron Cc: Nelson Elhage Cc: Davide Libenzi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/eventpoll.c | 234 ++++++++++++++++++++++++++++++++++---- include/linux/eventpoll.h | 1 + include/linux/fs.h | 1 + 3 files changed, 211 insertions(+), 25 deletions(-) diff --git a/fs/eventpoll.c b/fs/eventpoll.c index a39cf4cfb9d..6879d0c5cb5 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -197,6 +197,12 @@ struct eventpoll { /* The user that created the eventpoll descriptor */ struct user_struct *user; + + struct file *file; + + /* used to optimize loop detection check */ + int visited; + struct list_head visited_list_link; }; /* Wait structure used by the poll hooks */ @@ -255,6 +261,15 @@ static struct kmem_cache *epi_cache __read_mostly; /* Slab cache used to allocate "struct eppoll_entry" */ static struct kmem_cache *pwq_cache __read_mostly; +/* Visited nodes during ep_loop_check(), so we can unset them when we finish */ +static LIST_HEAD(visited_list); + +/* + * List of files with newly added links, where we may need to limit the number + * of emanating paths. Protected by the epmutex. + */ +static LIST_HEAD(tfile_check_list); + #ifdef CONFIG_SYSCTL #include @@ -276,6 +291,12 @@ ctl_table epoll_table[] = { }; #endif /* CONFIG_SYSCTL */ +static const struct file_operations eventpoll_fops; + +static inline int is_file_epoll(struct file *f) +{ + return f->f_op == &eventpoll_fops; +} /* Setup the structure that is used as key for the RB tree */ static inline void ep_set_ffd(struct epoll_filefd *ffd, @@ -728,12 +749,6 @@ static const struct file_operations eventpoll_fops = { .llseek = noop_llseek, }; -/* Fast test to see if the file is an evenpoll file */ -static inline int is_file_epoll(struct file *f) -{ - return f->f_op == &eventpoll_fops; -} - /* * This is called from eventpoll_release() to unlink files from the eventpoll * interface. We need to have this facility to cleanup correctly files that are @@ -954,6 +969,99 @@ static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi) rb_insert_color(&epi->rbn, &ep->rbr); } + + +#define PATH_ARR_SIZE 5 +/* + * These are the number paths of length 1 to 5, that we are allowing to emanate + * from a single file of interest. For example, we allow 1000 paths of length + * 1, to emanate from each file of interest. This essentially represents the + * potential wakeup paths, which need to be limited in order to avoid massive + * uncontrolled wakeup storms. The common use case should be a single ep which + * is connected to n file sources. In this case each file source has 1 path + * of length 1. Thus, the numbers below should be more than sufficient. These + * path limits are enforced during an EPOLL_CTL_ADD operation, since a modify + * and delete can't add additional paths. Protected by the epmutex. + */ +static const int path_limits[PATH_ARR_SIZE] = { 1000, 500, 100, 50, 10 }; +static int path_count[PATH_ARR_SIZE]; + +static int path_count_inc(int nests) +{ + if (++path_count[nests] > path_limits[nests]) + return -1; + return 0; +} + +static void path_count_init(void) +{ + int i; + + for (i = 0; i < PATH_ARR_SIZE; i++) + path_count[i] = 0; +} + +static int reverse_path_check_proc(void *priv, void *cookie, int call_nests) +{ + int error = 0; + struct file *file = priv; + struct file *child_file; + struct epitem *epi; + + list_for_each_entry(epi, &file->f_ep_links, fllink) { + child_file = epi->ep->file; + if (is_file_epoll(child_file)) { + if (list_empty(&child_file->f_ep_links)) { + if (path_count_inc(call_nests)) { + error = -1; + break; + } + } else { + error = ep_call_nested(&poll_loop_ncalls, + EP_MAX_NESTS, + reverse_path_check_proc, + child_file, child_file, + current); + } + if (error != 0) + break; + } else { + printk(KERN_ERR "reverse_path_check_proc: " + "file is not an ep!\n"); + } + } + return error; +} + +/** + * reverse_path_check - The tfile_check_list is list of file *, which have + * links that are proposed to be newly added. We need to + * make sure that those added links don't add too many + * paths such that we will spend all our time waking up + * eventpoll objects. + * + * Returns: Returns zero if the proposed links don't create too many paths, + * -1 otherwise. + */ +static int reverse_path_check(void) +{ + int length = 0; + int error = 0; + struct file *current_file; + + /* let's call this for all tfiles */ + list_for_each_entry(current_file, &tfile_check_list, f_tfile_llink) { + length++; + path_count_init(); + error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS, + reverse_path_check_proc, current_file, + current_file, current); + if (error) + break; + } + return error; +} + /* * Must be called with "mtx" held. */ @@ -1015,6 +1123,11 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, */ ep_rbtree_insert(ep, epi); + /* now check if we've created too many backpaths */ + error = -EINVAL; + if (reverse_path_check()) + goto error_remove_epi; + /* We have to drop the new item inside our item list to keep track of it */ spin_lock_irqsave(&ep->lock, flags); @@ -1039,6 +1152,14 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event, return 0; +error_remove_epi: + spin_lock(&tfile->f_lock); + if (ep_is_linked(&epi->fllink)) + list_del_init(&epi->fllink); + spin_unlock(&tfile->f_lock); + + rb_erase(&epi->rbn, &ep->rbr); + error_unregister: ep_unregister_pollwait(ep, epi); @@ -1303,18 +1424,36 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests) int error = 0; struct file *file = priv; struct eventpoll *ep = file->private_data; + struct eventpoll *ep_tovisit; struct rb_node *rbp; struct epitem *epi; mutex_lock_nested(&ep->mtx, call_nests + 1); + ep->visited = 1; + list_add(&ep->visited_list_link, &visited_list); for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) { epi = rb_entry(rbp, struct epitem, rbn); if (unlikely(is_file_epoll(epi->ffd.file))) { + ep_tovisit = epi->ffd.file->private_data; + if (ep_tovisit->visited) + continue; error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS, - ep_loop_check_proc, epi->ffd.file, - epi->ffd.file->private_data, current); + ep_loop_check_proc, epi->ffd.file, + ep_tovisit, current); if (error != 0) break; + } else { + /* + * If we've reached a file that is not associated with + * an ep, then we need to check if the newly added + * links are going to add too many wakeup paths. We do + * this by adding it to the tfile_check_list, if it's + * not already there, and calling reverse_path_check() + * during ep_insert(). + */ + if (list_empty(&epi->ffd.file->f_tfile_llink)) + list_add(&epi->ffd.file->f_tfile_llink, + &tfile_check_list); } } mutex_unlock(&ep->mtx); @@ -1335,8 +1474,31 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests) */ static int ep_loop_check(struct eventpoll *ep, struct file *file) { - return ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS, + int ret; + struct eventpoll *ep_cur, *ep_next; + + ret = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS, ep_loop_check_proc, file, ep, current); + /* clear visited list */ + list_for_each_entry_safe(ep_cur, ep_next, &visited_list, + visited_list_link) { + ep_cur->visited = 0; + list_del(&ep_cur->visited_list_link); + } + return ret; +} + +static void clear_tfile_check_list(void) +{ + struct file *file; + + /* first clear the tfile_check_list */ + while (!list_empty(&tfile_check_list)) { + file = list_first_entry(&tfile_check_list, struct file, + f_tfile_llink); + list_del_init(&file->f_tfile_llink); + } + INIT_LIST_HEAD(&tfile_check_list); } /* @@ -1344,8 +1506,9 @@ static int ep_loop_check(struct eventpoll *ep, struct file *file) */ SYSCALL_DEFINE1(epoll_create1, int, flags) { - int error; + int error, fd; struct eventpoll *ep = NULL; + struct file *file; /* Check the EPOLL_* constant for consistency. */ BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC); @@ -1362,11 +1525,25 @@ SYSCALL_DEFINE1(epoll_create1, int, flags) * Creates all the items needed to setup an eventpoll file. That is, * a file structure and a free file descriptor. */ - error = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep, + fd = get_unused_fd_flags(O_RDWR | (flags & O_CLOEXEC)); + if (fd < 0) { + error = fd; + goto out_free_ep; + } + file = anon_inode_getfile("[eventpoll]", &eventpoll_fops, ep, O_RDWR | (flags & O_CLOEXEC)); - if (error < 0) - ep_free(ep); - + if (IS_ERR(file)) { + error = PTR_ERR(file); + goto out_free_fd; + } + fd_install(fd, file); + ep->file = file; + return fd; + +out_free_fd: + put_unused_fd(fd); +out_free_ep: + ep_free(ep); return error; } @@ -1432,21 +1609,27 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, /* * When we insert an epoll file descriptor, inside another epoll file * descriptor, there is the change of creating closed loops, which are - * better be handled here, than in more critical paths. + * better be handled here, than in more critical paths. While we are + * checking for loops we also determine the list of files reachable + * and hang them on the tfile_check_list, so we can check that we + * haven't created too many possible wakeup paths. * - * We hold epmutex across the loop check and the insert in this case, in - * order to prevent two separate inserts from racing and each doing the - * insert "at the same time" such that ep_loop_check passes on both - * before either one does the insert, thereby creating a cycle. + * We need to hold the epmutex across both ep_insert and ep_remove + * b/c we want to make sure we are looking at a coherent view of + * epoll network. */ - if (unlikely(is_file_epoll(tfile) && op == EPOLL_CTL_ADD)) { + if (op == EPOLL_CTL_ADD || op == EPOLL_CTL_DEL) { mutex_lock(&epmutex); did_lock_epmutex = 1; - error = -ELOOP; - if (ep_loop_check(ep, tfile) != 0) - goto error_tgt_fput; } - + if (op == EPOLL_CTL_ADD) { + if (is_file_epoll(tfile)) { + error = -ELOOP; + if (ep_loop_check(ep, tfile) != 0) + goto error_tgt_fput; + } else + list_add(&tfile->f_tfile_llink, &tfile_check_list); + } mutex_lock_nested(&ep->mtx, 0); @@ -1465,6 +1648,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, error = ep_insert(ep, &epds, tfile, fd); } else error = -EEXIST; + clear_tfile_check_list(); break; case EPOLL_CTL_DEL: if (epi) @@ -1483,7 +1667,7 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, mutex_unlock(&ep->mtx); error_tgt_fput: - if (unlikely(did_lock_epmutex)) + if (did_lock_epmutex) mutex_unlock(&epmutex); fput(tfile); diff --git a/include/linux/eventpoll.h b/include/linux/eventpoll.h index f362733186a..657ab55beda 100644 --- a/include/linux/eventpoll.h +++ b/include/linux/eventpoll.h @@ -61,6 +61,7 @@ struct file; static inline void eventpoll_init_file(struct file *file) { INIT_LIST_HEAD(&file->f_ep_links); + INIT_LIST_HEAD(&file->f_tfile_llink); } diff --git a/include/linux/fs.h b/include/linux/fs.h index 7b17db7c5a6..d8ecb015ff8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -969,6 +969,7 @@ struct file { #ifdef CONFIG_EPOLL /* Used by fs/eventpoll.c to link all the hooks to this file */ struct list_head f_ep_links; + struct list_head f_tfile_llink; #endif /* #ifdef CONFIG_EPOLL */ struct address_space *f_mapping; #ifdef CONFIG_DEBUG_WRITECOUNT From 6b06abace47c8ac0afb6cac21a133b85cd296e50 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 6 Feb 2012 10:20:45 +0100 Subject: [PATCH 1003/4025] cdrom: use copy_to_user() without the underscores commit 822bfa51ce44f2c63c300fdb76dc99c4d5a5ca9f upstream. "nframes" comes from the user and "nframes * CD_FRAMESIZE_RAW" can wrap on 32 bit systems. That would have been ok if we used the same wrapped value for the copy, but we use a shifted value. We should just use the checked version of copy_to_user() because it's not going to make a difference to the speed. Signed-off-by: Dan Carpenter Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/cdrom/cdrom.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index b693cbdb421..cc6471aa9f4 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2114,11 +2114,6 @@ static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf, if (!nr) return -ENOMEM; - if (!access_ok(VERIFY_WRITE, ubuf, nframes * CD_FRAMESIZE_RAW)) { - ret = -EFAULT; - goto out; - } - cgc.data_direction = CGC_DATA_READ; while (nframes > 0) { if (nr > nframes) @@ -2127,7 +2122,7 @@ static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf, ret = cdrom_read_block(cdi, &cgc, lba, nr, 1, CD_FRAMESIZE_RAW); if (ret) break; - if (__copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr)) { + if (copy_to_user(ubuf, cgc.buffer, CD_FRAMESIZE_RAW * nr)) { ret = -EFAULT; break; } @@ -2135,7 +2130,6 @@ static int cdrom_read_cdda_old(struct cdrom_device_info *cdi, __u8 __user *ubuf, nframes -= nr; lba += nr; } -out: kfree(cgc.buffer); return ret; } From bf6a68d2a214e07f7c0d6538e00e17b826714160 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 29 Feb 2012 16:35:02 -0800 Subject: [PATCH 1004/4025] Linux 3.0.23 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index a5b22532ef7..d14684ee277 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 3 PATCHLEVEL = 0 -SUBLEVEL = 22 +SUBLEVEL = 23 EXTRAVERSION = NAME = Sneaky Weasel From 74374e40791f1f7b58252df275dd5227ead88b89 Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Thu, 1 Mar 2012 18:06:13 +0100 Subject: [PATCH 1005/4025] Add compress xz possiblity for this kernel That will reduce size and will speed up loading --- arch/arm/Kconfig | 1 + arch/arm/boot/compressed/Makefile | 17 ++++++++++++----- arch/arm/boot/compressed/decompress.c | 4 ++++ arch/arm/boot/compressed/piggy.xzkern.S | 7 +++++++ lib/xz/xz_dec_stream.c | 1 + 5 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 arch/arm/boot/compressed/piggy.xzkern.S diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 66a70453023..b6cec365cae 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -20,6 +20,7 @@ config ARM select HAVE_KERNEL_GZIP select HAVE_KERNEL_LZO select HAVE_KERNEL_LZMA + select HAVE_KERNEL_XZ select HAVE_IRQ_WORK select HAVE_PERF_EVENTS select PERF_USE_VMALLOC diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 23aad072230..777f70df7f3 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -79,16 +79,17 @@ endif SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/BSS_START/$(ZBSSADDR)/ -suffix_$(CONFIG_KERNEL_GZIP) = gzip -suffix_$(CONFIG_KERNEL_LZO) = lzo -suffix_$(CONFIG_KERNEL_LZMA) = lzma +suffix_$(CONFIG_KERNEL_GZIP) := gzip +suffix_$(CONFIG_KERNEL_LZO) := lzo +suffix_$(CONFIG_KERNEL_LZMA) := lzma +suffix_$(CONFIG_KERNEL_XZ) := xzkern targets := vmlinux vmlinux.lds \ piggy.$(suffix_y) piggy.$(suffix_y).o \ font.o font.c head.o misc.o $(OBJS) # Make sure files are removed during clean -extra-y += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S +extra-y += piggy.gzip piggy.lzo piggy.lzma piggy.xzkern lib1funcs.S ashldi3.S ifeq ($(CONFIG_FUNCTION_TRACER),y) ORIG_CFLAGS := $(KBUILD_CFLAGS) @@ -120,6 +121,12 @@ lib1funcs = $(obj)/lib1funcs.o $(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S FORCE $(call cmd,shipped) +# For __aeabi_llsl +ashldi3 = $(obj)/ashldi3.o + +$(obj)/ashldi3.S: $(srctree)/arch/$(SRCARCH)/lib/ashldi3.S FORCE + $(call cmd,shipped) + # We need to prevent any GOTOFF relocs being used with references # to symbols in the .bss section since we cannot relocate them # independently from the rest at run time. This can be achieved by @@ -134,7 +141,7 @@ bad_syms=$$($(CROSS_COMPILE)nm $@ | sed -n 's/^.\{8\} [bc] \(.*\)/\1/p') && \ echo "$$bad_syms" >&2; rm -f $@; false ) $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \ - $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) FORCE + $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) FORCE $(call if_changed,ld) @$(check_for_bad_syms) diff --git a/arch/arm/boot/compressed/decompress.c b/arch/arm/boot/compressed/decompress.c index 07be5a2f830..0ecd8b4806b 100644 --- a/arch/arm/boot/compressed/decompress.c +++ b/arch/arm/boot/compressed/decompress.c @@ -44,6 +44,10 @@ extern void error(char *); #include "../../../../lib/decompress_unlzma.c" #endif +#ifdef CONFIG_KERNEL_XZ +#include "../../../../lib/decompress_unxz.c" +#endif + int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x)) { return decompress(input, len, NULL, NULL, output, NULL, error); diff --git a/arch/arm/boot/compressed/piggy.xzkern.S b/arch/arm/boot/compressed/piggy.xzkern.S new file mode 100644 index 00000000000..fc6f6a533fc --- /dev/null +++ b/arch/arm/boot/compressed/piggy.xzkern.S @@ -0,0 +1,7 @@ + .section .piggydata,#alloc + .globl input_data +input_data: + .incbin "arch/arm/boot/compressed/piggy.xzkern" + .globl input_data_end +input_data_end: + diff --git a/lib/xz/xz_dec_stream.c b/lib/xz/xz_dec_stream.c index ac809b1e64f..9a60cc21964 100644 --- a/lib/xz/xz_dec_stream.c +++ b/lib/xz/xz_dec_stream.c @@ -9,6 +9,7 @@ #include "xz_private.h" #include "xz_stream.h" +#include /* Hash used to validate the Index field */ struct xz_dec_hash { From c54adc9ac2405c90d343506197d2919cb8d9a31b Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Thu, 1 Mar 2012 18:17:43 +0100 Subject: [PATCH 1006/4025] Update defconfig Select xz as compressor for crespo kernel --- arch/arm/configs/crespo_defconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/configs/crespo_defconfig b/arch/arm/configs/crespo_defconfig index b3da60cfbc0..a241b55aa32 100644 --- a/arch/arm/configs/crespo_defconfig +++ b/arch/arm/configs/crespo_defconfig @@ -40,9 +40,11 @@ CONFIG_LOCALVERSION="-Cyanogenmod" CONFIG_LOCALVERSION_AUTO=y CONFIG_HAVE_KERNEL_GZIP=y CONFIG_HAVE_KERNEL_LZMA=y +CONFIG_HAVE_KERNEL_XZ=y CONFIG_HAVE_KERNEL_LZO=y # CONFIG_KERNEL_GZIP is not set -CONFIG_KERNEL_LZMA=y +# CONFIG_KERNEL_LZMA is not set +CONFIG_KERNEL_XZ=y # CONFIG_KERNEL_LZO is not set CONFIG_DEFAULT_HOSTNAME="(none)" # CONFIG_SWAP is not set From 912f44a01c5065d744182538b89ffa2a6e0a41a0 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 3 Mar 2012 20:56:29 +0100 Subject: [PATCH 1007/4025] ARM: fix rcu stalls on SMP platforms We can stall RCU processing on SMP platforms if a CPU sits in its idle loop for a long time. This happens because we don't call irq_enter() and irq_exit() around generic_smp_call_function_interrupt() and friends. Add the necessary calls, and remove the one from within ipi_timer(), so that they're all in a common place. Signed-off-by: Russell King --- arch/arm/kernel/smp.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 9739bb8a2d2..e12db611d95 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -450,9 +450,7 @@ static DEFINE_PER_CPU(struct clock_event_device, percpu_clockevent); static void ipi_timer(void) { struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent); - irq_enter(); evt->event_handler(evt); - irq_exit(); } #ifdef CONFIG_LOCAL_TIMERS @@ -625,23 +623,31 @@ asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs) switch (ipinr) { case IPI_TIMER: + irq_enter(); ipi_timer(); - break; + irq_exit(); + break; case IPI_RESCHEDULE: scheduler_ipi(); break; case IPI_CALL_FUNC: + irq_enter(); generic_smp_call_function_interrupt(); + irq_exit(); break; case IPI_CALL_FUNC_SINGLE: + irq_enter(); generic_smp_call_function_single_interrupt(); + irq_exit(); break; case IPI_CPU_STOP: + irq_enter(); ipi_cpu_stop(cpu); + irq_exit(); break; case IPI_CPU_BACKTRACE: From 0d86bf5079d0c8d15f41943183b9393ac7cb53fe Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Sat, 3 Mar 2012 21:34:17 +0100 Subject: [PATCH 1008/4025] Check irq condition mask condition --- kernel/irq/chip.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c index ca14f5dcabd..cd770d03992 100644 --- a/kernel/irq/chip.c +++ b/kernel/irq/chip.c @@ -328,8 +328,10 @@ static void cond_unmask_irq(struct irq_desc *desc) * spurious interrupt or a primary handler handling it * completely). */ - if (!irqd_irq_disabled(&desc->irq_data) && - irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) + // FIXME + // if (!irqd_irq_disabled(&desc->irq_data) && + // irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) + if (!irqd_irq_disabled(&desc->irq_data) && !(desc->istate & IRQS_ONESHOT)) unmask_irq(desc); } From a182a74e0ad6bd978d4fe8f95be8501e74c03883 Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Mon, 5 Mar 2012 12:46:53 -0800 Subject: [PATCH 1009/4025] mmc: sdhci: Skip rest of suspend if mmc_suspend_host() fails Signed-off-by: Dmitry Shmidt --- drivers/mmc/host/sdhci.c | 4 ++++ 1 file changed, 4 insertions(+) mode change 100755 => 100644 drivers/mmc/host/sdhci.c diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c old mode 100755 new mode 100644 index 46042f70656..1536485b212 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2329,6 +2329,10 @@ int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state) } ret = mmc_suspend_host(host->mmc); + if (ret) { + sdhci_enable_card_detection(host); + return ret; + } sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); From 21b0e08c99180f54138f7ef0a87081ed79a5308b Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Mon, 5 Mar 2012 11:48:19 -0800 Subject: [PATCH 1010/4025] herring_defconfig: enable dynamic debug We need this temporarily to debug watchdog issues around resume. There will be a matching init.rc change to allow non-root user builds to change debugging at runtime. Change-Id: Ib5359e7d2874fe738f19ca1aeec19369917d02d2 Signed-off-by: JP Abgrall --- arch/arm/configs/herring_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/herring_defconfig b/arch/arm/configs/herring_defconfig index a24382364fd..ca5e8be049c 100644 --- a/arch/arm/configs/herring_defconfig +++ b/arch/arm/configs/herring_defconfig @@ -380,6 +380,7 @@ CONFIG_DEBUG_KERNEL=y # CONFIG_DEBUG_PREEMPT is not set CONFIG_DEBUG_INFO=y CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_DYNAMIC_DEBUG=y # CONFIG_ARM_UNWIND is not set CONFIG_DEBUG_USER=y CONFIG_DEBUG_S3C_UART=2 From 538bae6ee1b5c15ba819b6e292c22d6c7349f5c4 Mon Sep 17 00:00:00 2001 From: Shareef Ali Date: Thu, 8 Mar 2012 09:11:47 +0100 Subject: [PATCH 1011/4025] decrease mmap usage to provide more ram to userspace. 22 MB is required for 720p decoding and disables suppoort for 1080p decrease mmap usage to provide more ram to userspace. 22 MB is required for 720p decoding and disables suppoort for 1080p videos. I managed to reduce memory of the FIMC driver and it works. 22 MB is required for camera @ 720p and front facing camera require 1MB. --- arch/arm/mach-s5pv210/mach-herring.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c index 83edf1e1ceb..fcb807a40e2 100755 --- a/arch/arm/mach-s5pv210/mach-herring.c +++ b/arch/arm/mach-s5pv210/mach-herring.c @@ -368,8 +368,8 @@ static struct s3cfb_lcd r61408 = { #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC0 (6144 * SZ_1K) #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC1 (9900 * SZ_1K) #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC2 (6144 * SZ_1K) -#define S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC0 (36864 * SZ_1K) -#define S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC1 (36864 * SZ_1K) +#define S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC0 (11264 * SZ_1K) // 11Mb +#define S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC1 (11264 * SZ_1K) // 11Mb #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMD (S5PV210_LCD_WIDTH * \ S5PV210_LCD_HEIGHT * 4 * \ (CONFIG_FB_S3C_NR_BUFFERS + \ From 34b845d11e7944387fd720de1478b749c7d8aece Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Thu, 8 Mar 2012 09:23:42 +0100 Subject: [PATCH 1012/4025] Add NTFS Capability to the kernel as a module --- arch/arm/configs/crespo_defconfig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/crespo_defconfig b/arch/arm/configs/crespo_defconfig index a241b55aa32..eb7c49116f2 100644 --- a/arch/arm/configs/crespo_defconfig +++ b/arch/arm/configs/crespo_defconfig @@ -1,6 +1,6 @@ # # Automatically generated make config: don't edit -# Linux/arm 3.0.20 Kernel Configuration +# Linux/arm 3.0.23 Kernel Configuration # CONFIG_ARM=y CONFIG_HAVE_PWM=y @@ -2215,7 +2215,9 @@ CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_FAT_DEFAULT_CODEPAGE=437 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -# CONFIG_NTFS_FS is not set +CONFIG_NTFS_FS=m +# CONFIG_NTFS_DEBUG is not set +CONFIG_NTFS_RW=y # # Pseudo filesystems From 316912acbe1a35e6b6f5499100ad7c5416f6929f Mon Sep 17 00:00:00 2001 From: Shareef Ali Date: Fri, 9 Mar 2012 07:52:27 +0100 Subject: [PATCH 1013/4025] Free more RAM by disabling FIMC1 mmap and reduce mmap usage for JPEG driver. 1.9 MB is freed. --- arch/arm/mach-s5pv210/mach-herring.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/arch/arm/mach-s5pv210/mach-herring.c b/arch/arm/mach-s5pv210/mach-herring.c index fcb807a40e2..7ba1277f284 100755 --- a/arch/arm/mach-s5pv210/mach-herring.c +++ b/arch/arm/mach-s5pv210/mach-herring.c @@ -366,7 +366,6 @@ static struct s3cfb_lcd r61408 = { }; #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC0 (6144 * SZ_1K) -#define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC1 (9900 * SZ_1K) #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC2 (6144 * SZ_1K) #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC0 (11264 * SZ_1K) // 11Mb #define S5PV210_VIDEO_SAMSUNG_MEMSIZE_MFC1 (11264 * SZ_1K) // 11Mb @@ -375,7 +374,7 @@ static struct s3cfb_lcd r61408 = { (CONFIG_FB_S3C_NR_BUFFERS + \ (CONFIG_FB_S3C_NUM_OVLY_WIN * \ CONFIG_FB_S3C_NUM_BUF_OVLY_WIN))) -#define S5PV210_VIDEO_SAMSUNG_MEMSIZE_JPEG (8192 * SZ_1K) +#define S5PV210_VIDEO_SAMSUNG_MEMSIZE_JPEG (4092 * SZ_1K) static struct s5p_media_device herring_media_devs[] = { [0] = { @@ -399,13 +398,6 @@ static struct s5p_media_device herring_media_devs[] = { .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC0, .paddr = 0, }, - [3] = { - .id = S5P_MDEV_FIMC1, - .name = "fimc1", - .bank = 1, - .memsize = S5PV210_VIDEO_SAMSUNG_MEMSIZE_FIMC1, - .paddr = 0, - }, [4] = { .id = S5P_MDEV_FIMC2, .name = "fimc2", From 2cdb45d19ebd62bcd249b4cff49c414fcf1f420c Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 20 Jan 2012 12:10:18 +0100 Subject: [PATCH 1014/4025] ARM: 7296/1: proc-v7.S: remove HARVARD_CACHE preprocessor guards commit 612539e81f655f6ac73c7af1da8701c1ee618aee upstream. On v7, we use the same cache maintenance instructions for data lines as for unified lines. This was not the case for v6, where HARVARD_CACHE was defined to indicate the L1 cache topology. This patch removes the erroneous compile-time check for HARVARD_CACHE in proc-v7.S, ensuring that we perform I-side invalidation at boot. Reported-and-Acked-by: Shawn Guo Acked-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/mm/proc-v7.S | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index 089c0b5e454..b6ba1032a98 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S @@ -270,10 +270,6 @@ cpu_resume_l1_flags: * Initialise TLB, Caches, and MMU state ready to switch the MMU * on. Return in r0 the new CP15 C1 control register setting. * - * We automatically detect if we have a Harvard cache, and use the - * Harvard cache control instructions insead of the unified cache - * control instructions. - * * This should be able to cover all ARMv7 cores. * * It is assumed that: @@ -363,9 +359,7 @@ __v7_setup: #endif 3: mov r10, #0 -#ifdef HARVARD_CACHE mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate -#endif dsb #ifdef CONFIG_MMU mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs From 815e627716ccc34cbeb1a496a7acc4d9db993dd0 Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Sat, 10 Mar 2012 08:56:37 +0100 Subject: [PATCH 1015/4025] Update Build Script --- build.sh | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/build.sh b/build.sh index e3612d19bc7..1a7abe19fbc 100755 --- a/build.sh +++ b/build.sh @@ -28,8 +28,6 @@ setup () KERNEL_DIR="$(dirname "$(readlink -f "$0")")" BUILD_DIR="$KERNEL_DIR/build" - # add modules which should be copied after build below - MODULES=("drivers/net/wireless/bcm4329/bcm4329.ko") if [ x = "x$NO_CCACHE" ] && ccache -V &>/dev/null ; then CCACHE=ccache @@ -88,9 +86,9 @@ CreateKernelZip () echo Sending $filename to /system/modules if adb push $filename /system/modules ; then echo "Rebooting again" - adb reboot fi done + adb reboot fi fi fi @@ -117,6 +115,26 @@ CompileError () echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! } +SenModulesToCMDevice() +{ + CURDIR=`pwd`; + cd bin/system/modules + rm $DEVICE_CM_DIR/KernelModules.mk + echo "# Kernel Modules TO BE COPIED" > $DEVICE_CM_DIR/KernelModules.mk + echo 'PRODUCT_COPY_FILES += \' >> $DEVICE_CM_DIR/KernelModules.mk + MODULEF=( $(find * -type f) ) + # get length of an array + tLen=${#MODULEF[@]} + # use for loop read all modules but not the last + for (( i=0; i<${tLen}-1; i++ )); + do + echo ' device/samsung/'${BOARD}'/'${MODULEF[$i]}':system/modules/'${MODULEF[$i]}' \' >>$DEVICE_CM_DIR/KernelModules.mk + echo ${MODULEF[$i]} + done + echo ' device/samsung/'${BOARD}'/'${MODULEF[$i]}':system/modules/'${MODULEF[$i]} >>$DEVICE_CM_DIR/KernelModules.mk + cd $CURDIR +} + build () { local target=$1 @@ -135,10 +153,13 @@ build () if [[ $RET == 0 ]] ; then cp "$target_dir"/arch/arm/boot/zImage $DEVICE_CM_DIR/kernel cp "$target_dir"/arch/arm/boot/zImage bin/kernel/zImage + MODULES=( $(find $target_dir/* -type f -name *.ko) ) for module in "${MODULES[@]}" ; do - cp "$target_dir/$module" $DEVICE_CM_DIR - cp "$target_dir/$module" bin/system/modules + echo $module + # cp "$module" $DEVICE_CM_DIR + cp "$module" bin/system/modules done + SenModulesToCMDevice CheckVersion CreateKernelZip UpgradeMinor @@ -167,10 +188,7 @@ if [ "$1" = clean ] ; then exit 0 fi -targets=("$@") -if [ 0 = "${#targets[@]}" ] ; then - targets=(crespo) -fi +targets=(crespo) START=$(date +%s) From 39d013fad87165c40b901534b9333a013f5670c8 Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Sat, 10 Mar 2012 08:57:00 +0100 Subject: [PATCH 1016/4025] Update defconfig Make modules from the lowest use fs --- arch/arm/configs/crespo_defconfig | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/configs/crespo_defconfig b/arch/arm/configs/crespo_defconfig index eb7c49116f2..ad4f07ad0c0 100644 --- a/arch/arm/configs/crespo_defconfig +++ b/arch/arm/configs/crespo_defconfig @@ -2184,7 +2184,7 @@ CONFIG_JBD2=y # CONFIG_BTRFS_FS is not set # CONFIG_NILFS2_FS is not set CONFIG_FS_POSIX_ACL=y -CONFIG_EXPORTFS=y +CONFIG_EXPORTFS=m CONFIG_FILE_LOCKING=y CONFIG_FSNOTIFY=y # CONFIG_DNOTIFY is not set @@ -2269,18 +2269,18 @@ CONFIG_ROMFS_ON_BLOCK=y # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set CONFIG_NETWORK_FILESYSTEMS=y -CONFIG_NFS_FS=y +CONFIG_NFS_FS=m # CONFIG_NFS_V3 is not set # CONFIG_NFS_V4 is not set -CONFIG_NFSD=y +CONFIG_NFSD=m CONFIG_NFSD_DEPRECATED=y # CONFIG_NFSD_V3 is not set # CONFIG_NFSD_V4 is not set -CONFIG_LOCKD=y +CONFIG_LOCKD=m CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=y +CONFIG_SUNRPC=m # CONFIG_CEPH_FS is not set -CONFIG_CIFS=y +CONFIG_CIFS=m # CONFIG_CIFS_STATS is not set # CONFIG_CIFS_WEAK_PW_HASH is not set # CONFIG_CIFS_XATTR is not set From 5be72e22c7db24358b71c23d281a3a664b73c23a Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Sat, 10 Mar 2012 11:11:06 +0100 Subject: [PATCH 1017/4025] Update buildscript Send .ko files to crespo device dir --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 1a7abe19fbc..ed34f3d1545 100755 --- a/build.sh +++ b/build.sh @@ -156,7 +156,7 @@ build () MODULES=( $(find $target_dir/* -type f -name *.ko) ) for module in "${MODULES[@]}" ; do echo $module - # cp "$module" $DEVICE_CM_DIR + cp "$module" $DEVICE_CM_DIR cp "$module" bin/system/modules done SenModulesToCMDevice From 2dc23110650332721bc8318972d8d96166eb480b Mon Sep 17 00:00:00 2001 From: KalimochoAz Date: Sun, 11 Mar 2012 22:02:33 +0100 Subject: [PATCH 1018/4025] Revert the creation of modules Since we don't have the 04modules script in init.d for cm9 this is not a good idea. --- arch/arm/configs/crespo_defconfig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm/configs/crespo_defconfig b/arch/arm/configs/crespo_defconfig index ad4f07ad0c0..a86d1a7c03c 100644 --- a/arch/arm/configs/crespo_defconfig +++ b/arch/arm/configs/crespo_defconfig @@ -2184,7 +2184,7 @@ CONFIG_JBD2=y # CONFIG_BTRFS_FS is not set # CONFIG_NILFS2_FS is not set CONFIG_FS_POSIX_ACL=y -CONFIG_EXPORTFS=m +CONFIG_EXPORTFS=y CONFIG_FILE_LOCKING=y CONFIG_FSNOTIFY=y # CONFIG_DNOTIFY is not set @@ -2215,7 +2215,7 @@ CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_FAT_DEFAULT_CODEPAGE=437 CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1" -CONFIG_NTFS_FS=m +CONFIG_NTFS_FS=y # CONFIG_NTFS_DEBUG is not set CONFIG_NTFS_RW=y @@ -2269,18 +2269,18 @@ CONFIG_ROMFS_ON_BLOCK=y # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set CONFIG_NETWORK_FILESYSTEMS=y -CONFIG_NFS_FS=m +CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set # CONFIG_NFS_V4 is not set -CONFIG_NFSD=m +CONFIG_NFSD=y CONFIG_NFSD_DEPRECATED=y # CONFIG_NFSD_V3 is not set # CONFIG_NFSD_V4 is not set -CONFIG_LOCKD=m +CONFIG_LOCKD=y CONFIG_NFS_COMMON=y -CONFIG_SUNRPC=m +CONFIG_SUNRPC=y # CONFIG_CEPH_FS is not set -CONFIG_CIFS=m +CONFIG_CIFS=y # CONFIG_CIFS_STATS is not set # CONFIG_CIFS_WEAK_PW_HASH is not set # CONFIG_CIFS_XATTR is not set From 499f286dc02cde6b668e2d757dfe100cb0c43445 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Wed, 22 Feb 2012 20:45:44 +0800 Subject: [PATCH 1019/4025] autofs: work around unhappy compat problem on x86-64 commit a32744d4abae24572eff7269bc17895c41bd0085 upstream. When the autofs protocol version 5 packet type was added in commit 5c0a32fc2cd0 ("autofs4: add new packet type for v5 communications"), it obvously tried quite hard to be word-size agnostic, and uses explicitly sized fields that are all correctly aligned. However, with the final "char name[NAME_MAX+1]" array at the end, the actual size of the structure ends up being not very well defined: because the struct isn't marked 'packed', doing a "sizeof()" on it will align the size of the struct up to the biggest alignment of the members it has. And despite all the members being the same, the alignment of them is different: a "__u64" has 4-byte alignment on x86-32, but native 8-byte alignment on x86-64. And while 'NAME_MAX+1' ends up being a nice round number (256), the name[] array starts out a 4-byte aligned. End result: the "packed" size of the structure is 300 bytes: 4-byte, but not 8-byte aligned. As a result, despite all the fields being in the same place on all architectures, sizeof() will round up that size to 304 bytes on architectures that have 8-byte alignment for u64. Note that this is *not* a problem for 32-bit compat mode on POWER, since there __u64 is 8-byte aligned even in 32-bit mode. But on x86, 32-bit and 64-bit alignment is different for 64-bit entities, and as a result the structure that has exactly the same layout has different sizes. So on x86-64, but no other architecture, we will just subtract 4 from the size of the structure when running in a compat task. That way we will write the properly sized packet that user mode expects. Not pretty. Sadly, this very subtle, and unnecessary, size difference has been encoded in user space that wants to read packets of *exactly* the right size, and will refuse to touch anything else. Reported-and-tested-by: Thomas Meyer Signed-off-by: Ian Kent Signed-off-by: Linus Torvalds Cc: Jonathan Nieder Signed-off-by: Greg Kroah-Hartman --- fs/autofs4/autofs_i.h | 1 + fs/autofs4/dev-ioctl.c | 1 + fs/autofs4/inode.c | 2 ++ fs/autofs4/waitq.c | 22 +++++++++++++++++++--- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 475f9c597cb..10cc45aea22 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -120,6 +120,7 @@ struct autofs_sb_info { int sub_version; int min_proto; int max_proto; + int compat_daemon; unsigned long exp_timeout; unsigned int type; int reghost_enabled; diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c index 509fe1eb66a..56bac702ab0 100644 --- a/fs/autofs4/dev-ioctl.c +++ b/fs/autofs4/dev-ioctl.c @@ -385,6 +385,7 @@ static int autofs_dev_ioctl_setpipefd(struct file *fp, sbi->pipefd = pipefd; sbi->pipe = pipe; sbi->catatonic = 0; + sbi->compat_daemon = is_compat_task(); } out: mutex_unlock(&sbi->wq_mutex); diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 180fa2425e4..eb1e45ce303 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "autofs_i.h" #include @@ -224,6 +225,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) set_autofs_type_indirect(&sbi->type); sbi->min_proto = 0; sbi->max_proto = 0; + sbi->compat_daemon = is_compat_task(); mutex_init(&sbi->wq_mutex); spin_lock_init(&sbi->fs_lock); sbi->queues = NULL; diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 25435987d6a..fbbb749011a 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -90,7 +90,24 @@ static int autofs4_write(struct file *file, const void *addr, int bytes) return (bytes > 0); } - + +/* + * The autofs_v5 packet was misdesigned. + * + * The packets are identical on x86-32 and x86-64, but have different + * alignment. Which means that 'sizeof()' will give different results. + * Fix it up for the case of running 32-bit user mode on a 64-bit kernel. + */ +static noinline size_t autofs_v5_packet_size(struct autofs_sb_info *sbi) +{ + size_t pktsz = sizeof(struct autofs_v5_packet); +#if defined(CONFIG_X86_64) && defined(CONFIG_COMPAT) + if (sbi->compat_daemon > 0) + pktsz -= 4; +#endif + return pktsz; +} + static void autofs4_notify_daemon(struct autofs_sb_info *sbi, struct autofs_wait_queue *wq, int type) @@ -147,8 +164,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi, { struct autofs_v5_packet *packet = &pkt.v5_pkt.v5_packet; - pktsz = sizeof(*packet); - + pktsz = autofs_v5_packet_size(sbi); packet->wait_queue_token = wq->wait_queue_token; packet->len = wq->name.len; memcpy(packet->name, wq->name.name, wq->name.len); From a3ea6c14ec93e67c08de43bdf8ce7d701835152f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 26 Feb 2012 09:44:55 -0800 Subject: [PATCH 1020/4025] Fix autofs compile without CONFIG_COMPAT commit 3c761ea05a8900a907f32b628611873f6bef24b2 upstream. The autofs compat handling fix caused a compile failure when CONFIG_COMPAT isn't defined. Instead of adding random #ifdef'fery in autofs, let's just make the compat helpers earlier to use: without CONFIG_COMPAT, is_compat_task() just hardcodes to zero. We could probably do something similar for a number of other cases where we have #ifdef's in code, but this is the low-hanging fruit. Reported-and-tested-by: Andreas Schwab Signed-off-by: Linus Torvalds Cc: Jonathan Nieder Signed-off-by: Greg Kroah-Hartman --- include/linux/compat.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/compat.h b/include/linux/compat.h index 846bb179257..edaf3900f6b 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -561,5 +561,9 @@ extern ssize_t compat_rw_copy_check_uvector(int type, extern void __user *compat_alloc_user_space(unsigned long len); +#else + +#define is_compat_task() (0) + #endif /* CONFIG_COMPAT */ #endif /* _LINUX_COMPAT_H */ From 9eb9e47632735bb3bb3da343663ea10a6954ef31 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 27 Feb 2012 10:01:52 +0100 Subject: [PATCH 1021/4025] compat: fix compile breakage on s390 commit 048cd4e51d24ebf7f3552226d03c769d6ad91658 upstream. The new is_compat_task() define for the !COMPAT case in include/linux/compat.h conflicts with a similar define in arch/s390/include/asm/compat.h. This is the minimal patch which fixes the build issues. Signed-off-by: Heiko Carstens Signed-off-by: Linus Torvalds Cc: Jonathan Nieder Signed-off-by: Greg Kroah-Hartman --- arch/s390/include/asm/compat.h | 7 ------- arch/s390/kernel/process.c | 1 - arch/s390/kernel/ptrace.c | 2 +- arch/s390/kernel/setup.c | 2 +- arch/s390/mm/fault.c | 1 - arch/s390/mm/mmap.c | 2 +- drivers/s390/block/dasd_eckd.c | 2 +- drivers/s390/block/dasd_ioctl.c | 1 + drivers/s390/char/fs3270.c | 2 +- drivers/s390/char/vmcp.c | 1 + drivers/s390/cio/chsc_sch.c | 1 + drivers/s390/scsi/zfcp_cfdc.c | 1 + 12 files changed, 9 insertions(+), 14 deletions(-) diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h index da359ca6fe5..f7b74bcce10 100644 --- a/arch/s390/include/asm/compat.h +++ b/arch/s390/include/asm/compat.h @@ -172,13 +172,6 @@ static inline int is_compat_task(void) return is_32bit_task(); } -#else - -static inline int is_compat_task(void) -{ - return 0; -} - #endif static inline void __user *arch_compat_alloc_user_space(long len) diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 541a7509fae..abdc2b1063e 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "entry.h" diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 5804cfa7cba..5c55466e78e 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -20,8 +20,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 0c35dee10b0..7547f57e291 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -55,7 +56,6 @@ #include #include #include -#include #include long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index fe103e891e7..d814f791400 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -36,7 +36,6 @@ #include #include #include -#include #include "../kernel/entry.h" #ifndef CONFIG_64BIT diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c index c9a9f7f1818..c0cf9ceb383 100644 --- a/arch/s390/mm/mmap.c +++ b/arch/s390/mm/mmap.c @@ -28,8 +28,8 @@ #include #include #include +#include #include -#include static unsigned long stack_maxrandom_size(void) { diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 30fb979d684..cc2dd7fb289 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -18,12 +18,12 @@ #include /* HDIO_GETGEO */ #include #include +#include #include #include #include #include -#include #include #include #include diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 72261e4c516..9caeaea5d09 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -13,6 +13,7 @@ #define KMSG_COMPONENT "dasd" #include +#include #include #include #include diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index f6489eb7e97..e197fd7e1c0 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -14,8 +14,8 @@ #include #include #include +#include -#include #include #include #include diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 31a3ccbb649..84e569c9c15 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index e950f1ad4dd..ec760297dd3 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index 303dde09d29..fab2c2592a9 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -11,6 +11,7 @@ #define KMSG_COMPONENT "zfcp" #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#include #include #include #include From 46ef1956475fd62f21ee67b3f49dbfe2a60fa13d Mon Sep 17 00:00:00 2001 From: Alban Browaeys Date: Fri, 24 Feb 2012 17:12:45 +0000 Subject: [PATCH 1022/4025] drm/i915: Prevent a machine hang by checking crtc->active before loading lut commit aed3f09db39596e539f90b11a5016aea4d8442e1 upstream. Before loading the lut (gamma), check the active state of intel_crtc, otherwise at least on gen2 hang ensue. This is reproducible in Xorg via: xset dpms force off then xgamma -rgamma 2.0 # freeze. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=44505 Signed-off-by: Alban Browaeys Signed-off-by: Chris Wilson Reviewed-by: Jesse Barnes Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fed87d6a5b9..e4b25861a12 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5265,7 +5265,7 @@ void intel_crtc_load_lut(struct drm_crtc *crtc) int i; /* The clocks have to be on to load the palette. */ - if (!crtc->enabled) + if (!crtc->enabled || !intel_crtc->active) return; /* use legacy palette for Ironlake */ From fd3fb91a55d4a8f7eff63b26631a4a34c4ba76d0 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Mon, 27 Feb 2012 17:28:02 +0100 Subject: [PATCH 1023/4025] ARM: LPC32xx: serial.c: HW bug workaround commit 2707208ee8a80dbbd5426f5aa1a934f766825bb5 upstream. This patch fixes a HW bug by flushing RX FIFOs of the UARTs on init. It was ported from NXP's git.lpclinux.com tree. Signed-off-by: Roland Stigge Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-lpc32xx/serial.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/mach-lpc32xx/serial.c b/arch/arm/mach-lpc32xx/serial.c index 429cfdbb2b3..1a3fd4ce046 100644 --- a/arch/arm/mach-lpc32xx/serial.c +++ b/arch/arm/mach-lpc32xx/serial.c @@ -88,6 +88,7 @@ struct uartinit { char *uart_ck_name; u32 ck_mode_mask; void __iomem *pdiv_clk_reg; + resource_size_t mapbase; }; static struct uartinit uartinit_data[] __initdata = { @@ -97,6 +98,7 @@ static struct uartinit uartinit_data[] __initdata = { .ck_mode_mask = LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 5), .pdiv_clk_reg = LPC32XX_CLKPWR_UART5_CLK_CTRL, + .mapbase = LPC32XX_UART5_BASE, }, #endif #ifdef CONFIG_ARCH_LPC32XX_UART3_SELECT @@ -105,6 +107,7 @@ static struct uartinit uartinit_data[] __initdata = { .ck_mode_mask = LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 3), .pdiv_clk_reg = LPC32XX_CLKPWR_UART3_CLK_CTRL, + .mapbase = LPC32XX_UART3_BASE, }, #endif #ifdef CONFIG_ARCH_LPC32XX_UART4_SELECT @@ -113,6 +116,7 @@ static struct uartinit uartinit_data[] __initdata = { .ck_mode_mask = LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 4), .pdiv_clk_reg = LPC32XX_CLKPWR_UART4_CLK_CTRL, + .mapbase = LPC32XX_UART4_BASE, }, #endif #ifdef CONFIG_ARCH_LPC32XX_UART6_SELECT @@ -121,6 +125,7 @@ static struct uartinit uartinit_data[] __initdata = { .ck_mode_mask = LPC32XX_UART_CLKMODE_LOAD(LPC32XX_UART_CLKMODE_ON, 6), .pdiv_clk_reg = LPC32XX_CLKPWR_UART6_CLK_CTRL, + .mapbase = LPC32XX_UART6_BASE, }, #endif }; @@ -165,6 +170,19 @@ void __init lpc32xx_serial_init(void) /* pre-UART clock divider set to 1 */ __raw_writel(0x0101, uartinit_data[i].pdiv_clk_reg); + + /* + * Force a flush of the RX FIFOs to work around a + * HW bug + */ + puart = uartinit_data[i].mapbase; + __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart)); + __raw_writel(0x00, LPC32XX_UART_DLL_FIFO(puart)); + j = LPC32XX_SUART_FIFO_SIZE; + while (j--) + tmp = __raw_readl( + LPC32XX_UART_DLL_FIFO(puart)); + __raw_writel(0, LPC32XX_UART_IIR_FCR(puart)); } /* This needs to be done after all UART clocks are setup */ From 280e54b164802662ff59ba9cc24b66595f9a6bb9 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Mon, 27 Feb 2012 17:28:03 +0100 Subject: [PATCH 1024/4025] ARM: LPC32xx: serial.c: Fixed loop limit commit ff424aa4c89d19082e8ae5a3351006bc8a4cd91b upstream. This patch fixes a wrong loop limit on UART init. Signed-off-by: Roland Stigge Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-lpc32xx/serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-lpc32xx/serial.c b/arch/arm/mach-lpc32xx/serial.c index 1a3fd4ce046..f2735281616 100644 --- a/arch/arm/mach-lpc32xx/serial.c +++ b/arch/arm/mach-lpc32xx/serial.c @@ -187,7 +187,7 @@ void __init lpc32xx_serial_init(void) /* This needs to be done after all UART clocks are setup */ __raw_writel(clkmodes, LPC32XX_UARTCTL_CLKMODE); - for (i = 0; i < ARRAY_SIZE(uartinit_data) - 1; i++) { + for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) { /* Force a flush of the RX FIFOs to work around a HW bug */ puart = serial_std_platform_data[i].mapbase; __raw_writel(0xC1, LPC32XX_UART_IIR_FCR(puart)); From 19399c348f59bb2aa2321efe6e29ece9797717f7 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Mon, 27 Feb 2012 17:28:02 +0100 Subject: [PATCH 1025/4025] ARM: LPC32xx: irq.c: Clear latched event commit 94ed7830cba4dce57b18a2926b5d826bfd184bd6 upstream. This patch fixes the wakeup disable function by clearing latched events. Signed-off-by: Roland Stigge Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-lpc32xx/irq.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-lpc32xx/irq.c b/arch/arm/mach-lpc32xx/irq.c index 4eae566dfdc..965b1d6959e 100644 --- a/arch/arm/mach-lpc32xx/irq.c +++ b/arch/arm/mach-lpc32xx/irq.c @@ -305,9 +305,18 @@ static int lpc32xx_irq_wake(struct irq_data *d, unsigned int state) if (state) eventreg |= lpc32xx_events[d->irq].mask; - else + else { eventreg &= ~lpc32xx_events[d->irq].mask; + /* + * When disabling the wakeup, clear the latched + * event + */ + __raw_writel(lpc32xx_events[d->irq].mask, + lpc32xx_events[d->irq]. + event_group->rawstat_reg); + } + __raw_writel(eventreg, lpc32xx_events[d->irq].event_group->enab_reg); From 53fcf6ba805ffd82171a4f9459c2767ce0b3b580 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Mon, 27 Feb 2012 17:28:02 +0100 Subject: [PATCH 1026/4025] ARM: LPC32xx: Fix interrupt controller init commit 35dd0a75d4a382e7f769dd0277732e7aa5235718 upstream. This patch fixes the initialization of the interrupt controller of the LPC32xx by correctly setting up SIC1 and SIC2 instead of (wrongly) using the same value as for the Main Interrupt Controller (MIC). Signed-off-by: Roland Stigge Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-lpc32xx/irq.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-lpc32xx/irq.c b/arch/arm/mach-lpc32xx/irq.c index 965b1d6959e..198de470ca9 100644 --- a/arch/arm/mach-lpc32xx/irq.c +++ b/arch/arm/mach-lpc32xx/irq.c @@ -389,13 +389,15 @@ void __init lpc32xx_init_irq(void) /* Setup SIC1 */ __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC1_BASE)); - __raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC1_BASE)); - __raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC1_BASE)); + __raw_writel(SIC1_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC1_BASE)); + __raw_writel(SIC1_ATR_DEFAULT, + LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC1_BASE)); /* Setup SIC2 */ __raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC2_BASE)); - __raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC2_BASE)); - __raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC2_BASE)); + __raw_writel(SIC2_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC2_BASE)); + __raw_writel(SIC2_ATR_DEFAULT, + LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC2_BASE)); /* Configure supported IRQ's */ for (i = 0; i < NR_IRQS; i++) { From bb3b47ceebd8a5b8a8684fde8e2ba0b8f0127d05 Mon Sep 17 00:00:00 2001 From: Roland Stigge Date: Mon, 27 Feb 2012 17:28:02 +0100 Subject: [PATCH 1027/4025] ARM: LPC32xx: Fix irq on GPI_28 commit f6737055c1c432a9628a9a731f9881ad8e0a9eee upstream. The GPI_28 IRQ was not registered properly. The registration of IRQ_LPC32XX_GPI_28 was added and the (wrong) IRQ_LPC32XX_GPI_11 at LPC32XX_SIC1_IRQ(4) was replaced by IRQ_LPC32XX_GPI_28 (see manual of LPC32xx / interrupt controller). Signed-off-by: Roland Stigge Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-lpc32xx/include/mach/irqs.h | 2 +- arch/arm/mach-lpc32xx/irq.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-lpc32xx/include/mach/irqs.h b/arch/arm/mach-lpc32xx/include/mach/irqs.h index 2667f52e3b0..9e3b90df32e 100644 --- a/arch/arm/mach-lpc32xx/include/mach/irqs.h +++ b/arch/arm/mach-lpc32xx/include/mach/irqs.h @@ -61,7 +61,7 @@ */ #define IRQ_LPC32XX_JTAG_COMM_TX LPC32XX_SIC1_IRQ(1) #define IRQ_LPC32XX_JTAG_COMM_RX LPC32XX_SIC1_IRQ(2) -#define IRQ_LPC32XX_GPI_11 LPC32XX_SIC1_IRQ(4) +#define IRQ_LPC32XX_GPI_28 LPC32XX_SIC1_IRQ(4) #define IRQ_LPC32XX_TS_P LPC32XX_SIC1_IRQ(6) #define IRQ_LPC32XX_TS_IRQ LPC32XX_SIC1_IRQ(7) #define IRQ_LPC32XX_TS_AUX LPC32XX_SIC1_IRQ(8) diff --git a/arch/arm/mach-lpc32xx/irq.c b/arch/arm/mach-lpc32xx/irq.c index 198de470ca9..c74de01ab5b 100644 --- a/arch/arm/mach-lpc32xx/irq.c +++ b/arch/arm/mach-lpc32xx/irq.c @@ -118,6 +118,10 @@ static const struct lpc32xx_event_info lpc32xx_events[NR_IRQS] = { .event_group = &lpc32xx_event_pin_regs, .mask = LPC32XX_CLKPWR_EXTSRC_GPI_06_BIT, }, + [IRQ_LPC32XX_GPI_28] = { + .event_group = &lpc32xx_event_pin_regs, + .mask = LPC32XX_CLKPWR_EXTSRC_GPI_28_BIT, + }, [IRQ_LPC32XX_GPIO_00] = { .event_group = &lpc32xx_event_int_regs, .mask = LPC32XX_CLKPWR_INTSRC_GPIO_00_BIT, From 645507f2e948f022a30f1bc8811ca3b516c6c9bf Mon Sep 17 00:00:00 2001 From: Maxim Uvarov Date: Sun, 15 Jan 2012 20:02:50 -0800 Subject: [PATCH 1028/4025] watchdog: hpwdt: clean up set_memory_x call for 32 bit commit 97d2a10d5804d585ab0b58efbd710948401b886a upstream. 1. address has to be page aligned. 2. set_memory_x uses page size argument, not size. Bug causes with following commit: commit da28179b4e90dda56912ee825c7eaa62fc103797 Author: Mingarelli, Thomas Date: Mon Nov 7 10:59:00 2011 +0100 watchdog: hpwdt: Changes to handle NX secure bit in 32bit path commit e67d668e147c3b4fec638c9e0ace04319f5ceccd upstream. This patch makes use of the set_memory_x() kernel API in order to make necessary BIOS calls to source NMIs. Signed-off-by: Maxim Uvarov Signed-off-by: Wim Van Sebroeck Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/hpwdt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 9cb60dfbb59..d4ab797cf75 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -216,7 +216,7 @@ static int __devinit cru_detect(unsigned long map_entry, cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE; - set_memory_x((unsigned long)bios32_entrypoint, (2 * PAGE_SIZE)); + set_memory_x((unsigned long)bios32_map, 2); asminline_call(&cmn_regs, bios32_entrypoint); if (cmn_regs.u1.ral != 0) { @@ -235,7 +235,8 @@ static int __devinit cru_detect(unsigned long map_entry, cru_rom_addr = ioremap(cru_physical_address, cru_length); if (cru_rom_addr) { - set_memory_x((unsigned long)cru_rom_addr, cru_length); + set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK, + (cru_length + PAGE_SIZE - 1) >> PAGE_SHIFT); retval = 0; } } From 58cc48d37c4394fdfa8e70315dba705a1f4eb866 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 13 Jan 2012 12:14:26 +0100 Subject: [PATCH 1029/4025] i2c: mxs: only flag completion when queue is completely done MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 844990daa2e69a4258049ba9c2bae1180657dac3 upstream. The hardware generates an interrupt for every completed command in the queue while the code assumed that it will only generate one interrupt when the queue is empty. So, explicitly check if the queue is really empty. This patch fixed problems which occurred due to high traffic on the bus. While we are here, move the completion-initialization after the parameter error checking. Signed-off-by: Wolfram Sang Cc: Shawn Guo Cc: Marek Vasut Cc: Lothar Waßmann Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-mxs.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 7e78f7c8785..3d471d56bf1 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -72,6 +72,7 @@ #define MXS_I2C_QUEUESTAT (0x70) #define MXS_I2C_QUEUESTAT_RD_QUEUE_EMPTY 0x00002000 +#define MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK 0x0000001F #define MXS_I2C_QUEUECMD (0x80) @@ -219,14 +220,14 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int ret; int flags; - init_completion(&i2c->cmd_complete); - dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n", msg->addr, msg->len, msg->flags, stop); if (msg->len == 0) return -EINVAL; + init_completion(&i2c->cmd_complete); + flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0; if (msg->flags & I2C_M_RD) @@ -286,6 +287,7 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) { struct mxs_i2c_dev *i2c = dev_id; u32 stat = readl(i2c->regs + MXS_I2C_CTRL1) & MXS_I2C_IRQ_MASK; + bool is_last_cmd; if (!stat) return IRQ_NONE; @@ -300,9 +302,14 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) else i2c->cmd_err = 0; - complete(&i2c->cmd_complete); + is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) & + MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0; + + if (is_last_cmd || i2c->cmd_err) + complete(&i2c->cmd_complete); writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR); + return IRQ_HANDLED; } From e821453d52c2c984d9522a84a68d5b1f01de210a Mon Sep 17 00:00:00 2001 From: "Jett.Zhou" Date: Thu, 23 Feb 2012 19:52:08 +0800 Subject: [PATCH 1030/4025] regulator: fix the ldo configure according to 88pm860x spec commit 3380643b0eaa7ecf99c4f095bdfcb6e5df471616 upstream. Signed-off-by: Jett.Zhou Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- drivers/regulator/88pm8607.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index d63fddb0fbb..acda58e6ef0 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -195,7 +195,7 @@ static const unsigned int LDO12_suspend_table[] = { }; static const unsigned int LDO13_table[] = { - 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0, 0, + 1200000, 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0, }; static const unsigned int LDO13_suspend_table[] = { @@ -388,10 +388,10 @@ static struct pm8607_regulator_info pm8607_regulator_info[] = { PM8607_LDO( 7, LDO7, 0, 3, SUPPLIES_EN12, 1), PM8607_LDO( 8, LDO8, 0, 3, SUPPLIES_EN12, 2), PM8607_LDO( 9, LDO9, 0, 3, SUPPLIES_EN12, 3), - PM8607_LDO(10, LDO10, 0, 3, SUPPLIES_EN12, 4), + PM8607_LDO(10, LDO10, 0, 4, SUPPLIES_EN12, 4), PM8607_LDO(12, LDO12, 0, 4, SUPPLIES_EN12, 5), PM8607_LDO(13, VIBRATOR_SET, 1, 3, VIBRATOR_SET, 0), - PM8607_LDO(14, LDO14, 0, 4, SUPPLIES_EN12, 6), + PM8607_LDO(14, LDO14, 0, 3, SUPPLIES_EN12, 6), }; static int __devinit pm8607_regulator_probe(struct platform_device *pdev) From a8e161f4c38c371974319359165d544604e06b78 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 24 Feb 2012 18:01:27 +0100 Subject: [PATCH 1031/4025] S390: KEYS: Enable the compat keyctl wrapper on s390x commit 1d057720609ed052a6371fe1d53300e5e6328e94 upstream. Enable the compat keyctl wrapper on s390x so that 32-bit s390 userspace can call the keyctl() syscall. There's an s390x assembly wrapper that truncates all the register values to 32-bits and this then calls compat_sys_keyctl() - but the latter only exists if CONFIG_KEYS_COMPAT is enabled, and the s390 Kconfig doesn't enable it. Without this patch, 32-bit calls to the keyctl() syscall are given an ENOSYS error: [root@devel4 ~]# keyctl show Session Keyring -3: key inaccessible (Function not implemented) Signed-off-by: David Howells Acked-by: dan@danny.cz Cc: Carsten Otte Reviewed-by: Christian Borntraeger Cc: linux-s390@vger.kernel.org Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/Kconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index c03fef7a9c2..9b922b12e9f 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -228,6 +228,9 @@ config COMPAT config SYSVIPC_COMPAT def_bool y if COMPAT && SYSVIPC +config KEYS_COMPAT + def_bool y if COMPAT && KEYS + config AUDIT_ARCH def_bool y From 9c2143082d8e7797f6a63720100d06bec7586fd5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 27 Feb 2012 15:00:58 +0100 Subject: [PATCH 1032/4025] ALSA: hda - Add a fake mute feature commit 3868137ea41866773e75d9ac4b9988dcc361ff1d upstream. Some codecs don't supply the mute amp-capabilities although the lowest volume gives the mute. It'd be handy if the parser provides the mute mixers in such a case. This patch adds an extension amp-cap bit (which is used only in the driver) to represent the min volume = mute state. Also modified the amp cache code to support the fake mute feature when this bit is set but the real mute bit is unset. In addition, conexant cx5051 parser uses this new feature to implement the missing mute controls. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=42825 Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_codec.c | 8 ++++++-- sound/pci/hda/hda_codec.h | 3 +++ sound/pci/hda/patch_conexant.c | 22 +++++++++++++++++++++- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 67d341fa7d1..39e1a6a3ede 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1651,7 +1651,11 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT; parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT; parm |= index << AC_AMP_SET_INDEX_SHIFT; - parm |= val; + if ((val & HDA_AMP_MUTE) && !(info->amp_caps & AC_AMPCAP_MUTE) && + (info->amp_caps & AC_AMPCAP_MIN_MUTE)) + ; /* set the zero value as a fake mute */ + else + parm |= val; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); info->vol[ch] = val; } @@ -1918,7 +1922,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT); val1 += ofs; val1 = ((int)val1) * ((int)val2); - if (min_mute) + if (min_mute || (caps & AC_AMPCAP_MIN_MUTE)) val2 |= TLV_DB_SCALE_MUTE; if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv)) return -EFAULT; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 59c97306c1d..eff1fc54e56 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -302,6 +302,9 @@ enum { #define AC_AMPCAP_MUTE (1<<31) /* mute capable */ #define AC_AMPCAP_MUTE_SHIFT 31 +/* driver-specific amp-caps: using bits 24-30 */ +#define AC_AMPCAP_MIN_MUTE (1 << 30) /* min-volume = mute */ + /* Connection list */ #define AC_CLIST_LENGTH (0x7f<<0) #define AC_CLIST_LONG (1<<7) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 81ecd6c0321..4ad20a61531 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -4127,7 +4127,8 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, err = snd_hda_ctl_add(codec, nid, kctl); if (err < 0) return err; - if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE)) + if (!(query_amp_caps(codec, nid, hda_dir) & + (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE))) break; } return 0; @@ -4372,6 +4373,22 @@ static const struct hda_codec_ops cx_auto_patch_ops = { .reboot_notify = snd_hda_shutup_pins, }; +/* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches + * can be created (bko#42825) + */ +static void add_cx5051_fake_mutes(struct hda_codec *codec) +{ + static hda_nid_t out_nids[] = { + 0x10, 0x11, 0 + }; + hda_nid_t *p; + + for (p = out_nids; *p; p++) + snd_hda_override_amp_caps(codec, *p, HDA_OUTPUT, + AC_AMPCAP_MIN_MUTE | + query_amp_caps(codec, *p, HDA_OUTPUT)); +} + static int patch_conexant_auto(struct hda_codec *codec) { struct conexant_spec *spec; @@ -4390,6 +4407,9 @@ static int patch_conexant_auto(struct hda_codec *codec) case 0x14f15045: spec->single_adc_amp = 1; break; + case 0x14f15051: + add_cx5051_fake_mutes(codec); + break; } err = cx_auto_search_adcs(codec); From ca32b5c30d690d299e814fa98284a00d56e72339 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 29 Feb 2012 09:41:17 +0100 Subject: [PATCH 1033/4025] ALSA: hda - Always set HP pin in unsol handler for STAC/IDT codecs commit 7bff172a352a2fbe9856bba517d71a2072aab041 upstream. A bug report with an old Sony laptop showed that we can't rely on BIOS setting the pins of headphones but the driver should set always by itself. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_sigmatel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 43d88c72493..86706821a23 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4589,7 +4589,7 @@ static void stac92xx_hp_detect(struct hda_codec *codec) unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN; if (no_hp_sensing(spec, i)) continue; - if (presence) + if (1 /*presence*/) stac92xx_set_pinctl(codec, cfg->hp_pins[i], val); #if 0 /* FIXME */ /* Resetting the pinctl like below may lead to (a sort of) regressions From ec521c173fe9b56343808dfde63e3d75b223da07 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 2 Mar 2012 10:43:48 -0800 Subject: [PATCH 1034/4025] regset: Prevent null pointer reference on readonly regsets commit c8e252586f8d5de906385d8cf6385fee289a825e upstream. The regset common infrastructure assumed that regsets would always have .get and .set methods, but not necessarily .active methods. Unfortunately people have since written regsets without .set methods. Rather than putting in stub functions everywhere, handle regsets with null .get or .set methods explicitly. Signed-off-by: H. Peter Anvin Reviewed-by: Oleg Nesterov Acked-by: Roland McGrath Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/binfmt_elf.c | 2 +- include/linux/regset.h | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 9ba2ac755a7..618493e44ae 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -1422,7 +1422,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t, for (i = 1; i < view->n; ++i) { const struct user_regset *regset = &view->regsets[i]; do_thread_regset_writeback(t->task, regset); - if (regset->core_note_type && + if (regset->core_note_type && regset->get && (!regset->active || regset->active(t->task, regset))) { int ret; size_t size = regset->n * regset->size; diff --git a/include/linux/regset.h b/include/linux/regset.h index 8abee655622..5150fd16ef9 100644 --- a/include/linux/regset.h +++ b/include/linux/regset.h @@ -335,6 +335,9 @@ static inline int copy_regset_to_user(struct task_struct *target, { const struct user_regset *regset = &view->regsets[setno]; + if (!regset->get) + return -EOPNOTSUPP; + if (!access_ok(VERIFY_WRITE, data, size)) return -EIO; @@ -358,6 +361,9 @@ static inline int copy_regset_from_user(struct task_struct *target, { const struct user_regset *regset = &view->regsets[setno]; + if (!regset->set) + return -EOPNOTSUPP; + if (!access_ok(VERIFY_READ, data, size)) return -EIO; From 4b77339222a1d8809cde5d8920714a6cd180e5e0 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Fri, 2 Mar 2012 10:43:49 -0800 Subject: [PATCH 1035/4025] regset: Return -EFAULT, not -EIO, on host-side memory fault commit 5189fa19a4b2b4c3bec37c3a019d446148827717 upstream. There is only one error code to return for a bad user-space buffer pointer passed to a system call in the same address space as the system call is executed, and that is EFAULT. Furthermore, the low-level access routines, which catch most of the faults, return EFAULT already. Signed-off-by: H. Peter Anvin Reviewed-by: Oleg Nesterov Acked-by: Roland McGrath Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/regset.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/regset.h b/include/linux/regset.h index 5150fd16ef9..686f37327a4 100644 --- a/include/linux/regset.h +++ b/include/linux/regset.h @@ -339,7 +339,7 @@ static inline int copy_regset_to_user(struct task_struct *target, return -EOPNOTSUPP; if (!access_ok(VERIFY_WRITE, data, size)) - return -EIO; + return -EFAULT; return regset->get(target, regset, offset, size, NULL, data); } @@ -365,7 +365,7 @@ static inline int copy_regset_from_user(struct task_struct *target, return -EOPNOTSUPP; if (!access_ok(VERIFY_READ, data, size)) - return -EIO; + return -EFAULT; return regset->set(target, regset, offset, size, NULL, data); } From d7838b04ecb08709b09063a8ada0aa2d29636c12 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Sat, 18 Feb 2012 17:54:23 +0100 Subject: [PATCH 1036/4025] mfd: Fix ACPI conflict check commit 81b5482c32769abb6dfb979560dab2f952ba86fa upstream. The code is currently always checking the first resource of every device only (several times.) This has been broken since the ACPI check was added in February 2010 in commit 91fedede0338eb6203cdd618d8ece873fdb7c22c. Fix the check to run on each resource individually, once. Signed-off-by: Jean Delvare Signed-off-by: Samuel Ortiz Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/mfd-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 0902523af62..acf9dad686a 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -122,7 +122,7 @@ static int mfd_add_device(struct device *parent, int id, } if (!cell->ignore_resource_conflicts) { - ret = acpi_check_resource_conflict(res); + ret = acpi_check_resource_conflict(&res[r]); if (ret) goto fail_res; } From c847ac8e8e7447730aef70b94915f1c0880e6578 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 6 Mar 2012 23:18:54 +0100 Subject: [PATCH 1037/4025] genirq: Clear action->thread_mask if IRQ_ONESHOT is not set commit 52abb700e16a9aa4cbc03f3d7f80206cbbc80680 upstream. Xommit ac5637611(genirq: Unmask oneshot irqs when thread was not woken) fails to unmask when a !IRQ_ONESHOT threaded handler is handled by handle_level_irq. This happens because thread_mask is or'ed unconditionally in irq_wake_thread(), but for !IRQ_ONESHOT interrupts never cleared. So the check for !desc->thread_active fails and keeps the interrupt disabled. Keep the thread_mask zero for !IRQ_ONESHOT interrupts. Document the thread_mask magic while at it. Reported-and-tested-by: Sven Joachim Reported-and-tested-by: Stefan Lippers-Hollmann Signed-off-by: Thomas Gleixner Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/irq/manage.c | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index def3406fb43..e4eedb16197 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -976,6 +976,11 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) /* add new interrupt at end of irq queue */ do { + /* + * Or all existing action->thread_mask bits, + * so we can find the next zero bit for this + * new action. + */ thread_mask |= old->thread_mask; old_ptr = &old->next; old = *old_ptr; @@ -984,14 +989,41 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) } /* - * Setup the thread mask for this irqaction. Unlikely to have - * 32 resp 64 irqs sharing one line, but who knows. + * Setup the thread mask for this irqaction for ONESHOT. For + * !ONESHOT irqs the thread mask is 0 so we can avoid a + * conditional in irq_wake_thread(). */ - if (new->flags & IRQF_ONESHOT && thread_mask == ~0UL) { - ret = -EBUSY; - goto out_mask; + if (new->flags & IRQF_ONESHOT) { + /* + * Unlikely to have 32 resp 64 irqs sharing one line, + * but who knows. + */ + if (thread_mask == ~0UL) { + ret = -EBUSY; + goto out_mask; + } + /* + * The thread_mask for the action is or'ed to + * desc->thread_active to indicate that the + * IRQF_ONESHOT thread handler has been woken, but not + * yet finished. The bit is cleared when a thread + * completes. When all threads of a shared interrupt + * line have completed desc->threads_active becomes + * zero and the interrupt line is unmasked. See + * handle.c:irq_wake_thread() for further information. + * + * If no thread is woken by primary (hard irq context) + * interrupt handlers, then desc->threads_active is + * also checked for zero to unmask the irq line in the + * affected hard irq flow handlers + * (handle_[fasteoi|level]_irq). + * + * The new action gets the first zero bit of + * thread_mask assigned. See the loop above which or's + * all existing action->thread_mask bits. + */ + new->thread_mask = 1 << ffz(thread_mask); } - new->thread_mask = 1 << ffz(thread_mask); if (!shared) { init_waitqueue_head(&desc->wait_for_threads); From 0cd0b02bfce1497e21e11b33311fd4da6d10ea55 Mon Sep 17 00:00:00 2001 From: Gusakov Andrey Date: Sat, 3 Mar 2012 07:32:36 +0900 Subject: [PATCH 1038/4025] ARM: S3C24XX: DMA resume regression fix commit e39d40c65dfd8390b50c03482ae9e289b8a8f351 upstream. s3c2410_dma_suspend suspends channels from 0 to dma_channels. s3c2410_dma_resume resumes channels in reverse order. So pointer should be decremented instead of being incremented. Signed-off-by: Gusakov Andrey Reviewed-by: Heiko Stuebner Signed-off-by: Kukjin Kim Signed-off-by: Greg Kroah-Hartman --- arch/arm/plat-s3c24xx/dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c index 539bd0e3def..0719f49defb 100644 --- a/arch/arm/plat-s3c24xx/dma.c +++ b/arch/arm/plat-s3c24xx/dma.c @@ -1249,7 +1249,7 @@ static void s3c2410_dma_resume(void) struct s3c2410_dma_chan *cp = s3c2410_chans + dma_channels - 1; int channel; - for (channel = dma_channels - 1; channel >= 0; cp++, channel--) + for (channel = dma_channels - 1; channel >= 0; cp--, channel--) s3c2410_dma_resume_chan(cp); } From c2235bf93207cbd4d72c8e560d59b6adf36611b2 Mon Sep 17 00:00:00 2001 From: Scott Talbert Date: Tue, 21 Feb 2012 13:06:00 +0000 Subject: [PATCH 1039/4025] Move Logitech Harmony 900 from cdc_ether to zaurus commit ee932bf9acb2e2c6a309e808000f24856330e3f9 upstream. In the current kernel implementation, the Logitech Harmony 900 remote control is matched to the cdc_ether driver through the generic USB_CDC_SUBCLASS_MDLM entry. However, this device appears to be of the pseudo-MDLM (Belcarra) type, rather than the standard one. This patch blacklists the Harmony 900 from the cdc_ether driver and whitelists it for the pseudo-MDLM driver in zaurus. Signed-off-by: Scott Talbert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/cdc_ether.c | 7 +++++++ drivers/net/usb/zaurus.c | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index c924ea2bce0..13919ddb6f5 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -570,6 +570,13 @@ static const struct usb_device_id products [] = { .driver_info = (unsigned long)&wwan_info, }, +/* Logitech Harmony 900 - uses the pseudo-MDLM (BLAN) driver */ +{ + USB_DEVICE_AND_INTERFACE_INFO(0x046d, 0xc11f, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = 0, +}, + /* * WHITELIST!!! * diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c index 1a2234c2051..246b3bb14f2 100644 --- a/drivers/net/usb/zaurus.c +++ b/drivers/net/usb/zaurus.c @@ -349,6 +349,13 @@ static const struct usb_device_id products [] = { ZAURUS_MASTER_INTERFACE, .driver_info = OLYMPUS_MXL_INFO, }, + +/* Logitech Harmony 900 - uses the pseudo-MDLM (BLAN) driver */ +{ + USB_DEVICE_AND_INTERFACE_INFO(0x046d, 0xc11f, USB_CLASS_COMM, + USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE), + .driver_info = (unsigned long) &bogus_mdlm_info, +}, { }, // END }; MODULE_DEVICE_TABLE(usb, products); From f148e8a6cf51419b4dc7c99941054ed3ddad5a87 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 5 Mar 2012 14:59:19 -0800 Subject: [PATCH 1040/4025] alpha: fix 32/64-bit bug in futex support commit 62aca403657fe30e5235c5331e9871e676d9ea0a upstream. Michael Cree said: : : I have noticed some user space problems (pulseaudio crashes in pthread : : code, glibc/nptl test suite failures, java compiler freezes on SMP alpha : : systems) that arise when using a 2.6.39 or later kernel on Alpha. : : Bisecting between 2.6.38 and 2.6.39 (using glibc/nptl test suite as : : criterion for good/bad kernel) eventually leads to: : : : : 8d7718aa082aaf30a0b4989e1f04858952f941bc is the first bad commit : : commit 8d7718aa082aaf30a0b4989e1f04858952f941bc : : Author: Michel Lespinasse : : Date: Thu Mar 10 18:50:58 2011 -0800 : : : : futex: Sanitize futex ops argument types : : : : Change futex_atomic_op_inuser and futex_atomic_cmpxchg_inatomic : : prototypes to use u32 types for the futex as this is the data type the : : futex core code uses all over the place. : : : : Looking at the commit I see there is a change of the uaddr argument in : : the Alpha architecture specific code for futexes from int to u32, but I : : don't see why this should cause a problem. Richard Henderson said: : futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, : u32 oldval, u32 newval) : ... : : "r"(uaddr), "r"((long)oldval), "r"(newval) : : : There is no 32-bit compare instruction. These are implemented by : consistently extending the values to a 64-bit type. Since the : load instruction sign-extends, we want to sign-extend the other : quantity as well (despite the fact it's logically unsigned). : : So: : : - : "r"(uaddr), "r"((long)oldval), "r"(newval) : + : "r"(uaddr), "r"((long)(int)oldval), "r"(newval) : : should do the trick. Michael said: : This fixes the glibc test suite failures and the pulseaudio related : crashes, but it does not fix the java compiiler lockups that I was (and : are still) observing. That is some other problem. Reported-by: Michael Cree Tested-by: Michael Cree Acked-by: Phil Carmody Cc: Richard Henderson Cc: Michel Lespinasse Cc: Ivan Kokshaysky Reviewed-by: Matt Turner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/alpha/include/asm/futex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/alpha/include/asm/futex.h b/arch/alpha/include/asm/futex.h index e8a761aee08..f939794363a 100644 --- a/arch/alpha/include/asm/futex.h +++ b/arch/alpha/include/asm/futex.h @@ -108,7 +108,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, " lda $31,3b-2b(%0)\n" " .previous\n" : "+r"(ret), "=&r"(prev), "=&r"(cmp) - : "r"(uaddr), "r"((long)oldval), "r"(newval) + : "r"(uaddr), "r"((long)(int)oldval), "r"(newval) : "memory"); *uval = prev; From d5d292475ce5ed9d9cbc3630e0a5fbed8155bb3a Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 17 Feb 2012 11:51:49 +0100 Subject: [PATCH 1041/4025] mmc: sdhci-esdhc-imx: fix for mmc cards on i.MX5 commit 5b6b0ad6e572b32a641116aaa5f897ffebe31e44 upstream. On i.MX53 we have to write a special SDHCI_CMD_ABORTCMD to the SDHCI_TRANSFER_MODE register during a MMC_STOP_TRANSMISSION command. This works for SD cards. However, with MMC cards the MMC_SET_BLOCK_COUNT command is used instead, but this needs the same handling. Fix MMC cards by testing for the MMC_SET_BLOCK_COUNT command aswell. Tested on a custom i.MX53 board with a Transcend MMC+ card and eMMC. The kernel started used MMC_SET_BLOCK_COUNT in 3.0, so this is a regression for these boards introduced in 3.0; it should go to 3.0/3.1/3.2-stable. Signed-off-by: Sascha Hauer Acked-by: Shawn Guo Signed-off-by: Chris Ball Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci-esdhc-imx.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index ba31abee948..92e54370183 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -139,8 +139,9 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) imx_data->scratchpad = val; return; case SDHCI_COMMAND: - if ((host->cmd->opcode == MMC_STOP_TRANSMISSION) - && (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) + if ((host->cmd->opcode == MMC_STOP_TRANSMISSION || + host->cmd->opcode == MMC_SET_BLOCK_COUNT) && + (imx_data->flags & ESDHC_FLAG_MULTIBLK_NO_INT)) val |= SDHCI_CMD_ABORTCMD; writel(val << 16 | imx_data->scratchpad, host->ioaddr + SDHCI_TRANSFER_MODE); From 509c46f3d4fe2c6043ed2a00856ff4f4dce0f13a Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 24 Feb 2012 05:14:46 +0400 Subject: [PATCH 1042/4025] mm: memcg: Correct unregistring of events attached to the same eventfd commit 371528caec553785c37f73fa3926ea0de84f986f upstream. There is an issue when memcg unregisters events that were attached to the same eventfd: - On the first call mem_cgroup_usage_unregister_event() removes all events attached to a given eventfd, and if there were no events left, thresholds->primary would become NULL; - Since there were several events registered, cgroups core will call mem_cgroup_usage_unregister_event() again, but now kernel will oops, as the function doesn't expect that threshold->primary may be NULL. That's a good question whether mem_cgroup_usage_unregister_event() should actually remove all events in one go, but nowadays it can't do any better as cftype->unregister_event callback doesn't pass any private event-associated cookie. So, let's fix the issue by simply checking for threshold->primary. FWIW, w/o the patch the following oops may be observed: BUG: unable to handle kernel NULL pointer dereference at 0000000000000004 IP: [] mem_cgroup_usage_unregister_event+0x9c/0x1f0 Pid: 574, comm: kworker/0:2 Not tainted 3.3.0-rc4+ #9 Bochs Bochs RIP: 0010:[] [] mem_cgroup_usage_unregister_event+0x9c/0x1f0 RSP: 0018:ffff88001d0b9d60 EFLAGS: 00010246 Process kworker/0:2 (pid: 574, threadinfo ffff88001d0b8000, task ffff88001de91cc0) Call Trace: [] cgroup_event_remove+0x2b/0x60 [] process_one_work+0x174/0x450 [] worker_thread+0x123/0x2d0 Signed-off-by: Anton Vorontsov Acked-by: KAMEZAWA Hiroyuki Cc: Kirill A. Shutemov Cc: Michal Hocko Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/memcontrol.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 3791581d3e5..45059db3581 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -4558,6 +4558,9 @@ static void mem_cgroup_usage_unregister_event(struct cgroup *cgrp, */ BUG_ON(!thresholds); + if (!thresholds->primary) + goto unlock; + usage = mem_cgroup_usage(memcg, type == _MEMSWAP); /* Check if a threshold crossed before removing */ @@ -4606,7 +4609,7 @@ static void mem_cgroup_usage_unregister_event(struct cgroup *cgrp, /* To be sure that nobody uses thresholds */ synchronize_rcu(); - +unlock: mutex_unlock(&memcg->thresholds_lock); } From 0f062a5c0e3b23803c1f5b927ef5e8ba5ec52ff1 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 23 Feb 2012 13:51:00 +0000 Subject: [PATCH 1043/4025] NOMMU: Don't need to clear vm_mm when deleting a VMA commit b94cfaf6685d691dc3fab023cf32f65e9b7be09c upstream. Don't clear vm_mm in a deleted VMA as it's unnecessary and might conceivably break the filesystem or driver VMA close routine. Reported-by: Al Viro Signed-off-by: David Howells Acked-by: Al Viro Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/nommu.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/mm/nommu.c b/mm/nommu.c index 839775875e7..5ff9b35883e 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -780,8 +780,6 @@ static void delete_vma_from_mm(struct vm_area_struct *vma) if (vma->vm_next) vma->vm_next->vm_prev = vma->vm_prev; - - vma->vm_mm = NULL; } /* From 3c156187b23b66ce205a7d8d93ad6ff567fc6608 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 23 Feb 2012 09:37:45 -0500 Subject: [PATCH 1044/4025] cifs: fix dentry refcount leak when opening a FIFO on lookup commit 5bccda0ebc7c0331b81ac47d39e4b920b198b2cd upstream. The cifs code will attempt to open files on lookup under certain circumstances. What happens though if we find that the file we opened was actually a FIFO or other special file? Currently, the open filehandle just ends up being leaked leading to a dentry refcount mismatch and oops on umount. Fix this by having the code close the filehandle on the server if it turns out not to be a regular file. While we're at it, change this spaghetti if statement into a switch too. Reported-by: CAI Qian Tested-by: CAI Qian Reviewed-by: Shirish Pargaonkar Signed-off-by: Jeff Layton Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/dir.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 16cdd6da227..ed5c07b0cdb 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -583,10 +583,26 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, * If either that or op not supported returned, follow * the normal lookup. */ - if ((rc == 0) || (rc == -ENOENT)) + switch (rc) { + case 0: + /* + * The server may allow us to open things like + * FIFOs, but the client isn't set up to deal + * with that. If it's not a regular file, just + * close it and proceed as if it were a normal + * lookup. + */ + if (newInode && !S_ISREG(newInode->i_mode)) { + CIFSSMBClose(xid, pTcon, fileHandle); + break; + } + case -ENOENT: posix_open = true; - else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP)) + case -EOPNOTSUPP: + break; + default: pTcon->broken_posix_open = true; + } } if (!posix_open) rc = cifs_get_inode_info_unix(&newInode, full_path, From 34a9660ba1a8b98adf852f4f1090bdf084ccf991 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Mon, 20 Feb 2012 10:05:31 +0530 Subject: [PATCH 1045/4025] mac80211: zero initialize count field in ieee80211_tx_rate commit 8617b093d0031837a7be9b32bc674580cfb5f6b5 upstream. rate control algorithms concludes the rate as invalid with rate[i].idx < -1 , while they do also check for rate[i].count is non-zero. it would be safer to zero initialize the 'count' field. recently we had a ath9k rate control crash where the ath9k rate control in ath_tx_status assumed to check only for rate[i].count being non-zero in one instance and ended up in using invalid rate index for 'connection monitoring NULL func frames' which eventually lead to the crash. thanks to Pavel Roskin for fixing it and finding the root cause. https://bugzilla.redhat.com/show_bug.cgi?id=768639 Cc: Pavel Roskin Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- net/mac80211/rate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 3d5a2cb835c..816590b0d7f 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -314,7 +314,7 @@ void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { info->control.rates[i].idx = -1; info->control.rates[i].flags = 0; - info->control.rates[i].count = 1; + info->control.rates[i].count = 0; } if (sdata->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) From b0f1b35e3cf604dcafdeae9ba3b4a1a86df7d9e8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 15 Feb 2012 19:31:20 +0100 Subject: [PATCH 1046/4025] ath9k_hw: prevent writes to const data on AR9160 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 9bbb8168ed3d8b946f9c1901a63a675012de88f2 upstream. Duplicate the data for iniAddac early on, to avoid having to do redundant memcpy calls later. While we're at it, make AR5416 < v2.2 use the same codepath. Fixes a reported crash on x86. Signed-off-by: Felix Fietkau Reported-by: Magnus Määttä Signed-off-by: John W. Linville Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath9k/ar5008_phy.c | 25 +-------------------- drivers/net/wireless/ath/ath9k/ar9002_hw.c | 19 ++++++++++++++++ drivers/net/wireless/ath/ath9k/hw.h | 1 - 3 files changed, 20 insertions(+), 25 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 441bb33f17a..0f23b1a789e 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -489,8 +489,6 @@ static int ar5008_hw_rf_alloc_ext_banks(struct ath_hw *ah) ATH_ALLOC_BANK(ah->analogBank6Data, ah->iniBank6.ia_rows); ATH_ALLOC_BANK(ah->analogBank6TPCData, ah->iniBank6TPC.ia_rows); ATH_ALLOC_BANK(ah->analogBank7Data, ah->iniBank7.ia_rows); - ATH_ALLOC_BANK(ah->addac5416_21, - ah->iniAddac.ia_rows * ah->iniAddac.ia_columns); ATH_ALLOC_BANK(ah->bank6Temp, ah->iniBank6.ia_rows); return 0; @@ -519,7 +517,6 @@ static void ar5008_hw_rf_free_ext_banks(struct ath_hw *ah) ATH_FREE_BANK(ah->analogBank6Data); ATH_FREE_BANK(ah->analogBank6TPCData); ATH_FREE_BANK(ah->analogBank7Data); - ATH_FREE_BANK(ah->addac5416_21); ATH_FREE_BANK(ah->bank6Temp); #undef ATH_FREE_BANK @@ -799,27 +796,7 @@ static int ar5008_hw_process_ini(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO); ah->eep_ops->set_addac(ah, chan); - if (AR_SREV_5416_22_OR_LATER(ah)) { - REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites); - } else { - struct ar5416IniArray temp; - u32 addacSize = - sizeof(u32) * ah->iniAddac.ia_rows * - ah->iniAddac.ia_columns; - - /* For AR5416 2.0/2.1 */ - memcpy(ah->addac5416_21, - ah->iniAddac.ia_array, addacSize); - - /* override CLKDRV value at [row, column] = [31, 1] */ - (ah->addac5416_21)[31 * ah->iniAddac.ia_columns + 1] = 0; - - temp.ia_array = ah->addac5416_21; - temp.ia_columns = ah->iniAddac.ia_columns; - temp.ia_rows = ah->iniAddac.ia_rows; - REG_WRITE_ARRAY(&temp, 1, regWrites); - } - + REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites); REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); ENABLE_REGWRITE_BUFFER(ah); diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index c32f9d1b215..30bf703c044 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -179,6 +179,25 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac, ARRAY_SIZE(ar5416Addac), 2); } + + /* iniAddac needs to be modified for these chips */ + if (AR_SREV_9160(ah) || !AR_SREV_5416_22_OR_LATER(ah)) { + struct ar5416IniArray *addac = &ah->iniAddac; + u32 size = sizeof(u32) * addac->ia_rows * addac->ia_columns; + u32 *data; + + data = kmalloc(size, GFP_KERNEL); + if (!data) + return; + + memcpy(data, addac->ia_array, size); + addac->ia_array = data; + + if (!AR_SREV_5416_22_OR_LATER(ah)) { + /* override CLKDRV value */ + INI_RA(addac, 31,1) = 0; + } + } } /* Support for Japan ch.14 (2484) spread */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 939cc9d76c2..9dc2666fd1c 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -763,7 +763,6 @@ struct ath_hw { u32 *analogBank6Data; u32 *analogBank6TPCData; u32 *analogBank7Data; - u32 *addac5416_21; u32 *bank6Temp; u8 txpower_limit; From 3ddb5b56f09929992ac6a4e0c0c1f3fb6cbde509 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Mon, 5 Mar 2012 14:59:20 -0800 Subject: [PATCH 1047/4025] mm: thp: fix BUG on mm->nr_ptes commit 1c641e84719429bbfe62a95ed3545ee7fe24408f upstream. Dave Jones reports a few Fedora users hitting the BUG_ON(mm->nr_ptes...) in exit_mmap() recently. Quoting Hugh's discovery and explanation of the SMP race condition: "mm->nr_ptes had unusual locking: down_read mmap_sem plus page_table_lock when incrementing, down_write mmap_sem (or mm_users 0) when decrementing; whereas THP is careful to increment and decrement it under page_table_lock. Now most of those paths in THP also hold mmap_sem for read or write (with appropriate checks on mm_users), but two do not: when split_huge_page() is called by hwpoison_user_mappings(), and when called by add_to_swap(). It's conceivable that the latter case is responsible for the exit_mmap() BUG_ON mm->nr_ptes that has been reported on Fedora." The simplest way to fix it without having to alter the locking is to make split_huge_page() a noop in nr_ptes terms, so by counting the preallocated pagetables that exists for every mapped hugepage. It was an arbitrary choice not to count them and either way is not wrong or right, because they are not used but they're still allocated. Reported-by: Dave Jones Reported-by: Hugh Dickins Signed-off-by: Andrea Arcangeli Acked-by: Hugh Dickins Cc: David Rientjes Cc: Josh Boyer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/huge_memory.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 78a83e71699..8cc11dda6a7 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -641,6 +641,7 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm, set_pmd_at(mm, haddr, pmd, entry); prepare_pmd_huge_pte(pgtable, mm); add_mm_counter(mm, MM_ANONPAGES, HPAGE_PMD_NR); + mm->nr_ptes++; spin_unlock(&mm->page_table_lock); } @@ -759,6 +760,7 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, pmd = pmd_mkold(pmd_wrprotect(pmd)); set_pmd_at(dst_mm, addr, dst_pmd, pmd); prepare_pmd_huge_pte(pgtable, dst_mm); + dst_mm->nr_ptes++; ret = 0; out_unlock: @@ -857,7 +859,6 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm, } kfree(pages); - mm->nr_ptes++; smp_wmb(); /* make pte visible before pmd */ pmd_populate(mm, pmd, pgtable); page_remove_rmap(page); @@ -1016,6 +1017,7 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma, VM_BUG_ON(page_mapcount(page) < 0); add_mm_counter(tlb->mm, MM_ANONPAGES, -HPAGE_PMD_NR); VM_BUG_ON(!PageHead(page)); + tlb->mm->nr_ptes--; spin_unlock(&tlb->mm->page_table_lock); tlb_remove_page(tlb, page); pte_free(tlb->mm, pgtable); @@ -1310,7 +1312,6 @@ static int __split_huge_page_map(struct page *page, pte_unmap(pte); } - mm->nr_ptes++; smp_wmb(); /* make pte visible before pmd */ /* * Up to this point the pmd is present and huge and @@ -1925,7 +1926,6 @@ static void collapse_huge_page(struct mm_struct *mm, set_pmd_at(mm, address, pmd, _pmd); update_mmu_cache(vma, address, entry); prepare_pmd_huge_pte(pgtable, mm); - mm->nr_ptes--; spin_unlock(&mm->page_table_lock); #ifndef CONFIG_NUMA From 14dfead7ebff3fcd14549f613041c4f777f8b75e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 27 Feb 2012 11:23:45 -0500 Subject: [PATCH 1048/4025] HID: usbhid: Add NOGET quirk for the AIREN Slim+ keyboard commit 37891abc8464637964a26ae4b61d307fef831f80 upstream. This patch (as1531) adds a NOGET quirk for the Slim+ keyboard marketed by AIREN. This keyboard seems to have a lot of bugs; NOGET works around only one of them. Signed-off-by: Alan Stern Reported-by: okias Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index e0a28ade952..6781fe0022c 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -59,6 +59,9 @@ #define USB_VENDOR_ID_AIRCABLE 0x16CA #define USB_DEVICE_ID_AIRCABLE1 0x1502 +#define USB_VENDOR_ID_AIREN 0x1a2c +#define USB_DEVICE_ID_AIREN_SLIMPLUS 0x0002 + #define USB_VENDOR_ID_ALCOR 0x058f #define USB_DEVICE_ID_ALCOR_USBRS232 0x9720 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 3146fdcda27..85c845f7f61 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -52,6 +52,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, From 56c54856551b8a8199fda32aa7c416c719e5f0b9 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Mon, 27 Feb 2012 12:17:04 +0100 Subject: [PATCH 1049/4025] crypto: mv_cesa - fix final callback not ignoring input data commit f8f54e190ddb4ed697036b60f5e2ae6dd45b801c upstream. Broken by commit 6ef84509f3d439ed2d43ea40080643efec37f54f for users passing a request with non-zero 'nbytes' field, like e.g. testmgr. Signed-off-by: Phil Sutter Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/mv_cesa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index 38a3297ae2b..f53dd83438b 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -713,6 +713,7 @@ static int mv_hash_final(struct ahash_request *req) { struct mv_req_hash_ctx *ctx = ahash_request_ctx(req); + ahash_request_set_crypt(req, NULL, req->result, 0); mv_update_hash_req_ctx(ctx, 1, 0); return mv_handle_req(&req->base); } From d4d6cc13fa9c22283fdb6c5261ff988d00e018b8 Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Wed, 25 Jan 2012 21:42:58 +0200 Subject: [PATCH 1050/4025] osd_uld: Bump MAX_OSD_DEVICES from 64 to 1,048,576 commit 41f8ad76362e7aefe3a03949c43e23102dae6e0b upstream. It used to be that minors where 8 bit. But now they are actually 20 bit. So the fix is simplicity itself. I've tested with 300 devices and all user-mode utils work just fine. I have also mechanically added 10,000 to the ida (so devices are /dev/osd10000, /dev/osd10001 ...) and was able to mkfs an exofs filesystem and access osds from user-mode. All the open-osd user-mode code uses the same library to access devices through their symbolic names in /dev/osdX so I'd say it's pretty safe. (Well tested) This patch is very important because some of the systems that will be deploying the 3.2 pnfs-objects code are larger than 64 OSDs and will stop to work properly when reaching that number. Signed-off-by: Boaz Harrosh Signed-off-by: James Bottomley Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/osd/osd_uld.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c index b31a8e3841d..d4ed9eb5265 100644 --- a/drivers/scsi/osd/osd_uld.c +++ b/drivers/scsi/osd/osd_uld.c @@ -69,10 +69,10 @@ #ifndef SCSI_OSD_MAJOR # define SCSI_OSD_MAJOR 260 #endif -#define SCSI_OSD_MAX_MINOR 64 +#define SCSI_OSD_MAX_MINOR MINORMASK static const char osd_name[] = "osd"; -static const char *osd_version_string = "open-osd 0.2.0"; +static const char *osd_version_string = "open-osd 0.2.1"; MODULE_AUTHOR("Boaz Harrosh "); MODULE_DESCRIPTION("open-osd Upper-Layer-Driver osd.ko"); From 973c38c2d69dabf942f510d5bb2af8c3f1669c82 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 22 Feb 2012 15:52:56 +0000 Subject: [PATCH 1051/4025] ASoC: dapm: Check for bias level when powering down commit 7679e42ec833ed70aa34790a5f39dcb7e5bda4fe upstream. Recent enhancements in the bias management means that we might not be in standby when the CODEC is idle and can have active widgets without being in full power mode but the shutdown functionality assumes these things. Add checks for the bias level at each stage so that we don't do transitions other than the ON->PREPARE->STANDBY->OFF ones that the drivers are expecting. Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/soc-dapm.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 32ab7fc4579..058c0a8c2ec 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2615,9 +2615,13 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) * standby. */ if (powerdown) { - snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE); + if (dapm->bias_level == SND_SOC_BIAS_ON) + snd_soc_dapm_set_bias_level(dapm, + SND_SOC_BIAS_PREPARE); dapm_seq_run(dapm, &down_list, 0, false); - snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY); + if (dapm->bias_level == SND_SOC_BIAS_PREPARE) + snd_soc_dapm_set_bias_level(dapm, + SND_SOC_BIAS_STANDBY); } } @@ -2630,7 +2634,9 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card) list_for_each_entry(codec, &card->codec_dev_list, list) { soc_dapm_shutdown_codec(&codec->dapm); - snd_soc_dapm_set_bias_level(&codec->dapm, SND_SOC_BIAS_OFF); + if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) + snd_soc_dapm_set_bias_level(&codec->dapm, + SND_SOC_BIAS_OFF); } } From 1cd5a2cdce1508eabd38e530086b56fad68b89d0 Mon Sep 17 00:00:00 2001 From: Javier Martin Date: Thu, 23 Feb 2012 15:43:18 +0100 Subject: [PATCH 1052/4025] ASoC: i.MX SSI: Fix DSP_A format. commit 5ed80a75b248bfaf840ea6b38f941edcf6ee7dc7 upstream. According to i.MX27 Reference Manual (p 1593) TXBIT0 bit selects whether the most significant or the less significant part of the data word written to the FIFO is transmitted. As DSP_A is the same as DSP_B with a data offset of 1 bit, it doesn't make any sense to remove TXBIT0 bit here. Signed-off-by: Javier Martin Acked-by: Sascha Hauer Signed-off-by: Mark Brown Signed-off-by: Greg Kroah-Hartman --- sound/soc/imx/imx-ssi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c index 61fceb09cdb..3b56254006a 100644 --- a/sound/soc/imx/imx-ssi.c +++ b/sound/soc/imx/imx-ssi.c @@ -112,7 +112,7 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) break; case SND_SOC_DAIFMT_DSP_A: /* data on rising edge of bclk, frame high 1clk before data */ - strcr |= SSI_STCR_TFSL | SSI_STCR_TEFS; + strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0 | SSI_STCR_TEFS; break; } From b38d6b8e1914ed83cc58673341781f4cba4d9d06 Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Wed, 8 Feb 2012 20:02:03 +0100 Subject: [PATCH 1053/4025] bsg: fix sysfs link remove warning commit 37b40adf2d1b4a5e51323be73ccf8ddcf3f15dd3 upstream. We create "bsg" link if q->kobj.sd is not NULL, so remove it only when the same condition is true. Fixes: WARNING: at fs/sysfs/inode.c:323 sysfs_hash_and_remove+0x2b/0x77() sysfs: can not remove 'bsg', no directory Call Trace: [] warn_slowpath_common+0x6a/0x7f [] ? sysfs_hash_and_remove+0x2b/0x77 [] warn_slowpath_fmt+0x2b/0x2f [] sysfs_hash_and_remove+0x2b/0x77 [] sysfs_remove_link+0x20/0x23 [] bsg_unregister_queue+0x40/0x6d [] __scsi_remove_device+0x31/0x9d [] scsi_forget_host+0x41/0x52 [] scsi_remove_host+0x71/0xe0 [] quiesce_and_remove_host+0x51/0x83 [usb_storage] [] usb_stor_disconnect+0x18/0x22 [usb_storage] [] usb_unbind_interface+0x4e/0x109 [] __device_release_driver+0x6b/0xa6 [] device_release_driver+0x17/0x22 [] bus_remove_device+0xd6/0xe6 [] device_del+0xf2/0x137 [] usb_disable_device+0x94/0x1a0 Signed-off-by: Stanislaw Gruszka Signed-off-by: Jens Axboe Signed-off-by: Tim Gardner Signed-off-by: Greg Kroah-Hartman --- block/bsg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/block/bsg.c b/block/bsg.c index 0c8b64a1648..792ead66675 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -985,7 +985,8 @@ void bsg_unregister_queue(struct request_queue *q) mutex_lock(&bsg_mutex); idr_remove(&bsg_minor_idr, bcd->minor); - sysfs_remove_link(&q->kobj, "bsg"); + if (q->kobj.sd) + sysfs_remove_link(&q->kobj, "bsg"); device_unregister(bcd->class_dev); bcd->class_dev = NULL; kref_put(&bcd->ref, bsg_kref_release_function); From 3ff2d5a6e8e1f7c793e2354a7917fd20206c4983 Mon Sep 17 00:00:00 2001 From: Keng-Yu Lin Date: Fri, 2 Dec 2011 00:04:23 +0100 Subject: [PATCH 1054/4025] ACPI / PM: Do not save/restore NVS on Asus K54C/K54HR commit 5a50a7c32d630d6cdb13d69afabb0cc81b2f379c upstream. The models do not resume correctly without acpi_sleep=nonvs. Signed-off-by: Keng-Yu Lin Signed-off-by: Rafael J. Wysocki Cc: Tim Gardner Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/sleep.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 6c949602cbd..0bd4832fb1a 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -428,6 +428,22 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "1000 Series"), }, }, + { + .callback = init_nvs_nosave, + .ident = "Asus K54C", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "K54C"), + }, + }, + { + .callback = init_nvs_nosave, + .ident = "Asus K54HR", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"), + }, + }, {}, }; #endif /* CONFIG_SUSPEND */ From 896903eb8ed86754935bb65b377e69dc048eac34 Mon Sep 17 00:00:00 2001 From: Fabio Baltieri Date: Fri, 3 Feb 2012 15:37:14 -0800 Subject: [PATCH 1055/4025] avr32: select generic atomic64_t support commit 31e0017e6f6fb5cfdfaf932c1f98c9bef8d57688 upstream. Enable use of the generic atomic64 implementation on AVR32 platforms. Without this the kernel fails to build as the architecture does not provide its version. Signed-off-by: Fabio Baltieri Acked-by: Hans-Christian Egtvedt Cc: Haavard Skinnemoen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Jean-Christophe PLAGNIOL-VILLARD Signed-off-by: Greg Kroah-Hartman --- arch/avr32/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/avr32/Kconfig b/arch/avr32/Kconfig index e9d689b7c83..c614484f0fc 100644 --- a/arch/avr32/Kconfig +++ b/arch/avr32/Kconfig @@ -8,6 +8,7 @@ config AVR32 select HAVE_KPROBES select HAVE_GENERIC_HARDIRQS select GENERIC_IRQ_PROBE + select GENERIC_ATOMIC64 select HARDIRQS_SW_RESEND select GENERIC_IRQ_SHOW help From b8a0040ef7112439ad2efac6f1a79aa842b5924f Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 28 Feb 2012 10:41:37 +0000 Subject: [PATCH 1056/4025] kprobes: adjust "fix a memory leak in function pre_handler_kretprobe()" 3.0.21's 603b63484725a6e88e4ae5da58716efd88154b1e directly used the upstream patch, yet kprobes locking in 3.0.x uses spin_lock...() rather than raw_spin_lock...(). Signed-off-by: Jan Beulich Signed-off-by: Greg Kroah-Hartman --- kernel/kprobes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 749340c1e6f..f1dcde499f6 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1661,9 +1661,9 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p, ri->task = current; if (rp->entry_handler && rp->entry_handler(ri, regs)) { - raw_spin_lock_irqsave(&rp->lock, flags); + spin_lock_irqsave(&rp->lock, flags); hlist_add_head(&ri->hlist, &rp->free_instances); - raw_spin_unlock_irqrestore(&rp->lock, flags); + spin_unlock_irqrestore(&rp->lock, flags); return 0; } From f7f7943d1a0a34c2b8b93388daaa50571eade5e7 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Wed, 8 Feb 2012 12:53:49 -0800 Subject: [PATCH 1057/4025] drm/i915: gen7: implement rczunit workaround commit eae66b50c760233fad526edf4a0d327be17a055d upstream. This is yet another workaround related to clock gating which we need on Ivy Bridge. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=41353 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=44610 Tested-by: Eugeni Dodonov Signed-off-by: Eugeni Dodonov Signed-off-by: Kenneth Graunke Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_display.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 673f0d2cd4e..95b24e43500 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3371,6 +3371,7 @@ #define GT_FIFO_FREE_ENTRIES 0x120008 #define GEN6_UCGCTL2 0x9404 +# define GEN6_RCZUNIT_CLOCK_GATE_DISABLE (1 << 13) # define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE (1 << 12) # define GEN6_RCCUNIT_CLOCK_GATE_DISABLE (1 << 11) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e4b25861a12..f7627759875 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7457,6 +7457,11 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0); + /* According to the spec, bit 13 (RCZUNIT) must be set on IVB. + * This implements the WaDisableRCZUnitClockGating workaround. + */ + I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE); + I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); for_each_pipe(pipe) From 8d5124c4081c166e6b74a6b98c635a3279af0c91 Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Wed, 8 Feb 2012 12:53:50 -0800 Subject: [PATCH 1058/4025] drm/i915: gen7: Implement an L3 caching workaround. commit e4e0c058a19c41150d12ad2d3023b3cf09c5de67 upstream. This adds two cache-related workarounds for Ivy Bridge which can lead to 3D ring hangs and corruptions. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=41353 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=44610 Tested-by: Eugeni Dodonov Signed-off-by: Eugeni Dodonov Signed-off-by: Kenneth Graunke Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 7 +++++++ drivers/gpu/drm/i915/intel_display.c | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 95b24e43500..73e4a343735 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2847,6 +2847,13 @@ #define DISP_TILE_SURFACE_SWIZZLING (1<<13) #define DISP_FBC_WM_DIS (1<<15) +/* GEN7 chicken */ +#define GEN7_L3CNTLREG1 0xB01C +#define GEN7_WA_FOR_GEN7_L3_CONTROL 0x3C4FFF8C + +#define GEN7_L3_CHICKEN_MODE_REGISTER 0xB030 +#define GEN7_WA_L3_CHICKEN_MODE 0x20000000 + /* PCH */ /* south display engine interrupt */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f7627759875..8e717c744bb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7464,6 +7464,12 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); + /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */ + I915_WRITE(GEN7_L3CNTLREG1, + GEN7_WA_FOR_GEN7_L3_CONTROL); + I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, + GEN7_WA_L3_CHICKEN_MODE); + for_each_pipe(pipe) I915_WRITE(DSPCNTR(pipe), I915_READ(DSPCNTR(pipe)) | From a80a210c243ce15778d00d93c4726192f5b288ae Mon Sep 17 00:00:00 2001 From: Eugeni Dodonov Date: Wed, 8 Feb 2012 12:53:51 -0800 Subject: [PATCH 1059/4025] drm/i915: gen7: work around a system hang on IVB commit db099c8f963fe656108e0a068274c5580a17f69b upstream. This adds the workaround for WaCatErrorRejectionIssue which could result in a system hang. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=41353 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=44610 Tested-by: Eugeni Dodonov Reviewed-by: Kenneth Graunke Signed-off-by: Eugeni Dodonov Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 4 ++++ drivers/gpu/drm/i915/intel_display.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 73e4a343735..ed679d04bbb 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2854,6 +2854,10 @@ #define GEN7_L3_CHICKEN_MODE_REGISTER 0xB030 #define GEN7_WA_L3_CHICKEN_MODE 0x20000000 +/* WaCatErrorRejectionIssue */ +#define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG 0x9030 +#define GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB (1<<11) + /* PCH */ /* south display engine interrupt */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8e717c744bb..aac61b2849f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7470,6 +7470,11 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE); + /* This is required by WaCatErrorRejectionIssue */ + I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG, + I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) | + GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB); + for_each_pipe(pipe) I915_WRITE(DSPCNTR(pipe), I915_READ(DSPCNTR(pipe)) | From a9941b5ec0105f00a7148d20e320af950dc0a7e9 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Wed, 8 Feb 2012 12:53:52 -0800 Subject: [PATCH 1060/4025] drm/i915: gen7: Disable the RHWO optimization as it can cause GPU hangs. commit d71de14ddf423ccc9a2e3f7e37553c99ead20d7c upstream. The BSpec Workarounds page states that bits 10 and 26 must be set to avoid 3D ring hangs. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=41353 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=44610 Tested-by: Eugeni Dodonov Signed-off-by: Kenneth Graunke Signed-off-by: Jesse Barnes Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_reg.h | 3 +++ drivers/gpu/drm/i915/intel_display.c | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ed679d04bbb..56315cbef1e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2848,6 +2848,9 @@ #define DISP_FBC_WM_DIS (1<<15) /* GEN7 chicken */ +#define GEN7_COMMON_SLICE_CHICKEN1 0x7010 +# define GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC ((1<<10) | (1<<26)) + #define GEN7_L3CNTLREG1 0xB01C #define GEN7_WA_FOR_GEN7_L3_CONTROL 0x3C4FFF8C diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aac61b2849f..57f90437d08 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7464,6 +7464,10 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); + /* Apply the WaDisableRHWOOptimizationForRenderHang workaround. */ + I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1, + GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC); + /* WaApplyL3ControlAndL3ChickenMode requires those two on Ivy Bridge */ I915_WRITE(GEN7_L3CNTLREG1, GEN7_WA_FOR_GEN7_L3_CONTROL); From 90bb7234900ec12f36028c96fdb320a36f08d383 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 8 Feb 2012 15:52:47 +0100 Subject: [PATCH 1061/4025] ARM: orion: Fix USB phy for orion5x. commit 72053353583230952c4b187e110e9da00dfc3afb upstream. The patch "ARM: orion: Consolidate USB platform setup code.", commit 4fcd3f374a928081d391cd9a570afe3b2c692fdc broke USB on TS-7800 and other orion5x boards, because the wrong type of PHY was being passed to the EHCI driver in the platform data. Orion5x needs EHCI_PHY_ORION and all the others want EHCI_PHY_NA. Allow the mach- code to tell the generic plat-orion code which USB PHY enum to place into the platform data. Version 2: Rebase to v3.3-rc2. Reported-by: Ambroz Bizjak Signed-off-by: Andrew Lunn Tested-by: Ambroz Bizjak Acked-by: Nicolas Pitre Signed-off-by: Olof Johansson Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-dove/common.c | 3 ++- arch/arm/mach-kirkwood/common.c | 3 ++- arch/arm/mach-mv78xx0/common.c | 3 ++- arch/arm/mach-orion5x/common.c | 4 +++- arch/arm/plat-orion/common.c | 9 ++++----- arch/arm/plat-orion/include/plat/common.h | 3 ++- 6 files changed, 15 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-dove/common.c b/arch/arm/mach-dove/common.c index cf7e5985eeb..46c04498629 100644 --- a/arch/arm/mach-dove/common.c +++ b/arch/arm/mach-dove/common.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "common.h" @@ -74,7 +75,7 @@ void __init dove_map_io(void) void __init dove_ehci0_init(void) { orion_ehci_init(&dove_mbus_dram_info, - DOVE_USB0_PHYS_BASE, IRQ_DOVE_USB0); + DOVE_USB0_PHYS_BASE, IRQ_DOVE_USB0, EHCI_PHY_NA); } /***************************************************************************** diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c index f3248cfbe51..c5dbbb35e0b 100644 --- a/arch/arm/mach-kirkwood/common.c +++ b/arch/arm/mach-kirkwood/common.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include "common.h" @@ -74,7 +75,7 @@ void __init kirkwood_ehci_init(void) { kirkwood_clk_ctrl |= CGC_USB0; orion_ehci_init(&kirkwood_mbus_dram_info, - USB_PHYS_BASE, IRQ_KIRKWOOD_USB); + USB_PHYS_BASE, IRQ_KIRKWOOD_USB, EHCI_PHY_NA); } diff --git a/arch/arm/mach-mv78xx0/common.c b/arch/arm/mach-mv78xx0/common.c index 23d3980ef59..d90e244e05e 100644 --- a/arch/arm/mach-mv78xx0/common.c +++ b/arch/arm/mach-mv78xx0/common.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -170,7 +171,7 @@ void __init mv78xx0_map_io(void) void __init mv78xx0_ehci0_init(void) { orion_ehci_init(&mv78xx0_mbus_dram_info, - USB0_PHYS_BASE, IRQ_MV78XX0_USB_0); + USB0_PHYS_BASE, IRQ_MV78XX0_USB_0, EHCI_PHY_NA); } diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c index 0ab531d047f..8a98da0b3f8 100644 --- a/arch/arm/mach-orion5x/common.c +++ b/arch/arm/mach-orion5x/common.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include "common.h" @@ -72,7 +73,8 @@ void __init orion5x_map_io(void) void __init orion5x_ehci0_init(void) { orion_ehci_init(&orion5x_mbus_dram_info, - ORION5X_USB0_PHYS_BASE, IRQ_ORION5X_USB0_CTRL); + ORION5X_USB0_PHYS_BASE, IRQ_ORION5X_USB0_CTRL, + EHCI_PHY_ORION); } diff --git a/arch/arm/plat-orion/common.c b/arch/arm/plat-orion/common.c index 9e5451b3c8e..11dce87c248 100644 --- a/arch/arm/plat-orion/common.c +++ b/arch/arm/plat-orion/common.c @@ -806,10 +806,7 @@ void __init orion_xor1_init(unsigned long mapbase_low, /***************************************************************************** * EHCI ****************************************************************************/ -static struct orion_ehci_data orion_ehci_data = { - .phy_version = EHCI_PHY_NA, -}; - +static struct orion_ehci_data orion_ehci_data; static u64 ehci_dmamask = DMA_BIT_MASK(32); @@ -830,9 +827,11 @@ static struct platform_device orion_ehci = { void __init orion_ehci_init(struct mbus_dram_target_info *mbus_dram_info, unsigned long mapbase, - unsigned long irq) + unsigned long irq, + enum orion_ehci_phy_ver phy_version) { orion_ehci_data.dram = mbus_dram_info; + orion_ehci_data.phy_version = phy_version; fill_resources(&orion_ehci, orion_ehci_resources, mapbase, SZ_4K - 1, irq); diff --git a/arch/arm/plat-orion/include/plat/common.h b/arch/arm/plat-orion/include/plat/common.h index a63c357e2ab..a2c0e31ce0d 100644 --- a/arch/arm/plat-orion/include/plat/common.h +++ b/arch/arm/plat-orion/include/plat/common.h @@ -95,7 +95,8 @@ void __init orion_xor1_init(unsigned long mapbase_low, void __init orion_ehci_init(struct mbus_dram_target_info *mbus_dram_info, unsigned long mapbase, - unsigned long irq); + unsigned long irq, + enum orion_ehci_phy_ver phy_version); void __init orion_ehci_1_init(struct mbus_dram_target_info *mbus_dram_info, unsigned long mapbase, From 2d339926c077870a29181d37839920ce3ecd7409 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 8 Feb 2012 15:52:07 +0100 Subject: [PATCH 1062/4025] ARM: orion: Fix Orion5x GPIO regression from MPP cleanup commit b06540371063f0f07aafc1d1ac5e974da85c973c upstream. Patchset "ARM: orion: Refactor the MPP code common in the orion platform" broke at least Orion5x based platforms. These platforms have pins configured as GPIO when the selector is not 0x0. However the common code assumes the selector is always 0x0 for a GPIO lines. It then ignores the GPIO bits in the MPP definitions, resulting in that Orion5x machines cannot correctly configure there GPIO lines. The Fix removes the assumption that the selector is always 0x0. In order that none GPIO configurations are correctly blocked, Kirkwood and mv78xx0 MPP definitions are corrected to only set the GPIO bits for GPIO configurations. This third version, which does not contain any whitespace changes, and is rebased on v3.3-rc2. Signed-off-by: Andrew Lunn Acked-by: Nicolas Pitre Signed-off-by: Olof Johansson --- arch/arm/mach-kirkwood/mpp.h | 320 +++++++++++++++++------------------ arch/arm/mach-mv78xx0/mpp.h | 226 ++++++++++++------------- arch/arm/plat-orion/mpp.c | 3 +- 3 files changed, 274 insertions(+), 275 deletions(-) diff --git a/arch/arm/mach-kirkwood/mpp.h b/arch/arm/mach-kirkwood/mpp.h index ac787957e2d..7afccf47220 100644 --- a/arch/arm/mach-kirkwood/mpp.h +++ b/arch/arm/mach-kirkwood/mpp.h @@ -31,313 +31,313 @@ #define MPP_F6282_MASK MPP( 0, 0x0, 0, 0, 0, 0, 0, 0, 1 ) #define MPP0_GPIO MPP( 0, 0x0, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP0_NF_IO2 MPP( 0, 0x1, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP0_SPI_SCn MPP( 0, 0x2, 0, 1, 1, 1, 1, 1, 1 ) +#define MPP0_NF_IO2 MPP( 0, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP0_SPI_SCn MPP( 0, 0x2, 0, 0, 1, 1, 1, 1, 1 ) #define MPP1_GPO MPP( 1, 0x0, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP1_NF_IO3 MPP( 1, 0x1, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP1_SPI_MOSI MPP( 1, 0x2, 0, 1, 1, 1, 1, 1, 1 ) +#define MPP1_NF_IO3 MPP( 1, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP1_SPI_MOSI MPP( 1, 0x2, 0, 0, 1, 1, 1, 1, 1 ) #define MPP2_GPO MPP( 2, 0x0, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP2_NF_IO4 MPP( 2, 0x1, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP2_SPI_SCK MPP( 2, 0x2, 0, 1, 1, 1, 1, 1, 1 ) +#define MPP2_NF_IO4 MPP( 2, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP2_SPI_SCK MPP( 2, 0x2, 0, 0, 1, 1, 1, 1, 1 ) #define MPP3_GPO MPP( 3, 0x0, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP3_NF_IO5 MPP( 3, 0x1, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP3_SPI_MISO MPP( 3, 0x2, 1, 0, 1, 1, 1, 1, 1 ) +#define MPP3_NF_IO5 MPP( 3, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP3_SPI_MISO MPP( 3, 0x2, 0, 0, 1, 1, 1, 1, 1 ) #define MPP4_GPIO MPP( 4, 0x0, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP4_NF_IO6 MPP( 4, 0x1, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP4_UART0_RXD MPP( 4, 0x2, 1, 0, 1, 1, 1, 1, 1 ) -#define MPP4_SATA1_ACTn MPP( 4, 0x5, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP4_NF_IO6 MPP( 4, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP4_UART0_RXD MPP( 4, 0x2, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP4_SATA1_ACTn MPP( 4, 0x5, 0, 0, 0, 0, 1, 1, 1 ) #define MPP4_LCD_VGA_HSYNC MPP( 4, 0xb, 0, 0, 0, 0, 0, 0, 1 ) -#define MPP4_PTP_CLK MPP( 4, 0xd, 1, 0, 1, 1, 1, 1, 0 ) +#define MPP4_PTP_CLK MPP( 4, 0xd, 0, 0, 1, 1, 1, 1, 0 ) #define MPP5_GPO MPP( 5, 0x0, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP5_NF_IO7 MPP( 5, 0x1, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP5_UART0_TXD MPP( 5, 0x2, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP5_PTP_TRIG_GEN MPP( 5, 0x4, 0, 1, 1, 1, 1, 1, 0 ) -#define MPP5_SATA0_ACTn MPP( 5, 0x5, 0, 1, 0, 1, 1, 1, 1 ) +#define MPP5_NF_IO7 MPP( 5, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP5_UART0_TXD MPP( 5, 0x2, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP5_PTP_TRIG_GEN MPP( 5, 0x4, 0, 0, 1, 1, 1, 1, 0 ) +#define MPP5_SATA0_ACTn MPP( 5, 0x5, 0, 0, 0, 1, 1, 1, 1 ) #define MPP5_LCD_VGA_VSYNC MPP( 5, 0xb, 0, 0, 0, 0, 0, 0, 1 ) -#define MPP6_SYSRST_OUTn MPP( 6, 0x1, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP6_SPI_MOSI MPP( 6, 0x2, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP6_PTP_TRIG_GEN MPP( 6, 0x3, 0, 1, 1, 1, 1, 1, 0 ) +#define MPP6_SYSRST_OUTn MPP( 6, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP6_SPI_MOSI MPP( 6, 0x2, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP6_PTP_TRIG_GEN MPP( 6, 0x3, 0, 0, 1, 1, 1, 1, 0 ) #define MPP7_GPO MPP( 7, 0x0, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP7_PEX_RST_OUTn MPP( 7, 0x1, 0, 1, 1, 1, 1, 1, 0 ) -#define MPP7_SPI_SCn MPP( 7, 0x2, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP7_PTP_TRIG_GEN MPP( 7, 0x3, 0, 1, 1, 1, 1, 1, 0 ) -#define MPP7_LCD_PWM MPP( 7, 0xb, 0, 1, 0, 0, 0, 0, 1 ) +#define MPP7_PEX_RST_OUTn MPP( 7, 0x1, 0, 0, 1, 1, 1, 1, 0 ) +#define MPP7_SPI_SCn MPP( 7, 0x2, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP7_PTP_TRIG_GEN MPP( 7, 0x3, 0, 0, 1, 1, 1, 1, 0 ) +#define MPP7_LCD_PWM MPP( 7, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP8_GPIO MPP( 8, 0x0, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP8_TW0_SDA MPP( 8, 0x1, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP8_UART0_RTS MPP( 8, 0x2, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP8_UART1_RTS MPP( 8, 0x3, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP8_MII0_RXERR MPP( 8, 0x4, 1, 0, 0, 1, 1, 1, 1 ) -#define MPP8_SATA1_PRESENTn MPP( 8, 0x5, 0, 1, 0, 0, 1, 1, 1 ) -#define MPP8_PTP_CLK MPP( 8, 0xc, 1, 0, 1, 1, 1, 1, 0 ) -#define MPP8_MII0_COL MPP( 8, 0xd, 1, 0, 1, 1, 1, 1, 1 ) +#define MPP8_TW0_SDA MPP( 8, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP8_UART0_RTS MPP( 8, 0x2, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP8_UART1_RTS MPP( 8, 0x3, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP8_MII0_RXERR MPP( 8, 0x4, 0, 0, 0, 1, 1, 1, 1 ) +#define MPP8_SATA1_PRESENTn MPP( 8, 0x5, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP8_PTP_CLK MPP( 8, 0xc, 0, 0, 1, 1, 1, 1, 0 ) +#define MPP8_MII0_COL MPP( 8, 0xd, 0, 0, 1, 1, 1, 1, 1 ) #define MPP9_GPIO MPP( 9, 0x0, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP9_TW0_SCK MPP( 9, 0x1, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP9_UART0_CTS MPP( 9, 0x2, 1, 0, 1, 1, 1, 1, 1 ) -#define MPP9_UART1_CTS MPP( 9, 0x3, 1, 0, 1, 1, 1, 1, 1 ) -#define MPP9_SATA0_PRESENTn MPP( 9, 0x5, 0, 1, 0, 1, 1, 1, 1 ) -#define MPP9_PTP_EVENT_REQ MPP( 9, 0xc, 1, 0, 1, 1, 1, 1, 0 ) -#define MPP9_MII0_CRS MPP( 9, 0xd, 1, 0, 1, 1, 1, 1, 1 ) +#define MPP9_TW0_SCK MPP( 9, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP9_UART0_CTS MPP( 9, 0x2, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP9_UART1_CTS MPP( 9, 0x3, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP9_SATA0_PRESENTn MPP( 9, 0x5, 0, 0, 0, 1, 1, 1, 1 ) +#define MPP9_PTP_EVENT_REQ MPP( 9, 0xc, 0, 0, 1, 1, 1, 1, 0 ) +#define MPP9_MII0_CRS MPP( 9, 0xd, 0, 0, 1, 1, 1, 1, 1 ) #define MPP10_GPO MPP( 10, 0x0, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP10_SPI_SCK MPP( 10, 0x2, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP10_UART0_TXD MPP( 10, 0X3, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP10_SATA1_ACTn MPP( 10, 0x5, 0, 1, 0, 0, 1, 1, 1 ) -#define MPP10_PTP_TRIG_GEN MPP( 10, 0xc, 0, 1, 1, 1, 1, 1, 0 ) +#define MPP10_SPI_SCK MPP( 10, 0x2, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP10_UART0_TXD MPP( 10, 0X3, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP10_SATA1_ACTn MPP( 10, 0x5, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP10_PTP_TRIG_GEN MPP( 10, 0xc, 0, 0, 1, 1, 1, 1, 0 ) #define MPP11_GPIO MPP( 11, 0x0, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP11_SPI_MISO MPP( 11, 0x2, 1, 0, 1, 1, 1, 1, 1 ) -#define MPP11_UART0_RXD MPP( 11, 0x3, 1, 0, 1, 1, 1, 1, 1 ) -#define MPP11_PTP_EVENT_REQ MPP( 11, 0x4, 1, 0, 1, 1, 1, 1, 0 ) -#define MPP11_PTP_TRIG_GEN MPP( 11, 0xc, 0, 1, 1, 1, 1, 1, 0 ) -#define MPP11_PTP_CLK MPP( 11, 0xd, 1, 0, 1, 1, 1, 1, 0 ) -#define MPP11_SATA0_ACTn MPP( 11, 0x5, 0, 1, 0, 1, 1, 1, 1 ) +#define MPP11_SPI_MISO MPP( 11, 0x2, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP11_UART0_RXD MPP( 11, 0x3, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP11_PTP_EVENT_REQ MPP( 11, 0x4, 0, 0, 1, 1, 1, 1, 0 ) +#define MPP11_PTP_TRIG_GEN MPP( 11, 0xc, 0, 0, 1, 1, 1, 1, 0 ) +#define MPP11_PTP_CLK MPP( 11, 0xd, 0, 0, 1, 1, 1, 1, 0 ) +#define MPP11_SATA0_ACTn MPP( 11, 0x5, 0, 0, 0, 1, 1, 1, 1 ) #define MPP12_GPO MPP( 12, 0x0, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP12_SD_CLK MPP( 12, 0x1, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP12_AU_SPDIF0 MPP( 12, 0xa, 0, 1, 0, 0, 0, 0, 1 ) -#define MPP12_SPI_MOSI MPP( 12, 0xb, 0, 1, 0, 0, 0, 0, 1 ) -#define MPP12_TW1_SDA MPP( 12, 0xd, 1, 0, 0, 0, 0, 0, 1 ) +#define MPP12_SD_CLK MPP( 12, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP12_AU_SPDIF0 MPP( 12, 0xa, 0, 0, 0, 0, 0, 0, 1 ) +#define MPP12_SPI_MOSI MPP( 12, 0xb, 0, 0, 0, 0, 0, 0, 1 ) +#define MPP12_TW1_SDA MPP( 12, 0xd, 0, 0, 0, 0, 0, 0, 1 ) #define MPP13_GPIO MPP( 13, 0x0, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP13_SD_CMD MPP( 13, 0x1, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP13_UART1_TXD MPP( 13, 0x3, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP13_AU_SPDIFRMCLK MPP( 13, 0xa, 0, 1, 0, 0, 0, 0, 1 ) -#define MPP13_LCDPWM MPP( 13, 0xb, 0, 1, 0, 0, 0, 0, 1 ) +#define MPP13_SD_CMD MPP( 13, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP13_UART1_TXD MPP( 13, 0x3, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP13_AU_SPDIFRMCLK MPP( 13, 0xa, 0, 0, 0, 0, 0, 0, 1 ) +#define MPP13_LCDPWM MPP( 13, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP14_GPIO MPP( 14, 0x0, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP14_SD_D0 MPP( 14, 0x1, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP14_UART1_RXD MPP( 14, 0x3, 1, 0, 1, 1, 1, 1, 1 ) -#define MPP14_SATA1_PRESENTn MPP( 14, 0x4, 0, 1, 0, 0, 1, 1, 1 ) -#define MPP14_AU_SPDIFI MPP( 14, 0xa, 1, 0, 0, 0, 0, 0, 1 ) -#define MPP14_AU_I2SDI MPP( 14, 0xb, 1, 0, 0, 0, 0, 0, 1 ) -#define MPP14_MII0_COL MPP( 14, 0xd, 1, 0, 1, 1, 1, 1, 1 ) +#define MPP14_SD_D0 MPP( 14, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP14_UART1_RXD MPP( 14, 0x3, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP14_SATA1_PRESENTn MPP( 14, 0x4, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP14_AU_SPDIFI MPP( 14, 0xa, 0, 0, 0, 0, 0, 0, 1 ) +#define MPP14_AU_I2SDI MPP( 14, 0xb, 0, 0, 0, 0, 0, 0, 1 ) +#define MPP14_MII0_COL MPP( 14, 0xd, 0, 0, 1, 1, 1, 1, 1 ) #define MPP15_GPIO MPP( 15, 0x0, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP15_SD_D1 MPP( 15, 0x1, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP15_UART0_RTS MPP( 15, 0x2, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP15_UART1_TXD MPP( 15, 0x3, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP15_SATA0_ACTn MPP( 15, 0x4, 0, 1, 0, 1, 1, 1, 1 ) -#define MPP15_SPI_CSn MPP( 15, 0xb, 0, 1, 0, 0, 0, 0, 1 ) +#define MPP15_SD_D1 MPP( 15, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP15_UART0_RTS MPP( 15, 0x2, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP15_UART1_TXD MPP( 15, 0x3, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP15_SATA0_ACTn MPP( 15, 0x4, 0, 0, 0, 1, 1, 1, 1 ) +#define MPP15_SPI_CSn MPP( 15, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP16_GPIO MPP( 16, 0x0, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP16_SD_D2 MPP( 16, 0x1, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP16_UART0_CTS MPP( 16, 0x2, 1, 0, 1, 1, 1, 1, 1 ) -#define MPP16_UART1_RXD MPP( 16, 0x3, 1, 0, 1, 1, 1, 1, 1 ) -#define MPP16_SATA1_ACTn MPP( 16, 0x4, 0, 1, 0, 0, 1, 1, 1 ) -#define MPP16_LCD_EXT_REF_CLK MPP( 16, 0xb, 1, 0, 0, 0, 0, 0, 1 ) -#define MPP16_MII0_CRS MPP( 16, 0xd, 1, 0, 1, 1, 1, 1, 1 ) +#define MPP16_SD_D2 MPP( 16, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP16_UART0_CTS MPP( 16, 0x2, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP16_UART1_RXD MPP( 16, 0x3, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP16_SATA1_ACTn MPP( 16, 0x4, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP16_LCD_EXT_REF_CLK MPP( 16, 0xb, 0, 0, 0, 0, 0, 0, 1 ) +#define MPP16_MII0_CRS MPP( 16, 0xd, 0, 0, 1, 1, 1, 1, 1 ) #define MPP17_GPIO MPP( 17, 0x0, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP17_SD_D3 MPP( 17, 0x1, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP17_SATA0_PRESENTn MPP( 17, 0x4, 0, 1, 0, 1, 1, 1, 1 ) -#define MPP17_SATA1_ACTn MPP( 17, 0xa, 0, 1, 0, 0, 0, 0, 1 ) -#define MPP17_TW1_SCK MPP( 17, 0xd, 1, 1, 0, 0, 0, 0, 1 ) +#define MPP17_SD_D3 MPP( 17, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP17_SATA0_PRESENTn MPP( 17, 0x4, 0, 0, 0, 1, 1, 1, 1 ) +#define MPP17_SATA1_ACTn MPP( 17, 0xa, 0, 0, 0, 0, 0, 0, 1 ) +#define MPP17_TW1_SCK MPP( 17, 0xd, 0, 0, 0, 0, 0, 0, 1 ) #define MPP18_GPO MPP( 18, 0x0, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP18_NF_IO0 MPP( 18, 0x1, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP18_PEX0_CLKREQ MPP( 18, 0x2, 0, 1, 0, 0, 0, 0, 1 ) +#define MPP18_NF_IO0 MPP( 18, 0x1, 0, 0, 1, 1, 1, 1, 1 ) +#define MPP18_PEX0_CLKREQ MPP( 18, 0x2, 0, 0, 0, 0, 0, 0, 1 ) #define MPP19_GPO MPP( 19, 0x0, 0, 1, 1, 1, 1, 1, 1 ) -#define MPP19_NF_IO1 MPP( 19, 0x1, 1, 1, 1, 1, 1, 1, 1 ) +#define MPP19_NF_IO1 MPP( 19, 0x1, 0, 0, 1, 1, 1, 1, 1 ) #define MPP20_GPIO MPP( 20, 0x0, 1, 1, 0, 1, 1, 1, 1 ) -#define MPP20_TSMP0 MPP( 20, 0x1, 1, 1, 0, 0, 1, 1, 1 ) -#define MPP20_TDM_CH0_TX_QL MPP( 20, 0x2, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP20_TSMP0 MPP( 20, 0x1, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP20_TDM_CH0_TX_QL MPP( 20, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP20_GE1_TXD0 MPP( 20, 0x3, 0, 0, 0, 1, 1, 1, 1 ) -#define MPP20_AU_SPDIFI MPP( 20, 0x4, 1, 0, 0, 0, 1, 1, 1 ) -#define MPP20_SATA1_ACTn MPP( 20, 0x5, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP20_AU_SPDIFI MPP( 20, 0x4, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP20_SATA1_ACTn MPP( 20, 0x5, 0, 0, 0, 0, 1, 1, 1 ) #define MPP20_LCD_D0 MPP( 20, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP21_GPIO MPP( 21, 0x0, 1, 1, 0, 1, 1, 1, 1 ) -#define MPP21_TSMP1 MPP( 21, 0x1, 1, 1, 0, 0, 1, 1, 1 ) -#define MPP21_TDM_CH0_RX_QL MPP( 21, 0x2, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP21_TSMP1 MPP( 21, 0x1, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP21_TDM_CH0_RX_QL MPP( 21, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP21_GE1_TXD1 MPP( 21, 0x3, 0, 0, 0, 1, 1, 1, 1 ) -#define MPP21_AU_SPDIFO MPP( 21, 0x4, 0, 1, 0, 0, 1, 1, 1 ) -#define MPP21_SATA0_ACTn MPP( 21, 0x5, 0, 1, 0, 1, 1, 1, 1 ) +#define MPP21_AU_SPDIFO MPP( 21, 0x4, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP21_SATA0_ACTn MPP( 21, 0x5, 0, 0, 0, 1, 1, 1, 1 ) #define MPP21_LCD_D1 MPP( 21, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP22_GPIO MPP( 22, 0x0, 1, 1, 0, 1, 1, 1, 1 ) -#define MPP22_TSMP2 MPP( 22, 0x1, 1, 1, 0, 0, 1, 1, 1 ) -#define MPP22_TDM_CH2_TX_QL MPP( 22, 0x2, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP22_TSMP2 MPP( 22, 0x1, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP22_TDM_CH2_TX_QL MPP( 22, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP22_GE1_TXD2 MPP( 22, 0x3, 0, 0, 0, 1, 1, 1, 1 ) -#define MPP22_AU_SPDIFRMKCLK MPP( 22, 0x4, 0, 1, 0, 0, 1, 1, 1 ) -#define MPP22_SATA1_PRESENTn MPP( 22, 0x5, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP22_AU_SPDIFRMKCLK MPP( 22, 0x4, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP22_SATA1_PRESENTn MPP( 22, 0x5, 0, 0, 0, 0, 1, 1, 1 ) #define MPP22_LCD_D2 MPP( 22, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP23_GPIO MPP( 23, 0x0, 1, 1, 0, 1, 1, 1, 1 ) -#define MPP23_TSMP3 MPP( 23, 0x1, 1, 1, 0, 0, 1, 1, 1 ) -#define MPP23_TDM_CH2_RX_QL MPP( 23, 0x2, 1, 0, 0, 0, 1, 1, 1 ) +#define MPP23_TSMP3 MPP( 23, 0x1, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP23_TDM_CH2_RX_QL MPP( 23, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP23_GE1_TXD3 MPP( 23, 0x3, 0, 0, 0, 1, 1, 1, 1 ) -#define MPP23_AU_I2SBCLK MPP( 23, 0x4, 0, 1, 0, 0, 1, 1, 1 ) -#define MPP23_SATA0_PRESENTn MPP( 23, 0x5, 0, 1, 0, 1, 1, 1, 1 ) +#define MPP23_AU_I2SBCLK MPP( 23, 0x4, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP23_SATA0_PRESENTn MPP( 23, 0x5, 0, 0, 0, 1, 1, 1, 1 ) #define MPP23_LCD_D3 MPP( 23, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP24_GPIO MPP( 24, 0x0, 1, 1, 0, 1, 1, 1, 1 ) -#define MPP24_TSMP4 MPP( 24, 0x1, 1, 1, 0, 0, 1, 1, 1 ) -#define MPP24_TDM_SPI_CS0 MPP( 24, 0x2, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP24_TSMP4 MPP( 24, 0x1, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP24_TDM_SPI_CS0 MPP( 24, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP24_GE1_RXD0 MPP( 24, 0x3, 0, 0, 0, 1, 1, 1, 1 ) -#define MPP24_AU_I2SDO MPP( 24, 0x4, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP24_AU_I2SDO MPP( 24, 0x4, 0, 0, 0, 0, 1, 1, 1 ) #define MPP24_LCD_D4 MPP( 24, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP25_GPIO MPP( 25, 0x0, 1, 1, 0, 1, 1, 1, 1 ) -#define MPP25_TSMP5 MPP( 25, 0x1, 1, 1, 0, 0, 1, 1, 1 ) -#define MPP25_TDM_SPI_SCK MPP( 25, 0x2, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP25_TSMP5 MPP( 25, 0x1, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP25_TDM_SPI_SCK MPP( 25, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP25_GE1_RXD1 MPP( 25, 0x3, 0, 0, 0, 1, 1, 1, 1 ) -#define MPP25_AU_I2SLRCLK MPP( 25, 0x4, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP25_AU_I2SLRCLK MPP( 25, 0x4, 0, 0, 0, 0, 1, 1, 1 ) #define MPP25_LCD_D5 MPP( 25, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP26_GPIO MPP( 26, 0x0, 1, 1, 0, 1, 1, 1, 1 ) -#define MPP26_TSMP6 MPP( 26, 0x1, 1, 1, 0, 0, 1, 1, 1 ) -#define MPP26_TDM_SPI_MISO MPP( 26, 0x2, 1, 0, 0, 0, 1, 1, 1 ) +#define MPP26_TSMP6 MPP( 26, 0x1, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP26_TDM_SPI_MISO MPP( 26, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP26_GE1_RXD2 MPP( 26, 0x3, 0, 0, 0, 1, 1, 1, 1 ) -#define MPP26_AU_I2SMCLK MPP( 26, 0x4, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP26_AU_I2SMCLK MPP( 26, 0x4, 0, 0, 0, 0, 1, 1, 1 ) #define MPP26_LCD_D6 MPP( 26, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP27_GPIO MPP( 27, 0x0, 1, 1, 0, 1, 1, 1, 1 ) -#define MPP27_TSMP7 MPP( 27, 0x1, 1, 1, 0, 0, 1, 1, 1 ) -#define MPP27_TDM_SPI_MOSI MPP( 27, 0x2, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP27_TSMP7 MPP( 27, 0x1, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP27_TDM_SPI_MOSI MPP( 27, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP27_GE1_RXD3 MPP( 27, 0x3, 0, 0, 0, 1, 1, 1, 1 ) -#define MPP27_AU_I2SDI MPP( 27, 0x4, 1, 0, 0, 0, 1, 1, 1 ) +#define MPP27_AU_I2SDI MPP( 27, 0x4, 0, 0, 0, 0, 1, 1, 1 ) #define MPP27_LCD_D7 MPP( 27, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP28_GPIO MPP( 28, 0x0, 1, 1, 0, 1, 1, 1, 1 ) -#define MPP28_TSMP8 MPP( 28, 0x1, 1, 1, 0, 0, 1, 1, 1 ) +#define MPP28_TSMP8 MPP( 28, 0x1, 0, 0, 0, 0, 1, 1, 1 ) #define MPP28_TDM_CODEC_INTn MPP( 28, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP28_GE1_COL MPP( 28, 0x3, 0, 0, 0, 1, 1, 1, 1 ) -#define MPP28_AU_EXTCLK MPP( 28, 0x4, 1, 0, 0, 0, 1, 1, 1 ) +#define MPP28_AU_EXTCLK MPP( 28, 0x4, 0, 0, 0, 0, 1, 1, 1 ) #define MPP28_LCD_D8 MPP( 28, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP29_GPIO MPP( 29, 0x0, 1, 1, 0, 1, 1, 1, 1 ) -#define MPP29_TSMP9 MPP( 29, 0x1, 1, 1, 0, 0, 1, 1, 1 ) +#define MPP29_TSMP9 MPP( 29, 0x1, 0, 0, 0, 0, 1, 1, 1 ) #define MPP29_TDM_CODEC_RSTn MPP( 29, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP29_GE1_TCLK MPP( 29, 0x3, 0, 0, 0, 1, 1, 1, 1 ) #define MPP29_LCD_D9 MPP( 29, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP30_GPIO MPP( 30, 0x0, 1, 1, 0, 1, 1, 1, 1 ) -#define MPP30_TSMP10 MPP( 30, 0x1, 1, 1, 0, 0, 1, 1, 1 ) -#define MPP30_TDM_PCLK MPP( 30, 0x2, 1, 1, 0, 0, 1, 1, 1 ) +#define MPP30_TSMP10 MPP( 30, 0x1, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP30_TDM_PCLK MPP( 30, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP30_GE1_RXCTL MPP( 30, 0x3, 0, 0, 0, 1, 1, 1, 1 ) #define MPP30_LCD_D10 MPP( 30, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP31_GPIO MPP( 31, 0x0, 1, 1, 0, 1, 1, 1, 1 ) -#define MPP31_TSMP11 MPP( 31, 0x1, 1, 1, 0, 0, 1, 1, 1 ) -#define MPP31_TDM_FS MPP( 31, 0x2, 1, 1, 0, 0, 1, 1, 1 ) +#define MPP31_TSMP11 MPP( 31, 0x1, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP31_TDM_FS MPP( 31, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP31_GE1_RXCLK MPP( 31, 0x3, 0, 0, 0, 1, 1, 1, 1 ) #define MPP31_LCD_D11 MPP( 31, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP32_GPIO MPP( 32, 0x0, 1, 1, 0, 1, 1, 1, 1 ) -#define MPP32_TSMP12 MPP( 32, 0x1, 1, 1, 0, 0, 1, 1, 1 ) -#define MPP32_TDM_DRX MPP( 32, 0x2, 1, 0, 0, 0, 1, 1, 1 ) +#define MPP32_TSMP12 MPP( 32, 0x1, 0, 0, 0, 0, 1, 1, 1 ) +#define MPP32_TDM_DRX MPP( 32, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP32_GE1_TCLKOUT MPP( 32, 0x3, 0, 0, 0, 1, 1, 1, 1 ) #define MPP32_LCD_D12 MPP( 32, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP33_GPO MPP( 33, 0x0, 0, 1, 0, 1, 1, 1, 1 ) -#define MPP33_TDM_DTX MPP( 33, 0x2, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP33_TDM_DTX MPP( 33, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP33_GE1_TXCTL MPP( 33, 0x3, 0, 0, 0, 1, 1, 1, 1 ) #define MPP33_LCD_D13 MPP( 33, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP34_GPIO MPP( 34, 0x0, 1, 1, 0, 1, 1, 1, 1 ) -#define MPP34_TDM_SPI_CS1 MPP( 34, 0x2, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP34_TDM_SPI_CS1 MPP( 34, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP34_GE1_TXEN MPP( 34, 0x3, 0, 0, 0, 1, 1, 1, 1 ) -#define MPP34_SATA1_ACTn MPP( 34, 0x5, 0, 1, 0, 0, 0, 1, 1 ) +#define MPP34_SATA1_ACTn MPP( 34, 0x5, 0, 0, 0, 0, 0, 1, 1 ) #define MPP34_LCD_D14 MPP( 34, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP35_GPIO MPP( 35, 0x0, 1, 1, 1, 1, 1, 1, 1 ) -#define MPP35_TDM_CH0_TX_QL MPP( 35, 0x2, 0, 1, 0, 0, 1, 1, 1 ) +#define MPP35_TDM_CH0_TX_QL MPP( 35, 0x2, 0, 0, 0, 0, 1, 1, 1 ) #define MPP35_GE1_RXERR MPP( 35, 0x3, 0, 0, 0, 1, 1, 1, 1 ) -#define MPP35_SATA0_ACTn MPP( 35, 0x5, 0, 1, 0, 1, 1, 1, 1 ) +#define MPP35_SATA0_ACTn MPP( 35, 0x5, 0, 0, 0, 1, 1, 1, 1 ) #define MPP35_LCD_D15 MPP( 22, 0xb, 0, 0, 0, 0, 0, 0, 1 ) -#define MPP35_MII0_RXERR MPP( 35, 0xc, 1, 0, 1, 1, 1, 1, 1 ) +#define MPP35_MII0_RXERR MPP( 35, 0xc, 0, 0, 1, 1, 1, 1, 1 ) #define MPP36_GPIO MPP( 36, 0x0, 1, 1, 1, 0, 0, 1, 1 ) -#define MPP36_TSMP0 MPP( 36, 0x1, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP36_TDM_SPI_CS1 MPP( 36, 0x2, 0, 1, 0, 0, 0, 1, 1 ) -#define MPP36_AU_SPDIFI MPP( 36, 0x4, 1, 0, 1, 0, 0, 1, 1 ) -#define MPP36_TW1_SDA MPP( 36, 0xb, 1, 1, 0, 0, 0, 0, 1 ) +#define MPP36_TSMP0 MPP( 36, 0x1, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP36_TDM_SPI_CS1 MPP( 36, 0x2, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP36_AU_SPDIFI MPP( 36, 0x4, 0, 0, 1, 0, 0, 1, 1 ) +#define MPP36_TW1_SDA MPP( 36, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP37_GPIO MPP( 37, 0x0, 1, 1, 1, 0, 0, 1, 1 ) -#define MPP37_TSMP1 MPP( 37, 0x1, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP37_TDM_CH2_TX_QL MPP( 37, 0x2, 0, 1, 0, 0, 0, 1, 1 ) -#define MPP37_AU_SPDIFO MPP( 37, 0x4, 0, 1, 1, 0, 0, 1, 1 ) -#define MPP37_TW1_SCK MPP( 37, 0xb, 1, 1, 0, 0, 0, 0, 1 ) +#define MPP37_TSMP1 MPP( 37, 0x1, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP37_TDM_CH2_TX_QL MPP( 37, 0x2, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP37_AU_SPDIFO MPP( 37, 0x4, 0, 0, 1, 0, 0, 1, 1 ) +#define MPP37_TW1_SCK MPP( 37, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP38_GPIO MPP( 38, 0x0, 1, 1, 1, 0, 0, 1, 1 ) -#define MPP38_TSMP2 MPP( 38, 0x1, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP38_TDM_CH2_RX_QL MPP( 38, 0x2, 0, 1, 0, 0, 0, 1, 1 ) -#define MPP38_AU_SPDIFRMLCLK MPP( 38, 0x4, 0, 1, 1, 0, 0, 1, 1 ) +#define MPP38_TSMP2 MPP( 38, 0x1, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP38_TDM_CH2_RX_QL MPP( 38, 0x2, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP38_AU_SPDIFRMLCLK MPP( 38, 0x4, 0, 0, 1, 0, 0, 1, 1 ) #define MPP38_LCD_D18 MPP( 38, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP39_GPIO MPP( 39, 0x0, 1, 1, 1, 0, 0, 1, 1 ) -#define MPP39_TSMP3 MPP( 39, 0x1, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP39_TDM_SPI_CS0 MPP( 39, 0x2, 0, 1, 0, 0, 0, 1, 1 ) -#define MPP39_AU_I2SBCLK MPP( 39, 0x4, 0, 1, 1, 0, 0, 1, 1 ) +#define MPP39_TSMP3 MPP( 39, 0x1, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP39_TDM_SPI_CS0 MPP( 39, 0x2, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP39_AU_I2SBCLK MPP( 39, 0x4, 0, 0, 1, 0, 0, 1, 1 ) #define MPP39_LCD_D19 MPP( 39, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP40_GPIO MPP( 40, 0x0, 1, 1, 1, 0, 0, 1, 1 ) -#define MPP40_TSMP4 MPP( 40, 0x1, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP40_TDM_SPI_SCK MPP( 40, 0x2, 0, 1, 0, 0, 0, 1, 1 ) -#define MPP40_AU_I2SDO MPP( 40, 0x4, 0, 1, 1, 0, 0, 1, 1 ) +#define MPP40_TSMP4 MPP( 40, 0x1, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP40_TDM_SPI_SCK MPP( 40, 0x2, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP40_AU_I2SDO MPP( 40, 0x4, 0, 0, 1, 0, 0, 1, 1 ) #define MPP40_LCD_D20 MPP( 40, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP41_GPIO MPP( 41, 0x0, 1, 1, 1, 0, 0, 1, 1 ) -#define MPP41_TSMP5 MPP( 41, 0x1, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP41_TDM_SPI_MISO MPP( 41, 0x2, 1, 0, 0, 0, 0, 1, 1 ) -#define MPP41_AU_I2SLRCLK MPP( 41, 0x4, 0, 1, 1, 0, 0, 1, 1 ) +#define MPP41_TSMP5 MPP( 41, 0x1, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP41_TDM_SPI_MISO MPP( 41, 0x2, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP41_AU_I2SLRCLK MPP( 41, 0x4, 0, 0, 1, 0, 0, 1, 1 ) #define MPP41_LCD_D21 MPP( 41, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP42_GPIO MPP( 42, 0x0, 1, 1, 1, 0, 0, 1, 1 ) -#define MPP42_TSMP6 MPP( 42, 0x1, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP42_TDM_SPI_MOSI MPP( 42, 0x2, 0, 1, 0, 0, 0, 1, 1 ) -#define MPP42_AU_I2SMCLK MPP( 42, 0x4, 0, 1, 1, 0, 0, 1, 1 ) +#define MPP42_TSMP6 MPP( 42, 0x1, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP42_TDM_SPI_MOSI MPP( 42, 0x2, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP42_AU_I2SMCLK MPP( 42, 0x4, 0, 0, 1, 0, 0, 1, 1 ) #define MPP42_LCD_D22 MPP( 42, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP43_GPIO MPP( 43, 0x0, 1, 1, 1, 0, 0, 1, 1 ) -#define MPP43_TSMP7 MPP( 43, 0x1, 1, 1, 0, 0, 0, 1, 1 ) +#define MPP43_TSMP7 MPP( 43, 0x1, 0, 0, 0, 0, 0, 1, 1 ) #define MPP43_TDM_CODEC_INTn MPP( 43, 0x2, 0, 0, 0, 0, 0, 1, 1 ) -#define MPP43_AU_I2SDI MPP( 43, 0x4, 1, 0, 1, 0, 0, 1, 1 ) +#define MPP43_AU_I2SDI MPP( 43, 0x4, 0, 0, 1, 0, 0, 1, 1 ) #define MPP43_LCD_D23 MPP( 22, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP44_GPIO MPP( 44, 0x0, 1, 1, 1, 0, 0, 1, 1 ) -#define MPP44_TSMP8 MPP( 44, 0x1, 1, 1, 0, 0, 0, 1, 1 ) +#define MPP44_TSMP8 MPP( 44, 0x1, 0, 0, 0, 0, 0, 1, 1 ) #define MPP44_TDM_CODEC_RSTn MPP( 44, 0x2, 0, 0, 0, 0, 0, 1, 1 ) -#define MPP44_AU_EXTCLK MPP( 44, 0x4, 1, 0, 1, 0, 0, 1, 1 ) +#define MPP44_AU_EXTCLK MPP( 44, 0x4, 0, 0, 1, 0, 0, 1, 1 ) #define MPP44_LCD_CLK MPP( 44, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP45_GPIO MPP( 45, 0x0, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP45_TSMP9 MPP( 45, 0x1, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP45_TDM_PCLK MPP( 45, 0x2, 1, 1, 0, 0, 0, 1, 1 ) +#define MPP45_TSMP9 MPP( 45, 0x1, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP45_TDM_PCLK MPP( 45, 0x2, 0, 0, 0, 0, 0, 1, 1 ) #define MPP245_LCD_E MPP( 45, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP46_GPIO MPP( 46, 0x0, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP46_TSMP10 MPP( 46, 0x1, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP46_TDM_FS MPP( 46, 0x2, 1, 1, 0, 0, 0, 1, 1 ) +#define MPP46_TSMP10 MPP( 46, 0x1, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP46_TDM_FS MPP( 46, 0x2, 0, 0, 0, 0, 0, 1, 1 ) #define MPP46_LCD_HSYNC MPP( 46, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP47_GPIO MPP( 47, 0x0, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP47_TSMP11 MPP( 47, 0x1, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP47_TDM_DRX MPP( 47, 0x2, 1, 0, 0, 0, 0, 1, 1 ) +#define MPP47_TSMP11 MPP( 47, 0x1, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP47_TDM_DRX MPP( 47, 0x2, 0, 0, 0, 0, 0, 1, 1 ) #define MPP47_LCD_VSYNC MPP( 47, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP48_GPIO MPP( 48, 0x0, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP48_TSMP12 MPP( 48, 0x1, 1, 1, 0, 0, 0, 1, 1 ) -#define MPP48_TDM_DTX MPP( 48, 0x2, 0, 1, 0, 0, 0, 1, 1 ) +#define MPP48_TSMP12 MPP( 48, 0x1, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP48_TDM_DTX MPP( 48, 0x2, 0, 0, 0, 0, 0, 1, 1 ) #define MPP48_LCD_D16 MPP( 22, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP49_GPIO MPP( 49, 0x0, 1, 1, 0, 0, 0, 1, 0 ) #define MPP49_GPO MPP( 49, 0x0, 0, 1, 0, 0, 0, 0, 1 ) -#define MPP49_TSMP9 MPP( 49, 0x1, 1, 1, 0, 0, 0, 1, 0 ) -#define MPP49_TDM_CH0_RX_QL MPP( 49, 0x2, 0, 1, 0, 0, 0, 1, 1 ) -#define MPP49_PTP_CLK MPP( 49, 0x5, 1, 0, 0, 0, 0, 1, 0 ) -#define MPP49_PEX0_CLKREQ MPP( 49, 0xa, 0, 1, 0, 0, 0, 0, 1 ) +#define MPP49_TSMP9 MPP( 49, 0x1, 0, 0, 0, 0, 0, 1, 0 ) +#define MPP49_TDM_CH0_RX_QL MPP( 49, 0x2, 0, 0, 0, 0, 0, 1, 1 ) +#define MPP49_PTP_CLK MPP( 49, 0x5, 0, 0, 0, 0, 0, 1, 0 ) +#define MPP49_PEX0_CLKREQ MPP( 49, 0xa, 0, 0, 0, 0, 0, 0, 1 ) #define MPP49_LCD_D17 MPP( 49, 0xb, 0, 0, 0, 0, 0, 0, 1 ) #define MPP_MAX 49 diff --git a/arch/arm/mach-mv78xx0/mpp.h b/arch/arm/mach-mv78xx0/mpp.h index b61b5092712..3752302ae2e 100644 --- a/arch/arm/mach-mv78xx0/mpp.h +++ b/arch/arm/mach-mv78xx0/mpp.h @@ -24,296 +24,296 @@ #define MPP_78100_A0_MASK MPP(0, 0x0, 0, 0, 1) #define MPP0_GPIO MPP(0, 0x0, 1, 1, 1) -#define MPP0_GE0_COL MPP(0, 0x1, 1, 0, 1) -#define MPP0_GE1_TXCLK MPP(0, 0x2, 0, 1, 1) +#define MPP0_GE0_COL MPP(0, 0x1, 0, 0, 1) +#define MPP0_GE1_TXCLK MPP(0, 0x2, 0, 0, 1) #define MPP0_UNUSED MPP(0, 0x3, 0, 0, 1) #define MPP1_GPIO MPP(1, 0x0, 1, 1, 1) -#define MPP1_GE0_RXERR MPP(1, 0x1, 1, 0, 1) -#define MPP1_GE1_TXCTL MPP(1, 0x2, 0, 1, 1) +#define MPP1_GE0_RXERR MPP(1, 0x1, 0, 0, 1) +#define MPP1_GE1_TXCTL MPP(1, 0x2, 0, 0, 1) #define MPP1_UNUSED MPP(1, 0x3, 0, 0, 1) #define MPP2_GPIO MPP(2, 0x0, 1, 1, 1) -#define MPP2_GE0_CRS MPP(2, 0x1, 1, 0, 1) -#define MPP2_GE1_RXCTL MPP(2, 0x2, 1, 0, 1) +#define MPP2_GE0_CRS MPP(2, 0x1, 0, 0, 1) +#define MPP2_GE1_RXCTL MPP(2, 0x2, 0, 0, 1) #define MPP2_UNUSED MPP(2, 0x3, 0, 0, 1) #define MPP3_GPIO MPP(3, 0x0, 1, 1, 1) -#define MPP3_GE0_TXERR MPP(3, 0x1, 0, 1, 1) -#define MPP3_GE1_RXCLK MPP(3, 0x2, 1, 0, 1) +#define MPP3_GE0_TXERR MPP(3, 0x1, 0, 0, 1) +#define MPP3_GE1_RXCLK MPP(3, 0x2, 0, 0, 1) #define MPP3_UNUSED MPP(3, 0x3, 0, 0, 1) #define MPP4_GPIO MPP(4, 0x0, 1, 1, 1) -#define MPP4_GE0_TXD4 MPP(4, 0x1, 0, 1, 1) -#define MPP4_GE1_TXD0 MPP(4, 0x2, 0, 1, 1) +#define MPP4_GE0_TXD4 MPP(4, 0x1, 0, 0, 1) +#define MPP4_GE1_TXD0 MPP(4, 0x2, 0, 0, 1) #define MPP4_UNUSED MPP(4, 0x3, 0, 0, 1) #define MPP5_GPIO MPP(5, 0x0, 1, 1, 1) -#define MPP5_GE0_TXD5 MPP(5, 0x1, 0, 1, 1) -#define MPP5_GE1_TXD1 MPP(5, 0x2, 0, 1, 1) +#define MPP5_GE0_TXD5 MPP(5, 0x1, 0, 0, 1) +#define MPP5_GE1_TXD1 MPP(5, 0x2, 0, 0, 1) #define MPP5_UNUSED MPP(5, 0x3, 0, 0, 1) #define MPP6_GPIO MPP(6, 0x0, 1, 1, 1) -#define MPP6_GE0_TXD6 MPP(6, 0x1, 0, 1, 1) -#define MPP6_GE1_TXD2 MPP(6, 0x2, 0, 1, 1) +#define MPP6_GE0_TXD6 MPP(6, 0x1, 0, 0, 1) +#define MPP6_GE1_TXD2 MPP(6, 0x2, 0, 0, 1) #define MPP6_UNUSED MPP(6, 0x3, 0, 0, 1) #define MPP7_GPIO MPP(7, 0x0, 1, 1, 1) -#define MPP7_GE0_TXD7 MPP(7, 0x1, 0, 1, 1) -#define MPP7_GE1_TXD3 MPP(7, 0x2, 0, 1, 1) +#define MPP7_GE0_TXD7 MPP(7, 0x1, 0, 0, 1) +#define MPP7_GE1_TXD3 MPP(7, 0x2, 0, 0, 1) #define MPP7_UNUSED MPP(7, 0x3, 0, 0, 1) #define MPP8_GPIO MPP(8, 0x0, 1, 1, 1) -#define MPP8_GE0_RXD4 MPP(8, 0x1, 1, 0, 1) -#define MPP8_GE1_RXD0 MPP(8, 0x2, 1, 0, 1) +#define MPP8_GE0_RXD4 MPP(8, 0x1, 0, 0, 1) +#define MPP8_GE1_RXD0 MPP(8, 0x2, 0, 0, 1) #define MPP8_UNUSED MPP(8, 0x3, 0, 0, 1) #define MPP9_GPIO MPP(9, 0x0, 1, 1, 1) -#define MPP9_GE0_RXD5 MPP(9, 0x1, 1, 0, 1) -#define MPP9_GE1_RXD1 MPP(9, 0x2, 1, 0, 1) +#define MPP9_GE0_RXD5 MPP(9, 0x1, 0, 0, 1) +#define MPP9_GE1_RXD1 MPP(9, 0x2, 0, 0, 1) #define MPP9_UNUSED MPP(9, 0x3, 0, 0, 1) #define MPP10_GPIO MPP(10, 0x0, 1, 1, 1) -#define MPP10_GE0_RXD6 MPP(10, 0x1, 1, 0, 1) -#define MPP10_GE1_RXD2 MPP(10, 0x2, 1, 0, 1) +#define MPP10_GE0_RXD6 MPP(10, 0x1, 0, 0, 1) +#define MPP10_GE1_RXD2 MPP(10, 0x2, 0, 0, 1) #define MPP10_UNUSED MPP(10, 0x3, 0, 0, 1) #define MPP11_GPIO MPP(11, 0x0, 1, 1, 1) -#define MPP11_GE0_RXD7 MPP(11, 0x1, 1, 0, 1) -#define MPP11_GE1_RXD3 MPP(11, 0x2, 1, 0, 1) +#define MPP11_GE0_RXD7 MPP(11, 0x1, 0, 0, 1) +#define MPP11_GE1_RXD3 MPP(11, 0x2, 0, 0, 1) #define MPP11_UNUSED MPP(11, 0x3, 0, 0, 1) #define MPP12_GPIO MPP(12, 0x0, 1, 1, 1) -#define MPP12_M_BB MPP(12, 0x3, 1, 0, 1) -#define MPP12_UA0_CTSn MPP(12, 0x4, 1, 0, 1) -#define MPP12_NAND_FLASH_REn0 MPP(12, 0x5, 0, 1, 1) -#define MPP12_TDM0_SCSn MPP(12, 0X6, 0, 1, 1) +#define MPP12_M_BB MPP(12, 0x3, 0, 0, 1) +#define MPP12_UA0_CTSn MPP(12, 0x4, 0, 0, 1) +#define MPP12_NAND_FLASH_REn0 MPP(12, 0x5, 0, 0, 1) +#define MPP12_TDM0_SCSn MPP(12, 0X6, 0, 0, 1) #define MPP12_UNUSED MPP(12, 0x1, 0, 0, 1) #define MPP13_GPIO MPP(13, 0x0, 1, 1, 1) -#define MPP13_SYSRST_OUTn MPP(13, 0x3, 0, 1, 1) -#define MPP13_UA0_RTSn MPP(13, 0x4, 0, 1, 1) -#define MPP13_NAN_FLASH_WEn0 MPP(13, 0x5, 0, 1, 1) -#define MPP13_TDM_SCLK MPP(13, 0x6, 0, 1, 1) +#define MPP13_SYSRST_OUTn MPP(13, 0x3, 0, 0, 1) +#define MPP13_UA0_RTSn MPP(13, 0x4, 0, 0, 1) +#define MPP13_NAN_FLASH_WEn0 MPP(13, 0x5, 0, 0, 1) +#define MPP13_TDM_SCLK MPP(13, 0x6, 0, 0, 1) #define MPP13_UNUSED MPP(13, 0x1, 0, 0, 1) #define MPP14_GPIO MPP(14, 0x0, 1, 1, 1) -#define MPP14_SATA1_ACTn MPP(14, 0x3, 0, 1, 1) -#define MPP14_UA1_CTSn MPP(14, 0x4, 1, 0, 1) -#define MPP14_NAND_FLASH_REn1 MPP(14, 0x5, 0, 1, 1) -#define MPP14_TDM_SMOSI MPP(14, 0x6, 0, 1, 1) +#define MPP14_SATA1_ACTn MPP(14, 0x3, 0, 0, 1) +#define MPP14_UA1_CTSn MPP(14, 0x4, 0, 0, 1) +#define MPP14_NAND_FLASH_REn1 MPP(14, 0x5, 0, 0, 1) +#define MPP14_TDM_SMOSI MPP(14, 0x6, 0, 0, 1) #define MPP14_UNUSED MPP(14, 0x1, 0, 0, 1) #define MPP15_GPIO MPP(15, 0x0, 1, 1, 1) -#define MPP15_SATA0_ACTn MPP(15, 0x3, 0, 1, 1) -#define MPP15_UA1_RTSn MPP(15, 0x4, 0, 1, 1) -#define MPP15_NAND_FLASH_WEn1 MPP(15, 0x5, 0, 1, 1) -#define MPP15_TDM_SMISO MPP(15, 0x6, 1, 0, 1) +#define MPP15_SATA0_ACTn MPP(15, 0x3, 0, 0, 1) +#define MPP15_UA1_RTSn MPP(15, 0x4, 0, 0, 1) +#define MPP15_NAND_FLASH_WEn1 MPP(15, 0x5, 0, 0, 1) +#define MPP15_TDM_SMISO MPP(15, 0x6, 0, 0, 1) #define MPP15_UNUSED MPP(15, 0x1, 0, 0, 1) #define MPP16_GPIO MPP(16, 0x0, 1, 1, 1) -#define MPP16_SATA1_PRESENTn MPP(16, 0x3, 0, 1, 1) -#define MPP16_UA2_TXD MPP(16, 0x4, 0, 1, 1) -#define MPP16_NAND_FLASH_REn3 MPP(16, 0x5, 0, 1, 1) -#define MPP16_TDM_INTn MPP(16, 0x6, 1, 0, 1) +#define MPP16_SATA1_PRESENTn MPP(16, 0x3, 0, 0, 1) +#define MPP16_UA2_TXD MPP(16, 0x4, 0, 0, 1) +#define MPP16_NAND_FLASH_REn3 MPP(16, 0x5, 0, 0, 1) +#define MPP16_TDM_INTn MPP(16, 0x6, 0, 0, 1) #define MPP16_UNUSED MPP(16, 0x1, 0, 0, 1) #define MPP17_GPIO MPP(17, 0x0, 1, 1, 1) -#define MPP17_SATA0_PRESENTn MPP(17, 0x3, 0, 1, 1) -#define MPP17_UA2_RXD MPP(17, 0x4, 1, 0, 1) -#define MPP17_NAND_FLASH_WEn3 MPP(17, 0x5, 0, 1, 1) -#define MPP17_TDM_RSTn MPP(17, 0x6, 0, 1, 1) +#define MPP17_SATA0_PRESENTn MPP(17, 0x3, 0, 0, 1) +#define MPP17_UA2_RXD MPP(17, 0x4, 0, 0, 1) +#define MPP17_NAND_FLASH_WEn3 MPP(17, 0x5, 0, 0, 1) +#define MPP17_TDM_RSTn MPP(17, 0x6, 0, 0, 1) #define MPP17_UNUSED MPP(17, 0x1, 0, 0, 1) #define MPP18_GPIO MPP(18, 0x0, 1, 1, 1) -#define MPP18_UA0_CTSn MPP(18, 0x4, 1, 0, 1) -#define MPP18_BOOT_FLASH_REn MPP(18, 0x5, 0, 1, 1) +#define MPP18_UA0_CTSn MPP(18, 0x4, 0, 0, 1) +#define MPP18_BOOT_FLASH_REn MPP(18, 0x5, 0, 0, 1) #define MPP18_UNUSED MPP(18, 0x1, 0, 0, 1) #define MPP19_GPIO MPP(19, 0x0, 1, 1, 1) -#define MPP19_UA0_CTSn MPP(19, 0x4, 0, 1, 1) -#define MPP19_BOOT_FLASH_WEn MPP(19, 0x5, 0, 1, 1) +#define MPP19_UA0_CTSn MPP(19, 0x4, 0, 0, 1) +#define MPP19_BOOT_FLASH_WEn MPP(19, 0x5, 0, 0, 1) #define MPP19_UNUSED MPP(19, 0x1, 0, 0, 1) #define MPP20_GPIO MPP(20, 0x0, 1, 1, 1) -#define MPP20_UA1_CTSs MPP(20, 0x4, 1, 0, 1) -#define MPP20_TDM_PCLK MPP(20, 0x6, 1, 1, 0) +#define MPP20_UA1_CTSs MPP(20, 0x4, 0, 0, 1) +#define MPP20_TDM_PCLK MPP(20, 0x6, 0, 0, 0) #define MPP20_UNUSED MPP(20, 0x1, 0, 0, 1) #define MPP21_GPIO MPP(21, 0x0, 1, 1, 1) -#define MPP21_UA1_CTSs MPP(21, 0x4, 0, 1, 1) -#define MPP21_TDM_FSYNC MPP(21, 0x6, 1, 1, 0) +#define MPP21_UA1_CTSs MPP(21, 0x4, 0, 0, 1) +#define MPP21_TDM_FSYNC MPP(21, 0x6, 0, 0, 0) #define MPP21_UNUSED MPP(21, 0x1, 0, 0, 1) #define MPP22_GPIO MPP(22, 0x0, 1, 1, 1) -#define MPP22_UA3_TDX MPP(22, 0x4, 0, 1, 1) -#define MPP22_NAND_FLASH_REn2 MPP(22, 0x5, 0, 1, 1) -#define MPP22_TDM_DRX MPP(22, 0x6, 1, 0, 1) +#define MPP22_UA3_TDX MPP(22, 0x4, 0, 0, 1) +#define MPP22_NAND_FLASH_REn2 MPP(22, 0x5, 0, 0, 1) +#define MPP22_TDM_DRX MPP(22, 0x6, 0, 0, 1) #define MPP22_UNUSED MPP(22, 0x1, 0, 0, 1) #define MPP23_GPIO MPP(23, 0x0, 1, 1, 1) -#define MPP23_UA3_RDX MPP(23, 0x4, 1, 0, 1) -#define MPP23_NAND_FLASH_WEn2 MPP(23, 0x5, 0, 1, 1) -#define MPP23_TDM_DTX MPP(23, 0x6, 0, 1, 1) +#define MPP23_UA3_RDX MPP(23, 0x4, 0, 0, 1) +#define MPP23_NAND_FLASH_WEn2 MPP(23, 0x5, 0, 0, 1) +#define MPP23_TDM_DTX MPP(23, 0x6, 0, 0, 1) #define MPP23_UNUSED MPP(23, 0x1, 0, 0, 1) #define MPP24_GPIO MPP(24, 0x0, 1, 1, 1) -#define MPP24_UA2_TXD MPP(24, 0x4, 0, 1, 1) -#define MPP24_TDM_INTn MPP(24, 0x6, 1, 0, 1) +#define MPP24_UA2_TXD MPP(24, 0x4, 0, 0, 1) +#define MPP24_TDM_INTn MPP(24, 0x6, 0, 0, 1) #define MPP24_UNUSED MPP(24, 0x1, 0, 0, 1) #define MPP25_GPIO MPP(25, 0x0, 1, 1, 1) -#define MPP25_UA2_RXD MPP(25, 0x4, 1, 0, 1) -#define MPP25_TDM_RSTn MPP(25, 0x6, 0, 1, 1) +#define MPP25_UA2_RXD MPP(25, 0x4, 0, 0, 1) +#define MPP25_TDM_RSTn MPP(25, 0x6, 0, 0, 1) #define MPP25_UNUSED MPP(25, 0x1, 0, 0, 1) #define MPP26_GPIO MPP(26, 0x0, 1, 1, 1) -#define MPP26_UA2_CTSn MPP(26, 0x4, 1, 0, 1) -#define MPP26_TDM_PCLK MPP(26, 0x6, 1, 1, 1) +#define MPP26_UA2_CTSn MPP(26, 0x4, 0, 0, 1) +#define MPP26_TDM_PCLK MPP(26, 0x6, 0, 0, 1) #define MPP26_UNUSED MPP(26, 0x1, 0, 0, 1) #define MPP27_GPIO MPP(27, 0x0, 1, 1, 1) -#define MPP27_UA2_RTSn MPP(27, 0x4, 0, 1, 1) -#define MPP27_TDM_FSYNC MPP(27, 0x6, 1, 1, 1) +#define MPP27_UA2_RTSn MPP(27, 0x4, 0, 0, 1) +#define MPP27_TDM_FSYNC MPP(27, 0x6, 0, 0, 1) #define MPP27_UNUSED MPP(27, 0x1, 0, 0, 1) #define MPP28_GPIO MPP(28, 0x0, 1, 1, 1) -#define MPP28_UA3_TXD MPP(28, 0x4, 0, 1, 1) -#define MPP28_TDM_DRX MPP(28, 0x6, 1, 0, 1) +#define MPP28_UA3_TXD MPP(28, 0x4, 0, 0, 1) +#define MPP28_TDM_DRX MPP(28, 0x6, 0, 0, 1) #define MPP28_UNUSED MPP(28, 0x1, 0, 0, 1) #define MPP29_GPIO MPP(29, 0x0, 1, 1, 1) -#define MPP29_UA3_RXD MPP(29, 0x4, 1, 0, 1) -#define MPP29_SYSRST_OUTn MPP(29, 0x5, 0, 1, 1) -#define MPP29_TDM_DTX MPP(29, 0x6, 0, 1, 1) +#define MPP29_UA3_RXD MPP(29, 0x4, 0, 0, 1) +#define MPP29_SYSRST_OUTn MPP(29, 0x5, 0, 0, 1) +#define MPP29_TDM_DTX MPP(29, 0x6, 0, 0, 1) #define MPP29_UNUSED MPP(29, 0x1, 0, 0, 1) #define MPP30_GPIO MPP(30, 0x0, 1, 1, 1) -#define MPP30_UA3_CTSn MPP(30, 0x4, 1, 0, 1) +#define MPP30_UA3_CTSn MPP(30, 0x4, 0, 0, 1) #define MPP30_UNUSED MPP(30, 0x1, 0, 0, 1) #define MPP31_GPIO MPP(31, 0x0, 1, 1, 1) -#define MPP31_UA3_RTSn MPP(31, 0x4, 0, 1, 1) -#define MPP31_TDM1_SCSn MPP(31, 0x6, 0, 1, 1) +#define MPP31_UA3_RTSn MPP(31, 0x4, 0, 0, 1) +#define MPP31_TDM1_SCSn MPP(31, 0x6, 0, 0, 1) #define MPP31_UNUSED MPP(31, 0x1, 0, 0, 1) #define MPP32_GPIO MPP(32, 0x1, 1, 1, 1) -#define MPP32_UA3_TDX MPP(32, 0x4, 0, 1, 1) -#define MPP32_SYSRST_OUTn MPP(32, 0x5, 0, 1, 1) -#define MPP32_TDM0_RXQ MPP(32, 0x6, 0, 1, 1) +#define MPP32_UA3_TDX MPP(32, 0x4, 0, 0, 1) +#define MPP32_SYSRST_OUTn MPP(32, 0x5, 0, 0, 1) +#define MPP32_TDM0_RXQ MPP(32, 0x6, 0, 0, 1) #define MPP32_UNUSED MPP(32, 0x3, 0, 0, 1) #define MPP33_GPIO MPP(33, 0x1, 1, 1, 1) -#define MPP33_UA3_RDX MPP(33, 0x4, 1, 0, 1) -#define MPP33_TDM0_TXQ MPP(33, 0x6, 0, 1, 1) +#define MPP33_UA3_RDX MPP(33, 0x4, 0, 0, 1) +#define MPP33_TDM0_TXQ MPP(33, 0x6, 0, 0, 1) #define MPP33_UNUSED MPP(33, 0x3, 0, 0, 1) #define MPP34_GPIO MPP(34, 0x1, 1, 1, 1) -#define MPP34_UA2_TDX MPP(34, 0x4, 0, 1, 1) -#define MPP34_TDM1_RXQ MPP(34, 0x6, 0, 1, 1) +#define MPP34_UA2_TDX MPP(34, 0x4, 0, 0, 1) +#define MPP34_TDM1_RXQ MPP(34, 0x6, 0, 0, 1) #define MPP34_UNUSED MPP(34, 0x3, 0, 0, 1) #define MPP35_GPIO MPP(35, 0x1, 1, 1, 1) -#define MPP35_UA2_RDX MPP(35, 0x4, 1, 0, 1) -#define MPP35_TDM1_TXQ MPP(35, 0x6, 0, 1, 1) +#define MPP35_UA2_RDX MPP(35, 0x4, 0, 0, 1) +#define MPP35_TDM1_TXQ MPP(35, 0x6, 0, 0, 1) #define MPP35_UNUSED MPP(35, 0x3, 0, 0, 1) #define MPP36_GPIO MPP(36, 0x1, 1, 1, 1) -#define MPP36_UA0_CTSn MPP(36, 0x2, 1, 0, 1) -#define MPP36_UA2_TDX MPP(36, 0x4, 0, 1, 1) -#define MPP36_TDM0_SCSn MPP(36, 0x6, 0, 1, 1) +#define MPP36_UA0_CTSn MPP(36, 0x2, 0, 0, 1) +#define MPP36_UA2_TDX MPP(36, 0x4, 0, 0, 1) +#define MPP36_TDM0_SCSn MPP(36, 0x6, 0, 0, 1) #define MPP36_UNUSED MPP(36, 0x3, 0, 0, 1) #define MPP37_GPIO MPP(37, 0x1, 1, 1, 1) -#define MPP37_UA0_RTSn MPP(37, 0x2, 0, 1, 1) -#define MPP37_UA2_RXD MPP(37, 0x4, 1, 0, 1) -#define MPP37_SYSRST_OUTn MPP(37, 0x5, 0, 1, 1) -#define MPP37_TDM_SCLK MPP(37, 0x6, 0, 1, 1) +#define MPP37_UA0_RTSn MPP(37, 0x2, 0, 0, 1) +#define MPP37_UA2_RXD MPP(37, 0x4, 0, 0, 1) +#define MPP37_SYSRST_OUTn MPP(37, 0x5, 0, 0, 1) +#define MPP37_TDM_SCLK MPP(37, 0x6, 0, 0, 1) #define MPP37_UNUSED MPP(37, 0x3, 0, 0, 1) #define MPP38_GPIO MPP(38, 0x1, 1, 1, 1) -#define MPP38_UA1_CTSn MPP(38, 0x2, 1, 0, 1) -#define MPP38_UA3_TXD MPP(38, 0x4, 0, 1, 1) -#define MPP38_SYSRST_OUTn MPP(38, 0x5, 0, 1, 1) -#define MPP38_TDM_SMOSI MPP(38, 0x6, 0, 1, 1) +#define MPP38_UA1_CTSn MPP(38, 0x2, 0, 0, 1) +#define MPP38_UA3_TXD MPP(38, 0x4, 0, 0, 1) +#define MPP38_SYSRST_OUTn MPP(38, 0x5, 0, 0, 1) +#define MPP38_TDM_SMOSI MPP(38, 0x6, 0, 0, 1) #define MPP38_UNUSED MPP(38, 0x3, 0, 0, 1) #define MPP39_GPIO MPP(39, 0x1, 1, 1, 1) -#define MPP39_UA1_RTSn MPP(39, 0x2, 0, 1, 1) -#define MPP39_UA3_RXD MPP(39, 0x4, 1, 0, 1) -#define MPP39_SYSRST_OUTn MPP(39, 0x5, 0, 1, 1) -#define MPP39_TDM_SMISO MPP(39, 0x6, 1, 0, 1) +#define MPP39_UA1_RTSn MPP(39, 0x2, 0, 0, 1) +#define MPP39_UA3_RXD MPP(39, 0x4, 0, 0, 1) +#define MPP39_SYSRST_OUTn MPP(39, 0x5, 0, 0, 1) +#define MPP39_TDM_SMISO MPP(39, 0x6, 0, 0, 1) #define MPP39_UNUSED MPP(39, 0x3, 0, 0, 1) #define MPP40_GPIO MPP(40, 0x1, 1, 1, 1) -#define MPP40_TDM_INTn MPP(40, 0x6, 1, 0, 1) +#define MPP40_TDM_INTn MPP(40, 0x6, 0, 0, 1) #define MPP40_UNUSED MPP(40, 0x0, 0, 0, 1) #define MPP41_GPIO MPP(41, 0x1, 1, 1, 1) -#define MPP41_TDM_RSTn MPP(41, 0x6, 0, 1, 1) +#define MPP41_TDM_RSTn MPP(41, 0x6, 0, 0, 1) #define MPP41_UNUSED MPP(41, 0x0, 0, 0, 1) #define MPP42_GPIO MPP(42, 0x1, 1, 1, 1) -#define MPP42_TDM_PCLK MPP(42, 0x6, 1, 1, 1) +#define MPP42_TDM_PCLK MPP(42, 0x6, 0, 0, 1) #define MPP42_UNUSED MPP(42, 0x0, 0, 0, 1) #define MPP43_GPIO MPP(43, 0x1, 1, 1, 1) -#define MPP43_TDM_FSYNC MPP(43, 0x6, 1, 1, 1) +#define MPP43_TDM_FSYNC MPP(43, 0x6, 0, 0, 1) #define MPP43_UNUSED MPP(43, 0x0, 0, 0, 1) #define MPP44_GPIO MPP(44, 0x1, 1, 1, 1) -#define MPP44_TDM_DRX MPP(44, 0x6, 1, 0, 1) +#define MPP44_TDM_DRX MPP(44, 0x6, 0, 0, 1) #define MPP44_UNUSED MPP(44, 0x0, 0, 0, 1) #define MPP45_GPIO MPP(45, 0x1, 1, 1, 1) -#define MPP45_SATA0_ACTn MPP(45, 0x3, 0, 1, 1) -#define MPP45_TDM_DRX MPP(45, 0x6, 0, 1, 1) +#define MPP45_SATA0_ACTn MPP(45, 0x3, 0, 0, 1) +#define MPP45_TDM_DRX MPP(45, 0x6, 0, 0, 1) #define MPP45_UNUSED MPP(45, 0x0, 0, 0, 1) #define MPP46_GPIO MPP(46, 0x1, 1, 1, 1) -#define MPP46_TDM_SCSn MPP(46, 0x6, 0, 1, 1) +#define MPP46_TDM_SCSn MPP(46, 0x6, 0, 0, 1) #define MPP46_UNUSED MPP(46, 0x0, 0, 0, 1) @@ -323,14 +323,14 @@ #define MPP48_GPIO MPP(48, 0x1, 1, 1, 1) -#define MPP48_SATA1_ACTn MPP(48, 0x3, 0, 1, 1) +#define MPP48_SATA1_ACTn MPP(48, 0x3, 0, 0, 1) #define MPP48_UNUSED MPP(48, 0x2, 0, 0, 1) #define MPP49_GPIO MPP(49, 0x1, 1, 1, 1) -#define MPP49_SATA0_ACTn MPP(49, 0x3, 0, 1, 1) -#define MPP49_M_BB MPP(49, 0x4, 1, 0, 1) +#define MPP49_SATA0_ACTn MPP(49, 0x3, 0, 0, 1) +#define MPP49_M_BB MPP(49, 0x4, 0, 0, 1) #define MPP49_UNUSED MPP(49, 0x2, 0, 0, 1) diff --git a/arch/arm/plat-orion/mpp.c b/arch/arm/plat-orion/mpp.c index 91553432711..3b1e17bd3d1 100644 --- a/arch/arm/plat-orion/mpp.c +++ b/arch/arm/plat-orion/mpp.c @@ -64,8 +64,7 @@ void __init orion_mpp_conf(unsigned int *mpp_list, unsigned int variant_mask, gpio_mode |= GPIO_INPUT_OK; if (*mpp_list & MPP_OUTPUT_MASK) gpio_mode |= GPIO_OUTPUT_OK; - if (sel != 0) - gpio_mode = 0; + orion_gpio_set_valid(num, gpio_mode); } From 1825e65dbb5370d5cebd13dbdfe4bce86caf351c Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 22 Aug 2011 13:02:52 +0300 Subject: [PATCH 1063/4025] OMAP: DSS2: HDMI: use default dividers commit 8d88767a4377171752c22ac39bcb2b505eb751da upstream. Use default regn and regm2 dividers in the hdmi driver if the board file does not define them. Cc: Mythri P K Acked-by: Tony Lindgren Signed-off-by: Tomi Valkeinen Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/board-4430sdp.c | 9 --------- drivers/video/omap2/dss/hdmi.c | 15 +++++++++++++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 63de2d396e2..f515fa29a10 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -617,15 +617,6 @@ static struct omap_dss_device sdp4430_hdmi_device = { .name = "hdmi", .driver_name = "hdmi_panel", .type = OMAP_DISPLAY_TYPE_HDMI, - .clocks = { - .dispc = { - .dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK, - }, - .hdmi = { - .regn = 15, - .regm2 = 1, - }, - }, .platform_enable = sdp4430_panel_enable_hdmi, .platform_disable = sdp4430_panel_disable_hdmi, .channel = OMAP_DSS_CHANNEL_DIGIT, diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index b0555f4f0a7..f3369cf3337 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -40,6 +40,9 @@ #include "hdmi.h" #include "dss_features.h" +#define HDMI_DEFAULT_REGN 15 +#define HDMI_DEFAULT_REGM2 1 + static struct { struct mutex lock; struct omap_display_platform_data *pdata; @@ -1069,7 +1072,11 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, * Input clock is predivided by N + 1 * out put of which is reference clk */ - pi->regn = dssdev->clocks.hdmi.regn; + if (dssdev->clocks.hdmi.regn == 0) + pi->regn = HDMI_DEFAULT_REGN; + else + pi->regn = dssdev->clocks.hdmi.regn; + refclk = clkin / (pi->regn + 1); /* @@ -1077,7 +1084,11 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, * Multiplying by 100 to avoid fractional part removal */ pi->regm = (phy * 100 / (refclk)) / 100; - pi->regm2 = dssdev->clocks.hdmi.regm2; + + if (dssdev->clocks.hdmi.regm2 == 0) + pi->regm2 = HDMI_DEFAULT_REGM2; + else + pi->regm2 = dssdev->clocks.hdmi.regm2; /* * fractional multiplier is remainder of the difference between From 850e968cce74f2e242e06d09dd072e51bd85aee3 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 17 Jan 2012 11:04:53 +0200 Subject: [PATCH 1064/4025] OMAP: 4430SDP/Panda: use gpio_free_array to free HDMI gpios commit 575753e3bea3b67eef8e454fb87f719e3f7da599 upstream. Instead of freeing the GPIOs individually, use gpio_free_array(). Signed-off-by: Tomi Valkeinen Acked-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/board-4430sdp.c | 3 +-- arch/arm/mach-omap2/board-omap4panda.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index f515fa29a10..7feefb888a8 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -609,8 +609,7 @@ static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev) static void sdp4430_panel_disable_hdmi(struct omap_dss_device *dssdev) { - gpio_free(HDMI_GPIO_LS_OE); - gpio_free(HDMI_GPIO_HPD); + gpio_free_array(sdp4430_hdmi_gpios, ARRAY_SIZE(sdp4430_hdmi_gpios)); } static struct omap_dss_device sdp4430_hdmi_device = { diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 0cfe2005cb5..2e9a6f36128 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -645,8 +645,7 @@ static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev) static void omap4_panda_panel_disable_hdmi(struct omap_dss_device *dssdev) { - gpio_free(HDMI_GPIO_LS_OE); - gpio_free(HDMI_GPIO_HPD); + gpio_free_array(panda_hdmi_gpios, ARRAY_SIZE(panda_hdmi_gpios)); } static struct omap_dss_device omap4_panda_hdmi_device = { From 61826fb9866fc86c9832263d1f5bb427f4329277 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 17 Jan 2012 10:49:38 +0200 Subject: [PATCH 1065/4025] OMAP: 4430SDP/Panda: rename HPD GPIO to CT_CP_HPD commit 3932a32fcf5393f8be70ac99dc718ad7ad0a415b upstream. The GPIO 60 on 4430sdp and Panda is not HPD GPIO, as currently marked in the board files, but CT_CP_HPD, which is used to enable/disable HPD functionality. This patch renames the GPIO. Signed-off-by: Tomi Valkeinen Acked-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/board-4430sdp.c | 4 ++-- arch/arm/mach-omap2/board-omap4panda.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 7feefb888a8..d0a49c3792b 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -49,7 +49,7 @@ #define ETH_KS8851_QUART 138 #define OMAP4_SFH7741_SENSOR_OUTPUT_GPIO 184 #define OMAP4_SFH7741_ENABLE_GPIO 188 -#define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */ +#define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */ #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ static const int sdp4430_keymap[] = { @@ -591,7 +591,7 @@ static void sdp4430_hdmi_mux_init(void) } static struct gpio sdp4430_hdmi_gpios[] = { - { HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" }, + { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" }, { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, }; diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 2e9a6f36128..bc9874930b9 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -52,7 +52,7 @@ #define GPIO_HUB_NRESET 62 #define GPIO_WIFI_PMENA 43 #define GPIO_WIFI_IRQ 53 -#define HDMI_GPIO_HPD 60 /* Hot plug pin for HDMI */ +#define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */ #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ /* wl127x BT, FM, GPS connectivity chip */ @@ -627,7 +627,7 @@ static void omap4_panda_hdmi_mux_init(void) } static struct gpio panda_hdmi_gpios[] = { - { HDMI_GPIO_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_hpd" }, + { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" }, { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, }; From ed3984fec88b0a39f6e66ee40f124e1568f75c12 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 17 Jan 2012 10:59:00 +0200 Subject: [PATCH 1066/4025] OMAPDSS: remove wrong HDMI HPD muxing commit 7bb122d155f742fe2d79849090c825be7b4a247e upstream. "hdmi_hpd" pin is muxed to INPUT and PULLUP, but the pin is not currently used, and in the future when it is used, the pin is used as a GPIO and is board specific, not an OMAP4 wide thing. So remove the muxing for now. Signed-off-by: Tomi Valkeinen Acked-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/board-4430sdp.c | 4 ---- arch/arm/mach-omap2/board-omap4panda.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index d0a49c3792b..9bc418e138d 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -578,12 +578,8 @@ static void __init omap_sfh7741prox_init(void) static void sdp4430_hdmi_mux_init(void) { - /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */ - omap_mux_init_signal("hdmi_hpd", - OMAP_PIN_INPUT_PULLUP); omap_mux_init_signal("hdmi_cec", OMAP_PIN_INPUT_PULLUP); - /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */ omap_mux_init_signal("hdmi_ddc_scl", OMAP_PIN_INPUT_PULLUP); omap_mux_init_signal("hdmi_ddc_sda", diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index bc9874930b9..86a2d30a9fc 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -614,12 +614,8 @@ int __init omap4_panda_dvi_init(void) static void omap4_panda_hdmi_mux_init(void) { - /* PAD0_HDMI_HPD_PAD1_HDMI_CEC */ - omap_mux_init_signal("hdmi_hpd", - OMAP_PIN_INPUT_PULLUP); omap_mux_init_signal("hdmi_cec", OMAP_PIN_INPUT_PULLUP); - /* PAD0_HDMI_DDC_SCL_PAD1_HDMI_DDC_SDA */ omap_mux_init_signal("hdmi_ddc_scl", OMAP_PIN_INPUT_PULLUP); omap_mux_init_signal("hdmi_ddc_sda", From bdd91fa44646ae9e80e7a716320e9d1e7287766b Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 17 Jan 2012 11:02:36 +0200 Subject: [PATCH 1067/4025] OMAP: 4430SDP/Panda: setup HDMI GPIO muxes commit 78a1ad8f12db70b8b0a4548b90704de08ee216ce upstream. The HDMI GPIO pins LS_OE and CT_CP_HPD are not currently configured. This patch configures them as output pins. Signed-off-by: Tomi Valkeinen Acked-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/board-4430sdp.c | 3 +++ arch/arm/mach-omap2/board-omap4panda.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 9bc418e138d..669e3293780 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -631,6 +631,9 @@ void omap_4430sdp_display_init(void) { sdp4430_hdmi_mux_init(); omap_display_init(&sdp4430_dss_data); + + omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(HDMI_GPIO_CT_CP_HPD, OMAP_PIN_OUTPUT); } #ifdef CONFIG_OMAP_MUX diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 86a2d30a9fc..5d519fb01a8 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -674,6 +674,9 @@ void omap4_panda_display_init(void) omap4_panda_hdmi_mux_init(); omap_display_init(&omap4_panda_dss_data); + + omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(HDMI_GPIO_CT_CP_HPD, OMAP_PIN_OUTPUT); } static void __init omap4_panda_init(void) From 8d1b18d569d59c8aa95964e2e5e4c5d544928258 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 17 Jan 2012 11:05:32 +0200 Subject: [PATCH 1068/4025] OMAP: 4430SDP/Panda: add HDMI HPD gpio commit aa74274b464d4aa24703963ac89a0ee942d5d267 upstream. Both Panda and 4430SDP use GPIO 63 as HDMI hot-plug-detect. Configure this GPIO in the board files. Signed-off-by: Tomi Valkeinen Acked-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/board-4430sdp.c | 3 +++ arch/arm/mach-omap2/board-omap4panda.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 669e3293780..0ee578a2251 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -51,6 +51,7 @@ #define OMAP4_SFH7741_ENABLE_GPIO 188 #define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */ #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ +#define HDMI_GPIO_HPD 63 /* Hotplug detect */ static const int sdp4430_keymap[] = { KEY(0, 0, KEY_E), @@ -589,6 +590,7 @@ static void sdp4430_hdmi_mux_init(void) static struct gpio sdp4430_hdmi_gpios[] = { { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" }, { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, + { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" }, }; static int sdp4430_panel_enable_hdmi(struct omap_dss_device *dssdev) @@ -634,6 +636,7 @@ void omap_4430sdp_display_init(void) omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT); omap_mux_init_gpio(HDMI_GPIO_CT_CP_HPD, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(HDMI_GPIO_HPD, OMAP_PIN_INPUT_PULLDOWN); } #ifdef CONFIG_OMAP_MUX diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 5d519fb01a8..2b3f7e0f5d3 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -54,6 +54,7 @@ #define GPIO_WIFI_IRQ 53 #define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */ #define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */ +#define HDMI_GPIO_HPD 63 /* Hotplug detect */ /* wl127x BT, FM, GPS connectivity chip */ static int wl1271_gpios[] = {46, -1, -1}; @@ -625,6 +626,7 @@ static void omap4_panda_hdmi_mux_init(void) static struct gpio panda_hdmi_gpios[] = { { HDMI_GPIO_CT_CP_HPD, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ct_cp_hpd" }, { HDMI_GPIO_LS_OE, GPIOF_OUT_INIT_HIGH, "hdmi_gpio_ls_oe" }, + { HDMI_GPIO_HPD, GPIOF_DIR_IN, "hdmi_gpio_hpd" }, }; static int omap4_panda_panel_enable_hdmi(struct omap_dss_device *dssdev) @@ -677,6 +679,7 @@ void omap4_panda_display_init(void) omap_mux_init_gpio(HDMI_GPIO_LS_OE, OMAP_PIN_OUTPUT); omap_mux_init_gpio(HDMI_GPIO_CT_CP_HPD, OMAP_PIN_OUTPUT); + omap_mux_init_gpio(HDMI_GPIO_HPD, OMAP_PIN_INPUT_PULLDOWN); } static void __init omap4_panda_init(void) From 21189f03d3ec3a74d9949907c828410d7a9a86d5 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 17 Jan 2012 11:09:57 +0200 Subject: [PATCH 1069/4025] OMAPDSS: HDMI: PHY burnout fix commit c49d005b6cc8491fad5b24f82805be2d6bcbd3dd upstream. A hardware bug in the OMAP4 HDMI PHY causes physical damage to the board if the HDMI PHY is kept powered on when the cable is not connected. This patch solves the problem by adding hot-plug-detection into the HDMI IP driver. This is not a real HPD support in the sense that nobody else than the IP driver gets to know about the HPD events, but is only meant to fix the HW bug. The strategy is simple: If the display device is turned off by the user, the PHY power is set to OFF. When the display device is turned on by the user, the PHY power is set either to LDOON or TXON, depending on whether the HDMI cable is connected. The reason to avoid PHY OFF when the display device is on, but the cable is disconnected, is that when the PHY is turned OFF, the HDMI IP is not "ticking" and thus the DISPC does not receive pixel clock from the HDMI IP. This would, for example, prevent any VSYNCs from happening, and would thus affect the users of omapdss. By using LDOON when the cable is disconnected we'll avoid the HW bug, but keep the HDMI working as usual from the user's point of view. Signed-off-by: Tomi Valkeinen Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/board-4430sdp.c | 5 ++ arch/arm/mach-omap2/board-omap4panda.c | 5 ++ drivers/video/omap2/dss/hdmi.c | 71 ++++++++++++++++++++++++-- include/video/omapdss.h | 5 ++ 4 files changed, 82 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-omap2/board-4430sdp.c b/arch/arm/mach-omap2/board-4430sdp.c index 0ee578a2251..14a5971d0d4 100644 --- a/arch/arm/mach-omap2/board-4430sdp.c +++ b/arch/arm/mach-omap2/board-4430sdp.c @@ -610,6 +610,10 @@ static void sdp4430_panel_disable_hdmi(struct omap_dss_device *dssdev) gpio_free_array(sdp4430_hdmi_gpios, ARRAY_SIZE(sdp4430_hdmi_gpios)); } +static struct omap_dss_hdmi_data sdp4430_hdmi_data = { + .hpd_gpio = HDMI_GPIO_HPD, +}; + static struct omap_dss_device sdp4430_hdmi_device = { .name = "hdmi", .driver_name = "hdmi_panel", @@ -617,6 +621,7 @@ static struct omap_dss_device sdp4430_hdmi_device = { .platform_enable = sdp4430_panel_enable_hdmi, .platform_disable = sdp4430_panel_disable_hdmi, .channel = OMAP_DSS_CHANNEL_DIGIT, + .data = &sdp4430_hdmi_data, }; static struct omap_dss_device *sdp4430_dss_devices[] = { diff --git a/arch/arm/mach-omap2/board-omap4panda.c b/arch/arm/mach-omap2/board-omap4panda.c index 2b3f7e0f5d3..107dfc377a8 100644 --- a/arch/arm/mach-omap2/board-omap4panda.c +++ b/arch/arm/mach-omap2/board-omap4panda.c @@ -646,6 +646,10 @@ static void omap4_panda_panel_disable_hdmi(struct omap_dss_device *dssdev) gpio_free_array(panda_hdmi_gpios, ARRAY_SIZE(panda_hdmi_gpios)); } +static struct omap_dss_hdmi_data omap4_panda_hdmi_data = { + .hpd_gpio = HDMI_GPIO_HPD, +}; + static struct omap_dss_device omap4_panda_hdmi_device = { .name = "hdmi", .driver_name = "hdmi_panel", @@ -653,6 +657,7 @@ static struct omap_dss_device omap4_panda_hdmi_device = { .platform_enable = omap4_panda_panel_enable_hdmi, .platform_disable = omap4_panda_panel_disable_hdmi, .channel = OMAP_DSS_CHANNEL_DIGIT, + .data = &omap4_panda_hdmi_data, }; static struct omap_dss_device *omap4_panda_dss_devices[] = { diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index f3369cf3337..fadd6a0836c 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -29,6 +29,7 @@ #include #include #include +#include #include