Annotation of qemu/hw/etraxfs_eth.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * QEMU ETRAX Ethernet Controller.
        !             3:  *
        !             4:  * Copyright (c) 2008 Edgar E. Iglesias, Axis Communications AB.
        !             5:  *
        !             6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
        !             7:  * of this software and associated documentation files (the "Software"), to deal
        !             8:  * in the Software without restriction, including without limitation the rights
        !             9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        !            10:  * copies of the Software, and to permit persons to whom the Software is
        !            11:  * furnished to do so, subject to the following conditions:
        !            12:  *
        !            13:  * The above copyright notice and this permission notice shall be included in
        !            14:  * all copies or substantial portions of the Software.
        !            15:  *
        !            16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        !            17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
        !            19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        !            20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        !            21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
        !            22:  * THE SOFTWARE.
        !            23:  */
        !            24: 
        !            25: #include <stdio.h>
        !            26: #include "hw.h"
        !            27: #include "net.h"
        !            28: #include "etraxfs.h"
        !            29: 
        !            30: #define D(x)
        !            31: 
        !            32: /* Advertisement control register. */
        !            33: #define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
        !            34: #define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
        !            35: #define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
        !            36: #define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
        !            37: 
        !            38: /* 
        !            39:  * The MDIO extensions in the TDK PHY model were reversed engineered from the 
        !            40:  * linux driver (PHYID and Diagnostics reg).
        !            41:  * TODO: Add friendly names for the register nums.
        !            42:  */
        !            43: struct qemu_phy
        !            44: {
        !            45:        uint32_t regs[32];
        !            46: 
        !            47:        int link;
        !            48: 
        !            49:        unsigned int (*read)(struct qemu_phy *phy, unsigned int req);
        !            50:        void (*write)(struct qemu_phy *phy, unsigned int req, 
        !            51:                      unsigned int data);
        !            52: };
        !            53: 
        !            54: static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req)
        !            55: {
        !            56:        int regnum;
        !            57:        unsigned r = 0;
        !            58: 
        !            59:        regnum = req & 0x1f;
        !            60: 
        !            61:        switch (regnum) {
        !            62:                case 1:
        !            63:                        if (!phy->link)
        !            64:                                break;
        !            65:                        /* MR1.  */
        !            66:                        /* Speeds and modes.  */
        !            67:                        r |= (1 << 13) | (1 << 14);
        !            68:                        r |= (1 << 11) | (1 << 12);
        !            69:                        r |= (1 << 5); /* Autoneg complete.  */
        !            70:                        r |= (1 << 3); /* Autoneg able.  */
        !            71:                        r |= (1 << 2); /* link.  */
        !            72:                        break;
        !            73:                case 5:
        !            74:                        /* Link partner ability.
        !            75:                           We are kind; always agree with whatever best mode
        !            76:                           the guest advertises.  */
        !            77:                        r = 1 << 14; /* Success.  */
        !            78:                        /* Copy advertised modes.  */
        !            79:                        r |= phy->regs[4] & (15 << 5);
        !            80:                        /* Autoneg support.  */
        !            81:                        r |= 1;
        !            82:                        break;
        !            83:                case 18:
        !            84:                {
        !            85:                        /* Diagnostics reg.  */
        !            86:                        int duplex = 0;
        !            87:                        int speed_100 = 0;
        !            88: 
        !            89:                        if (!phy->link)
        !            90:                                break;
        !            91: 
        !            92:                        /* Are we advertising 100 half or 100 duplex ? */
        !            93:                        speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF);
        !            94:                        speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL);
        !            95: 
        !            96:                        /* Are we advertising 10 duplex or 100 duplex ? */
        !            97:                        duplex = !!(phy->regs[4] & ADVERTISE_100FULL);
        !            98:                        duplex |= !!(phy->regs[4] & ADVERTISE_10FULL);
        !            99:                        r = (speed_100 << 10) | (duplex << 11);
        !           100:                }
        !           101:                break;
        !           102: 
        !           103:                default:
        !           104:                        r = phy->regs[regnum];
        !           105:                        break;
        !           106:        }
        !           107:        D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum));
        !           108:        return r;
        !           109: }
        !           110: 
        !           111: static void 
        !           112: tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data)
        !           113: {
        !           114:        int regnum;
        !           115: 
        !           116:        regnum = req & 0x1f;
        !           117:        D(printf("%s reg[%d] = %x\n", __func__, regnum, data));
        !           118:        switch (regnum) {
        !           119:                default:
        !           120:                        phy->regs[regnum] = data;
        !           121:                        break;
        !           122:        }
        !           123: }
        !           124: 
        !           125: static void 
        !           126: tdk_init(struct qemu_phy *phy)
        !           127: {
        !           128:        phy->regs[0] = 0x3100;
        !           129:        /* PHY Id.  */
        !           130:        phy->regs[2] = 0x0300;
        !           131:        phy->regs[3] = 0xe400;
        !           132:        /* Autonegotiation advertisement reg.  */
        !           133:        phy->regs[4] = 0x01E1;
        !           134:        phy->link = 1;
        !           135: 
        !           136:        phy->read = tdk_read;
        !           137:        phy->write = tdk_write;
        !           138: }
        !           139: 
        !           140: struct qemu_mdio
        !           141: {
        !           142:        /* bus.  */
        !           143:        int mdc;
        !           144:        int mdio;
        !           145: 
        !           146:        /* decoder.  */
        !           147:        enum {
        !           148:                PREAMBLE,
        !           149:                SOF,
        !           150:                OPC,
        !           151:                ADDR,
        !           152:                REQ,
        !           153:                TURNAROUND,
        !           154:                DATA
        !           155:        } state;
        !           156:        unsigned int drive;
        !           157: 
        !           158:        unsigned int cnt;
        !           159:        unsigned int addr;
        !           160:        unsigned int opc;
        !           161:        unsigned int req;
        !           162:        unsigned int data;
        !           163: 
        !           164:        struct qemu_phy *devs[32];
        !           165: };
        !           166: 
        !           167: static void 
        !           168: mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
        !           169: {
        !           170:        bus->devs[addr & 0x1f] = phy;
        !           171: }
        !           172: 
        !           173: #ifdef USE_THIS_DEAD_CODE
        !           174: static void 
        !           175: mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr)
        !           176: {
        !           177:        bus->devs[addr & 0x1f] = NULL;  
        !           178: }
        !           179: #endif
        !           180: 
        !           181: static void mdio_read_req(struct qemu_mdio *bus)
        !           182: {
        !           183:        struct qemu_phy *phy;
        !           184: 
        !           185:        phy = bus->devs[bus->addr];
        !           186:        if (phy && phy->read)
        !           187:                bus->data = phy->read(phy, bus->req);
        !           188:        else 
        !           189:                bus->data = 0xffff;
        !           190: }
        !           191: 
        !           192: static void mdio_write_req(struct qemu_mdio *bus)
        !           193: {
        !           194:        struct qemu_phy *phy;
        !           195: 
        !           196:        phy = bus->devs[bus->addr];
        !           197:        if (phy && phy->write)
        !           198:                phy->write(phy, bus->req, bus->data);
        !           199: }
        !           200: 
        !           201: static void mdio_cycle(struct qemu_mdio *bus)
        !           202: {
        !           203:        bus->cnt++;
        !           204: 
        !           205:        D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n",
        !           206:                bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive));
        !           207: #if 0
        !           208:        if (bus->mdc)
        !           209:                printf("%d", bus->mdio);
        !           210: #endif
        !           211:        switch (bus->state)
        !           212:        {
        !           213:                case PREAMBLE:
        !           214:                        if (bus->mdc) {
        !           215:                                if (bus->cnt >= (32 * 2) && !bus->mdio) {
        !           216:                                        bus->cnt = 0;
        !           217:                                        bus->state = SOF;
        !           218:                                        bus->data = 0;
        !           219:                                }
        !           220:                        }
        !           221:                        break;
        !           222:                case SOF:
        !           223:                        if (bus->mdc) {
        !           224:                                if (bus->mdio != 1)
        !           225:                                        printf("WARNING: no SOF\n");
        !           226:                                if (bus->cnt == 1*2) {
        !           227:                                        bus->cnt = 0;
        !           228:                                        bus->opc = 0;
        !           229:                                        bus->state = OPC;
        !           230:                                }
        !           231:                        }
        !           232:                        break;
        !           233:                case OPC:
        !           234:                        if (bus->mdc) {
        !           235:                                bus->opc <<= 1;
        !           236:                                bus->opc |= bus->mdio & 1;
        !           237:                                if (bus->cnt == 2*2) {
        !           238:                                        bus->cnt = 0;
        !           239:                                        bus->addr = 0;
        !           240:                                        bus->state = ADDR;
        !           241:                                }
        !           242:                        }
        !           243:                        break;
        !           244:                case ADDR:
        !           245:                        if (bus->mdc) {
        !           246:                                bus->addr <<= 1;
        !           247:                                bus->addr |= bus->mdio & 1;
        !           248: 
        !           249:                                if (bus->cnt == 5*2) {
        !           250:                                        bus->cnt = 0;
        !           251:                                        bus->req = 0;
        !           252:                                        bus->state = REQ;
        !           253:                                }
        !           254:                        }
        !           255:                        break;
        !           256:                case REQ:
        !           257:                        if (bus->mdc) {
        !           258:                                bus->req <<= 1;
        !           259:                                bus->req |= bus->mdio & 1;
        !           260:                                if (bus->cnt == 5*2) {
        !           261:                                        bus->cnt = 0;
        !           262:                                        bus->state = TURNAROUND;
        !           263:                                }
        !           264:                        }
        !           265:                        break;
        !           266:                case TURNAROUND:
        !           267:                        if (bus->mdc && bus->cnt == 2*2) {
        !           268:                                bus->mdio = 0;
        !           269:                                bus->cnt = 0;
        !           270: 
        !           271:                                if (bus->opc == 2) {
        !           272:                                        bus->drive = 1;
        !           273:                                        mdio_read_req(bus);
        !           274:                                        bus->mdio = bus->data & 1;
        !           275:                                }
        !           276:                                bus->state = DATA;
        !           277:                        }
        !           278:                        break;
        !           279:                case DATA:                      
        !           280:                        if (!bus->mdc) {
        !           281:                                if (bus->drive) {
        !           282:                                        bus->mdio = !!(bus->data & (1 << 15));
        !           283:                                        bus->data <<= 1;
        !           284:                                }
        !           285:                        } else {
        !           286:                                if (!bus->drive) {
        !           287:                                        bus->data <<= 1;
        !           288:                                        bus->data |= bus->mdio;
        !           289:                                }
        !           290:                                if (bus->cnt == 16 * 2) {
        !           291:                                        bus->cnt = 0;
        !           292:                                        bus->state = PREAMBLE;
        !           293:                                        if (!bus->drive)
        !           294:                                                mdio_write_req(bus);
        !           295:                                        bus->drive = 0;
        !           296:                                }
        !           297:                        }
        !           298:                        break;
        !           299:                default:
        !           300:                        break;
        !           301:        }
        !           302: }
        !           303: 
        !           304: /* ETRAX-FS Ethernet MAC block starts here.  */
        !           305: 
        !           306: #define RW_MA0_LO        0x00
        !           307: #define RW_MA0_HI        0x01
        !           308: #define RW_MA1_LO        0x02
        !           309: #define RW_MA1_HI        0x03
        !           310: #define RW_GA_LO         0x04
        !           311: #define RW_GA_HI         0x05
        !           312: #define RW_GEN_CTRL      0x06
        !           313: #define RW_REC_CTRL      0x07
        !           314: #define RW_TR_CTRL       0x08
        !           315: #define RW_CLR_ERR       0x09
        !           316: #define RW_MGM_CTRL      0x0a
        !           317: #define R_STAT           0x0b
        !           318: #define FS_ETH_MAX_REGS          0x17
        !           319: 
        !           320: struct fs_eth
        !           321: {
        !           322:        CPUState *env;
        !           323:        qemu_irq *irq;
        !           324:        VLANClientState *vc;
        !           325:        int ethregs;
        !           326: 
        !           327:        /* Two addrs in the filter.  */
        !           328:        uint8_t macaddr[2][6];
        !           329:        uint32_t regs[FS_ETH_MAX_REGS];
        !           330: 
        !           331:        struct etraxfs_dma_client *dma_out;
        !           332:        struct etraxfs_dma_client *dma_in;
        !           333: 
        !           334:        /* MDIO bus.  */
        !           335:        struct qemu_mdio mdio_bus;
        !           336:        unsigned int phyaddr;
        !           337:        int duplex_mismatch;
        !           338: 
        !           339:        /* PHY.  */
        !           340:        struct qemu_phy phy;
        !           341: };
        !           342: 
        !           343: static void eth_validate_duplex(struct fs_eth *eth)
        !           344: {
        !           345:        struct qemu_phy *phy;
        !           346:        unsigned int phy_duplex;
        !           347:        unsigned int mac_duplex;
        !           348:        int new_mm = 0;
        !           349: 
        !           350:        phy = eth->mdio_bus.devs[eth->phyaddr];
        !           351:        phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
        !           352:        mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
        !           353: 
        !           354:        if (mac_duplex != phy_duplex)
        !           355:                new_mm = 1;
        !           356: 
        !           357:        if (eth->regs[RW_GEN_CTRL] & 1) {
        !           358:                if (new_mm != eth->duplex_mismatch) {
        !           359:                        if (new_mm)
        !           360:                                printf("HW: WARNING "
        !           361:                                       "ETH duplex mismatch MAC=%d PHY=%d\n",
        !           362:                                       mac_duplex, phy_duplex);
        !           363:                        else
        !           364:                                printf("HW: ETH duplex ok.\n");
        !           365:                }
        !           366:                eth->duplex_mismatch = new_mm;
        !           367:        }
        !           368: }
        !           369: 
        !           370: static uint32_t eth_readl (void *opaque, target_phys_addr_t addr)
        !           371: {
        !           372:        struct fs_eth *eth = opaque;
        !           373:        uint32_t r = 0;
        !           374: 
        !           375:        addr >>= 2;
        !           376: 
        !           377:        switch (addr) {
        !           378:                case R_STAT:
        !           379:                        r = eth->mdio_bus.mdio & 1;
        !           380:                        break;
        !           381:        default:
        !           382:                r = eth->regs[addr];
        !           383:                D(printf ("%s %x\n", __func__, addr * 4));
        !           384:                break;
        !           385:        }
        !           386:        return r;
        !           387: }
        !           388: 
        !           389: static void eth_update_ma(struct fs_eth *eth, int ma)
        !           390: {
        !           391:        int reg;
        !           392:        int i = 0;
        !           393: 
        !           394:        ma &= 1;
        !           395: 
        !           396:        reg = RW_MA0_LO;
        !           397:        if (ma)
        !           398:                reg = RW_MA1_LO;
        !           399: 
        !           400:        eth->macaddr[ma][i++] = eth->regs[reg];
        !           401:        eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
        !           402:        eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
        !           403:        eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
        !           404:        eth->macaddr[ma][i++] = eth->regs[reg + 4];
        !           405:        eth->macaddr[ma][i++] = eth->regs[reg + 4] >> 8;
        !           406: 
        !           407:        D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
        !           408:                 eth->macaddr[ma][0], eth->macaddr[ma][1],
        !           409:                 eth->macaddr[ma][2], eth->macaddr[ma][3],
        !           410:                 eth->macaddr[ma][4], eth->macaddr[ma][5]));
        !           411: }
        !           412: 
        !           413: static void
        !           414: eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
        !           415: {
        !           416:        struct fs_eth *eth = opaque;
        !           417: 
        !           418:        addr >>= 2;
        !           419:        switch (addr)
        !           420:        {
        !           421:                case RW_MA0_LO:
        !           422:                case RW_MA0_HI:
        !           423:                        eth->regs[addr] = value;
        !           424:                        eth_update_ma(eth, 0);
        !           425:                        break;
        !           426:                case RW_MA1_LO:
        !           427:                case RW_MA1_HI:
        !           428:                        eth->regs[addr] = value;
        !           429:                        eth_update_ma(eth, 1);
        !           430:                        break;
        !           431: 
        !           432:                case RW_MGM_CTRL:
        !           433:                        /* Attach an MDIO/PHY abstraction.  */
        !           434:                        if (value & 2)
        !           435:                                eth->mdio_bus.mdio = value & 1;
        !           436:                        if (eth->mdio_bus.mdc != (value & 4)) {
        !           437:                                mdio_cycle(&eth->mdio_bus);
        !           438:                                eth_validate_duplex(eth);
        !           439:                        }
        !           440:                        eth->mdio_bus.mdc = !!(value & 4);
        !           441:                        break;
        !           442: 
        !           443:                case RW_REC_CTRL:
        !           444:                        eth->regs[addr] = value;
        !           445:                        eth_validate_duplex(eth);
        !           446:                        break;
        !           447: 
        !           448:                default:
        !           449:                        eth->regs[addr] = value;
        !           450:                        D(printf ("%s %x %x\n",
        !           451:                                  __func__, addr, value));
        !           452:                        break;
        !           453:        }
        !           454: }
        !           455: 
        !           456: /* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
        !           457:    filter dropping group addresses we have not joined. The filter has 64
        !           458:    bits (m). The has function is a simple nible xor of the group addr. */
        !           459: static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
        !           460: {
        !           461:        unsigned int hsh;
        !           462:        int m_individual = eth->regs[RW_REC_CTRL] & 4;
        !           463:        int match;
        !           464: 
        !           465:        /* First bit on the wire of a MAC address signals multicast or
        !           466:           physical address.  */
        !           467:        if (!m_individual && !sa[0] & 1)
        !           468:                return 0;
        !           469: 
        !           470:        /* Calculate the hash index for the GA registers. */
        !           471:        hsh = 0;
        !           472:        hsh ^= (*sa) & 0x3f;
        !           473:        hsh ^= ((*sa) >> 6) & 0x03;
        !           474:        ++sa;
        !           475:        hsh ^= ((*sa) << 2) & 0x03c;
        !           476:        hsh ^= ((*sa) >> 4) & 0xf;
        !           477:        ++sa;
        !           478:        hsh ^= ((*sa) << 4) & 0x30;
        !           479:        hsh ^= ((*sa) >> 2) & 0x3f;
        !           480:        ++sa;
        !           481:        hsh ^= (*sa) & 0x3f;
        !           482:        hsh ^= ((*sa) >> 6) & 0x03;
        !           483:        ++sa;
        !           484:        hsh ^= ((*sa) << 2) & 0x03c;
        !           485:        hsh ^= ((*sa) >> 4) & 0xf;
        !           486:        ++sa;
        !           487:        hsh ^= ((*sa) << 4) & 0x30;
        !           488:        hsh ^= ((*sa) >> 2) & 0x3f;
        !           489: 
        !           490:        hsh &= 63;
        !           491:        if (hsh > 31)
        !           492:                match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
        !           493:        else
        !           494:                match = eth->regs[RW_GA_LO] & (1 << hsh);
        !           495:        D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
        !           496:                 eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
        !           497:        return match;
        !           498: }
        !           499: 
        !           500: static int eth_can_receive(void *opaque)
        !           501: {
        !           502:        return 1;
        !           503: }
        !           504: 
        !           505: static void eth_receive(void *opaque, const uint8_t *buf, int size)
        !           506: {
        !           507:        unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
        !           508:        struct fs_eth *eth = opaque;
        !           509:        int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
        !           510:        int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
        !           511:        int r_bcast = eth->regs[RW_REC_CTRL] & 8;
        !           512: 
        !           513:        if (size < 12)
        !           514:                return;
        !           515: 
        !           516:        D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
        !           517:                 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
        !           518:                 use_ma0, use_ma1, r_bcast));
        !           519:               
        !           520:        /* Does the frame get through the address filters?  */
        !           521:        if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
        !           522:            && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
        !           523:            && (!r_bcast || memcmp(buf, sa_bcast, 6))
        !           524:            && !eth_match_groupaddr(eth, buf))
        !           525:                return;
        !           526: 
        !           527:        /* FIXME: Find another way to pass on the fake csum.  */
        !           528:        etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
        !           529: }
        !           530: 
        !           531: static int eth_tx_push(void *opaque, unsigned char *buf, int len)
        !           532: {
        !           533:        struct fs_eth *eth = opaque;
        !           534: 
        !           535:        D(printf("%s buf=%p len=%d\n", __func__, buf, len));
        !           536:        qemu_send_packet(eth->vc, buf, len);
        !           537:        return len;
        !           538: }
        !           539: 
        !           540: static void eth_set_link(VLANClientState *vc)
        !           541: {
        !           542:        struct fs_eth *eth = vc->opaque;
        !           543:        D(printf("%s %d\n", __func__, vc->link_down));
        !           544:        eth->phy.link = !vc->link_down;
        !           545: }
        !           546: 
        !           547: static CPUReadMemoryFunc *eth_read[] = {
        !           548:        NULL, NULL,
        !           549:        &eth_readl,
        !           550: };
        !           551: 
        !           552: static CPUWriteMemoryFunc *eth_write[] = {
        !           553:        NULL, NULL,
        !           554:        &eth_writel,
        !           555: };
        !           556: 
        !           557: void *etraxfs_eth_init(NICInfo *nd, CPUState *env, 
        !           558:                       qemu_irq *irq, target_phys_addr_t base, int phyaddr)
        !           559: {
        !           560:        struct etraxfs_dma_client *dma = NULL;  
        !           561:        struct fs_eth *eth = NULL;
        !           562: 
        !           563:        qemu_check_nic_model(nd, "fseth");
        !           564: 
        !           565:        dma = qemu_mallocz(sizeof *dma * 2);
        !           566: 
        !           567:        eth = qemu_mallocz(sizeof *eth);
        !           568: 
        !           569:        dma[0].client.push = eth_tx_push;
        !           570:        dma[0].client.opaque = eth;
        !           571:        dma[1].client.opaque = eth;
        !           572:        dma[1].client.pull = NULL;
        !           573: 
        !           574:        eth->env = env;
        !           575:        eth->irq = irq;
        !           576:        eth->dma_out = dma;
        !           577:        eth->dma_in = dma + 1;
        !           578: 
        !           579:        /* Connect the phy.  */
        !           580:        eth->phyaddr = phyaddr & 0x1f;
        !           581:        tdk_init(&eth->phy);
        !           582:        mdio_attach(&eth->mdio_bus, &eth->phy, eth->phyaddr);
        !           583: 
        !           584:        eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth);
        !           585:        cpu_register_physical_memory (base, 0x5c, eth->ethregs);
        !           586: 
        !           587:        eth->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
        !           588:                                       eth_receive, eth_can_receive, eth);
        !           589:        eth->vc->opaque = eth;
        !           590:        eth->vc->link_status_changed = eth_set_link;
        !           591: 
        !           592:        return dma;
        !           593: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.