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
next prev parent 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: linkBe 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.