Statistics
| Branch: | Revision:

root / hw / mipsnet.c @ 37952117

History | View | Annotate | Download (7.2 kB)

1 87ecb68b pbrook
#include "hw.h"
2 87ecb68b pbrook
#include "net.h"
3 83818f7c Hervé Poussineau
#include "trace.h"
4 d118d64a Hervé Poussineau
#include "sysbus.h"
5 f0fc6f8f ths
6 f0fc6f8f ths
/* MIPSnet register offsets */
7 f0fc6f8f ths
8 f0fc6f8f ths
#define MIPSNET_DEV_ID                0x00
9 f0fc6f8f ths
#define MIPSNET_BUSY                0x08
10 f0fc6f8f ths
#define MIPSNET_RX_DATA_COUNT        0x0c
11 f0fc6f8f ths
#define MIPSNET_TX_DATA_COUNT        0x10
12 f0fc6f8f ths
#define MIPSNET_INT_CTL                0x14
13 f0fc6f8f ths
# define MIPSNET_INTCTL_TXDONE                0x00000001
14 f0fc6f8f ths
# define MIPSNET_INTCTL_RXDONE                0x00000002
15 f0fc6f8f ths
# define MIPSNET_INTCTL_TESTBIT                0x80000000
16 f0fc6f8f ths
#define MIPSNET_INTERRUPT_INFO        0x18
17 f0fc6f8f ths
#define MIPSNET_RX_DATA_BUFFER        0x1c
18 f0fc6f8f ths
#define MIPSNET_TX_DATA_BUFFER        0x20
19 f0fc6f8f ths
20 f0fc6f8f ths
#define MAX_ETH_FRAME_SIZE        1514
21 f0fc6f8f ths
22 f0fc6f8f ths
typedef struct MIPSnetState {
23 d118d64a Hervé Poussineau
    SysBusDevice busdev;
24 d118d64a Hervé Poussineau
25 f0fc6f8f ths
    uint32_t busy;
26 f0fc6f8f ths
    uint32_t rx_count;
27 f0fc6f8f ths
    uint32_t rx_read;
28 f0fc6f8f ths
    uint32_t tx_count;
29 f0fc6f8f ths
    uint32_t tx_written;
30 f0fc6f8f ths
    uint32_t intctl;
31 f0fc6f8f ths
    uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
32 f0fc6f8f ths
    uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
33 d118d64a Hervé Poussineau
    MemoryRegion io;
34 f0fc6f8f ths
    qemu_irq irq;
35 1f30d10a Mark McLoughlin
    NICState *nic;
36 1f30d10a Mark McLoughlin
    NICConf conf;
37 f0fc6f8f ths
} MIPSnetState;
38 f0fc6f8f ths
39 f0fc6f8f ths
static void mipsnet_reset(MIPSnetState *s)
40 f0fc6f8f ths
{
41 f0fc6f8f ths
    s->busy = 1;
42 f0fc6f8f ths
    s->rx_count = 0;
43 f0fc6f8f ths
    s->rx_read = 0;
44 f0fc6f8f ths
    s->tx_count = 0;
45 f0fc6f8f ths
    s->tx_written = 0;
46 f0fc6f8f ths
    s->intctl = 0;
47 f0fc6f8f ths
    memset(s->rx_buffer, 0, MAX_ETH_FRAME_SIZE);
48 f0fc6f8f ths
    memset(s->tx_buffer, 0, MAX_ETH_FRAME_SIZE);
49 f0fc6f8f ths
}
50 f0fc6f8f ths
51 f0fc6f8f ths
static void mipsnet_update_irq(MIPSnetState *s)
52 f0fc6f8f ths
{
53 f0fc6f8f ths
    int isr = !!s->intctl;
54 83818f7c Hervé Poussineau
    trace_mipsnet_irq(isr, s->intctl);
55 f0fc6f8f ths
    qemu_set_irq(s->irq, isr);
56 f0fc6f8f ths
}
57 f0fc6f8f ths
58 f0fc6f8f ths
static int mipsnet_buffer_full(MIPSnetState *s)
59 f0fc6f8f ths
{
60 f0fc6f8f ths
    if (s->rx_count >= MAX_ETH_FRAME_SIZE)
61 f0fc6f8f ths
        return 1;
62 f0fc6f8f ths
    return 0;
63 f0fc6f8f ths
}
64 f0fc6f8f ths
65 1f30d10a Mark McLoughlin
static int mipsnet_can_receive(VLANClientState *nc)
66 f0fc6f8f ths
{
67 1f30d10a Mark McLoughlin
    MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
68 f0fc6f8f ths
69 f0fc6f8f ths
    if (s->busy)
70 f0fc6f8f ths
        return 0;
71 f0fc6f8f ths
    return !mipsnet_buffer_full(s);
72 f0fc6f8f ths
}
73 f0fc6f8f ths
74 1f30d10a Mark McLoughlin
static ssize_t mipsnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
75 f0fc6f8f ths
{
76 1f30d10a Mark McLoughlin
    MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
77 f0fc6f8f ths
78 83818f7c Hervé Poussineau
    trace_mipsnet_receive(size);
79 1f30d10a Mark McLoughlin
    if (!mipsnet_can_receive(nc))
80 4f1c942b Mark McLoughlin
        return -1;
81 f0fc6f8f ths
82 f0fc6f8f ths
    s->busy = 1;
83 f0fc6f8f ths
84 f0fc6f8f ths
    /* Just accept everything. */
85 f0fc6f8f ths
86 f0fc6f8f ths
    /* Write packet data. */
87 f0fc6f8f ths
    memcpy(s->rx_buffer, buf, size);
88 f0fc6f8f ths
89 f0fc6f8f ths
    s->rx_count = size;
90 f0fc6f8f ths
    s->rx_read = 0;
91 f0fc6f8f ths
92 f0fc6f8f ths
    /* Now we can signal we have received something. */
93 f0fc6f8f ths
    s->intctl |= MIPSNET_INTCTL_RXDONE;
94 f0fc6f8f ths
    mipsnet_update_irq(s);
95 4f1c942b Mark McLoughlin
96 4f1c942b Mark McLoughlin
    return size;
97 f0fc6f8f ths
}
98 f0fc6f8f ths
99 d118d64a Hervé Poussineau
static uint64_t mipsnet_ioport_read(void *opaque, target_phys_addr_t addr,
100 d118d64a Hervé Poussineau
                                    unsigned int size)
101 f0fc6f8f ths
{
102 f0fc6f8f ths
    MIPSnetState *s = opaque;
103 f0fc6f8f ths
    int ret = 0;
104 f0fc6f8f ths
105 f0fc6f8f ths
    addr &= 0x3f;
106 f0fc6f8f ths
    switch (addr) {
107 f0fc6f8f ths
    case MIPSNET_DEV_ID:
108 9b595395 aurel32
        ret = be32_to_cpu(0x4d495053);                /* MIPS */
109 f0fc6f8f ths
        break;
110 f0fc6f8f ths
    case MIPSNET_DEV_ID + 4:
111 9b595395 aurel32
        ret = be32_to_cpu(0x4e455430);                /* NET0 */
112 f0fc6f8f ths
        break;
113 f0fc6f8f ths
    case MIPSNET_BUSY:
114 f0fc6f8f ths
        ret = s->busy;
115 f0fc6f8f ths
        break;
116 f0fc6f8f ths
    case MIPSNET_RX_DATA_COUNT:
117 f0fc6f8f ths
        ret = s->rx_count;
118 f0fc6f8f ths
        break;
119 f0fc6f8f ths
    case MIPSNET_TX_DATA_COUNT:
120 f0fc6f8f ths
        ret = s->tx_count;
121 f0fc6f8f ths
        break;
122 f0fc6f8f ths
    case MIPSNET_INT_CTL:
123 f0fc6f8f ths
        ret = s->intctl;
124 f0fc6f8f ths
        s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
125 f0fc6f8f ths
        break;
126 f0fc6f8f ths
    case MIPSNET_INTERRUPT_INFO:
127 f0fc6f8f ths
        /* XXX: This seems to be a per-VPE interrupt number. */
128 f0fc6f8f ths
        ret = 0;
129 f0fc6f8f ths
        break;
130 f0fc6f8f ths
    case MIPSNET_RX_DATA_BUFFER:
131 f0fc6f8f ths
        if (s->rx_count) {
132 f0fc6f8f ths
            s->rx_count--;
133 f0fc6f8f ths
            ret = s->rx_buffer[s->rx_read++];
134 f0fc6f8f ths
        }
135 f0fc6f8f ths
        break;
136 f0fc6f8f ths
    /* Reads as zero. */
137 f0fc6f8f ths
    case MIPSNET_TX_DATA_BUFFER:
138 f0fc6f8f ths
    default:
139 f0fc6f8f ths
        break;
140 f0fc6f8f ths
    }
141 83818f7c Hervé Poussineau
    trace_mipsnet_read(addr, ret);
142 f0fc6f8f ths
    return ret;
143 f0fc6f8f ths
}
144 f0fc6f8f ths
145 d118d64a Hervé Poussineau
static void mipsnet_ioport_write(void *opaque, target_phys_addr_t addr,
146 d118d64a Hervé Poussineau
                                 uint64_t val, unsigned int size)
147 f0fc6f8f ths
{
148 f0fc6f8f ths
    MIPSnetState *s = opaque;
149 f0fc6f8f ths
150 f0fc6f8f ths
    addr &= 0x3f;
151 83818f7c Hervé Poussineau
    trace_mipsnet_write(addr, val);
152 f0fc6f8f ths
    switch (addr) {
153 f0fc6f8f ths
    case MIPSNET_TX_DATA_COUNT:
154 f0fc6f8f ths
        s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
155 f0fc6f8f ths
        s->tx_written = 0;
156 f0fc6f8f ths
        break;
157 f0fc6f8f ths
    case MIPSNET_INT_CTL:
158 f0fc6f8f ths
        if (val & MIPSNET_INTCTL_TXDONE) {
159 f0fc6f8f ths
            s->intctl &= ~MIPSNET_INTCTL_TXDONE;
160 f0fc6f8f ths
        } else if (val & MIPSNET_INTCTL_RXDONE) {
161 f0fc6f8f ths
            s->intctl &= ~MIPSNET_INTCTL_RXDONE;
162 f0fc6f8f ths
        } else if (val & MIPSNET_INTCTL_TESTBIT) {
163 f0fc6f8f ths
            mipsnet_reset(s);
164 f0fc6f8f ths
            s->intctl |= MIPSNET_INTCTL_TESTBIT;
165 f0fc6f8f ths
        } else if (!val) {
166 f0fc6f8f ths
            /* ACK testbit interrupt, flag was cleared on read. */
167 f0fc6f8f ths
        }
168 f0fc6f8f ths
        s->busy = !!s->intctl;
169 f0fc6f8f ths
        mipsnet_update_irq(s);
170 f0fc6f8f ths
        break;
171 f0fc6f8f ths
    case MIPSNET_TX_DATA_BUFFER:
172 f0fc6f8f ths
        s->tx_buffer[s->tx_written++] = val;
173 f0fc6f8f ths
        if (s->tx_written == s->tx_count) {
174 f0fc6f8f ths
            /* Send buffer. */
175 83818f7c Hervé Poussineau
            trace_mipsnet_send(s->tx_count);
176 1f30d10a Mark McLoughlin
            qemu_send_packet(&s->nic->nc, s->tx_buffer, s->tx_count);
177 f0fc6f8f ths
            s->tx_count = s->tx_written = 0;
178 f0fc6f8f ths
            s->intctl |= MIPSNET_INTCTL_TXDONE;
179 f0fc6f8f ths
            s->busy = 1;
180 f0fc6f8f ths
            mipsnet_update_irq(s);
181 f0fc6f8f ths
        }
182 f0fc6f8f ths
        break;
183 f0fc6f8f ths
    /* Read-only registers */
184 f0fc6f8f ths
    case MIPSNET_DEV_ID:
185 f0fc6f8f ths
    case MIPSNET_BUSY:
186 f0fc6f8f ths
    case MIPSNET_RX_DATA_COUNT:
187 f0fc6f8f ths
    case MIPSNET_INTERRUPT_INFO:
188 f0fc6f8f ths
    case MIPSNET_RX_DATA_BUFFER:
189 f0fc6f8f ths
    default:
190 f0fc6f8f ths
        break;
191 f0fc6f8f ths
    }
192 f0fc6f8f ths
}
193 f0fc6f8f ths
194 c7298ab2 Juan Quintela
static const VMStateDescription vmstate_mipsnet = {
195 c7298ab2 Juan Quintela
    .name = "mipsnet",
196 c7298ab2 Juan Quintela
    .version_id = 0,
197 c7298ab2 Juan Quintela
    .minimum_version_id = 0,
198 c7298ab2 Juan Quintela
    .minimum_version_id_old = 0,
199 c7298ab2 Juan Quintela
    .fields      = (VMStateField[]) {
200 c7298ab2 Juan Quintela
        VMSTATE_UINT32(busy, MIPSnetState),
201 c7298ab2 Juan Quintela
        VMSTATE_UINT32(rx_count, MIPSnetState),
202 c7298ab2 Juan Quintela
        VMSTATE_UINT32(rx_read, MIPSnetState),
203 c7298ab2 Juan Quintela
        VMSTATE_UINT32(tx_count, MIPSnetState),
204 c7298ab2 Juan Quintela
        VMSTATE_UINT32(tx_written, MIPSnetState),
205 c7298ab2 Juan Quintela
        VMSTATE_UINT32(intctl, MIPSnetState),
206 c7298ab2 Juan Quintela
        VMSTATE_BUFFER(rx_buffer, MIPSnetState),
207 c7298ab2 Juan Quintela
        VMSTATE_BUFFER(tx_buffer, MIPSnetState),
208 c7298ab2 Juan Quintela
        VMSTATE_END_OF_LIST()
209 c7298ab2 Juan Quintela
    }
210 c7298ab2 Juan Quintela
};
211 f0fc6f8f ths
212 1f30d10a Mark McLoughlin
static void mipsnet_cleanup(VLANClientState *nc)
213 b946a153 aliguori
{
214 1f30d10a Mark McLoughlin
    MIPSnetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
215 b946a153 aliguori
216 d118d64a Hervé Poussineau
    s->nic = NULL;
217 b946a153 aliguori
}
218 b946a153 aliguori
219 1f30d10a Mark McLoughlin
static NetClientInfo net_mipsnet_info = {
220 1f30d10a Mark McLoughlin
    .type = NET_CLIENT_TYPE_NIC,
221 1f30d10a Mark McLoughlin
    .size = sizeof(NICState),
222 1f30d10a Mark McLoughlin
    .can_receive = mipsnet_can_receive,
223 1f30d10a Mark McLoughlin
    .receive = mipsnet_receive,
224 1f30d10a Mark McLoughlin
    .cleanup = mipsnet_cleanup,
225 1f30d10a Mark McLoughlin
};
226 1f30d10a Mark McLoughlin
227 a348f108 Stefan Weil
static const MemoryRegionOps mipsnet_ioport_ops = {
228 d118d64a Hervé Poussineau
    .read = mipsnet_ioport_read,
229 d118d64a Hervé Poussineau
    .write = mipsnet_ioport_write,
230 d118d64a Hervé Poussineau
    .impl.min_access_size = 1,
231 d118d64a Hervé Poussineau
    .impl.max_access_size = 4,
232 d118d64a Hervé Poussineau
};
233 0ae18cee aliguori
234 d118d64a Hervé Poussineau
static int mipsnet_sysbus_init(SysBusDevice *dev)
235 d118d64a Hervé Poussineau
{
236 d118d64a Hervé Poussineau
    MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev, dev);
237 f0fc6f8f ths
238 d118d64a Hervé Poussineau
    memory_region_init_io(&s->io, &mipsnet_ioport_ops, s, "mipsnet-io", 36);
239 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->io);
240 d118d64a Hervé Poussineau
    sysbus_init_irq(dev, &s->irq);
241 f0fc6f8f ths
242 d118d64a Hervé Poussineau
    s->nic = qemu_new_nic(&net_mipsnet_info, &s->conf,
243 f79f2bfc Anthony Liguori
                          object_get_typename(OBJECT(dev)), dev->qdev.id, s);
244 d118d64a Hervé Poussineau
    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
245 1f30d10a Mark McLoughlin
246 d118d64a Hervé Poussineau
    return 0;
247 d118d64a Hervé Poussineau
}
248 f0fc6f8f ths
249 d118d64a Hervé Poussineau
static void mipsnet_sysbus_reset(DeviceState *dev)
250 d118d64a Hervé Poussineau
{
251 d118d64a Hervé Poussineau
    MIPSnetState *s = DO_UPCAST(MIPSnetState, busdev.qdev, dev);
252 d118d64a Hervé Poussineau
    mipsnet_reset(s);
253 d118d64a Hervé Poussineau
}
254 1f30d10a Mark McLoughlin
255 999e12bb Anthony Liguori
static Property mipsnet_properties[] = {
256 999e12bb Anthony Liguori
    DEFINE_NIC_PROPERTIES(MIPSnetState, conf),
257 999e12bb Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
258 999e12bb Anthony Liguori
};
259 999e12bb Anthony Liguori
260 999e12bb Anthony Liguori
static void mipsnet_class_init(ObjectClass *klass, void *data)
261 999e12bb Anthony Liguori
{
262 39bffca2 Anthony Liguori
    DeviceClass *dc = DEVICE_CLASS(klass);
263 999e12bb Anthony Liguori
    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
264 999e12bb Anthony Liguori
265 999e12bb Anthony Liguori
    k->init = mipsnet_sysbus_init;
266 39bffca2 Anthony Liguori
    dc->desc = "MIPS Simulator network device";
267 39bffca2 Anthony Liguori
    dc->reset = mipsnet_sysbus_reset;
268 39bffca2 Anthony Liguori
    dc->vmsd = &vmstate_mipsnet;
269 39bffca2 Anthony Liguori
    dc->props = mipsnet_properties;
270 999e12bb Anthony Liguori
}
271 999e12bb Anthony Liguori
272 39bffca2 Anthony Liguori
static TypeInfo mipsnet_info = {
273 39bffca2 Anthony Liguori
    .name          = "mipsnet",
274 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
275 39bffca2 Anthony Liguori
    .instance_size = sizeof(MIPSnetState),
276 39bffca2 Anthony Liguori
    .class_init    = mipsnet_class_init,
277 d118d64a Hervé Poussineau
};
278 f0fc6f8f ths
279 83f7d43a Andreas Färber
static void mipsnet_register_types(void)
280 d118d64a Hervé Poussineau
{
281 39bffca2 Anthony Liguori
    type_register_static(&mipsnet_info);
282 f0fc6f8f ths
}
283 d118d64a Hervé Poussineau
284 83f7d43a Andreas Färber
type_init(mipsnet_register_types)