diff options
-rw-r--r-- | arch/sparc64/solaris/socket.c | 193 | ||||
-rw-r--r-- | drivers/char/watchdog/i8xx_tco.c | 41 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-sibyte.c | 4 | ||||
-rw-r--r-- | drivers/message/i2o/Kconfig | 3 | ||||
-rw-r--r-- | drivers/message/i2o/config-osm.c | 494 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart.h | 10 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_core.c | 132 | ||||
-rw-r--r-- | drivers/serial/cpm_uart/cpm_uart_cpm1.c | 53 | ||||
-rw-r--r-- | kernel/cpuset.c | 68 | ||||
-rw-r--r-- | net/compat.c | 9 | ||||
-rw-r--r-- | net/sunrpc/svcsock.c | 2 |
11 files changed, 324 insertions, 685 deletions
diff --git a/arch/sparc64/solaris/socket.c b/arch/sparc64/solaris/socket.c index 06740582717..d3a66ea74a7 100644 --- a/arch/sparc64/solaris/socket.c +++ b/arch/sparc64/solaris/socket.c @@ -16,6 +16,7 @@ #include <linux/net.h> #include <linux/compat.h> #include <net/compat.h> +#include <net/sock.h> #include <asm/uaccess.h> #include <asm/string.h> @@ -297,121 +298,165 @@ asmlinkage int solaris_sendmsg(int fd, struct sol_nmsghdr __user *user_msg, unsi { struct socket *sock; char address[MAX_SOCK_ADDR]; - struct iovec iov[UIO_FASTIOV]; + struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; unsigned char ctl[sizeof(struct cmsghdr) + 20]; unsigned char *ctl_buf = ctl; - struct msghdr kern_msg; - int err, total_len; + struct msghdr msg_sys; + int err, ctl_len, iov_size, total_len; - if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) - return -EFAULT; - if(kern_msg.msg_iovlen > UIO_MAXIOV) - return -EINVAL; - err = verify_compat_iovec(&kern_msg, iov, address, VERIFY_READ); - if (err < 0) + err = -EFAULT; + if (msghdr_from_user32_to_kern(&msg_sys, user_msg)) + goto out; + + sock = sockfd_lookup(fd, &err); + if (!sock) goto out; + + /* do not move before msg_sys is valid */ + err = -EMSGSIZE; + if (msg_sys.msg_iovlen > UIO_MAXIOV) + goto out_put; + + /* Check whether to allocate the iovec area*/ + err = -ENOMEM; + iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); + if (msg_sys.msg_iovlen > UIO_FASTIOV) { + iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL); + if (!iov) + goto out_put; + } + + err = verify_compat_iovec(&msg_sys, iov, address, VERIFY_READ); + if (err < 0) + goto out_freeiov; total_len = err; - if(kern_msg.msg_controllen) { - struct sol_cmsghdr __user *ucmsg = kern_msg.msg_control; + err = -ENOBUFS; + if (msg_sys.msg_controllen > INT_MAX) + goto out_freeiov; + + ctl_len = msg_sys.msg_controllen; + if (ctl_len) { + struct sol_cmsghdr __user *ucmsg = msg_sys.msg_control; unsigned long *kcmsg; compat_size_t cmlen; - if (kern_msg.msg_controllen <= sizeof(compat_size_t)) - return -EINVAL; + err = -EINVAL; + if (ctl_len <= sizeof(compat_size_t)) + goto out_freeiov; - if(kern_msg.msg_controllen > sizeof(ctl)) { + if (ctl_len > sizeof(ctl)) { err = -ENOBUFS; - ctl_buf = kmalloc(kern_msg.msg_controllen, GFP_KERNEL); - if(!ctl_buf) + ctl_buf = kmalloc(ctl_len, GFP_KERNEL); + if (!ctl_buf) goto out_freeiov; } __get_user(cmlen, &ucmsg->cmsg_len); kcmsg = (unsigned long *) ctl_buf; *kcmsg++ = (unsigned long)cmlen; err = -EFAULT; - if(copy_from_user(kcmsg, &ucmsg->cmsg_level, - kern_msg.msg_controllen - sizeof(compat_size_t))) + if (copy_from_user(kcmsg, &ucmsg->cmsg_level, + ctl_len - sizeof(compat_size_t))) goto out_freectl; - kern_msg.msg_control = ctl_buf; + msg_sys.msg_control = ctl_buf; } - kern_msg.msg_flags = solaris_to_linux_msgflags(user_flags); + msg_sys.msg_flags = solaris_to_linux_msgflags(user_flags); - lock_kernel(); - sock = sockfd_lookup(fd, &err); - if (sock != NULL) { - if (sock->file->f_flags & O_NONBLOCK) - kern_msg.msg_flags |= MSG_DONTWAIT; - err = sock_sendmsg(sock, &kern_msg, total_len); - sockfd_put(sock); - } - unlock_kernel(); + if (sock->file->f_flags & O_NONBLOCK) + msg_sys.msg_flags |= MSG_DONTWAIT; + err = sock_sendmsg(sock, &msg_sys, total_len); out_freectl: - /* N.B. Use kfree here, as kern_msg.msg_controllen might change? */ - if(ctl_buf != ctl) - kfree(ctl_buf); + if (ctl_buf != ctl) + sock_kfree_s(sock->sk, ctl_buf, ctl_len); out_freeiov: - if(kern_msg.msg_iov != iov) - kfree(kern_msg.msg_iov); -out: + if (iov != iovstack) + sock_kfree_s(sock->sk, iov, iov_size); +out_put: + sockfd_put(sock); +out: return err; } asmlinkage int solaris_recvmsg(int fd, struct sol_nmsghdr __user *user_msg, unsigned int user_flags) { - struct iovec iovstack[UIO_FASTIOV]; - struct msghdr kern_msg; - char addr[MAX_SOCK_ADDR]; struct socket *sock; + struct iovec iovstack[UIO_FASTIOV]; struct iovec *iov = iovstack; + struct msghdr msg_sys; + unsigned long cmsg_ptr; + int err, iov_size, total_len, len; + + /* kernel mode address */ + char addr[MAX_SOCK_ADDR]; + + /* user mode address pointers */ struct sockaddr __user *uaddr; int __user *uaddr_len; - unsigned long cmsg_ptr; - int err, total_len, len = 0; - if(msghdr_from_user32_to_kern(&kern_msg, user_msg)) + if (msghdr_from_user32_to_kern(&msg_sys, user_msg)) return -EFAULT; - if(kern_msg.msg_iovlen > UIO_MAXIOV) - return -EINVAL; - uaddr = kern_msg.msg_name; + sock = sockfd_lookup(fd, &err); + if (!sock) + goto out; + + err = -EMSGSIZE; + if (msg_sys.msg_iovlen > UIO_MAXIOV) + goto out_put; + + /* Check whether to allocate the iovec area*/ + err = -ENOMEM; + iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); + if (msg_sys.msg_iovlen > UIO_FASTIOV) { + iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL); + if (!iov) + goto out_put; + } + + /* + * Save the user-mode address (verify_iovec will change the + * kernel msghdr to use the kernel address space) + */ + + uaddr = (void __user *) msg_sys.msg_name; uaddr_len = &user_msg->msg_namelen; - err = verify_compat_iovec(&kern_msg, iov, addr, VERIFY_WRITE); + err = verify_compat_iovec(&msg_sys, iov, addr, VERIFY_WRITE); if (err < 0) - goto out; + goto out_freeiov; total_len = err; - cmsg_ptr = (unsigned long) kern_msg.msg_control; - kern_msg.msg_flags = 0; + cmsg_ptr = (unsigned long) msg_sys.msg_control; + msg_sys.msg_flags = MSG_CMSG_COMPAT; - lock_kernel(); - sock = sockfd_lookup(fd, &err); - if (sock != NULL) { - if (sock->file->f_flags & O_NONBLOCK) - user_flags |= MSG_DONTWAIT; - err = sock_recvmsg(sock, &kern_msg, total_len, user_flags); - if(err >= 0) - len = err; - sockfd_put(sock); - } - unlock_kernel(); - - if(uaddr != NULL && err >= 0) - err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len); - if(err >= 0) { - err = __put_user(linux_to_solaris_msgflags(kern_msg.msg_flags), &user_msg->msg_flags); - if(!err) { - /* XXX Convert cmsg back into userspace 32-bit format... */ - err = __put_user((unsigned long)kern_msg.msg_control - cmsg_ptr, - &user_msg->msg_controllen); - } + if (sock->file->f_flags & O_NONBLOCK) + user_flags |= MSG_DONTWAIT; + + err = sock_recvmsg(sock, &msg_sys, total_len, user_flags); + if(err < 0) + goto out_freeiov; + + len = err; + + if (uaddr != NULL) { + err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len); + if (err < 0) + goto out_freeiov; } + err = __put_user(linux_to_solaris_msgflags(msg_sys.msg_flags), &user_msg->msg_flags); + if (err) + goto out_freeiov; + err = __put_user((unsigned long)msg_sys.msg_control - cmsg_ptr, + &user_msg->msg_controllen); + if (err) + goto out_freeiov; + err = len; - if(kern_msg.msg_iov != iov) - kfree(kern_msg.msg_iov); +out_freeiov: + if (iov != iovstack) + sock_kfree_s(sock->sk, iov, iov_size); +out_put: + sockfd_put(sock); out: - if(err < 0) - return err; - return len; + return err; } diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c index f975dab1ddf..a13395e2c37 100644 --- a/drivers/char/watchdog/i8xx_tco.c +++ b/drivers/char/watchdog/i8xx_tco.c @@ -1,5 +1,5 @@ /* - * i8xx_tco 0.07: TCO timer driver for i8xx chipsets + * i8xx_tco: TCO timer driver for i8xx chipsets * * (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved. * http://www.kernelconcepts.de @@ -63,6 +63,9 @@ * 20050128 Wim Van Sebroeck <wim@iguana.be> * 0.07 Added support for the ICH4-M, ICH6, ICH6R, ICH6-M, ICH6W and ICH6RW * chipsets. Also added support for the "undocumented" ICH7 chipset. + * 20050807 Wim Van Sebroeck <wim@iguana.be> + * 0.08 Make sure that the watchdog is only "armed" when started. + * (Kernel Bug 4251) */ /* @@ -87,7 +90,7 @@ #include "i8xx_tco.h" /* Module and version information */ -#define TCO_VERSION "0.07" +#define TCO_VERSION "0.08" #define TCO_MODULE_NAME "i8xx TCO timer" #define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION #define PFX TCO_MODULE_NAME ": " @@ -125,10 +128,18 @@ static int tco_timer_start (void) unsigned char val; spin_lock(&tco_lock); + + /* disable chipset's NO_REBOOT bit */ + pci_read_config_byte (i8xx_tco_pci, 0xd4, &val); + val &= 0xfd; + pci_write_config_byte (i8xx_tco_pci, 0xd4, val); + + /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ val = inb (TCO1_CNT + 1); val &= 0xf7; outb (val, TCO1_CNT + 1); val = inb (TCO1_CNT + 1); + spin_unlock(&tco_lock); if (val & 0x08) @@ -138,13 +149,20 @@ static int tco_timer_start (void) static int tco_timer_stop (void) { - unsigned char val; + unsigned char val, val1; spin_lock(&tco_lock); + /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ val = inb (TCO1_CNT + 1); val |= 0x08; outb (val, TCO1_CNT + 1); val = inb (TCO1_CNT + 1); + + /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ + pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1); + val1 |= 0x02; + pci_write_config_byte (i8xx_tco_pci, 0xd4, val1); + spin_unlock(&tco_lock); if ((val & 0x08) == 0) @@ -155,6 +173,7 @@ static int tco_timer_stop (void) static int tco_timer_keepalive (void) { spin_lock(&tco_lock); + /* Reload the timer by writing to the TCO Timer Reload register */ outb (0x01, TCO1_RLD); spin_unlock(&tco_lock); return 0; @@ -417,9 +436,8 @@ static unsigned char __init i8xx_tco_getdevice (void) printk (KERN_ERR PFX "failed to get TCOBASE address\n"); return 0; } - /* - * Check chipset's NO_REBOOT bit - */ + + /* Check chipset's NO_REBOOT bit */ pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1); if (val1 & 0x02) { val1 &= 0xfd; @@ -430,6 +448,10 @@ static unsigned char __init i8xx_tco_getdevice (void) return 0; /* Cannot reset NO_REBOOT bit */ } } + /* Disable reboots untill the watchdog starts */ + val1 |= 0x02; + pci_write_config_byte (i8xx_tco_pci, 0xd4, val1); + /* Set the TCO_EN bit in SMI_EN register */ if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) { printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", @@ -505,17 +527,10 @@ out: static void __exit watchdog_cleanup (void) { - u8 val; - /* Stop the timer before we leave */ if (!nowayout) tco_timer_stop (); - /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ - pci_read_config_byte (i8xx_tco_pci, 0xd4, &val); - val |= 0x02; - pci_write_config_byte (i8xx_tco_pci, 0xd4, val); - /* Deregister */ misc_deregister (&i8xx_tco_miscdev); unregister_reboot_notifier(&i8xx_tco_notifier); diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c index 1c99536b673..fa503ed9f86 100644 --- a/drivers/i2c/busses/i2c-sibyte.c +++ b/drivers/i2c/busses/i2c-sibyte.c @@ -23,8 +23,8 @@ #include <asm/sibyte/sb1250_smbus.h> static struct i2c_algo_sibyte_data sibyte_board_data[2] = { - { NULL, 0, (void *) (KSEG1+A_SMB_BASE(0)) }, - { NULL, 1, (void *) (KSEG1+A_SMB_BASE(1)) } + { NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) }, + { NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) } }; static struct i2c_adapter sibyte_board_adapter[2] = { diff --git a/drivers/message/i2o/Kconfig b/drivers/message/i2o/Kconfig index 06e8eb19a05..43a942a29c2 100644 --- a/drivers/message/i2o/Kconfig +++ b/drivers/message/i2o/Kconfig @@ -53,6 +53,9 @@ config I2O_CONFIG To compile this support as a module, choose M here: the module will be called i2o_config. + Note: If you want to use the new API you have to download the + i2o_config patch from http://i2o.shadowconnect.com/ + config I2O_CONFIG_OLD_IOCTL bool "Enable ioctls (OBSOLETE)" depends on I2O_CONFIG diff --git a/drivers/message/i2o/config-osm.c b/drivers/message/i2o/config-osm.c index fe2e7afc9ea..af32ab4e90c 100644 --- a/drivers/message/i2o/config-osm.c +++ b/drivers/message/i2o/config-osm.c @@ -30,503 +30,9 @@ static struct i2o_driver i2o_config_driver; -/* Special file operations for sysfs */ -struct fops_attribute { - struct bin_attribute bin; - struct file_operations fops; -}; - -/** - * sysfs_read_dummy - */ -static ssize_t sysfs_read_dummy(struct kobject *kobj, char *buf, loff_t offset, - size_t count) -{ - return 0; -}; - -/** - * sysfs_write_dummy - */ -static ssize_t sysfs_write_dummy(struct kobject *kobj, char *buf, loff_t offset, - size_t count) -{ - return 0; -}; - -/** - * sysfs_create_fops_file - Creates attribute with special file operations - * @kobj: kobject which should contains the attribute - * @attr: attributes which should be used to create file - * - * First creates attribute @attr in kobject @kobj. If it is the first time - * this function is called, merge old fops from sysfs with new one and - * write it back. Afterwords the new fops will be set for the created - * attribute. - * - * Returns 0 on success or negative error code on failure. - */ -static int sysfs_create_fops_file(struct kobject *kobj, - struct fops_attribute *attr) -{ - struct file_operations tmp, *fops; - struct dentry *d; - struct qstr qstr; - int rc; - - fops = &attr->fops; - - if (fops->read) - attr->bin.read = sysfs_read_dummy; - - if (fops->write) - attr->bin.write = sysfs_write_dummy; - - if ((rc = sysfs_create_bin_file(kobj, &attr->bin))) - return rc; - - qstr.name = attr->bin.attr.name; - qstr.len = strlen(qstr.name); - qstr.hash = full_name_hash(qstr.name, qstr.len); - - if ((d = lookup_hash(&qstr, kobj->dentry))) { - if (!fops->owner) { - memcpy(&tmp, d->d_inode->i_fop, sizeof(tmp)); - if (fops->read) - tmp.read = fops->read; - if (fops->write) - tmp.write = fops->write; - memcpy(fops, &tmp, sizeof(tmp)); - } - - d->d_inode->i_fop = fops; - } else - sysfs_remove_bin_file(kobj, &attr->bin); - - return -ENOENT; -}; - -/** - * sysfs_remove_fops_file - Remove attribute with special file operations - * @kobj: kobject which contains the attribute - * @attr: attributes which are used to create file - * - * Only wrapper arround sysfs_remove_bin_file() - * - * Returns 0 on success or negative error code on failure. - */ -static inline int sysfs_remove_fops_file(struct kobject *kobj, - struct fops_attribute *attr) -{ - return sysfs_remove_bin_file(kobj, &attr->bin); -}; - -/** - * i2o_config_read_hrt - Returns the HRT of the controller - * @kob: kernel object handle - * @buf: buffer into which the HRT should be copied - * @off: file offset - * @count: number of bytes to read - * - * Put @count bytes starting at @off into @buf from the HRT of the I2O - * controller corresponding to @kobj. - * - * Returns number of bytes copied into buffer. - */ -static ssize_t i2o_config_read_hrt(struct kobject *kobj, char *buf, - loff_t offset, size_t count) -{ - struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop; - i2o_hrt *hrt = c->hrt.virt; - - u32 size = (hrt->num_entries * hrt->entry_len + 2) * 4; - - if (offset > size) - return 0; - - if (offset + count > size) - count = size - offset; - - memcpy(buf, (u8 *) hrt + offset, count); - - return count; -}; - -/** - * i2o_config_read_lct - Returns the LCT of the controller - * @kob: kernel object handle - * @buf: buffer into which the LCT should be copied - * @off: file offset - * @count: number of bytes to read - * - * Put @count bytes starting at @off into @buf from the LCT of the I2O - * controller corresponding to @kobj. - * - * Returns number of bytes copied into buffer. - */ -static ssize_t i2o_config_read_lct(struct kobject *kobj, char *buf, - loff_t offset, size_t count) -{ - struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop; - u32 size = c->lct->table_size * 4; - - if (offset > size) - return 0; - - if (offset + count > size) - count = size - offset; - - memcpy(buf, (u8 *) c->lct + offset, count); - - return count; -}; - -#define I2O_CONFIG_SW_ATTR(_name,_mode,_type,_swid) \ -static ssize_t i2o_config_##_name##_read(struct file *file, char __user *buf, size_t count, loff_t * offset) { \ - return i2o_config_sw_read(file, buf, count, offset, _type, _swid); \ -};\ -\ -static ssize_t i2o_config_##_name##_write(struct file *file, const char __user *buf, size_t count, loff_t * offset) { \ - return i2o_config_sw_write(file, buf, count, offset, _type, _swid); \ -}; \ -\ -static struct fops_attribute i2o_config_attr_##_name = { \ - .bin = { .attr = { .name = __stringify(_name), .mode = _mode, \ - .owner = THIS_MODULE }, \ - .size = 0, }, \ - .fops = { .write = i2o_config_##_name##_write, \ - .read = i2o_config_##_name##_read} \ -}; - -#ifdef CONFIG_I2O_EXT_ADAPTEC - -/** - * i2o_config_dpt_reagion - Converts type and id to flash region - * @swtype: type of software module reading - * @swid: id of software which should be read - * - * Converts type and id from I2O spec to the matching region for DPT / - * Adaptec controllers. - * - * Returns region which match type and id or -1 on error. - */ -static u32 i2o_config_dpt_region(u8 swtype, u8 swid) -{ - switch (swtype) { - case I2O_SOFTWARE_MODULE_IRTOS: - /* - * content: operation firmware - * region size: - * 0xbc000 for 2554, 3754, 2564, 3757 - * 0x170000 for 2865 - * 0x17c000 for 3966 - */ - if (!swid) - return 0; - - break; - - case I2O_SOFTWARE_MODULE_IOP_PRIVATE: - /* - * content: BIOS and SMOR - * BIOS size: first 0x8000 bytes - * region size: - * 0x40000 for 2554, 3754, 2564, 3757 - * 0x80000 for 2865, 3966 - */ - if (!swid) - return 1; - - break; - - case I2O_SOFTWARE_MODULE_IOP_CONFIG: - switch (swid) { - case 0: - /* - * content: NVRAM defaults - * region size: 0x2000 bytes - */ - return 2; - case 1: - /* - * content: serial number - * region size: 0x2000 bytes - */ - return 3; - } - break; - } - - return -1; -}; - -#endif - -/** - * i2o_config_sw_read - Read a software module from controller - * @file: file pointer - * @buf: buffer into which the data should be copied - * @count: number of bytes to read - * @off: file offset - * @swtype: type of software module reading - * @swid: id of software which should be read - * - * Transfers @count bytes at offset @offset from IOP into buffer using - * type @swtype and id @swid as described in I2O spec. - * - * Returns number of bytes copied into buffer or error code on failure. - */ -static ssize_t i2o_config_sw_read(struct file *file, char __user * buf, - size_t count, loff_t * offset, u8 swtype, - u32 swid) -{ - struct sysfs_dirent *sd = file->f_dentry->d_parent->d_fsdata; - struct kobject *kobj = sd->s_element; - struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop; - u32 m, function = I2O_CMD_SW_UPLOAD; - struct i2o_dma buffer; - struct i2o_message __iomem *msg; - u32 __iomem *mptr; - int rc, status; - - m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); - if (m == I2O_QUEUE_EMPTY) - return -EBUSY; - - mptr = &msg->body[3]; - - if ((rc = i2o_dma_alloc(&c->pdev->dev, &buffer, count, GFP_KERNEL))) { - i2o_msg_nop(c, m); - return rc; - } -#ifdef CONFIG_I2O_EXT_ADAPTEC - if (c->adaptec) { - mptr = &msg->body[4]; - function = I2O_CMD_PRIVATE; - - writel(TEN_WORD_MSG_SIZE | SGL_OFFSET_8, &msg->u.head[0]); - - writel(I2O_VENDOR_DPT << 16 | I2O_DPT_FLASH_READ, - &msg->body[0]); - writel(i2o_config_dpt_region(swtype, swid), &msg->body[1]); - writel(*offset, &msg->body[2]); - writel(count, &msg->body[3]); - } else -#endif - writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]); - - writel(0xD0000000 | count, mptr++); - writel(buffer.phys, mptr); - - writel(function << 24 | HOST_TID << 12 | ADAPTER_TID, &msg->u.head[1]); - writel(i2o_config_driver.context, &msg->u.head[2]); - writel(0, &msg->u.head[3]); - -#ifdef CONFIG_I2O_EXT_ADAPTEC - if (!c->adaptec) -#endif - { - writel((u32) swtype << 16 | (u32) 1 << 8, &msg->body[0]); - writel(0, &msg->body[1]); - writel(swid, &msg->body[2]); - } - - status = i2o_msg_post_wait_mem(c, m, 60, &buffer); - - if (status == I2O_POST_WAIT_OK) { - if (!(rc = copy_to_user(buf, buffer.virt, count))) { - rc = count; - *offset += count; - } - } else - rc = -EIO; - - if (status != -ETIMEDOUT) - i2o_dma_free(&c->pdev->dev, &buffer); - - return rc; -}; - -/** - * i2o_config_sw_write - Write a software module to controller - * @file: file pointer - * @buf: buffer into which the data should be copied - * @count: number of bytes to read - * @off: file offset - * @swtype: type of software module writing - * @swid: id of software which should be written - * - * Transfers @count bytes at offset @offset from buffer to IOP using - * type @swtype and id @swid as described in I2O spec. - * - * Returns number of bytes copied from buffer or error code on failure. - */ -static ssize_t i2o_config_sw_write(struct file *file, const char __user * buf, - size_t count, loff_t * offset, u8 swtype, - u32 swid) -{ - struct sysfs_dirent *sd = file->f_dentry->d_parent->d_fsdata; - struct kobject *kobj = sd->s_element; - struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop; - u32 m, function = I2O_CMD_SW_DOWNLOAD; - struct i2o_dma buffer; - struct i2o_message __iomem *msg; - u32 __iomem *mptr; - int rc, status; - - m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET); - if (m == I2O_QUEUE_EMPTY) - return -EBUSY; - - mptr = &msg->body[3]; - - if ((rc = i2o_dma_alloc(&c->pdev->dev, &buffer, count, GFP_KERNEL))) - goto nop_msg; - - if ((rc = copy_from_user(buffer.virt, buf, count))) - goto free_buffer; - -#ifdef CONFIG_I2O_EXT_ADAPTEC - if (c->adaptec) { - mptr = &msg->body[4]; - function = I2O_CMD_PRIVATE; - - writel(TEN_WORD_MSG_SIZE | SGL_OFFSET_8, &msg->u.head[0]); - - writel(I2O_VENDOR_DPT << 16 | I2O_DPT_FLASH_WRITE, - &msg->body[0]); - writel(i2o_config_dpt_region(swtype, swid), &msg->body[1]); - writel(*offset, &msg->body[2]); - writel(count, &msg->body[3]); - } else -#endif - writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]); - - writel(0xD4000000 | count, mptr++); - writel(buffer.phys, mptr); - - writel(function << 24 | HOST_TID << 12 | ADAPTER_TID, &msg->u.head[1]); - writel(i2o_config_driver.context, &msg->u.head[2]); - writel(0, &msg->u.head[3]); - -#ifdef CONFIG_I2O_EXT_ADAPTEC - if (!c->adaptec) -#endif - { - writel((u32) swtype << 16 | (u32) 1 << 8, &msg->body[0]); - writel(0, &msg->body[1]); - writel(swid, &msg->body[2]); - } - - status = i2o_msg_post_wait_mem(c, m, 60, &buffer); - - if (status != -ETIMEDOUT) - i2o_dma_free(&c->pdev->dev, &buffer); - - if (status != I2O_POST_WAIT_OK) - return -EIO; - - *offset += count; - - return count; - - free_buffer: - i2o_dma_free(&c->pdev->dev, &buffer); - - nop_msg: - i2o_msg_nop(c, m); - - return rc; -}; - -/* attribute for HRT in sysfs */ -static struct bin_attribute i2o_config_hrt_attr = { - .attr = { - .name = "hrt", - .mode = S_IRUGO, - .owner = THIS_MODULE}, - .size = 0, - .read = i2o_config_read_hrt -}; - -/* attribute for LCT in sysfs */ -static struct bin_attribute i2o_config_lct_attr = { - .attr = { - .name = "lct", - .mode = S_IRUGO, - .owner = THIS_MODULE}, - .size = 0, - .read = i2o_config_read_lct -}; - -/* IRTOS firmware access */ -I2O_CONFIG_SW_ATTR(irtos, S_IWRSR, I2O_SOFTWARE_MODULE_IRTOS, 0); - -#ifdef CONFIG_I2O_EXT_ADAPTEC - -/* - * attribute for BIOS / SMOR, nvram and serial number access on DPT / Adaptec - * controllers - */ -I2O_CONFIG_SW_ATTR(bios, S_IWRSR, I2O_SOFTWARE_MODULE_IOP_PRIVATE, 0); -I2O_CONFIG_SW_ATTR(nvram, S_IWRSR, I2O_SOFTWARE_MODULE_IOP_CONFIG, 0); -I2O_CONFIG_SW_ATTR(serial, S_IWRSR, I2O_SOFTWARE_MODULE_IOP_CONFIG, 1); - -#endif - -/** - * i2o_config_notify_controller_add - Notify of added controller - * @c: the controller which was added - * - * If a I2O controller is added, we catch the notification to add sysfs - * entries. - */ -static void i2o_config_notify_controller_add(struct i2o_controller *c) -{ - struct kobject *kobj = &c->exec->device.kobj; - - sysfs_create_bin_file(kobj, &i2o_config_hrt_attr); - sysfs_create_bin_file(kobj, &i2o_config_lct_attr); - - sysfs_create_fops_file(kobj, &i2o_config_attr_irtos); -#ifdef CONFIG_I2O_EXT_ADAPTEC - if (c->adaptec) { - sysfs_create_fops_file(kobj, &i2o_config_attr_bios); - sysfs_create_fops_file(kobj, &i2o_config_attr_nvram); - sysfs_create_fops_file(kobj, &i2o_config_attr_serial); - } -#endif -}; - -/** - * i2o_config_notify_controller_remove - Notify of removed controller - * @c: the controller which was removed - * - * If a I2O controller is removed, we catch the notification to remove the - * sysfs entries. - */ -static void i2o_config_notify_controller_remove(struct i2o_controller *c) -{ - struct kobject *kobj = &c->exec->device.kobj; - -#ifdef CONFIG_I2O_EXT_ADAPTEC - if (c->adaptec) { - sysfs_remove_fops_file(kobj, &i2o_config_attr_serial); - sysfs_remove_fops_file(kobj, &i2o_config_attr_nvram); - sysfs_remove_fops_file(kobj, &i2o_config_attr_bios); - } -#endif - sysfs_remove_fops_file(kobj, &i2o_config_attr_irtos); - - sysfs_remove_bin_file(kobj, &i2o_config_lct_attr); - sysfs_remove_bin_file(kobj, &i2o_config_hrt_attr); -}; - /* Config OSM driver struct */ static struct i2o_driver i2o_config_driver = { .name = OSM_NAME, - .notify_controller_add = i2o_config_notify_controller_add, - .notify_controller_remove = i2o_config_notify_controller_remove }; #ifdef CONFIG_I2O_CONFIG_OLD_IOCTL diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index 5f6187baad8..73c8a088c16 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h @@ -40,13 +40,15 @@ #define TX_NUM_FIFO 4 #define TX_BUF_SIZE 32 +#define SCC_WAIT_CLOSING 100 + struct uart_cpm_port { struct uart_port port; - u16 rx_nrfifos; + u16 rx_nrfifos; u16 rx_fifosize; - u16 tx_nrfifos; + u16 tx_nrfifos; u16 tx_fifosize; - smc_t *smcp; + smc_t *smcp; smc_uart_t *smcup; scc_t *sccp; scc_uart_t *sccup; @@ -67,6 +69,8 @@ struct uart_cpm_port { int bits; /* Keep track of 'odd' SMC2 wirings */ int is_portb; + /* wait on close if needed */ + int wait_closing; }; extern int cpm_uart_port_map[UART_NR]; diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index 29db677d428..d639ac92a11 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -9,9 +9,10 @@ * * Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2) * Pantelis Antoniou (panto@intracom.gr) (CPM1) - * + * * Copyright (C) 2004 Freescale Semiconductor, Inc. * (C) 2004 Intracom, S.A. + * (C) 2005 MontaVista Software, Inc. by Vitaly Bordug <vbordug@ru.mvista.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 @@ -70,8 +71,22 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo); /**************************************************************/ +static inline unsigned long cpu2cpm_addr(void *addr) +{ + if ((unsigned long)addr >= CPM_ADDR) + return (unsigned long)addr; + return virt_to_bus(addr); +} + +static inline void *cpm2cpu_addr(unsigned long addr) +{ + if (addr >= CPM_ADDR) + return (void *)addr; + return bus_to_virt(addr); +} + /* - * Check, if transmit buffers are processed + * Check, if transmit buffers are processed */ static unsigned int cpm_uart_tx_empty(struct uart_port *port) { @@ -143,15 +158,18 @@ static void cpm_uart_start_tx(struct uart_port *port, unsigned int tty_start) } if (cpm_uart_tx_pump(port) != 0) { - if (IS_SMC(pinfo)) + if (IS_SMC(pinfo)) { smcp->smc_smcm |= SMCM_TX; - else + smcp->smc_smcmr |= SMCMR_TEN; + } else { sccp->scc_sccm |= UART_SCCM_TX; + pinfo->sccp->scc_gsmrl |= SCC_GSMRL_ENT; + } } } /* - * Stop receiver + * Stop receiver */ static void cpm_uart_stop_rx(struct uart_port *port) { @@ -176,7 +194,7 @@ static void cpm_uart_enable_ms(struct uart_port *port) } /* - * Generate a break. + * Generate a break. */ static void cpm_uart_break_ctl(struct uart_port *port, int break_state) { @@ -231,7 +249,7 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs) /* get number of characters, and check spce in flip-buffer */ i = bdp->cbd_datlen; - /* If we have not enough room in tty flip buffer, then we try + /* If we have not enough room in tty flip buffer, then we try * later, which will be the next rx-interrupt or a timeout */ if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE) { @@ -243,7 +261,7 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs) } /* get pointer */ - cp = (unsigned char *)bus_to_virt(bdp->cbd_bufaddr); + cp = cpm2cpu_addr(bdp->cbd_bufaddr); /* loop through the buffer */ while (i-- > 0) { @@ -265,13 +283,14 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs) } /* End while (i--) */ /* This BD is ready to be used again. Clear status. get next */ - bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV); + bdp->cbd_sc &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV | BD_SC_ID); bdp->cbd_sc |= BD_SC_EMPTY; if (bdp->cbd_sc & BD_SC_WRAP) bdp = pinfo->rx_bd_base; else bdp++; + } /* End for (;;) */ /* Write back buffer pointer */ @@ -336,22 +355,22 @@ static irqreturn_t cpm_uart_int(int irq, void *data, struct pt_regs *regs) if (IS_SMC(pinfo)) { events = smcp->smc_smce; + smcp->smc_smce = events; if (events & SMCM_BRKE) uart_handle_break(port); if (events & SMCM_RX) cpm_uart_int_rx(port, regs); if (events & SMCM_TX) cpm_uart_int_tx(port, regs); - smcp->smc_smce = events; } else { events = sccp->scc_scce; + sccp->scc_scce = events; if (events & UART_SCCM_BRKE) uart_handle_break(port); if (events & UART_SCCM_RX) cpm_uart_int_rx(port, regs); if (events & UART_SCCM_TX) cpm_uart_int_tx(port, regs); - sccp->scc_scce = events; } return (events) ? IRQ_HANDLED : IRQ_NONE; } @@ -360,6 +379,7 @@ static int cpm_uart_startup(struct uart_port *port) { int retval; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; + int line = pinfo - cpm_uart_ports; pr_debug("CPM uart[%d]:startup\n", port->line); @@ -376,9 +396,19 @@ static int cpm_uart_startup(struct uart_port *port) pinfo->sccp->scc_sccm |= UART_SCCM_RX; } + if (!(pinfo->flags & FLAG_CONSOLE)) + cpm_line_cr_cmd(line,CPM_CR_INIT_TRX); return 0; } +inline void cpm_uart_wait_until_send(struct uart_cpm_port *pinfo) +{ + unsigned long target_jiffies = jiffies + pinfo->wait_closing; + + while (!time_after(jiffies, target_jiffies)) + schedule(); +} + /* * Shutdown the uart */ @@ -394,6 +424,12 @@ static void cpm_uart_shutdown(struct uart_port *port) /* If the port is not the console, disable Rx and Tx. */ if (!(pinfo->flags & FLAG_CONSOLE)) { + /* Wait for all the BDs marked sent */ + while(!cpm_uart_tx_empty(port)) + schedule_timeout(2); + if(pinfo->wait_closing) + cpm_uart_wait_until_send(pinfo); + /* Stop uarts */ if (IS_SMC(pinfo)) { volatile smc_t *smcp = pinfo->smcp; @@ -502,7 +538,7 @@ static void cpm_uart_set_termios(struct uart_port *port, */ if ((termios->c_cflag & CREAD) == 0) port->read_status_mask &= ~BD_SC_EMPTY; - + spin_lock_irqsave(&port->lock, flags); /* Start bit has not been added (so don't, because we would just @@ -569,7 +605,8 @@ static int cpm_uart_tx_pump(struct uart_port *port) /* Pick next descriptor and fill from buffer */ bdp = pinfo->tx_cur; - p = bus_to_virt(bdp->cbd_bufaddr); + p = cpm2cpu_addr(bdp->cbd_bufaddr); + *p++ = xmit->buf[xmit->tail]; bdp->cbd_datlen = 1; bdp->cbd_sc |= BD_SC_READY; @@ -595,7 +632,7 @@ static int cpm_uart_tx_pump(struct uart_port *port) while (!(bdp->cbd_sc & BD_SC_READY) && (xmit->tail != xmit->head)) { count = 0; - p = bus_to_virt(bdp->cbd_bufaddr); + p = cpm2cpu_addr(bdp->cbd_bufaddr); while (count < pinfo->tx_fifosize) { *p++ = xmit->buf[xmit->tail]; xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); @@ -606,6 +643,7 @@ static int cpm_uart_tx_pump(struct uart_port *port) } bdp->cbd_datlen = count; bdp->cbd_sc |= BD_SC_READY; + __asm__("eieio"); /* Get next BD. */ if (bdp->cbd_sc & BD_SC_WRAP) bdp = pinfo->tx_bd_base; @@ -643,12 +681,12 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) mem_addr = pinfo->mem_addr; bdp = pinfo->rx_cur = pinfo->rx_bd_base; for (i = 0; i < (pinfo->rx_nrfifos - 1); i++, bdp++) { - bdp->cbd_bufaddr = virt_to_bus(mem_addr); + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); bdp->cbd_sc = BD_SC_EMPTY | BD_SC_INTRPT; mem_addr += pinfo->rx_fifosize; } - - bdp->cbd_bufaddr = virt_to_bus(mem_addr); + + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); bdp->cbd_sc = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT; /* Set the physical address of the host memory @@ -658,12 +696,12 @@ static void cpm_uart_initbd(struct uart_cpm_port *pinfo) mem_addr = pinfo->mem_addr + L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize); bdp = pinfo->tx_cur = pinfo->tx_bd_base; for (i = 0; i < (pinfo->tx_nrfifos - 1); i++, bdp++) { - bdp->cbd_bufaddr = virt_to_bus(mem_addr); + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); bdp->cbd_sc = BD_SC_INTRPT; mem_addr += pinfo->tx_fifosize; } - - bdp->cbd_bufaddr = virt_to_bus(mem_addr); + + bdp->cbd_bufaddr = cpu2cpm_addr(mem_addr); bdp->cbd_sc = BD_SC_WRAP | BD_SC_INTRPT; } @@ -763,6 +801,8 @@ static void cpm_uart_init_smc(struct uart_cpm_port *pinfo) /* Using idle charater time requires some additional tuning. */ up->smc_mrblr = pinfo->rx_fifosize; up->smc_maxidl = pinfo->rx_fifosize; + up->smc_brklen = 0; + up->smc_brkec = 0; up->smc_brkcr = 1; cpm_line_cr_cmd(line, CPM_CR_INIT_TRX); @@ -796,7 +836,7 @@ static int cpm_uart_request_port(struct uart_port *port) /* * Setup any port IO, connect any baud rate generators, * etc. This is expected to be handled by board - * dependant code + * dependant code */ if (pinfo->set_lineif) pinfo->set_lineif(pinfo); @@ -815,6 +855,10 @@ static int cpm_uart_request_port(struct uart_port *port) return ret; cpm_uart_initbd(pinfo); + if (IS_SMC(pinfo)) + cpm_uart_init_smc(pinfo); + else + cpm_uart_init_scc(pinfo); return 0; } @@ -869,7 +913,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = { .flags = FLAG_SMC, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, - .rx_nrfifos = RX_NUM_FIFO, + .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = smc1_lineif, }, @@ -883,7 +927,7 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = { .flags = FLAG_SMC, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, - .rx_nrfifos = RX_NUM_FIFO, + .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = smc2_lineif, #ifdef CONFIG_SERIAL_CPM_ALT_SMC2 @@ -899,9 +943,10 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = { }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, - .rx_nrfifos = RX_NUM_FIFO, + .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = scc1_lineif, + .wait_closing = SCC_WAIT_CLOSING, }, [UART_SCC2] = { .port = { @@ -912,9 +957,10 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = { }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, - .rx_nrfifos = RX_NUM_FIFO, + .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = scc2_lineif, + .wait_closing = SCC_WAIT_CLOSING, }, [UART_SCC3] = { .port = { @@ -925,9 +971,10 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = { }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, - .rx_nrfifos = RX_NUM_FIFO, + .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = scc3_lineif, + .wait_closing = SCC_WAIT_CLOSING, }, [UART_SCC4] = { .port = { @@ -938,9 +985,10 @@ struct uart_cpm_port cpm_uart_ports[UART_NR] = { }, .tx_nrfifos = TX_NUM_FIFO, .tx_fifosize = TX_BUF_SIZE, - .rx_nrfifos = RX_NUM_FIFO, + .rx_nrfifos = RX_NUM_FIFO, .rx_fifosize = RX_BUF_SIZE, .set_lineif = scc4_lineif, + .wait_closing = SCC_WAIT_CLOSING, }, }; @@ -983,11 +1031,8 @@ static void cpm_uart_console_write(struct console *co, const char *s, * If the buffer address is in the CPM DPRAM, don't * convert it. */ - if ((uint) (bdp->cbd_bufaddr) > (uint) CPM_ADDR) - cp = (unsigned char *) (bdp->cbd_bufaddr); - else - cp = bus_to_virt(bdp->cbd_bufaddr); - + cp = cpm2cpu_addr(bdp->cbd_bufaddr); + *cp = *s; bdp->cbd_datlen = 1; @@ -1003,10 +1048,7 @@ static void cpm_uart_console_write(struct console *co, const char *s, while ((bdp->cbd_sc & BD_SC_READY) != 0) ; - if ((uint) (bdp->cbd_bufaddr) > (uint) CPM_ADDR) - cp = (unsigned char *) (bdp->cbd_bufaddr); - else - cp = bus_to_virt(bdp->cbd_bufaddr); + cp = cpm2cpu_addr(bdp->cbd_bufaddr); *cp = 13; bdp->cbd_datlen = 1; @@ -1045,7 +1087,7 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) port = (struct uart_port *)&cpm_uart_ports[cpm_uart_port_map[co->index]]; pinfo = (struct uart_cpm_port *)port; - + pinfo->flags |= FLAG_CONSOLE; if (options) { @@ -1062,7 +1104,7 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) /* * Setup any port IO, connect any baud rate generators, * etc. This is expected to be handled by board - * dependant code + * dependant code */ if (pinfo->set_lineif) pinfo->set_lineif(pinfo); @@ -1092,14 +1134,14 @@ static int __init cpm_uart_console_setup(struct console *co, char *options) return 0; } -extern struct uart_driver cpm_reg; +static struct uart_driver cpm_reg; static struct console cpm_scc_uart_console = { - .name "ttyCPM", - .write cpm_uart_console_write, - .device uart_console_device, - .setup cpm_uart_console_setup, - .flags CON_PRINTBUFFER, - .index -1, + .name = "ttyCPM", + .write = cpm_uart_console_write, + .device = uart_console_device, + .setup = cpm_uart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, .data = &cpm_reg, }; diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c index 8efbd6d1d6a..4b0786e7eb7 100644 --- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c +++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c @@ -5,7 +5,7 @@ * * Maintainer: Kumar Gala (kumar.gala@freescale.com) (CPM2) * Pantelis Antoniou (panto@intracom.gr) (CPM1) - * + * * Copyright (C) 2004 Freescale Semiconductor, Inc. * (C) 2004 Intracom, S.A. * @@ -82,6 +82,17 @@ void cpm_line_cr_cmd(int line, int cmd) void smc1_lineif(struct uart_cpm_port *pinfo) { volatile cpm8xx_t *cp = cpmp; + + (void)cp; /* fix warning */ +#if defined (CONFIG_MPC885ADS) + /* Enable SMC1 transceivers */ + { + cp->cp_pepar |= 0x000000c0; + cp->cp_pedir &= ~0x000000c0; + cp->cp_peso &= ~0x00000040; + cp->cp_peso |= 0x00000080; + } +#elif defined (CONFIG_MPC86XADS) unsigned int iobits = 0x000000c0; if (!pinfo->is_portb) { @@ -93,41 +104,33 @@ void smc1_lineif(struct uart_cpm_port *pinfo) ((immap_t *)IMAP_ADDR)->im_ioport.iop_padir &= ~iobits; ((immap_t *)IMAP_ADDR)->im_ioport.iop_paodr &= ~iobits; } - -#ifdef CONFIG_MPC885ADS - /* Enable SMC1 transceivers */ - { - volatile uint __iomem *bcsr1 = ioremap(BCSR1, 4); - uint tmp; - - tmp = in_be32(bcsr1); - tmp &= ~BCSR1_RS232EN_1; - out_be32(bcsr1, tmp); - iounmap(bcsr1); - } #endif - pinfo->brg = 1; } void smc2_lineif(struct uart_cpm_port *pinfo) { -#ifdef CONFIG_MPC885ADS volatile cpm8xx_t *cp = cpmp; - volatile uint __iomem *bcsr1; - uint tmp; + (void)cp; /* fix warning */ +#if defined (CONFIG_MPC885ADS) cp->cp_pepar |= 0x00000c00; cp->cp_pedir &= ~0x00000c00; cp->cp_peso &= ~0x00000400; cp->cp_peso |= 0x00000800; +#elif defined (CONFIG_MPC86XADS) + unsigned int iobits = 0x00000c00; + + if (!pinfo->is_portb) { + cp->cp_pbpar |= iobits; + cp->cp_pbdir &= ~iobits; + cp->cp_pbodr &= ~iobits; + } else { + ((immap_t *)IMAP_ADDR)->im_ioport.iop_papar |= iobits; + ((immap_t *)IMAP_ADDR)->im_ioport.iop_padir &= ~iobits; + ((immap_t *)IMAP_ADDR)->im_ioport.iop_paodr &= ~iobits; + } - /* Enable SMC2 transceivers */ - bcsr1 = ioremap(BCSR1, 4); - tmp = in_be32(bcsr1); - tmp &= ~BCSR1_RS232EN_2; - out_be32(bcsr1, tmp); - iounmap(bcsr1); #endif pinfo->brg = 2; @@ -158,7 +161,7 @@ void scc4_lineif(struct uart_cpm_port *pinfo) } /* - * Allocate DP-Ram and memory buffers. We need to allocate a transmit and + * Allocate DP-Ram and memory buffers. We need to allocate a transmit and * receive buffer descriptors from dual port ram, and a character * buffer area from host mem. If we are allocating for the console we need * to do it from bootmem @@ -185,6 +188,8 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con) memsz = L1_CACHE_ALIGN(pinfo->rx_nrfifos * pinfo->rx_fifosize) + L1_CACHE_ALIGN(pinfo->tx_nrfifos * pinfo->tx_fifosize); if (is_con) { + /* was hostalloc but changed cause it blows away the */ + /* large tlb mapping when pinning the kernel area */ mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8)); dma_addr = 0; } else diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 805fb909731..21a4e3b2cbd 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -398,21 +398,31 @@ static int cpuset_path(const struct cpuset *cs, char *buf, int buflen) * to continue to serve a useful existence. Next time it's released, * we will get notified again, if it still has 'notify_on_release' set. * - * Note final arg to call_usermodehelper() is 0 - that means - * don't wait. Since we are holding the global cpuset_sem here, - * and we are asking another thread (started from keventd) to rmdir a - * cpuset, we can't wait - or we'd deadlock with the removing thread - * on cpuset_sem. + * The final arg to call_usermodehelper() is 0, which means don't + * wait. The separate /sbin/cpuset_release_agent task is forked by + * call_usermodehelper(), then control in this thread returns here, + * without waiting for the release agent task. We don't bother to + * wait because the caller of this routine has no use for the exit + * status of the /sbin/cpuset_release_agent task, so no sense holding + * our caller up for that. + * + * The simple act of forking that task might require more memory, + * which might need cpuset_sem. So this routine must be called while + * cpuset_sem is not held, to avoid a possible deadlock. See also + * comments for check_for_release(), below. */ -static int cpuset_release_agent(char *cpuset_str) +static void cpuset_release_agent(const char *pathbuf) { char *argv[3], *envp[3]; int i; + if (!pathbuf) + return; + i = 0; argv[i++] = "/sbin/cpuset_release_agent"; - argv[i++] = cpuset_str; + argv[i++] = (char *)pathbuf; argv[i] = NULL; i = 0; @@ -421,17 +431,29 @@ static int cpuset_release_agent(char *cpuset_str) envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; envp[i] = NULL; - return call_usermodehelper(argv[0], argv, envp, 0); + call_usermodehelper(argv[0], argv, envp, 0); + kfree(pathbuf); } /* * Either cs->count of using tasks transitioned to zero, or the * cs->children list of child cpusets just became empty. If this * cs is notify_on_release() and now both the user count is zero and - * the list of children is empty, send notice to user land. + * the list of children is empty, prepare cpuset path in a kmalloc'd + * buffer, to be returned via ppathbuf, so that the caller can invoke + * cpuset_release_agent() with it later on, once cpuset_sem is dropped. + * Call here with cpuset_sem held. + * + * This check_for_release() routine is responsible for kmalloc'ing + * pathbuf. The above cpuset_release_agent() is responsible for + * kfree'ing pathbuf. The caller of these routines is responsible + * for providing a pathbuf pointer, initialized to NULL, then + * calling check_for_release() with cpuset_sem held and the address + * of the pathbuf pointer, then dropping cpuset_sem, then calling + * cpuset_release_agent() with pathbuf, as set by check_for_release(). */ -static void check_for_release(struct cpuset *cs) +static void check_for_release(struct cpuset *cs, char **ppathbuf) { if (notify_on_release(cs) && atomic_read(&cs->count) == 0 && list_empty(&cs->children)) { @@ -441,10 +463,9 @@ static void check_for_release(struct cpuset *cs) if (!buf) return; if (cpuset_path(cs, buf, PAGE_SIZE) < 0) - goto out; - cpuset_release_agent(buf); -out: - kfree(buf); + kfree(buf); + else + *ppathbuf = buf; } } @@ -727,14 +748,14 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf) return 0; } -static int attach_task(struct cpuset *cs, char *buf) +static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf) { pid_t pid; struct task_struct *tsk; struct cpuset *oldcs; cpumask_t cpus; - if (sscanf(buf, "%d", &pid) != 1) + if (sscanf(pidbuf, "%d", &pid) != 1) return -EIO; if (cpus_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed)) return -ENOSPC; @@ -777,7 +798,7 @@ static int attach_task(struct cpuset *cs, char *buf) put_task_struct(tsk); if (atomic_dec_and_test(&oldcs->count)) - check_for_release(oldcs); + check_for_release(oldcs, ppathbuf); return 0; } @@ -801,6 +822,7 @@ static ssize_t cpuset_common_file_write(struct file *file, const char __user *us struct cftype *cft = __d_cft(file->f_dentry); cpuset_filetype_t type = cft->private; char *buffer; + char *pathbuf = NULL; int retval = 0; /* Crude upper limit on largest legitimate cpulist user might write. */ @@ -841,7 +863,7 @@ static ssize_t cpuset_common_file_write(struct file *file, const char __user *us retval = update_flag(CS_NOTIFY_ON_RELEASE, cs, buffer); break; case FILE_TASKLIST: - retval = attach_task(cs, buffer); + retval = attach_task(cs, buffer, &pathbuf); break; default: retval = -EINVAL; @@ -852,6 +874,7 @@ static ssize_t cpuset_common_file_write(struct file *file, const char __user *us retval = nbytes; out2: up(&cpuset_sem); + cpuset_release_agent(pathbuf); out1: kfree(buffer); return retval; @@ -1357,6 +1380,7 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry) struct cpuset *cs = dentry->d_fsdata; struct dentry *d; struct cpuset *parent; + char *pathbuf = NULL; /* the vfs holds both inode->i_sem already */ @@ -1376,7 +1400,7 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry) update_cpu_domains(cs); list_del(&cs->sibling); /* delete my sibling from parent->children */ if (list_empty(&parent->children)) - check_for_release(parent); + check_for_release(parent, &pathbuf); spin_lock(&cs->dentry->d_lock); d = dget(cs->dentry); cs->dentry = NULL; @@ -1384,6 +1408,7 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry) cpuset_d_remove_dir(d); dput(d); up(&cpuset_sem); + cpuset_release_agent(pathbuf); return 0; } @@ -1483,10 +1508,13 @@ void cpuset_exit(struct task_struct *tsk) task_unlock(tsk); if (notify_on_release(cs)) { + char *pathbuf = NULL; + down(&cpuset_sem); if (atomic_dec_and_test(&cs->count)) - check_for_release(cs); + check_for_release(cs, &pathbuf); up(&cpuset_sem); + cpuset_release_agent(pathbuf); } else { atomic_dec(&cs->count); } diff --git a/net/compat.c b/net/compat.c index be5d936dc42..d99ab969589 100644 --- a/net/compat.c +++ b/net/compat.c @@ -91,20 +91,11 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov, } else kern_msg->msg_name = NULL; - if(kern_msg->msg_iovlen > UIO_FASTIOV) { - kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec), - GFP_KERNEL); - if(!kern_iov) - return -ENOMEM; - } - tot_len = iov_from_user_compat_to_kern(kern_iov, (struct compat_iovec __user *)kern_msg->msg_iov, kern_msg->msg_iovlen); if(tot_len >= 0) kern_msg->msg_iov = kern_iov; - else if(kern_msg->msg_iovlen > UIO_FASTIOV) - kfree(kern_iov); return tot_len; } diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 56db8f13e6c..d0c3120d023 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -586,7 +586,7 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) } if (skb->stamp.tv_sec == 0) { skb->stamp.tv_sec = xtime.tv_sec; - skb->stamp.tv_usec = xtime.tv_nsec * 1000; + skb->stamp.tv_usec = xtime.tv_nsec / NSEC_PER_USEC; /* Don't enable netstamp, sunrpc doesn't need that much accuracy */ } |