]> git.proxmox.com Git - qemu.git/commitdiff
hw: move NICs to hw/net/, configure via default-configs/
authorPaolo Bonzini <pbonzini@redhat.com>
Tue, 5 Feb 2013 11:33:56 +0000 (12:33 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Mon, 8 Apr 2013 16:13:13 +0000 (18:13 +0200)
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
32 files changed:
default-configs/arm-softmmu.mak
default-configs/cris-softmmu.mak
default-configs/lm32-softmmu.mak
default-configs/m68k-softmmu.mak
default-configs/microblaze-softmmu.mak
default-configs/microblazeel-softmmu.mak
default-configs/ppc-softmmu.mak
default-configs/ppc64-softmmu.mak
default-configs/ppcemb-softmmu.mak
default-configs/sparc-softmmu.mak
hw/arm/Makefile.objs
hw/cris/Makefile.objs
hw/etraxfs_eth.c [deleted file]
hw/lance.c [deleted file]
hw/lm32/Makefile.objs
hw/m68k/Makefile.objs
hw/mcf_fec.c [deleted file]
hw/microblaze/Makefile.objs
hw/milkymist-minimac2.c [deleted file]
hw/net/Makefile.objs
hw/net/etraxfs_eth.c [new file with mode: 0644]
hw/net/lance.c [new file with mode: 0644]
hw/net/mcf_fec.c [new file with mode: 0644]
hw/net/milkymist-minimac2.c [new file with mode: 0644]
hw/net/spapr_llan.c [new file with mode: 0644]
hw/net/stellaris_enet.c [new file with mode: 0644]
hw/net/xilinx_ethlite.c [new file with mode: 0644]
hw/ppc/Makefile.objs
hw/spapr_llan.c [deleted file]
hw/sparc/Makefile.objs
hw/stellaris_enet.c [deleted file]
hw/xilinx_ethlite.c [deleted file]

index 4b72019878ce56fd62736b2330a687813d6f5777..cd353bd1fc23eea6a22d82be4a284ceacf83da12 100644 (file)
@@ -17,6 +17,7 @@ CONFIG_TSC2005=y
 CONFIG_LM832X=y
 CONFIG_TMP105=y
 CONFIG_STELLARIS_INPUT=y
+CONFIG_STELLARIS_ENET=y
 CONFIG_SSD0303=y
 CONFIG_SSD0323=y
 CONFIG_ADS7846=y
index 1a479cd8d3ea4b39e9e78dd2fd0294ada830ce24..d970d50158b7429f6209f9d4b71db3e730424545 100644 (file)
@@ -1,5 +1,6 @@
 # Default configuration for cris-softmmu
 
+CONFIG_ETRAXFS=y
 CONFIG_NAND=y
 CONFIG_PTIMER=y
 CONFIG_PFLASH_CFI02=y
index 0d19974b40b290878201e612e54147b9e3c9f4e8..2654ad6e449bec6cee0873d1a97a5437db463ff6 100644 (file)
@@ -1,5 +1,6 @@
 # Default configuration for lm32-softmmu
 
+CONFIG_MILKYMIST=y
 CONFIG_PTIMER=y
 CONFIG_PFLASH_CFI01=y
 CONFIG_PFLASH_CFI02=y
index 778ea82a10fb7311252c54a84223c13c5bd1ec9a..51fe5bb3215016b32546413db3db8b1f4d35828b 100644 (file)
@@ -2,5 +2,6 @@
 
 include pci.mak
 include usb.mak
+CONFIG_COLDFIRE=y
 CONFIG_GDBSTUB_XML=y
 CONFIG_PTIMER=y
index 2f442e5aea0def706f36f1aa9e5a544d5662d6da..050e273580cef4fb1404feb924728cff69388cd2 100644 (file)
@@ -5,5 +5,6 @@ CONFIG_PFLASH_CFI01=y
 CONFIG_SERIAL=y
 CONFIG_XILINX=y
 CONFIG_XILINX_AXI=y
+CONFIG_XILINX_ETHLITE=y
 CONFIG_SSI=y
 CONFIG_SSI_M25P80=y
index af9a3cde0d8e899e96d10ec9ddb978e0e66bb10a..db82dd8086f3607ac4b2549078b600d20ba0b33a 100644 (file)
@@ -5,5 +5,6 @@ CONFIG_PFLASH_CFI01=y
 CONFIG_SERIAL=y
 CONFIG_XILINX=y
 CONFIG_XILINX_AXI=y
+CONFIG_XILINX_ETHLITE=y
 CONFIG_SSI=y
 CONFIG_SSI_M25P80=y
index d9ced3ada0f2df89a1a8ce5d441c89164f0007ed..36a8ed3f7b6724ff58857efd16b08d65d843e27b 100644 (file)
@@ -40,6 +40,7 @@ CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
 CONFIG_I8259=y
 CONFIG_XILINX=y
+CONFIG_XILINX_ETHLITE=y
 CONFIG_E500=$(CONFIG_FDT)
 # For PReP
 CONFIG_MC146818RTC=y
index 7d62e1495dac2d3a470c8cd97ae82b65ac619de0..2d5df773056d80e1571cd4f03f7c849afb4b24d9 100644 (file)
@@ -40,6 +40,7 @@ CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
 CONFIG_I8259=y
 CONFIG_XILINX=y
+CONFIG_XILINX_ETHLITE=y
 CONFIG_PSERIES=$(CONFIG_FDT)
 CONFIG_E500=$(CONFIG_FDT)
 # For pSeries
index 9d8c5c774221c9739997584ca79b89433069ca1f..ce705a93c1575f7aaba05fee06785047e126cb2d 100644 (file)
@@ -35,6 +35,7 @@ CONFIG_PFLASH_CFI02=y
 CONFIG_PTIMER=y
 CONFIG_I8259=y
 CONFIG_XILINX=y
+CONFIG_XILINX_ETHLITE=y
 CONFIG_E500=$(CONFIG_FDT)
 # For PReP
 CONFIG_MC146818RTC=y
index b0310c51e20c59ba4af9e7b7f5caef5296ddc39d..6d11ba03690d2c7b74af2e0b2aef19215b0dfe0a 100644 (file)
@@ -8,3 +8,4 @@ CONFIG_PTIMER=y
 CONFIG_FDC=y
 CONFIG_EMPTY_SLOT=y
 CONFIG_PCNET_COMMON=y
+CONFIG_LANCE=y
index d809ad858af656d493ed0423bb222eac4053b597..b14beb86efb25fc1e0cb0829a4ef8de763b686cc 100644 (file)
@@ -8,7 +8,7 @@ obj-y += exynos4210_uart.o exynos4210_pwm.o
 obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o
 obj-y += exynos4210_rtc.o exynos4210_i2c.o
 obj-y += arm_mptimer.o a15mpcore.o
-obj-y += armv7m_nvic.o stellaris_enet.o
+obj-y += armv7m_nvic.o
 obj-y += pxa2xx_timer.o pxa2xx_dma.o
 obj-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
 obj-y += zaurus.o tc6393xb.o
index a94c62450d308e8c9b4f654d0105c754877460af..e02365d5cdc0b841672e23458e13d89edb4ac7ae 100644 (file)
@@ -1,7 +1,6 @@
 # IO blocks
 obj-y += etraxfs_dma.o
 obj-y += etraxfs_pic.o
-obj-y += etraxfs_eth.o
 obj-y += etraxfs_timer.o
 obj-y += etraxfs_ser.o
 
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c
deleted file mode 100644 (file)
index 1039913..0000000
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * QEMU ETRAX Ethernet Controller.
- *
- * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
- *
- * 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 <stdio.h>
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "hw/cris/etraxfs.h"
-
-#define D(x)
-
-/* Advertisement control register. */
-#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
-#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
-#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
-#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
-
-/*
- * The MDIO extensions in the TDK PHY model were reversed engineered from the
- * linux driver (PHYID and Diagnostics reg).
- * TODO: Add friendly names for the register nums.
- */
-struct qemu_phy
-{
-    uint32_t regs[32];
-
-    int link;
-
-    unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
-    void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
-};
-
-static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
-{
-    int regnum;
-    unsigned r = 0;
-
-    regnum = req & 0x1f;
-
-    switch (regnum) {
-    case 1:
-        if (!phy->link) {
-            break;
-        }
-        /* MR1.     */
-        /* Speeds and modes.  */
-        r |= (1 << 13) | (1 << 14);
-        r |= (1 << 11) | (1 << 12);
-        r |= (1 << 5); /* Autoneg complete.  */
-        r |= (1 << 3); /* Autoneg able.     */
-        r |= (1 << 2); /* link.     */
-        break;
-    case 5:
-        /* Link partner ability.
-           We are kind; always agree with whatever best mode
-           the guest advertises.  */
-        r = 1 << 14; /* Success.  */
-        /* Copy advertised modes.  */
-        r |= phy->regs[4] & (15 << 5);
-        /* Autoneg support.  */
-        r |= 1;
-        break;
-    case 18:
-    {
-        /* Diagnostics reg.  */
-        int duplex = 0;
-        int speed_100 = 0;
-
-        if (!phy->link) {
-            break;
-        }
-
-        /* Are we advertising 100 half or 100 duplex ? */
-        speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
-        speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
-
-        /* Are we advertising 10 duplex or 100 duplex ? */
-        duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
-        duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
-        r = (speed_100 << 10) | (duplex << 11);
-    }
-    break;
-
-    default:
-        r = phy->regs[regnum];
-        break;
-    }
-    D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
-    return r;
-}
-
-static void
-tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
-{
-    int regnum;
-
-    regnum = req & 0x1f;
-    D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
-    switch (regnum) {
-    default:
-        phy->regs[regnum] = data;
-        break;
-    }
-}
-
-static void
-tdk_init(struct qemu_phy *phy)
-{
-    phy->regs[0] = 0x3100;
-    /* PHY Id.  */
-    phy->regs[2] = 0x0300;
-    phy->regs[3] = 0xe400;
-    /* Autonegotiation advertisement reg.  */
-    phy->regs[4] = 0x01E1;
-    phy->link = 1;
-
-    phy->read = tdk_read;
-    phy->write = tdk_write;
-}
-
-struct qemu_mdio
-{
-    /* bus.     */
-    int mdc;
-    int mdio;
-
-    /* decoder.  */
-    enum {
-        PREAMBLE,
-        SOF,
-        OPC,
-        ADDR,
-        REQ,
-        TURNAROUND,
-        DATA
-    } state;
-    unsigned int drive;
-
-    unsigned int cnt;
-    unsigned int addr;
-    unsigned int opc;
-    unsigned int req;
-    unsigned int data;
-
-    struct qemu_phy *devs[32];
-};
-
-static void
-mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
-    bus->devs[addr & 0x1f] = phy;
-}
-
-#ifdef USE_THIS_DEAD_CODE
-static void
-mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
-{
-    bus->devs[addr & 0x1f] = NULL;
-}
-#endif
-
-static void mdio_read_req(struct qemu_mdio *bus)
-{
-    struct qemu_phy *phy;
-
-    phy = bus->devs[bus->addr];
-    if (phy && phy->read) {
-        bus->data = phy->read(phy, bus->req);
-    } else {
-        bus->data = 0xffff;
-    }
-}
-
-static void mdio_write_req(struct qemu_mdio *bus)
-{
-    struct qemu_phy *phy;
-
-    phy = bus->devs[bus->addr];
-    if (phy && phy->write) {
-        phy->write(phy, bus->req, bus->data);
-    }
-}
-
-static void mdio_cycle(struct qemu_mdio *bus)
-{
-    bus->cnt++;
-
-    D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
-        bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
-#if 0
-    if (bus->mdc) {
-        printf("%d", bus->mdio);
-    }
-#endif
-    switch (bus->state) {
-    case PREAMBLE:
-        if (bus->mdc) {
-            if (bus->cnt >= (32 * 2) && !bus->mdio) {
-                bus->cnt = 0;
-                bus->state = SOF;
-                bus->data = 0;
-            }
-        }
-        break;
-    case SOF:
-        if (bus->mdc) {
-            if (bus->mdio != 1) {
-                printf("WARNING: no SOF\n");
-            }
-            if (bus->cnt == 1*2) {
-                bus->cnt = 0;
-                bus->opc = 0;
-                bus->state = OPC;
-            }
-        }
-        break;
-    case OPC:
-        if (bus->mdc) {
-            bus->opc <<= 1;
-            bus->opc |= bus->mdio & 1;
-            if (bus->cnt == 2*2) {
-                bus->cnt = 0;
-                bus->addr = 0;
-                bus->state = ADDR;
-            }
-        }
-        break;
-    case ADDR:
-        if (bus->mdc) {
-            bus->addr <<= 1;
-            bus->addr |= bus->mdio & 1;
-
-            if (bus->cnt == 5*2) {
-                bus->cnt = 0;
-                bus->req = 0;
-                bus->state = REQ;
-            }
-        }
-        break;
-    case REQ:
-        if (bus->mdc) {
-            bus->req <<= 1;
-            bus->req |= bus->mdio & 1;
-            if (bus->cnt == 5*2) {
-                bus->cnt = 0;
-                bus->state = TURNAROUND;
-            }
-        }
-        break;
-    case TURNAROUND:
-        if (bus->mdc && bus->cnt == 2*2) {
-            bus->mdio = 0;
-            bus->cnt = 0;
-
-            if (bus->opc == 2) {
-                bus->drive = 1;
-                mdio_read_req(bus);
-                bus->mdio = bus->data & 1;
-            }
-            bus->state = DATA;
-        }
-        break;
-    case DATA:
-        if (!bus->mdc) {
-            if (bus->drive) {
-                bus->mdio = !!(bus->data & (1 << 15));
-                bus->data <<= 1;
-            }
-        } else {
-            if (!bus->drive) {
-                bus->data <<= 1;
-                bus->data |= bus->mdio;
-            }
-            if (bus->cnt == 16 * 2) {
-                bus->cnt = 0;
-                bus->state = PREAMBLE;
-                if (!bus->drive) {
-                    mdio_write_req(bus);
-                }
-                bus->drive = 0;
-            }
-        }
-        break;
-    default:
-        break;
-    }
-}
-
-/* ETRAX-FS Ethernet MAC block starts here.  */
-
-#define RW_MA0_LO      0x00
-#define RW_MA0_HI      0x01
-#define RW_MA1_LO      0x02
-#define RW_MA1_HI      0x03
-#define RW_GA_LO      0x04
-#define RW_GA_HI      0x05
-#define RW_GEN_CTRL      0x06
-#define RW_REC_CTRL      0x07
-#define RW_TR_CTRL      0x08
-#define RW_CLR_ERR      0x09
-#define RW_MGM_CTRL      0x0a
-#define R_STAT          0x0b
-#define FS_ETH_MAX_REGS      0x17
-
-struct fs_eth
-{
-    SysBusDevice busdev;
-    MemoryRegion mmio;
-    NICState *nic;
-    NICConf conf;
-
-    /* Two addrs in the filter.  */
-    uint8_t macaddr[2][6];
-    uint32_t regs[FS_ETH_MAX_REGS];
-
-    union {
-        void *vdma_out;
-        struct etraxfs_dma_client *dma_out;
-    };
-    union {
-        void *vdma_in;
-        struct etraxfs_dma_client *dma_in;
-    };
-
-    /* MDIO bus.  */
-    struct qemu_mdio mdio_bus;
-    unsigned int phyaddr;
-    int duplex_mismatch;
-
-    /* PHY.     */
-    struct qemu_phy phy;
-};
-
-static void eth_validate_duplex(struct fs_eth *eth)
-{
-    struct qemu_phy *phy;
-    unsigned int phy_duplex;
-    unsigned int mac_duplex;
-    int new_mm = 0;
-
-    phy = eth->mdio_bus.devs[eth->phyaddr];
-    phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
-    mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
-
-    if (mac_duplex != phy_duplex) {
-        new_mm = 1;
-    }
-
-    if (eth->regs[RW_GEN_CTRL] & 1) {
-        if (new_mm != eth->duplex_mismatch) {
-            if (new_mm) {
-                printf("HW: WARNING ETH duplex mismatch MAC=%d PHY=%d\n",
-                       mac_duplex, phy_duplex);
-            } else {
-                printf("HW: ETH duplex ok.\n");
-            }
-        }
-        eth->duplex_mismatch = new_mm;
-    }
-}
-
-static uint64_t
-eth_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    struct fs_eth *eth = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-
-    switch (addr) {
-    case R_STAT:
-        r = eth->mdio_bus.mdio & 1;
-        break;
-    default:
-        r = eth->regs[addr];
-        D(printf("%s %x\n", __func__, addr * 4));
-        break;
-    }
-    return r;
-}
-
-static void eth_update_ma(struct fs_eth *eth, int ma)
-{
-    int reg;
-    int i = 0;
-
-    ma &= 1;
-
-    reg = RW_MA0_LO;
-    if (ma) {
-        reg = RW_MA1_LO;
-    }
-
-    eth->macaddr[ma][i++] = eth->regs[reg];
-    eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
-    eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
-    eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
-    eth->macaddr[ma][i++] = eth->regs[reg + 1];
-    eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8;
-
-    D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
-             eth->macaddr[ma][0], eth->macaddr[ma][1],
-             eth->macaddr[ma][2], eth->macaddr[ma][3],
-             eth->macaddr[ma][4], eth->macaddr[ma][5]));
-}
-
-static void
-eth_write(void *opaque, hwaddr addr,
-          uint64_t val64, unsigned int size)
-{
-    struct fs_eth *eth = opaque;
-    uint32_t value = val64;
-
-    addr >>= 2;
-    switch (addr) {
-    case RW_MA0_LO:
-    case RW_MA0_HI:
-        eth->regs[addr] = value;
-        eth_update_ma(eth, 0);
-        break;
-    case RW_MA1_LO:
-    case RW_MA1_HI:
-        eth->regs[addr] = value;
-        eth_update_ma(eth, 1);
-        break;
-
-    case RW_MGM_CTRL:
-        /* Attach an MDIO/PHY abstraction.  */
-        if (value & 2) {
-            eth->mdio_bus.mdio = value & 1;
-        }
-        if (eth->mdio_bus.mdc != (value & 4)) {
-            mdio_cycle(&eth->mdio_bus);
-            eth_validate_duplex(eth);
-        }
-        eth->mdio_bus.mdc = !!(value & 4);
-        eth->regs[addr] = value;
-        break;
-
-    case RW_REC_CTRL:
-        eth->regs[addr] = value;
-        eth_validate_duplex(eth);
-        break;
-
-    default:
-        eth->regs[addr] = value;
-        D(printf("%s %x %x\n", __func__, addr, value));
-        break;
-    }
-}
-
-/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
-   filter dropping group addresses we have not joined.    The filter has 64
-   bits (m). The has function is a simple nible xor of the group addr.    */
-static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
-{
-    unsigned int hsh;
-    int m_individual = eth->regs[RW_REC_CTRL] & 4;
-    int match;
-
-    /* First bit on the wire of a MAC address signals multicast or
-       physical address.  */
-    if (!m_individual && !(sa[0] & 1)) {
-        return 0;
-    }
-
-    /* Calculate the hash index for the GA registers. */
-    hsh = 0;
-    hsh ^= (*sa) & 0x3f;
-    hsh ^= ((*sa) >> 6) & 0x03;
-    ++sa;
-    hsh ^= ((*sa) << 2) & 0x03c;
-    hsh ^= ((*sa) >> 4) & 0xf;
-    ++sa;
-    hsh ^= ((*sa) << 4) & 0x30;
-    hsh ^= ((*sa) >> 2) & 0x3f;
-    ++sa;
-    hsh ^= (*sa) & 0x3f;
-    hsh ^= ((*sa) >> 6) & 0x03;
-    ++sa;
-    hsh ^= ((*sa) << 2) & 0x03c;
-    hsh ^= ((*sa) >> 4) & 0xf;
-    ++sa;
-    hsh ^= ((*sa) << 4) & 0x30;
-    hsh ^= ((*sa) >> 2) & 0x3f;
-
-    hsh &= 63;
-    if (hsh > 31) {
-        match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
-    } else {
-        match = eth->regs[RW_GA_LO] & (1 << hsh);
-    }
-    D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
-             eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
-    return match;
-}
-
-static int eth_can_receive(NetClientState *nc)
-{
-    return 1;
-}
-
-static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-    struct fs_eth *eth = qemu_get_nic_opaque(nc);
-    int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
-    int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
-    int r_bcast = eth->regs[RW_REC_CTRL] & 8;
-
-    if (size < 12) {
-        return -1;
-    }
-
-    D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
-         buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
-         use_ma0, use_ma1, r_bcast));
-
-    /* Does the frame get through the address filters?  */
-    if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
-        && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
-        && (!r_bcast || memcmp(buf, sa_bcast, 6))
-        && !eth_match_groupaddr(eth, buf)) {
-        return size;
-    }
-
-    /* FIXME: Find another way to pass on the fake csum.  */
-    etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
-
-        return size;
-}
-
-static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop)
-{
-    struct fs_eth *eth = opaque;
-
-    D(printf("%s buf=%p len=%d\n", __func__, buf, len));
-    qemu_send_packet(qemu_get_queue(eth->nic), buf, len);
-    return len;
-}
-
-static void eth_set_link(NetClientState *nc)
-{
-    struct fs_eth *eth = qemu_get_nic_opaque(nc);
-    D(printf("%s %d\n", __func__, nc->link_down));
-    eth->phy.link = !nc->link_down;
-}
-
-static const MemoryRegionOps eth_ops = {
-    .read = eth_read,
-    .write = eth_write,
-    .endianness = DEVICE_LITTLE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static void eth_cleanup(NetClientState *nc)
-{
-    struct fs_eth *eth = qemu_get_nic_opaque(nc);
-
-    /* Disconnect the client.  */
-    eth->dma_out->client.push = NULL;
-    eth->dma_out->client.opaque = NULL;
-    eth->dma_in->client.opaque = NULL;
-    eth->dma_in->client.pull = NULL;
-        g_free(eth);
-}
-
-static NetClientInfo net_etraxfs_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = eth_can_receive,
-    .receive = eth_receive,
-    .cleanup = eth_cleanup,
-    .link_status_changed = eth_set_link,
-};
-
-static int fs_eth_init(SysBusDevice *dev)
-{
-    struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev);
-
-    if (!s->dma_out || !s->dma_in) {
-        hw_error("Unconnected ETRAX-FS Ethernet MAC.\n");
-    }
-
-    s->dma_out->client.push = eth_tx_push;
-    s->dma_out->client.opaque = s;
-    s->dma_in->client.opaque = s;
-    s->dma_in->client.pull = NULL;
-
-    memory_region_init_io(&s->mmio, &eth_ops, s, "etraxfs-eth", 0x5c);
-    sysbus_init_mmio(dev, &s->mmio);
-
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-    s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
-                          object_get_typename(OBJECT(s)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
-
-    tdk_init(&s->phy);
-    mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
-    return 0;
-}
-
-static Property etraxfs_eth_properties[] = {
-    DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1),
-    DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out),
-    DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in),
-    DEFINE_NIC_PROPERTIES(struct fs_eth, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void etraxfs_eth_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = fs_eth_init;
-    dc->props = etraxfs_eth_properties;
-}
-
-static const TypeInfo etraxfs_eth_info = {
-    .name          = "etraxfs-eth",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(struct fs_eth),
-    .class_init    = etraxfs_eth_class_init,
-};
-
-static void etraxfs_eth_register_types(void)
-{
-    type_register_static(&etraxfs_eth_info);
-}
-
-type_init(etraxfs_eth_register_types)
diff --git a/hw/lance.c b/hw/lance.c
deleted file mode 100644 (file)
index 0f4e808..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * QEMU AMD PC-Net II (Am79C970A) emulation
- *
- * 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.
- */
-
-/* This software was written to be compatible with the specification:
- * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
- * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
- */
-
-/*
- * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also
- * produced as NCR89C100. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
- * and
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
- */
-
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include "qemu/timer.h"
-#include "qemu/sockets.h"
-#include "hw/sparc/sun4m.h"
-#include "hw/pcnet.h"
-#include "trace.h"
-
-typedef struct {
-    SysBusDevice busdev;
-    PCNetState state;
-} SysBusPCNetState;
-
-static void parent_lance_reset(void *opaque, int irq, int level)
-{
-    SysBusPCNetState *d = opaque;
-    if (level)
-        pcnet_h_reset(&d->state);
-}
-
-static void lance_mem_write(void *opaque, hwaddr addr,
-                            uint64_t val, unsigned size)
-{
-    SysBusPCNetState *d = opaque;
-
-    trace_lance_mem_writew(addr, val & 0xffff);
-    pcnet_ioport_writew(&d->state, addr, val & 0xffff);
-}
-
-static uint64_t lance_mem_read(void *opaque, hwaddr addr,
-                               unsigned size)
-{
-    SysBusPCNetState *d = opaque;
-    uint32_t val;
-
-    val = pcnet_ioport_readw(&d->state, addr);
-    trace_lance_mem_readw(addr, val & 0xffff);
-    return val & 0xffff;
-}
-
-static const MemoryRegionOps lance_mem_ops = {
-    .read = lance_mem_read,
-    .write = lance_mem_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 2,
-        .max_access_size = 2,
-    },
-};
-
-static void lance_cleanup(NetClientState *nc)
-{
-    PCNetState *d = qemu_get_nic_opaque(nc);
-
-    pcnet_common_cleanup(d);
-}
-
-static NetClientInfo net_lance_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = pcnet_can_receive,
-    .receive = pcnet_receive,
-    .link_status_changed = pcnet_set_link_status,
-    .cleanup = lance_cleanup,
-};
-
-static const VMStateDescription vmstate_lance = {
-    .name = "pcnet",
-    .version_id = 3,
-    .minimum_version_id = 2,
-    .minimum_version_id_old = 2,
-    .fields      = (VMStateField []) {
-        VMSTATE_STRUCT(state, SysBusPCNetState, 0, vmstate_pcnet, PCNetState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static int lance_init(SysBusDevice *dev)
-{
-    SysBusPCNetState *d = FROM_SYSBUS(SysBusPCNetState, dev);
-    PCNetState *s = &d->state;
-
-    memory_region_init_io(&s->mmio, &lance_mem_ops, d, "lance-mmio", 4);
-
-    qdev_init_gpio_in(&dev->qdev, parent_lance_reset, 1);
-
-    sysbus_init_mmio(dev, &s->mmio);
-
-    sysbus_init_irq(dev, &s->irq);
-
-    s->phys_mem_read = ledma_memory_read;
-    s->phys_mem_write = ledma_memory_write;
-    return pcnet_common_init(&dev->qdev, s, &net_lance_info);
-}
-
-static void lance_reset(DeviceState *dev)
-{
-    SysBusPCNetState *d = DO_UPCAST(SysBusPCNetState, busdev.qdev, dev);
-
-    pcnet_h_reset(&d->state);
-}
-
-static Property lance_properties[] = {
-    DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque),
-    DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void lance_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = lance_init;
-    dc->fw_name = "ethernet";
-    dc->reset = lance_reset;
-    dc->vmsd = &vmstate_lance;
-    dc->props = lance_properties;
-}
-
-static const TypeInfo lance_info = {
-    .name          = "lance",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(SysBusPCNetState),
-    .class_init    = lance_class_init,
-};
-
-static void lance_register_types(void)
-{
-    type_register_static(&lance_info);
-}
-
-type_init(lance_register_types)
index 68ca90a3e2b491f2a25b550d664ef7cd36252442..d72756c8778ef0b2d887f4f080c0eb8cd770f6e0 100644 (file)
@@ -7,7 +7,6 @@ obj-y += lm32_sys.o
 obj-y += milkymist-ac97.o
 obj-y += milkymist-hpdmc.o
 obj-y += milkymist-memcard.o
-obj-y += milkymist-minimac2.o
 obj-y += milkymist-pfpu.o
 obj-y += milkymist-softusb.o
 obj-y += milkymist-sysctl.o
index ede32a7c4ef00bd1a0a0a0ae416f640f25270cf5..ebbe0038042f5a3cd59d5fb855cf149922237f96 100644 (file)
@@ -1,4 +1,4 @@
-obj-y = mcf_uart.o mcf_fec.o
+obj-y = mcf_uart.o
 
 obj-y := $(addprefix ../,$(obj-y))
 
diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c
deleted file mode 100644 (file)
index 9b68052..0000000
+++ /dev/null
@@ -1,480 +0,0 @@
-/*
- * ColdFire Fast Ethernet Controller emulation.
- *
- * Copyright (c) 2007 CodeSourcery.
- *
- * This code is licensed under the GPL
- */
-#include "hw/hw.h"
-#include "net/net.h"
-#include "hw/m68k/mcf.h"
-/* For crc32 */
-#include <zlib.h>
-#include "exec/address-spaces.h"
-
-//#define DEBUG_FEC 1
-
-#ifdef DEBUG_FEC
-#define DPRINTF(fmt, ...) \
-do { printf("mcf_fec: " fmt , ## __VA_ARGS__); } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#endif
-
-#define FEC_MAX_FRAME_SIZE 2032
-
-typedef struct {
-    MemoryRegion *sysmem;
-    MemoryRegion iomem;
-    qemu_irq *irq;
-    NICState *nic;
-    NICConf conf;
-    uint32_t irq_state;
-    uint32_t eir;
-    uint32_t eimr;
-    int rx_enabled;
-    uint32_t rx_descriptor;
-    uint32_t tx_descriptor;
-    uint32_t ecr;
-    uint32_t mmfr;
-    uint32_t mscr;
-    uint32_t rcr;
-    uint32_t tcr;
-    uint32_t tfwr;
-    uint32_t rfsr;
-    uint32_t erdsr;
-    uint32_t etdsr;
-    uint32_t emrbr;
-} mcf_fec_state;
-
-#define FEC_INT_HB   0x80000000
-#define FEC_INT_BABR 0x40000000
-#define FEC_INT_BABT 0x20000000
-#define FEC_INT_GRA  0x10000000
-#define FEC_INT_TXF  0x08000000
-#define FEC_INT_TXB  0x04000000
-#define FEC_INT_RXF  0x02000000
-#define FEC_INT_RXB  0x01000000
-#define FEC_INT_MII  0x00800000
-#define FEC_INT_EB   0x00400000
-#define FEC_INT_LC   0x00200000
-#define FEC_INT_RL   0x00100000
-#define FEC_INT_UN   0x00080000
-
-#define FEC_EN      2
-#define FEC_RESET   1
-
-/* Map interrupt flags onto IRQ lines.  */
-#define FEC_NUM_IRQ 13
-static const uint32_t mcf_fec_irq_map[FEC_NUM_IRQ] = {
-    FEC_INT_TXF,
-    FEC_INT_TXB,
-    FEC_INT_UN,
-    FEC_INT_RL,
-    FEC_INT_RXF,
-    FEC_INT_RXB,
-    FEC_INT_MII,
-    FEC_INT_LC,
-    FEC_INT_HB,
-    FEC_INT_GRA,
-    FEC_INT_EB,
-    FEC_INT_BABT,
-    FEC_INT_BABR
-};
-
-/* Buffer Descriptor.  */
-typedef struct {
-    uint16_t flags;
-    uint16_t length;
-    uint32_t data;
-} mcf_fec_bd;
-
-#define FEC_BD_R    0x8000
-#define FEC_BD_E    0x8000
-#define FEC_BD_O1   0x4000
-#define FEC_BD_W    0x2000
-#define FEC_BD_O2   0x1000
-#define FEC_BD_L    0x0800
-#define FEC_BD_TC   0x0400
-#define FEC_BD_ABC  0x0200
-#define FEC_BD_M    0x0100
-#define FEC_BD_BC   0x0080
-#define FEC_BD_MC   0x0040
-#define FEC_BD_LG   0x0020
-#define FEC_BD_NO   0x0010
-#define FEC_BD_CR   0x0004
-#define FEC_BD_OV   0x0002
-#define FEC_BD_TR   0x0001
-
-static void mcf_fec_read_bd(mcf_fec_bd *bd, uint32_t addr)
-{
-    cpu_physical_memory_read(addr, (uint8_t *)bd, sizeof(*bd));
-    be16_to_cpus(&bd->flags);
-    be16_to_cpus(&bd->length);
-    be32_to_cpus(&bd->data);
-}
-
-static void mcf_fec_write_bd(mcf_fec_bd *bd, uint32_t addr)
-{
-    mcf_fec_bd tmp;
-    tmp.flags = cpu_to_be16(bd->flags);
-    tmp.length = cpu_to_be16(bd->length);
-    tmp.data = cpu_to_be32(bd->data);
-    cpu_physical_memory_write(addr, (uint8_t *)&tmp, sizeof(tmp));
-}
-
-static void mcf_fec_update(mcf_fec_state *s)
-{
-    uint32_t active;
-    uint32_t changed;
-    uint32_t mask;
-    int i;
-
-    active = s->eir & s->eimr;
-    changed = active ^s->irq_state;
-    for (i = 0; i < FEC_NUM_IRQ; i++) {
-        mask = mcf_fec_irq_map[i];
-        if (changed & mask) {
-            DPRINTF("IRQ %d = %d\n", i, (active & mask) != 0);
-            qemu_set_irq(s->irq[i], (active & mask) != 0);
-        }
-    }
-    s->irq_state = active;
-}
-
-static void mcf_fec_do_tx(mcf_fec_state *s)
-{
-    uint32_t addr;
-    mcf_fec_bd bd;
-    int frame_size;
-    int len;
-    uint8_t frame[FEC_MAX_FRAME_SIZE];
-    uint8_t *ptr;
-
-    DPRINTF("do_tx\n");
-    ptr = frame;
-    frame_size = 0;
-    addr = s->tx_descriptor;
-    while (1) {
-        mcf_fec_read_bd(&bd, addr);
-        DPRINTF("tx_bd %x flags %04x len %d data %08x\n",
-                addr, bd.flags, bd.length, bd.data);
-        if ((bd.flags & FEC_BD_R) == 0) {
-            /* Run out of descriptors to transmit.  */
-            break;
-        }
-        len = bd.length;
-        if (frame_size + len > FEC_MAX_FRAME_SIZE) {
-            len = FEC_MAX_FRAME_SIZE - frame_size;
-            s->eir |= FEC_INT_BABT;
-        }
-        cpu_physical_memory_read(bd.data, ptr, len);
-        ptr += len;
-        frame_size += len;
-        if (bd.flags & FEC_BD_L) {
-            /* Last buffer in frame.  */
-            DPRINTF("Sending packet\n");
-            qemu_send_packet(qemu_get_queue(s->nic), frame, len);
-            ptr = frame;
-            frame_size = 0;
-            s->eir |= FEC_INT_TXF;
-        }
-        s->eir |= FEC_INT_TXB;
-        bd.flags &= ~FEC_BD_R;
-        /* Write back the modified descriptor.  */
-        mcf_fec_write_bd(&bd, addr);
-        /* Advance to the next descriptor.  */
-        if ((bd.flags & FEC_BD_W) != 0) {
-            addr = s->etdsr;
-        } else {
-            addr += 8;
-        }
-    }
-    s->tx_descriptor = addr;
-}
-
-static void mcf_fec_enable_rx(mcf_fec_state *s)
-{
-    mcf_fec_bd bd;
-
-    mcf_fec_read_bd(&bd, s->rx_descriptor);
-    s->rx_enabled = ((bd.flags & FEC_BD_E) != 0);
-    if (!s->rx_enabled)
-        DPRINTF("RX buffer full\n");
-}
-
-static void mcf_fec_reset(mcf_fec_state *s)
-{
-    s->eir = 0;
-    s->eimr = 0;
-    s->rx_enabled = 0;
-    s->ecr = 0;
-    s->mscr = 0;
-    s->rcr = 0x05ee0001;
-    s->tcr = 0;
-    s->tfwr = 0;
-    s->rfsr = 0x500;
-}
-
-static uint64_t mcf_fec_read(void *opaque, hwaddr addr,
-                             unsigned size)
-{
-    mcf_fec_state *s = (mcf_fec_state *)opaque;
-    switch (addr & 0x3ff) {
-    case 0x004: return s->eir;
-    case 0x008: return s->eimr;
-    case 0x010: return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
-    case 0x014: return 0; /* TDAR */
-    case 0x024: return s->ecr;
-    case 0x040: return s->mmfr;
-    case 0x044: return s->mscr;
-    case 0x064: return 0; /* MIBC */
-    case 0x084: return s->rcr;
-    case 0x0c4: return s->tcr;
-    case 0x0e4: /* PALR */
-        return (s->conf.macaddr.a[0] << 24) | (s->conf.macaddr.a[1] << 16)
-              | (s->conf.macaddr.a[2] << 8) | s->conf.macaddr.a[3];
-        break;
-    case 0x0e8: /* PAUR */
-        return (s->conf.macaddr.a[4] << 24) | (s->conf.macaddr.a[5] << 16) | 0x8808;
-    case 0x0ec: return 0x10000; /* OPD */
-    case 0x118: return 0;
-    case 0x11c: return 0;
-    case 0x120: return 0;
-    case 0x124: return 0;
-    case 0x144: return s->tfwr;
-    case 0x14c: return 0x600;
-    case 0x150: return s->rfsr;
-    case 0x180: return s->erdsr;
-    case 0x184: return s->etdsr;
-    case 0x188: return s->emrbr;
-    default:
-        hw_error("mcf_fec_read: Bad address 0x%x\n", (int)addr);
-        return 0;
-    }
-}
-
-static void mcf_fec_write(void *opaque, hwaddr addr,
-                          uint64_t value, unsigned size)
-{
-    mcf_fec_state *s = (mcf_fec_state *)opaque;
-    switch (addr & 0x3ff) {
-    case 0x004:
-        s->eir &= ~value;
-        break;
-    case 0x008:
-        s->eimr = value;
-        break;
-    case 0x010: /* RDAR */
-        if ((s->ecr & FEC_EN) && !s->rx_enabled) {
-            DPRINTF("RX enable\n");
-            mcf_fec_enable_rx(s);
-        }
-        break;
-    case 0x014: /* TDAR */
-        if (s->ecr & FEC_EN) {
-            mcf_fec_do_tx(s);
-        }
-        break;
-    case 0x024:
-        s->ecr = value;
-        if (value & FEC_RESET) {
-            DPRINTF("Reset\n");
-            mcf_fec_reset(s);
-        }
-        if ((s->ecr & FEC_EN) == 0) {
-            s->rx_enabled = 0;
-        }
-        break;
-    case 0x040:
-        /* TODO: Implement MII.  */
-        s->mmfr = value;
-        break;
-    case 0x044:
-        s->mscr = value & 0xfe;
-        break;
-    case 0x064:
-        /* TODO: Implement MIB.  */
-        break;
-    case 0x084:
-        s->rcr = value & 0x07ff003f;
-        /* TODO: Implement LOOP mode.  */
-        break;
-    case 0x0c4: /* TCR */
-        /* We transmit immediately, so raise GRA immediately.  */
-        s->tcr = value;
-        if (value & 1)
-            s->eir |= FEC_INT_GRA;
-        break;
-    case 0x0e4: /* PALR */
-        s->conf.macaddr.a[0] = value >> 24;
-        s->conf.macaddr.a[1] = value >> 16;
-        s->conf.macaddr.a[2] = value >> 8;
-        s->conf.macaddr.a[3] = value;
-        break;
-    case 0x0e8: /* PAUR */
-        s->conf.macaddr.a[4] = value >> 24;
-        s->conf.macaddr.a[5] = value >> 16;
-        break;
-    case 0x0ec:
-        /* OPD */
-        break;
-    case 0x118:
-    case 0x11c:
-    case 0x120:
-    case 0x124:
-        /* TODO: implement MAC hash filtering.  */
-        break;
-    case 0x144:
-        s->tfwr = value & 3;
-        break;
-    case 0x14c:
-        /* FRBR writes ignored.  */
-        break;
-    case 0x150:
-        s->rfsr = (value & 0x3fc) | 0x400;
-        break;
-    case 0x180:
-        s->erdsr = value & ~3;
-        s->rx_descriptor = s->erdsr;
-        break;
-    case 0x184:
-        s->etdsr = value & ~3;
-        s->tx_descriptor = s->etdsr;
-        break;
-    case 0x188:
-        s->emrbr = value & 0x7f0;
-        break;
-    default:
-        hw_error("mcf_fec_write Bad address 0x%x\n", (int)addr);
-    }
-    mcf_fec_update(s);
-}
-
-static int mcf_fec_can_receive(NetClientState *nc)
-{
-    mcf_fec_state *s = qemu_get_nic_opaque(nc);
-    return s->rx_enabled;
-}
-
-static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    mcf_fec_state *s = qemu_get_nic_opaque(nc);
-    mcf_fec_bd bd;
-    uint32_t flags = 0;
-    uint32_t addr;
-    uint32_t crc;
-    uint32_t buf_addr;
-    uint8_t *crc_ptr;
-    unsigned int buf_len;
-
-    DPRINTF("do_rx len %d\n", size);
-    if (!s->rx_enabled) {
-        fprintf(stderr, "mcf_fec_receive: Unexpected packet\n");
-    }
-    /* 4 bytes for the CRC.  */
-    size += 4;
-    crc = cpu_to_be32(crc32(~0, buf, size));
-    crc_ptr = (uint8_t *)&crc;
-    /* Huge frames are truncted.  */
-    if (size > FEC_MAX_FRAME_SIZE) {
-        size = FEC_MAX_FRAME_SIZE;
-        flags |= FEC_BD_TR | FEC_BD_LG;
-    }
-    /* Frames larger than the user limit just set error flags.  */
-    if (size > (s->rcr >> 16)) {
-        flags |= FEC_BD_LG;
-    }
-    addr = s->rx_descriptor;
-    while (size > 0) {
-        mcf_fec_read_bd(&bd, addr);
-        if ((bd.flags & FEC_BD_E) == 0) {
-            /* No descriptors available.  Bail out.  */
-            /* FIXME: This is wrong.  We should probably either save the
-               remainder for when more RX buffers are available, or
-               flag an error.  */
-            fprintf(stderr, "mcf_fec: Lost end of frame\n");
-            break;
-        }
-        buf_len = (size <= s->emrbr) ? size: s->emrbr;
-        bd.length = buf_len;
-        size -= buf_len;
-        DPRINTF("rx_bd %x length %d\n", addr, bd.length);
-        /* The last 4 bytes are the CRC.  */
-        if (size < 4)
-            buf_len += size - 4;
-        buf_addr = bd.data;
-        cpu_physical_memory_write(buf_addr, buf, buf_len);
-        buf += buf_len;
-        if (size < 4) {
-            cpu_physical_memory_write(buf_addr + buf_len, crc_ptr, 4 - size);
-            crc_ptr += 4 - size;
-        }
-        bd.flags &= ~FEC_BD_E;
-        if (size == 0) {
-            /* Last buffer in frame.  */
-            bd.flags |= flags | FEC_BD_L;
-            DPRINTF("rx frame flags %04x\n", bd.flags);
-            s->eir |= FEC_INT_RXF;
-        } else {
-            s->eir |= FEC_INT_RXB;
-        }
-        mcf_fec_write_bd(&bd, addr);
-        /* Advance to the next descriptor.  */
-        if ((bd.flags & FEC_BD_W) != 0) {
-            addr = s->erdsr;
-        } else {
-            addr += 8;
-        }
-    }
-    s->rx_descriptor = addr;
-    mcf_fec_enable_rx(s);
-    mcf_fec_update(s);
-    return size;
-}
-
-static const MemoryRegionOps mcf_fec_ops = {
-    .read = mcf_fec_read,
-    .write = mcf_fec_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void mcf_fec_cleanup(NetClientState *nc)
-{
-    mcf_fec_state *s = qemu_get_nic_opaque(nc);
-
-    memory_region_del_subregion(s->sysmem, &s->iomem);
-    memory_region_destroy(&s->iomem);
-
-    g_free(s);
-}
-
-static NetClientInfo net_mcf_fec_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = mcf_fec_can_receive,
-    .receive = mcf_fec_receive,
-    .cleanup = mcf_fec_cleanup,
-};
-
-void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd,
-                  hwaddr base, qemu_irq *irq)
-{
-    mcf_fec_state *s;
-
-    qemu_check_nic_model(nd, "mcf_fec");
-
-    s = (mcf_fec_state *)g_malloc0(sizeof(mcf_fec_state));
-    s->sysmem = sysmem;
-    s->irq = irq;
-
-    memory_region_init_io(&s->iomem, &mcf_fec_ops, s, "fec", 0x400);
-    memory_region_add_subregion(sysmem, base, &s->iomem);
-
-    s->conf.macaddr = nd->macaddr;
-    s->conf.peers.ncs[0] = nd->netdev;
-
-    s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, nd->model, nd->name, s);
-
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-}
index 9e7f249941a7f6b6e003f61c9986851106ab765a..75f5ce6cfe1b87098056a986b6786194e525e795 100644 (file)
@@ -1,5 +1,4 @@
 obj-y += xilinx_spi.o
-obj-y += xilinx_ethlite.o
 
 obj-y := $(addprefix ../,$(obj-y))
 
diff --git a/hw/milkymist-minimac2.c b/hw/milkymist-minimac2.c
deleted file mode 100644 (file)
index 29618e8..0000000
+++ /dev/null
@@ -1,547 +0,0 @@
-/*
- *  QEMU model of the Milkymist minimac2 block.
- *
- *  Copyright (c) 2011 Michael Walle <michael@walle.cc>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>.
- *
- *
- * Specification available at:
- *   not available yet
- *
- */
-
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "trace.h"
-#include "net/net.h"
-#include "qemu/error-report.h"
-#include "hw/qdev-addr.h"
-
-#include <zlib.h>
-
-enum {
-    R_SETUP = 0,
-    R_MDIO,
-    R_STATE0,
-    R_COUNT0,
-    R_STATE1,
-    R_COUNT1,
-    R_TXCOUNT,
-    R_MAX
-};
-
-enum {
-    SETUP_PHY_RST = (1<<0),
-};
-
-enum {
-    MDIO_DO  = (1<<0),
-    MDIO_DI  = (1<<1),
-    MDIO_OE  = (1<<2),
-    MDIO_CLK = (1<<3),
-};
-
-enum {
-    STATE_EMPTY   = 0,
-    STATE_LOADED  = 1,
-    STATE_PENDING = 2,
-};
-
-enum {
-    MDIO_OP_WRITE = 1,
-    MDIO_OP_READ  = 2,
-};
-
-enum mdio_state {
-    MDIO_STATE_IDLE,
-    MDIO_STATE_READING,
-    MDIO_STATE_WRITING,
-};
-
-enum {
-    R_PHY_ID1  = 2,
-    R_PHY_ID2  = 3,
-    R_PHY_MAX  = 32
-};
-
-#define MINIMAC2_MTU 1530
-#define MINIMAC2_BUFFER_SIZE 2048
-
-struct MilkymistMinimac2MdioState {
-    int last_clk;
-    int count;
-    uint32_t data;
-    uint16_t data_out;
-    int state;
-
-    uint8_t phy_addr;
-    uint8_t reg_addr;
-};
-typedef struct MilkymistMinimac2MdioState MilkymistMinimac2MdioState;
-
-struct MilkymistMinimac2State {
-    SysBusDevice busdev;
-    NICState *nic;
-    NICConf conf;
-    char *phy_model;
-    MemoryRegion buffers;
-    MemoryRegion regs_region;
-
-    qemu_irq rx_irq;
-    qemu_irq tx_irq;
-
-    uint32_t regs[R_MAX];
-
-    MilkymistMinimac2MdioState mdio;
-
-    uint16_t phy_regs[R_PHY_MAX];
-
-    uint8_t *rx0_buf;
-    uint8_t *rx1_buf;
-    uint8_t *tx_buf;
-};
-typedef struct MilkymistMinimac2State MilkymistMinimac2State;
-
-static const uint8_t preamble_sfd[] = {
-        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5
-};
-
-static void minimac2_mdio_write_reg(MilkymistMinimac2State *s,
-        uint8_t phy_addr, uint8_t reg_addr, uint16_t value)
-{
-    trace_milkymist_minimac2_mdio_write(phy_addr, reg_addr, value);
-
-    /* nop */
-}
-
-static uint16_t minimac2_mdio_read_reg(MilkymistMinimac2State *s,
-        uint8_t phy_addr, uint8_t reg_addr)
-{
-    uint16_t r = s->phy_regs[reg_addr];
-
-    trace_milkymist_minimac2_mdio_read(phy_addr, reg_addr, r);
-
-    return r;
-}
-
-static void minimac2_update_mdio(MilkymistMinimac2State *s)
-{
-    MilkymistMinimac2MdioState *m = &s->mdio;
-
-    /* detect rising clk edge */
-    if (m->last_clk == 0 && (s->regs[R_MDIO] & MDIO_CLK)) {
-        /* shift data in */
-        int bit = ((s->regs[R_MDIO] & MDIO_DO)
-                   && (s->regs[R_MDIO] & MDIO_OE)) ? 1 : 0;
-        m->data = (m->data << 1) | bit;
-
-        /* check for sync */
-        if (m->data == 0xffffffff) {
-            m->count = 32;
-        }
-
-        if (m->count == 16) {
-            uint8_t start = (m->data >> 14) & 0x3;
-            uint8_t op = (m->data >> 12) & 0x3;
-            uint8_t ta = (m->data) & 0x3;
-
-            if (start == 1 && op == MDIO_OP_WRITE && ta == 2) {
-                m->state = MDIO_STATE_WRITING;
-            } else if (start == 1 && op == MDIO_OP_READ && (ta & 1) == 0) {
-                m->state = MDIO_STATE_READING;
-            } else {
-                m->state = MDIO_STATE_IDLE;
-            }
-
-            if (m->state != MDIO_STATE_IDLE) {
-                m->phy_addr = (m->data >> 7) & 0x1f;
-                m->reg_addr = (m->data >> 2) & 0x1f;
-            }
-
-            if (m->state == MDIO_STATE_READING) {
-                m->data_out = minimac2_mdio_read_reg(s, m->phy_addr,
-                        m->reg_addr);
-            }
-        }
-
-        if (m->count < 16 && m->state == MDIO_STATE_READING) {
-            int bit = (m->data_out & 0x8000) ? 1 : 0;
-            m->data_out <<= 1;
-
-            if (bit) {
-                s->regs[R_MDIO] |= MDIO_DI;
-            } else {
-                s->regs[R_MDIO] &= ~MDIO_DI;
-            }
-        }
-
-        if (m->count == 0 && m->state) {
-            if (m->state == MDIO_STATE_WRITING) {
-                uint16_t data = m->data & 0xffff;
-                minimac2_mdio_write_reg(s, m->phy_addr, m->reg_addr, data);
-            }
-            m->state = MDIO_STATE_IDLE;
-        }
-        m->count--;
-    }
-
-    m->last_clk = (s->regs[R_MDIO] & MDIO_CLK) ? 1 : 0;
-}
-
-static size_t assemble_frame(uint8_t *buf, size_t size,
-        const uint8_t *payload, size_t payload_size)
-{
-    uint32_t crc;
-
-    if (size < payload_size + 12) {
-        error_report("milkymist_minimac2: received too big ethernet frame");
-        return 0;
-    }
-
-    /* prepend preamble and sfd */
-    memcpy(buf, preamble_sfd, 8);
-
-    /* now copy the payload */
-    memcpy(buf + 8, payload, payload_size);
-
-    /* pad frame if needed */
-    if (payload_size < 60) {
-        memset(buf + payload_size + 8, 0, 60 - payload_size);
-        payload_size = 60;
-    }
-
-    /* append fcs */
-    crc = cpu_to_le32(crc32(0, buf + 8, payload_size));
-    memcpy(buf + payload_size + 8, &crc, 4);
-
-    return payload_size + 12;
-}
-
-static void minimac2_tx(MilkymistMinimac2State *s)
-{
-    uint32_t txcount = s->regs[R_TXCOUNT];
-    uint8_t *buf = s->tx_buf;
-
-    if (txcount < 64) {
-        error_report("milkymist_minimac2: ethernet frame too small (%u < %u)",
-                txcount, 64);
-        goto err;
-    }
-
-    if (txcount > MINIMAC2_MTU) {
-        error_report("milkymist_minimac2: MTU exceeded (%u > %u)",
-                txcount, MINIMAC2_MTU);
-        goto err;
-    }
-
-    if (memcmp(buf, preamble_sfd, 8) != 0) {
-        error_report("milkymist_minimac2: frame doesn't contain the preamble "
-                "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)",
-                buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
-        goto err;
-    }
-
-    trace_milkymist_minimac2_tx_frame(txcount - 12);
-
-    /* send packet, skipping preamble and sfd */
-    qemu_send_packet_raw(qemu_get_queue(s->nic), buf + 8, txcount - 12);
-
-    s->regs[R_TXCOUNT] = 0;
-
-err:
-    trace_milkymist_minimac2_pulse_irq_tx();
-    qemu_irq_pulse(s->tx_irq);
-}
-
-static void update_rx_interrupt(MilkymistMinimac2State *s)
-{
-    if (s->regs[R_STATE0] == STATE_PENDING
-            || s->regs[R_STATE1] == STATE_PENDING) {
-        trace_milkymist_minimac2_raise_irq_rx();
-        qemu_irq_raise(s->rx_irq);
-    } else {
-        trace_milkymist_minimac2_lower_irq_rx();
-        qemu_irq_lower(s->rx_irq);
-    }
-}
-
-static ssize_t minimac2_rx(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
-
-    uint32_t r_count;
-    uint32_t r_state;
-    uint8_t *rx_buf;
-
-    size_t frame_size;
-
-    trace_milkymist_minimac2_rx_frame(buf, size);
-
-    /* choose appropriate slot */
-    if (s->regs[R_STATE0] == STATE_LOADED) {
-        r_count = R_COUNT0;
-        r_state = R_STATE0;
-        rx_buf = s->rx0_buf;
-    } else if (s->regs[R_STATE1] == STATE_LOADED) {
-        r_count = R_COUNT1;
-        r_state = R_STATE1;
-        rx_buf = s->rx1_buf;
-    } else {
-        trace_milkymist_minimac2_drop_rx_frame(buf);
-        return size;
-    }
-
-    /* assemble frame */
-    frame_size = assemble_frame(rx_buf, MINIMAC2_BUFFER_SIZE, buf, size);
-
-    if (frame_size == 0) {
-        return size;
-    }
-
-    trace_milkymist_minimac2_rx_transfer(rx_buf, frame_size);
-
-    /* update slot */
-    s->regs[r_count] = frame_size;
-    s->regs[r_state] = STATE_PENDING;
-
-    update_rx_interrupt(s);
-
-    return size;
-}
-
-static uint64_t
-minimac2_read(void *opaque, hwaddr addr, unsigned size)
-{
-    MilkymistMinimac2State *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-    switch (addr) {
-    case R_SETUP:
-    case R_MDIO:
-    case R_STATE0:
-    case R_COUNT0:
-    case R_STATE1:
-    case R_COUNT1:
-    case R_TXCOUNT:
-        r = s->regs[addr];
-        break;
-
-    default:
-        error_report("milkymist_minimac2: read access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-
-    trace_milkymist_minimac2_memory_read(addr << 2, r);
-
-    return r;
-}
-
-static void
-minimac2_write(void *opaque, hwaddr addr, uint64_t value,
-               unsigned size)
-{
-    MilkymistMinimac2State *s = opaque;
-
-    trace_milkymist_minimac2_memory_read(addr, value);
-
-    addr >>= 2;
-    switch (addr) {
-    case R_MDIO:
-    {
-        /* MDIO_DI is read only */
-        int mdio_di = (s->regs[R_MDIO] & MDIO_DI);
-        s->regs[R_MDIO] = value;
-        if (mdio_di) {
-            s->regs[R_MDIO] |= mdio_di;
-        } else {
-            s->regs[R_MDIO] &= ~mdio_di;
-        }
-
-        minimac2_update_mdio(s);
-    } break;
-    case R_TXCOUNT:
-        s->regs[addr] = value;
-        if (value > 0) {
-            minimac2_tx(s);
-        }
-        break;
-    case R_STATE0:
-    case R_STATE1:
-        s->regs[addr] = value;
-        update_rx_interrupt(s);
-        break;
-    case R_SETUP:
-    case R_COUNT0:
-    case R_COUNT1:
-        s->regs[addr] = value;
-        break;
-
-    default:
-        error_report("milkymist_minimac2: write access to unknown register 0x"
-                TARGET_FMT_plx, addr << 2);
-        break;
-    }
-}
-
-static const MemoryRegionOps minimac2_ops = {
-    .read = minimac2_read,
-    .write = minimac2_write,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4,
-    },
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int minimac2_can_rx(NetClientState *nc)
-{
-    MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
-
-    if (s->regs[R_STATE0] == STATE_LOADED) {
-        return 1;
-    }
-    if (s->regs[R_STATE1] == STATE_LOADED) {
-        return 1;
-    }
-
-    return 0;
-}
-
-static void minimac2_cleanup(NetClientState *nc)
-{
-    MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
-
-    s->nic = NULL;
-}
-
-static void milkymist_minimac2_reset(DeviceState *d)
-{
-    MilkymistMinimac2State *s =
-            container_of(d, MilkymistMinimac2State, busdev.qdev);
-    int i;
-
-    for (i = 0; i < R_MAX; i++) {
-        s->regs[i] = 0;
-    }
-    for (i = 0; i < R_PHY_MAX; i++) {
-        s->phy_regs[i] = 0;
-    }
-
-    /* defaults */
-    s->phy_regs[R_PHY_ID1] = 0x0022; /* Micrel KSZ8001L */
-    s->phy_regs[R_PHY_ID2] = 0x161a;
-}
-
-static NetClientInfo net_milkymist_minimac2_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = minimac2_can_rx,
-    .receive = minimac2_rx,
-    .cleanup = minimac2_cleanup,
-};
-
-static int milkymist_minimac2_init(SysBusDevice *dev)
-{
-    MilkymistMinimac2State *s = FROM_SYSBUS(typeof(*s), dev);
-    size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE);
-
-    sysbus_init_irq(dev, &s->rx_irq);
-    sysbus_init_irq(dev, &s->tx_irq);
-
-    memory_region_init_io(&s->regs_region, &minimac2_ops, s,
-                          "milkymist-minimac2", R_MAX * 4);
-    sysbus_init_mmio(dev, &s->regs_region);
-
-    /* register buffers memory */
-    memory_region_init_ram(&s->buffers, "milkymist-minimac2.buffers",
-                           buffers_size);
-    vmstate_register_ram_global(&s->buffers);
-    s->rx0_buf = memory_region_get_ram_ptr(&s->buffers);
-    s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE;
-    s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE;
-
-    sysbus_init_mmio(dev, &s->buffers);
-
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-    s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf,
-                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
-    return 0;
-}
-
-static const VMStateDescription vmstate_milkymist_minimac2_mdio = {
-    .name = "milkymist-minimac2-mdio",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_INT32(last_clk, MilkymistMinimac2MdioState),
-        VMSTATE_INT32(count, MilkymistMinimac2MdioState),
-        VMSTATE_UINT32(data, MilkymistMinimac2MdioState),
-        VMSTATE_UINT16(data_out, MilkymistMinimac2MdioState),
-        VMSTATE_INT32(state, MilkymistMinimac2MdioState),
-        VMSTATE_UINT8(phy_addr, MilkymistMinimac2MdioState),
-        VMSTATE_UINT8(reg_addr, MilkymistMinimac2MdioState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static const VMStateDescription vmstate_milkymist_minimac2 = {
-    .name = "milkymist-minimac2",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .minimum_version_id_old = 1,
-    .fields      = (VMStateField[]) {
-        VMSTATE_UINT32_ARRAY(regs, MilkymistMinimac2State, R_MAX),
-        VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimac2State, R_PHY_MAX),
-        VMSTATE_STRUCT(mdio, MilkymistMinimac2State, 0,
-                vmstate_milkymist_minimac2_mdio, MilkymistMinimac2MdioState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static Property milkymist_minimac2_properties[] = {
-    DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
-    DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void milkymist_minimac2_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = milkymist_minimac2_init;
-    dc->reset = milkymist_minimac2_reset;
-    dc->vmsd = &vmstate_milkymist_minimac2;
-    dc->props = milkymist_minimac2_properties;
-}
-
-static const TypeInfo milkymist_minimac2_info = {
-    .name          = "milkymist-minimac2",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(MilkymistMinimac2State),
-    .class_init    = milkymist_minimac2_class_init,
-};
-
-static void milkymist_minimac2_register_types(void)
-{
-    type_register_static(&milkymist_minimac2_info);
-}
-
-type_init(milkymist_minimac2_register_types)
index 73217d80ae7c0142849b7a0fb55d55ce452d2cc6..951cca3a4b8c2cf31675d29b7e18cd5d032e3de5 100644 (file)
@@ -20,6 +20,14 @@ common-obj-$(CONFIG_MIPSNET) += mipsnet.o
 common-obj-$(CONFIG_XILINX_AXI) += xilinx_axienet.o
 
 common-obj-$(CONFIG_CADENCE) += cadence_gem.o
+common-obj-$(CONFIG_STELLARIS_ENET) += stellaris_enet.o
+common-obj-$(CONFIG_LANCE) += lance.o
+
+obj-$(CONFIG_ETRAXFS) += etraxfs_eth.o
+obj-$(CONFIG_COLDFIRE) += mcf_fec.o
+obj-$(CONFIG_MILKYMIST) += milkymist-minimac2.o
+obj-$(CONFIG_PSERIES) += spapr_llan.o
+obj-$(CONFIG_XILINX_ETHLITE) += xilinx_ethlite.o
 
 obj-$(CONFIG_VIRTIO) += virtio-net.o
 obj-y += vhost_net.o
diff --git a/hw/net/etraxfs_eth.c b/hw/net/etraxfs_eth.c
new file mode 100644 (file)
index 0000000..1039913
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * QEMU ETRAX Ethernet Controller.
+ *
+ * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
+ *
+ * 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 <stdio.h>
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include "hw/cris/etraxfs.h"
+
+#define D(x)
+
+/* Advertisement control register. */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+
+/*
+ * The MDIO extensions in the TDK PHY model were reversed engineered from the
+ * linux driver (PHYID and Diagnostics reg).
+ * TODO: Add friendly names for the register nums.
+ */
+struct qemu_phy
+{
+    uint32_t regs[32];
+
+    int link;
+
+    unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
+    void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data);
+};
+
+static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
+{
+    int regnum;
+    unsigned r = 0;
+
+    regnum = req & 0x1f;
+
+    switch (regnum) {
+    case 1:
+        if (!phy->link) {
+            break;
+        }
+        /* MR1.     */
+        /* Speeds and modes.  */
+        r |= (1 << 13) | (1 << 14);
+        r |= (1 << 11) | (1 << 12);
+        r |= (1 << 5); /* Autoneg complete.  */
+        r |= (1 << 3); /* Autoneg able.     */
+        r |= (1 << 2); /* link.     */
+        break;
+    case 5:
+        /* Link partner ability.
+           We are kind; always agree with whatever best mode
+           the guest advertises.  */
+        r = 1 << 14; /* Success.  */
+        /* Copy advertised modes.  */
+        r |= phy->regs[4] & (15 << 5);
+        /* Autoneg support.  */
+        r |= 1;
+        break;
+    case 18:
+    {
+        /* Diagnostics reg.  */
+        int duplex = 0;
+        int speed_100 = 0;
+
+        if (!phy->link) {
+            break;
+        }
+
+        /* Are we advertising 100 half or 100 duplex ? */
+        speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
+        speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
+
+        /* Are we advertising 10 duplex or 100 duplex ? */
+        duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
+        duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
+        r = (speed_100 << 10) | (duplex << 11);
+    }
+    break;
+
+    default:
+        r = phy->regs[regnum];
+        break;
+    }
+    D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
+    return r;
+}
+
+static void
+tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
+{
+    int regnum;
+
+    regnum = req & 0x1f;
+    D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
+    switch (regnum) {
+    default:
+        phy->regs[regnum] = data;
+        break;
+    }
+}
+
+static void
+tdk_init(struct qemu_phy *phy)
+{
+    phy->regs[0] = 0x3100;
+    /* PHY Id.  */
+    phy->regs[2] = 0x0300;
+    phy->regs[3] = 0xe400;
+    /* Autonegotiation advertisement reg.  */
+    phy->regs[4] = 0x01E1;
+    phy->link = 1;
+
+    phy->read = tdk_read;
+    phy->write = tdk_write;
+}
+
+struct qemu_mdio
+{
+    /* bus.     */
+    int mdc;
+    int mdio;
+
+    /* decoder.  */
+    enum {
+        PREAMBLE,
+        SOF,
+        OPC,
+        ADDR,
+        REQ,
+        TURNAROUND,
+        DATA
+    } state;
+    unsigned int drive;
+
+    unsigned int cnt;
+    unsigned int addr;
+    unsigned int opc;
+    unsigned int req;
+    unsigned int data;
+
+    struct qemu_phy *devs[32];
+};
+
+static void
+mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
+{
+    bus->devs[addr & 0x1f] = phy;
+}
+
+#ifdef USE_THIS_DEAD_CODE
+static void
+mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
+{
+    bus->devs[addr & 0x1f] = NULL;
+}
+#endif
+
+static void mdio_read_req(struct qemu_mdio *bus)
+{
+    struct qemu_phy *phy;
+
+    phy = bus->devs[bus->addr];
+    if (phy && phy->read) {
+        bus->data = phy->read(phy, bus->req);
+    } else {
+        bus->data = 0xffff;
+    }
+}
+
+static void mdio_write_req(struct qemu_mdio *bus)
+{
+    struct qemu_phy *phy;
+
+    phy = bus->devs[bus->addr];
+    if (phy && phy->write) {
+        phy->write(phy, bus->req, bus->data);
+    }
+}
+
+static void mdio_cycle(struct qemu_mdio *bus)
+{
+    bus->cnt++;
+
+    D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
+        bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
+#if 0
+    if (bus->mdc) {
+        printf("%d", bus->mdio);
+    }
+#endif
+    switch (bus->state) {
+    case PREAMBLE:
+        if (bus->mdc) {
+            if (bus->cnt >= (32 * 2) && !bus->mdio) {
+                bus->cnt = 0;
+                bus->state = SOF;
+                bus->data = 0;
+            }
+        }
+        break;
+    case SOF:
+        if (bus->mdc) {
+            if (bus->mdio != 1) {
+                printf("WARNING: no SOF\n");
+            }
+            if (bus->cnt == 1*2) {
+                bus->cnt = 0;
+                bus->opc = 0;
+                bus->state = OPC;
+            }
+        }
+        break;
+    case OPC:
+        if (bus->mdc) {
+            bus->opc <<= 1;
+            bus->opc |= bus->mdio & 1;
+            if (bus->cnt == 2*2) {
+                bus->cnt = 0;
+                bus->addr = 0;
+                bus->state = ADDR;
+            }
+        }
+        break;
+    case ADDR:
+        if (bus->mdc) {
+            bus->addr <<= 1;
+            bus->addr |= bus->mdio & 1;
+
+            if (bus->cnt == 5*2) {
+                bus->cnt = 0;
+                bus->req = 0;
+                bus->state = REQ;
+            }
+        }
+        break;
+    case REQ:
+        if (bus->mdc) {
+            bus->req <<= 1;
+            bus->req |= bus->mdio & 1;
+            if (bus->cnt == 5*2) {
+                bus->cnt = 0;
+                bus->state = TURNAROUND;
+            }
+        }
+        break;
+    case TURNAROUND:
+        if (bus->mdc && bus->cnt == 2*2) {
+            bus->mdio = 0;
+            bus->cnt = 0;
+
+            if (bus->opc == 2) {
+                bus->drive = 1;
+                mdio_read_req(bus);
+                bus->mdio = bus->data & 1;
+            }
+            bus->state = DATA;
+        }
+        break;
+    case DATA:
+        if (!bus->mdc) {
+            if (bus->drive) {
+                bus->mdio = !!(bus->data & (1 << 15));
+                bus->data <<= 1;
+            }
+        } else {
+            if (!bus->drive) {
+                bus->data <<= 1;
+                bus->data |= bus->mdio;
+            }
+            if (bus->cnt == 16 * 2) {
+                bus->cnt = 0;
+                bus->state = PREAMBLE;
+                if (!bus->drive) {
+                    mdio_write_req(bus);
+                }
+                bus->drive = 0;
+            }
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+/* ETRAX-FS Ethernet MAC block starts here.  */
+
+#define RW_MA0_LO      0x00
+#define RW_MA0_HI      0x01
+#define RW_MA1_LO      0x02
+#define RW_MA1_HI      0x03
+#define RW_GA_LO      0x04
+#define RW_GA_HI      0x05
+#define RW_GEN_CTRL      0x06
+#define RW_REC_CTRL      0x07
+#define RW_TR_CTRL      0x08
+#define RW_CLR_ERR      0x09
+#define RW_MGM_CTRL      0x0a
+#define R_STAT          0x0b
+#define FS_ETH_MAX_REGS      0x17
+
+struct fs_eth
+{
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+    NICState *nic;
+    NICConf conf;
+
+    /* Two addrs in the filter.  */
+    uint8_t macaddr[2][6];
+    uint32_t regs[FS_ETH_MAX_REGS];
+
+    union {
+        void *vdma_out;
+        struct etraxfs_dma_client *dma_out;
+    };
+    union {
+        void *vdma_in;
+        struct etraxfs_dma_client *dma_in;
+    };
+
+    /* MDIO bus.  */
+    struct qemu_mdio mdio_bus;
+    unsigned int phyaddr;
+    int duplex_mismatch;
+
+    /* PHY.     */
+    struct qemu_phy phy;
+};
+
+static void eth_validate_duplex(struct fs_eth *eth)
+{
+    struct qemu_phy *phy;
+    unsigned int phy_duplex;
+    unsigned int mac_duplex;
+    int new_mm = 0;
+
+    phy = eth->mdio_bus.devs[eth->phyaddr];
+    phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
+    mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
+
+    if (mac_duplex != phy_duplex) {
+        new_mm = 1;
+    }
+
+    if (eth->regs[RW_GEN_CTRL] & 1) {
+        if (new_mm != eth->duplex_mismatch) {
+            if (new_mm) {
+                printf("HW: WARNING ETH duplex mismatch MAC=%d PHY=%d\n",
+                       mac_duplex, phy_duplex);
+            } else {
+                printf("HW: ETH duplex ok.\n");
+            }
+        }
+        eth->duplex_mismatch = new_mm;
+    }
+}
+
+static uint64_t
+eth_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    struct fs_eth *eth = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+
+    switch (addr) {
+    case R_STAT:
+        r = eth->mdio_bus.mdio & 1;
+        break;
+    default:
+        r = eth->regs[addr];
+        D(printf("%s %x\n", __func__, addr * 4));
+        break;
+    }
+    return r;
+}
+
+static void eth_update_ma(struct fs_eth *eth, int ma)
+{
+    int reg;
+    int i = 0;
+
+    ma &= 1;
+
+    reg = RW_MA0_LO;
+    if (ma) {
+        reg = RW_MA1_LO;
+    }
+
+    eth->macaddr[ma][i++] = eth->regs[reg];
+    eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
+    eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
+    eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
+    eth->macaddr[ma][i++] = eth->regs[reg + 1];
+    eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8;
+
+    D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
+             eth->macaddr[ma][0], eth->macaddr[ma][1],
+             eth->macaddr[ma][2], eth->macaddr[ma][3],
+             eth->macaddr[ma][4], eth->macaddr[ma][5]));
+}
+
+static void
+eth_write(void *opaque, hwaddr addr,
+          uint64_t val64, unsigned int size)
+{
+    struct fs_eth *eth = opaque;
+    uint32_t value = val64;
+
+    addr >>= 2;
+    switch (addr) {
+    case RW_MA0_LO:
+    case RW_MA0_HI:
+        eth->regs[addr] = value;
+        eth_update_ma(eth, 0);
+        break;
+    case RW_MA1_LO:
+    case RW_MA1_HI:
+        eth->regs[addr] = value;
+        eth_update_ma(eth, 1);
+        break;
+
+    case RW_MGM_CTRL:
+        /* Attach an MDIO/PHY abstraction.  */
+        if (value & 2) {
+            eth->mdio_bus.mdio = value & 1;
+        }
+        if (eth->mdio_bus.mdc != (value & 4)) {
+            mdio_cycle(&eth->mdio_bus);
+            eth_validate_duplex(eth);
+        }
+        eth->mdio_bus.mdc = !!(value & 4);
+        eth->regs[addr] = value;
+        break;
+
+    case RW_REC_CTRL:
+        eth->regs[addr] = value;
+        eth_validate_duplex(eth);
+        break;
+
+    default:
+        eth->regs[addr] = value;
+        D(printf("%s %x %x\n", __func__, addr, value));
+        break;
+    }
+}
+
+/* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
+   filter dropping group addresses we have not joined.    The filter has 64
+   bits (m). The has function is a simple nible xor of the group addr.    */
+static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
+{
+    unsigned int hsh;
+    int m_individual = eth->regs[RW_REC_CTRL] & 4;
+    int match;
+
+    /* First bit on the wire of a MAC address signals multicast or
+       physical address.  */
+    if (!m_individual && !(sa[0] & 1)) {
+        return 0;
+    }
+
+    /* Calculate the hash index for the GA registers. */
+    hsh = 0;
+    hsh ^= (*sa) & 0x3f;
+    hsh ^= ((*sa) >> 6) & 0x03;
+    ++sa;
+    hsh ^= ((*sa) << 2) & 0x03c;
+    hsh ^= ((*sa) >> 4) & 0xf;
+    ++sa;
+    hsh ^= ((*sa) << 4) & 0x30;
+    hsh ^= ((*sa) >> 2) & 0x3f;
+    ++sa;
+    hsh ^= (*sa) & 0x3f;
+    hsh ^= ((*sa) >> 6) & 0x03;
+    ++sa;
+    hsh ^= ((*sa) << 2) & 0x03c;
+    hsh ^= ((*sa) >> 4) & 0xf;
+    ++sa;
+    hsh ^= ((*sa) << 4) & 0x30;
+    hsh ^= ((*sa) >> 2) & 0x3f;
+
+    hsh &= 63;
+    if (hsh > 31) {
+        match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
+    } else {
+        match = eth->regs[RW_GA_LO] & (1 << hsh);
+    }
+    D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
+             eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
+    return match;
+}
+
+static int eth_can_receive(NetClientState *nc)
+{
+    return 1;
+}
+
+static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+    struct fs_eth *eth = qemu_get_nic_opaque(nc);
+    int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
+    int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
+    int r_bcast = eth->regs[RW_REC_CTRL] & 8;
+
+    if (size < 12) {
+        return -1;
+    }
+
+    D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
+         buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
+         use_ma0, use_ma1, r_bcast));
+
+    /* Does the frame get through the address filters?  */
+    if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
+        && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
+        && (!r_bcast || memcmp(buf, sa_bcast, 6))
+        && !eth_match_groupaddr(eth, buf)) {
+        return size;
+    }
+
+    /* FIXME: Find another way to pass on the fake csum.  */
+    etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
+
+        return size;
+}
+
+static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop)
+{
+    struct fs_eth *eth = opaque;
+
+    D(printf("%s buf=%p len=%d\n", __func__, buf, len));
+    qemu_send_packet(qemu_get_queue(eth->nic), buf, len);
+    return len;
+}
+
+static void eth_set_link(NetClientState *nc)
+{
+    struct fs_eth *eth = qemu_get_nic_opaque(nc);
+    D(printf("%s %d\n", __func__, nc->link_down));
+    eth->phy.link = !nc->link_down;
+}
+
+static const MemoryRegionOps eth_ops = {
+    .read = eth_read,
+    .write = eth_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static void eth_cleanup(NetClientState *nc)
+{
+    struct fs_eth *eth = qemu_get_nic_opaque(nc);
+
+    /* Disconnect the client.  */
+    eth->dma_out->client.push = NULL;
+    eth->dma_out->client.opaque = NULL;
+    eth->dma_in->client.opaque = NULL;
+    eth->dma_in->client.pull = NULL;
+        g_free(eth);
+}
+
+static NetClientInfo net_etraxfs_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = eth_can_receive,
+    .receive = eth_receive,
+    .cleanup = eth_cleanup,
+    .link_status_changed = eth_set_link,
+};
+
+static int fs_eth_init(SysBusDevice *dev)
+{
+    struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev);
+
+    if (!s->dma_out || !s->dma_in) {
+        hw_error("Unconnected ETRAX-FS Ethernet MAC.\n");
+    }
+
+    s->dma_out->client.push = eth_tx_push;
+    s->dma_out->client.opaque = s;
+    s->dma_in->client.opaque = s;
+    s->dma_in->client.pull = NULL;
+
+    memory_region_init_io(&s->mmio, &eth_ops, s, "etraxfs-eth", 0x5c);
+    sysbus_init_mmio(dev, &s->mmio);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
+                          object_get_typename(OBJECT(s)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+
+
+    tdk_init(&s->phy);
+    mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
+    return 0;
+}
+
+static Property etraxfs_eth_properties[] = {
+    DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1),
+    DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out),
+    DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in),
+    DEFINE_NIC_PROPERTIES(struct fs_eth, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void etraxfs_eth_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = fs_eth_init;
+    dc->props = etraxfs_eth_properties;
+}
+
+static const TypeInfo etraxfs_eth_info = {
+    .name          = "etraxfs-eth",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct fs_eth),
+    .class_init    = etraxfs_eth_class_init,
+};
+
+static void etraxfs_eth_register_types(void)
+{
+    type_register_static(&etraxfs_eth_info);
+}
+
+type_init(etraxfs_eth_register_types)
diff --git a/hw/net/lance.c b/hw/net/lance.c
new file mode 100644 (file)
index 0000000..0f4e808
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * QEMU AMD PC-Net II (Am79C970A) emulation
+ *
+ * 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.
+ */
+
+/* This software was written to be compatible with the specification:
+ * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
+ * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
+ */
+
+/*
+ * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also
+ * produced as NCR89C100. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
+ * and
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
+ */
+
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include "qemu/timer.h"
+#include "qemu/sockets.h"
+#include "hw/sparc/sun4m.h"
+#include "hw/pcnet.h"
+#include "trace.h"
+
+typedef struct {
+    SysBusDevice busdev;
+    PCNetState state;
+} SysBusPCNetState;
+
+static void parent_lance_reset(void *opaque, int irq, int level)
+{
+    SysBusPCNetState *d = opaque;
+    if (level)
+        pcnet_h_reset(&d->state);
+}
+
+static void lance_mem_write(void *opaque, hwaddr addr,
+                            uint64_t val, unsigned size)
+{
+    SysBusPCNetState *d = opaque;
+
+    trace_lance_mem_writew(addr, val & 0xffff);
+    pcnet_ioport_writew(&d->state, addr, val & 0xffff);
+}
+
+static uint64_t lance_mem_read(void *opaque, hwaddr addr,
+                               unsigned size)
+{
+    SysBusPCNetState *d = opaque;
+    uint32_t val;
+
+    val = pcnet_ioport_readw(&d->state, addr);
+    trace_lance_mem_readw(addr, val & 0xffff);
+    return val & 0xffff;
+}
+
+static const MemoryRegionOps lance_mem_ops = {
+    .read = lance_mem_read,
+    .write = lance_mem_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 2,
+        .max_access_size = 2,
+    },
+};
+
+static void lance_cleanup(NetClientState *nc)
+{
+    PCNetState *d = qemu_get_nic_opaque(nc);
+
+    pcnet_common_cleanup(d);
+}
+
+static NetClientInfo net_lance_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = pcnet_can_receive,
+    .receive = pcnet_receive,
+    .link_status_changed = pcnet_set_link_status,
+    .cleanup = lance_cleanup,
+};
+
+static const VMStateDescription vmstate_lance = {
+    .name = "pcnet",
+    .version_id = 3,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields      = (VMStateField []) {
+        VMSTATE_STRUCT(state, SysBusPCNetState, 0, vmstate_pcnet, PCNetState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static int lance_init(SysBusDevice *dev)
+{
+    SysBusPCNetState *d = FROM_SYSBUS(SysBusPCNetState, dev);
+    PCNetState *s = &d->state;
+
+    memory_region_init_io(&s->mmio, &lance_mem_ops, d, "lance-mmio", 4);
+
+    qdev_init_gpio_in(&dev->qdev, parent_lance_reset, 1);
+
+    sysbus_init_mmio(dev, &s->mmio);
+
+    sysbus_init_irq(dev, &s->irq);
+
+    s->phys_mem_read = ledma_memory_read;
+    s->phys_mem_write = ledma_memory_write;
+    return pcnet_common_init(&dev->qdev, s, &net_lance_info);
+}
+
+static void lance_reset(DeviceState *dev)
+{
+    SysBusPCNetState *d = DO_UPCAST(SysBusPCNetState, busdev.qdev, dev);
+
+    pcnet_h_reset(&d->state);
+}
+
+static Property lance_properties[] = {
+    DEFINE_PROP_PTR("dma", SysBusPCNetState, state.dma_opaque),
+    DEFINE_NIC_PROPERTIES(SysBusPCNetState, state.conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void lance_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = lance_init;
+    dc->fw_name = "ethernet";
+    dc->reset = lance_reset;
+    dc->vmsd = &vmstate_lance;
+    dc->props = lance_properties;
+}
+
+static const TypeInfo lance_info = {
+    .name          = "lance",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(SysBusPCNetState),
+    .class_init    = lance_class_init,
+};
+
+static void lance_register_types(void)
+{
+    type_register_static(&lance_info);
+}
+
+type_init(lance_register_types)
diff --git a/hw/net/mcf_fec.c b/hw/net/mcf_fec.c
new file mode 100644 (file)
index 0000000..9b68052
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * ColdFire Fast Ethernet Controller emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licensed under the GPL
+ */
+#include "hw/hw.h"
+#include "net/net.h"
+#include "hw/m68k/mcf.h"
+/* For crc32 */
+#include <zlib.h>
+#include "exec/address-spaces.h"
+
+//#define DEBUG_FEC 1
+
+#ifdef DEBUG_FEC
+#define DPRINTF(fmt, ...) \
+do { printf("mcf_fec: " fmt , ## __VA_ARGS__); } while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#endif
+
+#define FEC_MAX_FRAME_SIZE 2032
+
+typedef struct {
+    MemoryRegion *sysmem;
+    MemoryRegion iomem;
+    qemu_irq *irq;
+    NICState *nic;
+    NICConf conf;
+    uint32_t irq_state;
+    uint32_t eir;
+    uint32_t eimr;
+    int rx_enabled;
+    uint32_t rx_descriptor;
+    uint32_t tx_descriptor;
+    uint32_t ecr;
+    uint32_t mmfr;
+    uint32_t mscr;
+    uint32_t rcr;
+    uint32_t tcr;
+    uint32_t tfwr;
+    uint32_t rfsr;
+    uint32_t erdsr;
+    uint32_t etdsr;
+    uint32_t emrbr;
+} mcf_fec_state;
+
+#define FEC_INT_HB   0x80000000
+#define FEC_INT_BABR 0x40000000
+#define FEC_INT_BABT 0x20000000
+#define FEC_INT_GRA  0x10000000
+#define FEC_INT_TXF  0x08000000
+#define FEC_INT_TXB  0x04000000
+#define FEC_INT_RXF  0x02000000
+#define FEC_INT_RXB  0x01000000
+#define FEC_INT_MII  0x00800000
+#define FEC_INT_EB   0x00400000
+#define FEC_INT_LC   0x00200000
+#define FEC_INT_RL   0x00100000
+#define FEC_INT_UN   0x00080000
+
+#define FEC_EN      2
+#define FEC_RESET   1
+
+/* Map interrupt flags onto IRQ lines.  */
+#define FEC_NUM_IRQ 13
+static const uint32_t mcf_fec_irq_map[FEC_NUM_IRQ] = {
+    FEC_INT_TXF,
+    FEC_INT_TXB,
+    FEC_INT_UN,
+    FEC_INT_RL,
+    FEC_INT_RXF,
+    FEC_INT_RXB,
+    FEC_INT_MII,
+    FEC_INT_LC,
+    FEC_INT_HB,
+    FEC_INT_GRA,
+    FEC_INT_EB,
+    FEC_INT_BABT,
+    FEC_INT_BABR
+};
+
+/* Buffer Descriptor.  */
+typedef struct {
+    uint16_t flags;
+    uint16_t length;
+    uint32_t data;
+} mcf_fec_bd;
+
+#define FEC_BD_R    0x8000
+#define FEC_BD_E    0x8000
+#define FEC_BD_O1   0x4000
+#define FEC_BD_W    0x2000
+#define FEC_BD_O2   0x1000
+#define FEC_BD_L    0x0800
+#define FEC_BD_TC   0x0400
+#define FEC_BD_ABC  0x0200
+#define FEC_BD_M    0x0100
+#define FEC_BD_BC   0x0080
+#define FEC_BD_MC   0x0040
+#define FEC_BD_LG   0x0020
+#define FEC_BD_NO   0x0010
+#define FEC_BD_CR   0x0004
+#define FEC_BD_OV   0x0002
+#define FEC_BD_TR   0x0001
+
+static void mcf_fec_read_bd(mcf_fec_bd *bd, uint32_t addr)
+{
+    cpu_physical_memory_read(addr, (uint8_t *)bd, sizeof(*bd));
+    be16_to_cpus(&bd->flags);
+    be16_to_cpus(&bd->length);
+    be32_to_cpus(&bd->data);
+}
+
+static void mcf_fec_write_bd(mcf_fec_bd *bd, uint32_t addr)
+{
+    mcf_fec_bd tmp;
+    tmp.flags = cpu_to_be16(bd->flags);
+    tmp.length = cpu_to_be16(bd->length);
+    tmp.data = cpu_to_be32(bd->data);
+    cpu_physical_memory_write(addr, (uint8_t *)&tmp, sizeof(tmp));
+}
+
+static void mcf_fec_update(mcf_fec_state *s)
+{
+    uint32_t active;
+    uint32_t changed;
+    uint32_t mask;
+    int i;
+
+    active = s->eir & s->eimr;
+    changed = active ^s->irq_state;
+    for (i = 0; i < FEC_NUM_IRQ; i++) {
+        mask = mcf_fec_irq_map[i];
+        if (changed & mask) {
+            DPRINTF("IRQ %d = %d\n", i, (active & mask) != 0);
+            qemu_set_irq(s->irq[i], (active & mask) != 0);
+        }
+    }
+    s->irq_state = active;
+}
+
+static void mcf_fec_do_tx(mcf_fec_state *s)
+{
+    uint32_t addr;
+    mcf_fec_bd bd;
+    int frame_size;
+    int len;
+    uint8_t frame[FEC_MAX_FRAME_SIZE];
+    uint8_t *ptr;
+
+    DPRINTF("do_tx\n");
+    ptr = frame;
+    frame_size = 0;
+    addr = s->tx_descriptor;
+    while (1) {
+        mcf_fec_read_bd(&bd, addr);
+        DPRINTF("tx_bd %x flags %04x len %d data %08x\n",
+                addr, bd.flags, bd.length, bd.data);
+        if ((bd.flags & FEC_BD_R) == 0) {
+            /* Run out of descriptors to transmit.  */
+            break;
+        }
+        len = bd.length;
+        if (frame_size + len > FEC_MAX_FRAME_SIZE) {
+            len = FEC_MAX_FRAME_SIZE - frame_size;
+            s->eir |= FEC_INT_BABT;
+        }
+        cpu_physical_memory_read(bd.data, ptr, len);
+        ptr += len;
+        frame_size += len;
+        if (bd.flags & FEC_BD_L) {
+            /* Last buffer in frame.  */
+            DPRINTF("Sending packet\n");
+            qemu_send_packet(qemu_get_queue(s->nic), frame, len);
+            ptr = frame;
+            frame_size = 0;
+            s->eir |= FEC_INT_TXF;
+        }
+        s->eir |= FEC_INT_TXB;
+        bd.flags &= ~FEC_BD_R;
+        /* Write back the modified descriptor.  */
+        mcf_fec_write_bd(&bd, addr);
+        /* Advance to the next descriptor.  */
+        if ((bd.flags & FEC_BD_W) != 0) {
+            addr = s->etdsr;
+        } else {
+            addr += 8;
+        }
+    }
+    s->tx_descriptor = addr;
+}
+
+static void mcf_fec_enable_rx(mcf_fec_state *s)
+{
+    mcf_fec_bd bd;
+
+    mcf_fec_read_bd(&bd, s->rx_descriptor);
+    s->rx_enabled = ((bd.flags & FEC_BD_E) != 0);
+    if (!s->rx_enabled)
+        DPRINTF("RX buffer full\n");
+}
+
+static void mcf_fec_reset(mcf_fec_state *s)
+{
+    s->eir = 0;
+    s->eimr = 0;
+    s->rx_enabled = 0;
+    s->ecr = 0;
+    s->mscr = 0;
+    s->rcr = 0x05ee0001;
+    s->tcr = 0;
+    s->tfwr = 0;
+    s->rfsr = 0x500;
+}
+
+static uint64_t mcf_fec_read(void *opaque, hwaddr addr,
+                             unsigned size)
+{
+    mcf_fec_state *s = (mcf_fec_state *)opaque;
+    switch (addr & 0x3ff) {
+    case 0x004: return s->eir;
+    case 0x008: return s->eimr;
+    case 0x010: return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
+    case 0x014: return 0; /* TDAR */
+    case 0x024: return s->ecr;
+    case 0x040: return s->mmfr;
+    case 0x044: return s->mscr;
+    case 0x064: return 0; /* MIBC */
+    case 0x084: return s->rcr;
+    case 0x0c4: return s->tcr;
+    case 0x0e4: /* PALR */
+        return (s->conf.macaddr.a[0] << 24) | (s->conf.macaddr.a[1] << 16)
+              | (s->conf.macaddr.a[2] << 8) | s->conf.macaddr.a[3];
+        break;
+    case 0x0e8: /* PAUR */
+        return (s->conf.macaddr.a[4] << 24) | (s->conf.macaddr.a[5] << 16) | 0x8808;
+    case 0x0ec: return 0x10000; /* OPD */
+    case 0x118: return 0;
+    case 0x11c: return 0;
+    case 0x120: return 0;
+    case 0x124: return 0;
+    case 0x144: return s->tfwr;
+    case 0x14c: return 0x600;
+    case 0x150: return s->rfsr;
+    case 0x180: return s->erdsr;
+    case 0x184: return s->etdsr;
+    case 0x188: return s->emrbr;
+    default:
+        hw_error("mcf_fec_read: Bad address 0x%x\n", (int)addr);
+        return 0;
+    }
+}
+
+static void mcf_fec_write(void *opaque, hwaddr addr,
+                          uint64_t value, unsigned size)
+{
+    mcf_fec_state *s = (mcf_fec_state *)opaque;
+    switch (addr & 0x3ff) {
+    case 0x004:
+        s->eir &= ~value;
+        break;
+    case 0x008:
+        s->eimr = value;
+        break;
+    case 0x010: /* RDAR */
+        if ((s->ecr & FEC_EN) && !s->rx_enabled) {
+            DPRINTF("RX enable\n");
+            mcf_fec_enable_rx(s);
+        }
+        break;
+    case 0x014: /* TDAR */
+        if (s->ecr & FEC_EN) {
+            mcf_fec_do_tx(s);
+        }
+        break;
+    case 0x024:
+        s->ecr = value;
+        if (value & FEC_RESET) {
+            DPRINTF("Reset\n");
+            mcf_fec_reset(s);
+        }
+        if ((s->ecr & FEC_EN) == 0) {
+            s->rx_enabled = 0;
+        }
+        break;
+    case 0x040:
+        /* TODO: Implement MII.  */
+        s->mmfr = value;
+        break;
+    case 0x044:
+        s->mscr = value & 0xfe;
+        break;
+    case 0x064:
+        /* TODO: Implement MIB.  */
+        break;
+    case 0x084:
+        s->rcr = value & 0x07ff003f;
+        /* TODO: Implement LOOP mode.  */
+        break;
+    case 0x0c4: /* TCR */
+        /* We transmit immediately, so raise GRA immediately.  */
+        s->tcr = value;
+        if (value & 1)
+            s->eir |= FEC_INT_GRA;
+        break;
+    case 0x0e4: /* PALR */
+        s->conf.macaddr.a[0] = value >> 24;
+        s->conf.macaddr.a[1] = value >> 16;
+        s->conf.macaddr.a[2] = value >> 8;
+        s->conf.macaddr.a[3] = value;
+        break;
+    case 0x0e8: /* PAUR */
+        s->conf.macaddr.a[4] = value >> 24;
+        s->conf.macaddr.a[5] = value >> 16;
+        break;
+    case 0x0ec:
+        /* OPD */
+        break;
+    case 0x118:
+    case 0x11c:
+    case 0x120:
+    case 0x124:
+        /* TODO: implement MAC hash filtering.  */
+        break;
+    case 0x144:
+        s->tfwr = value & 3;
+        break;
+    case 0x14c:
+        /* FRBR writes ignored.  */
+        break;
+    case 0x150:
+        s->rfsr = (value & 0x3fc) | 0x400;
+        break;
+    case 0x180:
+        s->erdsr = value & ~3;
+        s->rx_descriptor = s->erdsr;
+        break;
+    case 0x184:
+        s->etdsr = value & ~3;
+        s->tx_descriptor = s->etdsr;
+        break;
+    case 0x188:
+        s->emrbr = value & 0x7f0;
+        break;
+    default:
+        hw_error("mcf_fec_write Bad address 0x%x\n", (int)addr);
+    }
+    mcf_fec_update(s);
+}
+
+static int mcf_fec_can_receive(NetClientState *nc)
+{
+    mcf_fec_state *s = qemu_get_nic_opaque(nc);
+    return s->rx_enabled;
+}
+
+static ssize_t mcf_fec_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    mcf_fec_state *s = qemu_get_nic_opaque(nc);
+    mcf_fec_bd bd;
+    uint32_t flags = 0;
+    uint32_t addr;
+    uint32_t crc;
+    uint32_t buf_addr;
+    uint8_t *crc_ptr;
+    unsigned int buf_len;
+
+    DPRINTF("do_rx len %d\n", size);
+    if (!s->rx_enabled) {
+        fprintf(stderr, "mcf_fec_receive: Unexpected packet\n");
+    }
+    /* 4 bytes for the CRC.  */
+    size += 4;
+    crc = cpu_to_be32(crc32(~0, buf, size));
+    crc_ptr = (uint8_t *)&crc;
+    /* Huge frames are truncted.  */
+    if (size > FEC_MAX_FRAME_SIZE) {
+        size = FEC_MAX_FRAME_SIZE;
+        flags |= FEC_BD_TR | FEC_BD_LG;
+    }
+    /* Frames larger than the user limit just set error flags.  */
+    if (size > (s->rcr >> 16)) {
+        flags |= FEC_BD_LG;
+    }
+    addr = s->rx_descriptor;
+    while (size > 0) {
+        mcf_fec_read_bd(&bd, addr);
+        if ((bd.flags & FEC_BD_E) == 0) {
+            /* No descriptors available.  Bail out.  */
+            /* FIXME: This is wrong.  We should probably either save the
+               remainder for when more RX buffers are available, or
+               flag an error.  */
+            fprintf(stderr, "mcf_fec: Lost end of frame\n");
+            break;
+        }
+        buf_len = (size <= s->emrbr) ? size: s->emrbr;
+        bd.length = buf_len;
+        size -= buf_len;
+        DPRINTF("rx_bd %x length %d\n", addr, bd.length);
+        /* The last 4 bytes are the CRC.  */
+        if (size < 4)
+            buf_len += size - 4;
+        buf_addr = bd.data;
+        cpu_physical_memory_write(buf_addr, buf, buf_len);
+        buf += buf_len;
+        if (size < 4) {
+            cpu_physical_memory_write(buf_addr + buf_len, crc_ptr, 4 - size);
+            crc_ptr += 4 - size;
+        }
+        bd.flags &= ~FEC_BD_E;
+        if (size == 0) {
+            /* Last buffer in frame.  */
+            bd.flags |= flags | FEC_BD_L;
+            DPRINTF("rx frame flags %04x\n", bd.flags);
+            s->eir |= FEC_INT_RXF;
+        } else {
+            s->eir |= FEC_INT_RXB;
+        }
+        mcf_fec_write_bd(&bd, addr);
+        /* Advance to the next descriptor.  */
+        if ((bd.flags & FEC_BD_W) != 0) {
+            addr = s->erdsr;
+        } else {
+            addr += 8;
+        }
+    }
+    s->rx_descriptor = addr;
+    mcf_fec_enable_rx(s);
+    mcf_fec_update(s);
+    return size;
+}
+
+static const MemoryRegionOps mcf_fec_ops = {
+    .read = mcf_fec_read,
+    .write = mcf_fec_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void mcf_fec_cleanup(NetClientState *nc)
+{
+    mcf_fec_state *s = qemu_get_nic_opaque(nc);
+
+    memory_region_del_subregion(s->sysmem, &s->iomem);
+    memory_region_destroy(&s->iomem);
+
+    g_free(s);
+}
+
+static NetClientInfo net_mcf_fec_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = mcf_fec_can_receive,
+    .receive = mcf_fec_receive,
+    .cleanup = mcf_fec_cleanup,
+};
+
+void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd,
+                  hwaddr base, qemu_irq *irq)
+{
+    mcf_fec_state *s;
+
+    qemu_check_nic_model(nd, "mcf_fec");
+
+    s = (mcf_fec_state *)g_malloc0(sizeof(mcf_fec_state));
+    s->sysmem = sysmem;
+    s->irq = irq;
+
+    memory_region_init_io(&s->iomem, &mcf_fec_ops, s, "fec", 0x400);
+    memory_region_add_subregion(sysmem, base, &s->iomem);
+
+    s->conf.macaddr = nd->macaddr;
+    s->conf.peers.ncs[0] = nd->netdev;
+
+    s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, nd->model, nd->name, s);
+
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+}
diff --git a/hw/net/milkymist-minimac2.c b/hw/net/milkymist-minimac2.c
new file mode 100644 (file)
index 0000000..29618e8
--- /dev/null
@@ -0,0 +1,547 @@
+/*
+ *  QEMU model of the Milkymist minimac2 block.
+ *
+ *  Copyright (c) 2011 Michael Walle <michael@walle.cc>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   not available yet
+ *
+ */
+
+#include "hw/hw.h"
+#include "hw/sysbus.h"
+#include "trace.h"
+#include "net/net.h"
+#include "qemu/error-report.h"
+#include "hw/qdev-addr.h"
+
+#include <zlib.h>
+
+enum {
+    R_SETUP = 0,
+    R_MDIO,
+    R_STATE0,
+    R_COUNT0,
+    R_STATE1,
+    R_COUNT1,
+    R_TXCOUNT,
+    R_MAX
+};
+
+enum {
+    SETUP_PHY_RST = (1<<0),
+};
+
+enum {
+    MDIO_DO  = (1<<0),
+    MDIO_DI  = (1<<1),
+    MDIO_OE  = (1<<2),
+    MDIO_CLK = (1<<3),
+};
+
+enum {
+    STATE_EMPTY   = 0,
+    STATE_LOADED  = 1,
+    STATE_PENDING = 2,
+};
+
+enum {
+    MDIO_OP_WRITE = 1,
+    MDIO_OP_READ  = 2,
+};
+
+enum mdio_state {
+    MDIO_STATE_IDLE,
+    MDIO_STATE_READING,
+    MDIO_STATE_WRITING,
+};
+
+enum {
+    R_PHY_ID1  = 2,
+    R_PHY_ID2  = 3,
+    R_PHY_MAX  = 32
+};
+
+#define MINIMAC2_MTU 1530
+#define MINIMAC2_BUFFER_SIZE 2048
+
+struct MilkymistMinimac2MdioState {
+    int last_clk;
+    int count;
+    uint32_t data;
+    uint16_t data_out;
+    int state;
+
+    uint8_t phy_addr;
+    uint8_t reg_addr;
+};
+typedef struct MilkymistMinimac2MdioState MilkymistMinimac2MdioState;
+
+struct MilkymistMinimac2State {
+    SysBusDevice busdev;
+    NICState *nic;
+    NICConf conf;
+    char *phy_model;
+    MemoryRegion buffers;
+    MemoryRegion regs_region;
+
+    qemu_irq rx_irq;
+    qemu_irq tx_irq;
+
+    uint32_t regs[R_MAX];
+
+    MilkymistMinimac2MdioState mdio;
+
+    uint16_t phy_regs[R_PHY_MAX];
+
+    uint8_t *rx0_buf;
+    uint8_t *rx1_buf;
+    uint8_t *tx_buf;
+};
+typedef struct MilkymistMinimac2State MilkymistMinimac2State;
+
+static const uint8_t preamble_sfd[] = {
+        0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5
+};
+
+static void minimac2_mdio_write_reg(MilkymistMinimac2State *s,
+        uint8_t phy_addr, uint8_t reg_addr, uint16_t value)
+{
+    trace_milkymist_minimac2_mdio_write(phy_addr, reg_addr, value);
+
+    /* nop */
+}
+
+static uint16_t minimac2_mdio_read_reg(MilkymistMinimac2State *s,
+        uint8_t phy_addr, uint8_t reg_addr)
+{
+    uint16_t r = s->phy_regs[reg_addr];
+
+    trace_milkymist_minimac2_mdio_read(phy_addr, reg_addr, r);
+
+    return r;
+}
+
+static void minimac2_update_mdio(MilkymistMinimac2State *s)
+{
+    MilkymistMinimac2MdioState *m = &s->mdio;
+
+    /* detect rising clk edge */
+    if (m->last_clk == 0 && (s->regs[R_MDIO] & MDIO_CLK)) {
+        /* shift data in */
+        int bit = ((s->regs[R_MDIO] & MDIO_DO)
+                   && (s->regs[R_MDIO] & MDIO_OE)) ? 1 : 0;
+        m->data = (m->data << 1) | bit;
+
+        /* check for sync */
+        if (m->data == 0xffffffff) {
+            m->count = 32;
+        }
+
+        if (m->count == 16) {
+            uint8_t start = (m->data >> 14) & 0x3;
+            uint8_t op = (m->data >> 12) & 0x3;
+            uint8_t ta = (m->data) & 0x3;
+
+            if (start == 1 && op == MDIO_OP_WRITE && ta == 2) {
+                m->state = MDIO_STATE_WRITING;
+            } else if (start == 1 && op == MDIO_OP_READ && (ta & 1) == 0) {
+                m->state = MDIO_STATE_READING;
+            } else {
+                m->state = MDIO_STATE_IDLE;
+            }
+
+            if (m->state != MDIO_STATE_IDLE) {
+                m->phy_addr = (m->data >> 7) & 0x1f;
+                m->reg_addr = (m->data >> 2) & 0x1f;
+            }
+
+            if (m->state == MDIO_STATE_READING) {
+                m->data_out = minimac2_mdio_read_reg(s, m->phy_addr,
+                        m->reg_addr);
+            }
+        }
+
+        if (m->count < 16 && m->state == MDIO_STATE_READING) {
+            int bit = (m->data_out & 0x8000) ? 1 : 0;
+            m->data_out <<= 1;
+
+            if (bit) {
+                s->regs[R_MDIO] |= MDIO_DI;
+            } else {
+                s->regs[R_MDIO] &= ~MDIO_DI;
+            }
+        }
+
+        if (m->count == 0 && m->state) {
+            if (m->state == MDIO_STATE_WRITING) {
+                uint16_t data = m->data & 0xffff;
+                minimac2_mdio_write_reg(s, m->phy_addr, m->reg_addr, data);
+            }
+            m->state = MDIO_STATE_IDLE;
+        }
+        m->count--;
+    }
+
+    m->last_clk = (s->regs[R_MDIO] & MDIO_CLK) ? 1 : 0;
+}
+
+static size_t assemble_frame(uint8_t *buf, size_t size,
+        const uint8_t *payload, size_t payload_size)
+{
+    uint32_t crc;
+
+    if (size < payload_size + 12) {
+        error_report("milkymist_minimac2: received too big ethernet frame");
+        return 0;
+    }
+
+    /* prepend preamble and sfd */
+    memcpy(buf, preamble_sfd, 8);
+
+    /* now copy the payload */
+    memcpy(buf + 8, payload, payload_size);
+
+    /* pad frame if needed */
+    if (payload_size < 60) {
+        memset(buf + payload_size + 8, 0, 60 - payload_size);
+        payload_size = 60;
+    }
+
+    /* append fcs */
+    crc = cpu_to_le32(crc32(0, buf + 8, payload_size));
+    memcpy(buf + payload_size + 8, &crc, 4);
+
+    return payload_size + 12;
+}
+
+static void minimac2_tx(MilkymistMinimac2State *s)
+{
+    uint32_t txcount = s->regs[R_TXCOUNT];
+    uint8_t *buf = s->tx_buf;
+
+    if (txcount < 64) {
+        error_report("milkymist_minimac2: ethernet frame too small (%u < %u)",
+                txcount, 64);
+        goto err;
+    }
+
+    if (txcount > MINIMAC2_MTU) {
+        error_report("milkymist_minimac2: MTU exceeded (%u > %u)",
+                txcount, MINIMAC2_MTU);
+        goto err;
+    }
+
+    if (memcmp(buf, preamble_sfd, 8) != 0) {
+        error_report("milkymist_minimac2: frame doesn't contain the preamble "
+                "and/or the SFD (%02x %02x %02x %02x %02x %02x %02x %02x)",
+                buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
+        goto err;
+    }
+
+    trace_milkymist_minimac2_tx_frame(txcount - 12);
+
+    /* send packet, skipping preamble and sfd */
+    qemu_send_packet_raw(qemu_get_queue(s->nic), buf + 8, txcount - 12);
+
+    s->regs[R_TXCOUNT] = 0;
+
+err:
+    trace_milkymist_minimac2_pulse_irq_tx();
+    qemu_irq_pulse(s->tx_irq);
+}
+
+static void update_rx_interrupt(MilkymistMinimac2State *s)
+{
+    if (s->regs[R_STATE0] == STATE_PENDING
+            || s->regs[R_STATE1] == STATE_PENDING) {
+        trace_milkymist_minimac2_raise_irq_rx();
+        qemu_irq_raise(s->rx_irq);
+    } else {
+        trace_milkymist_minimac2_lower_irq_rx();
+        qemu_irq_lower(s->rx_irq);
+    }
+}
+
+static ssize_t minimac2_rx(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
+
+    uint32_t r_count;
+    uint32_t r_state;
+    uint8_t *rx_buf;
+
+    size_t frame_size;
+
+    trace_milkymist_minimac2_rx_frame(buf, size);
+
+    /* choose appropriate slot */
+    if (s->regs[R_STATE0] == STATE_LOADED) {
+        r_count = R_COUNT0;
+        r_state = R_STATE0;
+        rx_buf = s->rx0_buf;
+    } else if (s->regs[R_STATE1] == STATE_LOADED) {
+        r_count = R_COUNT1;
+        r_state = R_STATE1;
+        rx_buf = s->rx1_buf;
+    } else {
+        trace_milkymist_minimac2_drop_rx_frame(buf);
+        return size;
+    }
+
+    /* assemble frame */
+    frame_size = assemble_frame(rx_buf, MINIMAC2_BUFFER_SIZE, buf, size);
+
+    if (frame_size == 0) {
+        return size;
+    }
+
+    trace_milkymist_minimac2_rx_transfer(rx_buf, frame_size);
+
+    /* update slot */
+    s->regs[r_count] = frame_size;
+    s->regs[r_state] = STATE_PENDING;
+
+    update_rx_interrupt(s);
+
+    return size;
+}
+
+static uint64_t
+minimac2_read(void *opaque, hwaddr addr, unsigned size)
+{
+    MilkymistMinimac2State *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SETUP:
+    case R_MDIO:
+    case R_STATE0:
+    case R_COUNT0:
+    case R_STATE1:
+    case R_COUNT1:
+    case R_TXCOUNT:
+        r = s->regs[addr];
+        break;
+
+    default:
+        error_report("milkymist_minimac2: read access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_milkymist_minimac2_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void
+minimac2_write(void *opaque, hwaddr addr, uint64_t value,
+               unsigned size)
+{
+    MilkymistMinimac2State *s = opaque;
+
+    trace_milkymist_minimac2_memory_read(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_MDIO:
+    {
+        /* MDIO_DI is read only */
+        int mdio_di = (s->regs[R_MDIO] & MDIO_DI);
+        s->regs[R_MDIO] = value;
+        if (mdio_di) {
+            s->regs[R_MDIO] |= mdio_di;
+        } else {
+            s->regs[R_MDIO] &= ~mdio_di;
+        }
+
+        minimac2_update_mdio(s);
+    } break;
+    case R_TXCOUNT:
+        s->regs[addr] = value;
+        if (value > 0) {
+            minimac2_tx(s);
+        }
+        break;
+    case R_STATE0:
+    case R_STATE1:
+        s->regs[addr] = value;
+        update_rx_interrupt(s);
+        break;
+    case R_SETUP:
+    case R_COUNT0:
+    case R_COUNT1:
+        s->regs[addr] = value;
+        break;
+
+    default:
+        error_report("milkymist_minimac2: write access to unknown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static const MemoryRegionOps minimac2_ops = {
+    .read = minimac2_read,
+    .write = minimac2_write,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static int minimac2_can_rx(NetClientState *nc)
+{
+    MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
+
+    if (s->regs[R_STATE0] == STATE_LOADED) {
+        return 1;
+    }
+    if (s->regs[R_STATE1] == STATE_LOADED) {
+        return 1;
+    }
+
+    return 0;
+}
+
+static void minimac2_cleanup(NetClientState *nc)
+{
+    MilkymistMinimac2State *s = qemu_get_nic_opaque(nc);
+
+    s->nic = NULL;
+}
+
+static void milkymist_minimac2_reset(DeviceState *d)
+{
+    MilkymistMinimac2State *s =
+            container_of(d, MilkymistMinimac2State, busdev.qdev);
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    for (i = 0; i < R_PHY_MAX; i++) {
+        s->phy_regs[i] = 0;
+    }
+
+    /* defaults */
+    s->phy_regs[R_PHY_ID1] = 0x0022; /* Micrel KSZ8001L */
+    s->phy_regs[R_PHY_ID2] = 0x161a;
+}
+
+static NetClientInfo net_milkymist_minimac2_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = minimac2_can_rx,
+    .receive = minimac2_rx,
+    .cleanup = minimac2_cleanup,
+};
+
+static int milkymist_minimac2_init(SysBusDevice *dev)
+{
+    MilkymistMinimac2State *s = FROM_SYSBUS(typeof(*s), dev);
+    size_t buffers_size = TARGET_PAGE_ALIGN(3 * MINIMAC2_BUFFER_SIZE);
+
+    sysbus_init_irq(dev, &s->rx_irq);
+    sysbus_init_irq(dev, &s->tx_irq);
+
+    memory_region_init_io(&s->regs_region, &minimac2_ops, s,
+                          "milkymist-minimac2", R_MAX * 4);
+    sysbus_init_mmio(dev, &s->regs_region);
+
+    /* register buffers memory */
+    memory_region_init_ram(&s->buffers, "milkymist-minimac2.buffers",
+                           buffers_size);
+    vmstate_register_ram_global(&s->buffers);
+    s->rx0_buf = memory_region_get_ram_ptr(&s->buffers);
+    s->rx1_buf = s->rx0_buf + MINIMAC2_BUFFER_SIZE;
+    s->tx_buf = s->rx1_buf + MINIMAC2_BUFFER_SIZE;
+
+    sysbus_init_mmio(dev, &s->buffers);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_milkymist_minimac2_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_milkymist_minimac2_mdio = {
+    .name = "milkymist-minimac2-mdio",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_INT32(last_clk, MilkymistMinimac2MdioState),
+        VMSTATE_INT32(count, MilkymistMinimac2MdioState),
+        VMSTATE_UINT32(data, MilkymistMinimac2MdioState),
+        VMSTATE_UINT16(data_out, MilkymistMinimac2MdioState),
+        VMSTATE_INT32(state, MilkymistMinimac2MdioState),
+        VMSTATE_UINT8(phy_addr, MilkymistMinimac2MdioState),
+        VMSTATE_UINT8(reg_addr, MilkymistMinimac2MdioState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static const VMStateDescription vmstate_milkymist_minimac2 = {
+    .name = "milkymist-minimac2",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, MilkymistMinimac2State, R_MAX),
+        VMSTATE_UINT16_ARRAY(phy_regs, MilkymistMinimac2State, R_PHY_MAX),
+        VMSTATE_STRUCT(mdio, MilkymistMinimac2State, 0,
+                vmstate_milkymist_minimac2_mdio, MilkymistMinimac2MdioState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static Property milkymist_minimac2_properties[] = {
+    DEFINE_NIC_PROPERTIES(MilkymistMinimac2State, conf),
+    DEFINE_PROP_STRING("phy_model", MilkymistMinimac2State, phy_model),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void milkymist_minimac2_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = milkymist_minimac2_init;
+    dc->reset = milkymist_minimac2_reset;
+    dc->vmsd = &vmstate_milkymist_minimac2;
+    dc->props = milkymist_minimac2_properties;
+}
+
+static const TypeInfo milkymist_minimac2_info = {
+    .name          = "milkymist-minimac2",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(MilkymistMinimac2State),
+    .class_init    = milkymist_minimac2_class_init,
+};
+
+static void milkymist_minimac2_register_types(void)
+{
+    type_register_static(&milkymist_minimac2_info);
+}
+
+type_init(milkymist_minimac2_register_types)
diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c
new file mode 100644 (file)
index 0000000..34332f2
--- /dev/null
@@ -0,0 +1,531 @@
+/*
+ * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
+ *
+ * PAPR Inter-VM Logical Lan, aka ibmveth
+ *
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * 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 "hw/hw.h"
+#include "net/net.h"
+#include "hw/qdev.h"
+#include "hw/ppc/spapr.h"
+#include "hw/ppc/spapr_vio.h"
+
+#include <libfdt.h>
+
+#define ETH_ALEN        6
+#define MAX_PACKET_SIZE 65536
+
+/*#define DEBUG*/
+
+#ifdef DEBUG
+#define dprintf(fmt...) do { fprintf(stderr, fmt); } while (0)
+#else
+#define dprintf(fmt...)
+#endif
+
+/*
+ * Virtual LAN device
+ */
+
+typedef uint64_t vlan_bd_t;
+
+#define VLAN_BD_VALID        0x8000000000000000ULL
+#define VLAN_BD_TOGGLE       0x4000000000000000ULL
+#define VLAN_BD_NO_CSUM      0x0200000000000000ULL
+#define VLAN_BD_CSUM_GOOD    0x0100000000000000ULL
+#define VLAN_BD_LEN_MASK     0x00ffffff00000000ULL
+#define VLAN_BD_LEN(bd)      (((bd) & VLAN_BD_LEN_MASK) >> 32)
+#define VLAN_BD_ADDR_MASK    0x00000000ffffffffULL
+#define VLAN_BD_ADDR(bd)     ((bd) & VLAN_BD_ADDR_MASK)
+
+#define VLAN_VALID_BD(addr, len) (VLAN_BD_VALID | \
+                                  (((len) << 32) & VLAN_BD_LEN_MASK) |  \
+                                  (addr & VLAN_BD_ADDR_MASK))
+
+#define VLAN_RXQC_TOGGLE     0x80
+#define VLAN_RXQC_VALID      0x40
+#define VLAN_RXQC_NO_CSUM    0x02
+#define VLAN_RXQC_CSUM_GOOD  0x01
+
+#define VLAN_RQ_ALIGNMENT    16
+#define VLAN_RXQ_BD_OFF      0
+#define VLAN_FILTER_BD_OFF   8
+#define VLAN_RX_BDS_OFF      16
+#define VLAN_MAX_BUFS        ((SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8)
+
+typedef struct VIOsPAPRVLANDevice {
+    VIOsPAPRDevice sdev;
+    NICConf nicconf;
+    NICState *nic;
+    int isopen;
+    target_ulong buf_list;
+    int add_buf_ptr, use_buf_ptr, rx_bufs;
+    target_ulong rxq_ptr;
+} VIOsPAPRVLANDevice;
+
+static int spapr_vlan_can_receive(NetClientState *nc)
+{
+    VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
+
+    return (dev->isopen && dev->rx_bufs > 0);
+}
+
+static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
+                                  size_t size)
+{
+    VIOsPAPRDevice *sdev = qemu_get_nic_opaque(nc);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t rxq_bd = vio_ldq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF);
+    vlan_bd_t bd;
+    int buf_ptr = dev->use_buf_ptr;
+    uint64_t handle;
+    uint8_t control;
+
+    dprintf("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id,
+            dev->rx_bufs);
+
+    if (!dev->isopen) {
+        return -1;
+    }
+
+    if (!dev->rx_bufs) {
+        return -1;
+    }
+
+    do {
+        buf_ptr += 8;
+        if (buf_ptr >= SPAPR_TCE_PAGE_SIZE) {
+            buf_ptr = VLAN_RX_BDS_OFF;
+        }
+
+        bd = vio_ldq(sdev, dev->buf_list + buf_ptr);
+        dprintf("use_buf_ptr=%d bd=0x%016llx\n",
+                buf_ptr, (unsigned long long)bd);
+    } while ((!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8)))
+             && (buf_ptr != dev->use_buf_ptr));
+
+    if (!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8))) {
+        /* Failed to find a suitable buffer */
+        return -1;
+    }
+
+    /* Remove the buffer from the pool */
+    dev->rx_bufs--;
+    dev->use_buf_ptr = buf_ptr;
+    vio_stq(sdev, dev->buf_list + dev->use_buf_ptr, 0);
+
+    dprintf("Found buffer: ptr=%d num=%d\n", dev->use_buf_ptr, dev->rx_bufs);
+
+    /* Transfer the packet data */
+    if (spapr_vio_dma_write(sdev, VLAN_BD_ADDR(bd) + 8, buf, size) < 0) {
+        return -1;
+    }
+
+    dprintf("spapr_vlan_receive: DMA write completed\n");
+
+    /* Update the receive queue */
+    control = VLAN_RXQC_TOGGLE | VLAN_RXQC_VALID;
+    if (rxq_bd & VLAN_BD_TOGGLE) {
+        control ^= VLAN_RXQC_TOGGLE;
+    }
+
+    handle = vio_ldq(sdev, VLAN_BD_ADDR(bd));
+    vio_stq(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 8, handle);
+    vio_stl(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 4, size);
+    vio_sth(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 2, 8);
+    vio_stb(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr, control);
+
+    dprintf("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n",
+            (unsigned long long)dev->rxq_ptr,
+            (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) +
+                                        dev->rxq_ptr),
+            (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) +
+                                        dev->rxq_ptr + 8));
+
+    dev->rxq_ptr += 16;
+    if (dev->rxq_ptr >= VLAN_BD_LEN(rxq_bd)) {
+        dev->rxq_ptr = 0;
+        vio_stq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF, rxq_bd ^ VLAN_BD_TOGGLE);
+    }
+
+    if (sdev->signal_state & 1) {
+        qemu_irq_pulse(spapr_vio_qirq(sdev));
+    }
+
+    return size;
+}
+
+static void spapr_vlan_cleanup(NetClientState *nc)
+{
+    VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
+
+    dev->nic = NULL;
+}
+
+static NetClientInfo net_spapr_vlan_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = spapr_vlan_can_receive,
+    .receive = spapr_vlan_receive,
+    .cleanup = spapr_vlan_cleanup,
+};
+
+static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
+{
+    VIOsPAPRVLANDevice *dev = DO_UPCAST(VIOsPAPRVLANDevice, sdev, sdev);
+
+    dev->buf_list = 0;
+    dev->rx_bufs = 0;
+    dev->isopen = 0;
+}
+
+static int spapr_vlan_init(VIOsPAPRDevice *sdev)
+{
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+
+    qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
+
+    dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
+                            object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev);
+    qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a);
+
+    return 0;
+}
+
+void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd)
+{
+    DeviceState *dev;
+
+    dev = qdev_create(&bus->bus, "spapr-vlan");
+
+    qdev_set_nic_properties(dev, nd);
+
+    qdev_init_nofail(dev);
+}
+
+static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
+{
+    VIOsPAPRVLANDevice *vdev = (VIOsPAPRVLANDevice *)dev;
+    uint8_t padded_mac[8] = {0, 0};
+    int ret;
+
+    /* Some old phyp versions give the mac address in an 8-byte
+     * property.  The kernel driver has an insane workaround for this;
+     * rather than doing the obvious thing and checking the property
+     * length, it checks whether the first byte has 0b10 in the low
+     * bits.  If a correct 6-byte property has a different first byte
+     * the kernel will get the wrong mac address, overrunning its
+     * buffer in the process (read only, thank goodness).
+     *
+     * Here we workaround the kernel workaround by always supplying an
+     * 8-byte property, with the mac address in the last six bytes */
+    memcpy(&padded_mac[2], &vdev->nicconf.macaddr, ETH_ALEN);
+    ret = fdt_setprop(fdt, node_off, "local-mac-address",
+                      padded_mac, sizeof(padded_mac));
+    if (ret < 0) {
+        return ret;
+    }
+
+    ret = fdt_setprop_cell(fdt, node_off, "ibm,mac-address-filters", 0);
+    if (ret < 0) {
+        return ret;
+    }
+
+    return 0;
+}
+
+static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd,
+                    target_ulong alignment)
+{
+    if ((VLAN_BD_ADDR(bd) % alignment)
+        || (VLAN_BD_LEN(bd) % alignment)) {
+        return -1;
+    }
+
+    if (!spapr_vio_dma_valid(&dev->sdev, VLAN_BD_ADDR(bd),
+                             VLAN_BD_LEN(bd), DMA_DIRECTION_FROM_DEVICE)
+        || !spapr_vio_dma_valid(&dev->sdev, VLAN_BD_ADDR(bd),
+                                VLAN_BD_LEN(bd), DMA_DIRECTION_TO_DEVICE)) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
+                                           sPAPREnvironment *spapr,
+                                           target_ulong opcode,
+                                           target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong buf_list = args[1];
+    target_ulong rec_queue = args[2];
+    target_ulong filter_list = args[3];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t filter_list_bd;
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    if (dev->isopen) {
+        hcall_dprintf("H_REGISTER_LOGICAL_LAN called twice without "
+                      "H_FREE_LOGICAL_LAN\n");
+        return H_RESOURCE;
+    }
+
+    if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_TCE_PAGE_SIZE),
+                 SPAPR_TCE_PAGE_SIZE) < 0) {
+        hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx "\n", buf_list);
+        return H_PARAMETER;
+    }
+
+    filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_TCE_PAGE_SIZE);
+    if (check_bd(dev, filter_list_bd, SPAPR_TCE_PAGE_SIZE) < 0) {
+        hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx "\n", filter_list);
+        return H_PARAMETER;
+    }
+
+    if (!(rec_queue & VLAN_BD_VALID)
+        || (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) {
+        hcall_dprintf("Bad receive queue\n");
+        return H_PARAMETER;
+    }
+
+    dev->buf_list = buf_list;
+    sdev->signal_state = 0;
+
+    rec_queue &= ~VLAN_BD_TOGGLE;
+
+    /* Initialize the buffer list */
+    vio_stq(sdev, buf_list, rec_queue);
+    vio_stq(sdev, buf_list + 8, filter_list_bd);
+    spapr_vio_dma_set(sdev, buf_list + VLAN_RX_BDS_OFF, 0,
+                      SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF);
+    dev->add_buf_ptr = VLAN_RX_BDS_OFF - 8;
+    dev->use_buf_ptr = VLAN_RX_BDS_OFF - 8;
+    dev->rx_bufs = 0;
+    dev->rxq_ptr = 0;
+
+    /* Initialize the receive queue */
+    spapr_vio_dma_set(sdev, VLAN_BD_ADDR(rec_queue), 0, VLAN_BD_LEN(rec_queue));
+
+    dev->isopen = 1;
+    return H_SUCCESS;
+}
+
+
+static target_ulong h_free_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                                       target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    if (!dev->isopen) {
+        hcall_dprintf("H_FREE_LOGICAL_LAN called without "
+                      "H_REGISTER_LOGICAL_LAN\n");
+        return H_RESOURCE;
+    }
+
+    spapr_vlan_reset(sdev);
+    return H_SUCCESS;
+}
+
+static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
+                                             sPAPREnvironment *spapr,
+                                             target_ulong opcode,
+                                             target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong buf = args[1];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    vlan_bd_t bd;
+
+    dprintf("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx
+            ", 0x" TARGET_FMT_lx ")\n", reg, buf);
+
+    if (!sdev) {
+        hcall_dprintf("Bad device\n");
+        return H_PARAMETER;
+    }
+
+    if ((check_bd(dev, buf, 4) < 0)
+        || (VLAN_BD_LEN(buf) < 16)) {
+        hcall_dprintf("Bad buffer enqueued\n");
+        return H_PARAMETER;
+    }
+
+    if (!dev->isopen || dev->rx_bufs >= VLAN_MAX_BUFS) {
+        return H_RESOURCE;
+    }
+
+    do {
+        dev->add_buf_ptr += 8;
+        if (dev->add_buf_ptr >= SPAPR_TCE_PAGE_SIZE) {
+            dev->add_buf_ptr = VLAN_RX_BDS_OFF;
+        }
+
+        bd = vio_ldq(sdev, dev->buf_list + dev->add_buf_ptr);
+    } while (bd & VLAN_BD_VALID);
+
+    vio_stq(sdev, dev->buf_list + dev->add_buf_ptr, buf);
+
+    dev->rx_bufs++;
+
+    dprintf("h_add_logical_lan_buffer():  Added buf  ptr=%d  rx_bufs=%d"
+            " bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
+            (unsigned long long)buf);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                                       target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong *bufs = args + 1;
+    target_ulong continue_token = args[7];
+    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
+    unsigned total_len;
+    uint8_t *lbuf, *p;
+    int i, nbufs;
+    int ret;
+
+    dprintf("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x"
+            TARGET_FMT_lx ")\n", reg, continue_token);
+
+    if (!sdev) {
+        return H_PARAMETER;
+    }
+
+    dprintf("rxbufs = %d\n", dev->rx_bufs);
+
+    if (!dev->isopen) {
+        return H_DROPPED;
+    }
+
+    if (continue_token) {
+        return H_HARDWARE; /* FIXME actually handle this */
+    }
+
+    total_len = 0;
+    for (i = 0; i < 6; i++) {
+        dprintf("   buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]);
+        if (!(bufs[i] & VLAN_BD_VALID)) {
+            break;
+        }
+        total_len += VLAN_BD_LEN(bufs[i]);
+    }
+
+    nbufs = i;
+    dprintf("h_send_logical_lan() %d buffers, total length 0x%x\n",
+            nbufs, total_len);
+
+    if (total_len == 0) {
+        return H_SUCCESS;
+    }
+
+    if (total_len > MAX_PACKET_SIZE) {
+        /* Don't let the guest force too large an allocation */
+        return H_RESOURCE;
+    }
+
+    lbuf = alloca(total_len);
+    p = lbuf;
+    for (i = 0; i < nbufs; i++) {
+        ret = spapr_vio_dma_read(sdev, VLAN_BD_ADDR(bufs[i]),
+                                 p, VLAN_BD_LEN(bufs[i]));
+        if (ret < 0) {
+            return ret;
+        }
+
+        p += VLAN_BD_LEN(bufs[i]);
+    }
+
+    qemu_send_packet(qemu_get_queue(dev->nic), lbuf, total_len);
+
+    return H_SUCCESS;
+}
+
+static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+                                     target_ulong opcode, target_ulong *args)
+{
+    target_ulong reg = args[0];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+
+    if (!dev) {
+        return H_PARAMETER;
+    }
+
+    return H_SUCCESS;
+}
+
+static Property spapr_vlan_properties[] = {
+    DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev),
+    DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void spapr_vlan_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
+
+    k->init = spapr_vlan_init;
+    k->reset = spapr_vlan_reset;
+    k->devnode = spapr_vlan_devnode;
+    k->dt_name = "l-lan";
+    k->dt_type = "network";
+    k->dt_compatible = "IBM,l-lan";
+    k->signal_mask = 0x1;
+    dc->props = spapr_vlan_properties;
+    k->rtce_window_size = 0x10000000;
+}
+
+static const TypeInfo spapr_vlan_info = {
+    .name          = "spapr-vlan",
+    .parent        = TYPE_VIO_SPAPR_DEVICE,
+    .instance_size = sizeof(VIOsPAPRVLANDevice),
+    .class_init    = spapr_vlan_class_init,
+};
+
+static void spapr_vlan_register_types(void)
+{
+    spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
+    spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
+    spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
+    spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
+                             h_add_logical_lan_buffer);
+    spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
+    type_register_static(&spapr_vlan_info);
+}
+
+type_init(spapr_vlan_register_types)
diff --git a/hw/net/stellaris_enet.c b/hw/net/stellaris_enet.c
new file mode 100644 (file)
index 0000000..59b8456
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * Luminary Micro Stellaris Ethernet Controller
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+#include "hw/sysbus.h"
+#include "net/net.h"
+#include <zlib.h>
+
+//#define DEBUG_STELLARIS_ENET 1
+
+#ifdef DEBUG_STELLARIS_ENET
+#define DPRINTF(fmt, ...) \
+do { printf("stellaris_enet: " fmt , ## __VA_ARGS__); } while (0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, ...) do {} while(0)
+#define BADF(fmt, ...) \
+do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__);} while (0)
+#endif
+
+#define SE_INT_RX       0x01
+#define SE_INT_TXER     0x02
+#define SE_INT_TXEMP    0x04
+#define SE_INT_FOV      0x08
+#define SE_INT_RXER     0x10
+#define SE_INT_MD       0x20
+#define SE_INT_PHY      0x40
+
+#define SE_RCTL_RXEN    0x01
+#define SE_RCTL_AMUL    0x02
+#define SE_RCTL_PRMS    0x04
+#define SE_RCTL_BADCRC  0x08
+#define SE_RCTL_RSTFIFO 0x10
+
+#define SE_TCTL_TXEN    0x01
+#define SE_TCTL_PADEN   0x02
+#define SE_TCTL_CRC     0x04
+#define SE_TCTL_DUPLEX  0x08
+
+typedef struct {
+    SysBusDevice busdev;
+    uint32_t ris;
+    uint32_t im;
+    uint32_t rctl;
+    uint32_t tctl;
+    uint32_t thr;
+    uint32_t mctl;
+    uint32_t mdv;
+    uint32_t mtxd;
+    uint32_t mrxd;
+    uint32_t np;
+    int tx_frame_len;
+    int tx_fifo_len;
+    uint8_t tx_fifo[2048];
+    /* Real hardware has a 2k fifo, which works out to be at most 31 packets.
+       We implement a full 31 packet fifo.  */
+    struct {
+        uint8_t data[2048];
+        int len;
+    } rx[31];
+    uint8_t *rx_fifo;
+    int rx_fifo_len;
+    int next_packet;
+    NICState *nic;
+    NICConf conf;
+    qemu_irq irq;
+    MemoryRegion mmio;
+} stellaris_enet_state;
+
+static void stellaris_enet_update(stellaris_enet_state *s)
+{
+    qemu_set_irq(s->irq, (s->ris & s->im) != 0);
+}
+
+/* TODO: Implement MAC address filtering.  */
+static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    stellaris_enet_state *s = qemu_get_nic_opaque(nc);
+    int n;
+    uint8_t *p;
+    uint32_t crc;
+
+    if ((s->rctl & SE_RCTL_RXEN) == 0)
+        return -1;
+    if (s->np >= 31) {
+        DPRINTF("Packet dropped\n");
+        return -1;
+    }
+
+    DPRINTF("Received packet len=%d\n", size);
+    n = s->next_packet + s->np;
+    if (n >= 31)
+        n -= 31;
+    s->np++;
+
+    s->rx[n].len = size + 6;
+    p = s->rx[n].data;
+    *(p++) = (size + 6);
+    *(p++) = (size + 6) >> 8;
+    memcpy (p, buf, size);
+    p += size;
+    crc = crc32(~0, buf, size);
+    *(p++) = crc;
+    *(p++) = crc >> 8;
+    *(p++) = crc >> 16;
+    *(p++) = crc >> 24;
+    /* Clear the remaining bytes in the last word.  */
+    if ((size & 3) != 2) {
+        memset(p, 0, (6 - size) & 3);
+    }
+
+    s->ris |= SE_INT_RX;
+    stellaris_enet_update(s);
+
+    return size;
+}
+
+static int stellaris_enet_can_receive(NetClientState *nc)
+{
+    stellaris_enet_state *s = qemu_get_nic_opaque(nc);
+
+    if ((s->rctl & SE_RCTL_RXEN) == 0)
+        return 1;
+
+    return (s->np < 31);
+}
+
+static uint64_t stellaris_enet_read(void *opaque, hwaddr offset,
+                                    unsigned size)
+{
+    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
+    uint32_t val;
+
+    switch (offset) {
+    case 0x00: /* RIS */
+        DPRINTF("IRQ status %02x\n", s->ris);
+        return s->ris;
+    case 0x04: /* IM */
+        return s->im;
+    case 0x08: /* RCTL */
+        return s->rctl;
+    case 0x0c: /* TCTL */
+        return s->tctl;
+    case 0x10: /* DATA */
+        if (s->rx_fifo_len == 0) {
+            if (s->np == 0) {
+                BADF("RX underflow\n");
+                return 0;
+            }
+            s->rx_fifo_len = s->rx[s->next_packet].len;
+            s->rx_fifo = s->rx[s->next_packet].data;
+            DPRINTF("RX FIFO start packet len=%d\n", s->rx_fifo_len);
+        }
+        val = s->rx_fifo[0] | (s->rx_fifo[1] << 8) | (s->rx_fifo[2] << 16)
+              | (s->rx_fifo[3] << 24);
+        s->rx_fifo += 4;
+        s->rx_fifo_len -= 4;
+        if (s->rx_fifo_len <= 0) {
+            s->rx_fifo_len = 0;
+            s->next_packet++;
+            if (s->next_packet >= 31)
+                s->next_packet = 0;
+            s->np--;
+            DPRINTF("RX done np=%d\n", s->np);
+        }
+        return val;
+    case 0x14: /* IA0 */
+        return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
+               | (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24);
+    case 0x18: /* IA1 */
+        return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
+    case 0x1c: /* THR */
+        return s->thr;
+    case 0x20: /* MCTL */
+        return s->mctl;
+    case 0x24: /* MDV */
+        return s->mdv;
+    case 0x28: /* MADD */
+        return 0;
+    case 0x2c: /* MTXD */
+        return s->mtxd;
+    case 0x30: /* MRXD */
+        return s->mrxd;
+    case 0x34: /* NP */
+        return s->np;
+    case 0x38: /* TR */
+        return 0;
+    case 0x3c: /* Undocuented: Timestamp? */
+        return 0;
+    default:
+        hw_error("stellaris_enet_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+}
+
+static void stellaris_enet_write(void *opaque, hwaddr offset,
+                                 uint64_t value, unsigned size)
+{
+    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
+
+    switch (offset) {
+    case 0x00: /* IACK */
+        s->ris &= ~value;
+        DPRINTF("IRQ ack %02x/%02x\n", value, s->ris);
+        stellaris_enet_update(s);
+        /* Clearing TXER also resets the TX fifo.  */
+        if (value & SE_INT_TXER)
+            s->tx_frame_len = -1;
+        break;
+    case 0x04: /* IM */
+        DPRINTF("IRQ mask %02x/%02x\n", value, s->ris);
+        s->im = value;
+        stellaris_enet_update(s);
+        break;
+    case 0x08: /* RCTL */
+        s->rctl = value;
+        if (value & SE_RCTL_RSTFIFO) {
+            s->rx_fifo_len = 0;
+            s->np = 0;
+            stellaris_enet_update(s);
+        }
+        break;
+    case 0x0c: /* TCTL */
+        s->tctl = value;
+        break;
+    case 0x10: /* DATA */
+        if (s->tx_frame_len == -1) {
+            s->tx_frame_len = value & 0xffff;
+            if (s->tx_frame_len > 2032) {
+                DPRINTF("TX frame too long (%d)\n", s->tx_frame_len);
+                s->tx_frame_len = 0;
+                s->ris |= SE_INT_TXER;
+                stellaris_enet_update(s);
+            } else {
+                DPRINTF("Start TX frame len=%d\n", s->tx_frame_len);
+                /* The value written does not include the ethernet header.  */
+                s->tx_frame_len += 14;
+                if ((s->tctl & SE_TCTL_CRC) == 0)
+                    s->tx_frame_len += 4;
+                s->tx_fifo_len = 0;
+                s->tx_fifo[s->tx_fifo_len++] = value >> 16;
+                s->tx_fifo[s->tx_fifo_len++] = value >> 24;
+            }
+        } else {
+            s->tx_fifo[s->tx_fifo_len++] = value;
+            s->tx_fifo[s->tx_fifo_len++] = value >> 8;
+            s->tx_fifo[s->tx_fifo_len++] = value >> 16;
+            s->tx_fifo[s->tx_fifo_len++] = value >> 24;
+            if (s->tx_fifo_len >= s->tx_frame_len) {
+                /* We don't implement explicit CRC, so just chop it off.  */
+                if ((s->tctl & SE_TCTL_CRC) == 0)
+                    s->tx_frame_len -= 4;
+                if ((s->tctl & SE_TCTL_PADEN) && s->tx_frame_len < 60) {
+                    memset(&s->tx_fifo[s->tx_frame_len], 0, 60 - s->tx_frame_len);
+                    s->tx_fifo_len = 60;
+                }
+                qemu_send_packet(qemu_get_queue(s->nic), s->tx_fifo,
+                                 s->tx_frame_len);
+                s->tx_frame_len = -1;
+                s->ris |= SE_INT_TXEMP;
+                stellaris_enet_update(s);
+                DPRINTF("Done TX\n");
+            }
+        }
+        break;
+    case 0x14: /* IA0 */
+        s->conf.macaddr.a[0] = value;
+        s->conf.macaddr.a[1] = value >> 8;
+        s->conf.macaddr.a[2] = value >> 16;
+        s->conf.macaddr.a[3] = value >> 24;
+        break;
+    case 0x18: /* IA1 */
+        s->conf.macaddr.a[4] = value;
+        s->conf.macaddr.a[5] = value >> 8;
+        break;
+    case 0x1c: /* THR */
+        s->thr = value;
+        break;
+    case 0x20: /* MCTL */
+        s->mctl = value;
+        break;
+    case 0x24: /* MDV */
+        s->mdv = value;
+        break;
+    case 0x28: /* MADD */
+        /* ignored.  */
+        break;
+    case 0x2c: /* MTXD */
+        s->mtxd = value & 0xff;
+        break;
+    case 0x30: /* MRXD */
+    case 0x34: /* NP */
+    case 0x38: /* TR */
+        /* Ignored.  */
+    case 0x3c: /* Undocuented: Timestamp? */
+        /* Ignored.  */
+        break;
+    default:
+        hw_error("stellaris_enet_write: Bad offset %x\n", (int)offset);
+    }
+}
+
+static const MemoryRegionOps stellaris_enet_ops = {
+    .read = stellaris_enet_read,
+    .write = stellaris_enet_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void stellaris_enet_reset(stellaris_enet_state *s)
+{
+    s->mdv = 0x80;
+    s->rctl = SE_RCTL_BADCRC;
+    s->im = SE_INT_PHY | SE_INT_MD | SE_INT_RXER | SE_INT_FOV | SE_INT_TXEMP
+            | SE_INT_TXER | SE_INT_RX;
+    s->thr = 0x3f;
+    s->tx_frame_len = -1;
+}
+
+static void stellaris_enet_save(QEMUFile *f, void *opaque)
+{
+    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
+    int i;
+
+    qemu_put_be32(f, s->ris);
+    qemu_put_be32(f, s->im);
+    qemu_put_be32(f, s->rctl);
+    qemu_put_be32(f, s->tctl);
+    qemu_put_be32(f, s->thr);
+    qemu_put_be32(f, s->mctl);
+    qemu_put_be32(f, s->mdv);
+    qemu_put_be32(f, s->mtxd);
+    qemu_put_be32(f, s->mrxd);
+    qemu_put_be32(f, s->np);
+    qemu_put_be32(f, s->tx_frame_len);
+    qemu_put_be32(f, s->tx_fifo_len);
+    qemu_put_buffer(f, s->tx_fifo, sizeof(s->tx_fifo));
+    for (i = 0; i < 31; i++) {
+        qemu_put_be32(f, s->rx[i].len);
+        qemu_put_buffer(f, s->rx[i].data, sizeof(s->rx[i].data));
+
+    }
+    qemu_put_be32(f, s->next_packet);
+    qemu_put_be32(f, s->rx_fifo - s->rx[s->next_packet].data);
+    qemu_put_be32(f, s->rx_fifo_len);
+}
+
+static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id)
+{
+    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
+    int i;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    s->ris = qemu_get_be32(f);
+    s->im = qemu_get_be32(f);
+    s->rctl = qemu_get_be32(f);
+    s->tctl = qemu_get_be32(f);
+    s->thr = qemu_get_be32(f);
+    s->mctl = qemu_get_be32(f);
+    s->mdv = qemu_get_be32(f);
+    s->mtxd = qemu_get_be32(f);
+    s->mrxd = qemu_get_be32(f);
+    s->np = qemu_get_be32(f);
+    s->tx_frame_len = qemu_get_be32(f);
+    s->tx_fifo_len = qemu_get_be32(f);
+    qemu_get_buffer(f, s->tx_fifo, sizeof(s->tx_fifo));
+    for (i = 0; i < 31; i++) {
+        s->rx[i].len = qemu_get_be32(f);
+        qemu_get_buffer(f, s->rx[i].data, sizeof(s->rx[i].data));
+
+    }
+    s->next_packet = qemu_get_be32(f);
+    s->rx_fifo = s->rx[s->next_packet].data + qemu_get_be32(f);
+    s->rx_fifo_len = qemu_get_be32(f);
+
+    return 0;
+}
+
+static void stellaris_enet_cleanup(NetClientState *nc)
+{
+    stellaris_enet_state *s = qemu_get_nic_opaque(nc);
+
+    unregister_savevm(&s->busdev.qdev, "stellaris_enet", s);
+
+    memory_region_destroy(&s->mmio);
+
+    g_free(s);
+}
+
+static NetClientInfo net_stellaris_enet_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = stellaris_enet_can_receive,
+    .receive = stellaris_enet_receive,
+    .cleanup = stellaris_enet_cleanup,
+};
+
+static int stellaris_enet_init(SysBusDevice *dev)
+{
+    stellaris_enet_state *s = FROM_SYSBUS(stellaris_enet_state, dev);
+
+    memory_region_init_io(&s->mmio, &stellaris_enet_ops, s, "stellaris_enet",
+                          0x1000);
+    sysbus_init_mmio(dev, &s->mmio);
+    sysbus_init_irq(dev, &s->irq);
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+
+    s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+
+    stellaris_enet_reset(s);
+    register_savevm(&s->busdev.qdev, "stellaris_enet", -1, 1,
+                    stellaris_enet_save, stellaris_enet_load, s);
+    return 0;
+}
+
+static Property stellaris_enet_properties[] = {
+    DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void stellaris_enet_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = stellaris_enet_init;
+    dc->props = stellaris_enet_properties;
+}
+
+static const TypeInfo stellaris_enet_info = {
+    .name          = "stellaris_enet",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(stellaris_enet_state),
+    .class_init    = stellaris_enet_class_init,
+};
+
+static void stellaris_enet_register_types(void)
+{
+    type_register_static(&stellaris_enet_info);
+}
+
+type_init(stellaris_enet_register_types)
diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c
new file mode 100644 (file)
index 0000000..b2e3523
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * QEMU model of the Xilinx Ethernet Lite MAC.
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias.
+ *
+ * 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 "hw/sysbus.h"
+#include "hw/hw.h"
+#include "net/net.h"
+
+#define D(x)
+#define R_TX_BUF0     0
+#define R_TX_LEN0     (0x07f4 / 4)
+#define R_TX_GIE0     (0x07f8 / 4)
+#define R_TX_CTRL0    (0x07fc / 4)
+#define R_TX_BUF1     (0x0800 / 4)
+#define R_TX_LEN1     (0x0ff4 / 4)
+#define R_TX_CTRL1    (0x0ffc / 4)
+
+#define R_RX_BUF0     (0x1000 / 4)
+#define R_RX_CTRL0    (0x17fc / 4)
+#define R_RX_BUF1     (0x1800 / 4)
+#define R_RX_CTRL1    (0x1ffc / 4)
+#define R_MAX         (0x2000 / 4)
+
+#define GIE_GIE    0x80000000
+
+#define CTRL_I     0x8
+#define CTRL_P     0x2
+#define CTRL_S     0x1
+
+struct xlx_ethlite
+{
+    SysBusDevice busdev;
+    MemoryRegion mmio;
+    qemu_irq irq;
+    NICState *nic;
+    NICConf conf;
+
+    uint32_t c_tx_pingpong;
+    uint32_t c_rx_pingpong;
+    unsigned int txbuf;
+    unsigned int rxbuf;
+
+    uint32_t regs[R_MAX];
+};
+
+static inline void eth_pulse_irq(struct xlx_ethlite *s)
+{
+    /* Only the first gie reg is active.  */
+    if (s->regs[R_TX_GIE0] & GIE_GIE) {
+        qemu_irq_pulse(s->irq);
+    }
+}
+
+static uint64_t
+eth_read(void *opaque, hwaddr addr, unsigned int size)
+{
+    struct xlx_ethlite *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+
+    switch (addr)
+    {
+        case R_TX_GIE0:
+        case R_TX_LEN0:
+        case R_TX_LEN1:
+        case R_TX_CTRL1:
+        case R_TX_CTRL0:
+        case R_RX_CTRL1:
+        case R_RX_CTRL0:
+            r = s->regs[addr];
+            D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr * 4, r));
+            break;
+
+        default:
+            r = tswap32(s->regs[addr]);
+            break;
+    }
+    return r;
+}
+
+static void
+eth_write(void *opaque, hwaddr addr,
+          uint64_t val64, unsigned int size)
+{
+    struct xlx_ethlite *s = opaque;
+    unsigned int base = 0;
+    uint32_t value = val64;
+
+    addr >>= 2;
+    switch (addr) 
+    {
+        case R_TX_CTRL0:
+        case R_TX_CTRL1:
+            if (addr == R_TX_CTRL1)
+                base = 0x800 / 4;
+
+            D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n",
+                       __func__, addr * 4, value));
+            if ((value & (CTRL_P | CTRL_S)) == CTRL_S) {
+                qemu_send_packet(qemu_get_queue(s->nic),
+                                 (void *) &s->regs[base],
+                                 s->regs[base + R_TX_LEN0]);
+                D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0]));
+                if (s->regs[base + R_TX_CTRL0] & CTRL_I)
+                    eth_pulse_irq(s);
+            } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) {
+                memcpy(&s->conf.macaddr.a[0], &s->regs[base], 6);
+                if (s->regs[base + R_TX_CTRL0] & CTRL_I)
+                    eth_pulse_irq(s);
+            }
+
+            /* We are fast and get ready pretty much immediately so
+               we actually never flip the S nor P bits to one.  */
+            s->regs[addr] = value & ~(CTRL_P | CTRL_S);
+            break;
+
+        /* Keep these native.  */
+        case R_RX_CTRL0:
+        case R_RX_CTRL1:
+            if (!(value & CTRL_S)) {
+                qemu_flush_queued_packets(qemu_get_queue(s->nic));
+            }
+        case R_TX_LEN0:
+        case R_TX_LEN1:
+        case R_TX_GIE0:
+            D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n",
+                       __func__, addr * 4, value));
+            s->regs[addr] = value;
+            break;
+
+        default:
+            s->regs[addr] = tswap32(value);
+            break;
+    }
+}
+
+static const MemoryRegionOps eth_ops = {
+    .read = eth_read,
+    .write = eth_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4
+    }
+};
+
+static int eth_can_rx(NetClientState *nc)
+{
+    struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
+    unsigned int rxbase = s->rxbuf * (0x800 / 4);
+
+    return !(s->regs[rxbase + R_RX_CTRL0] & CTRL_S);
+}
+
+static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
+{
+    struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
+    unsigned int rxbase = s->rxbuf * (0x800 / 4);
+
+    /* DA filter.  */
+    if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6))
+        return size;
+
+    if (s->regs[rxbase + R_RX_CTRL0] & CTRL_S) {
+        D(qemu_log("ethlite lost packet %x\n", s->regs[R_RX_CTRL0]));
+        return -1;
+    }
+
+    D(qemu_log("%s %zd rxbase=%x\n", __func__, size, rxbase));
+    memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size);
+
+    s->regs[rxbase + R_RX_CTRL0] |= CTRL_S;
+    if (s->regs[rxbase + R_RX_CTRL0] & CTRL_I)
+        eth_pulse_irq(s);
+
+    /* If c_rx_pingpong was set flip buffers.  */
+    s->rxbuf ^= s->c_rx_pingpong;
+    return size;
+}
+
+static void eth_cleanup(NetClientState *nc)
+{
+    struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
+
+    s->nic = NULL;
+}
+
+static NetClientInfo net_xilinx_ethlite_info = {
+    .type = NET_CLIENT_OPTIONS_KIND_NIC,
+    .size = sizeof(NICState),
+    .can_receive = eth_can_rx,
+    .receive = eth_rx,
+    .cleanup = eth_cleanup,
+};
+
+static int xilinx_ethlite_init(SysBusDevice *dev)
+{
+    struct xlx_ethlite *s = FROM_SYSBUS(typeof (*s), dev);
+
+    sysbus_init_irq(dev, &s->irq);
+    s->rxbuf = 0;
+
+    memory_region_init_io(&s->mmio, &eth_ops, s, "xlnx.xps-ethernetlite",
+                                                                    R_MAX * 4);
+    sysbus_init_mmio(dev, &s->mmio);
+
+    qemu_macaddr_default_if_unset(&s->conf.macaddr);
+    s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
+                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
+    return 0;
+}
+
+static Property xilinx_ethlite_properties[] = {
+    DEFINE_PROP_UINT32("tx-ping-pong", struct xlx_ethlite, c_tx_pingpong, 1),
+    DEFINE_PROP_UINT32("rx-ping-pong", struct xlx_ethlite, c_rx_pingpong, 1),
+    DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void xilinx_ethlite_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+    k->init = xilinx_ethlite_init;
+    dc->props = xilinx_ethlite_properties;
+}
+
+static const TypeInfo xilinx_ethlite_info = {
+    .name          = "xlnx.xps-ethernetlite",
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(struct xlx_ethlite),
+    .class_init    = xilinx_ethlite_class_init,
+};
+
+static void xilinx_ethlite_register_types(void)
+{
+    type_register_static(&xilinx_ethlite_info);
+}
+
+type_init(xilinx_ethlite_register_types)
index b22a6f1ce41c456d83899f021b45fe2442be49c2..42c7d087823fb354c0c065c1afa20b007e689077 100644 (file)
@@ -1,5 +1,5 @@
 # IBM pSeries (sPAPR)
-obj-$(CONFIG_PSERIES) += spapr_vty.o spapr_llan.o spapr_vscsi.o
+obj-$(CONFIG_PSERIES) += spapr_vty.o spapr_vscsi.o
 obj-$(CONFIG_PSERIES) += spapr_pci.o
 obj-$(CONFIG_PSERIES) += spapr_nvram.o
 # PowerPC 4xx boards
@@ -7,9 +7,6 @@ obj-y += ppc4xx_pci.o
 # PowerPC OpenPIC
 obj-y += openpic.o
 
-# Xilinx PPC peripherals
-obj-y += xilinx_ethlite.o
-
 obj-y := $(addprefix ../,$(obj-y))
 
 # shared objects
diff --git a/hw/spapr_llan.c b/hw/spapr_llan.c
deleted file mode 100644 (file)
index 34332f2..0000000
+++ /dev/null
@@ -1,531 +0,0 @@
-/*
- * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
- *
- * PAPR Inter-VM Logical Lan, aka ibmveth
- *
- * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
- *
- * 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 "hw/hw.h"
-#include "net/net.h"
-#include "hw/qdev.h"
-#include "hw/ppc/spapr.h"
-#include "hw/ppc/spapr_vio.h"
-
-#include <libfdt.h>
-
-#define ETH_ALEN        6
-#define MAX_PACKET_SIZE 65536
-
-/*#define DEBUG*/
-
-#ifdef DEBUG
-#define dprintf(fmt...) do { fprintf(stderr, fmt); } while (0)
-#else
-#define dprintf(fmt...)
-#endif
-
-/*
- * Virtual LAN device
- */
-
-typedef uint64_t vlan_bd_t;
-
-#define VLAN_BD_VALID        0x8000000000000000ULL
-#define VLAN_BD_TOGGLE       0x4000000000000000ULL
-#define VLAN_BD_NO_CSUM      0x0200000000000000ULL
-#define VLAN_BD_CSUM_GOOD    0x0100000000000000ULL
-#define VLAN_BD_LEN_MASK     0x00ffffff00000000ULL
-#define VLAN_BD_LEN(bd)      (((bd) & VLAN_BD_LEN_MASK) >> 32)
-#define VLAN_BD_ADDR_MASK    0x00000000ffffffffULL
-#define VLAN_BD_ADDR(bd)     ((bd) & VLAN_BD_ADDR_MASK)
-
-#define VLAN_VALID_BD(addr, len) (VLAN_BD_VALID | \
-                                  (((len) << 32) & VLAN_BD_LEN_MASK) |  \
-                                  (addr & VLAN_BD_ADDR_MASK))
-
-#define VLAN_RXQC_TOGGLE     0x80
-#define VLAN_RXQC_VALID      0x40
-#define VLAN_RXQC_NO_CSUM    0x02
-#define VLAN_RXQC_CSUM_GOOD  0x01
-
-#define VLAN_RQ_ALIGNMENT    16
-#define VLAN_RXQ_BD_OFF      0
-#define VLAN_FILTER_BD_OFF   8
-#define VLAN_RX_BDS_OFF      16
-#define VLAN_MAX_BUFS        ((SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF) / 8)
-
-typedef struct VIOsPAPRVLANDevice {
-    VIOsPAPRDevice sdev;
-    NICConf nicconf;
-    NICState *nic;
-    int isopen;
-    target_ulong buf_list;
-    int add_buf_ptr, use_buf_ptr, rx_bufs;
-    target_ulong rxq_ptr;
-} VIOsPAPRVLANDevice;
-
-static int spapr_vlan_can_receive(NetClientState *nc)
-{
-    VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
-
-    return (dev->isopen && dev->rx_bufs > 0);
-}
-
-static ssize_t spapr_vlan_receive(NetClientState *nc, const uint8_t *buf,
-                                  size_t size)
-{
-    VIOsPAPRDevice *sdev = qemu_get_nic_opaque(nc);
-    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
-    vlan_bd_t rxq_bd = vio_ldq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF);
-    vlan_bd_t bd;
-    int buf_ptr = dev->use_buf_ptr;
-    uint64_t handle;
-    uint8_t control;
-
-    dprintf("spapr_vlan_receive() [%s] rx_bufs=%d\n", sdev->qdev.id,
-            dev->rx_bufs);
-
-    if (!dev->isopen) {
-        return -1;
-    }
-
-    if (!dev->rx_bufs) {
-        return -1;
-    }
-
-    do {
-        buf_ptr += 8;
-        if (buf_ptr >= SPAPR_TCE_PAGE_SIZE) {
-            buf_ptr = VLAN_RX_BDS_OFF;
-        }
-
-        bd = vio_ldq(sdev, dev->buf_list + buf_ptr);
-        dprintf("use_buf_ptr=%d bd=0x%016llx\n",
-                buf_ptr, (unsigned long long)bd);
-    } while ((!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8)))
-             && (buf_ptr != dev->use_buf_ptr));
-
-    if (!(bd & VLAN_BD_VALID) || (VLAN_BD_LEN(bd) < (size + 8))) {
-        /* Failed to find a suitable buffer */
-        return -1;
-    }
-
-    /* Remove the buffer from the pool */
-    dev->rx_bufs--;
-    dev->use_buf_ptr = buf_ptr;
-    vio_stq(sdev, dev->buf_list + dev->use_buf_ptr, 0);
-
-    dprintf("Found buffer: ptr=%d num=%d\n", dev->use_buf_ptr, dev->rx_bufs);
-
-    /* Transfer the packet data */
-    if (spapr_vio_dma_write(sdev, VLAN_BD_ADDR(bd) + 8, buf, size) < 0) {
-        return -1;
-    }
-
-    dprintf("spapr_vlan_receive: DMA write completed\n");
-
-    /* Update the receive queue */
-    control = VLAN_RXQC_TOGGLE | VLAN_RXQC_VALID;
-    if (rxq_bd & VLAN_BD_TOGGLE) {
-        control ^= VLAN_RXQC_TOGGLE;
-    }
-
-    handle = vio_ldq(sdev, VLAN_BD_ADDR(bd));
-    vio_stq(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 8, handle);
-    vio_stl(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 4, size);
-    vio_sth(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr + 2, 8);
-    vio_stb(sdev, VLAN_BD_ADDR(rxq_bd) + dev->rxq_ptr, control);
-
-    dprintf("wrote rxq entry (ptr=0x%llx): 0x%016llx 0x%016llx\n",
-            (unsigned long long)dev->rxq_ptr,
-            (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) +
-                                        dev->rxq_ptr),
-            (unsigned long long)vio_ldq(sdev, VLAN_BD_ADDR(rxq_bd) +
-                                        dev->rxq_ptr + 8));
-
-    dev->rxq_ptr += 16;
-    if (dev->rxq_ptr >= VLAN_BD_LEN(rxq_bd)) {
-        dev->rxq_ptr = 0;
-        vio_stq(sdev, dev->buf_list + VLAN_RXQ_BD_OFF, rxq_bd ^ VLAN_BD_TOGGLE);
-    }
-
-    if (sdev->signal_state & 1) {
-        qemu_irq_pulse(spapr_vio_qirq(sdev));
-    }
-
-    return size;
-}
-
-static void spapr_vlan_cleanup(NetClientState *nc)
-{
-    VIOsPAPRVLANDevice *dev = qemu_get_nic_opaque(nc);
-
-    dev->nic = NULL;
-}
-
-static NetClientInfo net_spapr_vlan_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = spapr_vlan_can_receive,
-    .receive = spapr_vlan_receive,
-    .cleanup = spapr_vlan_cleanup,
-};
-
-static void spapr_vlan_reset(VIOsPAPRDevice *sdev)
-{
-    VIOsPAPRVLANDevice *dev = DO_UPCAST(VIOsPAPRVLANDevice, sdev, sdev);
-
-    dev->buf_list = 0;
-    dev->rx_bufs = 0;
-    dev->isopen = 0;
-}
-
-static int spapr_vlan_init(VIOsPAPRDevice *sdev)
-{
-    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
-
-    qemu_macaddr_default_if_unset(&dev->nicconf.macaddr);
-
-    dev->nic = qemu_new_nic(&net_spapr_vlan_info, &dev->nicconf,
-                            object_get_typename(OBJECT(sdev)), sdev->qdev.id, dev);
-    qemu_format_nic_info_str(qemu_get_queue(dev->nic), dev->nicconf.macaddr.a);
-
-    return 0;
-}
-
-void spapr_vlan_create(VIOsPAPRBus *bus, NICInfo *nd)
-{
-    DeviceState *dev;
-
-    dev = qdev_create(&bus->bus, "spapr-vlan");
-
-    qdev_set_nic_properties(dev, nd);
-
-    qdev_init_nofail(dev);
-}
-
-static int spapr_vlan_devnode(VIOsPAPRDevice *dev, void *fdt, int node_off)
-{
-    VIOsPAPRVLANDevice *vdev = (VIOsPAPRVLANDevice *)dev;
-    uint8_t padded_mac[8] = {0, 0};
-    int ret;
-
-    /* Some old phyp versions give the mac address in an 8-byte
-     * property.  The kernel driver has an insane workaround for this;
-     * rather than doing the obvious thing and checking the property
-     * length, it checks whether the first byte has 0b10 in the low
-     * bits.  If a correct 6-byte property has a different first byte
-     * the kernel will get the wrong mac address, overrunning its
-     * buffer in the process (read only, thank goodness).
-     *
-     * Here we workaround the kernel workaround by always supplying an
-     * 8-byte property, with the mac address in the last six bytes */
-    memcpy(&padded_mac[2], &vdev->nicconf.macaddr, ETH_ALEN);
-    ret = fdt_setprop(fdt, node_off, "local-mac-address",
-                      padded_mac, sizeof(padded_mac));
-    if (ret < 0) {
-        return ret;
-    }
-
-    ret = fdt_setprop_cell(fdt, node_off, "ibm,mac-address-filters", 0);
-    if (ret < 0) {
-        return ret;
-    }
-
-    return 0;
-}
-
-static int check_bd(VIOsPAPRVLANDevice *dev, vlan_bd_t bd,
-                    target_ulong alignment)
-{
-    if ((VLAN_BD_ADDR(bd) % alignment)
-        || (VLAN_BD_LEN(bd) % alignment)) {
-        return -1;
-    }
-
-    if (!spapr_vio_dma_valid(&dev->sdev, VLAN_BD_ADDR(bd),
-                             VLAN_BD_LEN(bd), DMA_DIRECTION_FROM_DEVICE)
-        || !spapr_vio_dma_valid(&dev->sdev, VLAN_BD_ADDR(bd),
-                                VLAN_BD_LEN(bd), DMA_DIRECTION_TO_DEVICE)) {
-        return -1;
-    }
-
-    return 0;
-}
-
-static target_ulong h_register_logical_lan(PowerPCCPU *cpu,
-                                           sPAPREnvironment *spapr,
-                                           target_ulong opcode,
-                                           target_ulong *args)
-{
-    target_ulong reg = args[0];
-    target_ulong buf_list = args[1];
-    target_ulong rec_queue = args[2];
-    target_ulong filter_list = args[3];
-    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
-    vlan_bd_t filter_list_bd;
-
-    if (!dev) {
-        return H_PARAMETER;
-    }
-
-    if (dev->isopen) {
-        hcall_dprintf("H_REGISTER_LOGICAL_LAN called twice without "
-                      "H_FREE_LOGICAL_LAN\n");
-        return H_RESOURCE;
-    }
-
-    if (check_bd(dev, VLAN_VALID_BD(buf_list, SPAPR_TCE_PAGE_SIZE),
-                 SPAPR_TCE_PAGE_SIZE) < 0) {
-        hcall_dprintf("Bad buf_list 0x" TARGET_FMT_lx "\n", buf_list);
-        return H_PARAMETER;
-    }
-
-    filter_list_bd = VLAN_VALID_BD(filter_list, SPAPR_TCE_PAGE_SIZE);
-    if (check_bd(dev, filter_list_bd, SPAPR_TCE_PAGE_SIZE) < 0) {
-        hcall_dprintf("Bad filter_list 0x" TARGET_FMT_lx "\n", filter_list);
-        return H_PARAMETER;
-    }
-
-    if (!(rec_queue & VLAN_BD_VALID)
-        || (check_bd(dev, rec_queue, VLAN_RQ_ALIGNMENT) < 0)) {
-        hcall_dprintf("Bad receive queue\n");
-        return H_PARAMETER;
-    }
-
-    dev->buf_list = buf_list;
-    sdev->signal_state = 0;
-
-    rec_queue &= ~VLAN_BD_TOGGLE;
-
-    /* Initialize the buffer list */
-    vio_stq(sdev, buf_list, rec_queue);
-    vio_stq(sdev, buf_list + 8, filter_list_bd);
-    spapr_vio_dma_set(sdev, buf_list + VLAN_RX_BDS_OFF, 0,
-                      SPAPR_TCE_PAGE_SIZE - VLAN_RX_BDS_OFF);
-    dev->add_buf_ptr = VLAN_RX_BDS_OFF - 8;
-    dev->use_buf_ptr = VLAN_RX_BDS_OFF - 8;
-    dev->rx_bufs = 0;
-    dev->rxq_ptr = 0;
-
-    /* Initialize the receive queue */
-    spapr_vio_dma_set(sdev, VLAN_BD_ADDR(rec_queue), 0, VLAN_BD_LEN(rec_queue));
-
-    dev->isopen = 1;
-    return H_SUCCESS;
-}
-
-
-static target_ulong h_free_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                                       target_ulong opcode, target_ulong *args)
-{
-    target_ulong reg = args[0];
-    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
-
-    if (!dev) {
-        return H_PARAMETER;
-    }
-
-    if (!dev->isopen) {
-        hcall_dprintf("H_FREE_LOGICAL_LAN called without "
-                      "H_REGISTER_LOGICAL_LAN\n");
-        return H_RESOURCE;
-    }
-
-    spapr_vlan_reset(sdev);
-    return H_SUCCESS;
-}
-
-static target_ulong h_add_logical_lan_buffer(PowerPCCPU *cpu,
-                                             sPAPREnvironment *spapr,
-                                             target_ulong opcode,
-                                             target_ulong *args)
-{
-    target_ulong reg = args[0];
-    target_ulong buf = args[1];
-    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
-    vlan_bd_t bd;
-
-    dprintf("H_ADD_LOGICAL_LAN_BUFFER(0x" TARGET_FMT_lx
-            ", 0x" TARGET_FMT_lx ")\n", reg, buf);
-
-    if (!sdev) {
-        hcall_dprintf("Bad device\n");
-        return H_PARAMETER;
-    }
-
-    if ((check_bd(dev, buf, 4) < 0)
-        || (VLAN_BD_LEN(buf) < 16)) {
-        hcall_dprintf("Bad buffer enqueued\n");
-        return H_PARAMETER;
-    }
-
-    if (!dev->isopen || dev->rx_bufs >= VLAN_MAX_BUFS) {
-        return H_RESOURCE;
-    }
-
-    do {
-        dev->add_buf_ptr += 8;
-        if (dev->add_buf_ptr >= SPAPR_TCE_PAGE_SIZE) {
-            dev->add_buf_ptr = VLAN_RX_BDS_OFF;
-        }
-
-        bd = vio_ldq(sdev, dev->buf_list + dev->add_buf_ptr);
-    } while (bd & VLAN_BD_VALID);
-
-    vio_stq(sdev, dev->buf_list + dev->add_buf_ptr, buf);
-
-    dev->rx_bufs++;
-
-    dprintf("h_add_logical_lan_buffer():  Added buf  ptr=%d  rx_bufs=%d"
-            " bd=0x%016llx\n", dev->add_buf_ptr, dev->rx_bufs,
-            (unsigned long long)buf);
-
-    return H_SUCCESS;
-}
-
-static target_ulong h_send_logical_lan(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                                       target_ulong opcode, target_ulong *args)
-{
-    target_ulong reg = args[0];
-    target_ulong *bufs = args + 1;
-    target_ulong continue_token = args[7];
-    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-    VIOsPAPRVLANDevice *dev = (VIOsPAPRVLANDevice *)sdev;
-    unsigned total_len;
-    uint8_t *lbuf, *p;
-    int i, nbufs;
-    int ret;
-
-    dprintf("H_SEND_LOGICAL_LAN(0x" TARGET_FMT_lx ", <bufs>, 0x"
-            TARGET_FMT_lx ")\n", reg, continue_token);
-
-    if (!sdev) {
-        return H_PARAMETER;
-    }
-
-    dprintf("rxbufs = %d\n", dev->rx_bufs);
-
-    if (!dev->isopen) {
-        return H_DROPPED;
-    }
-
-    if (continue_token) {
-        return H_HARDWARE; /* FIXME actually handle this */
-    }
-
-    total_len = 0;
-    for (i = 0; i < 6; i++) {
-        dprintf("   buf desc: 0x" TARGET_FMT_lx "\n", bufs[i]);
-        if (!(bufs[i] & VLAN_BD_VALID)) {
-            break;
-        }
-        total_len += VLAN_BD_LEN(bufs[i]);
-    }
-
-    nbufs = i;
-    dprintf("h_send_logical_lan() %d buffers, total length 0x%x\n",
-            nbufs, total_len);
-
-    if (total_len == 0) {
-        return H_SUCCESS;
-    }
-
-    if (total_len > MAX_PACKET_SIZE) {
-        /* Don't let the guest force too large an allocation */
-        return H_RESOURCE;
-    }
-
-    lbuf = alloca(total_len);
-    p = lbuf;
-    for (i = 0; i < nbufs; i++) {
-        ret = spapr_vio_dma_read(sdev, VLAN_BD_ADDR(bufs[i]),
-                                 p, VLAN_BD_LEN(bufs[i]));
-        if (ret < 0) {
-            return ret;
-        }
-
-        p += VLAN_BD_LEN(bufs[i]);
-    }
-
-    qemu_send_packet(qemu_get_queue(dev->nic), lbuf, total_len);
-
-    return H_SUCCESS;
-}
-
-static target_ulong h_multicast_ctrl(PowerPCCPU *cpu, sPAPREnvironment *spapr,
-                                     target_ulong opcode, target_ulong *args)
-{
-    target_ulong reg = args[0];
-    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
-
-    if (!dev) {
-        return H_PARAMETER;
-    }
-
-    return H_SUCCESS;
-}
-
-static Property spapr_vlan_properties[] = {
-    DEFINE_SPAPR_PROPERTIES(VIOsPAPRVLANDevice, sdev),
-    DEFINE_NIC_PROPERTIES(VIOsPAPRVLANDevice, nicconf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void spapr_vlan_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    VIOsPAPRDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
-
-    k->init = spapr_vlan_init;
-    k->reset = spapr_vlan_reset;
-    k->devnode = spapr_vlan_devnode;
-    k->dt_name = "l-lan";
-    k->dt_type = "network";
-    k->dt_compatible = "IBM,l-lan";
-    k->signal_mask = 0x1;
-    dc->props = spapr_vlan_properties;
-    k->rtce_window_size = 0x10000000;
-}
-
-static const TypeInfo spapr_vlan_info = {
-    .name          = "spapr-vlan",
-    .parent        = TYPE_VIO_SPAPR_DEVICE,
-    .instance_size = sizeof(VIOsPAPRVLANDevice),
-    .class_init    = spapr_vlan_class_init,
-};
-
-static void spapr_vlan_register_types(void)
-{
-    spapr_register_hypercall(H_REGISTER_LOGICAL_LAN, h_register_logical_lan);
-    spapr_register_hypercall(H_FREE_LOGICAL_LAN, h_free_logical_lan);
-    spapr_register_hypercall(H_SEND_LOGICAL_LAN, h_send_logical_lan);
-    spapr_register_hypercall(H_ADD_LOGICAL_LAN_BUFFER,
-                             h_add_logical_lan_buffer);
-    spapr_register_hypercall(H_MULTICAST_CTRL, h_multicast_ctrl);
-    type_register_static(&spapr_vlan_info);
-}
-
-type_init(spapr_vlan_register_types)
index 71bbddf8c31c8e441360c7a762aaefe508e01e07..56eeb9012b7b3678469469e4af98862c68675066 100644 (file)
@@ -1,4 +1,4 @@
-obj-y = lance.o tcx.o sun4m_iommu.o slavio_intctl.o
+obj-y = tcx.o sun4m_iommu.o slavio_intctl.o
 obj-y += slavio_timer.o slavio_misc.o sparc32_dma.o
 obj-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o
 
diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c
deleted file mode 100644 (file)
index 59b8456..0000000
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * Luminary Micro Stellaris Ethernet Controller
- *
- * Copyright (c) 2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-#include "hw/sysbus.h"
-#include "net/net.h"
-#include <zlib.h>
-
-//#define DEBUG_STELLARIS_ENET 1
-
-#ifdef DEBUG_STELLARIS_ENET
-#define DPRINTF(fmt, ...) \
-do { printf("stellaris_enet: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "stellaris_enet: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-#define SE_INT_RX       0x01
-#define SE_INT_TXER     0x02
-#define SE_INT_TXEMP    0x04
-#define SE_INT_FOV      0x08
-#define SE_INT_RXER     0x10
-#define SE_INT_MD       0x20
-#define SE_INT_PHY      0x40
-
-#define SE_RCTL_RXEN    0x01
-#define SE_RCTL_AMUL    0x02
-#define SE_RCTL_PRMS    0x04
-#define SE_RCTL_BADCRC  0x08
-#define SE_RCTL_RSTFIFO 0x10
-
-#define SE_TCTL_TXEN    0x01
-#define SE_TCTL_PADEN   0x02
-#define SE_TCTL_CRC     0x04
-#define SE_TCTL_DUPLEX  0x08
-
-typedef struct {
-    SysBusDevice busdev;
-    uint32_t ris;
-    uint32_t im;
-    uint32_t rctl;
-    uint32_t tctl;
-    uint32_t thr;
-    uint32_t mctl;
-    uint32_t mdv;
-    uint32_t mtxd;
-    uint32_t mrxd;
-    uint32_t np;
-    int tx_frame_len;
-    int tx_fifo_len;
-    uint8_t tx_fifo[2048];
-    /* Real hardware has a 2k fifo, which works out to be at most 31 packets.
-       We implement a full 31 packet fifo.  */
-    struct {
-        uint8_t data[2048];
-        int len;
-    } rx[31];
-    uint8_t *rx_fifo;
-    int rx_fifo_len;
-    int next_packet;
-    NICState *nic;
-    NICConf conf;
-    qemu_irq irq;
-    MemoryRegion mmio;
-} stellaris_enet_state;
-
-static void stellaris_enet_update(stellaris_enet_state *s)
-{
-    qemu_set_irq(s->irq, (s->ris & s->im) != 0);
-}
-
-/* TODO: Implement MAC address filtering.  */
-static ssize_t stellaris_enet_receive(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    stellaris_enet_state *s = qemu_get_nic_opaque(nc);
-    int n;
-    uint8_t *p;
-    uint32_t crc;
-
-    if ((s->rctl & SE_RCTL_RXEN) == 0)
-        return -1;
-    if (s->np >= 31) {
-        DPRINTF("Packet dropped\n");
-        return -1;
-    }
-
-    DPRINTF("Received packet len=%d\n", size);
-    n = s->next_packet + s->np;
-    if (n >= 31)
-        n -= 31;
-    s->np++;
-
-    s->rx[n].len = size + 6;
-    p = s->rx[n].data;
-    *(p++) = (size + 6);
-    *(p++) = (size + 6) >> 8;
-    memcpy (p, buf, size);
-    p += size;
-    crc = crc32(~0, buf, size);
-    *(p++) = crc;
-    *(p++) = crc >> 8;
-    *(p++) = crc >> 16;
-    *(p++) = crc >> 24;
-    /* Clear the remaining bytes in the last word.  */
-    if ((size & 3) != 2) {
-        memset(p, 0, (6 - size) & 3);
-    }
-
-    s->ris |= SE_INT_RX;
-    stellaris_enet_update(s);
-
-    return size;
-}
-
-static int stellaris_enet_can_receive(NetClientState *nc)
-{
-    stellaris_enet_state *s = qemu_get_nic_opaque(nc);
-
-    if ((s->rctl & SE_RCTL_RXEN) == 0)
-        return 1;
-
-    return (s->np < 31);
-}
-
-static uint64_t stellaris_enet_read(void *opaque, hwaddr offset,
-                                    unsigned size)
-{
-    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
-    uint32_t val;
-
-    switch (offset) {
-    case 0x00: /* RIS */
-        DPRINTF("IRQ status %02x\n", s->ris);
-        return s->ris;
-    case 0x04: /* IM */
-        return s->im;
-    case 0x08: /* RCTL */
-        return s->rctl;
-    case 0x0c: /* TCTL */
-        return s->tctl;
-    case 0x10: /* DATA */
-        if (s->rx_fifo_len == 0) {
-            if (s->np == 0) {
-                BADF("RX underflow\n");
-                return 0;
-            }
-            s->rx_fifo_len = s->rx[s->next_packet].len;
-            s->rx_fifo = s->rx[s->next_packet].data;
-            DPRINTF("RX FIFO start packet len=%d\n", s->rx_fifo_len);
-        }
-        val = s->rx_fifo[0] | (s->rx_fifo[1] << 8) | (s->rx_fifo[2] << 16)
-              | (s->rx_fifo[3] << 24);
-        s->rx_fifo += 4;
-        s->rx_fifo_len -= 4;
-        if (s->rx_fifo_len <= 0) {
-            s->rx_fifo_len = 0;
-            s->next_packet++;
-            if (s->next_packet >= 31)
-                s->next_packet = 0;
-            s->np--;
-            DPRINTF("RX done np=%d\n", s->np);
-        }
-        return val;
-    case 0x14: /* IA0 */
-        return s->conf.macaddr.a[0] | (s->conf.macaddr.a[1] << 8)
-               | (s->conf.macaddr.a[2] << 16) | (s->conf.macaddr.a[3] << 24);
-    case 0x18: /* IA1 */
-        return s->conf.macaddr.a[4] | (s->conf.macaddr.a[5] << 8);
-    case 0x1c: /* THR */
-        return s->thr;
-    case 0x20: /* MCTL */
-        return s->mctl;
-    case 0x24: /* MDV */
-        return s->mdv;
-    case 0x28: /* MADD */
-        return 0;
-    case 0x2c: /* MTXD */
-        return s->mtxd;
-    case 0x30: /* MRXD */
-        return s->mrxd;
-    case 0x34: /* NP */
-        return s->np;
-    case 0x38: /* TR */
-        return 0;
-    case 0x3c: /* Undocuented: Timestamp? */
-        return 0;
-    default:
-        hw_error("stellaris_enet_read: Bad offset %x\n", (int)offset);
-        return 0;
-    }
-}
-
-static void stellaris_enet_write(void *opaque, hwaddr offset,
-                                 uint64_t value, unsigned size)
-{
-    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
-
-    switch (offset) {
-    case 0x00: /* IACK */
-        s->ris &= ~value;
-        DPRINTF("IRQ ack %02x/%02x\n", value, s->ris);
-        stellaris_enet_update(s);
-        /* Clearing TXER also resets the TX fifo.  */
-        if (value & SE_INT_TXER)
-            s->tx_frame_len = -1;
-        break;
-    case 0x04: /* IM */
-        DPRINTF("IRQ mask %02x/%02x\n", value, s->ris);
-        s->im = value;
-        stellaris_enet_update(s);
-        break;
-    case 0x08: /* RCTL */
-        s->rctl = value;
-        if (value & SE_RCTL_RSTFIFO) {
-            s->rx_fifo_len = 0;
-            s->np = 0;
-            stellaris_enet_update(s);
-        }
-        break;
-    case 0x0c: /* TCTL */
-        s->tctl = value;
-        break;
-    case 0x10: /* DATA */
-        if (s->tx_frame_len == -1) {
-            s->tx_frame_len = value & 0xffff;
-            if (s->tx_frame_len > 2032) {
-                DPRINTF("TX frame too long (%d)\n", s->tx_frame_len);
-                s->tx_frame_len = 0;
-                s->ris |= SE_INT_TXER;
-                stellaris_enet_update(s);
-            } else {
-                DPRINTF("Start TX frame len=%d\n", s->tx_frame_len);
-                /* The value written does not include the ethernet header.  */
-                s->tx_frame_len += 14;
-                if ((s->tctl & SE_TCTL_CRC) == 0)
-                    s->tx_frame_len += 4;
-                s->tx_fifo_len = 0;
-                s->tx_fifo[s->tx_fifo_len++] = value >> 16;
-                s->tx_fifo[s->tx_fifo_len++] = value >> 24;
-            }
-        } else {
-            s->tx_fifo[s->tx_fifo_len++] = value;
-            s->tx_fifo[s->tx_fifo_len++] = value >> 8;
-            s->tx_fifo[s->tx_fifo_len++] = value >> 16;
-            s->tx_fifo[s->tx_fifo_len++] = value >> 24;
-            if (s->tx_fifo_len >= s->tx_frame_len) {
-                /* We don't implement explicit CRC, so just chop it off.  */
-                if ((s->tctl & SE_TCTL_CRC) == 0)
-                    s->tx_frame_len -= 4;
-                if ((s->tctl & SE_TCTL_PADEN) && s->tx_frame_len < 60) {
-                    memset(&s->tx_fifo[s->tx_frame_len], 0, 60 - s->tx_frame_len);
-                    s->tx_fifo_len = 60;
-                }
-                qemu_send_packet(qemu_get_queue(s->nic), s->tx_fifo,
-                                 s->tx_frame_len);
-                s->tx_frame_len = -1;
-                s->ris |= SE_INT_TXEMP;
-                stellaris_enet_update(s);
-                DPRINTF("Done TX\n");
-            }
-        }
-        break;
-    case 0x14: /* IA0 */
-        s->conf.macaddr.a[0] = value;
-        s->conf.macaddr.a[1] = value >> 8;
-        s->conf.macaddr.a[2] = value >> 16;
-        s->conf.macaddr.a[3] = value >> 24;
-        break;
-    case 0x18: /* IA1 */
-        s->conf.macaddr.a[4] = value;
-        s->conf.macaddr.a[5] = value >> 8;
-        break;
-    case 0x1c: /* THR */
-        s->thr = value;
-        break;
-    case 0x20: /* MCTL */
-        s->mctl = value;
-        break;
-    case 0x24: /* MDV */
-        s->mdv = value;
-        break;
-    case 0x28: /* MADD */
-        /* ignored.  */
-        break;
-    case 0x2c: /* MTXD */
-        s->mtxd = value & 0xff;
-        break;
-    case 0x30: /* MRXD */
-    case 0x34: /* NP */
-    case 0x38: /* TR */
-        /* Ignored.  */
-    case 0x3c: /* Undocuented: Timestamp? */
-        /* Ignored.  */
-        break;
-    default:
-        hw_error("stellaris_enet_write: Bad offset %x\n", (int)offset);
-    }
-}
-
-static const MemoryRegionOps stellaris_enet_ops = {
-    .read = stellaris_enet_read,
-    .write = stellaris_enet_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void stellaris_enet_reset(stellaris_enet_state *s)
-{
-    s->mdv = 0x80;
-    s->rctl = SE_RCTL_BADCRC;
-    s->im = SE_INT_PHY | SE_INT_MD | SE_INT_RXER | SE_INT_FOV | SE_INT_TXEMP
-            | SE_INT_TXER | SE_INT_RX;
-    s->thr = 0x3f;
-    s->tx_frame_len = -1;
-}
-
-static void stellaris_enet_save(QEMUFile *f, void *opaque)
-{
-    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
-    int i;
-
-    qemu_put_be32(f, s->ris);
-    qemu_put_be32(f, s->im);
-    qemu_put_be32(f, s->rctl);
-    qemu_put_be32(f, s->tctl);
-    qemu_put_be32(f, s->thr);
-    qemu_put_be32(f, s->mctl);
-    qemu_put_be32(f, s->mdv);
-    qemu_put_be32(f, s->mtxd);
-    qemu_put_be32(f, s->mrxd);
-    qemu_put_be32(f, s->np);
-    qemu_put_be32(f, s->tx_frame_len);
-    qemu_put_be32(f, s->tx_fifo_len);
-    qemu_put_buffer(f, s->tx_fifo, sizeof(s->tx_fifo));
-    for (i = 0; i < 31; i++) {
-        qemu_put_be32(f, s->rx[i].len);
-        qemu_put_buffer(f, s->rx[i].data, sizeof(s->rx[i].data));
-
-    }
-    qemu_put_be32(f, s->next_packet);
-    qemu_put_be32(f, s->rx_fifo - s->rx[s->next_packet].data);
-    qemu_put_be32(f, s->rx_fifo_len);
-}
-
-static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id)
-{
-    stellaris_enet_state *s = (stellaris_enet_state *)opaque;
-    int i;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    s->ris = qemu_get_be32(f);
-    s->im = qemu_get_be32(f);
-    s->rctl = qemu_get_be32(f);
-    s->tctl = qemu_get_be32(f);
-    s->thr = qemu_get_be32(f);
-    s->mctl = qemu_get_be32(f);
-    s->mdv = qemu_get_be32(f);
-    s->mtxd = qemu_get_be32(f);
-    s->mrxd = qemu_get_be32(f);
-    s->np = qemu_get_be32(f);
-    s->tx_frame_len = qemu_get_be32(f);
-    s->tx_fifo_len = qemu_get_be32(f);
-    qemu_get_buffer(f, s->tx_fifo, sizeof(s->tx_fifo));
-    for (i = 0; i < 31; i++) {
-        s->rx[i].len = qemu_get_be32(f);
-        qemu_get_buffer(f, s->rx[i].data, sizeof(s->rx[i].data));
-
-    }
-    s->next_packet = qemu_get_be32(f);
-    s->rx_fifo = s->rx[s->next_packet].data + qemu_get_be32(f);
-    s->rx_fifo_len = qemu_get_be32(f);
-
-    return 0;
-}
-
-static void stellaris_enet_cleanup(NetClientState *nc)
-{
-    stellaris_enet_state *s = qemu_get_nic_opaque(nc);
-
-    unregister_savevm(&s->busdev.qdev, "stellaris_enet", s);
-
-    memory_region_destroy(&s->mmio);
-
-    g_free(s);
-}
-
-static NetClientInfo net_stellaris_enet_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = stellaris_enet_can_receive,
-    .receive = stellaris_enet_receive,
-    .cleanup = stellaris_enet_cleanup,
-};
-
-static int stellaris_enet_init(SysBusDevice *dev)
-{
-    stellaris_enet_state *s = FROM_SYSBUS(stellaris_enet_state, dev);
-
-    memory_region_init_io(&s->mmio, &stellaris_enet_ops, s, "stellaris_enet",
-                          0x1000);
-    sysbus_init_mmio(dev, &s->mmio);
-    sysbus_init_irq(dev, &s->irq);
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-
-    s->nic = qemu_new_nic(&net_stellaris_enet_info, &s->conf,
-                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-
-    stellaris_enet_reset(s);
-    register_savevm(&s->busdev.qdev, "stellaris_enet", -1, 1,
-                    stellaris_enet_save, stellaris_enet_load, s);
-    return 0;
-}
-
-static Property stellaris_enet_properties[] = {
-    DEFINE_NIC_PROPERTIES(stellaris_enet_state, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void stellaris_enet_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = stellaris_enet_init;
-    dc->props = stellaris_enet_properties;
-}
-
-static const TypeInfo stellaris_enet_info = {
-    .name          = "stellaris_enet",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(stellaris_enet_state),
-    .class_init    = stellaris_enet_class_init,
-};
-
-static void stellaris_enet_register_types(void)
-{
-    type_register_static(&stellaris_enet_info);
-}
-
-type_init(stellaris_enet_register_types)
diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c
deleted file mode 100644 (file)
index b2e3523..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * QEMU model of the Xilinx Ethernet Lite MAC.
- *
- * Copyright (c) 2009 Edgar E. Iglesias.
- *
- * 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 "hw/sysbus.h"
-#include "hw/hw.h"
-#include "net/net.h"
-
-#define D(x)
-#define R_TX_BUF0     0
-#define R_TX_LEN0     (0x07f4 / 4)
-#define R_TX_GIE0     (0x07f8 / 4)
-#define R_TX_CTRL0    (0x07fc / 4)
-#define R_TX_BUF1     (0x0800 / 4)
-#define R_TX_LEN1     (0x0ff4 / 4)
-#define R_TX_CTRL1    (0x0ffc / 4)
-
-#define R_RX_BUF0     (0x1000 / 4)
-#define R_RX_CTRL0    (0x17fc / 4)
-#define R_RX_BUF1     (0x1800 / 4)
-#define R_RX_CTRL1    (0x1ffc / 4)
-#define R_MAX         (0x2000 / 4)
-
-#define GIE_GIE    0x80000000
-
-#define CTRL_I     0x8
-#define CTRL_P     0x2
-#define CTRL_S     0x1
-
-struct xlx_ethlite
-{
-    SysBusDevice busdev;
-    MemoryRegion mmio;
-    qemu_irq irq;
-    NICState *nic;
-    NICConf conf;
-
-    uint32_t c_tx_pingpong;
-    uint32_t c_rx_pingpong;
-    unsigned int txbuf;
-    unsigned int rxbuf;
-
-    uint32_t regs[R_MAX];
-};
-
-static inline void eth_pulse_irq(struct xlx_ethlite *s)
-{
-    /* Only the first gie reg is active.  */
-    if (s->regs[R_TX_GIE0] & GIE_GIE) {
-        qemu_irq_pulse(s->irq);
-    }
-}
-
-static uint64_t
-eth_read(void *opaque, hwaddr addr, unsigned int size)
-{
-    struct xlx_ethlite *s = opaque;
-    uint32_t r = 0;
-
-    addr >>= 2;
-
-    switch (addr)
-    {
-        case R_TX_GIE0:
-        case R_TX_LEN0:
-        case R_TX_LEN1:
-        case R_TX_CTRL1:
-        case R_TX_CTRL0:
-        case R_RX_CTRL1:
-        case R_RX_CTRL0:
-            r = s->regs[addr];
-            D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr * 4, r));
-            break;
-
-        default:
-            r = tswap32(s->regs[addr]);
-            break;
-    }
-    return r;
-}
-
-static void
-eth_write(void *opaque, hwaddr addr,
-          uint64_t val64, unsigned int size)
-{
-    struct xlx_ethlite *s = opaque;
-    unsigned int base = 0;
-    uint32_t value = val64;
-
-    addr >>= 2;
-    switch (addr) 
-    {
-        case R_TX_CTRL0:
-        case R_TX_CTRL1:
-            if (addr == R_TX_CTRL1)
-                base = 0x800 / 4;
-
-            D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n",
-                       __func__, addr * 4, value));
-            if ((value & (CTRL_P | CTRL_S)) == CTRL_S) {
-                qemu_send_packet(qemu_get_queue(s->nic),
-                                 (void *) &s->regs[base],
-                                 s->regs[base + R_TX_LEN0]);
-                D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0]));
-                if (s->regs[base + R_TX_CTRL0] & CTRL_I)
-                    eth_pulse_irq(s);
-            } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) {
-                memcpy(&s->conf.macaddr.a[0], &s->regs[base], 6);
-                if (s->regs[base + R_TX_CTRL0] & CTRL_I)
-                    eth_pulse_irq(s);
-            }
-
-            /* We are fast and get ready pretty much immediately so
-               we actually never flip the S nor P bits to one.  */
-            s->regs[addr] = value & ~(CTRL_P | CTRL_S);
-            break;
-
-        /* Keep these native.  */
-        case R_RX_CTRL0:
-        case R_RX_CTRL1:
-            if (!(value & CTRL_S)) {
-                qemu_flush_queued_packets(qemu_get_queue(s->nic));
-            }
-        case R_TX_LEN0:
-        case R_TX_LEN1:
-        case R_TX_GIE0:
-            D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n",
-                       __func__, addr * 4, value));
-            s->regs[addr] = value;
-            break;
-
-        default:
-            s->regs[addr] = tswap32(value);
-            break;
-    }
-}
-
-static const MemoryRegionOps eth_ops = {
-    .read = eth_read,
-    .write = eth_write,
-    .endianness = DEVICE_NATIVE_ENDIAN,
-    .valid = {
-        .min_access_size = 4,
-        .max_access_size = 4
-    }
-};
-
-static int eth_can_rx(NetClientState *nc)
-{
-    struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
-    unsigned int rxbase = s->rxbuf * (0x800 / 4);
-
-    return !(s->regs[rxbase + R_RX_CTRL0] & CTRL_S);
-}
-
-static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size)
-{
-    struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
-    unsigned int rxbase = s->rxbuf * (0x800 / 4);
-
-    /* DA filter.  */
-    if (!(buf[0] & 0x80) && memcmp(&s->conf.macaddr.a[0], buf, 6))
-        return size;
-
-    if (s->regs[rxbase + R_RX_CTRL0] & CTRL_S) {
-        D(qemu_log("ethlite lost packet %x\n", s->regs[R_RX_CTRL0]));
-        return -1;
-    }
-
-    D(qemu_log("%s %zd rxbase=%x\n", __func__, size, rxbase));
-    memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size);
-
-    s->regs[rxbase + R_RX_CTRL0] |= CTRL_S;
-    if (s->regs[rxbase + R_RX_CTRL0] & CTRL_I)
-        eth_pulse_irq(s);
-
-    /* If c_rx_pingpong was set flip buffers.  */
-    s->rxbuf ^= s->c_rx_pingpong;
-    return size;
-}
-
-static void eth_cleanup(NetClientState *nc)
-{
-    struct xlx_ethlite *s = qemu_get_nic_opaque(nc);
-
-    s->nic = NULL;
-}
-
-static NetClientInfo net_xilinx_ethlite_info = {
-    .type = NET_CLIENT_OPTIONS_KIND_NIC,
-    .size = sizeof(NICState),
-    .can_receive = eth_can_rx,
-    .receive = eth_rx,
-    .cleanup = eth_cleanup,
-};
-
-static int xilinx_ethlite_init(SysBusDevice *dev)
-{
-    struct xlx_ethlite *s = FROM_SYSBUS(typeof (*s), dev);
-
-    sysbus_init_irq(dev, &s->irq);
-    s->rxbuf = 0;
-
-    memory_region_init_io(&s->mmio, &eth_ops, s, "xlnx.xps-ethernetlite",
-                                                                    R_MAX * 4);
-    sysbus_init_mmio(dev, &s->mmio);
-
-    qemu_macaddr_default_if_unset(&s->conf.macaddr);
-    s->nic = qemu_new_nic(&net_xilinx_ethlite_info, &s->conf,
-                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
-    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
-    return 0;
-}
-
-static Property xilinx_ethlite_properties[] = {
-    DEFINE_PROP_UINT32("tx-ping-pong", struct xlx_ethlite, c_tx_pingpong, 1),
-    DEFINE_PROP_UINT32("rx-ping-pong", struct xlx_ethlite, c_rx_pingpong, 1),
-    DEFINE_NIC_PROPERTIES(struct xlx_ethlite, conf),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
-static void xilinx_ethlite_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = xilinx_ethlite_init;
-    dc->props = xilinx_ethlite_properties;
-}
-
-static const TypeInfo xilinx_ethlite_info = {
-    .name          = "xlnx.xps-ethernetlite",
-    .parent        = TYPE_SYS_BUS_DEVICE,
-    .instance_size = sizeof(struct xlx_ethlite),
-    .class_init    = xilinx_ethlite_class_init,
-};
-
-static void xilinx_ethlite_register_types(void)
-{
-    type_register_static(&xilinx_ethlite_info);
-}
-
-type_init(xilinx_ethlite_register_types)