Skip to content

Commit

Permalink
Merge tag 'fbdev-for-6.1-rc3' of git://git.kernel.org/pub/scm/linux/k…
Browse files Browse the repository at this point in the history
…ernel/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
  • Loading branch information
Linus Torvalds committed Oct 30, 2022
2 parents 9f12754 + 3c6bf6b commit b72018a
Show file tree
Hide file tree
Showing 11 changed files with 47 additions and 38 deletions.
2 changes: 1 addition & 1 deletion drivers/usb/misc/sisusbvga/sisusb_struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ struct SiS_Ext {
unsigned char VB_ExtTVYFilterIndex;
unsigned char VB_ExtTVYFilterIndexROM661;
unsigned char REFindex;
char ROMMODEIDX661;
signed char ROMMODEIDX661;
};

struct SiS_Ext2 {
Expand Down
2 changes: 2 additions & 0 deletions drivers/video/fbdev/cyber2000fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1796,6 +1796,7 @@ static int cyberpro_pci_probe(struct pci_dev *dev,
failed_regions:
cyberpro_free_fb_info(cfb);
failed_release:
pci_disable_device(dev);
return err;
}

Expand All @@ -1812,6 +1813,7 @@ static void cyberpro_pci_remove(struct pci_dev *dev)
int_cfb_info = NULL;

pci_release_regions(dev);
pci_disable_device(dev);
}
}

Expand Down
3 changes: 2 additions & 1 deletion drivers/video/fbdev/da8xx-fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,8 @@ static int fb_remove(struct platform_device *dev)
if (par->lcd_supply) {
ret = regulator_disable(par->lcd_supply);
if (ret)
return ret;
dev_warn(&dev->dev, "Failed to disable regulator (%pe)\n",
ERR_PTR(ret));
}

lcd_disable_raster(DA8XX_FRAME_WAIT);
Expand Down
4 changes: 2 additions & 2 deletions drivers/video/fbdev/gbefb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
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 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);
Expand Down
2 changes: 1 addition & 1 deletion drivers/video/fbdev/sis/sis_accel.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ SiS310SubsequentScreenToScreenCopy(struct sis_video_info *ivideo, int src_x, int
* and destination blitting areas overlap and
* adapt the bitmap addresses synchronously
* 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.
*/
if((mymax - mymin) < height) {
Expand Down
2 changes: 1 addition & 1 deletion drivers/video/fbdev/sis/vstruct.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ struct SiS_Ext {
unsigned char VB_ExtTVYFilterIndex;
unsigned char VB_ExtTVYFilterIndexROM661;
unsigned char REFindex;
char ROMMODEIDX661;
signed char ROMMODEIDX661;
};

struct SiS_Ext2 {
Expand Down
2 changes: 1 addition & 1 deletion drivers/video/fbdev/sm501fb.c
Original file line number Diff line number Diff line change
Expand Up @@ -1166,7 +1166,7 @@ static ssize_t sm501fb_crtsrc_show(struct device *dev,
ctrl = smc501_readl(info->regs + SM501_DC_CRT_CONTROL);
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
Expand Down
55 changes: 30 additions & 25 deletions drivers/video/fbdev/smscufx.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ struct ufx_data {
struct kref kref;
int fb_count;
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 lost_pixels; /* 1 = a render op failed. Need screen refresh */
u8 *edid; /* null until we read edid from hw or get from sysfs */
Expand Down Expand Up @@ -1117,15 +1116,24 @@ static void ufx_free(struct kref *kref)
{
struct ufx_data *dev = container_of(kref, struct ufx_data, kref);

/* this function will wait for all in-flight urbs to complete */
if (dev->urbs.count > 0)
ufx_free_urb_list(dev);
kfree(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)
{
struct urb_node *unode = container_of(work, struct urb_node,
Expand All @@ -1134,14 +1142,9 @@ static void ufx_release_urb_work(struct work_struct *work)
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;
int node = info->node;

unregister_framebuffer(info);

if (info->cmap.len != 0)
fb_dealloc_cmap(&info->cmap);
Expand All @@ -1153,11 +1156,6 @@ static void ufx_free_framebuffer_work(struct work_struct *work)

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 */
kref_put(&dev->kref, ufx_free);
}
Expand All @@ -1169,11 +1167,13 @@ static int ufx_ops_release(struct fb_info *info, int user)
{
struct ufx_data *dev = info->par;

mutex_lock(&disconnect_mutex);

dev->fb_count--;

/* We can't free fb_info here - fbmem will touch it when we return */
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)) {
fb_deferred_io_cleanup(info);
Expand All @@ -1186,6 +1186,8 @@ static int ufx_ops_release(struct fb_info *info, int user)

kref_put(&dev->kref, ufx_free);

mutex_unlock(&disconnect_mutex);

return 0;
}

Expand Down Expand Up @@ -1292,6 +1294,7 @@ static const struct fb_ops ufx_ops = {
.fb_blank = ufx_ops_blank,
.fb_check_var = ufx_ops_check_var,
.fb_set_par = ufx_ops_set_par,
.fb_destroy = ufx_ops_destory,
};

/* Assumes &info->lock held by caller
Expand Down Expand Up @@ -1673,9 +1676,6 @@ static int ufx_usb_probe(struct usb_interface *interface,
goto destroy_modedb;
}

INIT_DELAYED_WORK(&dev->free_framebuffer_work,
ufx_free_framebuffer_work);

retval = ufx_reg_read(dev, 0x3000, &id_rev);
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);
Expand Down Expand Up @@ -1748,10 +1748,12 @@ static int ufx_usb_probe(struct usb_interface *interface,
static void ufx_usb_disconnect(struct usb_interface *interface)
{
struct ufx_data *dev;
struct fb_info *info;

mutex_lock(&disconnect_mutex);

dev = usb_get_intfdata(interface);
info = dev->info;

pr_debug("USB disconnect starting\n");

Expand All @@ -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 (dev->fb_count == 0)
schedule_delayed_work(&dev->free_framebuffer_work, 0);
ufx_free_framebuffer(dev);

/* release reference taken by kref_init in probe() */
kref_put(&dev->kref, ufx_free);
/* this function will wait for all in-flight urbs to complete */
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);
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/video/fbdev/stifb.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

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);

SETUP_HW(fb);
Expand Down
8 changes: 4 additions & 4 deletions drivers/video/fbdev/xilinxfb.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ static int xilinxfb_assign(struct platform_device *pdev,
return rc;
}

static int xilinxfb_release(struct device *dev)
static void xilinxfb_release(struct device *dev)
{
struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev);

Expand All @@ -402,8 +402,6 @@ static int xilinxfb_release(struct device *dev)
if (!(drvdata->flags & BUS_ACCESS_FLAG))
dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
#endif

return 0;
}

/* ---------------------------------------------------------------------
Expand Down Expand Up @@ -480,7 +478,9 @@ static int xilinxfb_of_probe(struct platform_device *pdev)

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 */
Expand Down
2 changes: 1 addition & 1 deletion include/linux/fb.h
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ static inline struct apertures_struct *alloc_apertures(unsigned int max_num) {

#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__) || \
defined(__hppa__) || defined(__sh__) || defined(__powerpc__) || \
defined(__arm__) || defined(__aarch64__)
defined(__arm__) || defined(__aarch64__) || defined(__mips__)

#define fb_readb __raw_readb
#define fb_readw __raw_readw
Expand Down

0 comments on commit b72018a

Please sign in to comment.