Annotation of qemu/hw/dp8393x.c, revision 1.1.1.6

1.1       root        1: /*
                      2:  * QEMU NS SONIC DP8393x netcard
                      3:  *
                      4:  * Copyright (c) 2008-2009 Herve Poussineau
                      5:  *
                      6:  * This program is free software; you can redistribute it and/or
                      7:  * modify it under the terms of the GNU General Public License as
                      8:  * published by the Free Software Foundation; either version 2 of
                      9:  * the License, or (at your option) any later version.
                     10:  *
                     11:  * This program is distributed in the hope that it will be useful,
                     12:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     14:  * GNU General Public License for more details.
                     15:  *
                     16:  * You should have received a copy of the GNU General Public License along
                     17:  * with this program; if not, see <http://www.gnu.org/licenses/>.
                     18:  */
                     19: 
                     20: #include "hw.h"
                     21: #include "qemu-timer.h"
                     22: #include "net.h"
                     23: #include "mips.h"
                     24: 
                     25: //#define DEBUG_SONIC
                     26: 
                     27: /* Calculate CRCs properly on Rx packets */
                     28: #define SONIC_CALCULATE_RXCRC
                     29: 
                     30: #if defined(SONIC_CALCULATE_RXCRC)
                     31: /* For crc32 */
                     32: #include <zlib.h>
                     33: #endif
                     34: 
                     35: #ifdef DEBUG_SONIC
                     36: #define DPRINTF(fmt, ...) \
                     37: do { printf("sonic: " fmt , ##  __VA_ARGS__); } while (0)
                     38: static const char* reg_names[] = {
                     39:     "CR", "DCR", "RCR", "TCR", "IMR", "ISR", "UTDA", "CTDA",
                     40:     "TPS", "TFC", "TSA0", "TSA1", "TFS", "URDA", "CRDA", "CRBA0",
                     41:     "CRBA1", "RBWC0", "RBWC1", "EOBC", "URRA", "RSA", "REA", "RRP",
                     42:     "RWP", "TRBA0", "TRBA1", "0x1b", "0x1c", "0x1d", "0x1e", "LLFA",
                     43:     "TTDA", "CEP", "CAP2", "CAP1", "CAP0", "CE", "CDP", "CDC",
                     44:     "SR", "WT0", "WT1", "RSC", "CRCT", "FAET", "MPT", "MDT",
                     45:     "0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37",
                     46:     "0x38", "0x39", "0x3a", "0x3b", "0x3c", "0x3d", "0x3e", "DCR2" };
                     47: #else
                     48: #define DPRINTF(fmt, ...) do {} while (0)
                     49: #endif
                     50: 
                     51: #define SONIC_ERROR(fmt, ...) \
                     52: do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
                     53: 
                     54: #define SONIC_CR     0x00
                     55: #define SONIC_DCR    0x01
                     56: #define SONIC_RCR    0x02
                     57: #define SONIC_TCR    0x03
                     58: #define SONIC_IMR    0x04
                     59: #define SONIC_ISR    0x05
                     60: #define SONIC_UTDA   0x06
                     61: #define SONIC_CTDA   0x07
                     62: #define SONIC_TPS    0x08
                     63: #define SONIC_TFC    0x09
                     64: #define SONIC_TSA0   0x0a
                     65: #define SONIC_TSA1   0x0b
                     66: #define SONIC_TFS    0x0c
                     67: #define SONIC_URDA   0x0d
                     68: #define SONIC_CRDA   0x0e
                     69: #define SONIC_CRBA0  0x0f
                     70: #define SONIC_CRBA1  0x10
                     71: #define SONIC_RBWC0  0x11
                     72: #define SONIC_RBWC1  0x12
                     73: #define SONIC_EOBC   0x13
                     74: #define SONIC_URRA   0x14
                     75: #define SONIC_RSA    0x15
                     76: #define SONIC_REA    0x16
                     77: #define SONIC_RRP    0x17
                     78: #define SONIC_RWP    0x18
                     79: #define SONIC_TRBA0  0x19
                     80: #define SONIC_TRBA1  0x1a
                     81: #define SONIC_LLFA   0x1f
                     82: #define SONIC_TTDA   0x20
                     83: #define SONIC_CEP    0x21
                     84: #define SONIC_CAP2   0x22
                     85: #define SONIC_CAP1   0x23
                     86: #define SONIC_CAP0   0x24
                     87: #define SONIC_CE     0x25
                     88: #define SONIC_CDP    0x26
                     89: #define SONIC_CDC    0x27
                     90: #define SONIC_SR     0x28
                     91: #define SONIC_WT0    0x29
                     92: #define SONIC_WT1    0x2a
                     93: #define SONIC_RSC    0x2b
                     94: #define SONIC_CRCT   0x2c
                     95: #define SONIC_FAET   0x2d
                     96: #define SONIC_MPT    0x2e
                     97: #define SONIC_MDT    0x2f
                     98: #define SONIC_DCR2   0x3f
                     99: 
                    100: #define SONIC_CR_HTX     0x0001
                    101: #define SONIC_CR_TXP     0x0002
                    102: #define SONIC_CR_RXDIS   0x0004
                    103: #define SONIC_CR_RXEN    0x0008
                    104: #define SONIC_CR_STP     0x0010
                    105: #define SONIC_CR_ST      0x0020
                    106: #define SONIC_CR_RST     0x0080
                    107: #define SONIC_CR_RRRA    0x0100
                    108: #define SONIC_CR_LCAM    0x0200
                    109: #define SONIC_CR_MASK    0x03bf
                    110: 
                    111: #define SONIC_DCR_DW     0x0020
                    112: #define SONIC_DCR_LBR    0x2000
                    113: #define SONIC_DCR_EXBUS  0x8000
                    114: 
                    115: #define SONIC_RCR_PRX    0x0001
                    116: #define SONIC_RCR_LBK    0x0002
                    117: #define SONIC_RCR_FAER   0x0004
                    118: #define SONIC_RCR_CRCR   0x0008
                    119: #define SONIC_RCR_CRS    0x0020
                    120: #define SONIC_RCR_LPKT   0x0040
                    121: #define SONIC_RCR_BC     0x0080
                    122: #define SONIC_RCR_MC     0x0100
                    123: #define SONIC_RCR_LB0    0x0200
                    124: #define SONIC_RCR_LB1    0x0400
                    125: #define SONIC_RCR_AMC    0x0800
                    126: #define SONIC_RCR_PRO    0x1000
                    127: #define SONIC_RCR_BRD    0x2000
                    128: #define SONIC_RCR_RNT    0x4000
                    129: 
                    130: #define SONIC_TCR_PTX    0x0001
                    131: #define SONIC_TCR_BCM    0x0002
                    132: #define SONIC_TCR_FU     0x0004
                    133: #define SONIC_TCR_EXC    0x0040
                    134: #define SONIC_TCR_CRSL   0x0080
                    135: #define SONIC_TCR_NCRS   0x0100
                    136: #define SONIC_TCR_EXD    0x0400
                    137: #define SONIC_TCR_CRCI   0x2000
                    138: #define SONIC_TCR_PINT   0x8000
                    139: 
                    140: #define SONIC_ISR_RBE    0x0020
                    141: #define SONIC_ISR_RDE    0x0040
                    142: #define SONIC_ISR_TC     0x0080
                    143: #define SONIC_ISR_TXDN   0x0200
                    144: #define SONIC_ISR_PKTRX  0x0400
                    145: #define SONIC_ISR_PINT   0x0800
                    146: #define SONIC_ISR_LCD    0x1000
                    147: 
                    148: typedef struct dp8393xState {
                    149:     /* Hardware */
                    150:     int it_shift;
                    151:     qemu_irq irq;
                    152: #ifdef DEBUG_SONIC
                    153:     int irq_level;
                    154: #endif
                    155:     QEMUTimer *watchdog;
                    156:     int64_t wt_last_update;
1.1.1.2   root      157:     NICConf conf;
                    158:     NICState *nic;
1.1.1.6 ! root      159:     MemoryRegion *address_space;
        !           160:     MemoryRegion mmio;
1.1       root      161: 
                    162:     /* Registers */
                    163:     uint8_t cam[16][6];
                    164:     uint16_t regs[0x40];
                    165: 
                    166:     /* Temporaries */
                    167:     uint8_t tx_buffer[0x10000];
                    168:     int loopback_packet;
                    169: 
                    170:     /* Memory access */
                    171:     void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write);
                    172:     void* mem_opaque;
                    173: } dp8393xState;
                    174: 
                    175: static void dp8393x_update_irq(dp8393xState *s)
                    176: {
                    177:     int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0;
                    178: 
                    179: #ifdef DEBUG_SONIC
                    180:     if (level != s->irq_level) {
                    181:         s->irq_level = level;
                    182:         if (level) {
                    183:             DPRINTF("raise irq, isr is 0x%04x\n", s->regs[SONIC_ISR]);
                    184:         } else {
                    185:             DPRINTF("lower irq\n");
                    186:         }
                    187:     }
                    188: #endif
                    189: 
                    190:     qemu_set_irq(s->irq, level);
                    191: }
                    192: 
                    193: static void do_load_cam(dp8393xState *s)
                    194: {
                    195:     uint16_t data[8];
                    196:     int width, size;
                    197:     uint16_t index = 0;
                    198: 
                    199:     width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
                    200:     size = sizeof(uint16_t) * 4 * width;
                    201: 
                    202:     while (s->regs[SONIC_CDC] & 0x1f) {
                    203:         /* Fill current entry */
                    204:         s->memory_rw(s->mem_opaque,
                    205:             (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
                    206:             (uint8_t *)data, size, 0);
                    207:         s->cam[index][0] = data[1 * width] & 0xff;
                    208:         s->cam[index][1] = data[1 * width] >> 8;
                    209:         s->cam[index][2] = data[2 * width] & 0xff;
                    210:         s->cam[index][3] = data[2 * width] >> 8;
                    211:         s->cam[index][4] = data[3 * width] & 0xff;
                    212:         s->cam[index][5] = data[3 * width] >> 8;
                    213:         DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index,
                    214:             s->cam[index][0], s->cam[index][1], s->cam[index][2],
                    215:             s->cam[index][3], s->cam[index][4], s->cam[index][5]);
                    216:         /* Move to next entry */
                    217:         s->regs[SONIC_CDC]--;
                    218:         s->regs[SONIC_CDP] += size;
                    219:         index++;
                    220:     }
                    221: 
                    222:     /* Read CAM enable */
                    223:     s->memory_rw(s->mem_opaque,
                    224:         (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
                    225:         (uint8_t *)data, size, 0);
                    226:     s->regs[SONIC_CE] = data[0 * width];
                    227:     DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
                    228: 
                    229:     /* Done */
                    230:     s->regs[SONIC_CR] &= ~SONIC_CR_LCAM;
                    231:     s->regs[SONIC_ISR] |= SONIC_ISR_LCD;
                    232:     dp8393x_update_irq(s);
                    233: }
                    234: 
                    235: static void do_read_rra(dp8393xState *s)
                    236: {
                    237:     uint16_t data[8];
                    238:     int width, size;
                    239: 
                    240:     /* Read memory */
                    241:     width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
                    242:     size = sizeof(uint16_t) * 4 * width;
                    243:     s->memory_rw(s->mem_opaque,
                    244:         (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP],
                    245:         (uint8_t *)data, size, 0);
                    246: 
                    247:     /* Update SONIC registers */
                    248:     s->regs[SONIC_CRBA0] = data[0 * width];
                    249:     s->regs[SONIC_CRBA1] = data[1 * width];
                    250:     s->regs[SONIC_RBWC0] = data[2 * width];
                    251:     s->regs[SONIC_RBWC1] = data[3 * width];
                    252:     DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n",
                    253:         s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1],
                    254:         s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]);
                    255: 
                    256:     /* Go to next entry */
                    257:     s->regs[SONIC_RRP] += size;
                    258: 
                    259:     /* Handle wrap */
                    260:     if (s->regs[SONIC_RRP] == s->regs[SONIC_REA]) {
                    261:         s->regs[SONIC_RRP] = s->regs[SONIC_RSA];
                    262:     }
                    263: 
                    264:     /* Check resource exhaustion */
                    265:     if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP])
                    266:     {
                    267:         s->regs[SONIC_ISR] |= SONIC_ISR_RBE;
                    268:         dp8393x_update_irq(s);
                    269:     }
                    270: 
                    271:     /* Done */
                    272:     s->regs[SONIC_CR] &= ~SONIC_CR_RRRA;
                    273: }
                    274: 
                    275: static void do_software_reset(dp8393xState *s)
                    276: {
                    277:     qemu_del_timer(s->watchdog);
                    278: 
                    279:     s->regs[SONIC_CR] &= ~(SONIC_CR_LCAM | SONIC_CR_RRRA | SONIC_CR_TXP | SONIC_CR_HTX);
                    280:     s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS;
                    281: }
                    282: 
                    283: static void set_next_tick(dp8393xState *s)
                    284: {
                    285:     uint32_t ticks;
                    286:     int64_t delay;
                    287: 
                    288:     if (s->regs[SONIC_CR] & SONIC_CR_STP) {
                    289:         qemu_del_timer(s->watchdog);
                    290:         return;
                    291:     }
                    292: 
                    293:     ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
1.1.1.4   root      294:     s->wt_last_update = qemu_get_clock_ns(vm_clock);
1.1.1.2   root      295:     delay = get_ticks_per_sec() * ticks / 5000000;
1.1       root      296:     qemu_mod_timer(s->watchdog, s->wt_last_update + delay);
                    297: }
                    298: 
                    299: static void update_wt_regs(dp8393xState *s)
                    300: {
                    301:     int64_t elapsed;
                    302:     uint32_t val;
                    303: 
                    304:     if (s->regs[SONIC_CR] & SONIC_CR_STP) {
                    305:         qemu_del_timer(s->watchdog);
                    306:         return;
                    307:     }
                    308: 
1.1.1.4   root      309:     elapsed = s->wt_last_update - qemu_get_clock_ns(vm_clock);
1.1       root      310:     val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
                    311:     val -= elapsed / 5000000;
                    312:     s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
                    313:     s->regs[SONIC_WT0] = (val >> 0)  & 0xffff;
                    314:     set_next_tick(s);
                    315: 
                    316: }
                    317: 
                    318: static void do_start_timer(dp8393xState *s)
                    319: {
                    320:     s->regs[SONIC_CR] &= ~SONIC_CR_STP;
                    321:     set_next_tick(s);
                    322: }
                    323: 
                    324: static void do_stop_timer(dp8393xState *s)
                    325: {
                    326:     s->regs[SONIC_CR] &= ~SONIC_CR_ST;
                    327:     update_wt_regs(s);
                    328: }
                    329: 
                    330: static void do_receiver_enable(dp8393xState *s)
                    331: {
                    332:     s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS;
                    333: }
                    334: 
                    335: static void do_receiver_disable(dp8393xState *s)
                    336: {
                    337:     s->regs[SONIC_CR] &= ~SONIC_CR_RXEN;
                    338: }
                    339: 
                    340: static void do_transmit_packets(dp8393xState *s)
                    341: {
                    342:     uint16_t data[12];
                    343:     int width, size;
                    344:     int tx_len, len;
                    345:     uint16_t i;
                    346: 
                    347:     width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
                    348: 
                    349:     while (1) {
                    350:         /* Read memory */
                    351:         DPRINTF("Transmit packet at %08x\n",
                    352:                 (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]);
                    353:         size = sizeof(uint16_t) * 6 * width;
                    354:         s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
                    355:         s->memory_rw(s->mem_opaque,
                    356:             ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width,
                    357:             (uint8_t *)data, size, 0);
                    358:         tx_len = 0;
                    359: 
                    360:         /* Update registers */
                    361:         s->regs[SONIC_TCR] = data[0 * width] & 0xf000;
                    362:         s->regs[SONIC_TPS] = data[1 * width];
                    363:         s->regs[SONIC_TFC] = data[2 * width];
                    364:         s->regs[SONIC_TSA0] = data[3 * width];
                    365:         s->regs[SONIC_TSA1] = data[4 * width];
                    366:         s->regs[SONIC_TFS] = data[5 * width];
                    367: 
                    368:         /* Handle programmable interrupt */
                    369:         if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) {
                    370:             s->regs[SONIC_ISR] |= SONIC_ISR_PINT;
                    371:         } else {
                    372:             s->regs[SONIC_ISR] &= ~SONIC_ISR_PINT;
                    373:         }
                    374: 
                    375:         for (i = 0; i < s->regs[SONIC_TFC]; ) {
                    376:             /* Append fragment */
                    377:             len = s->regs[SONIC_TFS];
                    378:             if (tx_len + len > sizeof(s->tx_buffer)) {
                    379:                 len = sizeof(s->tx_buffer) - tx_len;
                    380:             }
                    381:             s->memory_rw(s->mem_opaque,
                    382:                 (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0],
                    383:                 &s->tx_buffer[tx_len], len, 0);
                    384:             tx_len += len;
                    385: 
                    386:             i++;
                    387:             if (i != s->regs[SONIC_TFC]) {
                    388:                 /* Read next fragment details */
                    389:                 size = sizeof(uint16_t) * 3 * width;
                    390:                 s->memory_rw(s->mem_opaque,
                    391:                     ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width,
                    392:                     (uint8_t *)data, size, 0);
                    393:                 s->regs[SONIC_TSA0] = data[0 * width];
                    394:                 s->regs[SONIC_TSA1] = data[1 * width];
                    395:                 s->regs[SONIC_TFS] = data[2 * width];
                    396:             }
                    397:         }
                    398: 
                    399:         /* Handle Ethernet checksum */
                    400:         if (!(s->regs[SONIC_TCR] & SONIC_TCR_CRCI)) {
                    401:             /* Don't append FCS there, to look like slirp packets
                    402:              * which don't have one */
                    403:         } else {
                    404:             /* Remove existing FCS */
                    405:             tx_len -= 4;
                    406:         }
                    407: 
                    408:         if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) {
                    409:             /* Loopback */
                    410:             s->regs[SONIC_TCR] |= SONIC_TCR_CRSL;
1.1.1.2   root      411:             if (s->nic->nc.info->can_receive(&s->nic->nc)) {
1.1       root      412:                 s->loopback_packet = 1;
1.1.1.2   root      413:                 s->nic->nc.info->receive(&s->nic->nc, s->tx_buffer, tx_len);
1.1       root      414:             }
                    415:         } else {
                    416:             /* Transmit packet */
1.1.1.2   root      417:             qemu_send_packet(&s->nic->nc, s->tx_buffer, tx_len);
1.1       root      418:         }
                    419:         s->regs[SONIC_TCR] |= SONIC_TCR_PTX;
                    420: 
                    421:         /* Write status */
                    422:         data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
                    423:         size = sizeof(uint16_t) * width;
                    424:         s->memory_rw(s->mem_opaque,
                    425:             (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA],
                    426:             (uint8_t *)data, size, 1);
                    427: 
                    428:         if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
                    429:             /* Read footer of packet */
                    430:             size = sizeof(uint16_t) * width;
                    431:             s->memory_rw(s->mem_opaque,
                    432:                 ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width,
                    433:                 (uint8_t *)data, size, 0);
                    434:             s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
                    435:             if (data[0 * width] & 0x1) {
                    436:                 /* EOL detected */
                    437:                 break;
                    438:             }
                    439:         }
                    440:     }
                    441: 
                    442:     /* Done */
                    443:     s->regs[SONIC_CR] &= ~SONIC_CR_TXP;
                    444:     s->regs[SONIC_ISR] |= SONIC_ISR_TXDN;
                    445:     dp8393x_update_irq(s);
                    446: }
                    447: 
                    448: static void do_halt_transmission(dp8393xState *s)
                    449: {
                    450:     /* Nothing to do */
                    451: }
                    452: 
                    453: static void do_command(dp8393xState *s, uint16_t command)
                    454: {
                    455:     if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) {
                    456:         s->regs[SONIC_CR] &= ~SONIC_CR_RST;
                    457:         return;
                    458:     }
                    459: 
                    460:     s->regs[SONIC_CR] |= (command & SONIC_CR_MASK);
                    461: 
                    462:     if (command & SONIC_CR_HTX)
                    463:         do_halt_transmission(s);
                    464:     if (command & SONIC_CR_TXP)
                    465:         do_transmit_packets(s);
                    466:     if (command & SONIC_CR_RXDIS)
                    467:         do_receiver_disable(s);
                    468:     if (command & SONIC_CR_RXEN)
                    469:         do_receiver_enable(s);
                    470:     if (command & SONIC_CR_STP)
                    471:         do_stop_timer(s);
                    472:     if (command & SONIC_CR_ST)
                    473:         do_start_timer(s);
                    474:     if (command & SONIC_CR_RST)
                    475:         do_software_reset(s);
                    476:     if (command & SONIC_CR_RRRA)
                    477:         do_read_rra(s);
                    478:     if (command & SONIC_CR_LCAM)
                    479:         do_load_cam(s);
                    480: }
                    481: 
                    482: static uint16_t read_register(dp8393xState *s, int reg)
                    483: {
                    484:     uint16_t val = 0;
                    485: 
                    486:     switch (reg) {
                    487:         /* Update data before reading it */
                    488:         case SONIC_WT0:
                    489:         case SONIC_WT1:
                    490:             update_wt_regs(s);
                    491:             val = s->regs[reg];
                    492:             break;
                    493:         /* Accept read to some registers only when in reset mode */
                    494:         case SONIC_CAP2:
                    495:         case SONIC_CAP1:
                    496:         case SONIC_CAP0:
                    497:             if (s->regs[SONIC_CR] & SONIC_CR_RST) {
                    498:                 val = s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg) + 1] << 8;
                    499:                 val |= s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg)];
                    500:             }
                    501:             break;
                    502:         /* All other registers have no special contrainst */
                    503:         default:
                    504:             val = s->regs[reg];
                    505:     }
                    506: 
                    507:     DPRINTF("read 0x%04x from reg %s\n", val, reg_names[reg]);
                    508: 
                    509:     return val;
                    510: }
                    511: 
                    512: static void write_register(dp8393xState *s, int reg, uint16_t val)
                    513: {
                    514:     DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]);
                    515: 
                    516:     switch (reg) {
                    517:         /* Command register */
                    518:         case SONIC_CR:
1.1.1.6 ! root      519:             do_command(s, val);
1.1       root      520:             break;
                    521:         /* Prevent write to read-only registers */
                    522:         case SONIC_CAP2:
                    523:         case SONIC_CAP1:
                    524:         case SONIC_CAP0:
                    525:         case SONIC_SR:
                    526:         case SONIC_MDT:
                    527:             DPRINTF("writing to reg %d invalid\n", reg);
                    528:             break;
                    529:         /* Accept write to some registers only when in reset mode */
                    530:         case SONIC_DCR:
                    531:             if (s->regs[SONIC_CR] & SONIC_CR_RST) {
                    532:                 s->regs[reg] = val & 0xbfff;
                    533:             } else {
                    534:                 DPRINTF("writing to DCR invalid\n");
                    535:             }
                    536:             break;
                    537:         case SONIC_DCR2:
                    538:             if (s->regs[SONIC_CR] & SONIC_CR_RST) {
                    539:                 s->regs[reg] = val & 0xf017;
                    540:             } else {
                    541:                 DPRINTF("writing to DCR2 invalid\n");
                    542:             }
                    543:             break;
                    544:         /* 12 lower bytes are Read Only */
                    545:         case SONIC_TCR:
                    546:             s->regs[reg] = val & 0xf000;
                    547:             break;
                    548:         /* 9 lower bytes are Read Only */
                    549:         case SONIC_RCR:
                    550:             s->regs[reg] = val & 0xffe0;
                    551:             break;
                    552:         /* Ignore most significant bit */
                    553:         case SONIC_IMR:
                    554:             s->regs[reg] = val & 0x7fff;
                    555:             dp8393x_update_irq(s);
                    556:             break;
                    557:         /* Clear bits by writing 1 to them */
                    558:         case SONIC_ISR:
                    559:             val &= s->regs[reg];
                    560:             s->regs[reg] &= ~val;
                    561:             if (val & SONIC_ISR_RBE) {
                    562:                 do_read_rra(s);
                    563:             }
                    564:             dp8393x_update_irq(s);
                    565:             break;
                    566:         /* Ignore least significant bit */
                    567:         case SONIC_RSA:
                    568:         case SONIC_REA:
                    569:         case SONIC_RRP:
                    570:         case SONIC_RWP:
                    571:             s->regs[reg] = val & 0xfffe;
                    572:             break;
                    573:         /* Invert written value for some registers */
                    574:         case SONIC_CRCT:
                    575:         case SONIC_FAET:
                    576:         case SONIC_MPT:
                    577:             s->regs[reg] = val ^ 0xffff;
                    578:             break;
                    579:         /* All other registers have no special contrainst */
                    580:         default:
                    581:             s->regs[reg] = val;
                    582:     }
                    583: 
                    584:     if (reg == SONIC_WT0 || reg == SONIC_WT1) {
                    585:         set_next_tick(s);
                    586:     }
                    587: }
                    588: 
                    589: static void dp8393x_watchdog(void *opaque)
                    590: {
                    591:     dp8393xState *s = opaque;
                    592: 
                    593:     if (s->regs[SONIC_CR] & SONIC_CR_STP) {
                    594:         return;
                    595:     }
                    596: 
                    597:     s->regs[SONIC_WT1] = 0xffff;
                    598:     s->regs[SONIC_WT0] = 0xffff;
                    599:     set_next_tick(s);
                    600: 
                    601:     /* Signal underflow */
                    602:     s->regs[SONIC_ISR] |= SONIC_ISR_TC;
                    603:     dp8393x_update_irq(s);
                    604: }
                    605: 
                    606: static uint32_t dp8393x_readw(void *opaque, target_phys_addr_t addr)
                    607: {
                    608:     dp8393xState *s = opaque;
                    609:     int reg;
                    610: 
                    611:     if ((addr & ((1 << s->it_shift) - 1)) != 0) {
                    612:         return 0;
                    613:     }
                    614: 
                    615:     reg = addr >> s->it_shift;
                    616:     return read_register(s, reg);
                    617: }
                    618: 
                    619: static uint32_t dp8393x_readb(void *opaque, target_phys_addr_t addr)
                    620: {
                    621:     uint16_t v = dp8393x_readw(opaque, addr & ~0x1);
                    622:     return (v >> (8 * (addr & 0x1))) & 0xff;
                    623: }
                    624: 
                    625: static uint32_t dp8393x_readl(void *opaque, target_phys_addr_t addr)
                    626: {
                    627:     uint32_t v;
                    628:     v = dp8393x_readw(opaque, addr);
                    629:     v |= dp8393x_readw(opaque, addr + 2) << 16;
                    630:     return v;
                    631: }
                    632: 
                    633: static void dp8393x_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
                    634: {
                    635:     dp8393xState *s = opaque;
                    636:     int reg;
                    637: 
                    638:     if ((addr & ((1 << s->it_shift) - 1)) != 0) {
                    639:         return;
                    640:     }
                    641: 
                    642:     reg = addr >> s->it_shift;
                    643: 
                    644:     write_register(s, reg, (uint16_t)val);
                    645: }
                    646: 
                    647: static void dp8393x_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
                    648: {
                    649:     uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1);
                    650: 
                    651:     switch (addr & 3) {
                    652:     case 0:
                    653:         val = val | (old_val & 0xff00);
                    654:         break;
                    655:     case 1:
                    656:         val = (val << 8) | (old_val & 0x00ff);
                    657:         break;
                    658:     }
                    659:     dp8393x_writew(opaque, addr & ~0x1, val);
                    660: }
                    661: 
                    662: static void dp8393x_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
                    663: {
                    664:     dp8393x_writew(opaque, addr, val & 0xffff);
                    665:     dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff);
                    666: }
                    667: 
1.1.1.6 ! root      668: static const MemoryRegionOps dp8393x_ops = {
        !           669:     .old_mmio = {
        !           670:         .read = { dp8393x_readb, dp8393x_readw, dp8393x_readl, },
        !           671:         .write = { dp8393x_writeb, dp8393x_writew, dp8393x_writel, },
        !           672:     },
        !           673:     .endianness = DEVICE_NATIVE_ENDIAN,
1.1       root      674: };
                    675: 
1.1.1.2   root      676: static int nic_can_receive(VLANClientState *nc)
1.1       root      677: {
1.1.1.2   root      678:     dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque;
1.1       root      679: 
                    680:     if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN))
                    681:         return 0;
                    682:     if (s->regs[SONIC_ISR] & SONIC_ISR_RBE)
                    683:         return 0;
                    684:     return 1;
                    685: }
                    686: 
                    687: static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
                    688: {
                    689:     static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
                    690:     int i;
                    691: 
                    692:     /* Check for runt packet (remember that checksum is not there) */
                    693:     if (size < 64 - 4) {
                    694:         return (s->regs[SONIC_RCR] & SONIC_RCR_RNT) ? 0 : -1;
                    695:     }
                    696: 
                    697:     /* Check promiscuous mode */
                    698:     if ((s->regs[SONIC_RCR] & SONIC_RCR_PRO) && (buf[0] & 1) == 0) {
                    699:         return 0;
                    700:     }
                    701: 
                    702:     /* Check multicast packets */
                    703:     if ((s->regs[SONIC_RCR] & SONIC_RCR_AMC) && (buf[0] & 1) == 1) {
                    704:         return SONIC_RCR_MC;
                    705:     }
                    706: 
                    707:     /* Check broadcast */
                    708:     if ((s->regs[SONIC_RCR] & SONIC_RCR_BRD) && !memcmp(buf, bcast, sizeof(bcast))) {
                    709:         return SONIC_RCR_BC;
                    710:     }
                    711: 
                    712:     /* Check CAM */
                    713:     for (i = 0; i < 16; i++) {
                    714:         if (s->regs[SONIC_CE] & (1 << i)) {
                    715:              /* Entry enabled */
                    716:              if (!memcmp(buf, s->cam[i], sizeof(s->cam[i]))) {
                    717:                  return 0;
                    718:              }
                    719:         }
                    720:     }
                    721: 
                    722:     return -1;
                    723: }
                    724: 
1.1.1.2   root      725: static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size)
1.1       root      726: {
1.1.1.2   root      727:     dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque;
1.1       root      728:     uint16_t data[10];
                    729:     int packet_type;
                    730:     uint32_t available, address;
                    731:     int width, rx_len = size;
                    732:     uint32_t checksum;
                    733: 
                    734:     width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
                    735: 
                    736:     s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER |
                    737:         SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC);
                    738: 
                    739:     packet_type = receive_filter(s, buf, size);
                    740:     if (packet_type < 0) {
                    741:         DPRINTF("packet not for netcard\n");
                    742:         return -1;
                    743:     }
                    744: 
                    745:     /* XXX: Check byte ordering */
                    746: 
                    747:     /* Check for EOL */
                    748:     if (s->regs[SONIC_LLFA] & 0x1) {
                    749:         /* Are we still in resource exhaustion? */
                    750:         size = sizeof(uint16_t) * 1 * width;
                    751:         address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width;
                    752:         s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0);
                    753:         if (data[0 * width] & 0x1) {
                    754:             /* Still EOL ; stop reception */
                    755:             return -1;
                    756:         } else {
                    757:             s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
                    758:         }
                    759:     }
                    760: 
                    761:     /* Save current position */
                    762:     s->regs[SONIC_TRBA1] = s->regs[SONIC_CRBA1];
                    763:     s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0];
                    764: 
                    765:     /* Calculate the ethernet checksum */
                    766: #ifdef SONIC_CALCULATE_RXCRC
                    767:     checksum = cpu_to_le32(crc32(0, buf, rx_len));
                    768: #else
                    769:     checksum = 0;
                    770: #endif
                    771: 
                    772:     /* Put packet into RBA */
                    773:     DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]);
                    774:     address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0];
                    775:     s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1);
                    776:     address += rx_len;
                    777:     s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1);
                    778:     rx_len += 4;
                    779:     s->regs[SONIC_CRBA1] = address >> 16;
                    780:     s->regs[SONIC_CRBA0] = address & 0xffff;
                    781:     available = (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0];
                    782:     available -= rx_len / 2;
                    783:     s->regs[SONIC_RBWC1] = available >> 16;
                    784:     s->regs[SONIC_RBWC0] = available & 0xffff;
                    785: 
                    786:     /* Update status */
                    787:     if (((s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]) < s->regs[SONIC_EOBC]) {
                    788:         s->regs[SONIC_RCR] |= SONIC_RCR_LPKT;
                    789:     }
                    790:     s->regs[SONIC_RCR] |= packet_type;
                    791:     s->regs[SONIC_RCR] |= SONIC_RCR_PRX;
                    792:     if (s->loopback_packet) {
                    793:         s->regs[SONIC_RCR] |= SONIC_RCR_LBK;
                    794:         s->loopback_packet = 0;
                    795:     }
                    796: 
                    797:     /* Write status to memory */
                    798:     DPRINTF("Write status at %08x\n", (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]);
                    799:     data[0 * width] = s->regs[SONIC_RCR]; /* status */
                    800:     data[1 * width] = rx_len; /* byte count */
                    801:     data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */
                    802:     data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
                    803:     data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
                    804:     size = sizeof(uint16_t) * 5 * width;
                    805:     s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1);
                    806: 
                    807:     /* Move to next descriptor */
                    808:     size = sizeof(uint16_t) * width;
                    809:     s->memory_rw(s->mem_opaque,
                    810:         ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width,
                    811:         (uint8_t *)data, size, 0);
                    812:     s->regs[SONIC_LLFA] = data[0 * width];
                    813:     if (s->regs[SONIC_LLFA] & 0x1) {
                    814:         /* EOL detected */
                    815:         s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
                    816:     } else {
                    817:         data[0 * width] = 0; /* in_use */
                    818:         s->memory_rw(s->mem_opaque,
                    819:             ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width,
                    820:             (uint8_t *)data, size, 1);
                    821:         s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
                    822:         s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
                    823:         s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
                    824: 
                    825:         if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
                    826:             /* Read next RRA */
                    827:             do_read_rra(s);
                    828:         }
                    829:     }
                    830: 
                    831:     /* Done */
                    832:     dp8393x_update_irq(s);
                    833: 
                    834:     return size;
                    835: }
                    836: 
                    837: static void nic_reset(void *opaque)
                    838: {
                    839:     dp8393xState *s = opaque;
                    840:     qemu_del_timer(s->watchdog);
                    841: 
                    842:     s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS;
                    843:     s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR);
                    844:     s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT);
                    845:     s->regs[SONIC_TCR] |= SONIC_TCR_NCRS | SONIC_TCR_PTX;
                    846:     s->regs[SONIC_TCR] &= ~SONIC_TCR_BCM;
                    847:     s->regs[SONIC_IMR] = 0;
                    848:     s->regs[SONIC_ISR] = 0;
                    849:     s->regs[SONIC_DCR2] = 0;
                    850:     s->regs[SONIC_EOBC] = 0x02F8;
                    851:     s->regs[SONIC_RSC] = 0;
                    852:     s->regs[SONIC_CE] = 0;
                    853:     s->regs[SONIC_RSC] = 0;
                    854: 
                    855:     /* Network cable is connected */
                    856:     s->regs[SONIC_RCR] |= SONIC_RCR_CRS;
                    857: 
                    858:     dp8393x_update_irq(s);
                    859: }
                    860: 
1.1.1.2   root      861: static void nic_cleanup(VLANClientState *nc)
1.1       root      862: {
1.1.1.2   root      863:     dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque;
1.1       root      864: 
1.1.1.6 ! root      865:     memory_region_del_subregion(s->address_space, &s->mmio);
        !           866:     memory_region_destroy(&s->mmio);
1.1       root      867: 
                    868:     qemu_del_timer(s->watchdog);
                    869:     qemu_free_timer(s->watchdog);
                    870: 
1.1.1.5   root      871:     g_free(s);
1.1       root      872: }
                    873: 
1.1.1.2   root      874: static NetClientInfo net_dp83932_info = {
                    875:     .type = NET_CLIENT_TYPE_NIC,
                    876:     .size = sizeof(NICState),
                    877:     .can_receive = nic_can_receive,
                    878:     .receive = nic_receive,
                    879:     .cleanup = nic_cleanup,
                    880: };
                    881: 
1.1       root      882: void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
1.1.1.6 ! root      883:                   MemoryRegion *address_space,
1.1       root      884:                   qemu_irq irq, void* mem_opaque,
                    885:                   void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write))
                    886: {
                    887:     dp8393xState *s;
                    888: 
                    889:     qemu_check_nic_model(nd, "dp83932");
                    890: 
1.1.1.5   root      891:     s = g_malloc0(sizeof(dp8393xState));
1.1       root      892: 
1.1.1.6 ! root      893:     s->address_space = address_space;
1.1       root      894:     s->mem_opaque = mem_opaque;
                    895:     s->memory_rw = memory_rw;
                    896:     s->it_shift = it_shift;
                    897:     s->irq = irq;
1.1.1.4   root      898:     s->watchdog = qemu_new_timer_ns(vm_clock, dp8393x_watchdog, s);
1.1       root      899:     s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
                    900: 
1.1.1.4   root      901:     s->conf.macaddr = nd->macaddr;
1.1.1.2   root      902:     s->conf.vlan = nd->vlan;
                    903:     s->conf.peer = nd->netdev;
                    904: 
                    905:     s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s);
1.1       root      906: 
1.1.1.2   root      907:     qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
1.1       root      908:     qemu_register_reset(nic_reset, s);
                    909:     nic_reset(s);
                    910: 
1.1.1.6 ! root      911:     memory_region_init_io(&s->mmio, &dp8393x_ops, s,
        !           912:                           "dp8393x", 0x40 << it_shift);
        !           913:     memory_region_add_subregion(address_space, base, &s->mmio);
1.1       root      914: }

unix.superglobalmegacorp.com

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