Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d26336c authored by Xiaowen Wu's avatar Xiaowen Wu
Browse files

drm/dp: defer h/w hpd registeration to the end of dp sub module init



Previously when hpd_get is called, it will register callback
function into hardware. There is a potential racing issue that hardware
may call the callback function immediately in a separate thread
when the rest dp sub module initializations are not finished yet.

A new api register_hpd is added to each dp_hpd type and will get
called when all sub modules are initialized. H/W registeration will
be moved to this new api to guarantee dp is fully initialized before
any callback would happen.

CRs-Fixed: 2359246
Change-Id: I941a5c11e09ad05cc336c307940cba7749ff84e8
Signed-off-by: default avatarXiaowen Wu <wxiaowen@codeaurora.org>
parent 2e4e6c46
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -1265,7 +1265,15 @@ static int dp_init_sub_modules(struct dp_display_private *dp)

	dp_display_get_usb_extcon(dp);

	rc = dp->hpd->register_hpd(dp->hpd);
	if (rc) {
		pr_err("failed register hpd\n");
		goto error_hpd_reg;
	}

	return rc;
error_hpd_reg:
	dp_debug_put(dp->debug);
error_debug:
	dp_hpd_put(dp->hpd);
error_hpd:
+30 −17
Original line number Diff line number Diff line
@@ -187,6 +187,35 @@ static int dp_gpio_hpd_simulate_attention(struct dp_hpd *dp_hpd, int vdo)
	return rc;
}

int dp_gpio_hpd_register(struct dp_hpd *dp_hpd)
{
	struct dp_gpio_hpd_private *gpio_hpd;
	int edge;
	int rc = 0;

	if (!dp_hpd)
		return -EINVAL;

	gpio_hpd = container_of(dp_hpd, struct dp_gpio_hpd_private, base);

	gpio_hpd->hpd = gpio_get_value_cansleep(gpio_hpd->gpio_cfg.gpio);

	edge = gpio_hpd->hpd ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
	rc = devm_request_threaded_irq(gpio_hpd->dev, gpio_hpd->irq, NULL,
		dp_gpio_isr,
		edge | IRQF_ONESHOT,
		"dp-gpio-intp", gpio_hpd);
	if (rc) {
		pr_err("Failed to request INTP threaded IRQ: %d\n", rc);
		return rc;
	}

	if (gpio_hpd->hpd)
		queue_delayed_work(system_wq, &gpio_hpd->work, 0);

	return rc;
}

struct dp_hpd *dp_gpio_hpd_get(struct device *dev,
	struct dp_hpd_cb *cb)
{
@@ -194,7 +223,6 @@ struct dp_hpd *dp_gpio_hpd_get(struct device *dev,
	const char *hpd_gpio_name = "qcom,dp-hpd-gpio";
	struct dp_gpio_hpd_private *gpio_hpd;
	struct dp_pinctrl pinctrl = {0};
	int edge;

	if (!dev || !cb) {
		pr_err("invalid device\n");
@@ -245,29 +273,14 @@ struct dp_hpd *dp_gpio_hpd_get(struct device *dev,
	gpio_hpd->dev = dev;
	gpio_hpd->cb = cb;
	gpio_hpd->irq = gpio_to_irq(gpio_hpd->gpio_cfg.gpio);
	gpio_hpd->hpd = gpio_get_value_cansleep(gpio_hpd->gpio_cfg.gpio);
	edge = gpio_hpd->hpd ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
	INIT_DELAYED_WORK(&gpio_hpd->work, dp_gpio_hpd_work);

	rc = devm_request_threaded_irq(dev, gpio_hpd->irq, NULL,
			dp_gpio_isr,
			edge | IRQF_ONESHOT,
			"dp-gpio-intp", gpio_hpd);
	if (rc) {
		pr_err("Failed to request INTP threaded IRQ: %d\n", rc);
		goto gpio_irq_error;
	}

	gpio_hpd->base.simulate_connect = dp_gpio_hpd_simulate_connect;
	gpio_hpd->base.simulate_attention = dp_gpio_hpd_simulate_attention;

	if (gpio_hpd->hpd)
		queue_delayed_work(system_wq, &gpio_hpd->work, 0);
	gpio_hpd->base.register_hpd = dp_gpio_hpd_register;

	return &gpio_hpd->base;

gpio_irq_error:
	devm_gpio_free(dev, gpio_hpd->gpio_cfg.gpio);
gpio_error:
	devm_kfree(dev, gpio_hpd);
error:
+2 −1
Original line number Diff line number Diff line
@@ -54,9 +54,9 @@ struct dp_hpd_cb {
 * @hpd_high: Hot Plug Detect signal is high.
 * @hpd_irq: Change in the status since last message
 * @alt_mode_cfg_done: bool to specify alt mode status
 * @switch_needed: bool to specify if switch is needed
 * @multi_func: multi-function preferred, USBPD type only
 * @isr: event interrupt, BUILTIN type only
 * @register_hpd: register hardware callback
 * @simulate_connect: simulate disconnect or connect for debug mode
 * @simulate_attention: simulate attention messages for debug mode
 */
@@ -69,6 +69,7 @@ struct dp_hpd {
	bool multi_func;

	void (*isr)(struct dp_hpd *dp_hpd, int event);
	int (*register_hpd)(struct dp_hpd *dp_hpd);
	int (*simulate_connect)(struct dp_hpd *dp_hpd, bool hpd);
	int (*simulate_attention)(struct dp_hpd *dp_hpd, int vdo);
};
+21 −8
Original line number Diff line number Diff line
@@ -485,6 +485,26 @@ static int dp_usbpd_simulate_attention(struct dp_hpd *dp_hpd, int vdo)
	return rc;
}

int dp_usbpd_register(struct dp_hpd *dp_hpd)
{
	struct dp_usbpd *dp_usbpd;
	struct dp_usbpd_private *usbpd;
	int rc = 0;

	if (!dp_hpd)
		return -EINVAL;

	dp_usbpd = container_of(dp_hpd, struct dp_usbpd, base);

	usbpd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd);

	rc = usbpd_register_svid(usbpd->pd, &usbpd->svid_handler);
	if (rc)
		pr_err("pd registration failed\n");

	return rc;
}

struct dp_hpd *dp_usbpd_get(struct device *dev, struct dp_hpd_cb *cb)
{
	int rc = 0;
@@ -524,17 +544,10 @@ struct dp_hpd *dp_usbpd_get(struct device *dev, struct dp_hpd_cb *cb)
	usbpd->svid_handler = svid_handler;
	usbpd->dp_cb = cb;

	rc = usbpd_register_svid(pd, &usbpd->svid_handler);
	if (rc) {
		pr_err("pd registration failed\n");
		rc = -ENODEV;
		devm_kfree(dev, usbpd);
		goto error;
	}

	dp_usbpd = &usbpd->dp_usbpd;
	dp_usbpd->base.simulate_connect = dp_usbpd_simulate_connect;
	dp_usbpd->base.simulate_attention = dp_usbpd_simulate_attention;
	dp_usbpd->base.register_hpd = dp_usbpd_register;

	return &dp_usbpd->base;
error: