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

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

unix.superglobalmegacorp.com

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