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

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;
                    157:     VLANClientState *vc;
                    158:     int mmio_index;
                    159: 
                    160:     /* Registers */
                    161:     uint8_t cam[16][6];
                    162:     uint16_t regs[0x40];
                    163: 
                    164:     /* Temporaries */
                    165:     uint8_t tx_buffer[0x10000];
                    166:     int loopback_packet;
                    167: 
                    168:     /* Memory access */
                    169:     void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write);
                    170:     void* mem_opaque;
                    171: } dp8393xState;
                    172: 
                    173: static void dp8393x_update_irq(dp8393xState *s)
                    174: {
                    175:     int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0;
                    176: 
                    177: #ifdef DEBUG_SONIC
                    178:     if (level != s->irq_level) {
                    179:         s->irq_level = level;
                    180:         if (level) {
                    181:             DPRINTF("raise irq, isr is 0x%04x\n", s->regs[SONIC_ISR]);
                    182:         } else {
                    183:             DPRINTF("lower irq\n");
                    184:         }
                    185:     }
                    186: #endif
                    187: 
                    188:     qemu_set_irq(s->irq, level);
                    189: }
                    190: 
                    191: static void do_load_cam(dp8393xState *s)
                    192: {
                    193:     uint16_t data[8];
                    194:     int width, size;
                    195:     uint16_t index = 0;
                    196: 
                    197:     width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
                    198:     size = sizeof(uint16_t) * 4 * width;
                    199: 
                    200:     while (s->regs[SONIC_CDC] & 0x1f) {
                    201:         /* Fill current entry */
                    202:         s->memory_rw(s->mem_opaque,
                    203:             (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
                    204:             (uint8_t *)data, size, 0);
                    205:         s->cam[index][0] = data[1 * width] & 0xff;
                    206:         s->cam[index][1] = data[1 * width] >> 8;
                    207:         s->cam[index][2] = data[2 * width] & 0xff;
                    208:         s->cam[index][3] = data[2 * width] >> 8;
                    209:         s->cam[index][4] = data[3 * width] & 0xff;
                    210:         s->cam[index][5] = data[3 * width] >> 8;
                    211:         DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index,
                    212:             s->cam[index][0], s->cam[index][1], s->cam[index][2],
                    213:             s->cam[index][3], s->cam[index][4], s->cam[index][5]);
                    214:         /* Move to next entry */
                    215:         s->regs[SONIC_CDC]--;
                    216:         s->regs[SONIC_CDP] += size;
                    217:         index++;
                    218:     }
                    219: 
                    220:     /* Read CAM enable */
                    221:     s->memory_rw(s->mem_opaque,
                    222:         (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
                    223:         (uint8_t *)data, size, 0);
                    224:     s->regs[SONIC_CE] = data[0 * width];
                    225:     DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
                    226: 
                    227:     /* Done */
                    228:     s->regs[SONIC_CR] &= ~SONIC_CR_LCAM;
                    229:     s->regs[SONIC_ISR] |= SONIC_ISR_LCD;
                    230:     dp8393x_update_irq(s);
                    231: }
                    232: 
                    233: static void do_read_rra(dp8393xState *s)
                    234: {
                    235:     uint16_t data[8];
                    236:     int width, size;
                    237: 
                    238:     /* Read memory */
                    239:     width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
                    240:     size = sizeof(uint16_t) * 4 * width;
                    241:     s->memory_rw(s->mem_opaque,
                    242:         (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP],
                    243:         (uint8_t *)data, size, 0);
                    244: 
                    245:     /* Update SONIC registers */
                    246:     s->regs[SONIC_CRBA0] = data[0 * width];
                    247:     s->regs[SONIC_CRBA1] = data[1 * width];
                    248:     s->regs[SONIC_RBWC0] = data[2 * width];
                    249:     s->regs[SONIC_RBWC1] = data[3 * width];
                    250:     DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n",
                    251:         s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1],
                    252:         s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]);
                    253: 
                    254:     /* Go to next entry */
                    255:     s->regs[SONIC_RRP] += size;
                    256: 
                    257:     /* Handle wrap */
                    258:     if (s->regs[SONIC_RRP] == s->regs[SONIC_REA]) {
                    259:         s->regs[SONIC_RRP] = s->regs[SONIC_RSA];
                    260:     }
                    261: 
                    262:     /* Check resource exhaustion */
                    263:     if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP])
                    264:     {
                    265:         s->regs[SONIC_ISR] |= SONIC_ISR_RBE;
                    266:         dp8393x_update_irq(s);
                    267:     }
                    268: 
                    269:     /* Done */
                    270:     s->regs[SONIC_CR] &= ~SONIC_CR_RRRA;
                    271: }
                    272: 
                    273: static void do_software_reset(dp8393xState *s)
                    274: {
                    275:     qemu_del_timer(s->watchdog);
                    276: 
                    277:     s->regs[SONIC_CR] &= ~(SONIC_CR_LCAM | SONIC_CR_RRRA | SONIC_CR_TXP | SONIC_CR_HTX);
                    278:     s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS;
                    279: }
                    280: 
                    281: static void set_next_tick(dp8393xState *s)
                    282: {
                    283:     uint32_t ticks;
                    284:     int64_t delay;
                    285: 
                    286:     if (s->regs[SONIC_CR] & SONIC_CR_STP) {
                    287:         qemu_del_timer(s->watchdog);
                    288:         return;
                    289:     }
                    290: 
                    291:     ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
                    292:     s->wt_last_update = qemu_get_clock(vm_clock);
                    293:     delay = ticks_per_sec * ticks / 5000000;
                    294:     qemu_mod_timer(s->watchdog, s->wt_last_update + delay);
                    295: }
                    296: 
                    297: static void update_wt_regs(dp8393xState *s)
                    298: {
                    299:     int64_t elapsed;
                    300:     uint32_t val;
                    301: 
                    302:     if (s->regs[SONIC_CR] & SONIC_CR_STP) {
                    303:         qemu_del_timer(s->watchdog);
                    304:         return;
                    305:     }
                    306: 
                    307:     elapsed = s->wt_last_update - qemu_get_clock(vm_clock);
                    308:     val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
                    309:     val -= elapsed / 5000000;
                    310:     s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
                    311:     s->regs[SONIC_WT0] = (val >> 0)  & 0xffff;
                    312:     set_next_tick(s);
                    313: 
                    314: }
                    315: 
                    316: static void do_start_timer(dp8393xState *s)
                    317: {
                    318:     s->regs[SONIC_CR] &= ~SONIC_CR_STP;
                    319:     set_next_tick(s);
                    320: }
                    321: 
                    322: static void do_stop_timer(dp8393xState *s)
                    323: {
                    324:     s->regs[SONIC_CR] &= ~SONIC_CR_ST;
                    325:     update_wt_regs(s);
                    326: }
                    327: 
                    328: static void do_receiver_enable(dp8393xState *s)
                    329: {
                    330:     s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS;
                    331: }
                    332: 
                    333: static void do_receiver_disable(dp8393xState *s)
                    334: {
                    335:     s->regs[SONIC_CR] &= ~SONIC_CR_RXEN;
                    336: }
                    337: 
                    338: static void do_transmit_packets(dp8393xState *s)
                    339: {
                    340:     uint16_t data[12];
                    341:     int width, size;
                    342:     int tx_len, len;
                    343:     uint16_t i;
                    344: 
                    345:     width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
                    346: 
                    347:     while (1) {
                    348:         /* Read memory */
                    349:         DPRINTF("Transmit packet at %08x\n",
                    350:                 (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]);
                    351:         size = sizeof(uint16_t) * 6 * width;
                    352:         s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
                    353:         s->memory_rw(s->mem_opaque,
                    354:             ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width,
                    355:             (uint8_t *)data, size, 0);
                    356:         tx_len = 0;
                    357: 
                    358:         /* Update registers */
                    359:         s->regs[SONIC_TCR] = data[0 * width] & 0xf000;
                    360:         s->regs[SONIC_TPS] = data[1 * width];
                    361:         s->regs[SONIC_TFC] = data[2 * width];
                    362:         s->regs[SONIC_TSA0] = data[3 * width];
                    363:         s->regs[SONIC_TSA1] = data[4 * width];
                    364:         s->regs[SONIC_TFS] = data[5 * width];
                    365: 
                    366:         /* Handle programmable interrupt */
                    367:         if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) {
                    368:             s->regs[SONIC_ISR] |= SONIC_ISR_PINT;
                    369:         } else {
                    370:             s->regs[SONIC_ISR] &= ~SONIC_ISR_PINT;
                    371:         }
                    372: 
                    373:         for (i = 0; i < s->regs[SONIC_TFC]; ) {
                    374:             /* Append fragment */
                    375:             len = s->regs[SONIC_TFS];
                    376:             if (tx_len + len > sizeof(s->tx_buffer)) {
                    377:                 len = sizeof(s->tx_buffer) - tx_len;
                    378:             }
                    379:             s->memory_rw(s->mem_opaque,
                    380:                 (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0],
                    381:                 &s->tx_buffer[tx_len], len, 0);
                    382:             tx_len += len;
                    383: 
                    384:             i++;
                    385:             if (i != s->regs[SONIC_TFC]) {
                    386:                 /* Read next fragment details */
                    387:                 size = sizeof(uint16_t) * 3 * width;
                    388:                 s->memory_rw(s->mem_opaque,
                    389:                     ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width,
                    390:                     (uint8_t *)data, size, 0);
                    391:                 s->regs[SONIC_TSA0] = data[0 * width];
                    392:                 s->regs[SONIC_TSA1] = data[1 * width];
                    393:                 s->regs[SONIC_TFS] = data[2 * width];
                    394:             }
                    395:         }
                    396: 
                    397:         /* Handle Ethernet checksum */
                    398:         if (!(s->regs[SONIC_TCR] & SONIC_TCR_CRCI)) {
                    399:             /* Don't append FCS there, to look like slirp packets
                    400:              * which don't have one */
                    401:         } else {
                    402:             /* Remove existing FCS */
                    403:             tx_len -= 4;
                    404:         }
                    405: 
                    406:         if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) {
                    407:             /* Loopback */
                    408:             s->regs[SONIC_TCR] |= SONIC_TCR_CRSL;
                    409:             if (s->vc->can_receive(s->vc)) {
                    410:                 s->loopback_packet = 1;
                    411:                 s->vc->receive(s->vc, s->tx_buffer, tx_len);
                    412:             }
                    413:         } else {
                    414:             /* Transmit packet */
                    415:             qemu_send_packet(s->vc, s->tx_buffer, tx_len);
                    416:         }
                    417:         s->regs[SONIC_TCR] |= SONIC_TCR_PTX;
                    418: 
                    419:         /* Write status */
                    420:         data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
                    421:         size = sizeof(uint16_t) * width;
                    422:         s->memory_rw(s->mem_opaque,
                    423:             (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA],
                    424:             (uint8_t *)data, size, 1);
                    425: 
                    426:         if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
                    427:             /* Read footer of packet */
                    428:             size = sizeof(uint16_t) * width;
                    429:             s->memory_rw(s->mem_opaque,
                    430:                 ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width,
                    431:                 (uint8_t *)data, size, 0);
                    432:             s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
                    433:             if (data[0 * width] & 0x1) {
                    434:                 /* EOL detected */
                    435:                 break;
                    436:             }
                    437:         }
                    438:     }
                    439: 
                    440:     /* Done */
                    441:     s->regs[SONIC_CR] &= ~SONIC_CR_TXP;
                    442:     s->regs[SONIC_ISR] |= SONIC_ISR_TXDN;
                    443:     dp8393x_update_irq(s);
                    444: }
                    445: 
                    446: static void do_halt_transmission(dp8393xState *s)
                    447: {
                    448:     /* Nothing to do */
                    449: }
                    450: 
                    451: static void do_command(dp8393xState *s, uint16_t command)
                    452: {
                    453:     if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) {
                    454:         s->regs[SONIC_CR] &= ~SONIC_CR_RST;
                    455:         return;
                    456:     }
                    457: 
                    458:     s->regs[SONIC_CR] |= (command & SONIC_CR_MASK);
                    459: 
                    460:     if (command & SONIC_CR_HTX)
                    461:         do_halt_transmission(s);
                    462:     if (command & SONIC_CR_TXP)
                    463:         do_transmit_packets(s);
                    464:     if (command & SONIC_CR_RXDIS)
                    465:         do_receiver_disable(s);
                    466:     if (command & SONIC_CR_RXEN)
                    467:         do_receiver_enable(s);
                    468:     if (command & SONIC_CR_STP)
                    469:         do_stop_timer(s);
                    470:     if (command & SONIC_CR_ST)
                    471:         do_start_timer(s);
                    472:     if (command & SONIC_CR_RST)
                    473:         do_software_reset(s);
                    474:     if (command & SONIC_CR_RRRA)
                    475:         do_read_rra(s);
                    476:     if (command & SONIC_CR_LCAM)
                    477:         do_load_cam(s);
                    478: }
                    479: 
                    480: static uint16_t read_register(dp8393xState *s, int reg)
                    481: {
                    482:     uint16_t val = 0;
                    483: 
                    484:     switch (reg) {
                    485:         /* Update data before reading it */
                    486:         case SONIC_WT0:
                    487:         case SONIC_WT1:
                    488:             update_wt_regs(s);
                    489:             val = s->regs[reg];
                    490:             break;
                    491:         /* Accept read to some registers only when in reset mode */
                    492:         case SONIC_CAP2:
                    493:         case SONIC_CAP1:
                    494:         case SONIC_CAP0:
                    495:             if (s->regs[SONIC_CR] & SONIC_CR_RST) {
                    496:                 val = s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg) + 1] << 8;
                    497:                 val |= s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg)];
                    498:             }
                    499:             break;
                    500:         /* All other registers have no special contrainst */
                    501:         default:
                    502:             val = s->regs[reg];
                    503:     }
                    504: 
                    505:     DPRINTF("read 0x%04x from reg %s\n", val, reg_names[reg]);
                    506: 
                    507:     return val;
                    508: }
                    509: 
                    510: static void write_register(dp8393xState *s, int reg, uint16_t val)
                    511: {
                    512:     DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]);
                    513: 
                    514:     switch (reg) {
                    515:         /* Command register */
                    516:         case SONIC_CR:
                    517:             do_command(s, val);;
                    518:             break;
                    519:         /* Prevent write to read-only registers */
                    520:         case SONIC_CAP2:
                    521:         case SONIC_CAP1:
                    522:         case SONIC_CAP0:
                    523:         case SONIC_SR:
                    524:         case SONIC_MDT:
                    525:             DPRINTF("writing to reg %d invalid\n", reg);
                    526:             break;
                    527:         /* Accept write to some registers only when in reset mode */
                    528:         case SONIC_DCR:
                    529:             if (s->regs[SONIC_CR] & SONIC_CR_RST) {
                    530:                 s->regs[reg] = val & 0xbfff;
                    531:             } else {
                    532:                 DPRINTF("writing to DCR invalid\n");
                    533:             }
                    534:             break;
                    535:         case SONIC_DCR2:
                    536:             if (s->regs[SONIC_CR] & SONIC_CR_RST) {
                    537:                 s->regs[reg] = val & 0xf017;
                    538:             } else {
                    539:                 DPRINTF("writing to DCR2 invalid\n");
                    540:             }
                    541:             break;
                    542:         /* 12 lower bytes are Read Only */
                    543:         case SONIC_TCR:
                    544:             s->regs[reg] = val & 0xf000;
                    545:             break;
                    546:         /* 9 lower bytes are Read Only */
                    547:         case SONIC_RCR:
                    548:             s->regs[reg] = val & 0xffe0;
                    549:             break;
                    550:         /* Ignore most significant bit */
                    551:         case SONIC_IMR:
                    552:             s->regs[reg] = val & 0x7fff;
                    553:             dp8393x_update_irq(s);
                    554:             break;
                    555:         /* Clear bits by writing 1 to them */
                    556:         case SONIC_ISR:
                    557:             val &= s->regs[reg];
                    558:             s->regs[reg] &= ~val;
                    559:             if (val & SONIC_ISR_RBE) {
                    560:                 do_read_rra(s);
                    561:             }
                    562:             dp8393x_update_irq(s);
                    563:             break;
                    564:         /* Ignore least significant bit */
                    565:         case SONIC_RSA:
                    566:         case SONIC_REA:
                    567:         case SONIC_RRP:
                    568:         case SONIC_RWP:
                    569:             s->regs[reg] = val & 0xfffe;
                    570:             break;
                    571:         /* Invert written value for some registers */
                    572:         case SONIC_CRCT:
                    573:         case SONIC_FAET:
                    574:         case SONIC_MPT:
                    575:             s->regs[reg] = val ^ 0xffff;
                    576:             break;
                    577:         /* All other registers have no special contrainst */
                    578:         default:
                    579:             s->regs[reg] = val;
                    580:     }
                    581: 
                    582:     if (reg == SONIC_WT0 || reg == SONIC_WT1) {
                    583:         set_next_tick(s);
                    584:     }
                    585: }
                    586: 
                    587: static void dp8393x_watchdog(void *opaque)
                    588: {
                    589:     dp8393xState *s = opaque;
                    590: 
                    591:     if (s->regs[SONIC_CR] & SONIC_CR_STP) {
                    592:         return;
                    593:     }
                    594: 
                    595:     s->regs[SONIC_WT1] = 0xffff;
                    596:     s->regs[SONIC_WT0] = 0xffff;
                    597:     set_next_tick(s);
                    598: 
                    599:     /* Signal underflow */
                    600:     s->regs[SONIC_ISR] |= SONIC_ISR_TC;
                    601:     dp8393x_update_irq(s);
                    602: }
                    603: 
                    604: static uint32_t dp8393x_readw(void *opaque, target_phys_addr_t addr)
                    605: {
                    606:     dp8393xState *s = opaque;
                    607:     int reg;
                    608: 
                    609:     if ((addr & ((1 << s->it_shift) - 1)) != 0) {
                    610:         return 0;
                    611:     }
                    612: 
                    613:     reg = addr >> s->it_shift;
                    614:     return read_register(s, reg);
                    615: }
                    616: 
                    617: static uint32_t dp8393x_readb(void *opaque, target_phys_addr_t addr)
                    618: {
                    619:     uint16_t v = dp8393x_readw(opaque, addr & ~0x1);
                    620:     return (v >> (8 * (addr & 0x1))) & 0xff;
                    621: }
                    622: 
                    623: static uint32_t dp8393x_readl(void *opaque, target_phys_addr_t addr)
                    624: {
                    625:     uint32_t v;
                    626:     v = dp8393x_readw(opaque, addr);
                    627:     v |= dp8393x_readw(opaque, addr + 2) << 16;
                    628:     return v;
                    629: }
                    630: 
                    631: static void dp8393x_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
                    632: {
                    633:     dp8393xState *s = opaque;
                    634:     int reg;
                    635: 
                    636:     if ((addr & ((1 << s->it_shift) - 1)) != 0) {
                    637:         return;
                    638:     }
                    639: 
                    640:     reg = addr >> s->it_shift;
                    641: 
                    642:     write_register(s, reg, (uint16_t)val);
                    643: }
                    644: 
                    645: static void dp8393x_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
                    646: {
                    647:     uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1);
                    648: 
                    649:     switch (addr & 3) {
                    650:     case 0:
                    651:         val = val | (old_val & 0xff00);
                    652:         break;
                    653:     case 1:
                    654:         val = (val << 8) | (old_val & 0x00ff);
                    655:         break;
                    656:     }
                    657:     dp8393x_writew(opaque, addr & ~0x1, val);
                    658: }
                    659: 
                    660: static void dp8393x_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
                    661: {
                    662:     dp8393x_writew(opaque, addr, val & 0xffff);
                    663:     dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff);
                    664: }
                    665: 
                    666: static CPUReadMemoryFunc *dp8393x_read[3] = {
                    667:     dp8393x_readb,
                    668:     dp8393x_readw,
                    669:     dp8393x_readl,
                    670: };
                    671: 
                    672: static CPUWriteMemoryFunc *dp8393x_write[3] = {
                    673:     dp8393x_writeb,
                    674:     dp8393x_writew,
                    675:     dp8393x_writel,
                    676: };
                    677: 
                    678: static int nic_can_receive(VLANClientState *vc)
                    679: {
                    680:     dp8393xState *s = vc->opaque;
                    681: 
                    682:     if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN))
                    683:         return 0;
                    684:     if (s->regs[SONIC_ISR] & SONIC_ISR_RBE)
                    685:         return 0;
                    686:     return 1;
                    687: }
                    688: 
                    689: static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
                    690: {
                    691:     static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
                    692:     int i;
                    693: 
                    694:     /* Check for runt packet (remember that checksum is not there) */
                    695:     if (size < 64 - 4) {
                    696:         return (s->regs[SONIC_RCR] & SONIC_RCR_RNT) ? 0 : -1;
                    697:     }
                    698: 
                    699:     /* Check promiscuous mode */
                    700:     if ((s->regs[SONIC_RCR] & SONIC_RCR_PRO) && (buf[0] & 1) == 0) {
                    701:         return 0;
                    702:     }
                    703: 
                    704:     /* Check multicast packets */
                    705:     if ((s->regs[SONIC_RCR] & SONIC_RCR_AMC) && (buf[0] & 1) == 1) {
                    706:         return SONIC_RCR_MC;
                    707:     }
                    708: 
                    709:     /* Check broadcast */
                    710:     if ((s->regs[SONIC_RCR] & SONIC_RCR_BRD) && !memcmp(buf, bcast, sizeof(bcast))) {
                    711:         return SONIC_RCR_BC;
                    712:     }
                    713: 
                    714:     /* Check CAM */
                    715:     for (i = 0; i < 16; i++) {
                    716:         if (s->regs[SONIC_CE] & (1 << i)) {
                    717:              /* Entry enabled */
                    718:              if (!memcmp(buf, s->cam[i], sizeof(s->cam[i]))) {
                    719:                  return 0;
                    720:              }
                    721:         }
                    722:     }
                    723: 
                    724:     return -1;
                    725: }
                    726: 
                    727: static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size)
                    728: {
                    729:     uint16_t data[10];
                    730:     dp8393xState *s = vc->opaque;
                    731:     int packet_type;
                    732:     uint32_t available, address;
                    733:     int width, rx_len = size;
                    734:     uint32_t checksum;
                    735: 
                    736:     width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
                    737: 
                    738:     s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER |
                    739:         SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC);
                    740: 
                    741:     packet_type = receive_filter(s, buf, size);
                    742:     if (packet_type < 0) {
                    743:         DPRINTF("packet not for netcard\n");
                    744:         return -1;
                    745:     }
                    746: 
                    747:     /* XXX: Check byte ordering */
                    748: 
                    749:     /* Check for EOL */
                    750:     if (s->regs[SONIC_LLFA] & 0x1) {
                    751:         /* Are we still in resource exhaustion? */
                    752:         size = sizeof(uint16_t) * 1 * width;
                    753:         address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width;
                    754:         s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0);
                    755:         if (data[0 * width] & 0x1) {
                    756:             /* Still EOL ; stop reception */
                    757:             return -1;
                    758:         } else {
                    759:             s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
                    760:         }
                    761:     }
                    762: 
                    763:     /* Save current position */
                    764:     s->regs[SONIC_TRBA1] = s->regs[SONIC_CRBA1];
                    765:     s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0];
                    766: 
                    767:     /* Calculate the ethernet checksum */
                    768: #ifdef SONIC_CALCULATE_RXCRC
                    769:     checksum = cpu_to_le32(crc32(0, buf, rx_len));
                    770: #else
                    771:     checksum = 0;
                    772: #endif
                    773: 
                    774:     /* Put packet into RBA */
                    775:     DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]);
                    776:     address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0];
                    777:     s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1);
                    778:     address += rx_len;
                    779:     s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1);
                    780:     rx_len += 4;
                    781:     s->regs[SONIC_CRBA1] = address >> 16;
                    782:     s->regs[SONIC_CRBA0] = address & 0xffff;
                    783:     available = (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0];
                    784:     available -= rx_len / 2;
                    785:     s->regs[SONIC_RBWC1] = available >> 16;
                    786:     s->regs[SONIC_RBWC0] = available & 0xffff;
                    787: 
                    788:     /* Update status */
                    789:     if (((s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]) < s->regs[SONIC_EOBC]) {
                    790:         s->regs[SONIC_RCR] |= SONIC_RCR_LPKT;
                    791:     }
                    792:     s->regs[SONIC_RCR] |= packet_type;
                    793:     s->regs[SONIC_RCR] |= SONIC_RCR_PRX;
                    794:     if (s->loopback_packet) {
                    795:         s->regs[SONIC_RCR] |= SONIC_RCR_LBK;
                    796:         s->loopback_packet = 0;
                    797:     }
                    798: 
                    799:     /* Write status to memory */
                    800:     DPRINTF("Write status at %08x\n", (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]);
                    801:     data[0 * width] = s->regs[SONIC_RCR]; /* status */
                    802:     data[1 * width] = rx_len; /* byte count */
                    803:     data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */
                    804:     data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
                    805:     data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
                    806:     size = sizeof(uint16_t) * 5 * width;
                    807:     s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1);
                    808: 
                    809:     /* Move to next descriptor */
                    810:     size = sizeof(uint16_t) * width;
                    811:     s->memory_rw(s->mem_opaque,
                    812:         ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width,
                    813:         (uint8_t *)data, size, 0);
                    814:     s->regs[SONIC_LLFA] = data[0 * width];
                    815:     if (s->regs[SONIC_LLFA] & 0x1) {
                    816:         /* EOL detected */
                    817:         s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
                    818:     } else {
                    819:         data[0 * width] = 0; /* in_use */
                    820:         s->memory_rw(s->mem_opaque,
                    821:             ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width,
                    822:             (uint8_t *)data, size, 1);
                    823:         s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
                    824:         s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
                    825:         s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
                    826: 
                    827:         if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
                    828:             /* Read next RRA */
                    829:             do_read_rra(s);
                    830:         }
                    831:     }
                    832: 
                    833:     /* Done */
                    834:     dp8393x_update_irq(s);
                    835: 
                    836:     return size;
                    837: }
                    838: 
                    839: static void nic_reset(void *opaque)
                    840: {
                    841:     dp8393xState *s = opaque;
                    842:     qemu_del_timer(s->watchdog);
                    843: 
                    844:     s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS;
                    845:     s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR);
                    846:     s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT);
                    847:     s->regs[SONIC_TCR] |= SONIC_TCR_NCRS | SONIC_TCR_PTX;
                    848:     s->regs[SONIC_TCR] &= ~SONIC_TCR_BCM;
                    849:     s->regs[SONIC_IMR] = 0;
                    850:     s->regs[SONIC_ISR] = 0;
                    851:     s->regs[SONIC_DCR2] = 0;
                    852:     s->regs[SONIC_EOBC] = 0x02F8;
                    853:     s->regs[SONIC_RSC] = 0;
                    854:     s->regs[SONIC_CE] = 0;
                    855:     s->regs[SONIC_RSC] = 0;
                    856: 
                    857:     /* Network cable is connected */
                    858:     s->regs[SONIC_RCR] |= SONIC_RCR_CRS;
                    859: 
                    860:     dp8393x_update_irq(s);
                    861: }
                    862: 
                    863: static void nic_cleanup(VLANClientState *vc)
                    864: {
                    865:     dp8393xState *s = vc->opaque;
                    866: 
                    867:     cpu_unregister_io_memory(s->mmio_index);
                    868: 
                    869:     qemu_del_timer(s->watchdog);
                    870:     qemu_free_timer(s->watchdog);
                    871: 
                    872:     qemu_free(s);
                    873: }
                    874: 
                    875: void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
                    876:                   qemu_irq irq, void* mem_opaque,
                    877:                   void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write))
                    878: {
                    879:     dp8393xState *s;
                    880: 
                    881:     qemu_check_nic_model(nd, "dp83932");
                    882: 
                    883:     s = qemu_mallocz(sizeof(dp8393xState));
                    884: 
                    885:     s->mem_opaque = mem_opaque;
                    886:     s->memory_rw = memory_rw;
                    887:     s->it_shift = it_shift;
                    888:     s->irq = irq;
                    889:     s->watchdog = qemu_new_timer(vm_clock, dp8393x_watchdog, s);
                    890:     s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
                    891: 
                    892:     s->vc = nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
                    893:                                           nic_can_receive, nic_receive, NULL,
                    894:                                           nic_cleanup, s);
                    895: 
                    896:     qemu_format_nic_info_str(s->vc, nd->macaddr);
                    897:     qemu_register_reset(nic_reset, s);
                    898:     nic_reset(s);
                    899: 
                    900:     s->mmio_index = cpu_register_io_memory(dp8393x_read, dp8393x_write, s);
                    901:     cpu_register_physical_memory(base, 0x40 << it_shift, s->mmio_index);
                    902: }

unix.superglobalmegacorp.com

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