From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([140.186.70.92]:39930) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Qyr0i-0004I3-Cx for qemu-devel@nongnu.org; Wed, 31 Aug 2011 16:03:49 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Qyr0f-0002aT-B7 for qemu-devel@nongnu.org; Wed, 31 Aug 2011 16:03:44 -0400 Received: from nm19-vm1.bullet.mail.ukl.yahoo.com ([217.146.183.114]:44873) by eggs.gnu.org with smtp (Exim 4.71) (envelope-from ) id 1Qyr0e-0002aB-MY for qemu-devel@nongnu.org; Wed, 31 Aug 2011 16:03:41 -0400 Message-ID: <1314821019.89881.YahooMailClassic@web27006.mail.ukl.yahoo.com> Date: Wed, 31 Aug 2011 21:03:39 +0100 (BST) From: bifferos In-Reply-To: MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Subject: [Qemu-devel] [PATCH v2] Add support for r6040 NIC List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Anthony Liguori , malc Cc: qemu-devel@nongnu.org =0AHere it is again with copyright, typo fix and hopefully now complying wi= th coding standards.=0A=0A=0ASigned-off-by: Mark Kelly = =0Adiff --git a/Makefile.objs b/Makefile.objs=0Aindex 6991a9f..7d87503 1006= 44=0A--- a/Makefile.objs=0A+++ b/Makefile.objs=0A@@ -240,6 +240,7 @@ hw-obj= -$(CONFIG_PCNET_PCI) +=3D pcnet-pci.o=0A hw-obj-$(CONFIG_PCNET_COMMON) +=3D= pcnet.o=0A hw-obj-$(CONFIG_E1000_PCI) +=3D e1000.o=0A hw-obj-$(CONFIG_RTL8= 139_PCI) +=3D rtl8139.o=0A+hw-obj-$(CONFIG_R6040_PCI) +=3D r6040.o=0A =0A h= w-obj-$(CONFIG_SMC91C111) +=3D smc91c111.o=0A hw-obj-$(CONFIG_LAN9118) +=3D= lan9118.o=0Adiff --git a/default-configs/pci.mak b/default-configs/pci.mak= =0Aindex 22bd350..d2ea7a2 100644=0A--- a/default-configs/pci.mak=0A+++ b/de= fault-configs/pci.mak=0A@@ -10,6 +10,7 @@ CONFIG_PCNET_PCI=3Dy=0A CONFIG_PC= NET_COMMON=3Dy=0A CONFIG_LSI_SCSI_PCI=3Dy=0A CONFIG_RTL8139_PCI=3Dy=0A+CONF= IG_R6040_PCI=3Dy=0A CONFIG_E1000_PCI=3Dy=0A CONFIG_IDE_CORE=3Dy=0A CONFIG_I= DE_QDEV=3Dy=0Adiff --git a/hw/pci.c b/hw/pci.c=0Aindex b904a4e..7e12935 100= 644=0A--- a/hw/pci.c=0A+++ b/hw/pci.c=0A@@ -1527,6 +1527,7 @@ static const = char * const pci_nic_models[] =3D {=0A "rtl8139",=0A "e1000",=0A = "pcnet",=0A+ "r6040",=0A "virtio",=0A NULL=0A };=0A@@ -1539,6 = +1540,7 @@ static const char * const pci_nic_names[] =3D {=0A "rtl8139"= ,=0A "e1000",=0A "pcnet",=0A+ "r6040",=0A "virtio-net-pci",= =0A NULL=0A };=0Adiff --git a/hw/r6040.c b/hw/r6040.c=0Anew file mode 1= 00644=0Aindex 0000000..2908459=0A--- /dev/null=0A+++ b/hw/r6040.c=0A@@ -0,0= +1,644 @@=0A+/*=0A+ * Emulation of r6040 ethernet controller found in a nu= mber of SoCs.=0A+ * Copyright (c) 2011 Mark Kelly, mark@bifferos.com=0A+ *= =0A+ * Permission is hereby granted, free of charge, to any person obtainin= g a=0A+ * copy of this software and associated documentation files (the "So= ftware"),=0A+ * to deal in the Software without restriction, including with= out limitation=0A+ * the rights to use, copy, modify, merge, publish, distr= ibute, sublicense,=0A+ * and/or sell copies of the Software, and to permit = persons to whom the=0A+ * Software is furnished to do so, subject to the fo= llowing conditions:=0A+ *=0A+ * The above copyright notice and this permiss= ion notice shall be included=0A+ * in all copies or substantial portions of= the Software.=0A+ *=0A+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRAN= TY OF ANY KIND, EXPRESS=0A+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE = WARRANTIES OF=0A+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND N= ONINFRINGEMENT. IN=0A+ * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE= LIABLE FOR ANY CLAIM,=0A+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTI= ON OF CONTRACT, TORT OR=0A+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECT= ION WITH THE SOFTWARE OR=0A+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.= =0A+ *=0A+ * This has been written using the R8610[1] and ip101a[2] datashe= ets.=0A+ *=0A+ * ICs with the embedded controller include R8610, R3210, AMR= ISC20000=0A+ * and Vortex86SX=0A+ *=0A+ * The emulation seems good enough t= o fool Linux 2.6.37.6. It is=0A+ * not perfect, but has proven useful.=0A+= *=0A+ * [1] http://www.sima.com.tw/download/R8610_D06_20051003.pdf=0A+ * [= 2] http://www.icplus.com.tw/pp-IP101A.html=0A+ */=0A+=0A+#include "hw.h"=0A= +#include "pci.h"=0A+#include "net.h"=0A+#include "loader.h"=0A+#include "s= ysemu.h"=0A+#include "qemu-timer.h"=0A+=0A+/* #define DEBUG_R6040 1 */=0A+= =0A+=0A+#if defined DEBUG_R6040=0A+#define DPRINTF(fmt, ...) \=0A+ do { = fprintf(stderr, "R6040: " fmt, ## __VA_ARGS__); } while (0)=0A+#else=0A+sta= tic inline GCC_FMT_ATTR(1, 2) int DPRINTF(const char *fmt, ...)=0A+{=0A+ = return 0;=0A+}=0A+#endif=0A+=0A+=0A+/* Cast in order of appearance. _W su= ffix means it's used to index the=0A+ register word array (regs_w)=0A+ */= =0A+=0A+#define MPSCCR_W (0x88 / 2)=0A+=0A+#define MAC0_W = (0x68 / 2)=0A+#define MAC1_W (0x6a / 2)=0A+#define MAC2_W = (0x6c / 2)=0A+=0A+=0A+#define RX_START_LOW_W (0x34 / 2)=0A+#define RX= _START_HIGH_W (0x38 / 2)=0A+#define TX_PKT_COUNT_W (0x5a / 2)=0A+#define= RX_PKT_COUNT_W (0x50 / 2)=0A+=0A+=0A+#define MCR0_W (0x00 / 2)= =0A+#define MCR1_W (0x04 / 2)=0A+#define BIT_MRST (1 << 0= )=0A+=0A+#define MTPR_W (0x14 / 2)=0A+#define MRBSR_W (0= x18 / 2)=0A+#define MISR_W (0x3c / 2)=0A+#define MIER_W = (0x40 / 2)=0A+=0A+#define MMDIO_W (0x20 / 2)=0A+#define MDIO_READ= _W (0x24 / 2)=0A+#define MDIO_WRITE_W (0x28 / 2)=0A+=0A+#define MR= CNT_W (0x50 / 2)=0A+#define MTCNT_W (0x5c / 2)=0A+=0A+=0A= +#define MDIO_WRITE 0x4000=0A+#define MDIO_READ 0x2000=0A+=0A+= =0A+typedef struct R6040State {=0A+ PCIDevice dev;=0A+ NICState *nic;= =0A+ NICConf conf;=0A+=0A+ /* PHY related register sets */=0A+ uin= t16_t mid0[3];=0A+ uint16_t phy_regs[32];=0A+ uint32_t phy_op_in_prog= ress;=0A+=0A+ /* Primary IO address space */=0A+ union {=0A+ u= int8_t regs_b[0x100]; /* Byte access */=0A+ uint16_t regs_w[0x100/= 2]; /* word access */=0A+ uint32_t regs_l[0x100/4]; /* DWORD acces= s */=0A+ };=0A+=0A+} R6040State;=0A+=0A+=0A+/* some inlines to help acce= ss above structure */=0A+static inline uint32_t TX_START(R6040State *s)=0A+= {=0A+ uint32_t tmp =3D s->regs_w[0x2c/2];=0A+ return tmp | (s->regs_w= [0x30/2] << 16);=0A+}=0A+=0A+static inline void TX_START_SET(R6040State *s,= uint32_t start)=0A+{=0A+ s->regs_w[0x2c/2] =3D start & 0xffff;=0A+ s= ->regs_w[0x30/2] =3D (start >> 16) & 0xffff;=0A+}=0A+=0A+static inline uint= 32_t RX_START(R6040State *s)=0A+{=0A+ uint32_t tmp =3D s->regs_w[0x34/2]= ;=0A+ return tmp | (s->regs_w[0x38/2] << 16);=0A+}=0A+=0A+static inline = void RX_START_SET(R6040State *s, uint32_t start)=0A+{=0A+ s->regs_w[0x34= /2] =3D start & 0xffff;=0A+ s->regs_w[0x38/2] =3D (start >> 16) & 0xffff= ;=0A+}=0A+=0A+=0A+static void r6040_update_irq(R6040State *s)=0A+{=0A+ u= int16_t isr =3D s->regs_w[MISR_W] & s->regs_w[MIER_W];=0A+=0A+ qemu_set_= irq(s->dev.irq[0], isr ? 1 : 0);=0A+}=0A+=0A+=0A+/* Mark auto-neg complete,= NIC up. */=0A+static void PhysicalLinkUp(void *opaque)=0A+{=0A+ R6040S= tate *s =3D opaque;=0A+ s->phy_regs[1] |=3D (1 << 2);=0A+}=0A+=0A+=0A+/*= Transmit and receive descriptors are doubled up=0A+ One is a subset of t= he other anyhow=0A+ */=0A+typedef struct Descriptor {=0A+ uint16_t dst;= =0A+ uint16_t dlen;=0A+ uint32_t dbp;=0A+ uint32_t dnx;=0A+ uin= t16_t hidx;=0A+ uint16_t reserved_1;=0A+ uint16_t reserved_2;=0A+} De= scriptor;=0A+=0A+=0A+/* Some debugging functions */=0A+=0A+#ifdef DEBUG_R60= 40=0A+static void addr_dump16(const char *name, uint16_t val)=0A+{=0A+ D= PRINTF("%s: 0x%04x ", name, val);=0A+}=0A+=0A+static void addr_dump32(cons= t char *name, uint32_t val)=0A+{=0A+ DPRINTF("%s: 0x%x ", name, val);= =0A+}=0A+=0A+static void hex_dump(const uint8_t *data, uint32_t len)=0A+{= =0A+ uint8_t i;=0A+ DPRINTF("hex: ");=0A+ for (i =3D 0; i < len; i= ++) {=0A+ fprintf(stderr, "%02x ", *data);=0A+ if (i && !(i %= 0x20)) {=0A+ fprintf(stderr, "\n");=0A+ }=0A+ dat= a++;=0A+ }=0A+ fprintf(stderr, "\n");=0A+}=0A+=0A+static void desc_du= mp(Descriptor *d, uint32_t addr)=0A+{=0A+ DPRINTF("\nDumping: 0x%x\n", a= ddr);=0A+ addr_dump16("DST", d->dst);=0A+ addr_dump16("DLEN", d->dlen= );=0A+ addr_dump32("DBP", (unsigned long)d->dbp);=0A+ addr_dump32("DN= X", (unsigned long)d->dnx);=0A+ addr_dump16("HIDX", d->hidx);=0A+ pri= ntf("\n");=0A+}=0A+=0A+static void dump_phys_mem(uint32_t addr, int len)=0A= +{=0A+ uint8_t buffer[1024];=0A+ cpu_physical_memory_read(addr, buffe= r, len);=0A+ hex_dump(buffer, len);=0A+}=0A+=0A+static void dump_pci(uin= t8_t *pci_conf)=0A+{=0A+ uint32_t *p =3D (uint32_t *)pci_conf;=0A+ in= t i =3D 0;=0A+ for (i =3D 0; i < 0x40; i +=3D 4) {=0A+ DPRINTF("A= ddr: 0x%08x, Data: 0x%08x\n", i, *p);=0A+ p++;=0A+ }=0A+}=0A+#en= dif=0A+=0A+=0A+static const VMStateDescription vmstate_r6040 =3D {=0A+ .= name =3D "r6040",=0A+ .version_id =3D 3,=0A+ .minimum_version_id =3D = 2,=0A+ .minimum_version_id_old =3D 2,=0A+ .fields =3D (VMStateField[]= ) {=0A+ VMSTATE_PCI_DEVICE(dev, R6040State),=0A+ VMSTATE_BUFF= ER(regs_b, R6040State),=0A+ VMSTATE_UINT16_ARRAY(mid0, R6040State, 3= ),=0A+ VMSTATE_UINT16_ARRAY(phy_regs, R6040State, 32),=0A+ VM= STATE_UINT32(phy_op_in_progress, R6040State),=0A+ VMSTATE_MACADDR(co= nf.macaddr, R6040State),=0A+ VMSTATE_END_OF_LIST()=0A+ }=0A+};=0A= +=0A+=0A+static int TryToSendOnePacket(void *opaque)=0A+{=0A+ R6040State= *s =3D opaque;=0A+ Descriptor d;=0A+ uint8_t pkt_buffer[2000];=0A+ = uint32_t tocopy;=0A+=0A+ cpu_physical_memory_read(TX_START(s), (uint8_= t *)&d, sizeof(d));=0A+=0A+ if (d.dst & 0x8000) { /* MAC owns it? */= =0A+ tocopy =3D d.dlen;=0A+ if (tocopy > sizeof(pkt_buffer)) = {=0A+ tocopy =3D sizeof(pkt_buffer);=0A+ }=0A+ /* = copy the packet to send it */=0A+ cpu_physical_memory_read(d.dbp, pk= t_buffer, tocopy);=0A+=0A+ qemu_send_packet(&s->nic->nc, pkt_buffer,= tocopy);=0A+ s->regs_w[TX_PKT_COUNT_W]++;=0A+=0A+ /* relinqu= ish ownership, we're done with it */=0A+ d.dst &=3D ~0x8000;=0A+=0A+= /* Copy the new version of the descriptor back */=0A+ cpu_ph= ysical_memory_write(TX_START(s), (uint8_t *)&d, sizeof(d));=0A+=0A+ = /* Advance to the next buffer if packet processed */=0A+ TX_START_SE= T(s, d.dnx);=0A+=0A+ return 1;=0A+ }=0A+=0A+ return 0;=0A+}=0A= +=0A+=0A+static void r6040_transmit(void *opaque)=0A+{=0A+ R6040State *s= =3D opaque;=0A+ int count =3D 0;=0A+=0A+ while (TryToSendOnePacket(s= )) {=0A+ ++count;=0A+ }=0A+=0A+ if (count) {=0A+ s->reg= s_w[MISR_W] |=3D 0x10;=0A+ r6040_update_irq(s);=0A+ }=0A+}=0A+=0A= +=0A+/* Whether to allow callback returning 1 for yes, can receive */=0A+st= atic int r6040_can_receive(VLANClientState *nc)=0A+{=0A+ R6040State *s = =3D DO_UPCAST(NICState, nc, nc)->opaque;=0A+ int tmp =3D (s->regs_w[0] &= (1 << 1)) ? 1 : 0;=0A+ return tmp;=0A+}=0A+=0A+=0A+static int ReceiveOn= ePacket(void *opaque, const uint8_t *buf, size_t len)=0A+{=0A+ R6040Stat= e *s =3D opaque;=0A+ uint32_t tocopy =3D len+4; /* include checksum */= =0A+ Descriptor d;=0A+=0A+ cpu_physical_memory_read(RX_START(s), (uin= t8_t *)&d, sizeof(Descriptor));=0A+ /*desc_dump(&d, 0);*/=0A+=0A+ if = (d.dst & 0x8000) { /* MAC owned? */=0A+=0A+ uint16_t max_buffer = =3D s->regs_w[MRBSR_W] & 0x07fc;=0A+ if (tocopy > max_buffer) {=0A+ = tocopy =3D max_buffer;=0A+ }=0A+=0A+ cpu_physical_= memory_write(d.dbp, buf, tocopy-4);=0A+=0A+ /* indicate received OK = */=0A+ d.dst |=3D (1 << 14);=0A+ d.dlen =3D tocopy;=0A+ = /* relinquish ownership */=0A+ d.dst &=3D ~0x8000;=0A+=0A+ = /* Copy the descriptor back */=0A+ cpu_physical_memory_write(RX_STAR= T(s), (uint8_t *)&d,=0A+ sizeof(Descripto= r));=0A+=0A+ s->regs_w[RX_PKT_COUNT_W]++;=0A+=0A+ s->regs_w[M= ISR_W] |=3D 1; /* received pkt interrupt */=0A+=0A+ r6040_update_ir= q(s);=0A+=0A+ RX_START_SET(s, d.dnx); /* advance */=0A+=0A+ = return 0;=0A+ }=0A+ return -1;=0A+}=0A+=0A+=0A+/* called on incoming = packets */=0A+static ssize_t r6040_receive(VLANClientState *nc, const uint8= _t *buf,=0A+ size_t len)=0A+{=0A+ = R6040State *s =3D DO_UPCAST(NICState, nc, nc)->opaque;=0A+ DPRINTF("Rec= eived incoming packet of len %ld\n", len);=0A+=0A+ if (0 =3D=3D ReceiveO= nePacket(s, buf, len)) {=0A+ return len; /* copied OK */=0A+ }= =0A+=0A+ return 0;=0A+}=0A+=0A+=0A+static void r6040_cleanup(VLANClientS= tate *vc)=0A+{=0A+ DPRINTF("r6040_cleanup\n");=0A+}=0A+=0A+=0A+static in= line int BIT_SET(uint16_t old, uint16_t new, uint16_t bit)=0A+{=0A+ uint= 16_t before =3D (old & (1 << bit));=0A+ uint16_t after =3D (new & (1 << = bit));=0A+ if (!before && after) {=0A+ return 1;=0A+ }=0A+ = return 0;=0A+}=0A+=0A+=0A+static void r6040_ioport_writew(void *opaque, uin= t32_t addr, uint32_t val)=0A+{=0A+ R6040State *s =3D opaque;=0A+ uint= 16_t old;=0A+ addr &=3D 0xff; /* get relative to base address */=0A+ = addr /=3D 2; /* Get the offset into the word-array */=0A+ old =3D s= ->regs_w[addr]; /* store the old value for future use */=0A+=0A+ switc= h (addr) {=0A+ case MCR0_W: /* 0x00 */=0A+ if (BIT_SET(old, val= , 12)) {=0A+ r6040_transmit(opaque);=0A+ }=0A+ bre= ak;=0A+ case MCR1_W: /* 0x04 */=0A+ if (val & BIT_MRST) { /* r= eset request incoming */=0A+ /* reset requested, complete it imm= ediately, set this value to=0A+ default */=0A+ val= =3D 0x0010;=0A+ }=0A+ break;=0A+ case MTPR_W: /* TX comm= and reg, 0x14 */=0A+ if (val & 1) {=0A+ r6040_transmit(op= aque);=0A+ val &=3D ~1;=0A+ }=0A+ break;=0A+ ca= se MMDIO_W: /* MDIO control, 0x20 */=0A+ {=0A+ int phy_e= xists =3D ((val & 0x1f00) =3D=3D 0x100) ? 1 : 0;=0A+ uint16_t *p= hy =3D s->phy_regs;=0A+ phy +=3D (val & 0x1f);=0A+=0A+ = if (val & (1 << 13)) { /* read data */=0A+ if (phy_exis= ts) {=0A+ s->regs_w[MDIO_READ_W] =3D *phy;=0A+ = } else {=0A+ s->regs_w[MDIO_READ_W] =3D 0xffff;=0A= + }=0A+ } else if (val & (1 << 14)) { /* write d= ata */=0A+ if (phy_exists) {=0A+ *phy =3D= s->regs_w[MDIO_WRITE_W];=0A+ }=0A+ }=0A+=0A+ = /* Whether you request to read or write, both bits go high while=0A= + the operation is in progress, e.g. tell it to read, and the= =0A+ write-in-progress flag also goes high */=0A+ = val |=3D 0x6000; /* signal operation has started */=0A+ s->phy_= op_in_progress =3D 1;=0A+=0A+ break;=0A+ }=0A+ case MI= SR_W: /* interrupt status reg (read to clear), 0x3c */=0A+ return;= =0A+=0A+ case MIER_W: /* interrupt enable register, 0x40 */=0A+ = s->regs_w[MIER_W] =3D val;=0A+ r6040_update_irq(s);=0A+ retur= n;=0A+=0A+ case MRCNT_W: /* 0x50 */=0A+ case MTCNT_W: /* 0x5c */= =0A+ return; /* Can't write to pkt count registers, skip */=0A+=0A+= }=0A+ s->regs_w[addr] =3D val & 0xFFFF;=0A+}=0A+=0A+=0A+static uint3= 2_t r6040_ioport_readw(void *opaque, uint32_t addr)=0A+{=0A+ R6040State = *s =3D opaque;=0A+ addr &=3D 0xff; /* get relative to base address */= =0A+ addr /=3D 2; /* Get the offset into the word-array */=0A+ uin= t32_t tmp =3D s->regs_w[addr]; /* get the value */=0A+=0A+ switch (addr= ) {=0A+=0A+ case MMDIO_W: /* MDIO control, 0x20 */=0A+ {=0A+ = /* Clear any in-progress MDIO activity for the next read=0A+ = This simulates the polling of the MDIO operation status,=0A+ = so the driver code always has to read the register twice=0A+ = before it thinks the operation is complete. */=0A+ if (s= ->phy_op_in_progress) {=0A+ s->regs_w[addr] &=3D ~0x6000;=0A= + s->phy_op_in_progress =3D 0;=0A+ }=0A+ = break;=0A+ }=0A+ case MISR_W: /* interrupt status reg (read t= o clear) 0x3c */=0A+ s->regs_w[addr] =3D 0;=0A+ break;=0A+ = case MIER_W: /* interrupt enable reg 0x40 */=0A+ break;=0A+ ca= se MRCNT_W: /* 0x50 */=0A+ case MTCNT_W: /* 0x5c */=0A+ s->regs= _w[addr] =3D 0; /* read to clear */=0A+ break;=0A+ default:=0A+= break;=0A+ }=0A+ return tmp;=0A+}=0A+=0A+=0A+/* byte and long= access are routed via the word operation handlers */=0A+static void r6040_= ioport_writeb(void *opaque, uint32_t addr, uint32_t val)=0A+{=0A+ R6040S= tate *s =3D opaque;=0A+ addr &=3D 0xFF;=0A+ val &=3D 0xFF;=0A+ uin= t16_t old =3D s->regs_w[addr/2]; /* get the current value */=0A+ if (ad= dr & 1) {=0A+ old &=3D 0xff;=0A+ old |=3D (val << 8);=0A+ = } else {=0A+ old &=3D 0xff00;=0A+ old |=3D val;=0A+ }=0A+= =0A+ r6040_ioport_writew(opaque, addr, old); /* call the word-based ver= sion */=0A+}=0A+=0A+static void r6040_ioport_writel(void *opaque, uint32_t = addr, uint32_t val)=0A+{=0A+ /* Set the low value */=0A+ r6040_ioport= _writew(opaque, addr, val & 0xffff);=0A+ /* Set the high value */=0A+ = r6040_ioport_writew(opaque, addr+2, (val >> 16) & 0xffff);=0A+}=0A+=0A+sta= tic uint32_t r6040_ioport_readb(void *opaque, uint32_t addr)=0A+{=0A+ ui= nt32_t tmp =3D r6040_ioport_readw(opaque, addr & ~1);=0A+ if (addr & 1) = {=0A+ return (tmp & 0xff00) >> 8;=0A+ }=0A+ return tmp & 0xff;= =0A+}=0A+=0A+static uint32_t r6040_ioport_readl(void *opaque, uint32_t addr= )=0A+{=0A+ uint32_t tmp =3D r6040_ioport_readw(opaque, addr);=0A+ ret= urn tmp | (r6040_ioport_readw(opaque, addr+2) << 16);=0A+}=0A+=0A+=0A+stati= c void r6040_register_ioports(R6040State *s, pcibus_t addr)=0A+{=0A+ reg= ister_ioport_write(addr, 0x100, 1, r6040_ioport_writeb, s);=0A+ register= _ioport_read(addr, 0x100, 1, r6040_ioport_readb, s);=0A+=0A+ register_i= oport_write(addr, 0x100, 2, r6040_ioport_writew, s);=0A+ register_ioport= _read(addr, 0x100, 2, r6040_ioport_readw, s);=0A+=0A+ register_ioport_w= rite(addr, 0x100, 4, r6040_ioport_writel, s);=0A+ register_ioport_read(a= ddr, 0x100, 4, r6040_ioport_readl, s);=0A+}=0A+=0A+=0A+static void r6040_m= ap(PCIDevice *pci_dev, int region_num,=0A+ pcibus_t a= ddr, pcibus_t size, int type)=0A+{=0A+ R6040State *s =3D DO_UPCAST(R6040= State, dev, pci_dev);;=0A+=0A+ DPRINTF("## Mapping to address %lx\n", ad= dr);=0A+ r6040_register_ioports(s, addr);=0A+}=0A+=0A+=0A+static NetClie= ntInfo net_r6040_info =3D {=0A+ .type =3D NET_CLIENT_TYPE_NIC,=0A+ .s= ize =3D sizeof(NICState),=0A+ .can_receive =3D r6040_can_receive,=0A+ = .receive =3D r6040_receive,=0A+ .cleanup =3D r6040_cleanup,=0A+};=0A+= =0A+=0A+static int r6040_init_pci(PCIDevice *dev)=0A+{=0A+ QEMUTimer *ti= mer;=0A+=0A+ R6040State *s =3D DO_UPCAST(R6040State, dev, dev);=0A+ u= int8_t *pci_conf;=0A+=0A+ /* MAC PHYS status change register. Linux dri= ver expects something=0A+ sensible as default and if not will try to = set it */=0A+ s->regs_w[MPSCCR_W] =3D 0x9f07;=0A+=0A+ /* Default valu= e for maximum packet size */=0A+ s->regs_w[MRBSR_W] =3D 0x600;=0A+=0A+ = /* set the MAC, linux driver reads this when it loads, it is=0A+ no= rmally set by the BIOS, but obviously Qemu BIOS isn't going=0A+ to do= that */=0A+ s->regs_w[MAC0_W] =3D 0x5452;=0A+ s->regs_w[MAC1_W] =3D = 0x1200;=0A+ s->regs_w[MAC2_W] =3D 0x5734;=0A+=0A+ /* Tell Qemu the sa= me thing */=0A+ s->conf.macaddr.a[0] =3D s->regs_w[MAC0_W] & 0xff;=0A+ = s->conf.macaddr.a[1] =3D (s->regs_w[MAC0_W] >> 8) & 0xff;=0A+ s->conf.= macaddr.a[2] =3D s->regs_w[MAC1_W] & 0xff;=0A+ s->conf.macaddr.a[3] =3D = (s->regs_w[MAC1_W] >> 8) & 0xff;=0A+ s->conf.macaddr.a[4] =3D s->regs_w[= MAC2_W] & 0xff;=0A+ s->conf.macaddr.a[5] =3D (s->regs_w[MAC2_W] >> 8) & = 0xff;=0A+=0A+ /* no commands running */=0A+ s->phy_op_in_progress =3D= 0;=0A+=0A+ /* PHY auto-neg in progress */=0A+ s->phy_regs[1] =3D 0x7= 86d & ~(1 << 2);=0A+ s->phy_regs[2] =3D 0x0243;=0A+ s->phy_regs[3] = =3D 0x0c54;=0A+=0A+ pci_conf =3D (uint8_t *)s->dev.config;=0A+=0A+ pc= i_conf[PCI_HEADER_TYPE] =3D PCI_HEADER_TYPE_NORMAL; /* header_type */=0A+ = pci_conf[PCI_INTERRUPT_LINE] =3D 0xa; /* interrupt line */=0A+ pc= i_conf[PCI_INTERRUPT_PIN] =3D 1; /* interrupt pin 0 */=0A+=0A+ pci_= register_bar(&s->dev, 0, 0x100, PCI_BASE_ADDRESS_SPACE_IO, r6040_map);=0A+= =0A+ s->nic =3D qemu_new_nic(&net_r6040_info, &s->conf,=0A+ = dev->qdev.info->name, dev->qdev.id, s);=0A+=0A+ qemu_form= at_nic_info_str(&s->nic->nc, s->conf.macaddr.a);=0A+=0A+ /* Simulate a d= elay of a couple of seconds for the link to come up.=0A+ Not required= for Linux but very handy for developing BIOS code.=0A+ */=0A+ timer= =3D qemu_new_timer_ns(vm_clock, PhysicalLinkUp, s);=0A+ qemu_mod_timer(= timer, qemu_get_clock_ms(vm_clock) + 1500000000);=0A+=0A+ /* Register IO= port access as well */=0A+ r6040_register_ioports(s, 0xe800);=0A+=0A+ = return 0;=0A+}=0A+=0A+=0A+static PCIDeviceInfo r6040_info =3D {=0A+ .q= dev.name =3D "r6040",=0A+ .qdev.size =3D sizeof(R6040State),=0A+ .qde= v.vmsd =3D &vmstate_r6040,=0A+ .init =3D r6040_init_pci,=0A+ .v= endor_id =3D 0x17f3, /* RDC */=0A+ .device_id =3D 0x6040, /* r6040 ni= c */=0A+ .class_id =3D PCI_CLASS_NETWORK_ETHERNET,=0A+ .qdev.props = =3D (Property[]) {=0A+ DEFINE_NIC_PROPERTIES(R6040State, conf),=0A+ = DEFINE_PROP_END_OF_LIST(),=0A+ }=0A+};=0A+=0A+=0A+static void r60= 40_register(void)=0A+{=0A+ pci_qdev_register(&r6040_info);=0A+}=0A+=0A+= =0A+device_init(r6040_register)=0A