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

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>
1.1.1.9 ! root       26: #include "sysbus.h"
1.1       root       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: {
1.1.1.9 ! root      322:        SysBusDevice busdev;
        !           323:        MemoryRegion mmio;
1.1.1.5   root      324:        NICState *nic;
                    325:        NICConf conf;
1.1       root      326:        int ethregs;
                    327: 
                    328:        /* Two addrs in the filter.  */
                    329:        uint8_t macaddr[2][6];
                    330:        uint32_t regs[FS_ETH_MAX_REGS];
                    331: 
1.1.1.9 ! root      332:        union {
        !           333:                void *vdma_out;
        !           334:                struct etraxfs_dma_client *dma_out;
        !           335:        };
        !           336:        union {
        !           337:                void *vdma_in;
        !           338:                struct etraxfs_dma_client *dma_in;
        !           339:        };
1.1       root      340: 
                    341:        /* MDIO bus.  */
                    342:        struct qemu_mdio mdio_bus;
                    343:        unsigned int phyaddr;
                    344:        int duplex_mismatch;
                    345: 
                    346:        /* PHY.  */
                    347:        struct qemu_phy phy;
                    348: };
                    349: 
                    350: static void eth_validate_duplex(struct fs_eth *eth)
                    351: {
                    352:        struct qemu_phy *phy;
                    353:        unsigned int phy_duplex;
                    354:        unsigned int mac_duplex;
                    355:        int new_mm = 0;
                    356: 
                    357:        phy = eth->mdio_bus.devs[eth->phyaddr];
                    358:        phy_duplex = !!(phy->read(phy, 18) & (1 << 11));
                    359:        mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128);
                    360: 
                    361:        if (mac_duplex != phy_duplex)
                    362:                new_mm = 1;
                    363: 
                    364:        if (eth->regs[RW_GEN_CTRL] & 1) {
                    365:                if (new_mm != eth->duplex_mismatch) {
                    366:                        if (new_mm)
                    367:                                printf("HW: WARNING "
                    368:                                       "ETH duplex mismatch MAC=%d PHY=%d\n",
                    369:                                       mac_duplex, phy_duplex);
                    370:                        else
                    371:                                printf("HW: ETH duplex ok.\n");
                    372:                }
                    373:                eth->duplex_mismatch = new_mm;
                    374:        }
                    375: }
                    376: 
1.1.1.9 ! root      377: static uint64_t
        !           378: eth_read(void *opaque, target_phys_addr_t addr, unsigned int size)
1.1       root      379: {
                    380:        struct fs_eth *eth = opaque;
                    381:        uint32_t r = 0;
                    382: 
                    383:        addr >>= 2;
                    384: 
                    385:        switch (addr) {
                    386:                case R_STAT:
                    387:                        r = eth->mdio_bus.mdio & 1;
                    388:                        break;
                    389:        default:
                    390:                r = eth->regs[addr];
                    391:                D(printf ("%s %x\n", __func__, addr * 4));
                    392:                break;
                    393:        }
                    394:        return r;
                    395: }
                    396: 
                    397: static void eth_update_ma(struct fs_eth *eth, int ma)
                    398: {
                    399:        int reg;
                    400:        int i = 0;
                    401: 
                    402:        ma &= 1;
                    403: 
                    404:        reg = RW_MA0_LO;
                    405:        if (ma)
                    406:                reg = RW_MA1_LO;
                    407: 
                    408:        eth->macaddr[ma][i++] = eth->regs[reg];
                    409:        eth->macaddr[ma][i++] = eth->regs[reg] >> 8;
                    410:        eth->macaddr[ma][i++] = eth->regs[reg] >> 16;
                    411:        eth->macaddr[ma][i++] = eth->regs[reg] >> 24;
1.1.1.3   root      412:        eth->macaddr[ma][i++] = eth->regs[reg + 1];
1.1.1.6   root      413:        eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8;
1.1       root      414: 
                    415:        D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma,
                    416:                 eth->macaddr[ma][0], eth->macaddr[ma][1],
                    417:                 eth->macaddr[ma][2], eth->macaddr[ma][3],
                    418:                 eth->macaddr[ma][4], eth->macaddr[ma][5]));
                    419: }
                    420: 
                    421: static void
1.1.1.9 ! root      422: eth_write(void *opaque, target_phys_addr_t addr,
        !           423:           uint64_t val64, unsigned int size)
1.1       root      424: {
                    425:        struct fs_eth *eth = opaque;
1.1.1.9 ! root      426:        uint32_t value = val64;
1.1       root      427: 
                    428:        addr >>= 2;
                    429:        switch (addr)
                    430:        {
                    431:                case RW_MA0_LO:
                    432:                case RW_MA0_HI:
                    433:                        eth->regs[addr] = value;
                    434:                        eth_update_ma(eth, 0);
                    435:                        break;
                    436:                case RW_MA1_LO:
                    437:                case RW_MA1_HI:
                    438:                        eth->regs[addr] = value;
                    439:                        eth_update_ma(eth, 1);
                    440:                        break;
                    441: 
                    442:                case RW_MGM_CTRL:
                    443:                        /* Attach an MDIO/PHY abstraction.  */
                    444:                        if (value & 2)
                    445:                                eth->mdio_bus.mdio = value & 1;
                    446:                        if (eth->mdio_bus.mdc != (value & 4)) {
                    447:                                mdio_cycle(&eth->mdio_bus);
                    448:                                eth_validate_duplex(eth);
                    449:                        }
                    450:                        eth->mdio_bus.mdc = !!(value & 4);
1.1.1.6   root      451:                        eth->regs[addr] = value;
1.1       root      452:                        break;
                    453: 
                    454:                case RW_REC_CTRL:
                    455:                        eth->regs[addr] = value;
                    456:                        eth_validate_duplex(eth);
                    457:                        break;
                    458: 
                    459:                default:
                    460:                        eth->regs[addr] = value;
                    461:                        D(printf ("%s %x %x\n",
                    462:                                  __func__, addr, value));
                    463:                        break;
                    464:        }
                    465: }
                    466: 
                    467: /* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom
                    468:    filter dropping group addresses we have not joined. The filter has 64
                    469:    bits (m). The has function is a simple nible xor of the group addr. */
                    470: static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
                    471: {
                    472:        unsigned int hsh;
                    473:        int m_individual = eth->regs[RW_REC_CTRL] & 4;
                    474:        int match;
                    475: 
                    476:        /* First bit on the wire of a MAC address signals multicast or
                    477:           physical address.  */
1.1.1.7   root      478:        if (!m_individual && !(sa[0] & 1))
1.1       root      479:                return 0;
                    480: 
                    481:        /* Calculate the hash index for the GA registers. */
                    482:        hsh = 0;
                    483:        hsh ^= (*sa) & 0x3f;
                    484:        hsh ^= ((*sa) >> 6) & 0x03;
                    485:        ++sa;
                    486:        hsh ^= ((*sa) << 2) & 0x03c;
                    487:        hsh ^= ((*sa) >> 4) & 0xf;
                    488:        ++sa;
                    489:        hsh ^= ((*sa) << 4) & 0x30;
                    490:        hsh ^= ((*sa) >> 2) & 0x3f;
                    491:        ++sa;
                    492:        hsh ^= (*sa) & 0x3f;
                    493:        hsh ^= ((*sa) >> 6) & 0x03;
                    494:        ++sa;
                    495:        hsh ^= ((*sa) << 2) & 0x03c;
                    496:        hsh ^= ((*sa) >> 4) & 0xf;
                    497:        ++sa;
                    498:        hsh ^= ((*sa) << 4) & 0x30;
                    499:        hsh ^= ((*sa) >> 2) & 0x3f;
                    500: 
                    501:        hsh &= 63;
                    502:        if (hsh > 31)
                    503:                match = eth->regs[RW_GA_HI] & (1 << (hsh - 32));
                    504:        else
                    505:                match = eth->regs[RW_GA_LO] & (1 << hsh);
                    506:        D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh,
                    507:                 eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match));
                    508:        return match;
                    509: }
                    510: 
1.1.1.5   root      511: static int eth_can_receive(VLANClientState *nc)
1.1       root      512: {
                    513:        return 1;
                    514: }
                    515: 
1.1.1.5   root      516: static ssize_t eth_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
1.1       root      517: {
                    518:        unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1.1.1.5   root      519:        struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
1.1       root      520:        int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
                    521:        int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
                    522:        int r_bcast = eth->regs[RW_REC_CTRL] & 8;
                    523: 
                    524:        if (size < 12)
1.1.1.4   root      525:                return -1;
1.1       root      526: 
                    527:        D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
                    528:                 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
                    529:                 use_ma0, use_ma1, r_bcast));
                    530:               
                    531:        /* Does the frame get through the address filters?  */
                    532:        if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6))
                    533:            && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
                    534:            && (!r_bcast || memcmp(buf, sa_bcast, 6))
                    535:            && !eth_match_groupaddr(eth, buf))
1.1.1.4   root      536:                return size;
1.1       root      537: 
                    538:        /* FIXME: Find another way to pass on the fake csum.  */
                    539:        etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
1.1.1.4   root      540: 
                    541:         return size;
1.1       root      542: }
                    543: 
                    544: static int eth_tx_push(void *opaque, unsigned char *buf, int len)
                    545: {
                    546:        struct fs_eth *eth = opaque;
                    547: 
                    548:        D(printf("%s buf=%p len=%d\n", __func__, buf, len));
1.1.1.5   root      549:        qemu_send_packet(&eth->nic->nc, buf, len);
1.1       root      550:        return len;
                    551: }
                    552: 
1.1.1.5   root      553: static void eth_set_link(VLANClientState *nc)
1.1       root      554: {
1.1.1.5   root      555:        struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
                    556:        D(printf("%s %d\n", __func__, nc->link_down));
                    557:        eth->phy.link = !nc->link_down;
1.1       root      558: }
                    559: 
1.1.1.9 ! root      560: static const MemoryRegionOps eth_ops = {
        !           561:        .read = eth_read,
        !           562:        .write = eth_write,
        !           563:        .endianness = DEVICE_LITTLE_ENDIAN,
        !           564:        .valid = {
        !           565:                .min_access_size = 4,
        !           566:                .max_access_size = 4
        !           567:        }
1.1       root      568: };
                    569: 
1.1.1.5   root      570: static void eth_cleanup(VLANClientState *nc)
1.1.1.2   root      571: {
1.1.1.5   root      572:        struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque;
1.1.1.2   root      573: 
                    574:         cpu_unregister_io_memory(eth->ethregs);
                    575: 
1.1.1.9 ! root      576:        /* Disconnect the client.  */
        !           577:        eth->dma_out->client.push = NULL;
        !           578:        eth->dma_out->client.opaque = NULL;
        !           579:        eth->dma_in->client.opaque = NULL;
        !           580:        eth->dma_in->client.pull = NULL;
        !           581:         g_free(eth);
1.1.1.2   root      582: }
                    583: 
1.1.1.5   root      584: static NetClientInfo net_etraxfs_info = {
                    585:        .type = NET_CLIENT_TYPE_NIC,
                    586:        .size = sizeof(NICState),
                    587:        .can_receive = eth_can_receive,
                    588:        .receive = eth_receive,
                    589:        .cleanup = eth_cleanup,
                    590:        .link_status_changed = eth_set_link,
                    591: };
                    592: 
1.1.1.9 ! root      593: static int fs_eth_init(SysBusDevice *dev)
1.1       root      594: {
1.1.1.9 ! root      595:        struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev);
1.1       root      596: 
1.1.1.9 ! root      597:        if (!s->dma_out || !s->dma_in) {
        !           598:                hw_error("Unconnected ETRAX-FS Ethernet MAC.\n");
        !           599:        }
1.1.1.5   root      600: 
1.1.1.9 ! root      601:        s->dma_out->client.push = eth_tx_push;
        !           602:        s->dma_out->client.opaque = s;
        !           603:        s->dma_in->client.opaque = s;
        !           604:        s->dma_in->client.pull = NULL;
        !           605: 
        !           606:        memory_region_init_io(&s->mmio, &eth_ops, s, "etraxfs-eth", 0x5c);
        !           607:        sysbus_init_mmio_region(dev, &s->mmio);
        !           608: 
        !           609:        qemu_macaddr_default_if_unset(&s->conf.macaddr);
        !           610:        s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf,
        !           611:                              dev->qdev.info->name, dev->qdev.id, s);
        !           612:        qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
        !           613: 
        !           614:        tdk_init(&s->phy);
        !           615:        mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr);
        !           616:        return 0;
        !           617: }
        !           618: 
        !           619: static SysBusDeviceInfo etraxfs_eth_info = {
        !           620:        .init = fs_eth_init,
        !           621:        .qdev.name  = "etraxfs-eth",
        !           622:        .qdev.size  = sizeof(struct fs_eth),
        !           623:        .qdev.props = (Property[]) {
        !           624:                DEFINE_PROP_UINT32("phyaddr", struct fs_eth, phyaddr, 1),
        !           625:                DEFINE_PROP_PTR("dma_out", struct fs_eth, vdma_out),
        !           626:                DEFINE_PROP_PTR("dma_in", struct fs_eth, vdma_in),
        !           627:                DEFINE_NIC_PROPERTIES(struct fs_eth, conf),
        !           628:                DEFINE_PROP_END_OF_LIST(),
        !           629:        }
        !           630: };
1.1       root      631: 
1.1.1.9 ! root      632: static void etraxfs_eth_register(void)
        !           633: {
        !           634:        sysbus_register_withprop(&etraxfs_eth_info);
1.1       root      635: }
1.1.1.9 ! root      636: 
        !           637: device_init(etraxfs_eth_register)

unix.superglobalmegacorp.com

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