diff mbox

[2/9] drm/xen-front: Implement Xen bus state handling

Message ID 1519200222-20623-3-git-send-email-andr2000@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Oleksandr Andrushchenko Feb. 21, 2018, 8:03 a.m. UTC
From: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>

Initial handling for Xen bus states: implement
Xen bus state machine for the frontend driver according to
the state diagram and recovery flow from display para-virtualized
protocol: xen/interface/io/displif.h.

Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
---
 drivers/gpu/drm/xen/xen_drm_front.c | 124 +++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/xen/xen_drm_front.h |  26 ++++++++
 2 files changed, 149 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/xen/xen_drm_front.h

Comments

Jürgen Groß Feb. 21, 2018, 8:23 a.m. UTC | #1
On 21/02/18 09:03, Oleksandr Andrushchenko wrote:
> From: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> 
> Initial handling for Xen bus states: implement
> Xen bus state machine for the frontend driver according to
> the state diagram and recovery flow from display para-virtualized
> protocol: xen/interface/io/displif.h.
> 
> Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
> ---
>  drivers/gpu/drm/xen/xen_drm_front.c | 124 +++++++++++++++++++++++++++++++++++-
>  drivers/gpu/drm/xen/xen_drm_front.h |  26 ++++++++
>  2 files changed, 149 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/xen/xen_drm_front.h
> 
> diff --git a/drivers/gpu/drm/xen/xen_drm_front.c b/drivers/gpu/drm/xen/xen_drm_front.c
> index fd372fb464a1..d0306f9d660d 100644
> --- a/drivers/gpu/drm/xen/xen_drm_front.c
> +++ b/drivers/gpu/drm/xen/xen_drm_front.c
> @@ -24,19 +24,141 @@
>  
>  #include <xen/interface/io/displif.h>
>  
> +#include "xen_drm_front.h"
> +
> +static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
> +{
> +}
> +
> +static int backend_on_initwait(struct xen_drm_front_info *front_info)
> +{
> +	return 0;
> +}
> +
> +static int backend_on_connected(struct xen_drm_front_info *front_info)
> +{
> +	return 0;
> +}
> +
> +static void backend_on_disconnected(struct xen_drm_front_info *front_info)
> +{
> +	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
> +}
> +
>  static void backend_on_changed(struct xenbus_device *xb_dev,
>  		enum xenbus_state backend_state)
>  {
> +	struct xen_drm_front_info *front_info = dev_get_drvdata(&xb_dev->dev);
> +	int ret;
> +
> +	DRM_DEBUG("Backend state is %s, front is %s\n",
> +			xenbus_strstate(backend_state),
> +			xenbus_strstate(xb_dev->state));
> +
> +	switch (backend_state) {
> +	case XenbusStateReconfiguring:
> +		/* fall through */
> +	case XenbusStateReconfigured:
> +		/* fall through */
> +	case XenbusStateInitialised:
> +		break;
> +
> +	case XenbusStateInitialising:
> +		/* recovering after backend unexpected closure */
> +		backend_on_disconnected(front_info);
> +		break;
> +
> +	case XenbusStateInitWait:
> +		/* recovering after backend unexpected closure */
> +		backend_on_disconnected(front_info);
> +		if (xb_dev->state != XenbusStateInitialising)
> +			break;
> +
> +		ret = backend_on_initwait(front_info);
> +		if (ret < 0)
> +			xenbus_dev_fatal(xb_dev, ret, "initializing frontend");
> +		else
> +			xenbus_switch_state(xb_dev, XenbusStateInitialised);
> +		break;
> +
> +	case XenbusStateConnected:
> +		if (xb_dev->state != XenbusStateInitialised)
> +			break;
> +
> +		ret = backend_on_connected(front_info);
> +		if (ret < 0)
> +			xenbus_dev_fatal(xb_dev, ret, "initializing DRM driver");
> +		else
> +			xenbus_switch_state(xb_dev, XenbusStateConnected);
> +		break;
> +
> +	case XenbusStateClosing:
> +		/*
> +		 * in this state backend starts freeing resources,
> +		 * so let it go into closed state, so we can also
> +		 * remove ours
> +		 */
> +		break;
> +
> +	case XenbusStateUnknown:
> +		/* fall through */
> +	case XenbusStateClosed:
> +		if (xb_dev->state == XenbusStateClosed)
> +			break;
> +
> +		backend_on_disconnected(front_info);
> +		break;
> +	}
>  }
>  
>  static int xen_drv_probe(struct xenbus_device *xb_dev,
>  		const struct xenbus_device_id *id)
>  {
> -	return 0;
> +	struct xen_drm_front_info *front_info;
> +
> +	front_info = devm_kzalloc(&xb_dev->dev,
> +			sizeof(*front_info), GFP_KERNEL);
> +	if (!front_info) {
> +		xenbus_dev_fatal(xb_dev, -ENOMEM, "allocating device memory");

No need for message in case of allocation failure: this is
handled in memory allocation already.


Juergen
Oleksandr Andrushchenko Feb. 21, 2018, 8:50 a.m. UTC | #2
On 02/21/2018 10:23 AM, Juergen Gross wrote:
> On 21/02/18 09:03, Oleksandr Andrushchenko wrote:
>> From: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
>>
>> Initial handling for Xen bus states: implement
>> Xen bus state machine for the frontend driver according to
>> the state diagram and recovery flow from display para-virtualized
>> protocol: xen/interface/io/displif.h.
>>
>> Signed-off-by: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
>> ---
>>   drivers/gpu/drm/xen/xen_drm_front.c | 124 +++++++++++++++++++++++++++++++++++-
>>   drivers/gpu/drm/xen/xen_drm_front.h |  26 ++++++++
>>   2 files changed, 149 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/gpu/drm/xen/xen_drm_front.h
>>
>> diff --git a/drivers/gpu/drm/xen/xen_drm_front.c b/drivers/gpu/drm/xen/xen_drm_front.c
>> index fd372fb464a1..d0306f9d660d 100644
>> --- a/drivers/gpu/drm/xen/xen_drm_front.c
>> +++ b/drivers/gpu/drm/xen/xen_drm_front.c
>> @@ -24,19 +24,141 @@
>>   
>>   #include <xen/interface/io/displif.h>
>>   
>> +#include "xen_drm_front.h"
>> +
>> +static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
>> +{
>> +}
>> +
>> +static int backend_on_initwait(struct xen_drm_front_info *front_info)
>> +{
>> +	return 0;
>> +}
>> +
>> +static int backend_on_connected(struct xen_drm_front_info *front_info)
>> +{
>> +	return 0;
>> +}
>> +
>> +static void backend_on_disconnected(struct xen_drm_front_info *front_info)
>> +{
>> +	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
>> +}
>> +
>>   static void backend_on_changed(struct xenbus_device *xb_dev,
>>   		enum xenbus_state backend_state)
>>   {
>> +	struct xen_drm_front_info *front_info = dev_get_drvdata(&xb_dev->dev);
>> +	int ret;
>> +
>> +	DRM_DEBUG("Backend state is %s, front is %s\n",
>> +			xenbus_strstate(backend_state),
>> +			xenbus_strstate(xb_dev->state));
>> +
>> +	switch (backend_state) {
>> +	case XenbusStateReconfiguring:
>> +		/* fall through */
>> +	case XenbusStateReconfigured:
>> +		/* fall through */
>> +	case XenbusStateInitialised:
>> +		break;
>> +
>> +	case XenbusStateInitialising:
>> +		/* recovering after backend unexpected closure */
>> +		backend_on_disconnected(front_info);
>> +		break;
>> +
>> +	case XenbusStateInitWait:
>> +		/* recovering after backend unexpected closure */
>> +		backend_on_disconnected(front_info);
>> +		if (xb_dev->state != XenbusStateInitialising)
>> +			break;
>> +
>> +		ret = backend_on_initwait(front_info);
>> +		if (ret < 0)
>> +			xenbus_dev_fatal(xb_dev, ret, "initializing frontend");
>> +		else
>> +			xenbus_switch_state(xb_dev, XenbusStateInitialised);
>> +		break;
>> +
>> +	case XenbusStateConnected:
>> +		if (xb_dev->state != XenbusStateInitialised)
>> +			break;
>> +
>> +		ret = backend_on_connected(front_info);
>> +		if (ret < 0)
>> +			xenbus_dev_fatal(xb_dev, ret, "initializing DRM driver");
>> +		else
>> +			xenbus_switch_state(xb_dev, XenbusStateConnected);
>> +		break;
>> +
>> +	case XenbusStateClosing:
>> +		/*
>> +		 * in this state backend starts freeing resources,
>> +		 * so let it go into closed state, so we can also
>> +		 * remove ours
>> +		 */
>> +		break;
>> +
>> +	case XenbusStateUnknown:
>> +		/* fall through */
>> +	case XenbusStateClosed:
>> +		if (xb_dev->state == XenbusStateClosed)
>> +			break;
>> +
>> +		backend_on_disconnected(front_info);
>> +		break;
>> +	}
>>   }
>>   
>>   static int xen_drv_probe(struct xenbus_device *xb_dev,
>>   		const struct xenbus_device_id *id)
>>   {
>> -	return 0;
>> +	struct xen_drm_front_info *front_info;
>> +
>> +	front_info = devm_kzalloc(&xb_dev->dev,
>> +			sizeof(*front_info), GFP_KERNEL);
>> +	if (!front_info) {
>> +		xenbus_dev_fatal(xb_dev, -ENOMEM, "allocating device memory");
> No need for message in case of allocation failure: this is
> handled in memory allocation already.
Will remove, thank you
>
> Juergen
diff mbox

Patch

diff --git a/drivers/gpu/drm/xen/xen_drm_front.c b/drivers/gpu/drm/xen/xen_drm_front.c
index fd372fb464a1..d0306f9d660d 100644
--- a/drivers/gpu/drm/xen/xen_drm_front.c
+++ b/drivers/gpu/drm/xen/xen_drm_front.c
@@ -24,19 +24,141 @@ 
 
 #include <xen/interface/io/displif.h>
 
+#include "xen_drm_front.h"
+
+static void xen_drv_remove_internal(struct xen_drm_front_info *front_info)
+{
+}
+
+static int backend_on_initwait(struct xen_drm_front_info *front_info)
+{
+	return 0;
+}
+
+static int backend_on_connected(struct xen_drm_front_info *front_info)
+{
+	return 0;
+}
+
+static void backend_on_disconnected(struct xen_drm_front_info *front_info)
+{
+	xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising);
+}
+
 static void backend_on_changed(struct xenbus_device *xb_dev,
 		enum xenbus_state backend_state)
 {
+	struct xen_drm_front_info *front_info = dev_get_drvdata(&xb_dev->dev);
+	int ret;
+
+	DRM_DEBUG("Backend state is %s, front is %s\n",
+			xenbus_strstate(backend_state),
+			xenbus_strstate(xb_dev->state));
+
+	switch (backend_state) {
+	case XenbusStateReconfiguring:
+		/* fall through */
+	case XenbusStateReconfigured:
+		/* fall through */
+	case XenbusStateInitialised:
+		break;
+
+	case XenbusStateInitialising:
+		/* recovering after backend unexpected closure */
+		backend_on_disconnected(front_info);
+		break;
+
+	case XenbusStateInitWait:
+		/* recovering after backend unexpected closure */
+		backend_on_disconnected(front_info);
+		if (xb_dev->state != XenbusStateInitialising)
+			break;
+
+		ret = backend_on_initwait(front_info);
+		if (ret < 0)
+			xenbus_dev_fatal(xb_dev, ret, "initializing frontend");
+		else
+			xenbus_switch_state(xb_dev, XenbusStateInitialised);
+		break;
+
+	case XenbusStateConnected:
+		if (xb_dev->state != XenbusStateInitialised)
+			break;
+
+		ret = backend_on_connected(front_info);
+		if (ret < 0)
+			xenbus_dev_fatal(xb_dev, ret, "initializing DRM driver");
+		else
+			xenbus_switch_state(xb_dev, XenbusStateConnected);
+		break;
+
+	case XenbusStateClosing:
+		/*
+		 * in this state backend starts freeing resources,
+		 * so let it go into closed state, so we can also
+		 * remove ours
+		 */
+		break;
+
+	case XenbusStateUnknown:
+		/* fall through */
+	case XenbusStateClosed:
+		if (xb_dev->state == XenbusStateClosed)
+			break;
+
+		backend_on_disconnected(front_info);
+		break;
+	}
 }
 
 static int xen_drv_probe(struct xenbus_device *xb_dev,
 		const struct xenbus_device_id *id)
 {
-	return 0;
+	struct xen_drm_front_info *front_info;
+
+	front_info = devm_kzalloc(&xb_dev->dev,
+			sizeof(*front_info), GFP_KERNEL);
+	if (!front_info) {
+		xenbus_dev_fatal(xb_dev, -ENOMEM, "allocating device memory");
+		return -ENOMEM;
+	}
+
+	front_info->xb_dev = xb_dev;
+	dev_set_drvdata(&xb_dev->dev, front_info);
+	return xenbus_switch_state(xb_dev, XenbusStateInitialising);
 }
 
 static int xen_drv_remove(struct xenbus_device *dev)
 {
+	struct xen_drm_front_info *front_info = dev_get_drvdata(&dev->dev);
+	int to = 100;
+
+	xenbus_switch_state(dev, XenbusStateClosing);
+
+	/*
+	 * On driver removal it is disconnected from XenBus,
+	 * so no backend state change events come via .otherend_changed
+	 * callback. This prevents us from exiting gracefully, e.g.
+	 * signaling the backend to free event channels, waiting for its
+	 * state to change to XenbusStateClosed and cleaning at our end.
+	 * Normally when front driver removed backend will finally go into
+	 * XenbusStateInitWait state.
+	 *
+	 * Workaround: read backend's state manually and wait with time-out.
+	 */
+	while ((xenbus_read_unsigned(front_info->xb_dev->otherend,
+			"state", XenbusStateUnknown) != XenbusStateInitWait) &&
+			to--)
+		msleep(10);
+
+	if (!to)
+		DRM_ERROR("Backend state is %s while removing driver\n",
+			xenbus_strstate(xenbus_read_unsigned(
+					front_info->xb_dev->otherend,
+					"state", XenbusStateUnknown)));
+
+	xen_drv_remove_internal(front_info);
+	xenbus_frontend_closed(dev);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/xen/xen_drm_front.h b/drivers/gpu/drm/xen/xen_drm_front.h
new file mode 100644
index 000000000000..8af46850f126
--- /dev/null
+++ b/drivers/gpu/drm/xen/xen_drm_front.h
@@ -0,0 +1,26 @@ 
+/*
+ *  Xen para-virtual DRM device
+ *
+ *   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
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ * Copyright (C) 2016-2018 EPAM Systems Inc.
+ *
+ * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com>
+ */
+
+#ifndef __XEN_DRM_FRONT_H_
+#define __XEN_DRM_FRONT_H_
+
+struct xen_drm_front_info {
+	struct xenbus_device *xb_dev;
+};
+
+#endif /* __XEN_DRM_FRONT_H_ */