netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jeff Garzik <jgarzik@pobox.com>
To: torvalds@osdl.org
Cc: netdev@oss.sgi.com
Subject: [bk patches] 2.6.x net driver updates
Date: Sun, 28 Sep 2003 10:45:01 -0400	[thread overview]
Message-ID: <20030928144501.GA16484@gtf.org> (raw)


Linus, please do a

	bk pull bk://kernel.bkbits.net/jgarzik/net-drivers-2.5

This will update the following files:

 drivers/net/Space.c               |    4 
 drivers/net/ne3210.c              |  293 ++++++++++++++++----------------------
 drivers/net/wireless/arlan-main.c |    2 
 include/linux/hdlcdrv.h           |   10 -
 4 files changed, 137 insertions(+), 172 deletions(-)

through these ChangeSets:

<mzyngier@freesurf.fr> (03/09/28 1.1378)
   [PATCH] ne3210 update
   
   The enclosed patch ports the ne3210 driver over the EISA probing API.
   
   It also fixes some ioremap/isa_memcopy_fromio problems (depending on
   where the card memory was mapped) by using ioremap unconditionally and
   letting memcopy_fromio do the right thing.
   
   Finally, it removes the card from Space.c (warning, potential
   interface renumbering !).
   
   The module options are currently disabled, until Rusty's
   module_param_array() patch is included. I will re-introduce them ASAP.
   
   Quite heavily tested on x86.

<shemminger@osdl.org> (03/09/28 1.1377)
   [PATCH] Fix warnings in hamradio/baycom build
   
   Sorry, overlooked the corresponding .h file in that patch, here it is.

<romieu@fr.zoreil.com> (03/09/28 1.1376)
   [PATCH] Fix debug statement after return in drivers/net/wireless/arlan-main.c
   
   This patch applies to 2.5.68 and is listed on kbugs.org. The debug statement
   is never executed because it is after a return.



diff -Nru a/drivers/net/Space.c b/drivers/net/Space.c
--- a/drivers/net/Space.c	Sun Sep 28 10:38:07 2003
+++ b/drivers/net/Space.c	Sun Sep 28 10:38:07 2003
@@ -67,7 +67,6 @@
 extern int ac3200_probe(struct net_device *);
 extern int es_probe(struct net_device *);
 extern int lne390_probe(struct net_device *);
-extern int ne3210_probe(struct net_device *);
 extern int e2100_probe(struct net_device *);
 extern int ni5010_probe(struct net_device *);
 extern int ni52_probe(struct net_device *);
@@ -154,9 +153,6 @@
 #endif
 #ifdef CONFIG_LNE390
 	{lne390_probe, 0},
-#endif
-#ifdef CONFIG_NE3210
-	{ne3210_probe, 0},
 #endif
 	{NULL, 0},
 };
diff -Nru a/drivers/net/ne3210.c b/drivers/net/ne3210.c
--- a/drivers/net/ne3210.c	Sun Sep 28 10:38:07 2003
+++ b/drivers/net/ne3210.c	Sun Sep 28 10:38:07 2003
@@ -23,6 +23,7 @@
 	This driver WILL NOT WORK FOR THE NE3200 - it is completely different
 	and does not use an 8390 at all.
 
+	Updated to EISA probing API 5/2003 by Marc Zyngier.
 */
 
 static const char *version =
@@ -44,9 +45,6 @@
 
 #include "8390.h"
 
-int ne3210_probe(struct net_device *dev);
-static int ne3210_probe1(struct net_device *dev, int ioaddr);
-
 static int ne3210_open(struct net_device *dev);
 static int ne3210_close(struct net_device *dev);
 
@@ -59,7 +57,6 @@
 #define NE3210_START_PG		0x00    /* First page of TX buffer	*/
 #define NE3210_STOP_PG		0x80    /* Last page +1 of RX ring	*/
 
-#define NE3210_ID_PORT		0xc80	/* Same for all EISA cards 	*/
 #define NE3210_IO_EXTENT	0x20
 #define NE3210_SA_PROM		0x16	/* Start of e'net addr.		*/
 #define NE3210_RESET_PORT	0xc84
@@ -69,10 +66,9 @@
 #define NE3210_ADDR1		0x00
 #define NE3210_ADDR2		0x1b
 
-#define NE3210_ID	0x0118cc3a	/* 0x3acc = 1110 10110 01100 =  nvl */
-
 #define NE3210_CFG1		0xc84	/* NB: 0xc84 is also "reset" port. */
 #define NE3210_CFG2		0xc90
+#define NE3210_CFG_EXTENT       (NE3210_CFG2 - NE3210_CFG1 + 1)
 
 /*
  *	You can OR any of the following bits together and assign it
@@ -89,152 +85,108 @@
 
 static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
 static unsigned int shmem_map[] __initdata = {0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0};
+static const char *ifmap[] __initdata = {"UTP", "?", "BNC", "AUI"};
+static int ifmap_val[] __initdata = {
+		IF_PORT_10BASET,
+		IF_PORT_UNKNOWN,
+		IF_PORT_10BASE2,
+		IF_PORT_AUI,
+};
 
-/*
- *	Probe for the card. The best way is to read the EISA ID if it
- *	is known. Then we can check the prefix of the station address
- *	PROM for a match against the value assigned to Novell.
- */
-
-int __init ne3210_probe(struct net_device *dev)
+static int __init ne3210_eisa_probe (struct device *device)
 {
-	unsigned short ioaddr = dev->base_addr;
-
-	SET_MODULE_OWNER(dev);
+	unsigned long ioaddr, phys_mem;
+	int i, retval, port_index;
+	struct eisa_device *edev = to_eisa_device (device);
+	struct net_device *dev;
 
-	if (ioaddr > 0x1ff)		/* Check a single specified location. */
-		return ne3210_probe1(dev, ioaddr);
-	else if (ioaddr > 0)		/* Don't probe at all. */
-		return -ENXIO;
-
-	if (!EISA_bus) {
-#if NE3210_DEBUG & NE3210_D_PROBE
-		printk("ne3210-debug: Not an EISA bus. Not probing high ports.\n");
-#endif
-		return -ENXIO;
+	/* Allocate dev->priv and fill in 8390 specific dev fields. */
+	if (!(dev = alloc_ei_netdev ())) {
+		printk ("ne3210.c: unable to allocate memory for dev!\n");
+		return -ENOMEM;
 	}
 
-	/* EISA spec allows for up to 16 slots, but 8 is typical. */
-	for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000)
-		if (ne3210_probe1(dev, ioaddr) == 0)
-			return 0;
-
-	return -ENODEV;
-}
-
-static int __init ne3210_probe1(struct net_device *dev, int ioaddr)
-{
-	int i, retval;
-	unsigned long eisa_id;
-	const char *ifmap[] = {"UTP", "?", "BNC", "AUI"};
-
-	if (!request_region(dev->base_addr, NE3210_IO_EXTENT, dev->name))
-		return -EBUSY;
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, device);
+	device->driver_data = dev;
+	ioaddr = edev->base_addr;
 
-	if (inb_p(ioaddr + NE3210_ID_PORT) == 0xff) {
-		retval = -ENODEV;
+	if (ethdev_init (dev)) {
+		printk ("ne3210.c: unable to allocate memory for dev->priv!\n");
+		retval = -ENOMEM;
 		goto out;
 	}
 
-#if NE3210_DEBUG & NE3210_D_PROBE
-	printk("ne3210-debug: probe at %#x, ID %#8x\n", ioaddr, inl(ioaddr + NE3210_ID_PORT));
-	printk("ne3210-debug: config regs: %#x %#x\n",
-		inb(ioaddr + NE3210_CFG1), inb(ioaddr + NE3210_CFG2));
-#endif
-
-
-/*	Check the EISA ID of the card. */
-	eisa_id = inl(ioaddr + NE3210_ID_PORT);
-	if (eisa_id != NE3210_ID) {
-		retval = -ENODEV;
+	if (!request_region(ioaddr, NE3210_IO_EXTENT, dev->name)) {
+		retval = -EBUSY;
 		goto out;
 	}
 
-	
-#if 0
-/*	Check the vendor ID as well. Not really required. */
-	if (inb(ioaddr + NE3210_SA_PROM + 0) != NE3210_ADDR0
-		|| inb(ioaddr + NE3210_SA_PROM + 1) != NE3210_ADDR1
-		|| inb(ioaddr + NE3210_SA_PROM + 2) != NE3210_ADDR2 ) {
-		printk("ne3210.c: card not found");
-		for(i = 0; i < ETHER_ADDR_LEN; i++)
-			printk(" %02x", inb(ioaddr + NE3210_SA_PROM + i));
-		printk(" (invalid prefix).\n");
-		retval = -ENODEV;
-		goto out;
+	if (!request_region(ioaddr + NE3210_CFG1,
+			    NE3210_CFG_EXTENT, dev->name)) {
+		retval = -EBUSY;
+		goto out1;
 	}
+
+#if NE3210_DEBUG & NE3210_D_PROBE
+	printk("ne3210-debug: probe at %#x, ID %s\n", ioaddr, edev->id.sig);
+	printk("ne3210-debug: config regs: %#x %#x\n",
+		inb(ioaddr + NE3210_CFG1), inb(ioaddr + NE3210_CFG2));
 #endif
 
-	/* Allocate dev->priv and fill in 8390 specific dev fields. */
-	if (ethdev_init(dev)) {
-		printk ("ne3210.c: unable to allocate memory for dev->priv!\n");
-		retval = -ENOMEM;
-		goto out;
-	}
 
+	port_index = inb(ioaddr + NE3210_CFG2) >> 6;
 	printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr:",
-		ioaddr/0x1000, ifmap[inb(ioaddr + NE3210_CFG2) >> 6]);
+		edev->slot, ifmap[port_index]);
 	for(i = 0; i < ETHER_ADDR_LEN; i++)
 		printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i)));
-	printk(".\nne3210.c: ");
+	
 
 	/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
-	if (dev->irq == 0) {
-		unsigned char irq_reg = inb(ioaddr + NE3210_CFG2) >> 3;
-		dev->irq = irq_map[irq_reg & 0x07];
-		printk("using");
-	} else {
-		/* This is useless unless we reprogram the card here too */
-		if (dev->irq == 2) dev->irq = 9;	/* Doh! */
-		printk("assigning");
-	}
-	printk(" IRQ %d,", dev->irq);
+	dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07];
+	printk(".\nne3210.c: using IRQ %d, ", dev->irq);
 
 	retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev);
 	if (retval) {
 		printk (" unable to get IRQ %d.\n", dev->irq);
-		goto out1;
-	}
-
-	if (dev->mem_start == 0) {
-		unsigned char mem_reg = inb(ioaddr + NE3210_CFG2) & 0x07;
-		dev->mem_start = shmem_map[mem_reg] * 0x1000;
-		printk(" using ");
-	} else {
-		/* Should check for value in shmem_map and reprogram the card to use it */
-		dev->mem_start &= 0xfff8000;
-		printk(" assigning ");
+		goto out2;
 	}
 
-	printk("%dkB memory at physical address %#lx\n",
-			NE3210_STOP_PG/4, dev->mem_start);
+	phys_mem = shmem_map[inb(ioaddr + NE3210_CFG2) & 0x07] * 0x1000;
 
 	/*
 	   BEWARE!! Some dain-bramaged EISA SCUs will allow you to put
 	   the card mem within the region covered by `normal' RAM  !!!
 	*/
-	if (dev->mem_start > 1024*1024) {	/* phys addr > 1MB */
-		if (dev->mem_start < virt_to_phys(high_memory)) {
+	if (phys_mem > 1024*1024) {	/* phys addr > 1MB */
+		if (phys_mem < virt_to_phys(high_memory)) {
 			printk(KERN_CRIT "ne3210.c: Card RAM overlaps with normal memory!!!\n");
 			printk(KERN_CRIT "ne3210.c: Use EISA SCU to set card memory below 1MB,\n");
 			printk(KERN_CRIT "ne3210.c: or to an address above 0x%lx.\n", virt_to_phys(high_memory));
 			printk(KERN_CRIT "ne3210.c: Driver NOT installed.\n");
 			retval = -EINVAL;
-			goto out2;
+			goto out3;
 		}
-		dev->mem_start = (unsigned long)ioremap(dev->mem_start, NE3210_STOP_PG*0x100);
-		if (dev->mem_start == 0) {
-			printk(KERN_ERR "ne3210.c: Unable to remap card memory above 1MB !!\n");
-			printk(KERN_ERR "ne3210.c: Try using EISA SCU to set memory below 1MB.\n");
-			printk(KERN_ERR "ne3210.c: Driver NOT installed.\n");
-			retval = -EAGAIN;
-			goto out2;
-		}
-		ei_status.reg0 = 1;	/* Use as remap flag */
-		printk("ne3210.c: remapped %dkB card memory to virtual address %#lx\n",
-				NE3210_STOP_PG/4, dev->mem_start);
 	}
+	
+	if (!request_mem_region (phys_mem, NE3210_STOP_PG*0x100, dev->name)) {
+		printk ("ne3210.c: Unable to request shared memory at physical address %#lx\n",
+			phys_mem);
+		goto out3;
+	}
+	
+	printk("%dkB memory at physical address %#lx\n",
+	       NE3210_STOP_PG/4, phys_mem);
 
+	dev->mem_start = (unsigned long)ioremap(phys_mem, NE3210_STOP_PG*0x100);
+	if (dev->mem_start == 0) {
+		printk(KERN_ERR "ne3210.c: Unable to remap card memory !!\n");
+		printk(KERN_ERR "ne3210.c: Driver NOT installed.\n");
+		retval = -EAGAIN;
+		goto out4;
+	}
+	printk("ne3210.c: remapped %dkB card memory to virtual address %#lx\n",
+	       NE3210_STOP_PG/4, dev->mem_start);
 	dev->mem_end = ei_status.rmem_end = dev->mem_start
 		+ (NE3210_STOP_PG - NE3210_START_PG)*256;
 	ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
@@ -247,6 +199,7 @@
 	ei_status.rx_start_page = NE3210_START_PG + TX_PAGES;
 	ei_status.stop_page = NE3210_STOP_PG;
 	ei_status.word16 = 1;
+	ei_status.priv = phys_mem;
 
 	if (ei_debug > 0)
 		printk(version);
@@ -258,18 +211,46 @@
 
 	dev->open = &ne3210_open;
 	dev->stop = &ne3210_close;
+	dev->if_port = ifmap_val[port_index];
+
+	if ((retval = register_netdev (dev)))
+		goto out5;
+		
 	NS8390_init(dev, 0);
 	return 0;
-out2:
-	free_irq(dev->irq, dev);	
-out1:
-	kfree(dev->priv);
-	dev->priv = NULL;
-out:
-	release_region(ioaddr, NE3210_IO_EXTENT);
+
+ out5:
+	iounmap((void *)dev->mem_start);
+ out4:
+	release_mem_region (phys_mem, NE3210_STOP_PG*0x100);
+ out3:
+	free_irq (dev->irq, dev);
+ out2:
+	release_region (ioaddr + NE3210_CFG1, NE3210_CFG_EXTENT);
+ out1:
+	release_region (ioaddr, NE3210_IO_EXTENT);
+ out:
+	free_netdev (dev);
+	
 	return retval;
 }
 
+static int __devexit ne3210_eisa_remove (struct device *device)
+{
+	struct net_device  *dev    = device->driver_data;
+	unsigned long       ioaddr = to_eisa_device (device)->base_addr;
+
+	unregister_netdev (dev);
+	iounmap((void *)dev->mem_start);
+	release_mem_region (ei_status.priv, NE3210_STOP_PG*0x100);
+	free_irq (dev->irq, dev);
+	release_region (ioaddr + NE3210_CFG1, NE3210_CFG_EXTENT);
+	release_region (ioaddr, NE3210_IO_EXTENT);
+	free_netdev (dev);
+
+	return 0;
+}
+
 /*
  *	Reset by toggling the "Board Enable" bits (bit 2 and 0).
  */
@@ -309,7 +290,7 @@
 ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
 {
 	unsigned long hdr_start = dev->mem_start + ((ring_page - NE3210_START_PG)<<8);
-	isa_memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
+	memcpy_fromio(hdr, hdr_start, sizeof(struct e8390_pkt_hdr));
 	hdr->count = (hdr->count + 3) & ~3;     /* Round up allocation. */
 }
 
@@ -327,12 +308,12 @@
 	if (xfer_start + count > ei_status.rmem_end) {
 		/* Packet wraps over end of ring buffer. */
 		int semi_count = ei_status.rmem_end - xfer_start;
-		isa_memcpy_fromio(skb->data, xfer_start, semi_count);
+		memcpy_fromio(skb->data, xfer_start, semi_count);
 		count -= semi_count;
-		isa_memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
+		memcpy_fromio(skb->data + semi_count, ei_status.rmem_start, count);
 	} else {
 		/* Packet is in one chunk. */
-		isa_memcpy_fromio(skb->data, xfer_start, count);
+		memcpy_fromio(skb->data, xfer_start, count);
 	}
 }
 
@@ -342,7 +323,7 @@
 	unsigned long shmem = dev->mem_start + ((start_page - NE3210_START_PG)<<8);
 
 	count = (count + 3) & ~3;     /* Round up to doubleword */
-	isa_memcpy_toio(shmem, buf, count);
+	memcpy_toio(shmem, buf, count);
 }
 
 static int ne3210_open(struct net_device *dev)
@@ -361,7 +342,23 @@
 	return 0;
 }
 
+static struct eisa_device_id ne3210_ids[] = {
+	{ "EGL0101" },
+	{ "NVL1801" },
+	{ "" },
+};
+
+static struct eisa_driver ne3210_eisa_driver = {
+	.id_table = ne3210_ids,
+	.driver   = {
+		.name   = "ne3210",
+		.probe  = ne3210_eisa_probe,
+		.remove = __devexit_p (ne3210_eisa_remove),
+	},
+};
+
 #ifdef MODULE
+#if 0
 #define MAX_NE3210_CARDS	4	/* Max number of NE3210 cards per module */
 static struct net_device dev_ne3210[MAX_NE3210_CARDS];
 static int io[MAX_NE3210_CARDS];
@@ -374,50 +371,22 @@
 MODULE_PARM_DESC(io, "I/O base address(es)");
 MODULE_PARM_DESC(irq, "IRQ number(s)");
 MODULE_PARM_DESC(mem, "memory base address(es)");
+#endif
+#endif /* MODULE */
+
+
 MODULE_DESCRIPTION("NE3210 EISA Ethernet driver");
 MODULE_LICENSE("GPL");
 
-int init_module(void)
+int ne3210_init(void)
 {
-	int this_dev, found = 0;
-
-	for (this_dev = 0; this_dev < MAX_NE3210_CARDS; this_dev++) {
-		struct net_device *dev = &dev_ne3210[this_dev];
-		dev->irq = irq[this_dev];
-		dev->base_addr = io[this_dev];
-		dev->mem_start = mem[this_dev];
-		dev->init = ne3210_probe;
-		/* Default is to only install one card. */
-		if (io[this_dev] == 0 && this_dev != 0) break;
-		if (register_netdev(dev) != 0) {
-			printk(KERN_WARNING "ne3210.c: No NE3210 card found (i/o = 0x%x).\n", io[this_dev]);
-			if (found != 0) {	/* Got at least one. */
-				return 0;
-			}
-			return -ENXIO;
-		}
-		found++;
-	}
-	return 0;
+	return eisa_driver_register (&ne3210_eisa_driver);
 }
 
-void cleanup_module(void)
+void ne3210_cleanup(void)
 {
-	int this_dev;
-
-	for (this_dev = 0; this_dev < MAX_NE3210_CARDS; this_dev++) {
-		struct net_device *dev = &dev_ne3210[this_dev];
-		if (dev->priv != NULL) {
-			free_irq(dev->irq, dev);
-			release_region(dev->base_addr, NE3210_IO_EXTENT);
-			if (ei_status.reg0)
-				iounmap((void *)dev->mem_start);
-			unregister_netdev(dev);
-			kfree(dev->priv);
-			dev->priv = NULL;
-		}
-	}
+	eisa_driver_unregister (&ne3210_eisa_driver);
 }
 
-#endif /* MODULE */
-
+module_init (ne3210_init);
+module_exit (ne3210_cleanup);
diff -Nru a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
--- a/drivers/net/wireless/arlan-main.c	Sun Sep 28 10:38:07 2003
+++ b/drivers/net/wireless/arlan-main.c	Sun Sep 28 10:38:07 2003
@@ -721,9 +721,9 @@
 	else
 	{
 		netif_stop_queue (dev);
-		return -1;
 		IFDEBUG(ARLAN_DEBUG_TX_CHAIN)
 			printk(KERN_ERR "TX TAIL & HEAD full, return, tailStart %d headEnd %d\n", tailStarts, headEnds);
+		return -1;
 	}
 	priv->out_bytes += length;
 	priv->out_bytes10 += length;
diff -Nru a/include/linux/hdlcdrv.h b/include/linux/hdlcdrv.h
--- a/include/linux/hdlcdrv.h	Sun Sep 28 10:38:07 2003
+++ b/include/linux/hdlcdrv.h	Sun Sep 28 10:38:07 2003
@@ -359,11 +359,11 @@
 void hdlcdrv_receiver(struct net_device *, struct hdlcdrv_state *);
 void hdlcdrv_transmitter(struct net_device *, struct hdlcdrv_state *);
 void hdlcdrv_arbitrate(struct net_device *, struct hdlcdrv_state *);
-int hdlcdrv_register_hdlcdrv(struct net_device *dev, const struct hdlcdrv_ops *ops,
-			     unsigned int privsize, char *ifname,
-			     unsigned int baseaddr, unsigned int irq, 
-			     unsigned int dma);
-int hdlcdrv_unregister_hdlcdrv(struct net_device *dev);
+struct net_device *hdlcdrv_register(const struct hdlcdrv_ops *ops,
+				    unsigned int privsize, const char *ifname,
+				    unsigned int baseaddr, unsigned int irq, 
+				    unsigned int dma);
+void hdlcdrv_unregister(struct net_device *dev);
 
 /* -------------------------------------------------------------------- */
 

             reply	other threads:[~2003-09-28 14:45 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-09-28 14:45 Jeff Garzik [this message]
  -- strict thread matches above, loose matches on Subject: below --
2005-03-09 17:22 [BK PATCHES] 2.6.x net driver updates Jeff Garzik
2005-03-08 19:31 Jeff Garzik
2005-03-07 17:10 Jeff Garzik
2005-03-06 23:38 Jeff Garzik
2005-03-05 18:44 Jeff Garzik
2005-01-18  8:15 Jeff Garzik
2005-01-11  5:01 Jeff Garzik
2004-11-05  8:22 Jeff Garzik
2004-10-30 13:32 Jeff Garzik
2004-10-26  5:37 Jeff Garzik
2004-10-25  8:24 Jeff Garzik
2004-10-22  2:11 Jeff Garzik
2004-07-09 20:14 Jeff Garzik
2004-07-02 17:14 Jeff Garzik
2004-07-01  3:54 Jeff Garzik
2004-06-17  1:01 Jeff Garzik
2003-10-14 19:06 Jeff Garzik
2003-09-27 11:55 Jeff Garzik
2003-09-26  1:02 [bk patches] " Jeff Garzik
2003-09-27  5:20 ` Linus Torvalds
2003-09-20 19:27 Jeff Garzik
2003-09-11 19:54 Jeff Garzik
2003-08-08  0:05 Jeff Garzik

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=20030928144501.GA16484@gtf.org \
    --to=jgarzik@pobox.com \
    --cc=netdev@oss.sgi.com \
    --cc=torvalds@osdl.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 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).