linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: Basharath Hussain Khaja <basharath@couthit.com>
To: Joe Damato <jdamato@fastly.com>
Cc: nm <nm@ti.com>, vigneshr <vigneshr@ti.com>,
	tony <tony@atomide.com>, edumazet <edumazet@google.com>,
	krishna <krishna@couthit.com>, pmohan <pmohan@couthit.com>,
	diogo ivo <diogo.ivo@siemens.com>, Rob Herring <robh@kernel.org>,
	javier carrasco cruz <javier.carrasco.cruz@gmail.com>,
	praneeth <praneeth@ti.com>, m-karicheri2 <m-karicheri2@ti.com>,
	basharath <basharath@couthit.com>, kuba <kuba@kernel.org>,
	pabeni <pabeni@redhat.com>,
	devicetree <devicetree@vger.kernel.org>,
	conor+dt <conor+dt@kernel.org>, schnelle <schnelle@linux.ibm.com>,
	mohan <mohan@couthit.com>,
	richardcochran <richardcochran@gmail.com>,
	prajith <prajith@ti.com>, rogerq <rogerq@kernel.org>,
	jacob e keller <jacob.e.keller@intel.com>,
	ssantosh <ssantosh@kernel.org>,
	linux-omap <linux-omap@vger.kernel.org>,
	linux-arm-kernel <linux-arm-kernel@lists.infradead.org>,
	rogerq <rogerq@ti.com>, srk <srk@ti.com>,
	pratheesh <pratheesh@ti.com>, m-malladi <m-malladi@ti.com>,
	netdev <netdev@vger.kernel.org>, rdunlap <rdunlap@infradead.org>,
	linux-kernel <linux-kernel@vger.kernel.org>,
	danishanwar <danishanwar@ti.com>, afd <afd@ti.com>,
	andrew+netdev <andrew+netdev@lunn.ch>,
	parvathi <parvathi@couthit.com>, horms <horms@kernel.org>,
	krzk+dt <krzk+dt@kernel.org>, davem <davem@davemloft.net>
Subject: Re: [RFC v2 PATCH 04/10] net: ti: prueth: Adds link detection, RX and TX support.
Date: Wed, 29 Jan 2025 11:11:08 +0530 (IST)	[thread overview]
Message-ID: <1925493932.450322.1738129268925.JavaMail.zimbra@couthit.local> (raw)
In-Reply-To: <Z5QegAP71PkbppOO@LQ3V64L9R2>

> On Fri, Jan 24, 2025 at 06:07:01PM +0530, Basharath Hussain Khaja wrote:
>> From: Roger Quadros <rogerq@ti.com>
>> 
>> Changes corresponding to link configuration such as speed and duplexity.
>> IRQ and handler initializations are performed for packet reception.Firmware
>> receives the packet from the wire and stores it into OCMC queue. Next, it
>> notifies the CPU via interrupt. Upon receiving the interrupt CPU will
>> service the IRQ and packet will be processed by pushing the newly allocated
>> SKB to upper layers.
>> 
>> When the user application want to transmit a packet, it will invoke
>> sys_send() which will inturn invoke the PRUETH driver, then it will write
>> the packet into OCMC queues. PRU firmware will pick up the packet and
>> transmit it on to the wire.
>> 
>> Signed-off-by: Roger Quadros <rogerq@ti.com>
>> Signed-off-by: Andrew F. Davis <afd@ti.com>
>> Signed-off-by: Parvathi Pudi <parvathi@couthit.com>
>> Signed-off-by: Basharath Hussain Khaja <basharath@couthit.com>
>> ---
>>  drivers/net/ethernet/ti/icssm/icssm_prueth.c | 599 ++++++++++++++++++-
>>  drivers/net/ethernet/ti/icssm/icssm_prueth.h |  46 ++
>>  2 files changed, 640 insertions(+), 5 deletions(-)
>> 
>> diff --git a/drivers/net/ethernet/ti/icssm/icssm_prueth.c
>> b/drivers/net/ethernet/ti/icssm/icssm_prueth.c
>> index 82ed0e3a0d88..0ba1d16a7a15 100644
>> --- a/drivers/net/ethernet/ti/icssm/icssm_prueth.c
>> +++ b/drivers/net/ethernet/ti/icssm/icssm_prueth.c
> 
> [...]
> 
>> +/**
>> + * icssm_prueth_tx_enqueue - queue a packet to firmware for transmission
>> + *
>> + * @emac: EMAC data structure
>> + * @skb: packet data buffer
>> + * @queue_id: priority queue id
>> + *
>> + * Return: 0 (Success)
>> + */
>> +static int icssm_prueth_tx_enqueue(struct prueth_emac *emac,
>> +				   struct sk_buff *skb,
>> +				   enum prueth_queue_id queue_id)
>> +{
> 
> [...]
> 
>> +
>> +	/* which port to tx: MII0 or MII1 */
>> +	txport = emac->tx_port_queue;
>> +	src_addr = skb->data;
>> +	pktlen = skb->len;
>> +	/* Get the tx queue */
>> +	queue_desc = emac->tx_queue_descs + queue_id;
>> +	txqueue = &queue_infos[txport][queue_id];
>> +
>> +	buffer_desc_count = txqueue->buffer_desc_end -
>> +			    txqueue->buffer_desc_offset;
>> +	buffer_desc_count /= BD_SIZE;
>> +	buffer_desc_count++;
>> +
>> +	bd_rd_ptr = readw(&queue_desc->rd_ptr);
>> +	bd_wr_ptr = readw(&queue_desc->wr_ptr);
>> +
>> +	/* the PRU firmware deals mostly in pointers already
>> +	 * offset into ram, we would like to deal in indexes
>> +	 * within the queue we are working with for code
>> +	 * simplicity, calculate this here
>> +	 */
>> +	write_block = (bd_wr_ptr - txqueue->buffer_desc_offset) / BD_SIZE;
>> +	read_block = (bd_rd_ptr - txqueue->buffer_desc_offset) / BD_SIZE;
> 
> Seems like there's a lot of similar code repeated in the rx code
> path.
> 
> Maybe there's a way to simplify it all with a helper of some sort?
> 

We will plan to re-look into common code (more than twice) and create a helper
function and use it.

>> +	if (write_block > read_block) {
>> +		free_blocks = buffer_desc_count - write_block;
>> +		free_blocks += read_block;
>> +	} else if (write_block < read_block) {
>> +		free_blocks = read_block - write_block;
>> +	} else { /* they are all free */
>> +		free_blocks = buffer_desc_count;
>> +	}
>> +
>> +	pkt_block_size = DIV_ROUND_UP(pktlen, ICSS_BLOCK_SIZE);
>> +	if (pkt_block_size > free_blocks) /* out of queue space */
>> +		return -ENOBUFS;
>> +
>> +	/* calculate end BD address post write */
>> +	update_block = write_block + pkt_block_size;
>> +
>> +	/* Check for wrap around */
>> +	if (update_block >= buffer_desc_count) {
>> +		update_block %= buffer_desc_count;
>> +		buffer_wrapped = true;
>> +	}
>> +
>> +	/* OCMC RAM is not cached and write order is not important */
>> +	ocmc_ram = (__force void *)emac->prueth->mem[PRUETH_MEM_OCMC].va;
>> +	dst_addr = ocmc_ram + txqueue->buffer_offset +
>> +		   (write_block * ICSS_BLOCK_SIZE);
>> +
>> +	/* Copy the data from socket buffer(DRAM) to PRU buffers(OCMC) */
>> +	if (buffer_wrapped) { /* wrapped around buffer */
>> +		int bytes = (buffer_desc_count - write_block) * ICSS_BLOCK_SIZE;
>> +		int remaining;
>> +
>> +		/* bytes is integral multiple of ICSS_BLOCK_SIZE but
>> +		 * entire packet may have fit within the last BD
>> +		 * if pkt_info.length is not integral multiple of
>> +		 * ICSS_BLOCK_SIZE
>> +		 */
>> +		if (pktlen < bytes)
>> +			bytes = pktlen;
>> +
>> +		/* copy non-wrapped part */
>> +		memcpy(dst_addr, src_addr, bytes);
>> +
>> +		/* copy wrapped part */
>> +		src_addr += bytes;
>> +		remaining = pktlen - bytes;
>> +		dst_addr = ocmc_ram + txqueue->buffer_offset;
>> +		memcpy(dst_addr, src_addr, remaining);
>> +	} else {
>> +		memcpy(dst_addr, src_addr, pktlen);
>> +	}
>> +
>> +       /* update first buffer descriptor */
>> +	wr_buf_desc = (pktlen << PRUETH_BD_LENGTH_SHIFT) &
>> +		       PRUETH_BD_LENGTH_MASK;
>> +	writel(wr_buf_desc, dram + bd_wr_ptr);
>> +
>> +	/* update the write pointer in this queue descriptor, the firmware
>> +	 * polls for this change so this will signal the start of transmission
>> +	 */
>> +	update_wr_ptr = txqueue->buffer_desc_offset + (update_block * BD_SIZE);
>> +	writew(update_wr_ptr, &queue_desc->wr_ptr);
>> +
>> +	return 0;
>> +}
> 
> [...]
> 
>> +
>> +/* get packet from queue
>> + * negative for error
>> + */
> 
> The comment above seems superfluous and does not seem to follow the
> format of the tx comment which appears to use kdoc style
> 

We will address in the next version.

>> +int icssm_emac_rx_packet(struct prueth_emac *emac, u16 *bd_rd_ptr,
>> +			 struct prueth_packet_info *pkt_info,
>> +			 const struct prueth_queue_info *rxqueue)
>> +{
> 
> [...]
> 
>> +
>> +	/* the PRU firmware deals mostly in pointers already
>> +	 * offset into ram, we would like to deal in indexes
>> +	 * within the queue we are working with for code
>> +	 * simplicity, calculate this here
>> +	 */
>> +	buffer_desc_count = rxqueue->buffer_desc_end -
>> +			    rxqueue->buffer_desc_offset;
>> +	buffer_desc_count /= BD_SIZE;
>> +	buffer_desc_count++;
>> +	read_block = (*bd_rd_ptr - rxqueue->buffer_desc_offset) / BD_SIZE;
>> +	pkt_block_size = DIV_ROUND_UP(pkt_info->length, ICSS_BLOCK_SIZE);
>> +
>> +	/* calculate end BD address post read */
>> +	update_block = read_block + pkt_block_size;
>> +
>> +	/* Check for wrap around */
>> +	if (update_block >= buffer_desc_count) {
>> +		update_block %= buffer_desc_count;
>> +		if (update_block)
>> +			buffer_wrapped = true;
>> +	}
>> +
>> +	/* calculate new pointer in ram */
>> +	*bd_rd_ptr = rxqueue->buffer_desc_offset + (update_block * BD_SIZE);
> 
> Seems like there's a lot of repeated math here and in the above
> function. Maybe this can be simplified with a helper function to
> avoid repeating the math in multiple places?
> 

We will plan to re-look into common code (more than twice) and create a helper
function and use it.

>> +
>> +	/* Pkt len w/ HSR tag removed, If applicable */
>> +	actual_pkt_len = pkt_info->length - start_offset;
>> +
>> +	/* Allocate a socket buffer for this packet */
>> +	skb = netdev_alloc_skb_ip_align(ndev, actual_pkt_len);
>> +	if (!skb) {
>> +		if (netif_msg_rx_err(emac) && net_ratelimit())
>> +			netdev_err(ndev, "failed rx buffer alloc\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	dst_addr = skb->data;
>> +
>> +	/* OCMC RAM is not cached and read order is not important */
>> +	ocmc_ram = (__force void *)emac->prueth->mem[PRUETH_MEM_OCMC].va;
>> +
>> +	/* Get the start address of the first buffer from
>> +	 * the read buffer description
>> +	 */
>> +	src_addr = ocmc_ram + rxqueue->buffer_offset +
>> +		   (read_block * ICSS_BLOCK_SIZE);
>> +	src_addr += start_offset;
>> +
>> +	/* Copy the data from PRU buffers(OCMC) to socket buffer(DRAM) */
>> +	if (buffer_wrapped) { /* wrapped around buffer */
>> +		int bytes = (buffer_desc_count - read_block) * ICSS_BLOCK_SIZE;
>> +		int remaining;
>> +		/* bytes is integral multiple of ICSS_BLOCK_SIZE but
>> +		 * entire packet may have fit within the last BD
>> +		 * if pkt_info.length is not integral multiple of
>> +		 * ICSS_BLOCK_SIZE
>> +		 */
>> +		if (pkt_info->length < bytes)
>> +			bytes = pkt_info->length;
>> +
>> +		/* If applicable, account for the HSR tag removed */
>> +		bytes -= start_offset;
>> +
>> +		/* copy non-wrapped part */
>> +		memcpy(dst_addr, src_addr, bytes);
>> +
>> +		/* copy wrapped part */
>> +		dst_addr += bytes;
>> +		remaining = actual_pkt_len - bytes;
>> +
>> +		src_addr = ocmc_ram + rxqueue->buffer_offset;
>> +		memcpy(dst_addr, src_addr, remaining);
>> +		src_addr += remaining;
>> +	} else {
>> +		memcpy(dst_addr, src_addr, actual_pkt_len);
>> +		src_addr += actual_pkt_len;
>> +	}
>> +
>> +	if (!pkt_info->sv_frame) {
>> +		skb_put(skb, actual_pkt_len);
>> +
>> +		/* send packet up the stack */
>> +		skb->protocol = eth_type_trans(skb, ndev);
>> +		local_bh_disable();
>> +		netif_receive_skb(skb);
>> +		local_bh_enable();
>> +	} else {
>> +		dev_kfree_skb_any(skb);
>> +	}
>> +
>> +	/* update stats */
>> +	ndev->stats.rx_bytes += actual_pkt_len;
>> +	ndev->stats.rx_packets++;
> 
> See comment below about atomicity.
> 
>> +	return 0;
>> +}
>> +
>> +/**
>> + * icssm_emac_rx_thread - EMAC Rx interrupt thread handler
>> + * @irq: interrupt number
>> + * @dev_id: pointer to net_device
>> + *
>> + * EMAC Rx Interrupt thread handler - function to process the rx frames in a
>> + * irq thread function. There is only limited buffer at the ingress to
>> + * queue the frames. As the frames are to be emptied as quickly as
>> + * possible to avoid overflow, irq thread is necessary. Current implementation
>> + * based on NAPI poll results in packet loss due to overflow at
>> + * the ingress queues. Industrial use case requires loss free packet
>> + * processing. Tests shows that with threaded irq based processing,
>> + * no overflow happens when receiving at ~92Mbps for MTU sized frames and thus
>> + * meet the requirement for industrial use case.
> 
> That's interesting. Any idea why this is the case? Is there not
> enough CPU for softirq/NAPI processing to run or something? I
> suppose I'd imagine that NAPI would run and if data is arriving fast
> enough, the NAPI would be added to the repoll list and processed
> later.
> 
> So I guess either there isn't enough CPU or the ingress queues don't
> have many descriptors or something like that ?
> 

This is due to combination of both limited number of buffer descriptors 
(memory constraints) and also not having enough CPU.

>> + *
>> + * Return: interrupt handled condition
>> + */
>> +static irqreturn_t icssm_emac_rx_thread(int irq, void *dev_id)
>> +{
>> +	struct net_device *ndev = (struct net_device *)dev_id;
>> +	struct prueth_emac *emac = netdev_priv(ndev);
>> +	struct prueth_queue_desc __iomem *queue_desc;
>> +	const struct prueth_queue_info *rxqueue;
>> +	struct prueth *prueth = emac->prueth;
>> +	struct net_device_stats *ndevstats;
>> +	struct prueth_packet_info pkt_info;
>> +	int start_queue, end_queue;
>> +	void __iomem *shared_ram;
>> +	u16 bd_rd_ptr, bd_wr_ptr;
>> +	u16 update_rd_ptr;
>> +	u8 overflow_cnt;
>> +	u32 rd_buf_desc;
>> +	int used = 0;
>> +	int i, ret;
>> +
>> +	ndevstats = &emac->ndev->stats;
> 
> FWIW the docs in include/linux/netdevice.h say:
> 
> /**
> ...
> *      @stats:         Statistics struct, which was left as a legacy, use
> *                      rtnl_link_stats64 instead
> ...
> */
> struct net_device {
>  ...
>  struct net_device_stats stats; /* not used by modern drivers */
>  ...
> };
> 
> perhaps consider using rtnl_link_stats64 as suggested instead?
> 
>> +	shared_ram = emac->prueth->mem[PRUETH_MEM_SHARED_RAM].va;
>> +
>> +	start_queue = emac->rx_queue_start;
>> +	end_queue = emac->rx_queue_end;
>> +retry:
>> +	/* search host queues for packets */
>> +	for (i = start_queue; i <= end_queue; i++) {
>> +		queue_desc = emac->rx_queue_descs + i;
>> +		rxqueue = &queue_infos[PRUETH_PORT_HOST][i];
>> +
>> +		overflow_cnt = readb(&queue_desc->overflow_cnt);
>> +		if (overflow_cnt > 0) {
>> +			emac->ndev->stats.rx_over_errors += overflow_cnt;
>> +			/* reset to zero */
>> +			writeb(0, &queue_desc->overflow_cnt);
>> +		}
>> +
>> +		bd_rd_ptr = readw(&queue_desc->rd_ptr);
>> +		bd_wr_ptr = readw(&queue_desc->wr_ptr);
>> +
>> +		/* while packets are available in this queue */
>> +		while (bd_rd_ptr != bd_wr_ptr) {
>> +			/* get packet info from the read buffer descriptor */
>> +			rd_buf_desc = readl(shared_ram + bd_rd_ptr);
>> +			icssm_parse_packet_info(prueth, rd_buf_desc, &pkt_info);
>> +
>> +			if (pkt_info.length <= 0) {
>> +				/* a packet length of zero will cause us to
>> +				 * never move the read pointer ahead, locking
>> +				 * the driver, so we manually have to move it
>> +				 * to the write pointer, discarding all
>> +				 * remaining packets in this queue. This should
>> +				 * never happen.
>> +				 */
>> +				update_rd_ptr = bd_wr_ptr;
>> +				ndevstats->rx_length_errors++;
> 
> See question below.
> 
>> +			} else if (pkt_info.length > EMAC_MAX_FRM_SUPPORT) {
>> +				/* if the packet is too large we skip it but we
>> +				 * still need to move the read pointer ahead
>> +				 * and assume something is wrong with the read
>> +				 * pointer as the firmware should be filtering
>> +				 * these packets
>> +				 */
>> +				update_rd_ptr = bd_wr_ptr;
>> +				ndevstats->rx_length_errors++;
> 
> in netdevice.h it says:
> 
> * struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
> *      Called when a user wants to get the network device usage
> *      statistics. Drivers must do one of the following:
> *      1. Define @ndo_get_stats64 to fill in a zero-initialised
> *         rtnl_link_stats64 structure passed by the caller.
> *      2. Define @ndo_get_stats to update a net_device_stats structure
> *         (which should normally be dev->stats) and return a pointer to
> *         it. The structure may be changed asynchronously only if each
> *         field is written atomically.
> *      3. Update dev->stats asynchronously and atomically, and define
> *         neither operation.
> 
> I didn't look in the other patches to see if ndo_get_stats is
> defined or not, but are these increments atomic?

This module maintain 32 bit statistics inside PRU firmware. we will 
check the feasibility of using rtnl_link_stats64 and make appropriate 
changes as per your suggestion in next version. 

Thanks & Best Regards,
Basharath


  reply	other threads:[~2025-01-29  5:43 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-24 12:23 [RFC v2 PATCH 00/10] PRU-ICSSM Ethernet Driver Basharath Hussain Khaja
2025-01-24 12:23 ` [RFC v2 PATCH 01/10] dt-bindings: net: ti: Adds DUAL-EMAC mode support on PRU-ICSS2 for AM57xx SOCs Basharath Hussain Khaja
2025-01-24 16:39   ` Conor Dooley
2025-01-29  5:16     ` Basharath Hussain Khaja
2025-01-29 17:48       ` Conor Dooley
2025-02-03 12:29         ` Basharath Hussain Khaja
2025-02-04 18:16           ` Conor Dooley
2025-01-24 12:23 ` [RFC v2 PATCH 02/10] net: ti: prueth: Adds ICSSM Ethernet driver Basharath Hussain Khaja
2025-01-30 11:41   ` Simon Horman
2025-02-01 13:25     ` Basharath Hussain Khaja
2025-01-24 12:23 ` [RFC v2 PATCH 03/10] net: ti: prueth: Adds PRUETH HW and SW configuration Basharath Hussain Khaja
2025-01-30 15:47   ` Simon Horman
2025-02-01 13:34     ` Basharath Hussain Khaja
2025-01-24 13:40 ` [RFC v2 PATCH 04/10] net: ti: prueth: Adds link detection, RX and TX support Basharath Hussain Khaja
2025-01-24 23:20   ` Joe Damato
2025-01-29  5:43     ` Basharath Hussain Khaja
2025-01-24 13:40 ` [RFC v2 PATCH 05/10] net: ti: prueth: Adds ethtool support for ICSSM PRUETH Driver Basharath Hussain Khaja
2025-01-30 17:23   ` Simon Horman
2025-02-01 13:48     ` Basharath Hussain Khaja
2025-01-24 13:40 ` [RFC v2 PATCH 06/10] net: ti: prueth: Adds HW timestamping support for PTP using PRU-ICSS IEP module Basharath Hussain Khaja
2025-01-31 10:33   ` Simon Horman
2025-02-05 12:24     ` Basharath Hussain Khaja
2025-01-24 13:40 ` [RFC v2 PATCH 07/10] net: ti: prueth: Adds support for network filters for traffic control supported by PRU-ICSS Basharath Hussain Khaja
2025-01-24 14:45 ` [RFC v2 PATCH 08/10] net: ti: prueth: Adds support for RX interrupt coalescing/pacing Basharath Hussain Khaja
2025-01-24 14:45 ` [RFC v2 PATCH 09/10] net: ti: prueth: Adds power management support for PRU-ICSS Basharath Hussain Khaja
2025-01-24 14:45 ` [RFC v2 PATCH 10/10] arm: dts: ti: Adds device tree nodes for PRU Cores, IEP and eCAP modules of PRU-ICSS2 Instance Basharath Hussain Khaja
     [not found] ` <20250124123707.1457639-5-basharath@couthit.com>
2025-01-24 23:13   ` [RFC v2 PATCH 04/10] net: ti: prueth: Adds link detection, RX and TX support Joe Damato
2025-01-29  5:41     ` Basharath Hussain Khaja [this message]
2025-01-30 16:45   ` Simon Horman
2025-02-01 13:37     ` Basharath Hussain Khaja

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=1925493932.450322.1738129268925.JavaMail.zimbra@couthit.local \
    --to=basharath@couthit.com \
    --cc=afd@ti.com \
    --cc=andrew+netdev@lunn.ch \
    --cc=conor+dt@kernel.org \
    --cc=danishanwar@ti.com \
    --cc=davem@davemloft.net \
    --cc=devicetree@vger.kernel.org \
    --cc=diogo.ivo@siemens.com \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=jacob.e.keller@intel.com \
    --cc=javier.carrasco.cruz@gmail.com \
    --cc=jdamato@fastly.com \
    --cc=krishna@couthit.com \
    --cc=krzk+dt@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=m-karicheri2@ti.com \
    --cc=m-malladi@ti.com \
    --cc=mohan@couthit.com \
    --cc=netdev@vger.kernel.org \
    --cc=nm@ti.com \
    --cc=pabeni@redhat.com \
    --cc=parvathi@couthit.com \
    --cc=pmohan@couthit.com \
    --cc=prajith@ti.com \
    --cc=praneeth@ti.com \
    --cc=pratheesh@ti.com \
    --cc=rdunlap@infradead.org \
    --cc=richardcochran@gmail.com \
    --cc=robh@kernel.org \
    --cc=rogerq@kernel.org \
    --cc=rogerq@ti.com \
    --cc=schnelle@linux.ibm.com \
    --cc=srk@ti.com \
    --cc=ssantosh@kernel.org \
    --cc=tony@atomide.com \
    --cc=vigneshr@ti.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).