All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paolo Abeni <pabeni@redhat.com>
To: Matt Johnston <matt@codeconstruct.com.au>,
	linux-i3c@lists.infradead.org,  netdev@vger.kernel.org,
	devicetree@vger.kernel.org
Cc: "David S. Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>,
	 Eric Dumazet <edumazet@google.com>,
	Jeremy Kerr <jk@codeconstruct.com.au>,
	Alexandre Belloni <alexandre.belloni@bootlin.com>,
	Rob Herring <robh+dt@kernel.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
	Conor Dooley <conor+dt@kernel.org>,
	 miquel.raynal@bootlin.com
Subject: Re: [PATCH net-next v5 3/3] mctp i3c: MCTP I3C driver
Date: Thu, 12 Oct 2023 13:50:39 +0200	[thread overview]
Message-ID: <e704c45bc3c81d45541b82bded0618380d81634f.camel@redhat.com> (raw)
In-Reply-To: <20231009025451.490374-4-matt@codeconstruct.com.au>

On Mon, 2023-10-09 at 10:54 +0800, Matt Johnston wrote:

> +static int mctp_i3c_setup(struct mctp_i3c_device *mi)
> +{
> +	bool ibi_set = false, ibi_enabled = false;
> +	const struct i3c_ibi_setup ibi = {
> +		.max_payload_len = 1,
> +		.num_slots = MCTP_I3C_IBI_SLOTS,
> +		.handler = mctp_i3c_ibi_handler,
> +	};
> +	struct i3c_device_info info;
> +	int rc;
> +
> +	i3c_device_get_info(mi->i3c, &info);
> +	mi->have_mdb = info.bcr & BIT(2);
> +	mi->addr = info.dyn_addr;
> +	mi->mwl = info.max_write_len;
> +	mi->mrl = info.max_read_len;
> +	mi->pid = info.pid;
> +
> +	rc = i3c_device_request_ibi(mi->i3c, &ibi);
> +	if (rc == 0) {
> +		ibi_set = true;
> +	} else if (rc == -ENOTSUPP) {
> +		/* This driver only supports In-Band Interrupt mode
> +		 * (ENOTSUPP is from the i3c layer, not EOPNOTSUPP).
> +		 * Support for Polling Mode could be added if required.
> +		 */
> +		dev_warn(i3cdev_to_dev(mi->i3c), "Failed, bus driver doesn't support In-Band Interrupts");
> +		goto err;
> +	} else {
> +		dev_err(i3cdev_to_dev(mi->i3c),
> +			"Failed requesting IBI (%d)\n", rc);
> +		goto err;
> +	}
> +
> +	if (ibi_set) {
> +		/* Device setup must be complete when IBI is enabled */
> +		rc = i3c_device_enable_ibi(mi->i3c);
> +		if (rc < 0) {
> +			/* Assume a driver supporting request_ibi also
> +			 * supports enable_ibi.
> +			 */
> +			dev_err(i3cdev_to_dev(mi->i3c),
> +				"Failed enabling IBI (%d)\n", rc);
> +			goto err;
> +		}
> +		ibi_enabled = true;
> +	}
> +
> +	return 0;
> +err:
> +	if (ibi_enabled)
> +		i3c_device_disable_ibi(mi->i3c);

Apparently no error code path can reach here with 'ibi_enabled ==
true', if so please drop the above lines.

> +	if (ibi_set)
> +		i3c_device_free_ibi(mi->i3c);
> +	return rc;
> +}
> +
> +/* Adds a new MCTP i3c_device to a bus */
> +static int mctp_i3c_add_device(struct mctp_i3c_bus *mbus,
> +			       struct i3c_device *i3c)
> +__must_hold(&busdevs_lock)
> +{
> +	struct mctp_i3c_device *mi = NULL;
> +	int rc;
> +
> +	mi = kzalloc(sizeof(*mi), GFP_KERNEL);
> +	if (!mi) {
> +		rc = -ENOMEM;
> +		goto err;
> +	}
> +	mi->mbus = mbus;
> +	mi->i3c = i3c;
> +	mutex_init(&mi->lock);
> +	list_add(&mi->list, &mbus->devs);
> +
> +	i3cdev_set_drvdata(i3c, mi);
> +	rc = mctp_i3c_setup(mi);
> +	if (rc < 0)
> +		goto err;

You can make the code simpler with:

		goto free;
> +
> +	return 0;

and here:

free:
	list_del(&mi->list);
	kfree(mi);

err:
	dev_warn(i3cdev_to_dev(i3c), "Error adding mctp-i3c device, %d\n", rc);
	return rc;

> +err:
> +	dev_warn(i3cdev_to_dev(i3c), "Error adding mctp-i3c device, %d\n", rc);
> +	if (mi) {
> +		list_del(&mi->list);
> +		kfree(mi);
> +	}
> +	return rc;
> +}
> +
> +static int mctp_i3c_probe(struct i3c_device *i3c)
> +{
> +	struct mctp_i3c_bus *b = NULL, *mbus = NULL;
> +	int rc;
> +
> +	/* Look for a known bus */
> +	mutex_lock(&busdevs_lock);
> +	list_for_each_entry(b, &busdevs, list)
> +		if (b->bus == i3c->bus) {
> +			mbus = b;
> +			break;
> +		}
> +	mutex_unlock(&busdevs_lock);
> +
> +	if (!mbus) {
> +		/* probably no "mctp-controller" property on the i3c bus */
> +		return -ENODEV;
> +	}
> +
> +	rc = mctp_i3c_add_device(mbus, i3c);
> +	if (!rc)
> +		goto err;

This is confusing: if 'rc' is zero (!rc) the function will return 0
('return rc' later), and otherwise it will return zero again.

Either ignore the return code, or more likely the error path need some
change.

> +static void mctp_i3c_xmit(struct mctp_i3c_bus *mbus, struct sk_buff *skb)
> +{
> +	struct net_device_stats *stats = &mbus->ndev->stats;
> +	struct i3c_priv_xfer xfer = { .rnw = false };
> +	struct mctp_i3c_internal_hdr *ihdr = NULL;
> +	struct mctp_i3c_device *mi = NULL;
> +	unsigned int data_len;
> +	u8 *data = NULL;
> +	u8 addr, pec;
> +	int rc = 0;
> +	u64 pid;
> +
> +	skb_pull(skb, sizeof(struct mctp_i3c_internal_hdr));
> +	data_len = skb->len;
> +
> +	ihdr = (void *)skb_mac_header(skb);
> +
> +	pid = get_unaligned_be48(ihdr->dest);
> +	mi = mctp_i3c_lookup(mbus, pid);
> +	if (!mi) {
> +		/* I3C endpoint went away after the packet was enqueued? */
> +		stats->tx_dropped++;
> +		goto out;
> +	}
> +
> +	if (WARN_ON_ONCE(data_len + 1 > MCTP_I3C_MAXBUF))
> +		goto out;
> +
> +	if (data_len + 1 > (unsigned int)mi->mwl) {
> +		/* Route MTU was larger than supported by the endpoint */
> +		stats->tx_dropped++;
> +		goto out;
> +	}
> +
> +	/* Need a linear buffer with space for the PEC */
> +	xfer.len = data_len + 1;
> +	if (skb_tailroom(skb) >= 1) {
> +		skb_put(skb, 1);
> +		data = skb->data;
> +	} else {
> +		// TODO: test this

I hope this comment is a left over? In any case please avoid c++ style
comments.

> +		/* Otherwise need to copy the buffer */
> +		skb_copy_bits(skb, 0, mbus->tx_scratch, skb->len);
> +		data = mbus->tx_scratch;
> +	}
> +
> +	/* PEC calculation */
> +	addr = mi->addr << 1;
> +	pec = i2c_smbus_pec(0, &addr, 1);
> +	pec = i2c_smbus_pec(pec, data, data_len);
> +	data[data_len] = pec;
> +
> +	xfer.data.out = data;
> +	rc = i3c_device_do_priv_xfers(mi->i3c, &xfer, 1);
> +	if (rc == 0) {
> +		stats->tx_bytes += data_len;
> +		stats->tx_packets++;
> +	} else {
> +		stats->tx_errors++;
> +	}
> +
> +out:
> +	if (mi)
> +		mutex_unlock(&mi->lock);
> +}
> +
> +static int mctp_i3c_tx_thread(void *data)
> +{
> +	struct mctp_i3c_bus *mbus = data;
> +	struct sk_buff *skb;
> +	unsigned long flags;
> +
> +	for (;;) {
> +		if (kthread_should_stop())
> +			break;
> +
> +		spin_lock_irqsave(&mbus->tx_lock, flags);
> +		skb = mbus->tx_skb;
> +		mbus->tx_skb = NULL;
> +		spin_unlock_irqrestore(&mbus->tx_lock, flags);
> +
> +		if (netif_queue_stopped(mbus->ndev))
> +			netif_wake_queue(mbus->ndev);
> +
> +		if (skb) {
> +			mctp_i3c_xmit(mbus, skb);
> +			kfree_skb(skb);
> +		} else {
> +			wait_event_idle(mbus->tx_wq,
> +					mbus->tx_skb || kthread_should_stop());
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static netdev_tx_t mctp_i3c_start_xmit(struct sk_buff *skb,
> +				       struct net_device *ndev)
> +{
> +	struct mctp_i3c_bus *mbus = netdev_priv(ndev);
> +	unsigned long flags;
> +	netdev_tx_t ret;
> +
> +	spin_lock_irqsave(&mbus->tx_lock, flags);

Why are you using the _irqsave variant? The only other path acquiring
this lock is mctp_i3c_tx_thread(), in process context, while here we
have BH disabled. Plain spin_lock should suffice here, paired with _BH
variant in mctp_i3c_tx_thread.

> +	netif_stop_queue(ndev);
> +	if (mbus->tx_skb) {
> +		dev_warn_ratelimited(&ndev->dev, "TX with queue stopped");
> +		ret = NETDEV_TX_BUSY;
> +	} else {
> +		mbus->tx_skb = skb;
> +		ret = NETDEV_TX_OK;
> +	}
> +	spin_unlock_irqrestore(&mbus->tx_lock, flags);
> +
> +	if (ret == NETDEV_TX_OK)
> +		wake_up(&mbus->tx_wq);
> +
> +	return ret;
> +}

[...]

> +/* Returns an ERR_PTR on failure */
> +static struct mctp_i3c_bus *mctp_i3c_bus_add(struct i3c_bus *bus)
> +__must_hold(&busdevs_lock)
> +{
> +	struct mctp_i3c_bus *mbus = NULL;
> +	struct net_device *ndev = NULL;
> +	char namebuf[IFNAMSIZ];
> +	u8 addr[PID_SIZE];
> +	int rc;
> +
> +	if (!mctp_i3c_is_mctp_controller(bus))
> +		return ERR_PTR(-ENOENT);
> +
> +	snprintf(namebuf, sizeof(namebuf), "mctpi3c%d", bus->id);
> +	ndev = alloc_netdev(sizeof(*mbus), namebuf, NET_NAME_ENUM,
> +			    mctp_i3c_net_setup);
> +	if (!ndev) {
> +		rc = -ENOMEM;
> +		goto err;
> +	}
> +
> +	mbus = netdev_priv(ndev);
> +	mbus->ndev = ndev;
> +	mbus->bus = bus;
> +	INIT_LIST_HEAD(&mbus->devs);
> +	list_add(&mbus->list, &busdevs);
> +
> +	rc = mctp_i3c_bus_local_pid(bus, &mbus->pid);
> +	if (rc < 0) {
> +		dev_err(&ndev->dev, "No I3C PID available\n");
> +		goto err;
> +	}
> +	put_unaligned_be48(mbus->pid, addr);
> +	dev_addr_set(ndev, addr);
> +
> +	init_waitqueue_head(&mbus->tx_wq);
> +	spin_lock_init(&mbus->tx_lock);
> +	mbus->tx_thread = kthread_run(mctp_i3c_tx_thread, mbus,
> +				      "%s/tx", ndev->name);
> +	if (IS_ERR(mbus->tx_thread)) {
> +		dev_warn(&ndev->dev, "Error creating thread: %pe\n",
> +			 mbus->tx_thread);
> +		rc = PTR_ERR(mbus->tx_thread);
> +		mbus->tx_thread = NULL;
> +		goto err;
> +	}
> +
> +	rc = mctp_register_netdev(ndev, NULL);
> +	if (rc < 0) {
> +		dev_warn(&ndev->dev, "netdev register failed: %d\n", rc);
> +		goto err;
> +	}
> +	return mbus;
> +err:
> +	/* uninit will not get called if a netdev has not been registered,
> +	 * so we perform the same mbus cleanup manually.
> +	 */
> +	if (mbus)
> +		mctp_i3c_bus_free(mbus);
> +	if (ndev)
> +		free_netdev(ndev);

A more conventional way of handling the error paths would be using
multiple labels, e.g.:

err_free_bus:
	mctp_i3c_bus_free(mbus);

err_free_ndev:
	free_netdev(ndev);

err:

> +	return ERR_PTR(rc);
> +}

Cheers,

Paolo


WARNING: multiple messages have this Message-ID (diff)
From: Paolo Abeni <pabeni@redhat.com>
To: Matt Johnston <matt@codeconstruct.com.au>,
	linux-i3c@lists.infradead.org,  netdev@vger.kernel.org,
	devicetree@vger.kernel.org
Cc: "David S. Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>,
	 Eric Dumazet <edumazet@google.com>,
	Jeremy Kerr <jk@codeconstruct.com.au>,
	Alexandre Belloni <alexandre.belloni@bootlin.com>,
	Rob Herring <robh+dt@kernel.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
	Conor Dooley <conor+dt@kernel.org>,
	 miquel.raynal@bootlin.com
Subject: Re: [PATCH net-next v5 3/3] mctp i3c: MCTP I3C driver
Date: Thu, 12 Oct 2023 13:50:39 +0200	[thread overview]
Message-ID: <e704c45bc3c81d45541b82bded0618380d81634f.camel@redhat.com> (raw)
In-Reply-To: <20231009025451.490374-4-matt@codeconstruct.com.au>

On Mon, 2023-10-09 at 10:54 +0800, Matt Johnston wrote:

> +static int mctp_i3c_setup(struct mctp_i3c_device *mi)
> +{
> +	bool ibi_set = false, ibi_enabled = false;
> +	const struct i3c_ibi_setup ibi = {
> +		.max_payload_len = 1,
> +		.num_slots = MCTP_I3C_IBI_SLOTS,
> +		.handler = mctp_i3c_ibi_handler,
> +	};
> +	struct i3c_device_info info;
> +	int rc;
> +
> +	i3c_device_get_info(mi->i3c, &info);
> +	mi->have_mdb = info.bcr & BIT(2);
> +	mi->addr = info.dyn_addr;
> +	mi->mwl = info.max_write_len;
> +	mi->mrl = info.max_read_len;
> +	mi->pid = info.pid;
> +
> +	rc = i3c_device_request_ibi(mi->i3c, &ibi);
> +	if (rc == 0) {
> +		ibi_set = true;
> +	} else if (rc == -ENOTSUPP) {
> +		/* This driver only supports In-Band Interrupt mode
> +		 * (ENOTSUPP is from the i3c layer, not EOPNOTSUPP).
> +		 * Support for Polling Mode could be added if required.
> +		 */
> +		dev_warn(i3cdev_to_dev(mi->i3c), "Failed, bus driver doesn't support In-Band Interrupts");
> +		goto err;
> +	} else {
> +		dev_err(i3cdev_to_dev(mi->i3c),
> +			"Failed requesting IBI (%d)\n", rc);
> +		goto err;
> +	}
> +
> +	if (ibi_set) {
> +		/* Device setup must be complete when IBI is enabled */
> +		rc = i3c_device_enable_ibi(mi->i3c);
> +		if (rc < 0) {
> +			/* Assume a driver supporting request_ibi also
> +			 * supports enable_ibi.
> +			 */
> +			dev_err(i3cdev_to_dev(mi->i3c),
> +				"Failed enabling IBI (%d)\n", rc);
> +			goto err;
> +		}
> +		ibi_enabled = true;
> +	}
> +
> +	return 0;
> +err:
> +	if (ibi_enabled)
> +		i3c_device_disable_ibi(mi->i3c);

Apparently no error code path can reach here with 'ibi_enabled ==
true', if so please drop the above lines.

> +	if (ibi_set)
> +		i3c_device_free_ibi(mi->i3c);
> +	return rc;
> +}
> +
> +/* Adds a new MCTP i3c_device to a bus */
> +static int mctp_i3c_add_device(struct mctp_i3c_bus *mbus,
> +			       struct i3c_device *i3c)
> +__must_hold(&busdevs_lock)
> +{
> +	struct mctp_i3c_device *mi = NULL;
> +	int rc;
> +
> +	mi = kzalloc(sizeof(*mi), GFP_KERNEL);
> +	if (!mi) {
> +		rc = -ENOMEM;
> +		goto err;
> +	}
> +	mi->mbus = mbus;
> +	mi->i3c = i3c;
> +	mutex_init(&mi->lock);
> +	list_add(&mi->list, &mbus->devs);
> +
> +	i3cdev_set_drvdata(i3c, mi);
> +	rc = mctp_i3c_setup(mi);
> +	if (rc < 0)
> +		goto err;

You can make the code simpler with:

		goto free;
> +
> +	return 0;

and here:

free:
	list_del(&mi->list);
	kfree(mi);

err:
	dev_warn(i3cdev_to_dev(i3c), "Error adding mctp-i3c device, %d\n", rc);
	return rc;

> +err:
> +	dev_warn(i3cdev_to_dev(i3c), "Error adding mctp-i3c device, %d\n", rc);
> +	if (mi) {
> +		list_del(&mi->list);
> +		kfree(mi);
> +	}
> +	return rc;
> +}
> +
> +static int mctp_i3c_probe(struct i3c_device *i3c)
> +{
> +	struct mctp_i3c_bus *b = NULL, *mbus = NULL;
> +	int rc;
> +
> +	/* Look for a known bus */
> +	mutex_lock(&busdevs_lock);
> +	list_for_each_entry(b, &busdevs, list)
> +		if (b->bus == i3c->bus) {
> +			mbus = b;
> +			break;
> +		}
> +	mutex_unlock(&busdevs_lock);
> +
> +	if (!mbus) {
> +		/* probably no "mctp-controller" property on the i3c bus */
> +		return -ENODEV;
> +	}
> +
> +	rc = mctp_i3c_add_device(mbus, i3c);
> +	if (!rc)
> +		goto err;

This is confusing: if 'rc' is zero (!rc) the function will return 0
('return rc' later), and otherwise it will return zero again.

Either ignore the return code, or more likely the error path need some
change.

> +static void mctp_i3c_xmit(struct mctp_i3c_bus *mbus, struct sk_buff *skb)
> +{
> +	struct net_device_stats *stats = &mbus->ndev->stats;
> +	struct i3c_priv_xfer xfer = { .rnw = false };
> +	struct mctp_i3c_internal_hdr *ihdr = NULL;
> +	struct mctp_i3c_device *mi = NULL;
> +	unsigned int data_len;
> +	u8 *data = NULL;
> +	u8 addr, pec;
> +	int rc = 0;
> +	u64 pid;
> +
> +	skb_pull(skb, sizeof(struct mctp_i3c_internal_hdr));
> +	data_len = skb->len;
> +
> +	ihdr = (void *)skb_mac_header(skb);
> +
> +	pid = get_unaligned_be48(ihdr->dest);
> +	mi = mctp_i3c_lookup(mbus, pid);
> +	if (!mi) {
> +		/* I3C endpoint went away after the packet was enqueued? */
> +		stats->tx_dropped++;
> +		goto out;
> +	}
> +
> +	if (WARN_ON_ONCE(data_len + 1 > MCTP_I3C_MAXBUF))
> +		goto out;
> +
> +	if (data_len + 1 > (unsigned int)mi->mwl) {
> +		/* Route MTU was larger than supported by the endpoint */
> +		stats->tx_dropped++;
> +		goto out;
> +	}
> +
> +	/* Need a linear buffer with space for the PEC */
> +	xfer.len = data_len + 1;
> +	if (skb_tailroom(skb) >= 1) {
> +		skb_put(skb, 1);
> +		data = skb->data;
> +	} else {
> +		// TODO: test this

I hope this comment is a left over? In any case please avoid c++ style
comments.

> +		/* Otherwise need to copy the buffer */
> +		skb_copy_bits(skb, 0, mbus->tx_scratch, skb->len);
> +		data = mbus->tx_scratch;
> +	}
> +
> +	/* PEC calculation */
> +	addr = mi->addr << 1;
> +	pec = i2c_smbus_pec(0, &addr, 1);
> +	pec = i2c_smbus_pec(pec, data, data_len);
> +	data[data_len] = pec;
> +
> +	xfer.data.out = data;
> +	rc = i3c_device_do_priv_xfers(mi->i3c, &xfer, 1);
> +	if (rc == 0) {
> +		stats->tx_bytes += data_len;
> +		stats->tx_packets++;
> +	} else {
> +		stats->tx_errors++;
> +	}
> +
> +out:
> +	if (mi)
> +		mutex_unlock(&mi->lock);
> +}
> +
> +static int mctp_i3c_tx_thread(void *data)
> +{
> +	struct mctp_i3c_bus *mbus = data;
> +	struct sk_buff *skb;
> +	unsigned long flags;
> +
> +	for (;;) {
> +		if (kthread_should_stop())
> +			break;
> +
> +		spin_lock_irqsave(&mbus->tx_lock, flags);
> +		skb = mbus->tx_skb;
> +		mbus->tx_skb = NULL;
> +		spin_unlock_irqrestore(&mbus->tx_lock, flags);
> +
> +		if (netif_queue_stopped(mbus->ndev))
> +			netif_wake_queue(mbus->ndev);
> +
> +		if (skb) {
> +			mctp_i3c_xmit(mbus, skb);
> +			kfree_skb(skb);
> +		} else {
> +			wait_event_idle(mbus->tx_wq,
> +					mbus->tx_skb || kthread_should_stop());
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static netdev_tx_t mctp_i3c_start_xmit(struct sk_buff *skb,
> +				       struct net_device *ndev)
> +{
> +	struct mctp_i3c_bus *mbus = netdev_priv(ndev);
> +	unsigned long flags;
> +	netdev_tx_t ret;
> +
> +	spin_lock_irqsave(&mbus->tx_lock, flags);

Why are you using the _irqsave variant? The only other path acquiring
this lock is mctp_i3c_tx_thread(), in process context, while here we
have BH disabled. Plain spin_lock should suffice here, paired with _BH
variant in mctp_i3c_tx_thread.

> +	netif_stop_queue(ndev);
> +	if (mbus->tx_skb) {
> +		dev_warn_ratelimited(&ndev->dev, "TX with queue stopped");
> +		ret = NETDEV_TX_BUSY;
> +	} else {
> +		mbus->tx_skb = skb;
> +		ret = NETDEV_TX_OK;
> +	}
> +	spin_unlock_irqrestore(&mbus->tx_lock, flags);
> +
> +	if (ret == NETDEV_TX_OK)
> +		wake_up(&mbus->tx_wq);
> +
> +	return ret;
> +}

[...]

> +/* Returns an ERR_PTR on failure */
> +static struct mctp_i3c_bus *mctp_i3c_bus_add(struct i3c_bus *bus)
> +__must_hold(&busdevs_lock)
> +{
> +	struct mctp_i3c_bus *mbus = NULL;
> +	struct net_device *ndev = NULL;
> +	char namebuf[IFNAMSIZ];
> +	u8 addr[PID_SIZE];
> +	int rc;
> +
> +	if (!mctp_i3c_is_mctp_controller(bus))
> +		return ERR_PTR(-ENOENT);
> +
> +	snprintf(namebuf, sizeof(namebuf), "mctpi3c%d", bus->id);
> +	ndev = alloc_netdev(sizeof(*mbus), namebuf, NET_NAME_ENUM,
> +			    mctp_i3c_net_setup);
> +	if (!ndev) {
> +		rc = -ENOMEM;
> +		goto err;
> +	}
> +
> +	mbus = netdev_priv(ndev);
> +	mbus->ndev = ndev;
> +	mbus->bus = bus;
> +	INIT_LIST_HEAD(&mbus->devs);
> +	list_add(&mbus->list, &busdevs);
> +
> +	rc = mctp_i3c_bus_local_pid(bus, &mbus->pid);
> +	if (rc < 0) {
> +		dev_err(&ndev->dev, "No I3C PID available\n");
> +		goto err;
> +	}
> +	put_unaligned_be48(mbus->pid, addr);
> +	dev_addr_set(ndev, addr);
> +
> +	init_waitqueue_head(&mbus->tx_wq);
> +	spin_lock_init(&mbus->tx_lock);
> +	mbus->tx_thread = kthread_run(mctp_i3c_tx_thread, mbus,
> +				      "%s/tx", ndev->name);
> +	if (IS_ERR(mbus->tx_thread)) {
> +		dev_warn(&ndev->dev, "Error creating thread: %pe\n",
> +			 mbus->tx_thread);
> +		rc = PTR_ERR(mbus->tx_thread);
> +		mbus->tx_thread = NULL;
> +		goto err;
> +	}
> +
> +	rc = mctp_register_netdev(ndev, NULL);
> +	if (rc < 0) {
> +		dev_warn(&ndev->dev, "netdev register failed: %d\n", rc);
> +		goto err;
> +	}
> +	return mbus;
> +err:
> +	/* uninit will not get called if a netdev has not been registered,
> +	 * so we perform the same mbus cleanup manually.
> +	 */
> +	if (mbus)
> +		mctp_i3c_bus_free(mbus);
> +	if (ndev)
> +		free_netdev(ndev);

A more conventional way of handling the error paths would be using
multiple labels, e.g.:

err_free_bus:
	mctp_i3c_bus_free(mbus);

err_free_ndev:
	free_netdev(ndev);

err:

> +	return ERR_PTR(rc);
> +}

Cheers,

Paolo


-- 
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c

  reply	other threads:[~2023-10-12 11:53 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-09  2:54 [PATCH net-next v5 0/3] I3C MCTP net driver Matt Johnston
2023-10-09  2:54 ` Matt Johnston
2023-10-09  2:54 ` [PATCH net-next v5 1/3] dt-bindings: i3c: Add mctp-controller property Matt Johnston
2023-10-09  2:54   ` Matt Johnston
2023-10-09  2:54 ` [PATCH net-next v5 2/3] i3c: Add support for bus enumeration & notification Matt Johnston
2023-10-09  2:54   ` Matt Johnston
2023-10-09  2:54 ` [PATCH net-next v5 3/3] mctp i3c: MCTP I3C driver Matt Johnston
2023-10-09  2:54   ` Matt Johnston
2023-10-12 11:50   ` Paolo Abeni [this message]
2023-10-12 11:50     ` Paolo Abeni

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=e704c45bc3c81d45541b82bded0618380d81634f.camel@redhat.com \
    --to=pabeni@redhat.com \
    --cc=alexandre.belloni@bootlin.com \
    --cc=conor+dt@kernel.org \
    --cc=davem@davemloft.net \
    --cc=devicetree@vger.kernel.org \
    --cc=edumazet@google.com \
    --cc=jk@codeconstruct.com.au \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=kuba@kernel.org \
    --cc=linux-i3c@lists.infradead.org \
    --cc=matt@codeconstruct.com.au \
    --cc=miquel.raynal@bootlin.com \
    --cc=netdev@vger.kernel.org \
    --cc=robh+dt@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.