static void tb_xdomain_get_properties()

in xdomain.c [1055:1148]


static void tb_xdomain_get_properties(struct work_struct *work)
{
	struct tb_xdomain *xd = container_of(work, typeof(*xd),
					     get_properties_work.work);
	struct tb_property_dir *dir;
	struct tb *tb = xd->tb;
	bool update = false;
	u32 *block = NULL;
	u32 gen = 0;
	int ret;

	dev_dbg(&xd->dev, "requesting remote properties\n");

	ret = tb_xdp_properties_request(tb->ctl, xd->route, xd->local_uuid,
					xd->remote_uuid, xd->properties_retries,
					&block, &gen);
	if (ret < 0) {
		if (xd->properties_retries-- > 0) {
			dev_dbg(&xd->dev,
				"failed to request remote properties, retrying\n");
			queue_delayed_work(xd->tb->wq, &xd->get_properties_work,
					   msecs_to_jiffies(1000));
		} else {
			/* Give up now */
			dev_err(&xd->dev,
				"failed read XDomain properties from %pUb\n",
				xd->remote_uuid);
		}
		return;
	}

	xd->properties_retries = XDOMAIN_PROPERTIES_RETRIES;

	mutex_lock(&xd->lock);

	/* Only accept newer generation properties */
	if (xd->remote_properties && gen <= xd->remote_property_block_gen)
		goto err_free_block;

	dir = tb_property_parse_dir(block, ret);
	if (!dir) {
		dev_err(&xd->dev, "failed to parse XDomain properties\n");
		goto err_free_block;
	}

	ret = populate_properties(xd, dir);
	if (ret) {
		dev_err(&xd->dev, "missing XDomain properties in response\n");
		goto err_free_dir;
	}

	/* Release the existing one */
	if (xd->remote_properties) {
		tb_property_free_dir(xd->remote_properties);
		update = true;
	}

	xd->remote_properties = dir;
	xd->remote_property_block_gen = gen;

	tb_xdomain_update_link_attributes(xd);

	mutex_unlock(&xd->lock);

	kfree(block);

	/*
	 * Now the device should be ready enough so we can add it to the
	 * bus and let userspace know about it. If the device is already
	 * registered, we notify the userspace that it has changed.
	 */
	if (!update) {
		if (device_add(&xd->dev)) {
			dev_err(&xd->dev, "failed to add XDomain device\n");
			return;
		}
		dev_info(&xd->dev, "new host found, vendor=%#x device=%#x\n",
			 xd->vendor, xd->device);
		if (xd->vendor_name && xd->device_name)
			dev_info(&xd->dev, "%s %s\n", xd->vendor_name,
				 xd->device_name);
	} else {
		kobject_uevent(&xd->dev.kobj, KOBJ_CHANGE);
	}

	enumerate_services(xd);
	return;

err_free_dir:
	tb_property_free_dir(dir);
err_free_block:
	kfree(block);
	mutex_unlock(&xd->lock);
}