late_register() and early_unregister() callbacks have been introduced for connectors, let do the same for encoders, crcts and planes. Like for the previously introduced functions they are called right after drm device registration and before unregistration.
Those new callbacks allow to defer actions after drm_dev_register(). For example sti driver use them to initialize debugfs because it require to have register a drm device to get the root debug file.
Benjamin Gaignard (3): drm: Add callbacks for late registering drm: sti: use late_register and early_unregister callbacks drm: sti: rework init sequence
drivers/gpu/drm/drm_drv.c | 42 +++++++++++ drivers/gpu/drm/sti/sti_compositor.c | 20 +++++ drivers/gpu/drm/sti/sti_compositor.h | 3 + drivers/gpu/drm/sti/sti_crtc.c | 12 +++ drivers/gpu/drm/sti/sti_cursor.c | 32 +++++++- drivers/gpu/drm/sti/sti_drv.c | 140 +++++++++++++++++++++++++---------- drivers/gpu/drm/sti/sti_drv.h | 1 + drivers/gpu/drm/sti/sti_dvo.c | 25 +++---- drivers/gpu/drm/sti/sti_gdp.c | 32 +++++++- drivers/gpu/drm/sti/sti_hda.c | 26 +++---- drivers/gpu/drm/sti/sti_hdmi.c | 40 +++++----- drivers/gpu/drm/sti/sti_hqvdp.c | 32 +++++++- drivers/gpu/drm/sti/sti_mixer.c | 5 +- drivers/gpu/drm/sti/sti_mixer.h | 2 + drivers/gpu/drm/sti/sti_plane.c | 24 +----- drivers/gpu/drm/sti/sti_plane.h | 7 +- drivers/gpu/drm/sti/sti_tvout.c | 36 +++++++-- drivers/gpu/drm/sti/sti_vid.c | 5 +- drivers/gpu/drm/sti/sti_vid.h | 2 + include/drm/drm_crtc.h | 77 +++++++++++++++++++ 20 files changed, 420 insertions(+), 143 deletions(-)
Like what has been done for connectors add callbacks on encoder, crtc and plane to let driver do actions after drm device registration.
Correspondingly, add callbacks called before unregister drm device.
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org --- drivers/gpu/drm/drm_drv.c | 42 ++++++++++++++++++++++++++ include/drm/drm_crtc.h | 77 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+)
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index c7101c0..b4f7f62 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -666,6 +666,9 @@ EXPORT_SYMBOL(drm_dev_unref); int drm_dev_register(struct drm_device *dev, unsigned long flags) { int ret; + struct drm_crtc *crtc; + struct drm_plane *plane; + struct drm_encoder *encoder;
mutex_lock(&drm_global_mutex);
@@ -690,6 +693,27 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_connector_register_all(dev);
+ drm_for_each_crtc(crtc, dev) { + if (crtc->funcs->late_register) + ret = crtc->funcs->late_register(crtc); + if (ret) + goto err_minors; + } + + drm_for_each_plane(plane, dev) { + if (plane->funcs->late_register) + ret = plane->funcs->late_register(plane); + if (ret) + goto err_minors; + } + + drm_for_each_encoder(encoder, dev) { + if (encoder->funcs->late_register) + ret = encoder->funcs->late_register(encoder); + if (ret) + goto err_minors; + } + ret = 0; goto out_unlock;
@@ -717,12 +741,30 @@ EXPORT_SYMBOL(drm_dev_register); void drm_dev_unregister(struct drm_device *dev) { struct drm_map_list *r_list, *list_temp; + struct drm_crtc *crtc; + struct drm_plane *plane; + struct drm_encoder *encoder;
drm_lastclose(dev);
if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_connector_unregister_all(dev);
+ drm_for_each_crtc(crtc, dev) { + if (crtc->funcs->early_unregister) + crtc->funcs->early_unregister(crtc); + } + + drm_for_each_plane(plane, dev) { + if (plane->funcs->early_unregister) + plane->funcs->early_unregister(plane); + } + + drm_for_each_encoder(encoder, dev) { + if (encoder->funcs->early_unregister) + encoder->funcs->early_unregister(encoder); + } + if (dev->driver->unload) dev->driver->unload(dev);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index c273497..b4ab33f 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -704,6 +704,32 @@ struct drm_crtc_funcs { const struct drm_crtc_state *state, struct drm_property *property, uint64_t *val); + + /** + * @late_register: + * + * This optional hook can be used to register additional userspace + * interfaces attached to the crtc like debugfs interfaces. + * It is called late in the driver load sequence from drm_dev_register(). + * Everything added from this callback should be unregistered in + * the early_unregister callback. + * + * Returns: + * + * 0 on success, or a negative error code on failure. + */ + int (*late_register)(struct drm_crtc *crtc); + + /** + * @early_unregister: + * + * This optional hook should be used to unregister the additional + * userspace interfaces attached to the crtc from + * late_unregister(). It is called from drm_dev_unregister(), + * early in the driver unload sequence to disable userspace access + * before data structures are torndown. + */ + void (*early_unregister)(struct drm_crtc *crtc); };
/** @@ -1127,6 +1153,32 @@ struct drm_encoder_funcs { * hotplugged in DRM. */ void (*destroy)(struct drm_encoder *encoder); + + /** + * @late_register: + * + * This optional hook can be used to register additional userspace + * interfaces attached to the encoder like debugfs interfaces. + * It is called late in the driver load sequence from drm_dev_register(). + * Everything added from this callback should be unregistered in + * the early_unregister callback. + * + * Returns: + * + * 0 on success, or a negative error code on failure. + */ + int (*late_register)(struct drm_encoder *encoder); + + /** + * @early_unregister: + * + * This optional hook should be used to unregister the additional + * userspace interfaces attached to the encoder from + * late_unregister(). It is called from drm_dev_unregister(), + * early in the driver unload sequence to disable userspace access + * before data structures are torndown. + */ + void (*early_unregister)(struct drm_encoder *encoder); };
#define DRM_CONNECTOR_MAX_ENCODER 3 @@ -1570,6 +1622,31 @@ struct drm_plane_funcs { const struct drm_plane_state *state, struct drm_property *property, uint64_t *val); + /** + * @late_register: + * + * This optional hook can be used to register additional userspace + * interfaces attached to the plane like debugfs interfaces. + * It is called late in the driver load sequence from drm_dev_register(). + * Everything added from this callback should be unregistered in + * the early_unregister callback. + * + * Returns: + * + * 0 on success, or a negative error code on failure. + */ + int (*late_register)(struct drm_plane *plane); + + /** + * @early_unregister: + * + * This optional hook should be used to unregister the additional + * userspace interfaces attached to the plane from + * late_unregister(). It is called from drm_dev_unregister(), + * early in the driver unload sequence to disable userspace access + * before data structures are torndown. + */ + void (*early_unregister)(struct drm_plane *plane); };
enum drm_plane_type {
On Mon, Jun 20, 2016 at 05:22:55PM +0200, Benjamin Gaignard wrote:
Like what has been done for connectors add callbacks on encoder, crtc and plane to let driver do actions after drm device registration.
Correspondingly, add callbacks called before unregister drm device.
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org
drivers/gpu/drm/drm_drv.c | 42 ++++++++++++++++++++++++++ include/drm/drm_crtc.h | 77 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+)
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index c7101c0..b4f7f62 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -666,6 +666,9 @@ EXPORT_SYMBOL(drm_dev_unref); int drm_dev_register(struct drm_device *dev, unsigned long flags) { int ret;
struct drm_crtc *crtc;
struct drm_plane *plane;
struct drm_encoder *encoder;
mutex_lock(&drm_global_mutex);
@@ -690,6 +693,27 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_connector_register_all(dev);
Look above for the ouch.
- drm_for_each_crtc(crtc, dev) {
if (crtc->funcs->late_register)
ret = crtc->funcs->late_register(crtc);
if (ret)
goto err_minors;
- }
For the sake of conformity, is it worth adding drm_crtc_register_all() et all?
Then a drm_modeset_register_all ? (i.e. if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_modeset_register_all(dev); -> { connector, encoder, plane, crtc )
Also, is the logical order
drm_connector_register_all(); drm_encoder_register_all(); drm_plane_register_all(); drm_crtc_register_all();
or the other way around (basically working from output back to input, or input to output)? -Chris
On Mon, Jun 20, 2016 at 04:30:36PM +0100, Chris Wilson wrote:
On Mon, Jun 20, 2016 at 05:22:55PM +0200, Benjamin Gaignard wrote:
Like what has been done for connectors add callbacks on encoder, crtc and plane to let driver do actions after drm device registration.
Correspondingly, add callbacks called before unregister drm device.
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org
drivers/gpu/drm/drm_drv.c | 42 ++++++++++++++++++++++++++ include/drm/drm_crtc.h | 77 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+)
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index c7101c0..b4f7f62 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -666,6 +666,9 @@ EXPORT_SYMBOL(drm_dev_unref); int drm_dev_register(struct drm_device *dev, unsigned long flags) { int ret;
struct drm_crtc *crtc;
struct drm_plane *plane;
struct drm_encoder *encoder;
mutex_lock(&drm_global_mutex);
@@ -690,6 +693,27 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_connector_register_all(dev);
Look above for the ouch.
- drm_for_each_crtc(crtc, dev) {
if (crtc->funcs->late_register)
ret = crtc->funcs->late_register(crtc);
if (ret)
goto err_minors;
- }
For the sake of conformity, is it worth adding drm_crtc_register_all() et all?
Then a drm_modeset_register_all ? (i.e. if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_modeset_register_all(dev); -> { connector, encoder, plane, crtc )
Also, is the logical order
drm_connector_register_all(); drm_encoder_register_all(); drm_plane_register_all(); drm_crtc_register_all();
or the other way around (basically working from output back to input, or input to output)?
input to output would make sense to me. Once the output appears everything upstream of it would then be in place already.
Make sti driver use register callback to move debugfs initialization out of sub-components creation. This will allow to convert driver .load() to drm_dev_alloc() and drm_dev_register().
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org --- drivers/gpu/drm/sti/sti_compositor.c | 20 ++++++++++++++++++++ drivers/gpu/drm/sti/sti_compositor.h | 3 +++ drivers/gpu/drm/sti/sti_crtc.c | 12 ++++++++++++ drivers/gpu/drm/sti/sti_cursor.c | 32 ++++++++++++++++++++++++++++---- drivers/gpu/drm/sti/sti_dvo.c | 18 ++++++++++-------- drivers/gpu/drm/sti/sti_gdp.c | 32 ++++++++++++++++++++++++++++---- drivers/gpu/drm/sti/sti_hda.c | 18 ++++++++++-------- drivers/gpu/drm/sti/sti_hdmi.c | 19 +++++++++++++++---- drivers/gpu/drm/sti/sti_hqvdp.c | 32 ++++++++++++++++++++++++++++---- drivers/gpu/drm/sti/sti_mixer.c | 5 +---- drivers/gpu/drm/sti/sti_mixer.h | 2 ++ drivers/gpu/drm/sti/sti_plane.c | 24 +++--------------------- drivers/gpu/drm/sti/sti_plane.h | 7 +++++-- drivers/gpu/drm/sti/sti_tvout.c | 36 ++++++++++++++++++++++++++++++------ drivers/gpu/drm/sti/sti_vid.c | 5 +---- drivers/gpu/drm/sti/sti_vid.h | 2 ++ 16 files changed, 198 insertions(+), 69 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c index 3d2fa3a..794148f 100644 --- a/drivers/gpu/drm/sti/sti_compositor.c +++ b/drivers/gpu/drm/sti/sti_compositor.c @@ -55,6 +55,26 @@ struct sti_compositor_data stih416_compositor_data = { }, };
+int sti_compositor_debufs_init(struct sti_compositor *compo, + struct drm_minor *minor) +{ + int ret = 0, i; + + for (i = 0; compo->vid[i]; i++) { + ret = vid_debugfs_init(compo->vid[i], minor); + if (ret) + return ret; + } + + for (i = 0; compo->mixer[i]; i++) { + ret = sti_mixer_debugfs_init(compo->mixer[i], minor); + if (ret) + return ret; + } + + return 0; +} + static int sti_compositor_bind(struct device *dev, struct device *master, void *data) diff --git a/drivers/gpu/drm/sti/sti_compositor.h b/drivers/gpu/drm/sti/sti_compositor.h index 1a4a73d..24444ef 100644 --- a/drivers/gpu/drm/sti/sti_compositor.h +++ b/drivers/gpu/drm/sti/sti_compositor.h @@ -81,4 +81,7 @@ struct sti_compositor { struct notifier_block vtg_vblank_nb; };
+int sti_compositor_debufs_init(struct sti_compositor *compo, + struct drm_minor *minor); + #endif diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c index e04deed..7fab3af 100644 --- a/drivers/gpu/drm/sti/sti_crtc.c +++ b/drivers/gpu/drm/sti/sti_crtc.c @@ -331,6 +331,17 @@ void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe) } }
+static int sti_crtc_late_register(struct drm_crtc *crtc) +{ + struct sti_mixer *mixer = to_sti_mixer(crtc); + struct sti_compositor *compo = dev_get_drvdata(mixer->dev); + + if (drm_crtc_index(crtc) == 0) + return sti_compositor_debufs_init(compo, crtc->dev->primary); + + return 0; +} + static const struct drm_crtc_funcs sti_crtc_funcs = { .set_config = drm_atomic_helper_set_config, .page_flip = drm_atomic_helper_page_flip, @@ -339,6 +350,7 @@ static const struct drm_crtc_funcs sti_crtc_funcs = { .reset = drm_atomic_helper_crtc_reset, .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, + .late_register = sti_crtc_late_register, };
bool sti_crtc_is_main(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/sti/sti_cursor.c b/drivers/gpu/drm/sti/sti_cursor.c index 53aa002..a263bbb 100644 --- a/drivers/gpu/drm/sti/sti_cursor.c +++ b/drivers/gpu/drm/sti/sti_cursor.c @@ -329,6 +329,33 @@ static const struct drm_plane_helper_funcs sti_cursor_helpers_funcs = { .atomic_disable = sti_cursor_atomic_disable, };
+static void sti_cursor_destroy(struct drm_plane *drm_plane) +{ + DRM_DEBUG_DRIVER("\n"); + + drm_plane_helper_disable(drm_plane); + drm_plane_cleanup(drm_plane); +} + +static int sti_cursor_late_register(struct drm_plane *drm_plane) +{ + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_cursor *cursor = to_sti_cursor(plane); + + return cursor_debugfs_init(cursor, drm_plane->dev->primary); +} + +struct drm_plane_funcs sti_cursor_plane_helpers_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = sti_cursor_destroy, + .set_property = sti_plane_set_property, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + .late_register = sti_cursor_late_register, +}; + struct drm_plane *sti_cursor_create(struct drm_device *drm_dev, struct device *dev, int desc, void __iomem *baseaddr, @@ -363,7 +390,7 @@ struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
res = drm_universal_plane_init(drm_dev, &cursor->plane.drm_plane, possible_crtcs, - &sti_plane_helpers_funcs, + &sti_cursor_plane_helpers_funcs, cursor_supported_formats, ARRAY_SIZE(cursor_supported_formats), DRM_PLANE_TYPE_CURSOR, NULL); @@ -377,9 +404,6 @@ struct drm_plane *sti_cursor_create(struct drm_device *drm_dev,
sti_plane_init_property(&cursor->plane, DRM_PLANE_TYPE_CURSOR);
- if (cursor_debugfs_init(cursor, drm_dev->primary)) - DRM_ERROR("CURSOR debugfs setup failed\n"); - return &cursor->plane.drm_plane;
err_plane: diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index e290166..8a2b48f 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -404,24 +404,29 @@ sti_dvo_connector_detect(struct drm_connector *connector, bool force) return connector_status_disconnected; }
-static void sti_dvo_connector_destroy(struct drm_connector *connector) +static int sti_dvo_late_register(struct drm_connector *connector) { struct sti_dvo_connector *dvo_connector = to_sti_dvo_connector(connector); + struct sti_dvo *dvo = dvo_connector->dvo; + + if (dvo_debugfs_init(dvo, dvo->drm_dev->primary)) { + DRM_ERROR("DVO debugfs setup failed\n"); + return -EINVAL; + }
- drm_connector_unregister(connector); - drm_connector_cleanup(connector); - kfree(dvo_connector); + return 0; }
static const struct drm_connector_funcs sti_dvo_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_dvo_connector_detect, - .destroy = sti_dvo_connector_destroy, + .destroy = drm_connector_cleanup, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .late_register = sti_dvo_late_register, };
static struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev) @@ -502,9 +507,6 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data) goto err_sysfs; }
- if (dvo_debugfs_init(dvo, drm_dev->primary)) - DRM_ERROR("DVO debugfs setup failed\n"); - return 0;
err_sysfs: diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c index fdf69b5..bf63086 100644 --- a/drivers/gpu/drm/sti/sti_gdp.c +++ b/drivers/gpu/drm/sti/sti_gdp.c @@ -866,6 +866,33 @@ static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = { .atomic_disable = sti_gdp_atomic_disable, };
+static void sti_gdp_destroy(struct drm_plane *drm_plane) +{ + DRM_DEBUG_DRIVER("\n"); + + drm_plane_helper_disable(drm_plane); + drm_plane_cleanup(drm_plane); +} + +static int sti_gdp_late_register(struct drm_plane *drm_plane) +{ + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_gdp *gdp = to_sti_gdp(plane); + + return gdp_debugfs_init(gdp, drm_plane->dev->primary); +} + +struct drm_plane_funcs sti_gdp_plane_helpers_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = sti_gdp_destroy, + .set_property = sti_plane_set_property, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + .late_register = sti_gdp_late_register, +}; + struct drm_plane *sti_gdp_create(struct drm_device *drm_dev, struct device *dev, int desc, void __iomem *baseaddr, @@ -892,7 +919,7 @@ struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
res = drm_universal_plane_init(drm_dev, &gdp->plane.drm_plane, possible_crtcs, - &sti_plane_helpers_funcs, + &sti_gdp_plane_helpers_funcs, gdp_supported_formats, ARRAY_SIZE(gdp_supported_formats), type, NULL); @@ -905,9 +932,6 @@ struct drm_plane *sti_gdp_create(struct drm_device *drm_dev,
sti_plane_init_property(&gdp->plane, type);
- if (gdp_debugfs_init(gdp, drm_dev->primary)) - DRM_ERROR("GDP debugfs setup failed\n"); - return &gdp->plane.drm_plane;
err: diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index dcec5a8..e31d52d 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -681,24 +681,29 @@ sti_hda_connector_detect(struct drm_connector *connector, bool force) return connector_status_connected; }
-static void sti_hda_connector_destroy(struct drm_connector *connector) +static int sti_hda_late_register(struct drm_connector *connector) { struct sti_hda_connector *hda_connector = to_sti_hda_connector(connector); + struct sti_hda *hda = hda_connector->hda; + + if (hda_debugfs_init(hda, hda->drm_dev->primary)) { + DRM_ERROR("HDA debugfs setup failed\n"); + return -EINVAL; + }
- drm_connector_unregister(connector); - drm_connector_cleanup(connector); - kfree(hda_connector); + return 0; }
static const struct drm_connector_funcs sti_hda_connector_funcs = { .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_hda_connector_detect, - .destroy = sti_hda_connector_destroy, + .destroy = drm_connector_cleanup, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .late_register = sti_hda_late_register, };
static struct drm_encoder *sti_hda_find_encoder(struct drm_device *dev) @@ -769,9 +774,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) /* force to disable hd dacs at startup */ hda_enable_hd_dacs(hda, false);
- if (hda_debugfs_init(hda, drm_dev->primary)) - DRM_ERROR("HDA debugfs setup failed\n"); - return 0;
err_sysfs: diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 36d9d66..9d9c2c5 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -1007,8 +1007,21 @@ sti_hdmi_connector_get_property(struct drm_connector *connector, return -EINVAL; }
+static int sti_hdmi_late_register(struct drm_connector *connector) +{ + struct sti_hdmi_connector *hdmi_connector + = to_sti_hdmi_connector(connector); + struct sti_hdmi *hdmi = hdmi_connector->hdmi; + + if (hdmi_debugfs_init(hdmi, hdmi->drm_dev->primary)) { + DRM_ERROR("HDMI debugfs setup failed\n"); + return -EINVAL; + } + + return 0; +} + static const struct drm_connector_funcs sti_hdmi_connector_funcs = { - .dpms = drm_atomic_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_hdmi_connector_detect, .destroy = sti_hdmi_connector_destroy, @@ -1018,6 +1031,7 @@ static const struct drm_connector_funcs sti_hdmi_connector_funcs = { .atomic_get_property = sti_hdmi_connector_get_property, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, + .late_register = sti_hdmi_late_register, };
static struct drm_encoder *sti_hdmi_find_encoder(struct drm_device *dev) @@ -1091,9 +1105,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) /* Enable default interrupts */ hdmi_write(hdmi, HDMI_DEFAULT_INT, HDMI_INT_EN);
- if (hdmi_debugfs_init(hdmi, drm_dev->primary)) - DRM_ERROR("HDMI debugfs setup failed\n"); - return 0;
err_sysfs: diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c index 1c06a50..33d2f42 100644 --- a/drivers/gpu/drm/sti/sti_hqvdp.c +++ b/drivers/gpu/drm/sti/sti_hqvdp.c @@ -1234,6 +1234,33 @@ static const struct drm_plane_helper_funcs sti_hqvdp_helpers_funcs = { .atomic_disable = sti_hqvdp_atomic_disable, };
+static void sti_hqvdp_destroy(struct drm_plane *drm_plane) +{ + DRM_DEBUG_DRIVER("\n"); + + drm_plane_helper_disable(drm_plane); + drm_plane_cleanup(drm_plane); +} + +static int sti_hqvdp_late_register(struct drm_plane *drm_plane) +{ + struct sti_plane *plane = to_sti_plane(drm_plane); + struct sti_hqvdp *hqvdp = to_sti_hqvdp(plane); + + return hqvdp_debugfs_init(hqvdp, drm_plane->dev->primary); +} + +struct drm_plane_funcs sti_hqvdp_plane_helpers_funcs = { + .update_plane = drm_atomic_helper_update_plane, + .disable_plane = drm_atomic_helper_disable_plane, + .destroy = sti_hqvdp_destroy, + .set_property = sti_plane_set_property, + .reset = drm_atomic_helper_plane_reset, + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, + .late_register = sti_hqvdp_late_register, +}; + static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev, struct device *dev, int desc) { @@ -1246,7 +1273,7 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev, sti_hqvdp_init(hqvdp);
res = drm_universal_plane_init(drm_dev, &hqvdp->plane.drm_plane, 1, - &sti_plane_helpers_funcs, + &sti_hqvdp_plane_helpers_funcs, hqvdp_supported_formats, ARRAY_SIZE(hqvdp_supported_formats), DRM_PLANE_TYPE_OVERLAY, NULL); @@ -1259,9 +1286,6 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
sti_plane_init_property(&hqvdp->plane, DRM_PLANE_TYPE_OVERLAY);
- if (hqvdp_debugfs_init(hqvdp, drm_dev->primary)) - DRM_ERROR("HQVDP debugfs setup failed\n"); - return &hqvdp->plane.drm_plane; }
diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c index 6f86f2b..1885c7a 100644 --- a/drivers/gpu/drm/sti/sti_mixer.c +++ b/drivers/gpu/drm/sti/sti_mixer.c @@ -181,7 +181,7 @@ static struct drm_info_list mixer1_debugfs_files[] = { { "mixer_aux", mixer_dbg_show, 0, NULL }, };
-static int mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor) +int sti_mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor) { unsigned int i; struct drm_info_list *mixer_debugfs_files; @@ -393,8 +393,5 @@ struct sti_mixer *sti_mixer_create(struct device *dev, DRM_DEBUG_DRIVER("%s created. Regs=%p\n", sti_mixer_to_str(mixer), mixer->regs);
- if (mixer_debugfs_init(mixer, drm_dev->primary)) - DRM_ERROR("MIXER debugfs setup failed\n"); - return mixer; } diff --git a/drivers/gpu/drm/sti/sti_mixer.h b/drivers/gpu/drm/sti/sti_mixer.h index 6f35fc0..830a3c4 100644 --- a/drivers/gpu/drm/sti/sti_mixer.h +++ b/drivers/gpu/drm/sti/sti_mixer.h @@ -55,6 +55,8 @@ int sti_mixer_active_video_area(struct sti_mixer *mixer,
void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable);
+int sti_mixer_debugfs_init(struct sti_mixer *mixer, struct drm_minor *minor); + /* depth in Cross-bar control = z order */ #define GAM_MIXER_NB_DEPTH_LEVEL 6
diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c index f10c98d..85cee90 100644 --- a/drivers/gpu/drm/sti/sti_plane.c +++ b/drivers/gpu/drm/sti/sti_plane.c @@ -106,17 +106,9 @@ void sti_plane_update_fps(struct sti_plane *plane, plane->fps_info.fips_str); }
-static void sti_plane_destroy(struct drm_plane *drm_plane) -{ - DRM_DEBUG_DRIVER("\n"); - - drm_plane_helper_disable(drm_plane); - drm_plane_cleanup(drm_plane); -} - -static int sti_plane_set_property(struct drm_plane *drm_plane, - struct drm_property *property, - uint64_t val) +int sti_plane_set_property(struct drm_plane *drm_plane, + struct drm_property *property, + uint64_t val) { struct drm_device *dev = drm_plane->dev; struct sti_private *private = dev->dev_private; @@ -170,13 +162,3 @@ void sti_plane_init_property(struct sti_plane *plane, plane->drm_plane.base.id, sti_plane_to_str(plane), plane->zorder); } - -struct drm_plane_funcs sti_plane_helpers_funcs = { - .update_plane = drm_atomic_helper_update_plane, - .disable_plane = drm_atomic_helper_disable_plane, - .destroy = sti_plane_destroy, - .set_property = sti_plane_set_property, - .reset = drm_atomic_helper_plane_reset, - .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, -}; diff --git a/drivers/gpu/drm/sti/sti_plane.h b/drivers/gpu/drm/sti/sti_plane.h index c50a3b9..39d39f5 100644 --- a/drivers/gpu/drm/sti/sti_plane.h +++ b/drivers/gpu/drm/sti/sti_plane.h @@ -11,8 +11,6 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_plane_helper.h>
-extern struct drm_plane_funcs sti_plane_helpers_funcs; - #define to_sti_plane(x) container_of(x, struct sti_plane, drm_plane)
#define STI_PLANE_TYPE_SHIFT 8 @@ -83,6 +81,11 @@ const char *sti_plane_to_str(struct sti_plane *plane); void sti_plane_update_fps(struct sti_plane *plane, bool new_frame, bool new_field); + +int sti_plane_set_property(struct drm_plane *drm_plane, + struct drm_property *property, + uint64_t val); + void sti_plane_init_property(struct sti_plane *plane, enum drm_plane_type type); #endif diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c index 60fe0af..e25995b 100644 --- a/drivers/gpu/drm/sti/sti_tvout.c +++ b/drivers/gpu/drm/sti/sti_tvout.c @@ -112,6 +112,7 @@ struct sti_tvout { struct drm_encoder *hdmi; struct drm_encoder *hda; struct drm_encoder *dvo; + bool debugfs_registered; };
struct sti_tvout_encoder { @@ -625,8 +626,37 @@ static void sti_tvout_encoder_destroy(struct drm_encoder *encoder) kfree(sti_encoder); }
+static int sti_tvout_late_register(struct drm_encoder *encoder) +{ + struct sti_tvout *tvout = to_sti_tvout(encoder); + int ret; + + if (tvout->debugfs_registered) + return 0; + + ret = tvout_debugfs_init(tvout, encoder->dev->primary); + if (ret) + return ret; + + tvout->debugfs_registered = true; + return 0; +} + +static void sti_tvout_early_unregister(struct drm_encoder *encoder) +{ + struct sti_tvout *tvout = to_sti_tvout(encoder); + + if (!tvout->debugfs_registered) + return; + + tvout_debugfs_exit(tvout, encoder->dev->primary); + tvout->debugfs_registered = false; +} + static const struct drm_encoder_funcs sti_tvout_encoder_funcs = { .destroy = sti_tvout_encoder_destroy, + .late_register = sti_tvout_late_register, + .early_unregister = sti_tvout_early_unregister, };
static void sti_dvo_encoder_enable(struct drm_encoder *encoder) @@ -813,9 +843,6 @@ static int sti_tvout_bind(struct device *dev, struct device *master, void *data)
sti_tvout_create_encoders(drm_dev, tvout);
- if (tvout_debugfs_init(tvout, drm_dev->primary)) - DRM_ERROR("TVOUT debugfs setup failed\n"); - return 0; }
@@ -823,11 +850,8 @@ static void sti_tvout_unbind(struct device *dev, struct device *master, void *data) { struct sti_tvout *tvout = dev_get_drvdata(dev); - struct drm_device *drm_dev = data;
sti_tvout_destroy_encoders(tvout); - - tvout_debugfs_exit(tvout, drm_dev->primary); }
static const struct component_ops sti_tvout_ops = { diff --git a/drivers/gpu/drm/sti/sti_vid.c b/drivers/gpu/drm/sti/sti_vid.c index 0132aae..47634a0 100644 --- a/drivers/gpu/drm/sti/sti_vid.c +++ b/drivers/gpu/drm/sti/sti_vid.c @@ -123,7 +123,7 @@ static struct drm_info_list vid_debugfs_files[] = { { "vid", vid_dbg_show, 0, NULL }, };
-static int vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor) +int vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor) { unsigned int i;
@@ -220,8 +220,5 @@ struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev,
sti_vid_init(vid);
- if (vid_debugfs_init(vid, drm_dev->primary)) - DRM_ERROR("VID debugfs setup failed\n"); - return vid; } diff --git a/drivers/gpu/drm/sti/sti_vid.h b/drivers/gpu/drm/sti/sti_vid.h index 6c84234..fdc90f9 100644 --- a/drivers/gpu/drm/sti/sti_vid.h +++ b/drivers/gpu/drm/sti/sti_vid.h @@ -26,4 +26,6 @@ void sti_vid_disable(struct sti_vid *vid); struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev, int id, void __iomem *baseaddr);
+int vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor); + #endif
Use drm_dev_alloc() and drm_dev_register() instead of .load() To simplify init sequence only create fbdev when requested in output_poll_changed().
Signed-off-by: Benjamin Gaignard benjamin.gaignard@linaro.org --- drivers/gpu/drm/sti/sti_drv.c | 140 +++++++++++++++++++++++++++++------------ drivers/gpu/drm/sti/sti_drv.h | 1 + drivers/gpu/drm/sti/sti_dvo.c | 7 --- drivers/gpu/drm/sti/sti_hda.c | 8 +-- drivers/gpu/drm/sti/sti_hdmi.c | 21 +------ 5 files changed, 103 insertions(+), 74 deletions(-)
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c index 26aa85d..b38bced 100644 --- a/drivers/gpu/drm/sti/sti_drv.c +++ b/drivers/gpu/drm/sti/sti_drv.c @@ -226,8 +226,28 @@ static int sti_atomic_commit(struct drm_device *drm, return 0; }
+static void sti_output_poll_changed(struct drm_device *ddev) +{ + struct sti_private *private = ddev->dev_private; + + if (!ddev->mode_config.num_connector) + return; + + if (private->fbdev) { + drm_fbdev_cma_hotplug_event(private->fbdev); + return; + } + + private->fbdev = drm_fbdev_cma_init(ddev, 32, + ddev->mode_config.num_crtc, + ddev->mode_config.num_connector); + if (IS_ERR(private->fbdev)) + private->fbdev = NULL; +} + static const struct drm_mode_config_funcs sti_mode_config_funcs = { .fb_create = drm_fb_cma_create, + .output_poll_changed = sti_output_poll_changed, .atomic_check = drm_atomic_helper_check, .atomic_commit = sti_atomic_commit, }; @@ -248,44 +268,6 @@ static void sti_mode_config_init(struct drm_device *dev) dev->mode_config.funcs = &sti_mode_config_funcs; }
-static int sti_load(struct drm_device *dev, unsigned long flags) -{ - struct sti_private *private; - int ret; - - private = kzalloc(sizeof(*private), GFP_KERNEL); - if (!private) { - DRM_ERROR("Failed to allocate private\n"); - return -ENOMEM; - } - dev->dev_private = (void *)private; - private->drm_dev = dev; - - mutex_init(&private->commit.lock); - INIT_WORK(&private->commit.work, sti_atomic_work); - - drm_mode_config_init(dev); - drm_kms_helper_poll_init(dev); - - sti_mode_config_init(dev); - - ret = component_bind_all(dev->dev, dev); - if (ret) { - drm_kms_helper_poll_fini(dev); - drm_mode_config_cleanup(dev); - kfree(private); - return ret; - } - - drm_mode_config_reset(dev); - - drm_fbdev_cma_init(dev, 32, - dev->mode_config.num_crtc, - dev->mode_config.num_connector); - - return 0; -} - static const struct file_operations sti_driver_fops = { .owner = THIS_MODULE, .open = drm_open, @@ -302,7 +284,6 @@ static const struct file_operations sti_driver_fops = { static struct drm_driver sti_driver = { .driver_features = DRIVER_HAVE_IRQ | DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | DRIVER_ATOMIC, - .load = sti_load, .gem_free_object_unlocked = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, .dumb_create = drm_gem_cma_dumb_create, @@ -339,14 +320,91 @@ static int compare_of(struct device *dev, void *data) return dev->of_node == data; }
+static int sti_init(struct drm_device *ddev) +{ + struct sti_private *private; + + private = kzalloc(sizeof(*private), GFP_KERNEL); + if (!private) + return -ENOMEM; + + ddev->dev_private = (void *)private; + dev_set_drvdata(ddev->dev, ddev); + private->drm_dev = ddev; + + mutex_init(&private->commit.lock); + INIT_WORK(&private->commit.work, sti_atomic_work); + + drm_mode_config_init(ddev); + + sti_mode_config_init(ddev); + + drm_kms_helper_poll_init(ddev); + + return 0; +} + +static void sti_cleanup(struct drm_device *ddev) +{ + struct sti_private *private = ddev->dev_private; + + if (private->fbdev) { + drm_fbdev_cma_fini(private->fbdev); + private->fbdev = NULL; + } + + drm_kms_helper_poll_fini(ddev); + drm_vblank_cleanup(ddev); + kfree(private); + ddev->dev_private = NULL; +} + static int sti_bind(struct device *dev) { - return drm_platform_init(&sti_driver, to_platform_device(dev)); + struct drm_device *ddev; + int ret; + + ddev = drm_dev_alloc(&sti_driver, dev); + if (!ddev) + return -ENOMEM; + + drm_dev_set_unique(ddev, dev_name(dev)); + + ddev->platformdev = to_platform_device(dev); + + ret = sti_init(ddev); + if (ret) + goto err_drm_dev_unref; + + ret = component_bind_all(ddev->dev, ddev); + if (ret) + goto err_cleanup; + + ret = drm_dev_register(ddev, 0); + if (ret) + goto err_register; + + drm_mode_config_reset(ddev); + + return 0; + +err_register: + drm_mode_config_cleanup(ddev); +err_cleanup: + sti_cleanup(ddev); +err_drm_dev_unref: + drm_dev_unref(ddev); + return ret; }
static void sti_unbind(struct device *dev) { - drm_put_dev(dev_get_drvdata(dev)); + struct drm_device *ddev = dev_get_drvdata(dev); + + drm_connector_unregister_all(ddev); + drm_dev_unregister(ddev); + sti_cleanup(ddev); + drm_dev_unref(ddev); }
static const struct component_master_ops sti_ops = { diff --git a/drivers/gpu/drm/sti/sti_drv.h b/drivers/gpu/drm/sti/sti_drv.h index 30ddc20..78ebe5e 100644 --- a/drivers/gpu/drm/sti/sti_drv.h +++ b/drivers/gpu/drm/sti/sti_drv.h @@ -24,6 +24,7 @@ struct sti_private { struct sti_compositor *compo; struct drm_property *plane_zorder_property; struct drm_device *drm_dev; + struct drm_fbdev_cma *fbdev;
struct { struct drm_atomic_state *state; diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c index 8a2b48f..ec31080 100644 --- a/drivers/gpu/drm/sti/sti_dvo.c +++ b/drivers/gpu/drm/sti/sti_dvo.c @@ -497,10 +497,6 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data) drm_connector_helper_add(drm_connector, &sti_dvo_connector_helper_funcs);
- err = drm_connector_register(drm_connector); - if (err) - goto err_connector; - err = drm_mode_connector_attach_encoder(drm_connector, encoder); if (err) { DRM_ERROR("Failed to attach a connector to a encoder\n"); @@ -510,10 +506,7 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data) return 0;
err_sysfs: - drm_connector_unregister(drm_connector); -err_connector: drm_bridge_remove(bridge); - drm_connector_cleanup(drm_connector); return -EINVAL; }
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c index e31d52d..8505569 100644 --- a/drivers/gpu/drm/sti/sti_hda.c +++ b/drivers/gpu/drm/sti/sti_hda.c @@ -761,10 +761,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) drm_connector_helper_add(drm_connector, &sti_hda_connector_helper_funcs);
- err = drm_connector_register(drm_connector); - if (err) - goto err_connector; - err = drm_mode_connector_attach_encoder(drm_connector, encoder); if (err) { DRM_ERROR("Failed to attach a connector to a encoder\n"); @@ -777,9 +773,7 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data) return 0;
err_sysfs: - drm_connector_unregister(drm_connector); -err_connector: - drm_connector_cleanup(drm_connector); + drm_bridge_remove(bridge); return -EINVAL; }
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c index 9d9c2c5..8d1402b 100644 --- a/drivers/gpu/drm/sti/sti_hdmi.c +++ b/drivers/gpu/drm/sti/sti_hdmi.c @@ -915,16 +915,6 @@ sti_hdmi_connector_detect(struct drm_connector *connector, bool force) return connector_status_disconnected; }
-static void sti_hdmi_connector_destroy(struct drm_connector *connector) -{ - struct sti_hdmi_connector *hdmi_connector - = to_sti_hdmi_connector(connector); - - drm_connector_unregister(connector); - drm_connector_cleanup(connector); - kfree(hdmi_connector); -} - static void sti_hdmi_connector_init_property(struct drm_device *drm_dev, struct drm_connector *connector) { @@ -1024,7 +1014,7 @@ static int sti_hdmi_late_register(struct drm_connector *connector) static const struct drm_connector_funcs sti_hdmi_connector_funcs = { .fill_modes = drm_helper_probe_single_connector_modes, .detect = sti_hdmi_connector_detect, - .destroy = sti_hdmi_connector_destroy, + .destroy = drm_connector_cleanup, .reset = drm_atomic_helper_connector_reset, .set_property = drm_atomic_helper_connector_set_property, .atomic_set_property = sti_hdmi_connector_set_property, @@ -1092,10 +1082,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) /* initialise property */ sti_hdmi_connector_init_property(drm_dev, drm_connector);
- err = drm_connector_register(drm_connector); - if (err) - goto err_connector; - err = drm_mode_connector_attach_encoder(drm_connector, encoder); if (err) { DRM_ERROR("Failed to attach a connector to a encoder\n"); @@ -1108,10 +1094,7 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data) return 0;
err_sysfs: - drm_connector_unregister(drm_connector); -err_connector: - drm_connector_cleanup(drm_connector); - + drm_bridge_remove(bridge); return -EINVAL; }
On Mon, Jun 20, 2016 at 05:22:57PM +0200, Benjamin Gaignard wrote:
static int sti_bind(struct device *dev) {
- return drm_platform_init(&sti_driver, to_platform_device(dev));
- struct drm_device *ddev;
- int ret;
- ddev = drm_dev_alloc(&sti_driver, dev);
- if (!ddev)
return -ENOMEM;
- drm_dev_set_unique(ddev, dev_name(dev));
- ddev->platformdev = to_platform_device(dev);
- ret = sti_init(ddev);
- if (ret)
goto err_drm_dev_unref;
- ret = component_bind_all(ddev->dev, ddev);
- if (ret)
goto err_cleanup;
- ret = drm_dev_register(ddev, 0);
- if (ret)
goto err_register;
Instead of coupling compositor_debug_init into the first CRTC, you can call it explicitly now (since it is not CRTC related but dev).
- drm_mode_config_reset(ddev);
- return 0;
+err_register:
- drm_mode_config_cleanup(ddev);
+err_cleanup:
- sti_cleanup(ddev);
+err_drm_dev_unref:
- drm_dev_unref(ddev);
- return ret;
}
static void sti_unbind(struct device *dev) {
- drm_put_dev(dev_get_drvdata(dev));
- struct drm_device *ddev = dev_get_drvdata(dev);
- drm_connector_unregister_all(ddev);
^ redundant.
- drm_dev_unregister(ddev);
- sti_cleanup(ddev);
- drm_dev_unref(ddev);
}
Hi Benjamin,
On 20 June 2016 at 16:22, Benjamin Gaignard benjamin.gaignard@linaro.org wrote:
drm_dev_set_unique(ddev, dev_name(dev));
Daniel Vetter has a series in flight [1] which should make this obsolete (wrong actually). There were a couple of minor issues, but I'd expect it to be complete some time this week.
dri-devel@lists.freedesktop.org