Commit b72018ab authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'fbdev-for-6.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/linux-fbdev

Pull fbdev fixes from Helge Deller:
 "A use-after-free bugfix in the smscufx driver and various minor error
  path fixes, smaller build fixes, sysfs fixes and typos in comments in
  the stifb, sisfb, da8xxfb, xilinxfb, sm501fb, gbefb and cyber2000fb
  drivers"

* tag 'fbdev-for-6.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/linux-fbdev:
  fbdev: cyber2000fb: fix missing pci_disable_device()
  fbdev: sisfb: use explicitly signed char
  fbdev: smscufx: Fix several use-after-free bugs
  fbdev: xilinxfb: Make xilinxfb_release() return void
  fbdev: sisfb: fix repeated word in comment
  fbdev: gbefb: Convert sysfs snprintf to sysfs_emit
  fbdev: sm501fb: Convert sysfs snprintf to sysfs_emit
  fbdev: stifb: Fall back to cfb_fillrect() on 32-bit HCRX cards
  fbdev: da8xx-fb: Fix error handling in .remove()
  fbdev: MIPS supports iomem addresses
parents 9f127546 3c6bf6bd
...@@ -91,7 +91,7 @@ struct SiS_Ext { ...@@ -91,7 +91,7 @@ struct SiS_Ext {
unsigned char VB_ExtTVYFilterIndex; unsigned char VB_ExtTVYFilterIndex;
unsigned char VB_ExtTVYFilterIndexROM661; unsigned char VB_ExtTVYFilterIndexROM661;
unsigned char REFindex; unsigned char REFindex;
char ROMMODEIDX661; signed char ROMMODEIDX661;
}; };
struct SiS_Ext2 { struct SiS_Ext2 {
......
...@@ -1796,6 +1796,7 @@ static int cyberpro_pci_probe(struct pci_dev *dev, ...@@ -1796,6 +1796,7 @@ static int cyberpro_pci_probe(struct pci_dev *dev,
failed_regions: failed_regions:
cyberpro_free_fb_info(cfb); cyberpro_free_fb_info(cfb);
failed_release: failed_release:
pci_disable_device(dev);
return err; return err;
} }
...@@ -1812,6 +1813,7 @@ static void cyberpro_pci_remove(struct pci_dev *dev) ...@@ -1812,6 +1813,7 @@ static void cyberpro_pci_remove(struct pci_dev *dev)
int_cfb_info = NULL; int_cfb_info = NULL;
pci_release_regions(dev); pci_release_regions(dev);
pci_disable_device(dev);
} }
} }
......
...@@ -1076,7 +1076,8 @@ static int fb_remove(struct platform_device *dev) ...@@ -1076,7 +1076,8 @@ static int fb_remove(struct platform_device *dev)
if (par->lcd_supply) { if (par->lcd_supply) {
ret = regulator_disable(par->lcd_supply); ret = regulator_disable(par->lcd_supply);
if (ret) if (ret)
return ret; dev_warn(&dev->dev, "Failed to disable regulator (%pe)\n",
ERR_PTR(ret));
} }
lcd_disable_raster(DA8XX_FRAME_WAIT); lcd_disable_raster(DA8XX_FRAME_WAIT);
......
...@@ -1060,14 +1060,14 @@ static const struct fb_ops gbefb_ops = { ...@@ -1060,14 +1060,14 @@ static const struct fb_ops gbefb_ops = {
static ssize_t gbefb_show_memsize(struct device *dev, struct device_attribute *attr, char *buf) static ssize_t gbefb_show_memsize(struct device *dev, struct device_attribute *attr, char *buf)
{ {
return snprintf(buf, PAGE_SIZE, "%u\n", gbe_mem_size); return sysfs_emit(buf, "%u\n", gbe_mem_size);
} }
static DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL); static DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL);
static ssize_t gbefb_show_rev(struct device *device, struct device_attribute *attr, char *buf) static ssize_t gbefb_show_rev(struct device *device, struct device_attribute *attr, char *buf)
{ {
return snprintf(buf, PAGE_SIZE, "%d\n", gbe_revision); return sysfs_emit(buf, "%d\n", gbe_revision);
} }
static DEVICE_ATTR(revision, S_IRUGO, gbefb_show_rev, NULL); static DEVICE_ATTR(revision, S_IRUGO, gbefb_show_rev, NULL);
......
...@@ -202,7 +202,7 @@ SiS310SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, int ...@@ -202,7 +202,7 @@ SiS310SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, int
* and destination blitting areas overlap and * and destination blitting areas overlap and
* adapt the bitmap addresses synchronously * adapt the bitmap addresses synchronously
* if the coordinates exceed the valid range. * if the coordinates exceed the valid range.
* The the areas do not overlap, we do our * The areas do not overlap, we do our
* normal check. * normal check.
*/ */
if((mymax - mymin) < height) { if((mymax - mymin) < height) {
......
...@@ -148,7 +148,7 @@ struct SiS_Ext { ...@@ -148,7 +148,7 @@ struct SiS_Ext {
unsigned char VB_ExtTVYFilterIndex; unsigned char VB_ExtTVYFilterIndex;
unsigned char VB_ExtTVYFilterIndexROM661; unsigned char VB_ExtTVYFilterIndexROM661;
unsigned char REFindex; unsigned char REFindex;
char ROMMODEIDX661; signed char ROMMODEIDX661;
}; };
struct SiS_Ext2 { struct SiS_Ext2 {
......
...@@ -1166,7 +1166,7 @@ static ssize_t sm501fb_crtsrc_show(struct device *dev, ...@@ -1166,7 +1166,7 @@ static ssize_t sm501fb_crtsrc_show(struct device *dev,
ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL); ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
ctrl &= SM501_DC_CRT_CONTROL_SEL; ctrl &= SM501_DC_CRT_CONTROL_SEL;
return snprintf(buf, PAGE_SIZE, "%s\n", ctrl ? "crt" : "panel"); return sysfs_emit(buf, "%s\n", ctrl ? "crt" : "panel");
} }
/* sm501fb_crtsrc_show /* sm501fb_crtsrc_show
......
...@@ -97,7 +97,6 @@ struct ufx_data { ...@@ -97,7 +97,6 @@ struct ufx_data {
struct kref kref; struct kref kref;
int fb_count; int fb_count;
bool virtualized; /* true when physical usb device not present */ bool virtualized; /* true when physical usb device not present */
struct delayed_work free_framebuffer_work;
atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */ atomic_t usb_active; /* 0 = update virtual buffer, but no usb traffic */
atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */ atomic_t lost_pixels; /* 1 = a render op failed. Need screen refresh */
u8 *edid; /* null until we read edid from hw or get from sysfs */ u8 *edid; /* null until we read edid from hw or get from sysfs */
...@@ -1117,15 +1116,24 @@ static void ufx_free(struct kref *kref) ...@@ -1117,15 +1116,24 @@ static void ufx_free(struct kref *kref)
{ {
struct ufx_data *dev = container_of(kref, struct ufx_data, kref); struct ufx_data *dev = container_of(kref, struct ufx_data, kref);
/* this function will wait for all in-flight urbs to complete */ kfree(dev);
if (dev->urbs.count > 0) }
ufx_free_urb_list(dev);
pr_debug("freeing ufx_data %p", dev); static void ufx_ops_destory(struct fb_info *info)
{
struct ufx_data *dev = info->par;
int node = info->node;
kfree(dev); /* Assume info structure is freed after this point */
framebuffer_release(info);
pr_debug("fb_info for /dev/fb%d has been freed", node);
/* release reference taken by kref_init in probe() */
kref_put(&dev->kref, ufx_free);
} }
static void ufx_release_urb_work(struct work_struct *work) static void ufx_release_urb_work(struct work_struct *work)
{ {
struct urb_node *unode = container_of(work, struct urb_node, struct urb_node *unode = container_of(work, struct urb_node,
...@@ -1134,14 +1142,9 @@ static void ufx_release_urb_work(struct work_struct *work) ...@@ -1134,14 +1142,9 @@ static void ufx_release_urb_work(struct work_struct *work)
up(&unode->dev->urbs.limit_sem); up(&unode->dev->urbs.limit_sem);
} }
static void ufx_free_framebuffer_work(struct work_struct *work) static void ufx_free_framebuffer(struct ufx_data *dev)
{ {
struct ufx_data *dev = container_of(work, struct ufx_data,
free_framebuffer_work.work);
struct fb_info *info = dev->info; struct fb_info *info = dev->info;
int node = info->node;
unregister_framebuffer(info);
if (info->cmap.len != 0) if (info->cmap.len != 0)
fb_dealloc_cmap(&info->cmap); fb_dealloc_cmap(&info->cmap);
...@@ -1153,11 +1156,6 @@ static void ufx_free_framebuffer_work(struct work_struct *work) ...@@ -1153,11 +1156,6 @@ static void ufx_free_framebuffer_work(struct work_struct *work)
dev->info = NULL; dev->info = NULL;
/* Assume info structure is freed after this point */
framebuffer_release(info);
pr_debug("fb_info for /dev/fb%d has been freed", node);
/* ref taken in probe() as part of registering framebfufer */ /* ref taken in probe() as part of registering framebfufer */
kref_put(&dev->kref, ufx_free); kref_put(&dev->kref, ufx_free);
} }
...@@ -1169,11 +1167,13 @@ static int ufx_ops_release(struct fb_info *info, int user) ...@@ -1169,11 +1167,13 @@ static int ufx_ops_release(struct fb_info *info, int user)
{ {
struct ufx_data *dev = info->par; struct ufx_data *dev = info->par;
mutex_lock(&disconnect_mutex);
dev->fb_count--; dev->fb_count--;
/* We can't free fb_info here - fbmem will touch it when we return */ /* We can't free fb_info here - fbmem will touch it when we return */
if (dev->virtualized && (dev->fb_count == 0)) if (dev->virtualized && (dev->fb_count == 0))
schedule_delayed_work(&dev->free_framebuffer_work, HZ); ufx_free_framebuffer(dev);
if ((dev->fb_count == 0) && (info->fbdefio)) { if ((dev->fb_count == 0) && (info->fbdefio)) {
fb_deferred_io_cleanup(info); fb_deferred_io_cleanup(info);
...@@ -1186,6 +1186,8 @@ static int ufx_ops_release(struct fb_info *info, int user) ...@@ -1186,6 +1186,8 @@ static int ufx_ops_release(struct fb_info *info, int user)
kref_put(&dev->kref, ufx_free); kref_put(&dev->kref, ufx_free);
mutex_unlock(&disconnect_mutex);
return 0; return 0;
} }
...@@ -1292,6 +1294,7 @@ static const struct fb_ops ufx_ops = { ...@@ -1292,6 +1294,7 @@ static const struct fb_ops ufx_ops = {
.fb_blank = ufx_ops_blank, .fb_blank = ufx_ops_blank,
.fb_check_var = ufx_ops_check_var, .fb_check_var = ufx_ops_check_var,
.fb_set_par = ufx_ops_set_par, .fb_set_par = ufx_ops_set_par,
.fb_destroy = ufx_ops_destory,
}; };
/* Assumes &info->lock held by caller /* Assumes &info->lock held by caller
...@@ -1673,9 +1676,6 @@ static int ufx_usb_probe(struct usb_interface *interface, ...@@ -1673,9 +1676,6 @@ static int ufx_usb_probe(struct usb_interface *interface,
goto destroy_modedb; goto destroy_modedb;
} }
INIT_DELAYED_WORK(&dev->free_framebuffer_work,
ufx_free_framebuffer_work);
retval = ufx_reg_read(dev, 0x3000, &id_rev); retval = ufx_reg_read(dev, 0x3000, &id_rev);
check_warn_goto_error(retval, "error %d reading 0x3000 register from device", retval); check_warn_goto_error(retval, "error %d reading 0x3000 register from device", retval);
dev_dbg(dev->gdev, "ID_REV register value 0x%08x", id_rev); dev_dbg(dev->gdev, "ID_REV register value 0x%08x", id_rev);
...@@ -1748,10 +1748,12 @@ static int ufx_usb_probe(struct usb_interface *interface, ...@@ -1748,10 +1748,12 @@ static int ufx_usb_probe(struct usb_interface *interface,
static void ufx_usb_disconnect(struct usb_interface *interface) static void ufx_usb_disconnect(struct usb_interface *interface)
{ {
struct ufx_data *dev; struct ufx_data *dev;
struct fb_info *info;
mutex_lock(&disconnect_mutex); mutex_lock(&disconnect_mutex);
dev = usb_get_intfdata(interface); dev = usb_get_intfdata(interface);
info = dev->info;
pr_debug("USB disconnect starting\n"); pr_debug("USB disconnect starting\n");
...@@ -1765,12 +1767,15 @@ static void ufx_usb_disconnect(struct usb_interface *interface) ...@@ -1765,12 +1767,15 @@ static void ufx_usb_disconnect(struct usb_interface *interface)
/* if clients still have us open, will be freed on last close */ /* if clients still have us open, will be freed on last close */
if (dev->fb_count == 0) if (dev->fb_count == 0)
schedule_delayed_work(&dev->free_framebuffer_work, 0); ufx_free_framebuffer(dev);
/* release reference taken by kref_init in probe() */ /* this function will wait for all in-flight urbs to complete */
kref_put(&dev->kref, ufx_free); if (dev->urbs.count > 0)
ufx_free_urb_list(dev);
/* consider ufx_data freed */ pr_debug("freeing ufx_data %p", dev);
unregister_framebuffer(info);
mutex_unlock(&disconnect_mutex); mutex_unlock(&disconnect_mutex);
} }
......
...@@ -1055,7 +1055,8 @@ stifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ...@@ -1055,7 +1055,8 @@ stifb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{ {
struct stifb_info *fb = container_of(info, struct stifb_info, info); struct stifb_info *fb = container_of(info, struct stifb_info, info);
if (rect->rop != ROP_COPY) if (rect->rop != ROP_COPY ||
(fb->id == S9000_ID_HCRX && fb->info.var.bits_per_pixel == 32))
return cfb_fillrect(info, rect); return cfb_fillrect(info, rect);
SETUP_HW(fb); SETUP_HW(fb);
......
...@@ -376,7 +376,7 @@ static int xilinxfb_assign(struct platform_device *pdev, ...@@ -376,7 +376,7 @@ static int xilinxfb_assign(struct platform_device *pdev,
return rc; return rc;
} }
static int xilinxfb_release(struct device *dev) static void xilinxfb_release(struct device *dev)
{ {
struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev); struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev);
...@@ -402,8 +402,6 @@ static int xilinxfb_release(struct device *dev) ...@@ -402,8 +402,6 @@ static int xilinxfb_release(struct device *dev)
if (!(drvdata->flags & BUS_ACCESS_FLAG)) if (!(drvdata->flags & BUS_ACCESS_FLAG))
dcr_unmap(drvdata->dcr_host, drvdata->dcr_len); dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
#endif #endif
return 0;
} }
/* --------------------------------------------------------------------- /* ---------------------------------------------------------------------
...@@ -480,7 +478,9 @@ static int xilinxfb_of_probe(struct platform_device *pdev) ...@@ -480,7 +478,9 @@ static int xilinxfb_of_probe(struct platform_device *pdev)
static int xilinxfb_of_remove(struct platform_device *op) static int xilinxfb_of_remove(struct platform_device *op)
{ {
return xilinxfb_release(&op->dev); xilinxfb_release(&op->dev);
return 0;
} }
/* Match table for of_platform binding */ /* Match table for of_platform binding */
......
...@@ -555,7 +555,7 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { ...@@ -555,7 +555,7 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {
#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || \ #elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || \
defined(__hppa__) || defined(__sh__) || defined(__powerpc__) || \ defined(__hppa__) || defined(__sh__) || defined(__powerpc__) || \
defined(__arm__) || defined(__aarch64__) defined(__arm__) || defined(__aarch64__) || defined(__mips__)
#define fb_readb __raw_readb #define fb_readb __raw_readb
#define fb_readw __raw_readw #define fb_readw __raw_readw
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment