All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michal Simek <monstr@seznam.cz>
To: u-boot@lists.denx.de
Subject: [U-Boot-Users] [PATCH 1/4] emac
Date: Sun, 5 Aug 2007 20:56:25 +0200	[thread overview]
Message-ID: <001701c7d792$52efe900$0500a8c0@monstrone> (raw)
In-Reply-To: 0a6b01c7d77e$905d8e50$0500a8c0@monstrone

Hi Grant and everybody,

my patches are below. All patches are in u-boot-microblaze branch.

Signed-off-by: Michal Simek <monstr@monstr.eu>

Emac driver for Microblaze.

Michal Simek

diff --git a/Makefile b/Makefile
index bfa3846..146f647 100644
--- a/Makefile
+++ b/Makefile
@@ -143,7 +143,7 @@ ifeq ($(ARCH),m68k)
 CROSS_COMPILE = m68k-elf-
 endif
 ifeq ($(ARCH),microblaze)
-CROSS_COMPILE = mb-
+CROSS_COMPILE = microblaze-uclinux-
 endif
 ifeq ($(ARCH),blackfin)
 CROSS_COMPILE = bfin-uclinux-
@@ -199,7 +199,7 @@ LIBS += cpu/ixp/npe/libnpe.a
 endif
 LIBS += lib_$(ARCH)/lib$(ARCH).a
 LIBS += fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a 
fs/jffs2/libjffs2.a \
- fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a
+ fs/reiserfs/libreiserfs.a fs/ext2/libext2fs.a fs/romfs/libromfs.a
 LIBS += net/libnet.a
 LIBS += disk/libdisk.a
 LIBS += rtc/librtc.a
@@ -207,6 +207,7 @@ LIBS += dtt/libdtt.a
 LIBS += drivers/libdrivers.a
 LIBS += drivers/nand/libnand.a
 LIBS += drivers/nand_legacy/libnand_legacy.a
+LIBS += drivers/net/libnetdrv.a
 ifeq ($(CPU),mpc83xx)
 LIBS += drivers/qe/qe.a
 endif
@@ -316,14 +317,14 @@ depend dep:
 tags ctags:
   ctags -w -o $(OBJTREE)/ctags `find $(SUBDIRS) include \
     lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \
-    fs/cramfs fs/fat fs/fdos fs/jffs2 \
+    fs/cramfs fs/fat fs/fdos fs/jffs2 fs/romfs\
     net disk rtc dtt drivers drivers/sk98lin common \
    \( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`

 etags:
   etags -a -o $(OBJTREE)/etags `find $(SUBDIRS) include \
     lib_generic board/$(BOARDDIR) cpu/$(CPU) lib_$(ARCH) \
-    fs/cramfs fs/fat fs/fdos fs/jffs2 \
+    fs/cramfs fs/fat fs/fdos fs/jffs2 fs/romfs\
     net disk rtc dtt drivers drivers/sk98lin common \
    \( -name CVS -prune \) -o \( -name '*.[ch]' -print \)`




diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index e69de29..7342dc8 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -0,0 +1,45 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB  := $(obj)libnetdrv.a
+
+COBJS  := xilinx_emaclite.o xilinx_emac.o
+
+SRCS  := $(COBJS:.o=.c)
+OBJS  := $(addprefix $(obj),$(COBJS))
+
+all: $(LIB)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/drivers/net/xilinx_emac.c b/drivers/net/xilinx_emac.c
index e69de29..d44f31e 100644
--- a/drivers/net/xilinx_emac.c
+++ b/drivers/net/xilinx_emac.c
@@ -0,0 +1,372 @@
+/*
+ * (C) Copyright 2007 Michal Simek
+ *
+ * Michal SIMEK <monstr@monstr.eu>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Based on Xilinx drivers
+ *
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+#include <asm/io.h>
+#include <asm/asm.h>
+#include "xilinx_emac.h"
+
+#ifdef XILINX_EMAC
+
+#undef DEBUG
+
+#define ENET_MAX_MTU  PKTSIZE
+#define ENET_ADDR_LENGTH 6
+
+static unsigned int etherrxbuff[PKTSIZE_ALIGN/4]; /* Receive buffer */
+
+static u8 EMACAddr[ENET_ADDR_LENGTH] = { 0x00, 0x0a, 0x35, 0x00, 0x22, 
0x01 };
+
+static XEmac Emac;
+
+void eth_halt(void)
+{
+ return;
+}
+
+int eth_init(bd_t * bis)
+{
+ u32 HelpReg;
+#ifdef DEBUG
+ printf("EMAC Initialization Started\n\r");
+#endif
+ if (Emac.IsStarted) {
+  puts("Emac is started\n");
+  return 0;
+ }
+
+ memset (&Emac, 0, sizeof (XEmac));
+
+ Emac.BaseAddress = XILINX_EMAC_BASEADDR;
+
+ /* Setting up FIFOs */
+ Emac.RecvFifo.RegBaseAddress = Emac.BaseAddress +
+     XEM_PFIFO_RXREG_OFFSET;
+ Emac.RecvFifo.DataBaseAddress = Emac.BaseAddress +
+     XEM_PFIFO_RXDATA_OFFSET;
+ out_be32 (Emac.RecvFifo.RegBaseAddress, XPF_RESET_FIFO_MASK);
+
+ Emac.SendFifo.RegBaseAddress = Emac.BaseAddress +
+     XEM_PFIFO_TXREG_OFFSET;
+ Emac.SendFifo.DataBaseAddress = Emac.BaseAddress +
+     XEM_PFIFO_TXDATA_OFFSET;
+ out_be32 (Emac.SendFifo.RegBaseAddress, XPF_RESET_FIFO_MASK);
+
+ /* Reset the entire IPIF */
+ out_be32 (Emac.BaseAddress + XIIF_V123B_RESETR_OFFSET,
+     XIIF_V123B_RESET_MASK);
+
+ /* Stopping EMAC for setting up MAC */
+ HelpReg = in_be32 (Emac.BaseAddress + XEM_ECR_OFFSET);
+ HelpReg &= ~(XEM_ECR_XMIT_ENABLE_MASK | XEM_ECR_RECV_ENABLE_MASK);
+ out_be32 (Emac.BaseAddress + XEM_ECR_OFFSET, HelpReg);
+
+ if (!getenv("ethaddr")) {
+  memcpy(bis->bi_enetaddr, EMACAddr, ENET_ADDR_LENGTH);
+ }
+
+ /* Set the device station address high and low registers */
+ HelpReg = (bis->bi_enetaddr[0] << 8) | bis->bi_enetaddr[1];
+ out_be32 (Emac.BaseAddress + XEM_SAH_OFFSET, HelpReg);
+ HelpReg = (bis->bi_enetaddr[2] << 24) | (bis->bi_enetaddr[3] << 16) |
+   (bis->bi_enetaddr[4] << 8) | bis->bi_enetaddr[5];
+ out_be32 (Emac.BaseAddress + XEM_SAL_OFFSET, HelpReg);
+
+
+ HelpReg = XEM_ECR_UNICAST_ENABLE_MASK | XEM_ECR_BROAD_ENABLE_MASK |
+  XEM_ECR_FULL_DUPLEX_MASK | XEM_ECR_XMIT_FCS_ENABLE_MASK |
+  XEM_ECR_XMIT_PAD_ENABLE_MASK | XEM_ECR_PHY_ENABLE_MASK;
+ out_be32 (Emac.BaseAddress + XEM_ECR_OFFSET, HelpReg);
+
+ Emac.IsStarted = 1;
+
+ /* Enable the transmitter, and receiver */
+ HelpReg = in_be32 (Emac.BaseAddress + XEM_ECR_OFFSET);
+ HelpReg &= ~(XEM_ECR_XMIT_RESET_MASK | XEM_ECR_RECV_RESET_MASK);
+ HelpReg |= (XEM_ECR_XMIT_ENABLE_MASK | XEM_ECR_RECV_ENABLE_MASK);
+ out_be32 (Emac.BaseAddress + XEM_ECR_OFFSET, HelpReg);
+
+ printf("EMAC Initialization complete\n\r");
+ return 0;
+}
+
+int eth_send(volatile void *ptr, int len)
+{
+ u32 IntrStatus;
+ u32 XmitStatus;
+ u32 FifoCount;
+ u32 WordCount;
+ u32 ExtraByteCount;
+ u32 *WordBuffer = (u32 *) ptr;
+
+ if (len > ENET_MAX_MTU)
+  len = ENET_MAX_MTU;
+
+ /*
+  * Check for overruns and underruns for the transmit status and length
+  * FIFOs and make sure the send packet FIFO is not deadlocked.
+  * Any of these conditions is bad enough that we do not want to
+  * continue. The upper layer software should reset the device to resolve
+  * the error.
+  */
+ IntrStatus = in_be32 ((Emac.BaseAddress) + XIIF_V123B_IISR_OFFSET);
+ if (IntrStatus & (XEM_EIR_XMIT_SFIFO_OVER_MASK |
+   XEM_EIR_XMIT_LFIFO_OVER_MASK)) {
+#ifdef DEBUG
+  puts ("Transmitting overrun error\n");
+#endif
+  return 0;
+ } else if (IntrStatus & (XEM_EIR_XMIT_SFIFO_UNDER_MASK |
+   XEM_EIR_XMIT_LFIFO_UNDER_MASK)) {
+#ifdef DEBUG
+  puts ("Transmitting underrun error\n");
+#endif
+  return 0;
+ } else if (in_be32 (Emac.SendFifo.RegBaseAddress +
+   XPF_COUNT_STATUS_REG_OFFSET) & XPF_DEADLOCK_MASK) {
+#ifdef DEBUG
+  puts("Transmitting fifo error\n");
+#endif
+  return 0;
+ }
+
+ /*
+  * Before writing to the data FIFO, make sure the length FIFO is not
+  * full. The data FIFO might not be full yet even though the length FIFO
+  * is. This avoids an overrun condition on the length FIFO and keeps the
+  * FIFOs in sync.
+  *
+  * Clear the latched LFIFO_FULL bit so next time around the most
+  * current status is represented
+  */
+ if (IntrStatus & XEM_EIR_XMIT_LFIFO_FULL_MASK) {
+  out_be32 ((Emac.BaseAddress) + XIIF_V123B_IISR_OFFSET, IntrStatus
+    & XEM_EIR_XMIT_LFIFO_FULL_MASK);
+#ifdef DEBUG
+  puts ("Fifo is full\n");
+#endif
+  return 0;
+ }
+
+ /* get the count of how many words may be inserted into the FIFO */
+ FifoCount = in_be32 (Emac.SendFifo.RegBaseAddress +
+    XPF_COUNT_STATUS_REG_OFFSET) & XPF_COUNT_MASK;
+ WordCount = len >> 2;
+ ExtraByteCount = len & 0x3;
+
+ if (FifoCount < WordCount) {
+#ifdef DEBUG
+  puts ("Sending packet is larger then size of FIFO\n");
+#endif
+  return 0;
+ }
+
+ for (FifoCount = 0; FifoCount < WordCount; FifoCount++) {
+  out_be32 (Emac.SendFifo.DataBaseAddress, WordBuffer[FifoCount]);
+ }
+ if (ExtraByteCount > 0) {
+  u32 LastWord = 0;
+  u8 *ExtraBytesBuffer = (u8 *) (WordBuffer + WordCount);
+
+  if (ExtraByteCount == 1) {
+   LastWord = ExtraBytesBuffer[0] << 24;
+  } else if (ExtraByteCount == 2) {
+   LastWord = ExtraBytesBuffer[0] << 24 |
+    ExtraBytesBuffer[1] << 16;
+  } else if (ExtraByteCount == 3) {
+   LastWord = ExtraBytesBuffer[0] << 24 |
+    ExtraBytesBuffer[1] << 16 |
+    ExtraBytesBuffer[2] << 8;
+  }
+  out_be32 (Emac.SendFifo.DataBaseAddress, LastWord);
+ }
+
+ /* Loop on the MAC's status to wait for any pause to complete */
+ IntrStatus = in_be32 ((Emac.BaseAddress) + XIIF_V123B_IISR_OFFSET);
+ while ((IntrStatus & XEM_EIR_XMIT_PAUSE_MASK) != 0) {
+  IntrStatus = in_be32 ((Emac.BaseAddress) +
+     XIIF_V123B_IISR_OFFSET);
+  /* Clear the pause status from the transmit status register */
+  out_be32 ((Emac.BaseAddress) + XIIF_V123B_IISR_OFFSET,
+    IntrStatus & XEM_EIR_XMIT_PAUSE_MASK);
+ }
+
+ /*
+  * Set the MAC's transmit packet length register to tell it to transmit
+  */
+ out_be32 (Emac.BaseAddress + XEM_TPLR_OFFSET, len);
+
+ /*
+  * Loop on the MAC's status to wait for the transmit to complete.
+  * The transmit status is in the FIFO when the XMIT_DONE bit is set.
+  */
+ do {
+  IntrStatus = in_be32 ((Emac.BaseAddress) +
+      XIIF_V123B_IISR_OFFSET);
+ }
+ while ((IntrStatus & XEM_EIR_XMIT_DONE_MASK) == 0);
+
+ XmitStatus = in_be32 (Emac.BaseAddress + XEM_TSR_OFFSET);
+
+ if (IntrStatus & (XEM_EIR_XMIT_SFIFO_OVER_MASK |
+     XEM_EIR_XMIT_LFIFO_OVER_MASK)) {
+#ifdef DEBUG
+  puts ("Transmitting overrun error\n");
+#endif
+  return 0;
+ } else if (IntrStatus & (XEM_EIR_XMIT_SFIFO_UNDER_MASK |
+     XEM_EIR_XMIT_LFIFO_UNDER_MASK)) {
+#ifdef DEBUG
+  puts ("Transmitting underrun error\n");
+#endif
+  return 0;
+ }
+
+ /* Clear the interrupt status register of transmit statuses */
+ out_be32 ((Emac.BaseAddress) + XIIF_V123B_IISR_OFFSET,
+    IntrStatus & XEM_EIR_XMIT_ALL_MASK);
+
+ /*
+  * Collision errors are stored in the transmit status register
+  * instead of the interrupt status register
+  */
+ if ((XmitStatus & XEM_TSR_EXCESS_DEFERRAL_MASK) ||
+    (XmitStatus & XEM_TSR_LATE_COLLISION_MASK)) {
+#ifdef DEBUG
+  puts ("Transmitting collision error\n");
+#endif
+  return 0;
+ }
+ return 1;
+}
+
+int eth_rx(void)
+{
+ u32 PktLength;
+ u32 IntrStatus;
+ u32 FifoCount;
+ u32 WordCount;
+ u32 ExtraByteCount;
+ u32 LastWord;
+ u8 *ExtraBytesBuffer;
+
+ if (in_be32 (Emac.RecvFifo.RegBaseAddress + XPF_COUNT_STATUS_REG_OFFSET)
+   & XPF_DEADLOCK_MASK) {
+  out_be32 (Emac.RecvFifo.RegBaseAddress, XPF_RESET_FIFO_MASK);
+#ifdef DEBUG
+  puts ("Receiving FIFO deadlock\n");
+#endif
+  return 0;
+ }
+
+ /*
+  * Get the interrupt status to know what happened (whether an error 
occurred
+  * and/or whether frames have been received successfully). When clearing 
the
+  * intr status register, clear only statuses that pertain to receive.
+  */
+ IntrStatus = in_be32 ((Emac.BaseAddress) + XIIF_V123B_IISR_OFFSET);
+ /*
+  * Before reading from the length FIFO, make sure the length FIFO is not
+  * empty. We could cause an underrun error if we try to read from an
+  * empty FIFO.
+  */
+ if (!(IntrStatus & XEM_EIR_RECV_DONE_MASK)) {
+#ifdef DEBUG
+  /* puts("Receiving FIFO is empty\n"); */
+#endif
+  return 0;
+ }
+
+ /*
+  * Determine, from the MAC, the length of the next packet available
+  * in the data FIFO (there should be a non-zero length here)
+  */
+ PktLength = in_be32 (Emac.BaseAddress + XEM_RPLR_OFFSET);
+ if (!PktLength) {
+  return 0;
+ }
+
+ /*
+  * Write the RECV_DONE bit in the status register to clear it. This bit
+  * indicates the RPLR is non-empty, and we know it's set@this point.
+  * We clear it so that subsequent entry into this routine will reflect
+  * the current status. This is done because the non-empty bit is latched
+  * in the IPIF, which means it may indicate a non-empty condition even
+  * though there is something in the FIFO.
+  */
+ out_be32 ((Emac.BaseAddress) + XIIF_V123B_IISR_OFFSET,
+      XEM_EIR_RECV_DONE_MASK);
+
+ FifoCount = in_be32 (Emac.RecvFifo.RegBaseAddress +
+    XPF_COUNT_STATUS_REG_OFFSET) & XPF_COUNT_MASK;
+
+ if ((FifoCount * 4) < PktLength) {
+#ifdef DEBUG
+  puts ("Receiving FIFO is smaller than packet size.\n");
+#endif
+  return 0;
+ }
+
+ WordCount = PktLength >> 2;
+ ExtraByteCount = PktLength & 0x3;
+
+ for (FifoCount = 0; FifoCount < WordCount; FifoCount++) {
+  etherrxbuff[FifoCount] =
+    in_be32 (Emac.RecvFifo.DataBaseAddress);
+ }
+
+ /*
+  * if there are extra bytes to handle, read the last word from the FIFO
+  * and insert the extra bytes into the buffer
+  */
+ if (ExtraByteCount > 0) {
+  ExtraBytesBuffer = (u8 *) (etherrxbuff + WordCount);
+
+  LastWord = in_be32 (Emac.RecvFifo.DataBaseAddress);
+
+  /*
+   * one extra byte in the last word, put the byte into the next
+   * location of the buffer, bytes in a word of the FIFO are
+   * ordered from most significant byte to least
+   */
+  if (ExtraByteCount == 1) {
+   ExtraBytesBuffer[0] = (u8) (LastWord >> 24);
+  } else if (ExtraByteCount == 2) {
+   ExtraBytesBuffer[0] = (u8) (LastWord >> 24);
+   ExtraBytesBuffer[1] = (u8) (LastWord >> 16);
+  } else if (ExtraByteCount == 3) {
+   ExtraBytesBuffer[0] = (u8) (LastWord >> 24);
+   ExtraBytesBuffer[1] = (u8) (LastWord >> 16);
+   ExtraBytesBuffer[2] = (u8) (LastWord >> 8);
+  }
+ }
+ NetReceive((uchar *)etherrxbuff, PktLength);
+ return 1;
+}
+#endif
diff --git a/drivers/net/xilinx_emac.h b/drivers/net/xilinx_emac.h
index e69de29..7c00eeb 100644
--- a/drivers/net/xilinx_emac.h
+++ b/drivers/net/xilinx_emac.h
@@ -0,0 +1,127 @@
+/*
+ * (C) Copyright 2007 Michal Simek
+ *
+ * Michal SIMEK <monstr@monstr.eu>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * Based on Xilinx drivers
+ *
+ */
+
+typedef struct {
+ u32 RegBaseAddress; /* Base address of registers */
+ u32 DataBaseAddress; /* Base address of data for FIFOs */
+} XPacketFifoV100b;
+
+typedef struct {
+ u32 BaseAddress; /* Base address (of IPIF) */
+ u32 IsStarted;  /* Device is currently started 0-no, 1-yes */
+ XPacketFifoV100b RecvFifo; /* FIFO used to receive frames */
+ XPacketFifoV100b SendFifo; /* FIFO used to send frames */
+} XEmac;
+
+#define XIIF_V123B_IISR_OFFSET 32UL /* IP interrupt status register */
+#define XIIF_V123B_RESET_MASK  0xAUL
+#define XIIF_V123B_RESETR_OFFSET 64UL /* reset register */
+
+/* This constant is used with the Reset Register */
+#define XPF_RESET_FIFO_MASK  0x0000000A
+#define XPF_COUNT_STATUS_REG_OFFSET 4UL
+
+/* These constants are used with the Occupancy/Vacancy Count Register. This
+ * register also contains FIFO status */
+#define XPF_COUNT_MASK   0x0000FFFF
+#define XPF_DEADLOCK_MASK  0x20000000
+
+/* Offset of the MAC registers from the IPIF base address */
+#define XEM_REG_OFFSET  0x1100UL
+
+/*
+ * Register offsets for the Ethernet MAC. Each register is 32 bits.
+ */
+#define XEM_ECR_OFFSET (XEM_REG_OFFSET + 0x4) /* MAC Control */
+#define XEM_SAH_OFFSET (XEM_REG_OFFSET + 0xC) /* Station addr, high */
+#define XEM_SAL_OFFSET (XEM_REG_OFFSET + 0x10) /* Station addr, low */
+#define XEM_RPLR_OFFSET (XEM_REG_OFFSET + 0x1C) /* Rx packet length */
+#define XEM_TPLR_OFFSET (XEM_REG_OFFSET + 0x20) /* Tx packet length */
+#define XEM_TSR_OFFSET (XEM_REG_OFFSET + 0x24) /* Tx status */
+
+
+
+#define XEM_PFIFO_OFFSET 0x2000UL
+#define XEM_PFIFO_TXREG_OFFSET (XEM_PFIFO_OFFSET + 0x0) /* Tx registers */
+#define XEM_PFIFO_RXREG_OFFSET (XEM_PFIFO_OFFSET + 0x10) /* Rx registers */
+#define XEM_PFIFO_TXDATA_OFFSET (XEM_PFIFO_OFFSET + 0x100) /* Tx keyhole */
+#define XEM_PFIFO_RXDATA_OFFSET (XEM_PFIFO_OFFSET + 0x200) /* Rx keyhole */
+
+
+/*
+ * EMAC Interrupt Registers (Status and Enable) masks. These registers are
+ * part of the IPIF IP Interrupt registers
+ */
+/* A mask for all transmit interrupts, used in polled mode */
+#define XEM_EIR_XMIT_ALL_MASK (XEM_EIR_XMIT_DONE_MASK |\
+     XEM_EIR_XMIT_ERROR_MASK | \
+     XEM_EIR_XMIT_SFIFO_EMPTY_MASK |\
+     XEM_EIR_XMIT_LFIFO_FULL_MASK)
+
+#define XEM_EIR_XMIT_DONE_MASK  0x00000001UL /* Xmit complete */
+#define XEM_EIR_RECV_DONE_MASK  0x00000002UL /* Recv complete */
+#define XEM_EIR_XMIT_ERROR_MASK  0x00000004UL /* Xmit error */
+#define XEM_EIR_RECV_ERROR_MASK  0x00000008UL /* Recv error */
+#define XEM_EIR_XMIT_SFIFO_EMPTY_MASK 0x00000010UL /* Xmit status fifo 
empty */
+#define XEM_EIR_RECV_LFIFO_EMPTY_MASK 0x00000020UL /* Recv length fifo 
empty */
+#define XEM_EIR_XMIT_LFIFO_FULL_MASK 0x00000040UL /* Xmit length fifo full 
*/
+#define XEM_EIR_RECV_LFIFO_OVER_MASK 0x00000080UL /* Recv length fifo
+        * overrun */
+#define XEM_EIR_RECV_LFIFO_UNDER_MASK 0x00000100UL /* Recv length fifo
+        * underrun */
+#define XEM_EIR_XMIT_SFIFO_OVER_MASK 0x00000200UL /* Xmit status fifo
+        * overrun */
+#define XEM_EIR_XMIT_SFIFO_UNDER_MASK 0x00000400UL /* Transmit status fifo
+        * underrun */
+#define XEM_EIR_XMIT_LFIFO_OVER_MASK 0x00000800UL /* Transmit length fifo
+        * overrun */
+#define XEM_EIR_XMIT_LFIFO_UNDER_MASK 0x00001000UL /* Transmit length fifo
+        * underrun */
+#define XEM_EIR_XMIT_PAUSE_MASK  0x00002000UL /* Transmit pause pkt
+        * received */
+
+/*
+ * EMAC Control Register (ECR)
+ */
+#define XEM_ECR_FULL_DUPLEX_MASK  0x80000000UL /* Full duplex mode */
+#define XEM_ECR_XMIT_RESET_MASK   0x40000000UL /* Reset transmitter */
+#define XEM_ECR_XMIT_ENABLE_MASK  0x20000000UL /* Enable transmitter */
+#define XEM_ECR_RECV_RESET_MASK   0x10000000UL /* Reset receiver */
+#define XEM_ECR_RECV_ENABLE_MASK  0x08000000UL /* Enable receiver */
+#define XEM_ECR_PHY_ENABLE_MASK   0x04000000UL /* Enable PHY */
+#define XEM_ECR_XMIT_PAD_ENABLE_MASK  0x02000000UL /* Enable xmit pad
+        * insert */
+#define XEM_ECR_XMIT_FCS_ENABLE_MASK  0x01000000UL /* Enable xmit FCS
+        * insert */
+#define XEM_ECR_UNICAST_ENABLE_MASK  0x00020000UL /* Enable unicast
+        * addr */
+#define XEM_ECR_BROAD_ENABLE_MASK  0x00008000UL /* Enable broadcast
+        * addr */
+
+/* Transmit Status Register (TSR) */
+#define XEM_TSR_EXCESS_DEFERRAL_MASK 0x80000000UL /* Transmit excess 
deferral */
+#define XEM_TSR_LATE_COLLISION_MASK 0x01000000UL /* Transmit late collision 
*/
diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c
index e69de29..99e7035 100644
--- a/drivers/net/xilinx_emaclite.c
+++ b/drivers/net/xilinx_emaclite.c
@@ -0,0 +1,378 @@
+/*
+ * (C) Copyright 2007 Michal Simek
+ *
+ * Michal SIMEK <monstr@monstr.eu>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <net.h>
+#include <config.h>
+#include <asm/io.h>
+
+#ifdef XILINX_EMACLITE_BASEADDR
+
+#undef DEBUG
+
+#define ENET_MAX_MTU  PKTSIZE
+#define ENET_MAX_MTU_ALIGNED PKTSIZE_ALIGN
+#define ENET_ADDR_LENGTH 6
+
+/* EmacLite constants */
+#define XEL_BUFFER_OFFSET 0x0800 /* Next buffer's offset */
+#define XEL_TPLR_OFFSET  0x07F4 /* Tx packet length */
+#define XEL_TSR_OFFSET  0x07FC /* Tx status */
+#define XEL_RSR_OFFSET  0x17FC /* Rx status */
+#define XEL_RXBUFF_OFFSET 0x1000 /* Receive Buffer */
+
+/* Xmit complete */
+#define XEL_TSR_XMIT_BUSY_MASK  0x00000001UL
+/* Xmit interrupt enable bit */
+#define XEL_TSR_XMIT_IE_MASK  0x00000008UL
+/* Buffer is active, SW bit only */
+#define XEL_TSR_XMIT_ACTIVE_MASK 0x80000000UL
+/* Program the MAC address */
+#define XEL_TSR_PROGRAM_MASK  0x00000002UL
+/* define for programming the MAC address into the EMAC Lite */
+#define XEL_TSR_PROG_MAC_ADDR (XEL_TSR_XMIT_BUSY_MASK | 
XEL_TSR_PROGRAM_MASK)
+
+/* Transmit packet length upper byte */
+#define XEL_TPLR_LENGTH_MASK_HI  0x0000FF00UL
+/* Transmit packet length lower byte */
+#define XEL_TPLR_LENGTH_MASK_LO  0x000000FFUL
+
+/* Recv complete */
+#define XEL_RSR_RECV_DONE_MASK  0x00000001UL
+/* Recv interrupt enable bit */
+#define XEL_RSR_RECV_IE_MASK  0x00000008UL
+
+typedef struct {
+ unsigned int BaseAddress; /* Base address for device (IPIF) */
+ unsigned int NextTxBufferToUse; /* Next TX buffer to write to */
+ unsigned int NextRxBufferToUse; /* Next RX buffer to read from */
+ unsigned char DeviceId;  /* Unique ID of device - for future */
+} XEmacLite;
+
+static XEmacLite EmacLite;
+
+static char etherrxbuff[PKTSIZE_ALIGN]; /* Receive buffer */
+
+/* hardcoded MAC address for the Xilinx EMAC Core when env is nowhere*/
+#ifdef CFG_ENV_IS_NOWHERE
+static u8 EMACAddr[ENET_ADDR_LENGTH] = { 0x00, 0x0a, 0x35, 0x00, 0x22, 
0x01 };
+#endif
+
+void XEmacLite_AlignedRead (u32 * SrcPtr, void *DestPtr, unsigned 
ByteCount)
+{
+ unsigned i;
+ unsigned Length = ByteCount;
+ u32 AlignBuffer;
+ u32 *To32Ptr;
+ u32 *From32Ptr;
+ u8 *To8Ptr;
+ u8 *From8Ptr;
+
+ From32Ptr = (u32 *) SrcPtr;
+
+ /* Word aligned buffer, no correction needed. */
+ To32Ptr = (u32 *) DestPtr;
+ while (Length > 3) {
+  *To32Ptr++ = *From32Ptr++;
+  Length -= 4;
+ }
+ To8Ptr = (u8 *) To32Ptr;
+
+ AlignBuffer = *From32Ptr++;
+ From8Ptr = (u8 *) & AlignBuffer;
+
+ for (i = 0; i < Length; i++) {
+  *To8Ptr++ = *From8Ptr++;
+ }
+}
+
+void XEmacLite_AlignedWrite (void *SrcPtr, u32 * DestPtr, unsigned 
ByteCount)
+{
+ unsigned i;
+ unsigned Length = ByteCount;
+ u32 AlignBuffer;
+ u32 *To32Ptr;
+ u32 *From32Ptr;
+ u8 *To8Ptr;
+ u8 *From8Ptr;
+ To32Ptr = DestPtr;
+
+ From32Ptr = (u32 *) SrcPtr;
+ while (Length > 3) {
+
+  *To32Ptr++ = *From32Ptr++;
+  Length -= 4;
+ }
+
+ AlignBuffer = 0;
+ To8Ptr = (u8 *) & AlignBuffer;
+ From8Ptr = (u8 *) From32Ptr;
+
+ for (i = 0; i < Length; i++) {
+  *To8Ptr++ = *From8Ptr++;
+ }
+
+ *To32Ptr++ = AlignBuffer;
+}
+
+void eth_halt (void)
+{
+#ifdef DEBUG
+ puts ("eth_halt\n");
+#endif
+}
+
+int eth_init (bd_t * bis)
+{
+#ifdef DEBUG
+ puts ("EmacLite Initialization Started\n");
+#endif
+ memset (&EmacLite, 0, sizeof (XEmacLite));
+ EmacLite.BaseAddress = XILINX_EMACLITE_BASEADDR;
+
+#ifdef CFG_ENV_IS_NOWHERE
+ memcpy (bis->bi_enetaddr, EMACAddr, ENET_ADDR_LENGTH);
+#endif
+/*
+ * TX - TX_PING & TX_PONG initialization
+ */
+ /* Restart PING TX */
+ out_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET, 0);
+ /* Copy MAC address */
+ XEmacLite_AlignedWrite (bis->bi_enetaddr,
+  EmacLite.BaseAddress, ENET_ADDR_LENGTH);
+ /* Set the length */
+ out_be32 (EmacLite.BaseAddress + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH);
+ /* Update the MAC address in the EMAC Lite */
+ out_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET, XEL_TSR_PROG_MAC_ADDR);
+ /* Wait for EMAC Lite to finish with the MAC address update */
+ while ((in_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET) &
+  XEL_TSR_PROG_MAC_ADDR) != 0) ;
+
+#ifdef XILINX_EMACLITE_TX_PING_PONG
+ /* The same operation with PONG TX */
+ out_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET, 0);
+ XEmacLite_AlignedWrite (bis->bi_enetaddr,
+  EmacLite.BaseAddress + XEL_BUFFER_OFFSET, ENET_ADDR_LENGTH);
+ out_be32 (EmacLite.BaseAddress + XEL_TPLR_OFFSET, ENET_ADDR_LENGTH);
+ out_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET + XEL_BUFFER_OFFSET,
+  XEL_TSR_PROG_MAC_ADDR);
+ while ((in_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET +
+   XEL_BUFFER_OFFSET) & XEL_TSR_PROG_MAC_ADDR) != 0) ;
+#endif
+
+/*
+ * RX - RX_PING & RX_PONG initialization
+ */
+ /* Write out the value to flush the RX buffer */
+ out_be32 (EmacLite.BaseAddress + XEL_RSR_OFFSET, XEL_RSR_RECV_IE_MASK);
+#ifdef XILINX_EMACLITE_RX_PING_PONG
+ out_be32 (EmacLite.BaseAddress + XEL_RSR_OFFSET + XEL_BUFFER_OFFSET,
+  XEL_RSR_RECV_IE_MASK);
+#endif
+
+#ifdef DEBUG
+ puts ("EmacLite Initialization complete\n");
+#endif
+ return 0;
+}
+
+int XEmacLite_TxBufferAvailable (XEmacLite * InstancePtr)
+{
+ u32 Register;
+ u32 TxPingBusy;
+ u32 TxPongBusy;
+ /*
+  * Read the other buffer register
+  * and determine if the other buffer is available
+  */
+ Register = in_be32 (InstancePtr->BaseAddress +
+   InstancePtr->NextTxBufferToUse + 0);
+ TxPingBusy = ((Register & XEL_TSR_XMIT_BUSY_MASK) ==
+   XEL_TSR_XMIT_BUSY_MASK);
+
+ Register = in_be32 (InstancePtr->BaseAddress +
+   (InstancePtr->NextTxBufferToUse ^ XEL_TSR_OFFSET) + 0);
+ TxPongBusy = ((Register & XEL_TSR_XMIT_BUSY_MASK) ==
+   XEL_TSR_XMIT_BUSY_MASK);
+
+ return (!(TxPingBusy && TxPongBusy));
+}
+
+int eth_send (volatile void *ptr, int len) {
+
+ unsigned int Register;
+ unsigned int BaseAddress;
+
+ unsigned maxtry = 1000;
+
+ if (len > ENET_MAX_MTU)
+  len = ENET_MAX_MTU;
+
+ while (!XEmacLite_TxBufferAvailable (&EmacLite) && maxtry) {
+  udelay (10);
+  maxtry--;
+ }
+
+ if (!maxtry) {
+  printf ("Error: Timeout waiting for ethernet TX buffer\n");
+  /* Restart PING TX */
+  out_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET, 0);
+#ifdef XILINX_EMACLITE_TX_PING_PONG
+  out_be32 (EmacLite.BaseAddress + XEL_TSR_OFFSET +
+  XEL_BUFFER_OFFSET, 0);
+#endif
+  return 0;
+ }
+
+ /* Determine the expected TX buffer address */
+ BaseAddress = (EmacLite.BaseAddress + EmacLite.NextTxBufferToUse);
+
+ /* Determine if the expected buffer address is empty */
+ Register = in_be32 (BaseAddress + XEL_TSR_OFFSET);
+ if (((Register & XEL_TSR_XMIT_BUSY_MASK) == 0)
+  && ((in_be32 ((BaseAddress) + XEL_TSR_OFFSET)
+   & XEL_TSR_XMIT_ACTIVE_MASK) == 0)) {
+
+#ifdef XILINX_EMACLITE_TX_PING_PONG
+  EmacLite.NextTxBufferToUse ^= XEL_BUFFER_OFFSET;
+#endif
+#ifdef DEBUG
+  printf ("Send packet from 0x%x\n", BaseAddress);
+#endif
+  /* Write the frame to the buffer */
+  XEmacLite_AlignedWrite (ptr, (u32 *) BaseAddress, len);
+  out_be32 (BaseAddress + XEL_TPLR_OFFSET,(len &
+   (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO)));
+  Register = in_be32 (BaseAddress + XEL_TSR_OFFSET);
+  Register |= XEL_TSR_XMIT_BUSY_MASK;
+  if ((Register & XEL_TSR_XMIT_IE_MASK) != 0) {
+   Register |= XEL_TSR_XMIT_ACTIVE_MASK;
+  }
+  out_be32 (BaseAddress + XEL_TSR_OFFSET, Register);
+  return 1;
+ }
+#ifdef XILINX_EMACLITE_TX_PING_PONG
+ /* Switch to second buffer */
+ BaseAddress ^= XEL_BUFFER_OFFSET;
+ /* Determine if the expected buffer address is empty */
+ Register = in_be32 (BaseAddress + XEL_TSR_OFFSET);
+ if (((Register & XEL_TSR_XMIT_BUSY_MASK) == 0)
+  && ((in_be32 ((BaseAddress) + XEL_TSR_OFFSET)
+   & XEL_TSR_XMIT_ACTIVE_MASK) == 0)) {
+#ifdef DEBUG
+  printf ("Send packet from 0x%x\n", BaseAddress);
+#endif
+  /* Write the frame to the buffer */
+  XEmacLite_AlignedWrite (ptr, (u32 *) BaseAddress, len);
+  out_be32 (BaseAddress + XEL_TPLR_OFFSET,(len &
+   (XEL_TPLR_LENGTH_MASK_HI | XEL_TPLR_LENGTH_MASK_LO)));
+  Register = in_be32 (BaseAddress + XEL_TSR_OFFSET);
+  Register |= XEL_TSR_XMIT_BUSY_MASK;
+  if ((Register & XEL_TSR_XMIT_IE_MASK) != 0) {
+   Register |= XEL_TSR_XMIT_ACTIVE_MASK;
+  }
+  out_be32 (BaseAddress + XEL_TSR_OFFSET, Register);
+  return 1;
+ }
+#endif
+ puts ("Error while sending frame\n");
+ return 0;
+}
+
+int eth_rx (void)
+{
+ unsigned int Length;
+ unsigned int Register;
+ unsigned int BaseAddress;
+
+ BaseAddress = EmacLite.BaseAddress + EmacLite.NextRxBufferToUse;
+ Register = in_be32 (BaseAddress + XEL_RSR_OFFSET);
+#ifdef DEBUG
+ printf ("Testing data at address 0x%x\n", BaseAddress);
+#endif
+ if ((Register & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) {
+#ifdef XILINX_EMACLITE_RX_PING_PONG
+  EmacLite.NextRxBufferToUse ^= XEL_BUFFER_OFFSET;
+#endif
+ } else {
+#ifndef XILINX_EMACLITE_RX_PING_PONG
+#ifdef DEBUG
+  printf ("No data was available - address 0x%x\n", BaseAddress);
+#endif
+  return 0;
+#else
+  BaseAddress ^= XEL_BUFFER_OFFSET;
+  Register = in_be32 (BaseAddress + XEL_RSR_OFFSET);
+  if ((Register & XEL_RSR_RECV_DONE_MASK) !=
+     XEL_RSR_RECV_DONE_MASK) {
+#ifdef DEBUG
+   printf ("No data was available - address 0x%x\n",
+     BaseAddress);
+#endif
+   return 0;
+  }
+#endif
+ }
+ /* Get the length of the frame that arrived */
+ switch(((in_be32(BaseAddress + XEL_RXBUFF_OFFSET + 0xC)) &
+   0xFFFF0000 ) >> 16) {
+  case 0x806:
+   Length = 42 + 20; /* FIXME size of ARP */
+#ifdef DEBUG
+   puts ("ARP Packet\n");
+#endif
+   break;
+  case 0x800:
+   Length = 14 + 14 +
+   (((in_be32(BaseAddress + XEL_RXBUFF_OFFSET + 0x10)) &
+   0xFFFF0000) >> 16); /* FIXME size of IP packet */
+#ifdef DEBUG
+   puts("IP Packet\n");
+#endif
+   break;
+  default:
+#ifdef DEBUG
+   puts("Other Packet\n");
+#endif
+   Length = ENET_MAX_MTU;
+   break;
+ }
+
+ XEmacLite_AlignedRead ((BaseAddress + XEL_RXBUFF_OFFSET),
+   etherrxbuff, Length);
+
+ /* Acknowledge the frame */
+ Register = in_be32 (BaseAddress + XEL_RSR_OFFSET);
+ Register &= ~XEL_RSR_RECV_DONE_MASK;
+ out_be32 (BaseAddress + XEL_RSR_OFFSET, Register);
+
+#ifdef DEBUG
+ printf ("Packet receive from 0x%x, length %dB\n", BaseAddress, Length);
+#endif
+ NetReceive ((uchar *) etherrxbuff, Length);
+ return 1;
+
+}
+#endif
diff --git a/fs/romfs/Makefile b/fs/romfs/Makefile
index e69de29..937d755 100644
--- a/fs/romfs/Makefile
+++ b/fs/romfs/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)libromfs.a
+
+AOBJS =
+COBJS = romfs.o
+
+SRCS := $(AOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(AOBJS) $(COBJS))
+
+#CPPFLAGS +=
+
+all: $(LIB) $(AOBJS)
+
+$(LIB): $(obj).depend $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################

  reply	other threads:[~2007-08-05 18:56 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-08-05 13:38 [U-Boot-Users] Microblaze: PULL request Michal Simek
2007-08-05 14:47 ` Grant Likely
2007-08-05 14:52   ` Grant Likely
2007-08-05 15:13   ` Michal Simek
2007-08-05 16:12     ` Grant Likely
2007-08-05 16:34       ` Michal Simek
2007-08-05 18:56         ` Michal Simek [this message]
2007-08-05 20:07           ` [U-Boot-Users] [PATCH 1/4] emac Wolfgang Denk
2007-08-06 20:11             ` Michal Simek
2007-08-05 22:28           ` Grant Likely
2007-08-05 18:56         ` [U-Boot-Users] [PATCH 2/4] emaclite Michal Simek
2007-08-05 20:05           ` Wolfgang Denk
2007-08-06 20:00             ` Michal Simek
2007-08-06 20:54               ` Wolfgang Denk
2007-08-05 18:56         ` [U-Boot-Users] [PATCH 3/4] microblaze changes Michal Simek
2007-08-05 20:08           ` Wolfgang Denk
2007-08-05 18:56         ` [U-Boot-Users] [PATCH 4/4] romfs Michal Simek
2007-08-05 20:38           ` Wolfgang Denk
2007-08-05 20:01         ` [U-Boot-Users] Microblaze: PULL request Wolfgang Denk
2007-08-05 22:25           ` Grant Likely
2007-08-05 22:27             ` Wolfgang Denk
2007-08-05 22:32               ` Grant Likely
2007-08-06 17:03                 ` Michal Simek
2007-08-05 19:59     ` Wolfgang Denk

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='001701c7d792$52efe900$0500a8c0@monstrone' \
    --to=monstr@seznam.cz \
    --cc=u-boot@lists.denx.de \
    /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.