qemu/hw/net/pcnet.c
<<
>>
Prefs
   1/*
   2 * QEMU AMD PC-Net II (Am79C970A) emulation
   3 *
   4 * Copyright (c) 2004 Antony T Curtis
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25/* This software was written to be compatible with the specification:
  26 * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
  27 * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
  28 */
  29
  30/*
  31 * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also
  32 * produced as NCR89C100. See
  33 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
  34 * and
  35 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
  36 */
  37
  38#include "qemu/osdep.h"
  39#include "hw/qdev.h"
  40#include "net/net.h"
  41#include "qemu/timer.h"
  42#include "qemu/sockets.h"
  43#include "sysemu/sysemu.h"
  44#include "trace.h"
  45
  46#include "pcnet.h"
  47
  48//#define PCNET_DEBUG
  49//#define PCNET_DEBUG_IO
  50//#define PCNET_DEBUG_BCR
  51//#define PCNET_DEBUG_CSR
  52//#define PCNET_DEBUG_RMD
  53//#define PCNET_DEBUG_TMD
  54//#define PCNET_DEBUG_MATCH
  55
  56
  57struct qemu_ether_header {
  58    uint8_t ether_dhost[6];
  59    uint8_t ether_shost[6];
  60    uint16_t ether_type;
  61};
  62
  63#define CSR_INIT(S)      !!(((S)->csr[0])&0x0001)
  64#define CSR_STRT(S)      !!(((S)->csr[0])&0x0002)
  65#define CSR_STOP(S)      !!(((S)->csr[0])&0x0004)
  66#define CSR_TDMD(S)      !!(((S)->csr[0])&0x0008)
  67#define CSR_TXON(S)      !!(((S)->csr[0])&0x0010)
  68#define CSR_RXON(S)      !!(((S)->csr[0])&0x0020)
  69#define CSR_INEA(S)      !!(((S)->csr[0])&0x0040)
  70#define CSR_BSWP(S)      !!(((S)->csr[3])&0x0004)
  71#define CSR_LAPPEN(S)    !!(((S)->csr[3])&0x0020)
  72#define CSR_DXSUFLO(S)   !!(((S)->csr[3])&0x0040)
  73#define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800)
  74#define CSR_DPOLL(S)     !!(((S)->csr[4])&0x1000)
  75#define CSR_SPND(S)      !!(((S)->csr[5])&0x0001)
  76#define CSR_LTINTEN(S)   !!(((S)->csr[5])&0x4000)
  77#define CSR_TOKINTD(S)   !!(((S)->csr[5])&0x8000)
  78#define CSR_DRX(S)       !!(((S)->csr[15])&0x0001)
  79#define CSR_DTX(S)       !!(((S)->csr[15])&0x0002)
  80#define CSR_LOOP(S)      !!(((S)->csr[15])&0x0004)
  81#define CSR_DXMTFCS(S)   !!(((S)->csr[15])&0x0008)
  82#define CSR_INTL(S)      !!(((S)->csr[15])&0x0040)
  83#define CSR_DRCVPA(S)    !!(((S)->csr[15])&0x2000)
  84#define CSR_DRCVBC(S)    !!(((S)->csr[15])&0x4000)
  85#define CSR_PROM(S)      !!(((S)->csr[15])&0x8000)
  86
  87#define CSR_CRBC(S)      ((S)->csr[40])
  88#define CSR_CRST(S)      ((S)->csr[41])
  89#define CSR_CXBC(S)      ((S)->csr[42])
  90#define CSR_CXST(S)      ((S)->csr[43])
  91#define CSR_NRBC(S)      ((S)->csr[44])
  92#define CSR_NRST(S)      ((S)->csr[45])
  93#define CSR_POLL(S)      ((S)->csr[46])
  94#define CSR_PINT(S)      ((S)->csr[47])
  95#define CSR_RCVRC(S)     ((S)->csr[72])
  96#define CSR_XMTRC(S)     ((S)->csr[74])
  97#define CSR_RCVRL(S)     ((S)->csr[76])
  98#define CSR_XMTRL(S)     ((S)->csr[78])
  99#define CSR_MISSC(S)     ((S)->csr[112])
 100
 101#define CSR_IADR(S)      ((S)->csr[ 1] | ((uint32_t)(S)->csr[ 2] << 16))
 102#define CSR_CRBA(S)      ((S)->csr[18] | ((uint32_t)(S)->csr[19] << 16))
 103#define CSR_CXBA(S)      ((S)->csr[20] | ((uint32_t)(S)->csr[21] << 16))
 104#define CSR_NRBA(S)      ((S)->csr[22] | ((uint32_t)(S)->csr[23] << 16))
 105#define CSR_BADR(S)      ((S)->csr[24] | ((uint32_t)(S)->csr[25] << 16))
 106#define CSR_NRDA(S)      ((S)->csr[26] | ((uint32_t)(S)->csr[27] << 16))
 107#define CSR_CRDA(S)      ((S)->csr[28] | ((uint32_t)(S)->csr[29] << 16))
 108#define CSR_BADX(S)      ((S)->csr[30] | ((uint32_t)(S)->csr[31] << 16))
 109#define CSR_NXDA(S)      ((S)->csr[32] | ((uint32_t)(S)->csr[33] << 16))
 110#define CSR_CXDA(S)      ((S)->csr[34] | ((uint32_t)(S)->csr[35] << 16))
 111#define CSR_NNRD(S)      ((S)->csr[36] | ((uint32_t)(S)->csr[37] << 16))
 112#define CSR_NNXD(S)      ((S)->csr[38] | ((uint32_t)(S)->csr[39] << 16))
 113#define CSR_PXDA(S)      ((S)->csr[60] | ((uint32_t)(S)->csr[61] << 16))
 114#define CSR_NXBA(S)      ((S)->csr[64] | ((uint32_t)(S)->csr[65] << 16))
 115
 116#define PHYSADDR(S,A) \
 117  (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(S)->csr[2])<<16))
 118
 119struct pcnet_initblk16 {
 120    uint16_t mode;
 121    uint16_t padr[3];
 122    uint16_t ladrf[4];
 123    uint32_t rdra;
 124    uint32_t tdra;
 125};
 126
 127struct pcnet_initblk32 {
 128    uint16_t mode;
 129    uint8_t rlen;
 130    uint8_t tlen;
 131    uint16_t padr[3];
 132    uint16_t _res;
 133    uint16_t ladrf[4];
 134    uint32_t rdra;
 135    uint32_t tdra;
 136};
 137
 138struct pcnet_TMD {
 139    uint32_t tbadr;
 140    int16_t length;
 141    int16_t status;
 142    uint32_t misc;
 143    uint32_t res;
 144};
 145
 146#define TMDL_BCNT_MASK  0x0fff
 147#define TMDL_BCNT_SH    0
 148#define TMDL_ONES_MASK  0xf000
 149#define TMDL_ONES_SH    12
 150
 151#define TMDS_BPE_MASK   0x0080
 152#define TMDS_BPE_SH     7
 153#define TMDS_ENP_MASK   0x0100
 154#define TMDS_ENP_SH     8
 155#define TMDS_STP_MASK   0x0200
 156#define TMDS_STP_SH     9
 157#define TMDS_DEF_MASK   0x0400
 158#define TMDS_DEF_SH     10
 159#define TMDS_ONE_MASK   0x0800
 160#define TMDS_ONE_SH     11
 161#define TMDS_LTINT_MASK 0x1000
 162#define TMDS_LTINT_SH   12
 163#define TMDS_NOFCS_MASK 0x2000
 164#define TMDS_NOFCS_SH   13
 165#define TMDS_ADDFCS_MASK TMDS_NOFCS_MASK
 166#define TMDS_ADDFCS_SH  TMDS_NOFCS_SH
 167#define TMDS_ERR_MASK   0x4000
 168#define TMDS_ERR_SH     14
 169#define TMDS_OWN_MASK   0x8000
 170#define TMDS_OWN_SH     15
 171
 172#define TMDM_TRC_MASK   0x0000000f
 173#define TMDM_TRC_SH     0
 174#define TMDM_TDR_MASK   0x03ff0000
 175#define TMDM_TDR_SH     16
 176#define TMDM_RTRY_MASK  0x04000000
 177#define TMDM_RTRY_SH    26
 178#define TMDM_LCAR_MASK  0x08000000
 179#define TMDM_LCAR_SH    27
 180#define TMDM_LCOL_MASK  0x10000000
 181#define TMDM_LCOL_SH    28
 182#define TMDM_EXDEF_MASK 0x20000000
 183#define TMDM_EXDEF_SH   29
 184#define TMDM_UFLO_MASK  0x40000000
 185#define TMDM_UFLO_SH    30
 186#define TMDM_BUFF_MASK  0x80000000
 187#define TMDM_BUFF_SH    31
 188
 189struct pcnet_RMD {
 190    uint32_t rbadr;
 191    int16_t buf_length;
 192    int16_t status;
 193    uint32_t msg_length;
 194    uint32_t res;
 195};
 196
 197#define RMDL_BCNT_MASK  0x0fff
 198#define RMDL_BCNT_SH    0
 199#define RMDL_ONES_MASK  0xf000
 200#define RMDL_ONES_SH    12
 201
 202#define RMDS_BAM_MASK   0x0010
 203#define RMDS_BAM_SH     4
 204#define RMDS_LFAM_MASK  0x0020
 205#define RMDS_LFAM_SH    5
 206#define RMDS_PAM_MASK   0x0040
 207#define RMDS_PAM_SH     6
 208#define RMDS_BPE_MASK   0x0080
 209#define RMDS_BPE_SH     7
 210#define RMDS_ENP_MASK   0x0100
 211#define RMDS_ENP_SH     8
 212#define RMDS_STP_MASK   0x0200
 213#define RMDS_STP_SH     9
 214#define RMDS_BUFF_MASK  0x0400
 215#define RMDS_BUFF_SH    10
 216#define RMDS_CRC_MASK   0x0800
 217#define RMDS_CRC_SH     11
 218#define RMDS_OFLO_MASK  0x1000
 219#define RMDS_OFLO_SH    12
 220#define RMDS_FRAM_MASK  0x2000
 221#define RMDS_FRAM_SH    13
 222#define RMDS_ERR_MASK   0x4000
 223#define RMDS_ERR_SH     14
 224#define RMDS_OWN_MASK   0x8000
 225#define RMDS_OWN_SH     15
 226
 227#define RMDM_MCNT_MASK  0x00000fff
 228#define RMDM_MCNT_SH    0
 229#define RMDM_ZEROS_MASK 0x0000f000
 230#define RMDM_ZEROS_SH   12
 231#define RMDM_RPC_MASK   0x00ff0000
 232#define RMDM_RPC_SH     16
 233#define RMDM_RCC_MASK   0xff000000
 234#define RMDM_RCC_SH     24
 235
 236#define SET_FIELD(regp, name, field, value)             \
 237  (*(regp) = (*(regp) & ~(name ## _ ## field ## _MASK)) \
 238             | ((value) << name ## _ ## field ## _SH))
 239
 240#define GET_FIELD(reg, name, field)                     \
 241  (((reg) & name ## _ ## field ## _MASK) >> name ## _ ## field ## _SH)
 242
 243#define PRINT_TMD(T) printf(                            \
 244        "TMD0 : TBADR=0x%08x\n"                         \
 245        "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, "       \
 246        "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n"             \
 247        "       BPE=%d, BCNT=%d\n"                      \
 248        "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, "       \
 249        "LCA=%d, RTR=%d,\n"                             \
 250        "       TDR=%d, TRC=%d\n",                      \
 251        (T)->tbadr,                                     \
 252        GET_FIELD((T)->status, TMDS, OWN),              \
 253        GET_FIELD((T)->status, TMDS, ERR),              \
 254        GET_FIELD((T)->status, TMDS, NOFCS),            \
 255        GET_FIELD((T)->status, TMDS, LTINT),            \
 256        GET_FIELD((T)->status, TMDS, ONE),              \
 257        GET_FIELD((T)->status, TMDS, DEF),              \
 258        GET_FIELD((T)->status, TMDS, STP),              \
 259        GET_FIELD((T)->status, TMDS, ENP),              \
 260        GET_FIELD((T)->status, TMDS, BPE),              \
 261        4096-GET_FIELD((T)->length, TMDL, BCNT),        \
 262        GET_FIELD((T)->misc, TMDM, BUFF),               \
 263        GET_FIELD((T)->misc, TMDM, UFLO),               \
 264        GET_FIELD((T)->misc, TMDM, EXDEF),              \
 265        GET_FIELD((T)->misc, TMDM, LCOL),               \
 266        GET_FIELD((T)->misc, TMDM, LCAR),               \
 267        GET_FIELD((T)->misc, TMDM, RTRY),               \
 268        GET_FIELD((T)->misc, TMDM, TDR),                \
 269        GET_FIELD((T)->misc, TMDM, TRC))
 270
 271#define PRINT_RMD(R) printf(                            \
 272        "RMD0 : RBADR=0x%08x\n"                         \
 273        "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, "     \
 274        "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n       "     \
 275        "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
 276        "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n",   \
 277        (R)->rbadr,                                     \
 278        GET_FIELD((R)->status, RMDS, OWN),              \
 279        GET_FIELD((R)->status, RMDS, ERR),              \
 280        GET_FIELD((R)->status, RMDS, FRAM),             \
 281        GET_FIELD((R)->status, RMDS, OFLO),             \
 282        GET_FIELD((R)->status, RMDS, CRC),              \
 283        GET_FIELD((R)->status, RMDS, BUFF),             \
 284        GET_FIELD((R)->status, RMDS, STP),              \
 285        GET_FIELD((R)->status, RMDS, ENP),              \
 286        GET_FIELD((R)->status, RMDS, BPE),              \
 287        GET_FIELD((R)->status, RMDS, PAM),              \
 288        GET_FIELD((R)->status, RMDS, LFAM),             \
 289        GET_FIELD((R)->status, RMDS, BAM),              \
 290        GET_FIELD((R)->buf_length, RMDL, ONES),         \
 291        4096-GET_FIELD((R)->buf_length, RMDL, BCNT),    \
 292        GET_FIELD((R)->msg_length, RMDM, RCC),          \
 293        GET_FIELD((R)->msg_length, RMDM, RPC),          \
 294        GET_FIELD((R)->msg_length, RMDM, MCNT),         \
 295        GET_FIELD((R)->msg_length, RMDM, ZEROS))
 296
 297static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd,
 298                                  hwaddr addr)
 299{
 300    if (!BCR_SSIZE32(s)) {
 301        struct {
 302            uint32_t tbadr;
 303            int16_t length;
 304            int16_t status;
 305        } xda;
 306        s->phys_mem_read(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
 307        tmd->tbadr = le32_to_cpu(xda.tbadr) & 0xffffff;
 308        tmd->length = le16_to_cpu(xda.length);
 309        tmd->status = (le32_to_cpu(xda.tbadr) >> 16) & 0xff00;
 310        tmd->misc = le16_to_cpu(xda.status) << 16;
 311        tmd->res = 0;
 312    } else {
 313        s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, sizeof(*tmd), 0);
 314        le32_to_cpus(&tmd->tbadr);
 315        le16_to_cpus((uint16_t *)&tmd->length);
 316        le16_to_cpus((uint16_t *)&tmd->status);
 317        le32_to_cpus(&tmd->misc);
 318        le32_to_cpus(&tmd->res);
 319        if (BCR_SWSTYLE(s) == 3) {
 320            uint32_t tmp = tmd->tbadr;
 321            tmd->tbadr = tmd->misc;
 322            tmd->misc = tmp;
 323        }
 324    }
 325}
 326
 327static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd,
 328                                   hwaddr addr)
 329{
 330    if (!BCR_SSIZE32(s)) {
 331        struct {
 332            uint32_t tbadr;
 333            int16_t length;
 334            int16_t status;
 335        } xda;
 336        xda.tbadr = cpu_to_le32((tmd->tbadr & 0xffffff) |
 337                                ((tmd->status & 0xff00) << 16));
 338        xda.length = cpu_to_le16(tmd->length);
 339        xda.status = cpu_to_le16(tmd->misc >> 16);
 340        s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
 341    } else {
 342        struct {
 343            uint32_t tbadr;
 344            int16_t length;
 345            int16_t status;
 346            uint32_t misc;
 347            uint32_t res;
 348        } xda;
 349        xda.tbadr = cpu_to_le32(tmd->tbadr);
 350        xda.length = cpu_to_le16(tmd->length);
 351        xda.status = cpu_to_le16(tmd->status);
 352        xda.misc = cpu_to_le32(tmd->misc);
 353        xda.res = cpu_to_le32(tmd->res);
 354        if (BCR_SWSTYLE(s) == 3) {
 355            uint32_t tmp = xda.tbadr;
 356            xda.tbadr = xda.misc;
 357            xda.misc = tmp;
 358        }
 359        s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
 360    }
 361}
 362
 363static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd,
 364                                  hwaddr addr)
 365{
 366    if (!BCR_SSIZE32(s)) {
 367        struct {
 368            uint32_t rbadr;
 369            int16_t buf_length;
 370            int16_t msg_length;
 371        } rda;
 372        s->phys_mem_read(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
 373        rmd->rbadr = le32_to_cpu(rda.rbadr) & 0xffffff;
 374        rmd->buf_length = le16_to_cpu(rda.buf_length);
 375        rmd->status = (le32_to_cpu(rda.rbadr) >> 16) & 0xff00;
 376        rmd->msg_length = le16_to_cpu(rda.msg_length);
 377        rmd->res = 0;
 378    } else {
 379        s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, sizeof(*rmd), 0);
 380        le32_to_cpus(&rmd->rbadr);
 381        le16_to_cpus((uint16_t *)&rmd->buf_length);
 382        le16_to_cpus((uint16_t *)&rmd->status);
 383        le32_to_cpus(&rmd->msg_length);
 384        le32_to_cpus(&rmd->res);
 385        if (BCR_SWSTYLE(s) == 3) {
 386            uint32_t tmp = rmd->rbadr;
 387            rmd->rbadr = rmd->msg_length;
 388            rmd->msg_length = tmp;
 389        }
 390    }
 391}
 392
 393static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd,
 394                                   hwaddr addr)
 395{
 396    if (!BCR_SSIZE32(s)) {
 397        struct {
 398            uint32_t rbadr;
 399            int16_t buf_length;
 400            int16_t msg_length;
 401        } rda;
 402        rda.rbadr = cpu_to_le32((rmd->rbadr & 0xffffff) |
 403                                ((rmd->status & 0xff00) << 16));
 404        rda.buf_length = cpu_to_le16(rmd->buf_length);
 405        rda.msg_length = cpu_to_le16(rmd->msg_length);
 406        s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
 407    } else {
 408        struct {
 409            uint32_t rbadr;
 410            int16_t buf_length;
 411            int16_t status;
 412            uint32_t msg_length;
 413            uint32_t res;
 414        } rda;
 415        rda.rbadr = cpu_to_le32(rmd->rbadr);
 416        rda.buf_length = cpu_to_le16(rmd->buf_length);
 417        rda.status = cpu_to_le16(rmd->status);
 418        rda.msg_length = cpu_to_le32(rmd->msg_length);
 419        rda.res = cpu_to_le32(rmd->res);
 420        if (BCR_SWSTYLE(s) == 3) {
 421            uint32_t tmp = rda.rbadr;
 422            rda.rbadr = rda.msg_length;
 423            rda.msg_length = tmp;
 424        }
 425        s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
 426    }
 427}
 428
 429
 430#define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR)
 431
 432#define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR)
 433
 434#define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR)
 435
 436#define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR)
 437
 438#if 1
 439
 440#define CHECK_RMD(ADDR,RES) do {                \
 441    struct pcnet_RMD rmd;                       \
 442    RMDLOAD(&rmd,(ADDR));                       \
 443    (RES) |= (GET_FIELD(rmd.buf_length, RMDL, ONES) != 15) \
 444          || (GET_FIELD(rmd.msg_length, RMDM, ZEROS) != 0); \
 445} while (0)
 446
 447#define CHECK_TMD(ADDR,RES) do {                \
 448    struct pcnet_TMD tmd;                       \
 449    TMDLOAD(&tmd,(ADDR));                       \
 450    (RES) |= (GET_FIELD(tmd.length, TMDL, ONES) != 15); \
 451} while (0)
 452
 453#else
 454
 455#define CHECK_RMD(ADDR,RES) do {                \
 456    switch (BCR_SWSTYLE(s)) {                   \
 457    case 0x00:                                  \
 458        do {                                    \
 459            uint16_t rda[4];                    \
 460            s->phys_mem_read(s->dma_opaque, (ADDR), \
 461                (void *)&rda[0], sizeof(rda), 0); \
 462            (RES) |= (rda[2] & 0xf000)!=0xf000; \
 463            (RES) |= (rda[3] & 0xf000)!=0x0000; \
 464        } while (0);                            \
 465        break;                                  \
 466    case 0x01:                                  \
 467    case 0x02:                                  \
 468        do {                                    \
 469            uint32_t rda[4];                    \
 470            s->phys_mem_read(s->dma_opaque, (ADDR), \
 471                (void *)&rda[0], sizeof(rda), 0); \
 472            (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
 473            (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
 474        } while (0);                            \
 475        break;                                  \
 476    case 0x03:                                  \
 477        do {                                    \
 478            uint32_t rda[4];                    \
 479            s->phys_mem_read(s->dma_opaque, (ADDR), \
 480                (void *)&rda[0], sizeof(rda), 0); \
 481            (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
 482            (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
 483        } while (0);                            \
 484        break;                                  \
 485    }                                           \
 486} while (0)
 487
 488#define CHECK_TMD(ADDR,RES) do {                \
 489    switch (BCR_SWSTYLE(s)) {                   \
 490    case 0x00:                                  \
 491        do {                                    \
 492            uint16_t xda[4];                    \
 493            s->phys_mem_read(s->dma_opaque, (ADDR), \
 494                (void *)&xda[0], sizeof(xda), 0); \
 495            (RES) |= (xda[2] & 0xf000)!=0xf000; \
 496        } while (0);                            \
 497        break;                                  \
 498    case 0x01:                                  \
 499    case 0x02:                                  \
 500    case 0x03:                                  \
 501        do {                                    \
 502            uint32_t xda[4];                    \
 503            s->phys_mem_read(s->dma_opaque, (ADDR), \
 504                (void *)&xda[0], sizeof(xda), 0); \
 505            (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
 506        } while (0);                            \
 507        break;                                  \
 508    }                                           \
 509} while (0)
 510
 511#endif
 512
 513#define PRINT_PKTHDR(BUF) do {                  \
 514    struct qemu_ether_header *hdr = (void *)(BUF); \
 515    printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
 516           "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
 517           "type=0x%04x\n",                     \
 518           hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
 519           hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
 520           hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
 521           hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
 522           be16_to_cpu(hdr->ether_type));       \
 523} while (0)
 524
 525#define MULTICAST_FILTER_LEN 8
 526
 527static inline uint32_t lnc_mchash(const uint8_t *ether_addr)
 528{
 529#define LNC_POLYNOMIAL          0xEDB88320UL
 530    uint32_t crc = 0xFFFFFFFF;
 531    int idx, bit;
 532    uint8_t data;
 533
 534    for (idx = 0; idx < 6; idx++) {
 535        for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) {
 536            crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
 537            data >>= 1;
 538        }
 539    }
 540    return crc;
 541#undef LNC_POLYNOMIAL
 542}
 543
 544#define CRC(crc, ch)     (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
 545
 546/* generated using the AUTODIN II polynomial
 547 *      x^32 + x^26 + x^23 + x^22 + x^16 +
 548 *      x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
 549 */
 550static const uint32_t crctab[256] = {
 551        0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
 552        0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
 553        0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
 554        0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
 555        0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
 556        0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
 557        0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
 558        0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
 559        0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
 560        0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
 561        0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
 562        0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
 563        0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
 564        0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
 565        0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
 566        0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
 567        0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
 568        0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
 569        0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
 570        0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
 571        0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
 572        0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
 573        0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
 574        0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
 575        0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
 576        0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
 577        0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
 578        0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
 579        0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
 580        0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
 581        0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
 582        0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
 583        0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
 584        0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
 585        0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
 586        0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
 587        0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
 588        0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
 589        0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
 590        0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
 591        0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
 592        0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
 593        0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
 594        0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
 595        0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
 596        0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
 597        0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
 598        0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
 599        0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
 600        0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
 601        0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
 602        0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
 603        0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
 604        0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
 605        0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
 606        0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
 607        0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
 608        0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
 609        0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
 610        0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
 611        0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
 612        0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
 613        0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
 614        0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
 615};
 616
 617static inline int padr_match(PCNetState *s, const uint8_t *buf, int size)
 618{
 619    struct qemu_ether_header *hdr = (void *)buf;
 620    uint8_t padr[6] = {
 621        s->csr[12] & 0xff, s->csr[12] >> 8,
 622        s->csr[13] & 0xff, s->csr[13] >> 8,
 623        s->csr[14] & 0xff, s->csr[14] >> 8
 624    };
 625    int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6);
 626#ifdef PCNET_DEBUG_MATCH
 627    printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
 628           "padr=%02x:%02x:%02x:%02x:%02x:%02x\n",
 629           hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2],
 630           hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5],
 631           padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]);
 632    printf("padr_match result=%d\n", result);
 633#endif
 634    return result;
 635}
 636
 637static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size)
 638{
 639    static const uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 640    struct qemu_ether_header *hdr = (void *)buf;
 641    int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6);
 642#ifdef PCNET_DEBUG_MATCH
 643    printf("padr_bcast result=%d\n", result);
 644#endif
 645    return result;
 646}
 647
 648static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
 649{
 650    struct qemu_ether_header *hdr = (void *)buf;
 651    if ((*(hdr->ether_dhost)&0x01) &&
 652        ((uint64_t *)&s->csr[8])[0] != 0LL) {
 653        uint8_t ladr[8] = {
 654            s->csr[8] & 0xff, s->csr[8] >> 8,
 655            s->csr[9] & 0xff, s->csr[9] >> 8,
 656            s->csr[10] & 0xff, s->csr[10] >> 8,
 657            s->csr[11] & 0xff, s->csr[11] >> 8
 658        };
 659        int index = lnc_mchash(hdr->ether_dhost) >> 26;
 660        return !!(ladr[index >> 3] & (1 << (index & 7)));
 661    }
 662    return 0;
 663}
 664
 665static inline hwaddr pcnet_rdra_addr(PCNetState *s, int idx)
 666{
 667    while (idx < 1) {
 668        idx += CSR_RCVRL(s);
 669    }
 670    return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8));
 671}
 672
 673static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time)
 674{
 675    int64_t next_time = current_time +
 676                        (65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s))) * 30;
 677
 678    if (next_time <= current_time) {
 679        next_time = current_time + 1;
 680    }
 681    return next_time;
 682}
 683
 684static void pcnet_poll(PCNetState *s);
 685static void pcnet_poll_timer(void *opaque);
 686
 687static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
 688static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
 689static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
 690
 691static void pcnet_s_reset(PCNetState *s)
 692{
 693    trace_pcnet_s_reset(s);
 694
 695    s->rdra = 0;
 696    s->tdra = 0;
 697    s->rap = 0;
 698
 699    s->bcr[BCR_BSBC] &= ~0x0080;
 700
 701    s->csr[0]   = 0x0004;
 702    s->csr[3]   = 0x0000;
 703    s->csr[4]   = 0x0115;
 704    s->csr[5]   = 0x0000;
 705    s->csr[6]   = 0x0000;
 706    s->csr[8]   = 0;
 707    s->csr[9]   = 0;
 708    s->csr[10]  = 0;
 709    s->csr[11]  = 0;
 710    s->csr[12]  = le16_to_cpu(((uint16_t *)&s->prom[0])[0]);
 711    s->csr[13]  = le16_to_cpu(((uint16_t *)&s->prom[0])[1]);
 712    s->csr[14]  = le16_to_cpu(((uint16_t *)&s->prom[0])[2]);
 713    s->csr[15] &= 0x21c4;
 714    s->csr[72]  = 1;
 715    s->csr[74]  = 1;
 716    s->csr[76]  = 1;
 717    s->csr[78]  = 1;
 718    s->csr[80]  = 0x1410;
 719    s->csr[88]  = 0x1003;
 720    s->csr[89]  = 0x0262;
 721    s->csr[94]  = 0x0000;
 722    s->csr[100] = 0x0200;
 723    s->csr[103] = 0x0105;
 724    s->csr[112] = 0x0000;
 725    s->csr[114] = 0x0000;
 726    s->csr[122] = 0x0000;
 727    s->csr[124] = 0x0000;
 728
 729    s->tx_busy = 0;
 730}
 731
 732static void pcnet_update_irq(PCNetState *s)
 733{
 734    int isr = 0;
 735    s->csr[0] &= ~0x0080;
 736
 737#if 1
 738    if (((s->csr[0] & ~s->csr[3]) & 0x5f00) ||
 739        (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) ||
 740        (((s->csr[5]>>1) & s->csr[5]) & 0x0048))
 741#else
 742    if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ ||
 743        (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ ||
 744        (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ ||
 745        (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ ||
 746        (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ ||
 747        (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ ||
 748        (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ ||
 749        (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ ||
 750        (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ ||
 751        (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ ||
 752        (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ ||
 753        (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */)
 754#endif
 755    {
 756
 757        isr = CSR_INEA(s);
 758        s->csr[0] |= 0x0080;
 759    }
 760
 761    if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */
 762        s->csr[4] &= ~0x0080;
 763        s->csr[4] |= 0x0040;
 764        s->csr[0] |= 0x0080;
 765        isr = 1;
 766        trace_pcnet_user_int(s);
 767    }
 768
 769#if 1
 770    if (((s->csr[5]>>1) & s->csr[5]) & 0x0500)
 771#else
 772    if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ ||
 773        (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ )
 774#endif
 775    {
 776        isr = 1;
 777        s->csr[0] |= 0x0080;
 778    }
 779
 780    if (isr != s->isr) {
 781        trace_pcnet_isr_change(s, isr, s->isr);
 782    }
 783    qemu_set_irq(s->irq, isr);
 784    s->isr = isr;
 785}
 786
 787static void pcnet_init(PCNetState *s)
 788{
 789    int rlen, tlen;
 790    uint16_t padr[3], ladrf[4], mode;
 791    uint32_t rdra, tdra;
 792
 793    trace_pcnet_init(s, PHYSADDR(s, CSR_IADR(s)));
 794
 795    if (BCR_SSIZE32(s)) {
 796        struct pcnet_initblk32 initblk;
 797        s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
 798                (uint8_t *)&initblk, sizeof(initblk), 0);
 799        mode = le16_to_cpu(initblk.mode);
 800        rlen = initblk.rlen >> 4;
 801        tlen = initblk.tlen >> 4;
 802        ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
 803        ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
 804        ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
 805        ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
 806        padr[0] = le16_to_cpu(initblk.padr[0]);
 807        padr[1] = le16_to_cpu(initblk.padr[1]);
 808        padr[2] = le16_to_cpu(initblk.padr[2]);
 809        rdra = le32_to_cpu(initblk.rdra);
 810        tdra = le32_to_cpu(initblk.tdra);
 811    } else {
 812        struct pcnet_initblk16 initblk;
 813        s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
 814                (uint8_t *)&initblk, sizeof(initblk), 0);
 815        mode = le16_to_cpu(initblk.mode);
 816        ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
 817        ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
 818        ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
 819        ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
 820        padr[0] = le16_to_cpu(initblk.padr[0]);
 821        padr[1] = le16_to_cpu(initblk.padr[1]);
 822        padr[2] = le16_to_cpu(initblk.padr[2]);
 823        rdra = le32_to_cpu(initblk.rdra);
 824        tdra = le32_to_cpu(initblk.tdra);
 825        rlen = rdra >> 29;
 826        tlen = tdra >> 29;
 827        rdra &= 0x00ffffff;
 828        tdra &= 0x00ffffff;
 829    }
 830
 831    trace_pcnet_rlen_tlen(s, rlen, tlen);
 832
 833    CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512;
 834    CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512;
 835    s->csr[ 6] = (tlen << 12) | (rlen << 8);
 836    s->csr[15] = mode;
 837    s->csr[ 8] = ladrf[0];
 838    s->csr[ 9] = ladrf[1];
 839    s->csr[10] = ladrf[2];
 840    s->csr[11] = ladrf[3];
 841    s->csr[12] = padr[0];
 842    s->csr[13] = padr[1];
 843    s->csr[14] = padr[2];
 844    s->rdra = PHYSADDR(s, rdra);
 845    s->tdra = PHYSADDR(s, tdra);
 846
 847    CSR_RCVRC(s) = CSR_RCVRL(s);
 848    CSR_XMTRC(s) = CSR_XMTRL(s);
 849
 850    trace_pcnet_ss32_rdra_tdra(s, BCR_SSIZE32(s),
 851                               s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s));
 852
 853    s->csr[0] |= 0x0101;
 854    s->csr[0] &= ~0x0004;       /* clear STOP bit */
 855
 856    qemu_flush_queued_packets(qemu_get_queue(s->nic));
 857}
 858
 859static void pcnet_start(PCNetState *s)
 860{
 861#ifdef PCNET_DEBUG
 862    printf("pcnet_start\n");
 863#endif
 864
 865    if (!CSR_DTX(s)) {
 866        s->csr[0] |= 0x0010;    /* set TXON */
 867    }
 868    if (!CSR_DRX(s)) {
 869        s->csr[0] |= 0x0020;    /* set RXON */
 870    }
 871    s->csr[0] &= ~0x0004;       /* clear STOP bit */
 872    s->csr[0] |= 0x0002;
 873    pcnet_poll_timer(s);
 874
 875    qemu_flush_queued_packets(qemu_get_queue(s->nic));
 876}
 877
 878static void pcnet_stop(PCNetState *s)
 879{
 880#ifdef PCNET_DEBUG
 881    printf("pcnet_stop\n");
 882#endif
 883    s->csr[0] &= ~0xffeb;
 884    s->csr[0] |= 0x0014;
 885    s->csr[4] &= ~0x02c2;
 886    s->csr[5] &= ~0x0011;
 887    pcnet_poll_timer(s);
 888}
 889
 890static void pcnet_rdte_poll(PCNetState *s)
 891{
 892    s->csr[28] = s->csr[29] = 0;
 893    if (s->rdra) {
 894        int bad = 0;
 895#if 1
 896        hwaddr crda = pcnet_rdra_addr(s, CSR_RCVRC(s));
 897        hwaddr nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s));
 898        hwaddr nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s));
 899#else
 900        hwaddr crda = s->rdra +
 901            (CSR_RCVRL(s) - CSR_RCVRC(s)) *
 902            (BCR_SWSTYLE(s) ? 16 : 8 );
 903        int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1;
 904        hwaddr nrda = s->rdra +
 905            (CSR_RCVRL(s) - nrdc) *
 906            (BCR_SWSTYLE(s) ? 16 : 8 );
 907        int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1;
 908        hwaddr nnrd = s->rdra +
 909            (CSR_RCVRL(s) - nnrc) *
 910            (BCR_SWSTYLE(s) ? 16 : 8 );
 911#endif
 912
 913        CHECK_RMD(crda, bad);
 914        if (!bad) {
 915            CHECK_RMD(nrda, bad);
 916            if (bad || (nrda == crda)) nrda = 0;
 917            CHECK_RMD(nnrd, bad);
 918            if (bad || (nnrd == crda)) nnrd = 0;
 919
 920            s->csr[28] = crda & 0xffff;
 921            s->csr[29] = crda >> 16;
 922            s->csr[26] = nrda & 0xffff;
 923            s->csr[27] = nrda >> 16;
 924            s->csr[36] = nnrd & 0xffff;
 925            s->csr[37] = nnrd >> 16;
 926#ifdef PCNET_DEBUG
 927            if (bad) {
 928                printf("pcnet: BAD RMD RECORDS AFTER 0x" TARGET_FMT_plx "\n",
 929                       crda);
 930            }
 931        } else {
 932            printf("pcnet: BAD RMD RDA=0x" TARGET_FMT_plx "\n", crda);
 933#endif
 934        }
 935    }
 936
 937    if (CSR_CRDA(s)) {
 938        struct pcnet_RMD rmd;
 939        RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s)));
 940        CSR_CRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
 941        CSR_CRST(s) = rmd.status;
 942#ifdef PCNET_DEBUG_RMD_X
 943        printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMDL=0x%04x RMDS=0x%04x RMDM=0x%08x\n",
 944                PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s),
 945                rmd.buf_length, rmd.status, rmd.msg_length);
 946        PRINT_RMD(&rmd);
 947#endif
 948    } else {
 949        CSR_CRBC(s) = CSR_CRST(s) = 0;
 950    }
 951
 952    if (CSR_NRDA(s)) {
 953        struct pcnet_RMD rmd;
 954        RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s)));
 955        CSR_NRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
 956        CSR_NRST(s) = rmd.status;
 957    } else {
 958        CSR_NRBC(s) = CSR_NRST(s) = 0;
 959    }
 960
 961}
 962
 963static int pcnet_tdte_poll(PCNetState *s)
 964{
 965    s->csr[34] = s->csr[35] = 0;
 966    if (s->tdra) {
 967        hwaddr cxda = s->tdra +
 968            (CSR_XMTRL(s) - CSR_XMTRC(s)) *
 969            (BCR_SWSTYLE(s) ? 16 : 8);
 970        int bad = 0;
 971        CHECK_TMD(cxda, bad);
 972        if (!bad) {
 973            if (CSR_CXDA(s) != cxda) {
 974                s->csr[60] = s->csr[34];
 975                s->csr[61] = s->csr[35];
 976                s->csr[62] = CSR_CXBC(s);
 977                s->csr[63] = CSR_CXST(s);
 978            }
 979            s->csr[34] = cxda & 0xffff;
 980            s->csr[35] = cxda >> 16;
 981#ifdef PCNET_DEBUG_X
 982            printf("pcnet: BAD TMD XDA=0x%08x\n", cxda);
 983#endif
 984        }
 985    }
 986
 987    if (CSR_CXDA(s)) {
 988        struct pcnet_TMD tmd;
 989
 990        TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
 991
 992        CSR_CXBC(s) = GET_FIELD(tmd.length, TMDL, BCNT);
 993        CSR_CXST(s) = tmd.status;
 994    } else {
 995        CSR_CXBC(s) = CSR_CXST(s) = 0;
 996    }
 997
 998    return !!(CSR_CXST(s) & 0x8000);
 999}
1000
1001#define MIN_BUF_SIZE 60
1002
1003ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_)
1004{
1005    PCNetState *s = qemu_get_nic_opaque(nc);
1006    int is_padr = 0, is_bcast = 0, is_ladr = 0;
1007    uint8_t buf1[60];
1008    int remaining;
1009    int crc_err = 0;
1010    int size = size_;
1011
1012    if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size ||
1013        (CSR_LOOP(s) && !s->looptest)) {
1014        return -1;
1015    }
1016#ifdef PCNET_DEBUG
1017    printf("pcnet_receive size=%d\n", size);
1018#endif
1019
1020    /* if too small buffer, then expand it */
1021    if (size < MIN_BUF_SIZE) {
1022        memcpy(buf1, buf, size);
1023        memset(buf1 + size, 0, MIN_BUF_SIZE - size);
1024        buf = buf1;
1025        size = MIN_BUF_SIZE;
1026    }
1027
1028    if (CSR_PROM(s)
1029        || (is_padr=padr_match(s, buf, size))
1030        || (is_bcast=padr_bcast(s, buf, size))
1031        || (is_ladr=ladr_match(s, buf, size))) {
1032
1033        pcnet_rdte_poll(s);
1034
1035        if (!(CSR_CRST(s) & 0x8000) && s->rdra) {
1036            struct pcnet_RMD rmd;
1037            int rcvrc = CSR_RCVRC(s)-1,i;
1038            hwaddr nrda;
1039            for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) {
1040                if (rcvrc <= 1)
1041                    rcvrc = CSR_RCVRL(s);
1042                nrda = s->rdra +
1043                    (CSR_RCVRL(s) - rcvrc) *
1044                    (BCR_SWSTYLE(s) ? 16 : 8 );
1045                RMDLOAD(&rmd, nrda);
1046                if (GET_FIELD(rmd.status, RMDS, OWN)) {
1047#ifdef PCNET_DEBUG_RMD
1048                    printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
1049                                rcvrc, CSR_RCVRC(s));
1050#endif
1051                    CSR_RCVRC(s) = rcvrc;
1052                    pcnet_rdte_poll(s);
1053                    break;
1054                }
1055            }
1056        }
1057
1058        if (!(CSR_CRST(s) & 0x8000)) {
1059#ifdef PCNET_DEBUG_RMD
1060            printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s));
1061#endif
1062            s->csr[0] |= 0x1000; /* Set MISS flag */
1063            CSR_MISSC(s)++;
1064        } else {
1065            uint8_t *src = s->buffer;
1066            hwaddr crda = CSR_CRDA(s);
1067            struct pcnet_RMD rmd;
1068            int pktcount = 0;
1069
1070            if (!s->looptest) {
1071                if (size > 4092) {
1072#ifdef PCNET_DEBUG_RMD
1073                    fprintf(stderr, "pcnet: truncates rx packet.\n");
1074#endif
1075                    size = 4092;
1076                }
1077                memcpy(src, buf, size);
1078                /* no need to compute the CRC */
1079                src[size] = 0;
1080                src[size + 1] = 0;
1081                src[size + 2] = 0;
1082                src[size + 3] = 0;
1083                size += 4;
1084            } else if (s->looptest == PCNET_LOOPTEST_CRC ||
1085                       !CSR_DXMTFCS(s) || size < MIN_BUF_SIZE+4) {
1086                uint32_t fcs = ~0;
1087                uint8_t *p = src;
1088
1089                while (p != &src[size])
1090                    CRC(fcs, *p++);
1091                *(uint32_t *)p = htonl(fcs);
1092                size += 4;
1093            } else {
1094                uint32_t fcs = ~0;
1095                uint8_t *p = src;
1096
1097                while (p != &src[size])
1098                    CRC(fcs, *p++);
1099                crc_err = (*(uint32_t *)p != htonl(fcs));
1100            }
1101
1102#ifdef PCNET_DEBUG_MATCH
1103            PRINT_PKTHDR(buf);
1104#endif
1105
1106            RMDLOAD(&rmd, PHYSADDR(s,crda));
1107            /*if (!CSR_LAPPEN(s))*/
1108                SET_FIELD(&rmd.status, RMDS, STP, 1);
1109
1110#define PCNET_RECV_STORE() do {                                 \
1111    int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),remaining); \
1112    hwaddr rbadr = PHYSADDR(s, rmd.rbadr);          \
1113    s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \
1114    src += count; remaining -= count;                           \
1115    SET_FIELD(&rmd.status, RMDS, OWN, 0);                       \
1116    RMDSTORE(&rmd, PHYSADDR(s,crda));                           \
1117    pktcount++;                                                 \
1118} while (0)
1119
1120            remaining = size;
1121            PCNET_RECV_STORE();
1122            if ((remaining > 0) && CSR_NRDA(s)) {
1123                hwaddr nrda = CSR_NRDA(s);
1124#ifdef PCNET_DEBUG_RMD
1125                PRINT_RMD(&rmd);
1126#endif
1127                RMDLOAD(&rmd, PHYSADDR(s,nrda));
1128                if (GET_FIELD(rmd.status, RMDS, OWN)) {
1129                    crda = nrda;
1130                    PCNET_RECV_STORE();
1131#ifdef PCNET_DEBUG_RMD
1132                    PRINT_RMD(&rmd);
1133#endif
1134                    if ((remaining > 0) && (nrda=CSR_NNRD(s))) {
1135                        RMDLOAD(&rmd, PHYSADDR(s,nrda));
1136                        if (GET_FIELD(rmd.status, RMDS, OWN)) {
1137                            crda = nrda;
1138                            PCNET_RECV_STORE();
1139                        }
1140                    }
1141                }
1142            }
1143
1144#undef PCNET_RECV_STORE
1145
1146            RMDLOAD(&rmd, PHYSADDR(s,crda));
1147            if (remaining == 0) {
1148                SET_FIELD(&rmd.msg_length, RMDM, MCNT, size);
1149                SET_FIELD(&rmd.status, RMDS, ENP, 1);
1150                SET_FIELD(&rmd.status, RMDS, PAM, !CSR_PROM(s) && is_padr);
1151                SET_FIELD(&rmd.status, RMDS, LFAM, !CSR_PROM(s) && is_ladr);
1152                SET_FIELD(&rmd.status, RMDS, BAM, !CSR_PROM(s) && is_bcast);
1153                if (crc_err) {
1154                    SET_FIELD(&rmd.status, RMDS, CRC, 1);
1155                    SET_FIELD(&rmd.status, RMDS, ERR, 1);
1156                }
1157            } else {
1158                SET_FIELD(&rmd.status, RMDS, OFLO, 1);
1159                SET_FIELD(&rmd.status, RMDS, BUFF, 1);
1160                SET_FIELD(&rmd.status, RMDS, ERR, 1);
1161            }
1162            RMDSTORE(&rmd, PHYSADDR(s,crda));
1163            s->csr[0] |= 0x0400;
1164
1165#ifdef PCNET_DEBUG
1166            printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n",
1167                CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);
1168#endif
1169#ifdef PCNET_DEBUG_RMD
1170            PRINT_RMD(&rmd);
1171#endif
1172
1173            while (pktcount--) {
1174                if (CSR_RCVRC(s) <= 1) {
1175                    CSR_RCVRC(s) = CSR_RCVRL(s);
1176                } else {
1177                    CSR_RCVRC(s)--;
1178                }
1179            }
1180
1181            pcnet_rdte_poll(s);
1182
1183        }
1184    }
1185
1186    pcnet_poll(s);
1187    pcnet_update_irq(s);
1188
1189    return size_;
1190}
1191
1192void pcnet_set_link_status(NetClientState *nc)
1193{
1194    PCNetState *d = qemu_get_nic_opaque(nc);
1195
1196    d->lnkst = nc->link_down ? 0 : 0x40;
1197}
1198
1199static void pcnet_transmit(PCNetState *s)
1200{
1201    hwaddr xmit_cxda = 0;
1202    int count = CSR_XMTRL(s)-1;
1203    int add_crc = 0;
1204    int bcnt;
1205    s->xmit_pos = -1;
1206
1207    if (!CSR_TXON(s)) {
1208        s->csr[0] &= ~0x0008;
1209        return;
1210    }
1211
1212    s->tx_busy = 1;
1213
1214txagain:
1215    if (pcnet_tdte_poll(s)) {
1216        struct pcnet_TMD tmd;
1217
1218        TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
1219
1220#ifdef PCNET_DEBUG_TMD
1221        printf("  TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s)));
1222        PRINT_TMD(&tmd);
1223#endif
1224        if (GET_FIELD(tmd.status, TMDS, STP)) {
1225            s->xmit_pos = 0;
1226            xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
1227            if (BCR_SWSTYLE(s) != 1)
1228                add_crc = GET_FIELD(tmd.status, TMDS, ADDFCS);
1229        }
1230        if (s->lnkst == 0 &&
1231            (!CSR_LOOP(s) || (!CSR_INTL(s) && !BCR_TMAULOOP(s)))) {
1232            SET_FIELD(&tmd.misc, TMDM, LCAR, 1);
1233            SET_FIELD(&tmd.status, TMDS, ERR, 1);
1234            SET_FIELD(&tmd.status, TMDS, OWN, 0);
1235            s->csr[0] |= 0xa000; /* ERR | CERR */
1236            s->xmit_pos = -1;
1237            goto txdone;
1238        }
1239
1240        if (s->xmit_pos < 0) {
1241            goto txdone;
1242        }
1243
1244        bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
1245
1246        /* if multi-tmd packet outsizes s->buffer then skip it silently.
1247         * Note: this is not what real hw does.
1248         * Last four bytes of s->buffer are used to store CRC FCS code.
1249         */
1250        if (s->xmit_pos + bcnt > sizeof(s->buffer) - 4) {
1251            s->xmit_pos = -1;
1252            goto txdone;
1253        }
1254
1255        s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
1256                         s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
1257        s->xmit_pos += bcnt;
1258
1259        if (!GET_FIELD(tmd.status, TMDS, ENP)) {
1260            goto txdone;
1261        }
1262
1263#ifdef PCNET_DEBUG
1264        printf("pcnet_transmit size=%d\n", s->xmit_pos);
1265#endif
1266        if (CSR_LOOP(s)) {
1267            if (BCR_SWSTYLE(s) == 1)
1268                add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS);
1269            s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC;
1270            pcnet_receive(qemu_get_queue(s->nic), s->buffer, s->xmit_pos);
1271            s->looptest = 0;
1272        } else {
1273            if (s->nic) {
1274                qemu_send_packet(qemu_get_queue(s->nic), s->buffer,
1275                                 s->xmit_pos);
1276            }
1277        }
1278
1279        s->csr[0] &= ~0x0008;   /* clear TDMD */
1280        s->csr[4] |= 0x0004;    /* set TXSTRT */
1281        s->xmit_pos = -1;
1282
1283txdone:
1284        SET_FIELD(&tmd.status, TMDS, OWN, 0);
1285        TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
1286        if (!CSR_TOKINTD(s)
1287            || (CSR_LTINTEN(s) && GET_FIELD(tmd.status, TMDS, LTINT))) {
1288            s->csr[0] |= 0x0200;    /* set TINT */
1289        }
1290        if (CSR_XMTRC(s) <= 1) {
1291            CSR_XMTRC(s) = CSR_XMTRL(s);
1292        } else {
1293            CSR_XMTRC(s)--;
1294        }
1295        if (count--) {
1296            goto txagain;
1297        }
1298    } else if (s->xmit_pos >= 0) {
1299        struct pcnet_TMD tmd;
1300        TMDLOAD(&tmd, xmit_cxda);
1301        SET_FIELD(&tmd.misc, TMDM, BUFF, 1);
1302        SET_FIELD(&tmd.misc, TMDM, UFLO, 1);
1303        SET_FIELD(&tmd.status, TMDS, ERR, 1);
1304        SET_FIELD(&tmd.status, TMDS, OWN, 0);
1305        TMDSTORE(&tmd, xmit_cxda);
1306        s->csr[0] |= 0x0200;    /* set TINT */
1307        if (!CSR_DXSUFLO(s)) {
1308            s->csr[0] &= ~0x0010;
1309        } else if (count--) {
1310            goto txagain;
1311        }
1312    }
1313
1314    s->tx_busy = 0;
1315}
1316
1317static void pcnet_poll(PCNetState *s)
1318{
1319    if (CSR_RXON(s)) {
1320        pcnet_rdte_poll(s);
1321    }
1322
1323    if (CSR_TDMD(s) || (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s))) {
1324        /* prevent recursion */
1325        if (s->tx_busy) {
1326            return;
1327        }
1328        pcnet_transmit(s);
1329    }
1330}
1331
1332static void pcnet_poll_timer(void *opaque)
1333{
1334    PCNetState *s = opaque;
1335
1336    timer_del(s->poll_timer);
1337
1338    if (CSR_TDMD(s)) {
1339        pcnet_transmit(s);
1340    }
1341
1342    pcnet_update_irq(s);
1343
1344    if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) {
1345        uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) * 33;
1346        if (!s->timer || !now) {
1347            s->timer = now;
1348        } else {
1349            uint64_t t = now - s->timer + CSR_POLL(s);
1350            if (t > 0xffffLL) {
1351                pcnet_poll(s);
1352                CSR_POLL(s) = CSR_PINT(s);
1353            } else {
1354                CSR_POLL(s) = t;
1355            }
1356        }
1357        timer_mod(s->poll_timer,
1358            pcnet_get_next_poll_time(s,qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)));
1359    }
1360}
1361
1362
1363static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value)
1364{
1365    uint16_t val = new_value;
1366#ifdef PCNET_DEBUG_CSR
1367    printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val);
1368#endif
1369    switch (rap) {
1370    case 0:
1371        s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */
1372
1373        s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048);
1374
1375        val = (val & 0x007f) | (s->csr[0] & 0x7f00);
1376
1377        /* IFF STOP, STRT and INIT are set, clear STRT and INIT */
1378        if ((val & 7) == 7) {
1379            val &= ~3;
1380        }
1381        if (!CSR_STOP(s) && (val & 4)) {
1382            pcnet_stop(s);
1383        }
1384        if (!CSR_INIT(s) && (val & 1)) {
1385            pcnet_init(s);
1386        }
1387        if (!CSR_STRT(s) && (val & 2)) {
1388            pcnet_start(s);
1389        }
1390        if (CSR_TDMD(s)) {
1391            pcnet_transmit(s);
1392        }
1393        return;
1394    case 1:
1395    case 2:
1396    case 8:
1397    case 9:
1398    case 10:
1399    case 11:
1400    case 12:
1401    case 13:
1402    case 14:
1403    case 15:
1404    case 18: /* CRBAL */
1405    case 19: /* CRBAU */
1406    case 20: /* CXBAL */
1407    case 21: /* CXBAU */
1408    case 22: /* NRBAU */
1409    case 23: /* NRBAU */
1410    case 24:
1411    case 25:
1412    case 26:
1413    case 27:
1414    case 28:
1415    case 29:
1416    case 30:
1417    case 31:
1418    case 32:
1419    case 33:
1420    case 34:
1421    case 35:
1422    case 36:
1423    case 37:
1424    case 38:
1425    case 39:
1426    case 40: /* CRBC */
1427    case 41:
1428    case 42: /* CXBC */
1429    case 43:
1430    case 44:
1431    case 45:
1432    case 46: /* POLL */
1433    case 47: /* POLLINT */
1434    case 72:
1435    case 74:
1436        break;
1437    case 76: /* RCVRL */
1438    case 78: /* XMTRL */
1439        val = (val > 0) ? val : 512;
1440        break;
1441    case 112:
1442        if (CSR_STOP(s) || CSR_SPND(s)) {
1443            break;
1444        }
1445        return;
1446    case 3:
1447        break;
1448    case 4:
1449        s->csr[4] &= ~(val & 0x026a);
1450        val &= ~0x026a; val |= s->csr[4] & 0x026a;
1451        break;
1452    case 5:
1453        s->csr[5] &= ~(val & 0x0a90);
1454        val &= ~0x0a90; val |= s->csr[5] & 0x0a90;
1455        break;
1456    case 16:
1457        pcnet_csr_writew(s,1,val);
1458        return;
1459    case 17:
1460        pcnet_csr_writew(s,2,val);
1461        return;
1462    case 58:
1463        pcnet_bcr_writew(s,BCR_SWS,val);
1464        break;
1465    default:
1466        return;
1467    }
1468    s->csr[rap] = val;
1469}
1470
1471static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap)
1472{
1473    uint32_t val;
1474    switch (rap) {
1475    case 0:
1476        pcnet_update_irq(s);
1477        val = s->csr[0];
1478        val |= (val & 0x7800) ? 0x8000 : 0;
1479        break;
1480    case 16:
1481        return pcnet_csr_readw(s,1);
1482    case 17:
1483        return pcnet_csr_readw(s,2);
1484    case 58:
1485        return pcnet_bcr_readw(s,BCR_SWS);
1486    case 88:
1487        val = s->csr[89];
1488        val <<= 16;
1489        val |= s->csr[88];
1490        break;
1491    default:
1492        val = s->csr[rap];
1493    }
1494#ifdef PCNET_DEBUG_CSR
1495    printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val);
1496#endif
1497    return val;
1498}
1499
1500static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
1501{
1502    rap &= 127;
1503#ifdef PCNET_DEBUG_BCR
1504    printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val);
1505#endif
1506    switch (rap) {
1507    case BCR_SWS:
1508        if (!(CSR_STOP(s) || CSR_SPND(s)))
1509            return;
1510        val &= ~0x0300;
1511        switch (val & 0x00ff) {
1512        case 0:
1513            val |= 0x0200;
1514            break;
1515        case 1:
1516            val |= 0x0100;
1517            break;
1518        case 2:
1519        case 3:
1520            val |= 0x0300;
1521            break;
1522        default:
1523            printf("Bad SWSTYLE=0x%02x\n", val & 0xff);
1524            val = 0x0200;
1525            break;
1526        }
1527#ifdef PCNET_DEBUG
1528       printf("BCR_SWS=0x%04x\n", val);
1529#endif
1530        /* fall through */
1531    case BCR_LNKST:
1532    case BCR_LED1:
1533    case BCR_LED2:
1534    case BCR_LED3:
1535    case BCR_MC:
1536    case BCR_FDC:
1537    case BCR_BSBC:
1538    case BCR_EECAS:
1539    case BCR_PLAT:
1540        s->bcr[rap] = val;
1541        break;
1542    default:
1543        break;
1544    }
1545}
1546
1547uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
1548{
1549    uint32_t val;
1550    rap &= 127;
1551    switch (rap) {
1552    case BCR_LNKST:
1553    case BCR_LED1:
1554    case BCR_LED2:
1555    case BCR_LED3:
1556        val = s->bcr[rap] & ~0x8000;
1557        val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0;
1558        break;
1559    default:
1560        val = rap < 32 ? s->bcr[rap] : 0;
1561        break;
1562    }
1563#ifdef PCNET_DEBUG_BCR
1564    printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val);
1565#endif
1566    return val;
1567}
1568
1569void pcnet_h_reset(void *opaque)
1570{
1571    PCNetState *s = opaque;
1572
1573    s->bcr[BCR_MSRDA] = 0x0005;
1574    s->bcr[BCR_MSWRA] = 0x0005;
1575    s->bcr[BCR_MC   ] = 0x0002;
1576    s->bcr[BCR_LNKST] = 0x00c0;
1577    s->bcr[BCR_LED1 ] = 0x0084;
1578    s->bcr[BCR_LED2 ] = 0x0088;
1579    s->bcr[BCR_LED3 ] = 0x0090;
1580    s->bcr[BCR_FDC  ] = 0x0000;
1581    s->bcr[BCR_BSBC ] = 0x9001;
1582    s->bcr[BCR_EECAS] = 0x0002;
1583    s->bcr[BCR_SWS  ] = 0x0200;
1584    s->bcr[BCR_PLAT ] = 0xff06;
1585
1586    pcnet_s_reset(s);
1587    pcnet_update_irq(s);
1588    pcnet_poll_timer(s);
1589}
1590
1591void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
1592{
1593    PCNetState *s = opaque;
1594    pcnet_poll_timer(s);
1595#ifdef PCNET_DEBUG_IO
1596    printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val);
1597#endif
1598    if (!BCR_DWIO(s)) {
1599        switch (addr & 0x0f) {
1600        case 0x00: /* RDP */
1601            pcnet_csr_writew(s, s->rap, val);
1602            break;
1603        case 0x02:
1604            s->rap = val & 0x7f;
1605            break;
1606        case 0x06:
1607            pcnet_bcr_writew(s, s->rap, val);
1608            break;
1609        }
1610    }
1611    pcnet_update_irq(s);
1612}
1613
1614uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
1615{
1616    PCNetState *s = opaque;
1617    uint32_t val = -1;
1618    pcnet_poll_timer(s);
1619    if (!BCR_DWIO(s)) {
1620        switch (addr & 0x0f) {
1621        case 0x00: /* RDP */
1622            val = pcnet_csr_readw(s, s->rap);
1623            break;
1624        case 0x02:
1625            val = s->rap;
1626            break;
1627        case 0x04:
1628            pcnet_s_reset(s);
1629            val = 0;
1630            break;
1631        case 0x06:
1632            val = pcnet_bcr_readw(s, s->rap);
1633            break;
1634        }
1635    }
1636    pcnet_update_irq(s);
1637#ifdef PCNET_DEBUG_IO
1638    printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff);
1639#endif
1640    return val;
1641}
1642
1643void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
1644{
1645    PCNetState *s = opaque;
1646    pcnet_poll_timer(s);
1647#ifdef PCNET_DEBUG_IO
1648    printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val);
1649#endif
1650    if (BCR_DWIO(s)) {
1651        switch (addr & 0x0f) {
1652        case 0x00: /* RDP */
1653            pcnet_csr_writew(s, s->rap, val & 0xffff);
1654            break;
1655        case 0x04:
1656            s->rap = val & 0x7f;
1657            break;
1658        case 0x0c:
1659            pcnet_bcr_writew(s, s->rap, val & 0xffff);
1660            break;
1661        }
1662    } else if ((addr & 0x0f) == 0) {
1663        /* switch device to dword i/o mode */
1664        pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080);
1665#ifdef PCNET_DEBUG_IO
1666        printf("device switched into dword i/o mode\n");
1667#endif
1668    }
1669    pcnet_update_irq(s);
1670}
1671
1672uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
1673{
1674    PCNetState *s = opaque;
1675    uint32_t val = -1;
1676    pcnet_poll_timer(s);
1677    if (BCR_DWIO(s)) {
1678        switch (addr & 0x0f) {
1679        case 0x00: /* RDP */
1680            val = pcnet_csr_readw(s, s->rap);
1681            break;
1682        case 0x04:
1683            val = s->rap;
1684            break;
1685        case 0x08:
1686            pcnet_s_reset(s);
1687            val = 0;
1688            break;
1689        case 0x0c:
1690            val = pcnet_bcr_readw(s, s->rap);
1691            break;
1692        }
1693    }
1694    pcnet_update_irq(s);
1695#ifdef PCNET_DEBUG_IO
1696    printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val);
1697#endif
1698    return val;
1699}
1700
1701static bool is_version_2(void *opaque, int version_id)
1702{
1703    return version_id == 2;
1704}
1705
1706const VMStateDescription vmstate_pcnet = {
1707    .name = "pcnet",
1708    .version_id = 3,
1709    .minimum_version_id = 2,
1710    .fields = (VMStateField[]) {
1711        VMSTATE_INT32(rap, PCNetState),
1712        VMSTATE_INT32(isr, PCNetState),
1713        VMSTATE_INT32(lnkst, PCNetState),
1714        VMSTATE_UINT32(rdra, PCNetState),
1715        VMSTATE_UINT32(tdra, PCNetState),
1716        VMSTATE_BUFFER(prom, PCNetState),
1717        VMSTATE_UINT16_ARRAY(csr, PCNetState, 128),
1718        VMSTATE_UINT16_ARRAY(bcr, PCNetState, 32),
1719        VMSTATE_UINT64(timer, PCNetState),
1720        VMSTATE_INT32(xmit_pos, PCNetState),
1721        VMSTATE_BUFFER(buffer, PCNetState),
1722        VMSTATE_UNUSED_TEST(is_version_2, 4),
1723        VMSTATE_INT32(tx_busy, PCNetState),
1724        VMSTATE_TIMER_PTR(poll_timer, PCNetState),
1725        VMSTATE_END_OF_LIST()
1726    }
1727};
1728
1729void pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
1730{
1731    int i;
1732    uint16_t checksum;
1733
1734    s->poll_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pcnet_poll_timer, s);
1735
1736    qemu_macaddr_default_if_unset(&s->conf.macaddr);
1737    s->nic = qemu_new_nic(info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s);
1738    qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
1739
1740    /* Initialize the PROM */
1741
1742    /*
1743      Datasheet: http://pdfdata.datasheetsite.com/web/24528/AM79C970A.pdf
1744      page 95
1745    */
1746    memcpy(s->prom, s->conf.macaddr.a, 6);
1747    /* Reserved Location: must be 00h */
1748    s->prom[6] = s->prom[7] = 0x00;
1749    /* Reserved Location: must be 00h */
1750    s->prom[8] = 0x00;
1751    /* Hardware ID: must be 11h if compatibility to AMD drivers is desired */
1752    s->prom[9] = 0x11;
1753    /* User programmable space, init with 0 */
1754    s->prom[10] = s->prom[11] = 0x00;
1755    /* LSByte of two-byte checksum, which is the sum of bytes 00h-0Bh
1756       and bytes 0Eh and 0Fh, must therefore be initialized with 0! */
1757    s->prom[12] = s->prom[13] = 0x00;
1758    /* Must be ASCII W (57h) if compatibility to AMD
1759       driver software is desired */
1760    s->prom[14] = s->prom[15] = 0x57;
1761
1762    for (i = 0, checksum = 0; i < 16; i++) {
1763        checksum += s->prom[i];
1764    }
1765    *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
1766
1767    s->lnkst = 0x40; /* initial link state: up */
1768}
1769