From 98f92d75823866db25aff032eaf1b5900b68b071 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 25 Feb 2019 20:50:19 +0100 Subject: [PATCH] 4.19-stable patches added patches: pinctrl-max77620-use-define-directive-for-max77620_pinconf_param-values.patch udlfb-handle-unplug-properly.patch --- ...ve-for-max77620_pinconf_param-values.patch | 55 ++++ queue-4.19/series | 2 + queue-4.19/udlfb-handle-unplug-properly.patch | 311 ++++++++++++++++++ 3 files changed, 368 insertions(+) create mode 100644 queue-4.19/pinctrl-max77620-use-define-directive-for-max77620_pinconf_param-values.patch create mode 100644 queue-4.19/udlfb-handle-unplug-properly.patch diff --git a/queue-4.19/pinctrl-max77620-use-define-directive-for-max77620_pinconf_param-values.patch b/queue-4.19/pinctrl-max77620-use-define-directive-for-max77620_pinconf_param-values.patch new file mode 100644 index 00000000000..8727393e3de --- /dev/null +++ b/queue-4.19/pinctrl-max77620-use-define-directive-for-max77620_pinconf_param-values.patch @@ -0,0 +1,55 @@ +From 1f60652dd586d1b3eee7c4602892a97a62fa937a Mon Sep 17 00:00:00 2001 +From: Nathan Chancellor +Date: Wed, 31 Oct 2018 17:50:21 -0700 +Subject: pinctrl: max77620: Use define directive for max77620_pinconf_param values + +From: Nathan Chancellor + +commit 1f60652dd586d1b3eee7c4602892a97a62fa937a upstream. + +Clang warns when one enumerated type is implicitly converted to another: + +drivers/pinctrl/pinctrl-max77620.c:56:12: warning: implicit conversion +from enumeration type 'enum max77620_pinconf_param' to different +enumeration type 'enum pin_config_param' [-Wenum-conversion] + .param = MAX77620_ACTIVE_FPS_SOURCE, + ^~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is expected that pinctrl drivers can extend pin_config_param because +of the gap between PIN_CONFIG_END and PIN_CONFIG_MAX so this conversion +isn't an issue. Most drivers that take advantage of this define the +PIN_CONFIG variables as constants, rather than enumerated values. Do the +same thing here so that Clang no longer warns. + +Link: https://github.com/ClangBuiltLinux/linux/issues/139 +Signed-off-by: Nathan Chancellor +Signed-off-by: Linus Walleij +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/pinctrl/pinctrl-max77620.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +--- a/drivers/pinctrl/pinctrl-max77620.c ++++ b/drivers/pinctrl/pinctrl-max77620.c +@@ -34,14 +34,12 @@ enum max77620_pin_ppdrv { + MAX77620_PIN_PP_DRV, + }; + +-enum max77620_pinconf_param { +- MAX77620_ACTIVE_FPS_SOURCE = PIN_CONFIG_END + 1, +- MAX77620_ACTIVE_FPS_POWER_ON_SLOTS, +- MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS, +- MAX77620_SUSPEND_FPS_SOURCE, +- MAX77620_SUSPEND_FPS_POWER_ON_SLOTS, +- MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS, +-}; ++#define MAX77620_ACTIVE_FPS_SOURCE (PIN_CONFIG_END + 1) ++#define MAX77620_ACTIVE_FPS_POWER_ON_SLOTS (PIN_CONFIG_END + 2) ++#define MAX77620_ACTIVE_FPS_POWER_DOWN_SLOTS (PIN_CONFIG_END + 3) ++#define MAX77620_SUSPEND_FPS_SOURCE (PIN_CONFIG_END + 4) ++#define MAX77620_SUSPEND_FPS_POWER_ON_SLOTS (PIN_CONFIG_END + 5) ++#define MAX77620_SUSPEND_FPS_POWER_DOWN_SLOTS (PIN_CONFIG_END + 6) + + struct max77620_pin_function { + const char *name; diff --git a/queue-4.19/series b/queue-4.19/series index 18672d267bd..e6455f04afb 100644 --- a/queue-4.19/series +++ b/queue-4.19/series @@ -148,3 +148,5 @@ netfilter-nft_compat-use-after-free-when-deleting-targets.patch netfilter-ipv6-don-t-preserve-original-oif-for-loopback-address.patch netfilter-nfnetlink_osf-add-missing-fmatch-check.patch netfilter-ipt_clusterip-fix-sleep-in-atomic-bug-in-clusterip_config_entry_put.patch +udlfb-handle-unplug-properly.patch +pinctrl-max77620-use-define-directive-for-max77620_pinconf_param-values.patch diff --git a/queue-4.19/udlfb-handle-unplug-properly.patch b/queue-4.19/udlfb-handle-unplug-properly.patch new file mode 100644 index 00000000000..918c6331cff --- /dev/null +++ b/queue-4.19/udlfb-handle-unplug-properly.patch @@ -0,0 +1,311 @@ +From 68a958a915ca912b8ce71b9eea7445996f6e681e Mon Sep 17 00:00:00 2001 +From: Mikulas Patocka +Date: Mon, 8 Oct 2018 12:57:34 +0200 +Subject: udlfb: handle unplug properly + +From: Mikulas Patocka + +commit 68a958a915ca912b8ce71b9eea7445996f6e681e upstream. + +The udlfb driver maintained an open count and cleaned up itself when the +count reached zero. But the console is also counted in the reference count +- so, if the user unplugged the device, the open count would not drop to +zero and the driver stayed loaded with console attached. If the user +re-plugged the adapter, it would create a device /dev/fb1, show green +screen and the access to the console would be lost. + +The framebuffer subsystem has reference counting on its own - in order to +fix the unplug bug, we rely the framebuffer reference counting. When the +user unplugs the adapter, we call unregister_framebuffer unconditionally. +unregister_framebuffer will unbind the console, wait until all users stop +using the framebuffer and then call the fb_destroy method. The fb_destroy +cleans up the USB driver. + +This patch makes the following changes: +* Drop dlfb->kref and rely on implicit framebuffer reference counting + instead. +* dlfb_usb_disconnect calls unregister_framebuffer, the rest of driver + cleanup is done in the function dlfb_ops_destroy. dlfb_ops_destroy will + be called by the framebuffer subsystem when no processes have the + framebuffer open or mapped. +* We don't use workqueue during initialization, but initialize directly + from dlfb_usb_probe. The workqueue could race with dlfb_usb_disconnect + and this racing would produce various kinds of memory corruption. +* We use usb_get_dev and usb_put_dev to make sure that the USB subsystem + doesn't free the device under us. + +Signed-off-by: Mikulas Patocka +cc: Dave Airlie +Cc: Bernie Thompson , +Cc: Ladislav Michl +Signed-off-by: Bartlomiej Zolnierkiewicz +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/video/fbdev/udlfb.c | 141 +++++++++++--------------------------------- + include/video/udlfb.h | 3 + 2 files changed, 37 insertions(+), 107 deletions(-) + +--- a/drivers/video/fbdev/udlfb.c ++++ b/drivers/video/fbdev/udlfb.c +@@ -916,8 +916,6 @@ static int dlfb_ops_open(struct fb_info + + dlfb->fb_count++; + +- kref_get(&dlfb->kref); +- + if (fb_defio && (info->fbdefio == NULL)) { + /* enable defio at last moment if not disabled by client */ + +@@ -940,14 +938,17 @@ static int dlfb_ops_open(struct fb_info + return 0; + } + +-/* +- * Called when all client interfaces to start transactions have been disabled, +- * and all references to our device instance (dlfb_data) are released. +- * Every transaction must have a reference, so we know are fully spun down +- */ +-static void dlfb_free(struct kref *kref) ++static void dlfb_ops_destroy(struct fb_info *info) + { +- struct dlfb_data *dlfb = container_of(kref, struct dlfb_data, kref); ++ struct dlfb_data *dlfb = info->par; ++ ++ if (info->cmap.len != 0) ++ fb_dealloc_cmap(&info->cmap); ++ if (info->monspecs.modedb) ++ fb_destroy_modedb(info->monspecs.modedb); ++ vfree(info->screen_base); ++ ++ fb_destroy_modelist(&info->modelist); + + while (!list_empty(&dlfb->deferred_free)) { + struct dlfb_deferred_free *d = list_entry(dlfb->deferred_free.next, struct dlfb_deferred_free, list); +@@ -957,40 +958,13 @@ static void dlfb_free(struct kref *kref) + } + vfree(dlfb->backing_buffer); + kfree(dlfb->edid); ++ usb_put_dev(dlfb->udev); + kfree(dlfb); +-} +- +-static void dlfb_free_framebuffer(struct dlfb_data *dlfb) +-{ +- struct fb_info *info = dlfb->info; +- +- if (info) { +- unregister_framebuffer(info); +- +- if (info->cmap.len != 0) +- fb_dealloc_cmap(&info->cmap); +- if (info->monspecs.modedb) +- fb_destroy_modedb(info->monspecs.modedb); +- vfree(info->screen_base); +- +- fb_destroy_modelist(&info->modelist); +- +- dlfb->info = NULL; +- +- /* Assume info structure is freed after this point */ +- framebuffer_release(info); +- } + +- /* ref taken in probe() as part of registering framebfufer */ +- kref_put(&dlfb->kref, dlfb_free); ++ /* Assume info structure is freed after this point */ ++ framebuffer_release(info); + } + +-static void dlfb_free_framebuffer_work(struct work_struct *work) +-{ +- struct dlfb_data *dlfb = container_of(work, struct dlfb_data, +- free_framebuffer_work.work); +- dlfb_free_framebuffer(dlfb); +-} + /* + * Assumes caller is holding info->lock mutex (for open and release at least) + */ +@@ -1000,10 +974,6 @@ static int dlfb_ops_release(struct fb_in + + dlfb->fb_count--; + +- /* We can't free fb_info here - fbmem will touch it when we return */ +- if (dlfb->virtualized && (dlfb->fb_count == 0)) +- schedule_delayed_work(&dlfb->free_framebuffer_work, HZ); +- + if ((dlfb->fb_count == 0) && (info->fbdefio)) { + fb_deferred_io_cleanup(info); + kfree(info->fbdefio); +@@ -1013,8 +983,6 @@ static int dlfb_ops_release(struct fb_in + + dev_dbg(info->dev, "release, user=%d count=%d\n", user, dlfb->fb_count); + +- kref_put(&dlfb->kref, dlfb_free); +- + return 0; + } + +@@ -1172,6 +1140,7 @@ static struct fb_ops dlfb_ops = { + .fb_blank = dlfb_ops_blank, + .fb_check_var = dlfb_ops_check_var, + .fb_set_par = dlfb_ops_set_par, ++ .fb_destroy = dlfb_ops_destroy, + }; + + +@@ -1615,12 +1584,13 @@ success: + return true; + } + +-static void dlfb_init_framebuffer_work(struct work_struct *work); +- + static int dlfb_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) + { ++ int i; ++ const struct device_attribute *attr; + struct dlfb_data *dlfb; ++ struct fb_info *info; + int retval = -ENOMEM; + struct usb_device *usbdev = interface_to_usbdev(intf); + +@@ -1631,10 +1601,9 @@ static int dlfb_usb_probe(struct usb_int + goto error; + } + +- kref_init(&dlfb->kref); /* matching kref_put in usb .disconnect fn */ + INIT_LIST_HEAD(&dlfb->deferred_free); + +- dlfb->udev = usbdev; ++ dlfb->udev = usb_get_dev(usbdev); + usb_set_intfdata(intf, dlfb); + + dev_dbg(&intf->dev, "console enable=%d\n", console); +@@ -1657,42 +1626,6 @@ static int dlfb_usb_probe(struct usb_int + } + + +- if (!dlfb_alloc_urb_list(dlfb, WRITES_IN_FLIGHT, MAX_TRANSFER)) { +- retval = -ENOMEM; +- dev_err(&intf->dev, "unable to allocate urb list\n"); +- goto error; +- } +- +- kref_get(&dlfb->kref); /* matching kref_put in free_framebuffer_work */ +- +- /* We don't register a new USB class. Our client interface is dlfbev */ +- +- /* Workitem keep things fast & simple during USB enumeration */ +- INIT_DELAYED_WORK(&dlfb->init_framebuffer_work, +- dlfb_init_framebuffer_work); +- schedule_delayed_work(&dlfb->init_framebuffer_work, 0); +- +- return 0; +- +-error: +- if (dlfb) { +- +- kref_put(&dlfb->kref, dlfb_free); /* last ref from kref_init */ +- +- /* dev has been deallocated. Do not dereference */ +- } +- +- return retval; +-} +- +-static void dlfb_init_framebuffer_work(struct work_struct *work) +-{ +- int i, retval; +- struct fb_info *info; +- const struct device_attribute *attr; +- struct dlfb_data *dlfb = container_of(work, struct dlfb_data, +- init_framebuffer_work.work); +- + /* allocates framebuffer driver structure, not framebuffer memory */ + info = framebuffer_alloc(0, &dlfb->udev->dev); + if (!info) { +@@ -1706,17 +1639,22 @@ static void dlfb_init_framebuffer_work(s + dlfb->ops = dlfb_ops; + info->fbops = &dlfb->ops; + ++ INIT_LIST_HEAD(&info->modelist); ++ ++ if (!dlfb_alloc_urb_list(dlfb, WRITES_IN_FLIGHT, MAX_TRANSFER)) { ++ retval = -ENOMEM; ++ dev_err(&intf->dev, "unable to allocate urb list\n"); ++ goto error; ++ } ++ ++ /* We don't register a new USB class. Our client interface is dlfbev */ ++ + retval = fb_alloc_cmap(&info->cmap, 256, 0); + if (retval < 0) { + dev_err(info->device, "cmap allocation failed: %d\n", retval); + goto error; + } + +- INIT_DELAYED_WORK(&dlfb->free_framebuffer_work, +- dlfb_free_framebuffer_work); +- +- INIT_LIST_HEAD(&info->modelist); +- + retval = dlfb_setup_modes(dlfb, info, NULL, 0); + if (retval != 0) { + dev_err(info->device, +@@ -1760,10 +1698,16 @@ static void dlfb_init_framebuffer_work(s + dev_name(info->dev), info->var.xres, info->var.yres, + ((dlfb->backing_buffer) ? + info->fix.smem_len * 2 : info->fix.smem_len) >> 10); +- return; ++ return 0; + + error: +- dlfb_free_framebuffer(dlfb); ++ if (dlfb->info) { ++ dlfb_ops_destroy(dlfb->info); ++ } else if (dlfb) { ++ usb_put_dev(dlfb->udev); ++ kfree(dlfb); ++ } ++ return retval; + } + + static void dlfb_usb_disconnect(struct usb_interface *intf) +@@ -1791,20 +1735,9 @@ static void dlfb_usb_disconnect(struct u + for (i = 0; i < ARRAY_SIZE(fb_device_attrs); i++) + device_remove_file(info->dev, &fb_device_attrs[i]); + device_remove_bin_file(info->dev, &edid_attr); +- unlink_framebuffer(info); + } + +- usb_set_intfdata(intf, NULL); +- dlfb->udev = NULL; +- +- /* if clients still have us open, will be freed on last close */ +- if (dlfb->fb_count == 0) +- schedule_delayed_work(&dlfb->free_framebuffer_work, 0); +- +- /* release reference taken by kref_init in probe() */ +- kref_put(&dlfb->kref, dlfb_free); +- +- /* consider dlfb_data freed */ ++ unregister_framebuffer(info); + } + + static struct usb_driver dlfb_driver = { +--- a/include/video/udlfb.h ++++ b/include/video/udlfb.h +@@ -36,12 +36,9 @@ struct dlfb_data { + struct usb_device *udev; + struct fb_info *info; + struct urb_list urbs; +- struct kref kref; + char *backing_buffer; + int fb_count; + bool virtualized; /* true when physical usb device not present */ +- struct delayed_work init_framebuffer_work; +- 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 */ + char *edid; /* null until we read edid from hw or get from sysfs */ -- 2.47.3