qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] e1000 emulation
@ 2007-08-25 21:18 Dan Aloni
  2007-08-26 12:25 ` [Qemu-devel] " Triggered
  2007-08-26 15:57 ` [Qemu-devel] " Anthony Liguori
  0 siblings, 2 replies; 5+ messages in thread
From: Dan Aloni @ 2007-08-25 21:18 UTC (permalink / raw)
  To: qemu-devel

Hello,

Is anyone interested in a patch for an unstable, though working e1000 
emulation for
QEMU? It is aimed for this chip-set version:

0e:00.0 Ethernet controller: Intel Corporation 82573L Gigabit Ethernet 
Controller

I originally created it very recently to provide a virtual NIC that 
supports Jumbo
packets. Unfortunately it appears that the tun driver doesn't implement
change_mtu() so it didn't integrate very well with qemu-kvm.

-- 

Dan Aloni
XIV LTD, http://www.xivstorage.com
da-x (at) monatomic.org, dan (at) xiv.co.il

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [Qemu-devel] Re: e1000 emulation
  2007-08-25 21:18 [Qemu-devel] e1000 emulation Dan Aloni
@ 2007-08-26 12:25 ` Triggered
  2007-09-01 19:51   ` Dan Aloni
  2007-08-26 15:57 ` [Qemu-devel] " Anthony Liguori
  1 sibling, 1 reply; 5+ messages in thread
From: Triggered @ 2007-08-26 12:25 UTC (permalink / raw)
  To: qemu-devel

Dan Aloni schreef:
> Hello,
> 
> Is anyone interested in a patch for an unstable, though working e1000
> emulation for
> QEMU? It is aimed for this chip-set version:
> 
> 0e:00.0 Ethernet controller: Intel Corporation 82573L Gigabit Ethernet
> Controller
> 
> I originally created it very recently to provide a virtual NIC that
> supports Jumbo
> packets. Unfortunately it appears that the tun driver doesn't implement
> change_mtu() so it didn't integrate very well with qemu-kvm.
> 
I am very interested in a patch for Gbit-capable network card.
Please post a patch!

Thank you
Frederik van Hövell

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] e1000 emulation
  2007-08-25 21:18 [Qemu-devel] e1000 emulation Dan Aloni
  2007-08-26 12:25 ` [Qemu-devel] " Triggered
@ 2007-08-26 15:57 ` Anthony Liguori
  1 sibling, 0 replies; 5+ messages in thread
From: Anthony Liguori @ 2007-08-26 15:57 UTC (permalink / raw)
  To: qemu-devel


On Sun, 2007-08-26 at 00:18 +0300, Dan Aloni wrote:
> Hello,
> 
> Is anyone interested in a patch for an unstable, though working e1000 
> emulation for
> QEMU? It is aimed for this chip-set version:

Yes!  The e1000 has a lot of interesting features that should make it
emulation friendly.

> 0e:00.0 Ethernet controller: Intel Corporation 82573L Gigabit Ethernet 
> Controller
> 
> I originally created it very recently to provide a virtual NIC that 
> supports Jumbo
> packets. Unfortunately it appears that the tun driver doesn't implement
> change_mtu() so it didn't integrate very well with qemu-kvm.

If it proves useful, then there's no reason the tun driver can't be
changed.  Were you expecting to get a significant performance boost with
jumbo frames or was this just a functionality thing?  The current
emulated nic performance is pretty bad...

Regards,

Anthony Liguori

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] Re: e1000 emulation
  2007-08-26 12:25 ` [Qemu-devel] " Triggered
@ 2007-09-01 19:51   ` Dan Aloni
  2007-09-02  6:55     ` Mulyadi Santosa
  0 siblings, 1 reply; 5+ messages in thread
From: Dan Aloni @ 2007-09-01 19:51 UTC (permalink / raw)
  To: qemu-devel; +Cc: Triggered

On Sun, Aug 26, 2007 at 02:25:57PM +0200, Triggered wrote:
> Dan Aloni schreef:
> > Hello,
> > 
> > Is anyone interested in a patch for an unstable, though working e1000
> > emulation for
> > QEMU? It is aimed for this chip-set version:
> > 
> > 0e:00.0 Ethernet controller: Intel Corporation 82573L Gigabit Ethernet
> > Controller
> > 
> > I originally created it very recently to provide a virtual NIC that
> > supports Jumbo
> > packets. Unfortunately it appears that the tun driver doesn't implement
> > change_mtu() so it didn't integrate very well with qemu-kvm.
> > 
> I am very interested in a patch for Gbit-capable network card.
> Please post a patch!

Okay, just a few notes:

 * Sorry for sending this rather badly written patch, I have loads of 
   other stuff at the moment. I hope that it serves as a ground for 
   further development, though.
 * It depends on the e1000_hw.h header from a the Linux kernel driver (look 
   in drivers/net/e1000), I haven't included this header in the patch.
 * As far as I've seen, ICMP ping works, but TCP doesn't (I think it 
   is because this emulator implementation doesn't do the off-load of 
   packet checksuming,  as the guest expects)
 * Several up/downs of the interface while it is working seem to cause 
   guest memory corruption. Haven't looked into this yet.

Have fun hacking!

diff --git a/qemu/Makefile.target b/qemu/Makefile.target
index aeee2af..9363e22 100644
--- a/qemu/Makefile.target
+++ b/qemu/Makefile.target
@@ -372,7 +372,7 @@ VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
 VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o
 
 # PCI network cards
-VL_OBJS+= ne2000.o rtl8139.o pcnet.o
+VL_OBJS+= ne2000.o rtl8139.o pcnet.o e1000.o
 
 # PCI Hypercall
 VL_OBJS+= hypercall.o
diff --git a/qemu/hw/e1000.c b/qemu/hw/e1000.c
new file mode 100644
index 0000000..7e3c014
--- /dev/null
+++ b/qemu/hw/e1000.c
@@ -0,0 +1,695 @@
+/*
+ * QEMU e1000 emulation
+ * 
+ * Copyright (c) 2007 Dan Aloni
+ * Based on work done by:
+ * Copyright (c) 2004 Antony T Curtis
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+ 
+
+#include "vl.h"
+
+#define E1000_DEBUG
+#define E1000_DEBUG_UNK
+//#define E1000_DEBUG_CSR
+//#define E1000_DEBUG_RMD
+//#define E1000_DEBUG_TMD
+//#define E1000_DEBUG_MATCH
+
+#ifdef E1000_DEBUG
+#define	EDBGOUT(fmt, params...) fprintf(stderr, "e1000: " fmt, ##params)
+#else
+#define	EDBGOUT(fmt, params...) do {} while (0)
+#endif
+
+#ifdef E1000_DEBUG_UNK
+#define	EDBGUNKOUT(fmt, params...) EDBGOUT(fmt, ##params)
+#else
+#define	EDBGUNKOUT(fmt, params...) do {} while (0)
+#endif
+
+
+#define E1000_IOPORT_SIZE       0x40
+#define E1000_PNPMMIO_SIZE      0x60000
+
+#include "e1000_hw.h"
+
+typedef struct e1000_vmhw_st e1000_vmhw;
+
+struct e1000_eeprom {
+	unsigned short raw[64];
+};
+
+struct e1000_vmhw_st {
+	PCIDevice dev;
+	PCIDevice *pci_dev;
+	VLANClientState *vc;
+	NICInfo *nd;
+	uint32_t mmio_base;
+	uint32_t interrupt_mask;
+	uint32_t eeprom_semaphore;
+	uint32_t mdic;
+
+	uint32_t icr;
+	uint32_t tdlen;
+	uint64_t tdb;
+	uint32_t tdt;
+	uint32_t tdh;
+
+	uint32_t rdlen;
+	uint64_t rdb;
+	uint32_t rdt;
+	uint32_t rdh;
+	uint32_t rctl;
+	uint32_t receive_buf_size;
+
+	uint16_t phy_regs[0x20];
+
+	struct e1000_eeprom eeprom_data;
+	int eeprom_offset_to_read;
+	int mmio_index, rap, isr, lnkst;
+	void *dma_opaque;
+};
+
+static void e1000_ioport_map(PCIDevice *pci_dev, int region_num, 
+                             uint32_t addr, uint32_t size, int type)
+{
+	EDBGOUT("e1000_ioport_map addr=0x%04x size=0x%08x\n", addr, size);
+}
+
+static void e1000_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+	EDBGOUT("e1000_mmio_writeb addr=%p val=0x%08x\n", (void *)addr, val);
+}
+
+static uint32_t e1000_mmio_readb(void *opaque, target_phys_addr_t addr) 
+{
+	EDBGOUT("e1000_mmio_readb addr=%p\n", (void *)addr);
+	return 0;
+}
+
+static void e1000_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+	EDBGOUT("e1000_mmio_writew addr=0x%08x val=0x%04x\n", addr, val);
+}
+
+static uint32_t e1000_mmio_readw(void *opaque, target_phys_addr_t addr) 
+{
+	EDBGOUT("e1000_mmio_readw addr=0x%08x\n", addr);
+	return 0;
+}
+
+void e1000_update_interrupt(struct e1000_vmhw_st *s)
+{
+	if ((~s->interrupt_mask) & s->icr) {
+		EDBGOUT("update interrupt 0x%08x\n", (~s->interrupt_mask) & s->icr);
+	}
+	pci_set_irq(&s->dev, 0, ((~s->interrupt_mask) & s->icr) != 0);
+}
+
+void e1000_clear_interrupt_mask(struct e1000_vmhw_st *s, uint32_t val)
+{
+	s->interrupt_mask = val;
+	e1000_update_interrupt(s);
+}
+
+void e1000_set_interrupt_mask(struct e1000_vmhw_st *s, uint32_t val)
+{
+	s->interrupt_mask = ~val;
+	e1000_update_interrupt(s);
+}
+
+void e1000_set_interrupt_cause(struct e1000_vmhw_st *s, uint32_t val)
+{
+	if (val != 0) {
+		if (val & E1000_ICR_LSC) {
+			EDBGOUT("mocking up a link\n");
+			/* Trick the driver to think there's a link */
+			s->phy_regs[PHY_STATUS] = 0x796d;
+		}
+		val |= E1000_ICR_INT_ASSERTED;
+	}
+	s->icr = val;
+	e1000_update_interrupt(s);
+}
+
+uint32_t e1000_get_receive_control(struct e1000_vmhw_st *s)
+{
+	return s->rctl;
+}
+
+void e1000_set_receive_control(struct e1000_vmhw_st *s, uint32_t val)
+{
+	uint32_t reg_buf_size;
+
+	s->rctl = val;
+	s->receive_buf_size = 2048;
+
+	reg_buf_size = val & 0x00030000;
+	
+	if (val & E1000_RCTL_BSEX) {
+		switch (reg_buf_size) {
+		case E1000_RCTL_SZ_16384:
+			s->receive_buf_size = 16384;
+			break;
+		case E1000_RCTL_SZ_8192:
+			s->receive_buf_size = 8192;
+			break;
+		case E1000_RCTL_SZ_4096:
+			s->receive_buf_size = 4096;
+			break;
+		}
+	} else {
+		switch (reg_buf_size) {
+		case E1000_RCTL_SZ_2048:
+			s->receive_buf_size = 2048;
+			break;
+		case E1000_RCTL_SZ_1024:
+			s->receive_buf_size = 1024;
+			break;
+		case E1000_RCTL_SZ_512:
+			s->receive_buf_size = 512;
+			break;
+		case E1000_RCTL_SZ_256:
+			s->receive_buf_size = 256;
+			break;
+		}
+	}
+
+	EDBGOUT("RDT: %d, rctl = 0x%x\n", s->rdt, s->rctl);
+}
+
+uint32_t e1000_get_interrupt_cause(struct e1000_vmhw_st *s)
+{
+	uint32_t icr = s->icr;
+	e1000_set_interrupt_cause(s, 0);
+	return icr;
+}
+
+uint32_t e1000_get_control(struct e1000_vmhw_st *s)
+{
+	uint32_t reg;
+	
+	reg = (E1000_CTRL_SWDPIN2 | E1000_CTRL_SWDPIN0 | E1000_CTRL_SPD_1000 |
+	       E1000_CTRL_SLU | E1000_CTRL_LRST);
+
+	/* 00140248 */
+
+	EDBGOUT("e1000_mmio_readl CTRL val=0x%08x\n", reg);
+
+	return reg;
+}
+
+void e1000_set_control(struct e1000_vmhw_st *s, uint32_t val)
+{
+	EDBGOUT("e1000_mmio_write CTRL val=0x%08x\n", val);
+}
+
+void e1000_set_eeprom_semaphore(struct e1000_vmhw_st *s, uint32_t val)
+{	
+	s->eeprom_semaphore = val;
+}
+
+uint32_t e1000_get_eeprom_semaphore(struct e1000_vmhw_st *s)
+{
+	return s->eeprom_semaphore;
+}
+
+void e1000_set_mdic(struct e1000_vmhw_st *s, uint32_t val)
+{	
+	uint32_t phy_addr;
+	uint32_t reg_addr;
+	uint32_t reg_value;
+	
+	reg_value = val & E1000_MDIC_DATA_MASK;
+	reg_addr = ((val & E1000_MDIC_REG_MASK) >> E1000_MDIC_REG_SHIFT);
+	phy_addr = ((val & E1000_MDIC_PHY_MASK) >> E1000_MDIC_PHY_SHIFT);
+
+	if (phy_addr != 1)
+		goto exit;
+
+	s->mdic = val;
+
+	if (val & E1000_MDIC_OP_READ) {
+		EDBGOUT("MDIC read reg 0x%x\n", reg_addr);
+
+		switch (reg_addr) {
+		case PHY_STATUS:
+		case PHY_ID1:
+		case PHY_ID2:
+		case PHY_CTRL:
+		case M88E1000_PHY_SPEC_CTRL:
+		case M88E1000_EXT_PHY_SPEC_CTRL:
+		case PHY_AUTONEG_ADV:
+		case PHY_1000T_CTRL:
+			s->mdic |= s->phy_regs[reg_addr] | E1000_MDIC_READY;
+			return;
+		default:
+			EDBGOUT("MDIC read reg unhandled\n");
+			break;
+		}
+	} else if (val & E1000_MDIC_OP_WRITE) {
+		EDBGOUT("MDIC write reg 0x%x, value 0x%x\n", reg_addr, reg_value);
+		switch (reg_addr) {
+		case M88E1000_PHY_SPEC_CTRL:
+		case M88E1000_EXT_PHY_SPEC_CTRL:
+		case PHY_CTRL:
+		case PHY_AUTONEG_ADV:
+		case PHY_1000T_CTRL:
+			s->phy_regs[reg_addr] = reg_value;
+			s->mdic |= E1000_MDIC_READY;
+			return;
+		default:
+			EDBGOUT("MDIC write reg unhandled\n");
+			break;
+		}
+	}
+
+ exit:
+	s->mdic |= E1000_MDIC_ERROR;
+}
+
+uint32_t e1000_get_mdic(struct e1000_vmhw_st *s)
+{
+	return s->mdic;
+}
+
+uint32_t e1000_get_status(struct e1000_vmhw_st *s)
+{
+	uint32_t reg;
+	reg = 0x80000000;
+	reg |= E1000_STATUS_GIO_MASTER_ENABLE |
+		E1000_STATUS_ASDV | E1000_STATUS_MTXCKOK | 
+		E1000_STATUS_SPEED_1000;
+
+	reg |= E1000_STATUS_FD | E1000_STATUS_LU;		
+	return reg;
+}
+
+uint32_t e1000_get_flash_control(struct e1000_vmhw_st *s)
+{
+	uint32_t reg = 0;
+
+	reg = 0x08 << E1000_EECD_SECVAL_SHIFT;
+	reg |= 0x10000;
+	reg |= 3 << E1000_EECD_SIZE_EX_SHIFT;
+	reg |= E1000_EECD_PRES;
+	reg |= E1000_EECD_SIZE;
+	reg |= E1000_EECD_FWE_DIS;
+	reg |= E1000_EECD_DO;
+
+	//EDBGOUT("ECD: %08x\n", reg);
+
+	return reg;
+}
+
+uint32_t e1000_get_management_control(struct e1000_vmhw_st *s)
+{
+	return (E1000_MANC_EN_MNG2HOST | 
+		E1000_MANC_RCV_TCO_EN | 
+		E1000_MANC_ARP_EN |
+		E1000_MANC_0298_EN | 
+		E1000_MANC_RMCP_EN);
+}
+
+void e1000_flash_eerd_write(struct e1000_vmhw_st *s, uint32_t val)
+{
+	s->eeprom_offset_to_read = val;
+}
+
+uint32_t e1000_flash_eerd_read(struct e1000_vmhw_st *s)
+{
+	unsigned int index;
+
+	index = (s->eeprom_offset_to_read - E1000_EEPROM_RW_REG_START) >> E1000_EEPROM_RW_ADDR_SHIFT;
+
+	if (index >= 0  &&  index <= EEPROM_CHECKSUM_REG) {
+		uint32_t reg;
+		reg = s->eeprom_data.raw[index];
+		reg <<= E1000_EEPROM_RW_REG_DATA;
+		reg |= E1000_EEPROM_RW_REG_DONE | (s->eeprom_offset_to_read - E1000_EEPROM_RW_REG_START);
+		return reg;
+	}
+	
+	return 0;
+}
+
+void e1000_set_transmit_descriptor(struct e1000_vmhw_st *s, uint32_t val)
+{
+	uint32_t index;
+	target_phys_addr_t base;
+	struct e1000_tx_desc desc;
+	char packet_data[0x8000];
+	unsigned int packet_size;
+	unsigned int split_size;
+
+	s->tdt = val;
+	packet_size = 0;
+
+	while (s->tdh != s->tdt) {
+		index = s->tdh;
+		
+		base = s->tdb + sizeof(struct e1000_tx_desc) * index;
+		memset(&desc, 0, sizeof(desc));
+		cpu_physical_memory_read(base, (void *)&desc, sizeof(desc));
+
+		EDBGOUT("index %d: %p : %x %x\n", index, 
+			(void *)desc.buffer_addr, desc.lower.data, desc.upper.data);
+
+		split_size = desc.lower.flags.length;
+
+		if (split_size) {
+			cpu_physical_memory_read(desc.buffer_addr, (void *)&packet_data[packet_size], 
+						 split_size);
+			packet_size += split_size;
+		}
+
+		desc.upper.data |= E1000_TXD_STAT_DD;
+		cpu_physical_memory_write(base, &desc, sizeof(desc));
+
+		if (desc.lower.data & E1000_TXD_CMD_EOP) {
+			EDBGOUT("packet whose size is %d\n", packet_size);
+			qemu_send_packet(s->vc, packet_data, packet_size);
+			packet_size = 0;
+		}
+
+		s->tdh++;
+
+		if (base == s->tdb + s->tdlen - sizeof(desc))
+			s->tdh = 0;
+	}
+}
+
+static void e1000_receive(void *opaque, const uint8_t *buf, int size)
+{
+	struct e1000_vmhw_st *s = opaque;
+	struct e1000_rx_desc desc;
+	target_phys_addr_t base;
+	unsigned int index;
+
+
+	EDBGOUT("e1000_receive: %d\n", size);
+
+	if (!(s->rctl & E1000_RCTL_EN))
+		return;
+	
+	if (s->rdh == s->rdt)
+		return;
+
+	if (size > s->receive_buf_size) {
+		EDBGOUT("packet too large for buffers (%d > %d)\n", 
+			size, s->receive_buf_size);
+		return;
+	}
+
+	size += 4; /* for the header */
+	index = s->rdh;
+	base = s->rdb + sizeof(desc) * index;
+	cpu_physical_memory_read(base, (void *)&desc, sizeof(desc));
+	cpu_physical_memory_write(desc.buffer_addr, (void *)buf, size);
+	desc.length = size;
+	desc.status |= E1000_RXD_STAT_DD;
+	desc.status |= E1000_RXD_STAT_EOP;
+	cpu_physical_memory_write(base, (void *)&desc, sizeof(desc));
+
+	s->rdh++;
+	if (base == s->rdb + s->rdlen - sizeof(desc))
+		s->rdh = 0;
+
+	e1000_set_interrupt_cause(s, E1000_ICS_RXDMT0);
+}
+
+void e1000_set_receive_descriptor(struct e1000_vmhw_st *s, uint32_t val)
+{
+	s->rdt = val;
+}
+
+static int e1000_can_receive(void *opaque)
+{
+	struct e1000_vmhw_st *s = opaque;
+
+	if (!(s->rctl & E1000_RCTL_EN))
+	    return 1;
+
+	if (s->rdh == s->rdt)
+		return 1;
+
+	return 0;
+}
+
+static void e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+	struct e1000_vmhw_st *s = opaque;
+
+	switch (addr - s->mmio_base) {
+	case E1000_TDLEN:
+		s->tdlen = val;
+		break;
+	case E1000_TDBAH:
+		s->tdb &= 0x00000000ffffffff;
+		s->tdb |= ((uint64_t)val) << 32;
+		break;
+	case E1000_TDBAL:
+		s->tdb &= 0xffffffff00000000;
+		s->tdb |= val;
+		break;
+	case E1000_TDH:
+		s->tdh = val;
+		break;
+	case E1000_TDT:
+		e1000_set_transmit_descriptor(s, val);
+		break;
+
+	case E1000_RDLEN:
+		s->rdlen = val;
+		break;
+	case E1000_RDBAH:
+		s->rdb &= 0x00000000ffffffff;
+		s->rdb |= ((uint64_t)val) << 32;
+		break;
+	case E1000_RDBAL:
+		s->rdb &= 0xffffffff00000000;
+		s->rdb |= val;
+		break;
+	case E1000_RDH:
+		s->rdh = val;
+		break;
+	case E1000_RDT:
+		e1000_set_receive_descriptor(s, val);
+		break;
+
+	case E1000_STATUS:
+		EDBGOUT("e1000_mmio_writel STATUS 0x%04x\n", val);
+		break;
+	case E1000_CTRL:
+		e1000_set_control(s, val);
+		break;
+	case E1000_SWSM:
+		e1000_set_eeprom_semaphore(s, val);
+		break;
+	case E1000_IMC:
+		e1000_clear_interrupt_mask(s, val);
+		break;
+	case E1000_IMS:
+		e1000_set_interrupt_mask(s, val);
+		break;
+	case E1000_MDIC:
+		e1000_set_mdic(s, val);
+		break;
+	case E1000_ICR:
+		EDBGOUT("e1000_mmio_writel ICR val=0x%08x\n", val);
+		break;
+	case E1000_ICS:
+		e1000_set_interrupt_cause(s, val);
+		break;
+	case E1000_RCTL:
+		e1000_set_receive_control(s, val);
+		break;
+	case E1000_TCTL:
+		EDBGOUT("e1000_mmio_writel TCTL val=0x%08x\n", val);
+		break;
+	case E1000_EERD:
+		e1000_flash_eerd_write(s, val);
+		break;
+	default:
+		EDBGUNKOUT("MMIO unknown write addr=0x%08x,val=0x%08x\n", addr - s->mmio_base, val);
+		break;
+	}
+
+}
+
+static uint32_t e1000_mmio_readl(void *opaque, target_phys_addr_t addr) 
+{
+	struct e1000_vmhw_st *s = opaque;
+
+	switch (addr - s->mmio_base) {
+	case E1000_CRCERRS ... E1000_ICRXOC:
+		/* statistics - return zero for now */
+		return 0;
+	case E1000_TDH:
+		return s->tdh;
+	case E1000_CTRL:
+		return e1000_get_control(s);
+	case E1000_STATUS:
+		return e1000_get_status(s);
+	case E1000_SWSM:
+		return e1000_get_eeprom_semaphore(s);
+	case E1000_ICR:
+		return e1000_get_interrupt_cause(s);
+	case E1000_MDIC:
+		return e1000_get_mdic(s);
+	case E1000_EECD:
+		return e1000_get_flash_control(s);
+	case E1000_EERD:
+		return e1000_flash_eerd_read(s);
+	case E1000_MANC:
+		return e1000_get_management_control(s);
+	case E1000_RCTL:
+		return e1000_get_receive_control(s);
+	default:
+		EDBGUNKOUT("MMIO unknown read addr=0x%08x\n", addr - s->mmio_base);
+		break;
+	}
+
+	return 0;
+}
+
+struct e1000_eeprom e1000_eeprom_template = { .raw = {
+	0x0000, 0x0000, 0x0000, 0x0d30, 0xf746, 0x00f4, 0xffff, 0xffff,
+	0xffff, 0xffff, 0x026b, 0x108c, 0x15d9, 0x108c, 0x8086, 0x83df,
+	0x0008, 0x2000, 0x7e14, 0x0048, 0x1000, 0x00d8, 0x0000, 0x2700,
+	0x6cc9, 0x3150, 0x0722, 0x040b, 0x0984, 0x0000, 0xc000, 0x0706,
+	0x1008, 0x0000, 0x0f04, 0x7fff, 0x4d01, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0x0100, 0x4000, 0x121c, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+	0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0x0000,
+}};
+
+static void e1000_common_init(e1000_vmhw *d, NICInfo *nd, const char *info_str)
+{
+	uint16_t checksum = 0;
+	int i;
+	
+	d->nd = nd;
+	d->eeprom_data = e1000_eeprom_template;
+	d->eeprom_data.raw[0] = (nd->macaddr[1] << 8) | nd->macaddr[0];
+	d->eeprom_data.raw[1] = (nd->macaddr[3] << 8) | nd->macaddr[2];
+	d->eeprom_data.raw[2] = (nd->macaddr[5] << 8) | nd->macaddr[4];
+	for (i=0; i < EEPROM_CHECKSUM_REG; i++)
+		checksum += d->eeprom_data.raw[i];
+	checksum = (uint16_t) EEPROM_SUM - checksum;
+	d->eeprom_data.raw[EEPROM_CHECKSUM_REG] = checksum;
+
+	d->phy_regs[PHY_CTRL] = 0x1140;
+	d->phy_regs[PHY_STATUS] = 0x7949;
+	d->phy_regs[PHY_ID1] = 0x141;
+	d->phy_regs[PHY_ID2] = 0xcc2;
+	d->phy_regs[PHY_1000T_CTRL] = 0x0e00;
+	d->phy_regs[M88E1000_PHY_SPEC_CTRL] = 0x360;
+	d->phy_regs[M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60;
+	d->phy_regs[PHY_AUTONEG_ADV] = 0xde1;
+	d->rctl = 0;
+
+	d->interrupt_mask = ~0;
+
+	EDBGOUT("eeprom checksum: 0x%04x\n", checksum);
+
+	d->vc = qemu_new_vlan_client(nd->vlan, e1000_receive, 
+				     e1000_can_receive, d);
+    
+	snprintf(d->vc->info_str, sizeof(d->vc->info_str),
+		 "e1000 macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+		 d->nd->macaddr[0],
+		 d->nd->macaddr[1],
+		 d->nd->macaddr[2],
+		 d->nd->macaddr[3],
+		 d->nd->macaddr[4],
+		 d->nd->macaddr[5]);
+}
+
+/* PCI interface */
+
+static CPUWriteMemoryFunc *e1000_mmio_write[] = {
+	(CPUWriteMemoryFunc *)&e1000_mmio_writeb,
+	(CPUWriteMemoryFunc *)&e1000_mmio_writew,
+	(CPUWriteMemoryFunc *)&e1000_mmio_writel
+};
+
+static CPUReadMemoryFunc *e1000_mmio_read[] = {
+	(CPUReadMemoryFunc *)&e1000_mmio_readb,
+	(CPUReadMemoryFunc *)&e1000_mmio_readw,
+	(CPUReadMemoryFunc *)&e1000_mmio_readl
+};
+
+static void e1000_mmio_map(PCIDevice *pci_dev, int region_num, 
+                            uint32_t addr, uint32_t size, int type)
+{
+	e1000_vmhw *d = (e1000_vmhw *)pci_dev;
+
+	EDBGOUT("e1000_mmio_map addr=0x%08x 0x%08x\n", addr, size);
+
+	d->mmio_base = addr;
+	cpu_register_physical_memory(addr, E1000_PNPMMIO_SIZE, d->mmio_index);
+}
+
+void pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn)
+{
+	e1000_vmhw *d;
+	uint8_t *pci_conf;
+	
+	d = (e1000_vmhw *)pci_register_device(bus, "e1000", sizeof(e1000_vmhw),
+					      devfn, NULL, NULL);
+                                          
+	pci_conf = d->dev.config;
+
+	*(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x8086);
+	*(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x109a);    
+	*(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0407); 
+	*(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0010);
+	pci_conf[0x08] = 0x03;
+	pci_conf[0x09] = 0x00;
+	pci_conf[0x0a] = 0x00; // ethernet network controller 
+	pci_conf[0x0b] = 0x02;
+
+	pci_conf[0x0c] = 0x10;
+	pci_conf[0x0d] = 0x00;
+	pci_conf[0x0e] = 0x00;
+	pci_conf[0x0f] = 0x00;
+
+	*(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0xe0300000);
+	*(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000);
+    
+	pci_conf[0x3d] = 1; // interrupt pin 0
+	pci_conf[0x3e] = 0x00;
+	pci_conf[0x3f] = 0x00;
+
+	/* Handler for memory-mapped I/O */
+	d->mmio_index =
+		cpu_register_io_memory(0, e1000_mmio_read, e1000_mmio_write, d);
+
+	pci_register_io_region((PCIDevice *)d, 0, E1000_PNPMMIO_SIZE, 
+			       PCI_ADDRESS_SPACE_MEM, e1000_mmio_map);
+
+	pci_register_io_region((PCIDevice *)d, 1, E1000_IOPORT_SIZE, 
+			       PCI_ADDRESS_SPACE_IO, e1000_ioport_map);
+                           
+	e1000_common_init(d, nd, "e1000");
+}
diff --git a/qemu/hw/pci.c b/qemu/hw/pci.c
index b895f98..6d3be5c 100644
--- a/qemu/hw/pci.c
+++ b/qemu/hw/pci.c
@@ -552,6 +552,8 @@ void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn)
         pci_rtl8139_init(bus, nd, devfn);
     } else if (strcmp(nd->model, "pcnet") == 0) {
         pci_pcnet_init(bus, nd, devfn);
+    } else if (strcmp(nd->model, "e1000") == 0) {
+        pci_e1000_init(bus, nd, devfn);
     } else {
         fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
         exit (1);

-- 
Dan Aloni
XIV LTD, http://www.xivstorage.com
da-x (at) monatomic.org, dan (at) xiv.co.il

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [Qemu-devel] Re: e1000 emulation
  2007-09-01 19:51   ` Dan Aloni
@ 2007-09-02  6:55     ` Mulyadi Santosa
  0 siblings, 0 replies; 5+ messages in thread
From: Mulyadi Santosa @ 2007-09-02  6:55 UTC (permalink / raw)
  To: qemu-devel; +Cc: da-x

Hi Dan...!

How are you doing?
> Okay, just a few notes:
>
>  * Sorry for sending this rather badly written patch, I have loads of 
>    other stuff at the moment. I hope that it serves as a ground for 
>    further development, though.
>   
I appreciate your work here, congratulations!

regards,

Mulyadi

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2007-09-02  7:22 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-08-25 21:18 [Qemu-devel] e1000 emulation Dan Aloni
2007-08-26 12:25 ` [Qemu-devel] " Triggered
2007-09-01 19:51   ` Dan Aloni
2007-09-02  6:55     ` Mulyadi Santosa
2007-08-26 15:57 ` [Qemu-devel] " Anthony Liguori

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).