Char/Misc fixes for 4.18-rc5
Here are a few char/misc driver fixes for 4.18-rc5. The "largest" stuff here is fixes for the UIO changes in 4.18-rc1 that caused breakages for some people. Thanks to Xiubo Li for fixing them quickly. Other than that, minor fixes for thunderbolt, vmw_balloon, nvmem, mei, ibmasm, and mei drivers. There's also a MAINTAINERS update where Rafael is offering to help out with reviewing driver core patches. All of these have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCW0Xg+Q8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ynuzwCeP5imDvO+/phRkeuwpchIusaBZDIAoIsVjdoa UXNqthmixT4kmZzkdw4/ =NB+C -----END PGP SIGNATURE----- Merge tag 'char-misc-4.18-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc Pull char/misc fixes from Greg KH: "Here are a few char/misc driver fixes for 4.18-rc5. The "largest" stuff here is fixes for the UIO changes in 4.18-rc1 that caused breakages for some people. Thanks to Xiubo Li for fixing them quickly. Other than that, minor fixes for thunderbolt, vmw_balloon, nvmem, mei, ibmasm, and mei drivers. There's also a MAINTAINERS update where Rafael is offering to help out with reviewing driver core patches. All of these have been in linux-next with no reported issues" * tag 'char-misc-4.18-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: nvmem: Don't let a NULL cell_id for nvmem_cell_get() crash us thunderbolt: Notify userspace when boot_acl is changed uio: fix crash after the device is unregistered uio: change to use the mutex lock instead of the spin lock uio: use request_threaded_irq instead fpga: altera-cvp: Fix an error handling path in 'altera_cvp_probe()' ibmasm: don't write out of bounds in read handler MAINTAINERS: Add myself as driver core changes reviewer mei: discard messages from not connected client during power down. vmw_balloon: fix inflation with batching
This commit is contained in:
commit
a74aa9676c
|
@ -4460,6 +4460,7 @@ F: Documentation/blockdev/drbd/
|
|||
|
||||
DRIVER CORE, KOBJECTS, DEBUGFS AND SYSFS
|
||||
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
R: "Rafael J. Wysocki" <rafael@kernel.org>
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git
|
||||
S: Supported
|
||||
F: Documentation/kobject.txt
|
||||
|
|
|
@ -455,8 +455,10 @@ static int altera_cvp_probe(struct pci_dev *pdev,
|
|||
|
||||
mgr = fpga_mgr_create(&pdev->dev, conf->mgr_name,
|
||||
&altera_cvp_ops, conf);
|
||||
if (!mgr)
|
||||
return -ENOMEM;
|
||||
if (!mgr) {
|
||||
ret = -ENOMEM;
|
||||
goto err_unmap;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pdev, mgr);
|
||||
|
||||
|
|
|
@ -507,35 +507,14 @@ static int remote_settings_file_close(struct inode *inode, struct file *file)
|
|||
static ssize_t remote_settings_file_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
|
||||
{
|
||||
void __iomem *address = (void __iomem *)file->private_data;
|
||||
unsigned char *page;
|
||||
int retval;
|
||||
int len = 0;
|
||||
unsigned int value;
|
||||
|
||||
if (*offset < 0)
|
||||
return -EINVAL;
|
||||
if (count == 0 || count > 1024)
|
||||
return 0;
|
||||
if (*offset != 0)
|
||||
return 0;
|
||||
|
||||
page = (unsigned char *)__get_free_page(GFP_KERNEL);
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
char lbuf[20];
|
||||
|
||||
value = readl(address);
|
||||
len = sprintf(page, "%d\n", value);
|
||||
len = snprintf(lbuf, sizeof(lbuf), "%d\n", value);
|
||||
|
||||
if (copy_to_user(buf, page, len)) {
|
||||
retval = -EFAULT;
|
||||
goto exit;
|
||||
}
|
||||
*offset += len;
|
||||
retval = len;
|
||||
|
||||
exit:
|
||||
free_page((unsigned long)page);
|
||||
return retval;
|
||||
return simple_read_from_buffer(buf, count, offset, lbuf, len);
|
||||
}
|
||||
|
||||
static ssize_t remote_settings_file_write(struct file *file, const char __user *ubuff, size_t count, loff_t *offset)
|
||||
|
|
|
@ -310,8 +310,11 @@ int mei_irq_read_handler(struct mei_device *dev,
|
|||
if (&cl->link == &dev->file_list) {
|
||||
/* A message for not connected fixed address clients
|
||||
* should be silently discarded
|
||||
* On power down client may be force cleaned,
|
||||
* silently discard such messages
|
||||
*/
|
||||
if (hdr_is_fixed(mei_hdr)) {
|
||||
if (hdr_is_fixed(mei_hdr) ||
|
||||
dev->dev_state == MEI_DEV_POWER_DOWN) {
|
||||
mei_irq_discard_msg(dev, mei_hdr);
|
||||
ret = 0;
|
||||
goto reset_slots;
|
||||
|
|
|
@ -467,7 +467,7 @@ static int vmballoon_send_batched_lock(struct vmballoon *b,
|
|||
unsigned int num_pages, bool is_2m_pages, unsigned int *target)
|
||||
{
|
||||
unsigned long status;
|
||||
unsigned long pfn = page_to_pfn(b->page);
|
||||
unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page));
|
||||
|
||||
STATS_INC(b->stats.lock[is_2m_pages]);
|
||||
|
||||
|
@ -515,7 +515,7 @@ static bool vmballoon_send_batched_unlock(struct vmballoon *b,
|
|||
unsigned int num_pages, bool is_2m_pages, unsigned int *target)
|
||||
{
|
||||
unsigned long status;
|
||||
unsigned long pfn = page_to_pfn(b->page);
|
||||
unsigned long pfn = PHYS_PFN(virt_to_phys(b->batch_page));
|
||||
|
||||
STATS_INC(b->stats.unlock[is_2m_pages]);
|
||||
|
||||
|
|
|
@ -936,6 +936,10 @@ struct nvmem_cell *nvmem_cell_get(struct device *dev, const char *cell_id)
|
|||
return cell;
|
||||
}
|
||||
|
||||
/* NULL cell_id only allowed for device tree; invalid otherwise */
|
||||
if (!cell_id)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return nvmem_cell_get_from_list(cell_id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nvmem_cell_get);
|
||||
|
|
|
@ -213,6 +213,10 @@ static ssize_t boot_acl_store(struct device *dev, struct device_attribute *attr,
|
|||
goto err_free_acl;
|
||||
}
|
||||
ret = tb->cm_ops->set_boot_acl(tb, acl, tb->nboot_acl);
|
||||
if (!ret) {
|
||||
/* Notify userspace about the change */
|
||||
kobject_uevent(&tb->dev.kobj, KOBJ_CHANGE);
|
||||
}
|
||||
mutex_unlock(&tb->lock);
|
||||
|
||||
err_free_acl:
|
||||
|
|
|
@ -215,7 +215,20 @@ static ssize_t name_show(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct uio_device *idev = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%s\n", idev->info->name);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&idev->info_lock);
|
||||
if (!idev->info) {
|
||||
ret = -EINVAL;
|
||||
dev_err(dev, "the device has been unregistered\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = sprintf(buf, "%s\n", idev->info->name);
|
||||
|
||||
out:
|
||||
mutex_unlock(&idev->info_lock);
|
||||
return ret;
|
||||
}
|
||||
static DEVICE_ATTR_RO(name);
|
||||
|
||||
|
@ -223,7 +236,20 @@ static ssize_t version_show(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct uio_device *idev = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%s\n", idev->info->version);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&idev->info_lock);
|
||||
if (!idev->info) {
|
||||
ret = -EINVAL;
|
||||
dev_err(dev, "the device has been unregistered\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = sprintf(buf, "%s\n", idev->info->version);
|
||||
|
||||
out:
|
||||
mutex_unlock(&idev->info_lock);
|
||||
return ret;
|
||||
}
|
||||
static DEVICE_ATTR_RO(version);
|
||||
|
||||
|
@ -415,11 +441,15 @@ EXPORT_SYMBOL_GPL(uio_event_notify);
|
|||
static irqreturn_t uio_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct uio_device *idev = (struct uio_device *)dev_id;
|
||||
irqreturn_t ret = idev->info->handler(irq, idev->info);
|
||||
irqreturn_t ret;
|
||||
|
||||
mutex_lock(&idev->info_lock);
|
||||
|
||||
ret = idev->info->handler(irq, idev->info);
|
||||
if (ret == IRQ_HANDLED)
|
||||
uio_event_notify(idev->info);
|
||||
|
||||
mutex_unlock(&idev->info_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -433,7 +463,6 @@ static int uio_open(struct inode *inode, struct file *filep)
|
|||
struct uio_device *idev;
|
||||
struct uio_listener *listener;
|
||||
int ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&minor_lock);
|
||||
idev = idr_find(&uio_idr, iminor(inode));
|
||||
|
@ -460,10 +489,16 @@ static int uio_open(struct inode *inode, struct file *filep)
|
|||
listener->event_count = atomic_read(&idev->event);
|
||||
filep->private_data = listener;
|
||||
|
||||
spin_lock_irqsave(&idev->info_lock, flags);
|
||||
mutex_lock(&idev->info_lock);
|
||||
if (!idev->info) {
|
||||
mutex_unlock(&idev->info_lock);
|
||||
ret = -EINVAL;
|
||||
goto err_alloc_listener;
|
||||
}
|
||||
|
||||
if (idev->info && idev->info->open)
|
||||
ret = idev->info->open(idev->info, inode);
|
||||
spin_unlock_irqrestore(&idev->info_lock, flags);
|
||||
mutex_unlock(&idev->info_lock);
|
||||
if (ret)
|
||||
goto err_infoopen;
|
||||
|
||||
|
@ -495,12 +530,11 @@ static int uio_release(struct inode *inode, struct file *filep)
|
|||
int ret = 0;
|
||||
struct uio_listener *listener = filep->private_data;
|
||||
struct uio_device *idev = listener->dev;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&idev->info_lock, flags);
|
||||
mutex_lock(&idev->info_lock);
|
||||
if (idev->info && idev->info->release)
|
||||
ret = idev->info->release(idev->info, inode);
|
||||
spin_unlock_irqrestore(&idev->info_lock, flags);
|
||||
mutex_unlock(&idev->info_lock);
|
||||
|
||||
module_put(idev->owner);
|
||||
kfree(listener);
|
||||
|
@ -513,12 +547,11 @@ static __poll_t uio_poll(struct file *filep, poll_table *wait)
|
|||
struct uio_listener *listener = filep->private_data;
|
||||
struct uio_device *idev = listener->dev;
|
||||
__poll_t ret = 0;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&idev->info_lock, flags);
|
||||
mutex_lock(&idev->info_lock);
|
||||
if (!idev->info || !idev->info->irq)
|
||||
ret = -EIO;
|
||||
spin_unlock_irqrestore(&idev->info_lock, flags);
|
||||
mutex_unlock(&idev->info_lock);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -537,12 +570,11 @@ static ssize_t uio_read(struct file *filep, char __user *buf,
|
|||
DECLARE_WAITQUEUE(wait, current);
|
||||
ssize_t retval = 0;
|
||||
s32 event_count;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&idev->info_lock, flags);
|
||||
mutex_lock(&idev->info_lock);
|
||||
if (!idev->info || !idev->info->irq)
|
||||
retval = -EIO;
|
||||
spin_unlock_irqrestore(&idev->info_lock, flags);
|
||||
mutex_unlock(&idev->info_lock);
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
@ -592,9 +624,13 @@ static ssize_t uio_write(struct file *filep, const char __user *buf,
|
|||
struct uio_device *idev = listener->dev;
|
||||
ssize_t retval;
|
||||
s32 irq_on;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&idev->info_lock, flags);
|
||||
mutex_lock(&idev->info_lock);
|
||||
if (!idev->info) {
|
||||
retval = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!idev->info || !idev->info->irq) {
|
||||
retval = -EIO;
|
||||
goto out;
|
||||
|
@ -618,7 +654,7 @@ static ssize_t uio_write(struct file *filep, const char __user *buf,
|
|||
retval = idev->info->irqcontrol(idev->info, irq_on);
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&idev->info_lock, flags);
|
||||
mutex_unlock(&idev->info_lock);
|
||||
return retval ? retval : sizeof(s32);
|
||||
}
|
||||
|
||||
|
@ -640,10 +676,20 @@ static vm_fault_t uio_vma_fault(struct vm_fault *vmf)
|
|||
struct page *page;
|
||||
unsigned long offset;
|
||||
void *addr;
|
||||
int ret = 0;
|
||||
int mi;
|
||||
|
||||
int mi = uio_find_mem_index(vmf->vma);
|
||||
if (mi < 0)
|
||||
return VM_FAULT_SIGBUS;
|
||||
mutex_lock(&idev->info_lock);
|
||||
if (!idev->info) {
|
||||
ret = VM_FAULT_SIGBUS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mi = uio_find_mem_index(vmf->vma);
|
||||
if (mi < 0) {
|
||||
ret = VM_FAULT_SIGBUS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* We need to subtract mi because userspace uses offset = N*PAGE_SIZE
|
||||
|
@ -658,7 +704,11 @@ static vm_fault_t uio_vma_fault(struct vm_fault *vmf)
|
|||
page = vmalloc_to_page(addr);
|
||||
get_page(page);
|
||||
vmf->page = page;
|
||||
return 0;
|
||||
|
||||
out:
|
||||
mutex_unlock(&idev->info_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct uio_logical_vm_ops = {
|
||||
|
@ -683,6 +733,7 @@ static int uio_mmap_physical(struct vm_area_struct *vma)
|
|||
struct uio_device *idev = vma->vm_private_data;
|
||||
int mi = uio_find_mem_index(vma);
|
||||
struct uio_mem *mem;
|
||||
|
||||
if (mi < 0)
|
||||
return -EINVAL;
|
||||
mem = idev->info->mem + mi;
|
||||
|
@ -724,30 +775,46 @@ static int uio_mmap(struct file *filep, struct vm_area_struct *vma)
|
|||
|
||||
vma->vm_private_data = idev;
|
||||
|
||||
mutex_lock(&idev->info_lock);
|
||||
if (!idev->info) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mi = uio_find_mem_index(vma);
|
||||
if (mi < 0)
|
||||
return -EINVAL;
|
||||
if (mi < 0) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
requested_pages = vma_pages(vma);
|
||||
actual_pages = ((idev->info->mem[mi].addr & ~PAGE_MASK)
|
||||
+ idev->info->mem[mi].size + PAGE_SIZE -1) >> PAGE_SHIFT;
|
||||
if (requested_pages > actual_pages)
|
||||
return -EINVAL;
|
||||
if (requested_pages > actual_pages) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (idev->info->mmap) {
|
||||
ret = idev->info->mmap(idev->info, vma);
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (idev->info->mem[mi].memtype) {
|
||||
case UIO_MEM_PHYS:
|
||||
return uio_mmap_physical(vma);
|
||||
ret = uio_mmap_physical(vma);
|
||||
break;
|
||||
case UIO_MEM_LOGICAL:
|
||||
case UIO_MEM_VIRTUAL:
|
||||
return uio_mmap_logical(vma);
|
||||
ret = uio_mmap_logical(vma);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&idev->info_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations uio_fops = {
|
||||
|
@ -865,7 +932,7 @@ int __uio_register_device(struct module *owner,
|
|||
|
||||
idev->owner = owner;
|
||||
idev->info = info;
|
||||
spin_lock_init(&idev->info_lock);
|
||||
mutex_init(&idev->info_lock);
|
||||
init_waitqueue_head(&idev->wait);
|
||||
atomic_set(&idev->event, 0);
|
||||
|
||||
|
@ -902,8 +969,9 @@ int __uio_register_device(struct module *owner,
|
|||
* FDs at the time of unregister and therefore may not be
|
||||
* freed until they are released.
|
||||
*/
|
||||
ret = request_irq(info->irq, uio_interrupt,
|
||||
info->irq_flags, info->name, idev);
|
||||
ret = request_threaded_irq(info->irq, NULL, uio_interrupt,
|
||||
info->irq_flags, info->name, idev);
|
||||
|
||||
if (ret)
|
||||
goto err_request_irq;
|
||||
}
|
||||
|
@ -928,7 +996,6 @@ EXPORT_SYMBOL_GPL(__uio_register_device);
|
|||
void uio_unregister_device(struct uio_info *info)
|
||||
{
|
||||
struct uio_device *idev;
|
||||
unsigned long flags;
|
||||
|
||||
if (!info || !info->uio_dev)
|
||||
return;
|
||||
|
@ -937,14 +1004,14 @@ void uio_unregister_device(struct uio_info *info)
|
|||
|
||||
uio_free_minor(idev);
|
||||
|
||||
mutex_lock(&idev->info_lock);
|
||||
uio_dev_del_attributes(idev);
|
||||
|
||||
if (info->irq && info->irq != UIO_IRQ_CUSTOM)
|
||||
free_irq(info->irq, idev);
|
||||
|
||||
spin_lock_irqsave(&idev->info_lock, flags);
|
||||
idev->info = NULL;
|
||||
spin_unlock_irqrestore(&idev->info_lock, flags);
|
||||
mutex_unlock(&idev->info_lock);
|
||||
|
||||
device_unregister(&idev->dev);
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ struct uio_device {
|
|||
struct fasync_struct *async_queue;
|
||||
wait_queue_head_t wait;
|
||||
struct uio_info *info;
|
||||
spinlock_t info_lock;
|
||||
struct mutex info_lock;
|
||||
struct kobject *map_dir;
|
||||
struct kobject *portio_dir;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue