Statistics
| Branch: | Revision:

root / hw / xilinx_axienet.c @ 39ac8455

History | View | Annotate | Download (22.2 kB)

1 93f1e401 Edgar E. Iglesias
/*
2 93f1e401 Edgar E. Iglesias
 * QEMU model of Xilinx AXI-Ethernet.
3 93f1e401 Edgar E. Iglesias
 *
4 93f1e401 Edgar E. Iglesias
 * Copyright (c) 2011 Edgar E. Iglesias.
5 93f1e401 Edgar E. Iglesias
 *
6 93f1e401 Edgar E. Iglesias
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 93f1e401 Edgar E. Iglesias
 * of this software and associated documentation files (the "Software"), to deal
8 93f1e401 Edgar E. Iglesias
 * in the Software without restriction, including without limitation the rights
9 93f1e401 Edgar E. Iglesias
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 93f1e401 Edgar E. Iglesias
 * copies of the Software, and to permit persons to whom the Software is
11 93f1e401 Edgar E. Iglesias
 * furnished to do so, subject to the following conditions:
12 93f1e401 Edgar E. Iglesias
 *
13 93f1e401 Edgar E. Iglesias
 * The above copyright notice and this permission notice shall be included in
14 93f1e401 Edgar E. Iglesias
 * all copies or substantial portions of the Software.
15 93f1e401 Edgar E. Iglesias
 *
16 93f1e401 Edgar E. Iglesias
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 93f1e401 Edgar E. Iglesias
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 93f1e401 Edgar E. Iglesias
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 93f1e401 Edgar E. Iglesias
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 93f1e401 Edgar E. Iglesias
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 93f1e401 Edgar E. Iglesias
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 93f1e401 Edgar E. Iglesias
 * THE SOFTWARE.
23 93f1e401 Edgar E. Iglesias
 */
24 93f1e401 Edgar E. Iglesias
25 93f1e401 Edgar E. Iglesias
#include "sysbus.h"
26 93f1e401 Edgar E. Iglesias
#include "qemu-char.h"
27 93f1e401 Edgar E. Iglesias
#include "qemu-log.h"
28 93f1e401 Edgar E. Iglesias
#include "net.h"
29 93f1e401 Edgar E. Iglesias
#include "net/checksum.h"
30 93f1e401 Edgar E. Iglesias
31 93f1e401 Edgar E. Iglesias
#include "xilinx_axidma.h"
32 93f1e401 Edgar E. Iglesias
33 93f1e401 Edgar E. Iglesias
#define DPHY(x)
34 93f1e401 Edgar E. Iglesias
35 93f1e401 Edgar E. Iglesias
/* Advertisement control register. */
36 93f1e401 Edgar E. Iglesias
#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
37 93f1e401 Edgar E. Iglesias
#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
38 93f1e401 Edgar E. Iglesias
#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
39 93f1e401 Edgar E. Iglesias
#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
40 93f1e401 Edgar E. Iglesias
41 93f1e401 Edgar E. Iglesias
struct PHY {
42 93f1e401 Edgar E. Iglesias
    uint32_t regs[32];
43 93f1e401 Edgar E. Iglesias
44 93f1e401 Edgar E. Iglesias
    int link;
45 93f1e401 Edgar E. Iglesias
46 93f1e401 Edgar E. Iglesias
    unsigned int (*read)(struct PHY *phy, unsigned int req);
47 93f1e401 Edgar E. Iglesias
    void (*write)(struct PHY *phy, unsigned int req,
48 93f1e401 Edgar E. Iglesias
                  unsigned int data);
49 93f1e401 Edgar E. Iglesias
};
50 93f1e401 Edgar E. Iglesias
51 93f1e401 Edgar E. Iglesias
static unsigned int tdk_read(struct PHY *phy, unsigned int req)
52 93f1e401 Edgar E. Iglesias
{
53 93f1e401 Edgar E. Iglesias
    int regnum;
54 93f1e401 Edgar E. Iglesias
    unsigned r = 0;
55 93f1e401 Edgar E. Iglesias
56 93f1e401 Edgar E. Iglesias
    regnum = req & 0x1f;
57 93f1e401 Edgar E. Iglesias
58 93f1e401 Edgar E. Iglesias
    switch (regnum) {
59 93f1e401 Edgar E. Iglesias
        case 1:
60 93f1e401 Edgar E. Iglesias
            if (!phy->link) {
61 93f1e401 Edgar E. Iglesias
                break;
62 93f1e401 Edgar E. Iglesias
            }
63 93f1e401 Edgar E. Iglesias
            /* MR1.  */
64 93f1e401 Edgar E. Iglesias
            /* Speeds and modes.  */
65 93f1e401 Edgar E. Iglesias
            r |= (1 << 13) | (1 << 14);
66 93f1e401 Edgar E. Iglesias
            r |= (1 << 11) | (1 << 12);
67 93f1e401 Edgar E. Iglesias
            r |= (1 << 5); /* Autoneg complete.  */
68 93f1e401 Edgar E. Iglesias
            r |= (1 << 3); /* Autoneg able.  */
69 93f1e401 Edgar E. Iglesias
            r |= (1 << 2); /* link.  */
70 93f1e401 Edgar E. Iglesias
            r |= (1 << 1); /* link.  */
71 93f1e401 Edgar E. Iglesias
            break;
72 93f1e401 Edgar E. Iglesias
        case 5:
73 93f1e401 Edgar E. Iglesias
            /* Link partner ability.
74 93f1e401 Edgar E. Iglesias
               We are kind; always agree with whatever best mode
75 93f1e401 Edgar E. Iglesias
               the guest advertises.  */
76 93f1e401 Edgar E. Iglesias
            r = 1 << 14; /* Success.  */
77 93f1e401 Edgar E. Iglesias
            /* Copy advertised modes.  */
78 93f1e401 Edgar E. Iglesias
            r |= phy->regs[4] & (15 << 5);
79 93f1e401 Edgar E. Iglesias
            /* Autoneg support.  */
80 93f1e401 Edgar E. Iglesias
            r |= 1;
81 93f1e401 Edgar E. Iglesias
            break;
82 93f1e401 Edgar E. Iglesias
        case 17:
83 93f1e401 Edgar E. Iglesias
            /* Marvel PHY on many xilinx boards.  */
84 93f1e401 Edgar E. Iglesias
            r = 0x8000; /* 1000Mb  */
85 93f1e401 Edgar E. Iglesias
            break;
86 93f1e401 Edgar E. Iglesias
        case 18:
87 93f1e401 Edgar E. Iglesias
            {
88 93f1e401 Edgar E. Iglesias
                /* Diagnostics reg.  */
89 93f1e401 Edgar E. Iglesias
                int duplex = 0;
90 93f1e401 Edgar E. Iglesias
                int speed_100 = 0;
91 93f1e401 Edgar E. Iglesias
92 93f1e401 Edgar E. Iglesias
                if (!phy->link) {
93 93f1e401 Edgar E. Iglesias
                    break;
94 93f1e401 Edgar E. Iglesias
                }
95 93f1e401 Edgar E. Iglesias
96 93f1e401 Edgar E. Iglesias
                /* Are we advertising 100 half or 100 duplex ? */
97 93f1e401 Edgar E. Iglesias
                speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
98 93f1e401 Edgar E. Iglesias
                speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
99 93f1e401 Edgar E. Iglesias
100 93f1e401 Edgar E. Iglesias
                /* Are we advertising 10 duplex or 100 duplex ? */
101 93f1e401 Edgar E. Iglesias
                duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
102 93f1e401 Edgar E. Iglesias
                duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
103 93f1e401 Edgar E. Iglesias
                r = (speed_100 << 10) | (duplex << 11);
104 93f1e401 Edgar E. Iglesias
            }
105 93f1e401 Edgar E. Iglesias
            break;
106 93f1e401 Edgar E. Iglesias
107 93f1e401 Edgar E. Iglesias
        default:
108 93f1e401 Edgar E. Iglesias
            r = phy->regs[regnum];
109 93f1e401 Edgar E. Iglesias
            break;
110 93f1e401 Edgar E. Iglesias
    }
111 93f1e401 Edgar E. Iglesias
    DPHY(qemu_log("\n%s %x = reg[%d]\n", __func__, r, regnum));
112 93f1e401 Edgar E. Iglesias
    return r;
113 93f1e401 Edgar E. Iglesias
}
114 93f1e401 Edgar E. Iglesias
115 93f1e401 Edgar E. Iglesias
static void
116 93f1e401 Edgar E. Iglesias
tdk_write(struct PHY *phy, unsigned int req, unsigned int data)
117 93f1e401 Edgar E. Iglesias
{
118 93f1e401 Edgar E. Iglesias
    int regnum;
119 93f1e401 Edgar E. Iglesias
120 93f1e401 Edgar E. Iglesias
    regnum = req & 0x1f;
121 93f1e401 Edgar E. Iglesias
    DPHY(qemu_log("%s reg[%d] = %x\n", __func__, regnum, data));
122 93f1e401 Edgar E. Iglesias
    switch (regnum) {
123 93f1e401 Edgar E. Iglesias
        default:
124 93f1e401 Edgar E. Iglesias
            phy->regs[regnum] = data;
125 93f1e401 Edgar E. Iglesias
            break;
126 93f1e401 Edgar E. Iglesias
    }
127 93f1e401 Edgar E. Iglesias
}
128 93f1e401 Edgar E. Iglesias
129 93f1e401 Edgar E. Iglesias
static void
130 93f1e401 Edgar E. Iglesias
tdk_init(struct PHY *phy)
131 93f1e401 Edgar E. Iglesias
{
132 93f1e401 Edgar E. Iglesias
    phy->regs[0] = 0x3100;
133 93f1e401 Edgar E. Iglesias
    /* PHY Id.  */
134 93f1e401 Edgar E. Iglesias
    phy->regs[2] = 0x0300;
135 93f1e401 Edgar E. Iglesias
    phy->regs[3] = 0xe400;
136 93f1e401 Edgar E. Iglesias
    /* Autonegotiation advertisement reg.  */
137 93f1e401 Edgar E. Iglesias
    phy->regs[4] = 0x01E1;
138 93f1e401 Edgar E. Iglesias
    phy->link = 1;
139 93f1e401 Edgar E. Iglesias
140 93f1e401 Edgar E. Iglesias
    phy->read = tdk_read;
141 93f1e401 Edgar E. Iglesias
    phy->write = tdk_write;
142 93f1e401 Edgar E. Iglesias
}
143 93f1e401 Edgar E. Iglesias
144 93f1e401 Edgar E. Iglesias
struct MDIOBus {
145 93f1e401 Edgar E. Iglesias
    /* bus.  */
146 93f1e401 Edgar E. Iglesias
    int mdc;
147 93f1e401 Edgar E. Iglesias
    int mdio;
148 93f1e401 Edgar E. Iglesias
149 93f1e401 Edgar E. Iglesias
    /* decoder.  */
150 93f1e401 Edgar E. Iglesias
    enum {
151 93f1e401 Edgar E. Iglesias
        PREAMBLE,
152 93f1e401 Edgar E. Iglesias
        SOF,
153 93f1e401 Edgar E. Iglesias
        OPC,
154 93f1e401 Edgar E. Iglesias
        ADDR,
155 93f1e401 Edgar E. Iglesias
        REQ,
156 93f1e401 Edgar E. Iglesias
        TURNAROUND,
157 93f1e401 Edgar E. Iglesias
        DATA
158 93f1e401 Edgar E. Iglesias
    } state;
159 93f1e401 Edgar E. Iglesias
    unsigned int drive;
160 93f1e401 Edgar E. Iglesias
161 93f1e401 Edgar E. Iglesias
    unsigned int cnt;
162 93f1e401 Edgar E. Iglesias
    unsigned int addr;
163 93f1e401 Edgar E. Iglesias
    unsigned int opc;
164 93f1e401 Edgar E. Iglesias
    unsigned int req;
165 93f1e401 Edgar E. Iglesias
    unsigned int data;
166 93f1e401 Edgar E. Iglesias
167 93f1e401 Edgar E. Iglesias
    struct PHY *devs[32];
168 93f1e401 Edgar E. Iglesias
};
169 93f1e401 Edgar E. Iglesias
170 93f1e401 Edgar E. Iglesias
static void
171 93f1e401 Edgar E. Iglesias
mdio_attach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
172 93f1e401 Edgar E. Iglesias
{
173 93f1e401 Edgar E. Iglesias
    bus->devs[addr & 0x1f] = phy;
174 93f1e401 Edgar E. Iglesias
}
175 93f1e401 Edgar E. Iglesias
176 93f1e401 Edgar E. Iglesias
#ifdef USE_THIS_DEAD_CODE
177 93f1e401 Edgar E. Iglesias
static void
178 93f1e401 Edgar E. Iglesias
mdio_detach(struct MDIOBus *bus, struct PHY *phy, unsigned int addr)
179 93f1e401 Edgar E. Iglesias
{
180 93f1e401 Edgar E. Iglesias
    bus->devs[addr & 0x1f] = NULL;
181 93f1e401 Edgar E. Iglesias
}
182 93f1e401 Edgar E. Iglesias
#endif
183 93f1e401 Edgar E. Iglesias
184 93f1e401 Edgar E. Iglesias
static uint16_t mdio_read_req(struct MDIOBus *bus, unsigned int addr,
185 93f1e401 Edgar E. Iglesias
                  unsigned int reg)
186 93f1e401 Edgar E. Iglesias
{
187 93f1e401 Edgar E. Iglesias
    struct PHY *phy;
188 93f1e401 Edgar E. Iglesias
    uint16_t data;
189 93f1e401 Edgar E. Iglesias
190 93f1e401 Edgar E. Iglesias
    phy = bus->devs[addr];
191 93f1e401 Edgar E. Iglesias
    if (phy && phy->read) {
192 93f1e401 Edgar E. Iglesias
        data = phy->read(phy, reg);
193 93f1e401 Edgar E. Iglesias
    } else {
194 93f1e401 Edgar E. Iglesias
        data = 0xffff;
195 93f1e401 Edgar E. Iglesias
    }
196 93f1e401 Edgar E. Iglesias
    DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
197 93f1e401 Edgar E. Iglesias
    return data;
198 93f1e401 Edgar E. Iglesias
}
199 93f1e401 Edgar E. Iglesias
200 93f1e401 Edgar E. Iglesias
static void mdio_write_req(struct MDIOBus *bus, unsigned int addr,
201 93f1e401 Edgar E. Iglesias
               unsigned int reg, uint16_t data)
202 93f1e401 Edgar E. Iglesias
{
203 93f1e401 Edgar E. Iglesias
    struct PHY *phy;
204 93f1e401 Edgar E. Iglesias
205 93f1e401 Edgar E. Iglesias
    DPHY(qemu_log("%s addr=%d reg=%d data=%x\n", __func__, addr, reg, data));
206 93f1e401 Edgar E. Iglesias
    phy = bus->devs[addr];
207 93f1e401 Edgar E. Iglesias
    if (phy && phy->write) {
208 93f1e401 Edgar E. Iglesias
        phy->write(phy, reg, data);
209 93f1e401 Edgar E. Iglesias
    }
210 93f1e401 Edgar E. Iglesias
}
211 93f1e401 Edgar E. Iglesias
212 93f1e401 Edgar E. Iglesias
#define DENET(x)
213 93f1e401 Edgar E. Iglesias
214 93f1e401 Edgar E. Iglesias
#define R_RAF      (0x000 / 4)
215 93f1e401 Edgar E. Iglesias
enum {
216 93f1e401 Edgar E. Iglesias
    RAF_MCAST_REJ = (1 << 1),
217 93f1e401 Edgar E. Iglesias
    RAF_BCAST_REJ = (1 << 2),
218 93f1e401 Edgar E. Iglesias
    RAF_EMCF_EN = (1 << 12),
219 93f1e401 Edgar E. Iglesias
    RAF_NEWFUNC_EN = (1 << 11)
220 93f1e401 Edgar E. Iglesias
};
221 93f1e401 Edgar E. Iglesias
222 93f1e401 Edgar E. Iglesias
#define R_IS       (0x00C / 4)
223 93f1e401 Edgar E. Iglesias
enum {
224 93f1e401 Edgar E. Iglesias
    IS_HARD_ACCESS_COMPLETE = 1,
225 93f1e401 Edgar E. Iglesias
    IS_AUTONEG = (1 << 1),
226 93f1e401 Edgar E. Iglesias
    IS_RX_COMPLETE = (1 << 2),
227 93f1e401 Edgar E. Iglesias
    IS_RX_REJECT = (1 << 3),
228 93f1e401 Edgar E. Iglesias
    IS_TX_COMPLETE = (1 << 5),
229 93f1e401 Edgar E. Iglesias
    IS_RX_DCM_LOCK = (1 << 6),
230 93f1e401 Edgar E. Iglesias
    IS_MGM_RDY = (1 << 7),
231 93f1e401 Edgar E. Iglesias
    IS_PHY_RST_DONE = (1 << 8),
232 93f1e401 Edgar E. Iglesias
};
233 93f1e401 Edgar E. Iglesias
234 93f1e401 Edgar E. Iglesias
#define R_IP       (0x010 / 4)
235 93f1e401 Edgar E. Iglesias
#define R_IE       (0x014 / 4)
236 93f1e401 Edgar E. Iglesias
#define R_UAWL     (0x020 / 4)
237 93f1e401 Edgar E. Iglesias
#define R_UAWU     (0x024 / 4)
238 93f1e401 Edgar E. Iglesias
#define R_PPST     (0x030 / 4)
239 93f1e401 Edgar E. Iglesias
enum {
240 93f1e401 Edgar E. Iglesias
    PPST_LINKSTATUS = (1 << 0),
241 93f1e401 Edgar E. Iglesias
    PPST_PHY_LINKSTATUS = (1 << 7),
242 93f1e401 Edgar E. Iglesias
};
243 93f1e401 Edgar E. Iglesias
244 93f1e401 Edgar E. Iglesias
#define R_STATS_RX_BYTESL (0x200 / 4)
245 93f1e401 Edgar E. Iglesias
#define R_STATS_RX_BYTESH (0x204 / 4)
246 93f1e401 Edgar E. Iglesias
#define R_STATS_TX_BYTESL (0x208 / 4)
247 93f1e401 Edgar E. Iglesias
#define R_STATS_TX_BYTESH (0x20C / 4)
248 93f1e401 Edgar E. Iglesias
#define R_STATS_RXL       (0x290 / 4)
249 93f1e401 Edgar E. Iglesias
#define R_STATS_RXH       (0x294 / 4)
250 93f1e401 Edgar E. Iglesias
#define R_STATS_RX_BCASTL (0x2a0 / 4)
251 93f1e401 Edgar E. Iglesias
#define R_STATS_RX_BCASTH (0x2a4 / 4)
252 93f1e401 Edgar E. Iglesias
#define R_STATS_RX_MCASTL (0x2a8 / 4)
253 93f1e401 Edgar E. Iglesias
#define R_STATS_RX_MCASTH (0x2ac / 4)
254 93f1e401 Edgar E. Iglesias
255 93f1e401 Edgar E. Iglesias
#define R_RCW0     (0x400 / 4)
256 93f1e401 Edgar E. Iglesias
#define R_RCW1     (0x404 / 4)
257 93f1e401 Edgar E. Iglesias
enum {
258 93f1e401 Edgar E. Iglesias
    RCW1_VLAN = (1 << 27),
259 93f1e401 Edgar E. Iglesias
    RCW1_RX   = (1 << 28),
260 93f1e401 Edgar E. Iglesias
    RCW1_FCS  = (1 << 29),
261 93f1e401 Edgar E. Iglesias
    RCW1_JUM  = (1 << 30),
262 93f1e401 Edgar E. Iglesias
    RCW1_RST  = (1 << 31),
263 93f1e401 Edgar E. Iglesias
};
264 93f1e401 Edgar E. Iglesias
265 93f1e401 Edgar E. Iglesias
#define R_TC       (0x408 / 4)
266 93f1e401 Edgar E. Iglesias
enum {
267 93f1e401 Edgar E. Iglesias
    TC_VLAN = (1 << 27),
268 93f1e401 Edgar E. Iglesias
    TC_TX   = (1 << 28),
269 93f1e401 Edgar E. Iglesias
    TC_FCS  = (1 << 29),
270 93f1e401 Edgar E. Iglesias
    TC_JUM  = (1 << 30),
271 93f1e401 Edgar E. Iglesias
    TC_RST  = (1 << 31),
272 93f1e401 Edgar E. Iglesias
};
273 93f1e401 Edgar E. Iglesias
274 93f1e401 Edgar E. Iglesias
#define R_EMMC     (0x410 / 4)
275 93f1e401 Edgar E. Iglesias
enum {
276 93f1e401 Edgar E. Iglesias
    EMMC_LINKSPEED_10MB = (0 << 30),
277 93f1e401 Edgar E. Iglesias
    EMMC_LINKSPEED_100MB = (1 << 30),
278 93f1e401 Edgar E. Iglesias
    EMMC_LINKSPEED_1000MB = (2 << 30),
279 93f1e401 Edgar E. Iglesias
};
280 93f1e401 Edgar E. Iglesias
281 93f1e401 Edgar E. Iglesias
#define R_PHYC     (0x414 / 4)
282 93f1e401 Edgar E. Iglesias
283 93f1e401 Edgar E. Iglesias
#define R_MC       (0x500 / 4)
284 93f1e401 Edgar E. Iglesias
#define MC_EN      (1 << 6)
285 93f1e401 Edgar E. Iglesias
286 93f1e401 Edgar E. Iglesias
#define R_MCR      (0x504 / 4)
287 93f1e401 Edgar E. Iglesias
#define R_MWD      (0x508 / 4)
288 93f1e401 Edgar E. Iglesias
#define R_MRD      (0x50c / 4)
289 93f1e401 Edgar E. Iglesias
#define R_MIS      (0x600 / 4)
290 93f1e401 Edgar E. Iglesias
#define R_MIP      (0x620 / 4)
291 93f1e401 Edgar E. Iglesias
#define R_MIE      (0x640 / 4)
292 93f1e401 Edgar E. Iglesias
#define R_MIC      (0x640 / 4)
293 93f1e401 Edgar E. Iglesias
294 93f1e401 Edgar E. Iglesias
#define R_UAW0     (0x700 / 4)
295 93f1e401 Edgar E. Iglesias
#define R_UAW1     (0x704 / 4)
296 93f1e401 Edgar E. Iglesias
#define R_FMI      (0x708 / 4)
297 93f1e401 Edgar E. Iglesias
#define R_AF0      (0x710 / 4)
298 93f1e401 Edgar E. Iglesias
#define R_AF1      (0x714 / 4)
299 93f1e401 Edgar E. Iglesias
#define R_MAX      (0x34 / 4)
300 93f1e401 Edgar E. Iglesias
301 93f1e401 Edgar E. Iglesias
/* Indirect registers.  */
302 93f1e401 Edgar E. Iglesias
struct TEMAC  {
303 93f1e401 Edgar E. Iglesias
    struct MDIOBus mdio_bus;
304 93f1e401 Edgar E. Iglesias
    struct PHY phy;
305 93f1e401 Edgar E. Iglesias
306 93f1e401 Edgar E. Iglesias
    void *parent;
307 93f1e401 Edgar E. Iglesias
};
308 93f1e401 Edgar E. Iglesias
309 93f1e401 Edgar E. Iglesias
struct XilinxAXIEnet {
310 93f1e401 Edgar E. Iglesias
    SysBusDevice busdev;
311 93f1e401 Edgar E. Iglesias
    qemu_irq irq;
312 93f1e401 Edgar E. Iglesias
    void *dmach;
313 93f1e401 Edgar E. Iglesias
    NICState *nic;
314 93f1e401 Edgar E. Iglesias
    NICConf conf;
315 93f1e401 Edgar E. Iglesias
316 93f1e401 Edgar E. Iglesias
317 93f1e401 Edgar E. Iglesias
    uint32_t c_rxmem;
318 93f1e401 Edgar E. Iglesias
    uint32_t c_txmem;
319 93f1e401 Edgar E. Iglesias
    uint32_t c_phyaddr;
320 93f1e401 Edgar E. Iglesias
321 93f1e401 Edgar E. Iglesias
    struct TEMAC TEMAC;
322 93f1e401 Edgar E. Iglesias
323 93f1e401 Edgar E. Iglesias
    /* MII regs.  */
324 93f1e401 Edgar E. Iglesias
    union {
325 93f1e401 Edgar E. Iglesias
        uint32_t regs[4];
326 93f1e401 Edgar E. Iglesias
        struct {
327 93f1e401 Edgar E. Iglesias
            uint32_t mc;
328 93f1e401 Edgar E. Iglesias
            uint32_t mcr;
329 93f1e401 Edgar E. Iglesias
            uint32_t mwd;
330 93f1e401 Edgar E. Iglesias
            uint32_t mrd;
331 93f1e401 Edgar E. Iglesias
        };
332 93f1e401 Edgar E. Iglesias
    } mii;
333 93f1e401 Edgar E. Iglesias
334 93f1e401 Edgar E. Iglesias
    struct {
335 93f1e401 Edgar E. Iglesias
        uint64_t rx_bytes;
336 93f1e401 Edgar E. Iglesias
        uint64_t tx_bytes;
337 93f1e401 Edgar E. Iglesias
338 93f1e401 Edgar E. Iglesias
        uint64_t rx;
339 93f1e401 Edgar E. Iglesias
        uint64_t rx_bcast;
340 93f1e401 Edgar E. Iglesias
        uint64_t rx_mcast;
341 93f1e401 Edgar E. Iglesias
    } stats;
342 93f1e401 Edgar E. Iglesias
343 93f1e401 Edgar E. Iglesias
    /* Receive configuration words.  */
344 93f1e401 Edgar E. Iglesias
    uint32_t rcw[2];
345 93f1e401 Edgar E. Iglesias
    /* Transmit config.  */
346 93f1e401 Edgar E. Iglesias
    uint32_t tc;
347 93f1e401 Edgar E. Iglesias
    uint32_t emmc;
348 93f1e401 Edgar E. Iglesias
    uint32_t phyc;
349 93f1e401 Edgar E. Iglesias
350 93f1e401 Edgar E. Iglesias
    /* Unicast Address Word.  */
351 93f1e401 Edgar E. Iglesias
    uint32_t uaw[2];
352 93f1e401 Edgar E. Iglesias
    /* Unicast address filter used with extended mcast.  */
353 93f1e401 Edgar E. Iglesias
    uint32_t ext_uaw[2];
354 93f1e401 Edgar E. Iglesias
    uint32_t fmi;
355 93f1e401 Edgar E. Iglesias
356 93f1e401 Edgar E. Iglesias
    uint32_t regs[R_MAX];
357 93f1e401 Edgar E. Iglesias
358 93f1e401 Edgar E. Iglesias
    /* Multicast filter addrs.  */
359 93f1e401 Edgar E. Iglesias
    uint32_t maddr[4][2];
360 93f1e401 Edgar E. Iglesias
    /* 32K x 1 lookup filter.  */
361 93f1e401 Edgar E. Iglesias
    uint32_t ext_mtable[1024];
362 93f1e401 Edgar E. Iglesias
363 93f1e401 Edgar E. Iglesias
364 93f1e401 Edgar E. Iglesias
    uint8_t *rxmem;
365 93f1e401 Edgar E. Iglesias
};
366 93f1e401 Edgar E. Iglesias
367 93f1e401 Edgar E. Iglesias
static void axienet_rx_reset(struct XilinxAXIEnet *s)
368 93f1e401 Edgar E. Iglesias
{
369 93f1e401 Edgar E. Iglesias
    s->rcw[1] = RCW1_JUM | RCW1_FCS | RCW1_RX | RCW1_VLAN;
370 93f1e401 Edgar E. Iglesias
}
371 93f1e401 Edgar E. Iglesias
372 93f1e401 Edgar E. Iglesias
static void axienet_tx_reset(struct XilinxAXIEnet *s)
373 93f1e401 Edgar E. Iglesias
{
374 93f1e401 Edgar E. Iglesias
    s->tc = TC_JUM | TC_TX | TC_VLAN;
375 93f1e401 Edgar E. Iglesias
}
376 93f1e401 Edgar E. Iglesias
377 93f1e401 Edgar E. Iglesias
static inline int axienet_rx_resetting(struct XilinxAXIEnet *s)
378 93f1e401 Edgar E. Iglesias
{
379 93f1e401 Edgar E. Iglesias
    return s->rcw[1] & RCW1_RST;
380 93f1e401 Edgar E. Iglesias
}
381 93f1e401 Edgar E. Iglesias
382 93f1e401 Edgar E. Iglesias
static inline int axienet_rx_enabled(struct XilinxAXIEnet *s)
383 93f1e401 Edgar E. Iglesias
{
384 93f1e401 Edgar E. Iglesias
    return s->rcw[1] & RCW1_RX;
385 93f1e401 Edgar E. Iglesias
}
386 93f1e401 Edgar E. Iglesias
387 93f1e401 Edgar E. Iglesias
static inline int axienet_extmcf_enabled(struct XilinxAXIEnet *s)
388 93f1e401 Edgar E. Iglesias
{
389 93f1e401 Edgar E. Iglesias
    return !!(s->regs[R_RAF] & RAF_EMCF_EN);
390 93f1e401 Edgar E. Iglesias
}
391 93f1e401 Edgar E. Iglesias
392 93f1e401 Edgar E. Iglesias
static inline int axienet_newfunc_enabled(struct XilinxAXIEnet *s)
393 93f1e401 Edgar E. Iglesias
{
394 93f1e401 Edgar E. Iglesias
    return !!(s->regs[R_RAF] & RAF_NEWFUNC_EN);
395 93f1e401 Edgar E. Iglesias
}
396 93f1e401 Edgar E. Iglesias
397 93f1e401 Edgar E. Iglesias
static void axienet_reset(struct XilinxAXIEnet *s)
398 93f1e401 Edgar E. Iglesias
{
399 93f1e401 Edgar E. Iglesias
    axienet_rx_reset(s);
400 93f1e401 Edgar E. Iglesias
    axienet_tx_reset(s);
401 93f1e401 Edgar E. Iglesias
402 93f1e401 Edgar E. Iglesias
    s->regs[R_PPST] = PPST_LINKSTATUS | PPST_PHY_LINKSTATUS;
403 93f1e401 Edgar E. Iglesias
    s->regs[R_IS] = IS_AUTONEG | IS_RX_DCM_LOCK | IS_MGM_RDY | IS_PHY_RST_DONE;
404 93f1e401 Edgar E. Iglesias
405 93f1e401 Edgar E. Iglesias
    s->emmc = EMMC_LINKSPEED_100MB;
406 93f1e401 Edgar E. Iglesias
}
407 93f1e401 Edgar E. Iglesias
408 93f1e401 Edgar E. Iglesias
static void enet_update_irq(struct XilinxAXIEnet *s)
409 93f1e401 Edgar E. Iglesias
{
410 93f1e401 Edgar E. Iglesias
    s->regs[R_IP] = s->regs[R_IS] & s->regs[R_IE];
411 93f1e401 Edgar E. Iglesias
    qemu_set_irq(s->irq, !!s->regs[R_IP]);
412 93f1e401 Edgar E. Iglesias
}
413 93f1e401 Edgar E. Iglesias
414 93f1e401 Edgar E. Iglesias
static uint32_t enet_readl(void *opaque, target_phys_addr_t addr)
415 93f1e401 Edgar E. Iglesias
{
416 93f1e401 Edgar E. Iglesias
    struct XilinxAXIEnet *s = opaque;
417 93f1e401 Edgar E. Iglesias
    uint32_t r = 0;
418 93f1e401 Edgar E. Iglesias
    addr >>= 2;
419 93f1e401 Edgar E. Iglesias
420 93f1e401 Edgar E. Iglesias
    switch (addr) {
421 93f1e401 Edgar E. Iglesias
        case R_RCW0:
422 93f1e401 Edgar E. Iglesias
        case R_RCW1:
423 93f1e401 Edgar E. Iglesias
            r = s->rcw[addr & 1];
424 93f1e401 Edgar E. Iglesias
            break;
425 93f1e401 Edgar E. Iglesias
426 93f1e401 Edgar E. Iglesias
        case R_TC:
427 93f1e401 Edgar E. Iglesias
            r = s->tc;
428 93f1e401 Edgar E. Iglesias
            break;
429 93f1e401 Edgar E. Iglesias
430 93f1e401 Edgar E. Iglesias
        case R_EMMC:
431 93f1e401 Edgar E. Iglesias
            r = s->emmc;
432 93f1e401 Edgar E. Iglesias
            break;
433 93f1e401 Edgar E. Iglesias
434 93f1e401 Edgar E. Iglesias
        case R_PHYC:
435 93f1e401 Edgar E. Iglesias
            r = s->phyc;
436 93f1e401 Edgar E. Iglesias
            break;
437 93f1e401 Edgar E. Iglesias
438 93f1e401 Edgar E. Iglesias
        case R_MCR:
439 93f1e401 Edgar E. Iglesias
            r = s->mii.regs[addr & 3] | (1 << 7); /* Always ready.  */
440 93f1e401 Edgar E. Iglesias
            break;
441 93f1e401 Edgar E. Iglesias
442 93f1e401 Edgar E. Iglesias
        case R_STATS_RX_BYTESL:
443 93f1e401 Edgar E. Iglesias
        case R_STATS_RX_BYTESH:
444 93f1e401 Edgar E. Iglesias
            r = s->stats.rx_bytes >> (32 * (addr & 1));
445 93f1e401 Edgar E. Iglesias
            break;
446 93f1e401 Edgar E. Iglesias
447 93f1e401 Edgar E. Iglesias
        case R_STATS_TX_BYTESL:
448 93f1e401 Edgar E. Iglesias
        case R_STATS_TX_BYTESH:
449 93f1e401 Edgar E. Iglesias
            r = s->stats.tx_bytes >> (32 * (addr & 1));
450 93f1e401 Edgar E. Iglesias
            break;
451 93f1e401 Edgar E. Iglesias
452 93f1e401 Edgar E. Iglesias
        case R_STATS_RXL:
453 93f1e401 Edgar E. Iglesias
        case R_STATS_RXH:
454 93f1e401 Edgar E. Iglesias
            r = s->stats.rx >> (32 * (addr & 1));
455 93f1e401 Edgar E. Iglesias
            break;
456 93f1e401 Edgar E. Iglesias
        case R_STATS_RX_BCASTL:
457 93f1e401 Edgar E. Iglesias
        case R_STATS_RX_BCASTH:
458 93f1e401 Edgar E. Iglesias
            r = s->stats.rx_bcast >> (32 * (addr & 1));
459 93f1e401 Edgar E. Iglesias
            break;
460 93f1e401 Edgar E. Iglesias
        case R_STATS_RX_MCASTL:
461 93f1e401 Edgar E. Iglesias
        case R_STATS_RX_MCASTH:
462 93f1e401 Edgar E. Iglesias
            r = s->stats.rx_mcast >> (32 * (addr & 1));
463 93f1e401 Edgar E. Iglesias
            break;
464 93f1e401 Edgar E. Iglesias
465 93f1e401 Edgar E. Iglesias
        case R_MC:
466 93f1e401 Edgar E. Iglesias
        case R_MWD:
467 93f1e401 Edgar E. Iglesias
        case R_MRD:
468 93f1e401 Edgar E. Iglesias
            r = s->mii.regs[addr & 3];
469 93f1e401 Edgar E. Iglesias
            break;
470 93f1e401 Edgar E. Iglesias
471 93f1e401 Edgar E. Iglesias
        case R_UAW0:
472 93f1e401 Edgar E. Iglesias
        case R_UAW1:
473 93f1e401 Edgar E. Iglesias
            r = s->uaw[addr & 1];
474 93f1e401 Edgar E. Iglesias
            break;
475 93f1e401 Edgar E. Iglesias
476 93f1e401 Edgar E. Iglesias
        case R_UAWU:
477 93f1e401 Edgar E. Iglesias
        case R_UAWL:
478 93f1e401 Edgar E. Iglesias
            r = s->ext_uaw[addr & 1];
479 93f1e401 Edgar E. Iglesias
            break;
480 93f1e401 Edgar E. Iglesias
481 93f1e401 Edgar E. Iglesias
        case R_FMI:
482 93f1e401 Edgar E. Iglesias
            r = s->fmi;
483 93f1e401 Edgar E. Iglesias
            break;
484 93f1e401 Edgar E. Iglesias
485 93f1e401 Edgar E. Iglesias
        case R_AF0:
486 93f1e401 Edgar E. Iglesias
        case R_AF1:
487 93f1e401 Edgar E. Iglesias
            r = s->maddr[s->fmi & 3][addr & 1];
488 93f1e401 Edgar E. Iglesias
            break;
489 93f1e401 Edgar E. Iglesias
490 93f1e401 Edgar E. Iglesias
        case 0x8000 ... 0x83ff:
491 93f1e401 Edgar E. Iglesias
            r = s->ext_mtable[addr - 0x8000];
492 93f1e401 Edgar E. Iglesias
            break;
493 93f1e401 Edgar E. Iglesias
494 93f1e401 Edgar E. Iglesias
        default:
495 93f1e401 Edgar E. Iglesias
            if (addr < ARRAY_SIZE(s->regs)) {
496 93f1e401 Edgar E. Iglesias
                r = s->regs[addr];
497 93f1e401 Edgar E. Iglesias
            }
498 93f1e401 Edgar E. Iglesias
            DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
499 93f1e401 Edgar E. Iglesias
                            __func__, addr * 4, r));
500 93f1e401 Edgar E. Iglesias
            break;
501 93f1e401 Edgar E. Iglesias
    }
502 93f1e401 Edgar E. Iglesias
    return r;
503 93f1e401 Edgar E. Iglesias
}
504 93f1e401 Edgar E. Iglesias
505 93f1e401 Edgar E. Iglesias
static void
506 93f1e401 Edgar E. Iglesias
enet_writel(void *opaque, target_phys_addr_t addr, uint32_t value)
507 93f1e401 Edgar E. Iglesias
{
508 93f1e401 Edgar E. Iglesias
    struct XilinxAXIEnet *s = opaque;
509 93f1e401 Edgar E. Iglesias
    struct TEMAC *t = &s->TEMAC;
510 93f1e401 Edgar E. Iglesias
511 93f1e401 Edgar E. Iglesias
    addr >>= 2;
512 93f1e401 Edgar E. Iglesias
    switch (addr) {
513 93f1e401 Edgar E. Iglesias
        case R_RCW0:
514 93f1e401 Edgar E. Iglesias
        case R_RCW1:
515 93f1e401 Edgar E. Iglesias
            s->rcw[addr & 1] = value;
516 93f1e401 Edgar E. Iglesias
            if ((addr & 1) && value & RCW1_RST) {
517 93f1e401 Edgar E. Iglesias
                axienet_rx_reset(s);
518 93f1e401 Edgar E. Iglesias
            }
519 93f1e401 Edgar E. Iglesias
            break;
520 93f1e401 Edgar E. Iglesias
521 93f1e401 Edgar E. Iglesias
        case R_TC:
522 93f1e401 Edgar E. Iglesias
            s->tc = value;
523 93f1e401 Edgar E. Iglesias
            if (value & TC_RST) {
524 93f1e401 Edgar E. Iglesias
                axienet_tx_reset(s);
525 93f1e401 Edgar E. Iglesias
            }
526 93f1e401 Edgar E. Iglesias
            break;
527 93f1e401 Edgar E. Iglesias
528 93f1e401 Edgar E. Iglesias
        case R_EMMC:
529 93f1e401 Edgar E. Iglesias
            s->emmc = value;
530 93f1e401 Edgar E. Iglesias
            break;
531 93f1e401 Edgar E. Iglesias
532 93f1e401 Edgar E. Iglesias
        case R_PHYC:
533 93f1e401 Edgar E. Iglesias
            s->phyc = value;
534 93f1e401 Edgar E. Iglesias
            break;
535 93f1e401 Edgar E. Iglesias
536 93f1e401 Edgar E. Iglesias
        case R_MC:
537 93f1e401 Edgar E. Iglesias
             value &= ((1 < 7) - 1);
538 93f1e401 Edgar E. Iglesias
539 93f1e401 Edgar E. Iglesias
             /* Enable the MII.  */
540 93f1e401 Edgar E. Iglesias
             if (value & MC_EN) {
541 93f1e401 Edgar E. Iglesias
                 unsigned int miiclkdiv = value & ((1 << 6) - 1);
542 93f1e401 Edgar E. Iglesias
                 if (!miiclkdiv) {
543 93f1e401 Edgar E. Iglesias
                     qemu_log("AXIENET: MDIO enabled but MDIOCLK is zero!\n");
544 93f1e401 Edgar E. Iglesias
                 }
545 93f1e401 Edgar E. Iglesias
             }
546 93f1e401 Edgar E. Iglesias
             s->mii.mc = value;
547 93f1e401 Edgar E. Iglesias
             break;
548 93f1e401 Edgar E. Iglesias
549 93f1e401 Edgar E. Iglesias
        case R_MCR: {
550 93f1e401 Edgar E. Iglesias
             unsigned int phyaddr = (value >> 24) & 0x1f;
551 93f1e401 Edgar E. Iglesias
             unsigned int regaddr = (value >> 16) & 0x1f;
552 93f1e401 Edgar E. Iglesias
             unsigned int op = (value >> 14) & 3;
553 93f1e401 Edgar E. Iglesias
             unsigned int initiate = (value >> 11) & 1;
554 93f1e401 Edgar E. Iglesias
555 93f1e401 Edgar E. Iglesias
             if (initiate) {
556 93f1e401 Edgar E. Iglesias
                 if (op == 1) {
557 93f1e401 Edgar E. Iglesias
                     mdio_write_req(&t->mdio_bus, phyaddr, regaddr, s->mii.mwd);
558 93f1e401 Edgar E. Iglesias
                 } else if (op == 2) {
559 93f1e401 Edgar E. Iglesias
                     s->mii.mrd = mdio_read_req(&t->mdio_bus, phyaddr, regaddr);
560 93f1e401 Edgar E. Iglesias
                 } else {
561 93f1e401 Edgar E. Iglesias
                     qemu_log("AXIENET: invalid MDIOBus OP=%d\n", op);
562 93f1e401 Edgar E. Iglesias
                 }
563 93f1e401 Edgar E. Iglesias
             }
564 93f1e401 Edgar E. Iglesias
             s->mii.mcr = value;
565 93f1e401 Edgar E. Iglesias
             break;
566 93f1e401 Edgar E. Iglesias
        }
567 93f1e401 Edgar E. Iglesias
568 93f1e401 Edgar E. Iglesias
        case R_MWD:
569 93f1e401 Edgar E. Iglesias
        case R_MRD:
570 93f1e401 Edgar E. Iglesias
             s->mii.regs[addr & 3] = value;
571 93f1e401 Edgar E. Iglesias
             break;
572 93f1e401 Edgar E. Iglesias
573 93f1e401 Edgar E. Iglesias
574 93f1e401 Edgar E. Iglesias
        case R_UAW0:
575 93f1e401 Edgar E. Iglesias
        case R_UAW1:
576 93f1e401 Edgar E. Iglesias
            s->uaw[addr & 1] = value;
577 93f1e401 Edgar E. Iglesias
            break;
578 93f1e401 Edgar E. Iglesias
579 93f1e401 Edgar E. Iglesias
        case R_UAWL:
580 93f1e401 Edgar E. Iglesias
        case R_UAWU:
581 93f1e401 Edgar E. Iglesias
            s->ext_uaw[addr & 1] = value;
582 93f1e401 Edgar E. Iglesias
            break;
583 93f1e401 Edgar E. Iglesias
584 93f1e401 Edgar E. Iglesias
        case R_FMI:
585 93f1e401 Edgar E. Iglesias
            s->fmi = value;
586 93f1e401 Edgar E. Iglesias
            break;
587 93f1e401 Edgar E. Iglesias
588 93f1e401 Edgar E. Iglesias
        case R_AF0:
589 93f1e401 Edgar E. Iglesias
        case R_AF1:
590 93f1e401 Edgar E. Iglesias
            s->maddr[s->fmi & 3][addr & 1] = value;
591 93f1e401 Edgar E. Iglesias
            break;
592 93f1e401 Edgar E. Iglesias
593 93f1e401 Edgar E. Iglesias
        case 0x8000 ... 0x83ff:
594 93f1e401 Edgar E. Iglesias
            s->ext_mtable[addr - 0x8000] = value;
595 93f1e401 Edgar E. Iglesias
            break;
596 93f1e401 Edgar E. Iglesias
597 93f1e401 Edgar E. Iglesias
        default:
598 93f1e401 Edgar E. Iglesias
            DENET(qemu_log("%s addr=" TARGET_FMT_plx " v=%x\n",
599 93f1e401 Edgar E. Iglesias
                           __func__, addr * 4, value));
600 93f1e401 Edgar E. Iglesias
            if (addr < ARRAY_SIZE(s->regs)) {
601 93f1e401 Edgar E. Iglesias
                s->regs[addr] = value;
602 93f1e401 Edgar E. Iglesias
            }
603 93f1e401 Edgar E. Iglesias
            break;
604 93f1e401 Edgar E. Iglesias
    }
605 93f1e401 Edgar E. Iglesias
    enet_update_irq(s);
606 93f1e401 Edgar E. Iglesias
}
607 93f1e401 Edgar E. Iglesias
608 93f1e401 Edgar E. Iglesias
static CPUReadMemoryFunc * const enet_read[] = {
609 93f1e401 Edgar E. Iglesias
    &enet_readl,
610 93f1e401 Edgar E. Iglesias
    &enet_readl,
611 93f1e401 Edgar E. Iglesias
    &enet_readl,
612 93f1e401 Edgar E. Iglesias
};
613 93f1e401 Edgar E. Iglesias
614 93f1e401 Edgar E. Iglesias
static CPUWriteMemoryFunc * const enet_write[] = {
615 93f1e401 Edgar E. Iglesias
    &enet_writel,
616 93f1e401 Edgar E. Iglesias
    &enet_writel,
617 93f1e401 Edgar E. Iglesias
    &enet_writel,
618 93f1e401 Edgar E. Iglesias
};
619 93f1e401 Edgar E. Iglesias
620 93f1e401 Edgar E. Iglesias
static int eth_can_rx(VLANClientState *nc)
621 93f1e401 Edgar E. Iglesias
{
622 93f1e401 Edgar E. Iglesias
    struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque;
623 93f1e401 Edgar E. Iglesias
624 93f1e401 Edgar E. Iglesias
    /* RX enabled?  */
625 93f1e401 Edgar E. Iglesias
    return !axienet_rx_resetting(s) && axienet_rx_enabled(s);
626 93f1e401 Edgar E. Iglesias
}
627 93f1e401 Edgar E. Iglesias
628 93f1e401 Edgar E. Iglesias
static int enet_match_addr(const uint8_t *buf, uint32_t f0, uint32_t f1)
629 93f1e401 Edgar E. Iglesias
{
630 93f1e401 Edgar E. Iglesias
    int match = 1;
631 93f1e401 Edgar E. Iglesias
632 93f1e401 Edgar E. Iglesias
    if (memcmp(buf, &f0, 4)) {
633 93f1e401 Edgar E. Iglesias
        match = 0;
634 93f1e401 Edgar E. Iglesias
    }
635 93f1e401 Edgar E. Iglesias
636 93f1e401 Edgar E. Iglesias
    if (buf[4] != (f1 & 0xff) || buf[5] != ((f1 >> 8) & 0xff)) {
637 93f1e401 Edgar E. Iglesias
        match = 0;
638 93f1e401 Edgar E. Iglesias
    }
639 93f1e401 Edgar E. Iglesias
640 93f1e401 Edgar E. Iglesias
    return match;
641 93f1e401 Edgar E. Iglesias
}
642 93f1e401 Edgar E. Iglesias
643 93f1e401 Edgar E. Iglesias
static ssize_t eth_rx(VLANClientState *nc, const uint8_t *buf, size_t size)
644 93f1e401 Edgar E. Iglesias
{
645 93f1e401 Edgar E. Iglesias
    struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque;
646 93f1e401 Edgar E. Iglesias
    static const unsigned char sa_bcast[6] = {0xff, 0xff, 0xff,
647 93f1e401 Edgar E. Iglesias
                                              0xff, 0xff, 0xff};
648 93f1e401 Edgar E. Iglesias
    static const unsigned char sa_ipmcast[3] = {0x01, 0x00, 0x52};
649 93f1e401 Edgar E. Iglesias
    uint32_t app[6] = {0};
650 93f1e401 Edgar E. Iglesias
    int promisc = s->fmi & (1 << 31);
651 93f1e401 Edgar E. Iglesias
    int unicast, broadcast, multicast, ip_multicast = 0;
652 93f1e401 Edgar E. Iglesias
    uint32_t csum32;
653 93f1e401 Edgar E. Iglesias
    uint16_t csum16;
654 93f1e401 Edgar E. Iglesias
    int i;
655 93f1e401 Edgar E. Iglesias
656 93f1e401 Edgar E. Iglesias
    s = s;
657 93f1e401 Edgar E. Iglesias
    DENET(qemu_log("%s: %zd bytes\n", __func__, size));
658 93f1e401 Edgar E. Iglesias
659 93f1e401 Edgar E. Iglesias
    unicast = ~buf[0] & 0x1;
660 93f1e401 Edgar E. Iglesias
    broadcast = memcmp(buf, sa_bcast, 6) == 0;
661 93f1e401 Edgar E. Iglesias
    multicast = !unicast && !broadcast;
662 93f1e401 Edgar E. Iglesias
    if (multicast && (memcmp(sa_ipmcast, buf, sizeof sa_ipmcast) == 0)) {
663 93f1e401 Edgar E. Iglesias
        ip_multicast = 1;
664 93f1e401 Edgar E. Iglesias
    }
665 93f1e401 Edgar E. Iglesias
666 93f1e401 Edgar E. Iglesias
    /* Jumbo or vlan sizes ?  */
667 93f1e401 Edgar E. Iglesias
    if (!(s->rcw[1] & RCW1_JUM)) {
668 93f1e401 Edgar E. Iglesias
        if (size > 1518 && size <= 1522 && !(s->rcw[1] & RCW1_VLAN)) {
669 93f1e401 Edgar E. Iglesias
            return size;
670 93f1e401 Edgar E. Iglesias
        }
671 93f1e401 Edgar E. Iglesias
    }
672 93f1e401 Edgar E. Iglesias
673 93f1e401 Edgar E. Iglesias
    /* Basic Address filters.  If you want to use the extended filters
674 93f1e401 Edgar E. Iglesias
       you'll generally have to place the ethernet mac into promiscuous mode
675 93f1e401 Edgar E. Iglesias
       to avoid the basic filtering from dropping most frames.  */
676 93f1e401 Edgar E. Iglesias
    if (!promisc) {
677 93f1e401 Edgar E. Iglesias
        if (unicast) {
678 93f1e401 Edgar E. Iglesias
            if (!enet_match_addr(buf, s->uaw[0], s->uaw[1])) {
679 93f1e401 Edgar E. Iglesias
                return size;
680 93f1e401 Edgar E. Iglesias
            }
681 93f1e401 Edgar E. Iglesias
        } else {
682 93f1e401 Edgar E. Iglesias
            if (broadcast) {
683 93f1e401 Edgar E. Iglesias
                /* Broadcast.  */
684 93f1e401 Edgar E. Iglesias
                if (s->regs[R_RAF] & RAF_BCAST_REJ) {
685 93f1e401 Edgar E. Iglesias
                    return size;
686 93f1e401 Edgar E. Iglesias
                }
687 93f1e401 Edgar E. Iglesias
            } else {
688 93f1e401 Edgar E. Iglesias
                int drop = 1;
689 93f1e401 Edgar E. Iglesias
690 93f1e401 Edgar E. Iglesias
                /* Multicast.  */
691 93f1e401 Edgar E. Iglesias
                if (s->regs[R_RAF] & RAF_MCAST_REJ) {
692 93f1e401 Edgar E. Iglesias
                    return size;
693 93f1e401 Edgar E. Iglesias
                }
694 93f1e401 Edgar E. Iglesias
695 93f1e401 Edgar E. Iglesias
                for (i = 0; i < 4; i++) {
696 93f1e401 Edgar E. Iglesias
                    if (enet_match_addr(buf, s->maddr[i][0], s->maddr[i][1])) {
697 93f1e401 Edgar E. Iglesias
                        drop = 0;
698 93f1e401 Edgar E. Iglesias
                        break;
699 93f1e401 Edgar E. Iglesias
                    }
700 93f1e401 Edgar E. Iglesias
                }
701 93f1e401 Edgar E. Iglesias
702 93f1e401 Edgar E. Iglesias
                if (drop) {
703 93f1e401 Edgar E. Iglesias
                    return size;
704 93f1e401 Edgar E. Iglesias
                }
705 93f1e401 Edgar E. Iglesias
            }
706 93f1e401 Edgar E. Iglesias
        }
707 93f1e401 Edgar E. Iglesias
    }
708 93f1e401 Edgar E. Iglesias
709 93f1e401 Edgar E. Iglesias
    /* Extended mcast filtering enabled?  */
710 93f1e401 Edgar E. Iglesias
    if (axienet_newfunc_enabled(s) && axienet_extmcf_enabled(s)) {
711 93f1e401 Edgar E. Iglesias
        if (unicast) {
712 93f1e401 Edgar E. Iglesias
            if (!enet_match_addr(buf, s->ext_uaw[0], s->ext_uaw[1])) {
713 93f1e401 Edgar E. Iglesias
                return size;
714 93f1e401 Edgar E. Iglesias
            }
715 93f1e401 Edgar E. Iglesias
        } else {
716 93f1e401 Edgar E. Iglesias
            if (broadcast) {
717 93f1e401 Edgar E. Iglesias
                /* Broadcast. ???  */
718 93f1e401 Edgar E. Iglesias
                if (s->regs[R_RAF] & RAF_BCAST_REJ) {
719 93f1e401 Edgar E. Iglesias
                    return size;
720 93f1e401 Edgar E. Iglesias
                }
721 93f1e401 Edgar E. Iglesias
            } else {
722 93f1e401 Edgar E. Iglesias
                int idx, bit;
723 93f1e401 Edgar E. Iglesias
724 93f1e401 Edgar E. Iglesias
                /* Multicast.  */
725 93f1e401 Edgar E. Iglesias
                if (!memcmp(buf, sa_ipmcast, 3)) {
726 93f1e401 Edgar E. Iglesias
                    return size;
727 93f1e401 Edgar E. Iglesias
                }
728 93f1e401 Edgar E. Iglesias
729 93f1e401 Edgar E. Iglesias
                idx  = (buf[4] & 0x7f) << 8;
730 93f1e401 Edgar E. Iglesias
                idx |= buf[5];
731 93f1e401 Edgar E. Iglesias
732 93f1e401 Edgar E. Iglesias
                bit = 1 << (idx & 0x1f);
733 93f1e401 Edgar E. Iglesias
                idx >>= 5;
734 93f1e401 Edgar E. Iglesias
735 93f1e401 Edgar E. Iglesias
                if (!(s->ext_mtable[idx] & bit)) {
736 93f1e401 Edgar E. Iglesias
                    return size;
737 93f1e401 Edgar E. Iglesias
                }
738 93f1e401 Edgar E. Iglesias
            }
739 93f1e401 Edgar E. Iglesias
        }
740 93f1e401 Edgar E. Iglesias
    }
741 93f1e401 Edgar E. Iglesias
742 93f1e401 Edgar E. Iglesias
    if (size < 12) {
743 93f1e401 Edgar E. Iglesias
        s->regs[R_IS] |= IS_RX_REJECT;
744 93f1e401 Edgar E. Iglesias
        enet_update_irq(s);
745 93f1e401 Edgar E. Iglesias
        return -1;
746 93f1e401 Edgar E. Iglesias
    }
747 93f1e401 Edgar E. Iglesias
748 93f1e401 Edgar E. Iglesias
    if (size > (s->c_rxmem - 4)) {
749 93f1e401 Edgar E. Iglesias
        size = s->c_rxmem - 4;
750 93f1e401 Edgar E. Iglesias
    }
751 93f1e401 Edgar E. Iglesias
752 93f1e401 Edgar E. Iglesias
    memcpy(s->rxmem, buf, size);
753 93f1e401 Edgar E. Iglesias
    memset(s->rxmem + size, 0, 4); /* Clear the FCS.  */
754 93f1e401 Edgar E. Iglesias
755 93f1e401 Edgar E. Iglesias
    if (s->rcw[1] & RCW1_FCS) {
756 93f1e401 Edgar E. Iglesias
        size += 4; /* fcs is inband.  */
757 93f1e401 Edgar E. Iglesias
    }
758 93f1e401 Edgar E. Iglesias
759 93f1e401 Edgar E. Iglesias
    app[0] = 5 << 28;
760 93f1e401 Edgar E. Iglesias
    csum32 = net_checksum_add(size - 14, (uint8_t *)s->rxmem + 14);
761 93f1e401 Edgar E. Iglesias
    /* Fold it once.  */
762 93f1e401 Edgar E. Iglesias
    csum32 = (csum32 & 0xffff) + (csum32 >> 16);
763 93f1e401 Edgar E. Iglesias
    /* And twice to get rid of possible carries.  */
764 93f1e401 Edgar E. Iglesias
    csum16 = (csum32 & 0xffff) + (csum32 >> 16);
765 93f1e401 Edgar E. Iglesias
    app[3] = csum16;
766 93f1e401 Edgar E. Iglesias
    app[4] = size & 0xffff;
767 93f1e401 Edgar E. Iglesias
768 93f1e401 Edgar E. Iglesias
    s->stats.rx_bytes += size;
769 93f1e401 Edgar E. Iglesias
    s->stats.rx++;
770 93f1e401 Edgar E. Iglesias
    if (multicast) {
771 93f1e401 Edgar E. Iglesias
        s->stats.rx_mcast++;
772 93f1e401 Edgar E. Iglesias
        app[2] |= 1 | (ip_multicast << 1);
773 93f1e401 Edgar E. Iglesias
    } else if (broadcast) {
774 93f1e401 Edgar E. Iglesias
        s->stats.rx_bcast++;
775 93f1e401 Edgar E. Iglesias
        app[2] |= 1 << 3;
776 93f1e401 Edgar E. Iglesias
    }
777 93f1e401 Edgar E. Iglesias
778 93f1e401 Edgar E. Iglesias
    /* Good frame.  */
779 93f1e401 Edgar E. Iglesias
    app[2] |= 1 << 6;
780 93f1e401 Edgar E. Iglesias
781 93f1e401 Edgar E. Iglesias
    xlx_dma_push_to_dma(s->dmach, (void *)s->rxmem, size, app);
782 93f1e401 Edgar E. Iglesias
783 93f1e401 Edgar E. Iglesias
    s->regs[R_IS] |= IS_RX_COMPLETE;
784 93f1e401 Edgar E. Iglesias
    enet_update_irq(s);
785 93f1e401 Edgar E. Iglesias
    return size;
786 93f1e401 Edgar E. Iglesias
}
787 93f1e401 Edgar E. Iglesias
788 93f1e401 Edgar E. Iglesias
static void eth_cleanup(VLANClientState *nc)
789 93f1e401 Edgar E. Iglesias
{
790 93f1e401 Edgar E. Iglesias
    /* FIXME.  */
791 93f1e401 Edgar E. Iglesias
    struct XilinxAXIEnet *s = DO_UPCAST(NICState, nc, nc)->opaque;
792 93f1e401 Edgar E. Iglesias
    qemu_free(s->rxmem);
793 93f1e401 Edgar E. Iglesias
    qemu_free(s);
794 93f1e401 Edgar E. Iglesias
}
795 93f1e401 Edgar E. Iglesias
796 93f1e401 Edgar E. Iglesias
static void
797 93f1e401 Edgar E. Iglesias
axienet_stream_push(void *opaque, uint8_t *buf, size_t size, uint32_t *hdr)
798 93f1e401 Edgar E. Iglesias
{
799 93f1e401 Edgar E. Iglesias
    struct XilinxAXIEnet *s = opaque;
800 93f1e401 Edgar E. Iglesias
801 93f1e401 Edgar E. Iglesias
    /* TX enable ?  */
802 93f1e401 Edgar E. Iglesias
    if (!(s->tc & TC_TX)) {
803 93f1e401 Edgar E. Iglesias
        return;
804 93f1e401 Edgar E. Iglesias
    }
805 93f1e401 Edgar E. Iglesias
806 93f1e401 Edgar E. Iglesias
    /* Jumbo or vlan sizes ?  */
807 93f1e401 Edgar E. Iglesias
    if (!(s->tc & TC_JUM)) {
808 93f1e401 Edgar E. Iglesias
        if (size > 1518 && size <= 1522 && !(s->tc & TC_VLAN)) {
809 93f1e401 Edgar E. Iglesias
            return;
810 93f1e401 Edgar E. Iglesias
        }
811 93f1e401 Edgar E. Iglesias
    }
812 93f1e401 Edgar E. Iglesias
813 93f1e401 Edgar E. Iglesias
    if (hdr[0] & 1) {
814 93f1e401 Edgar E. Iglesias
        unsigned int start_off = hdr[1] >> 16;
815 93f1e401 Edgar E. Iglesias
        unsigned int write_off = hdr[1] & 0xffff;
816 93f1e401 Edgar E. Iglesias
        uint32_t tmp_csum;
817 93f1e401 Edgar E. Iglesias
        uint16_t csum;
818 93f1e401 Edgar E. Iglesias
819 93f1e401 Edgar E. Iglesias
        tmp_csum = net_checksum_add(size - start_off,
820 93f1e401 Edgar E. Iglesias
                                    (uint8_t *)buf + start_off);
821 93f1e401 Edgar E. Iglesias
        /* Accumulate the seed.  */
822 93f1e401 Edgar E. Iglesias
        tmp_csum += hdr[2] & 0xffff;
823 93f1e401 Edgar E. Iglesias
824 93f1e401 Edgar E. Iglesias
        /* Fold the 32bit partial checksum.  */
825 93f1e401 Edgar E. Iglesias
        csum = net_checksum_finish(tmp_csum);
826 93f1e401 Edgar E. Iglesias
827 93f1e401 Edgar E. Iglesias
        /* Writeback.  */
828 93f1e401 Edgar E. Iglesias
        buf[write_off] = csum >> 8;
829 93f1e401 Edgar E. Iglesias
        buf[write_off + 1] = csum & 0xff;
830 93f1e401 Edgar E. Iglesias
    }
831 93f1e401 Edgar E. Iglesias
832 93f1e401 Edgar E. Iglesias
    qemu_send_packet(&s->nic->nc, buf, size);
833 93f1e401 Edgar E. Iglesias
834 93f1e401 Edgar E. Iglesias
    s->stats.tx_bytes += size;
835 93f1e401 Edgar E. Iglesias
    s->regs[R_IS] |= IS_TX_COMPLETE;
836 93f1e401 Edgar E. Iglesias
    enet_update_irq(s);
837 93f1e401 Edgar E. Iglesias
}
838 93f1e401 Edgar E. Iglesias
839 93f1e401 Edgar E. Iglesias
static NetClientInfo net_xilinx_enet_info = {
840 93f1e401 Edgar E. Iglesias
    .type = NET_CLIENT_TYPE_NIC,
841 93f1e401 Edgar E. Iglesias
    .size = sizeof(NICState),
842 93f1e401 Edgar E. Iglesias
    .can_receive = eth_can_rx,
843 93f1e401 Edgar E. Iglesias
    .receive = eth_rx,
844 93f1e401 Edgar E. Iglesias
    .cleanup = eth_cleanup,
845 93f1e401 Edgar E. Iglesias
};
846 93f1e401 Edgar E. Iglesias
847 93f1e401 Edgar E. Iglesias
static int xilinx_enet_init(SysBusDevice *dev)
848 93f1e401 Edgar E. Iglesias
{
849 93f1e401 Edgar E. Iglesias
    struct XilinxAXIEnet *s = FROM_SYSBUS(typeof(*s), dev);
850 93f1e401 Edgar E. Iglesias
    int enet_regs;
851 93f1e401 Edgar E. Iglesias
852 93f1e401 Edgar E. Iglesias
    sysbus_init_irq(dev, &s->irq);
853 93f1e401 Edgar E. Iglesias
854 93f1e401 Edgar E. Iglesias
    if (!s->dmach) {
855 93f1e401 Edgar E. Iglesias
        hw_error("Unconnected Xilinx Ethernet MAC.\n");
856 93f1e401 Edgar E. Iglesias
    }
857 93f1e401 Edgar E. Iglesias
858 93f1e401 Edgar E. Iglesias
    xlx_dma_connect_client(s->dmach, s, axienet_stream_push);
859 93f1e401 Edgar E. Iglesias
860 93f1e401 Edgar E. Iglesias
    enet_regs = cpu_register_io_memory(enet_read, enet_write, s,
861 93f1e401 Edgar E. Iglesias
                                       DEVICE_LITTLE_ENDIAN);
862 93f1e401 Edgar E. Iglesias
    sysbus_init_mmio(dev, 0x40000, enet_regs);
863 93f1e401 Edgar E. Iglesias
864 93f1e401 Edgar E. Iglesias
    qemu_macaddr_default_if_unset(&s->conf.macaddr);
865 93f1e401 Edgar E. Iglesias
    s->nic = qemu_new_nic(&net_xilinx_enet_info, &s->conf,
866 93f1e401 Edgar E. Iglesias
                          dev->qdev.info->name, dev->qdev.id, s);
867 93f1e401 Edgar E. Iglesias
    qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
868 93f1e401 Edgar E. Iglesias
869 93f1e401 Edgar E. Iglesias
    tdk_init(&s->TEMAC.phy);
870 93f1e401 Edgar E. Iglesias
    mdio_attach(&s->TEMAC.mdio_bus, &s->TEMAC.phy, s->c_phyaddr);
871 93f1e401 Edgar E. Iglesias
872 93f1e401 Edgar E. Iglesias
    s->TEMAC.parent = s;
873 93f1e401 Edgar E. Iglesias
874 93f1e401 Edgar E. Iglesias
    s->rxmem = qemu_malloc(s->c_rxmem);
875 93f1e401 Edgar E. Iglesias
    axienet_reset(s);
876 93f1e401 Edgar E. Iglesias
877 93f1e401 Edgar E. Iglesias
    return 0;
878 93f1e401 Edgar E. Iglesias
}
879 93f1e401 Edgar E. Iglesias
880 93f1e401 Edgar E. Iglesias
static SysBusDeviceInfo xilinx_enet_info = {
881 93f1e401 Edgar E. Iglesias
    .init = xilinx_enet_init,
882 93f1e401 Edgar E. Iglesias
    .qdev.name  = "xilinx,axienet",
883 93f1e401 Edgar E. Iglesias
    .qdev.size  = sizeof(struct XilinxAXIEnet),
884 93f1e401 Edgar E. Iglesias
    .qdev.props = (Property[]) {
885 93f1e401 Edgar E. Iglesias
        DEFINE_PROP_UINT32("phyaddr", struct XilinxAXIEnet, c_phyaddr, 7),
886 93f1e401 Edgar E. Iglesias
        DEFINE_PROP_UINT32("c_rxmem", struct XilinxAXIEnet, c_rxmem, 0x1000),
887 93f1e401 Edgar E. Iglesias
        DEFINE_PROP_UINT32("c_txmem", struct XilinxAXIEnet, c_txmem, 0x1000),
888 93f1e401 Edgar E. Iglesias
        DEFINE_PROP_PTR("dmach", struct XilinxAXIEnet, dmach),
889 93f1e401 Edgar E. Iglesias
        DEFINE_NIC_PROPERTIES(struct XilinxAXIEnet, conf),
890 93f1e401 Edgar E. Iglesias
        DEFINE_PROP_END_OF_LIST(),
891 93f1e401 Edgar E. Iglesias
    }
892 93f1e401 Edgar E. Iglesias
};
893 93f1e401 Edgar E. Iglesias
static void xilinx_enet_register(void)
894 93f1e401 Edgar E. Iglesias
{
895 93f1e401 Edgar E. Iglesias
    sysbus_register_withprop(&xilinx_enet_info);
896 93f1e401 Edgar E. Iglesias
}
897 93f1e401 Edgar E. Iglesias
898 93f1e401 Edgar E. Iglesias
device_init(xilinx_enet_register)