Commit 80337b66a8e7a98963cb846f551d9ef533d7d489

Authored by bellard
1 parent 54ca9095

NIC emulation for qemu arm-softmmu (Paul Brook)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1682 c046a42c-6fe2-441c-8c8c-71466251a162
Makefile.target
... ... @@ -325,7 +325,7 @@ VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
325 325 endif
326 326 endif
327 327 ifeq ($(TARGET_BASE_ARCH), arm)
328   -VL_OBJS+= integratorcp.o ps2.o
  328 +VL_OBJS+= integratorcp.o ps2.o smc91c111.o
329 329 endif
330 330 ifdef CONFIG_GDBSTUB
331 331 VL_OBJS+=gdbstub.o
... ...
hw/integratorcp.c
... ... @@ -305,8 +305,6 @@ typedef struct icp_pic_state
305 305 int parent_irq;
306 306 } icp_pic_state;
307 307  
308   -static void icp_pic_set_level(icp_pic_state *, int, int);
309   -
310 308 static void icp_pic_update(icp_pic_state *s)
311 309 {
312 310 CPUState *env;
... ... @@ -314,8 +312,8 @@ static void icp_pic_update(icp_pic_state *s)
314 312 uint32_t flags;
315 313  
316 314 flags = (s->level & s->irq_enabled);
317   - icp_pic_set_level((icp_pic_state *)s->parent, s->parent_irq,
318   - flags != 0);
  315 + pic_set_irq_new(s->parent, s->parent_irq,
  316 + flags != 0);
319 317 return;
320 318 }
321 319 /* Raise CPU interrupt. */
... ... @@ -332,12 +330,13 @@ static void icp_pic_update(icp_pic_state *s)
332 330 }
333 331 }
334 332  
335   -static void icp_pic_set_level(icp_pic_state *s, int n, int level)
  333 +void pic_set_irq_new(void *opaque, int irq, int level)
336 334 {
  335 + icp_pic_state *s = (icp_pic_state *)opaque;
337 336 if (level)
338   - s->level |= 1 << n;
  337 + s->level |= 1 << irq;
339 338 else
340   - s->level &= ~(1 << n);
  339 + s->level &= ~(1 << irq);
341 340 icp_pic_update(s);
342 341 }
343 342  
... ... @@ -385,11 +384,11 @@ static void icp_pic_write(void *opaque, target_phys_addr_t offset,
385 384 break;
386 385 case 4: /* INT_SOFTSET */
387 386 if (value & 1)
388   - icp_pic_set_level(s, 0, 1);
  387 + pic_set_irq_new(s, 0, 1);
389 388 break;
390 389 case 5: /* INT_SOFTCLR */
391 390 if (value & 1)
392   - icp_pic_set_level(s, 0, 0);
  391 + pic_set_irq_new(s, 0, 0);
393 392 break;
394 393 case 10: /* FRQ_ENABLESET */
395 394 s->fiq_enabled |= value;
... ... @@ -513,9 +512,9 @@ static void icp_pit_update(icp_pit_state *s, int64_t now)
513 512 /* Update interrupts. */
514 513 for (n = 0; n < 3; n++) {
515 514 if (s->int_level[n] && (s->control[n] & 0x20)) {
516   - icp_pic_set_level(s->pic, 5 + n, 1);
  515 + pic_set_irq_new(s->pic, 5 + n, 1);
517 516 } else {
518   - icp_pic_set_level(s->pic, 5 + n, 0);
  517 + pic_set_irq_new(s->pic, 5 + n, 0);
519 518 }
520 519 if (next - s->expires[n] < 0)
521 520 next = s->expires[n];
... ... @@ -731,7 +730,7 @@ static void pl011_update(pl011_state *s)
731 730 uint32_t flags;
732 731  
733 732 flags = s->int_level & s->int_enabled;
734   - icp_pic_set_level(s->pic, s->irq, flags != 0);
  733 + pic_set_irq_new(s->pic, s->irq, flags != 0);
735 734 }
736 735  
737 736 static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
... ... @@ -1020,7 +1019,7 @@ static void icp_kmi_update(void *opaque, int level)
1020 1019 s->pending = level;
1021 1020 raise = (s->pending && (s->cr & 0x10) != 0)
1022 1021 || (s->cr & 0x08) != 0;
1023   - icp_pic_set_level(s->pic, s->irq, raise);
  1022 + pic_set_irq_new(s->pic, s->irq, raise);
1024 1023 }
1025 1024  
1026 1025 static uint32_t icp_kmi_read(void *opaque, target_phys_addr_t offset)
... ... @@ -1196,6 +1195,8 @@ static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device,
1196 1195 icp_control_init(0xcb000000);
1197 1196 icp_kmi_init(0x18000000, pic, 3, 0);
1198 1197 icp_kmi_init(0x19000000, pic, 4, 1);
  1198 + if (nd_table[0].vlan)
  1199 + smc91c111_init(&nd_table[0], 0xc8000000, pic, 27);
1199 1200  
1200 1201 /* Load the kernel. */
1201 1202 if (!kernel_filename) {
... ...
hw/smc91c111.c 0 โ†’ 100644
  1 +/*
  2 + * SMSC 91C111 Ethernet interface emulation
  3 + *
  4 + * Copyright (c) 2005 CodeSourcery, LLC.
  5 + * Written by Paul Brook
  6 + *
  7 + * This code is licenced under the GPL
  8 + */
  9 +
  10 +#include "vl.h"
  11 +/* For crc32 */
  12 +#include <zlib.h>
  13 +
  14 +/* Number of 2k memory pages available. */
  15 +#define NUM_PACKETS 4
  16 +
  17 +typedef struct {
  18 + uint32_t base;
  19 + VLANClientState *vc;
  20 + uint16_t tcr;
  21 + uint16_t rcr;
  22 + uint16_t cr;
  23 + uint16_t ctr;
  24 + uint16_t gpr;
  25 + uint16_t ptr;
  26 + uint16_t ercv;
  27 + void *pic;
  28 + int irq;
  29 + int bank;
  30 + int packet_num;
  31 + int tx_alloc;
  32 + /* Bitmask of allocated packets. */
  33 + int allocated;
  34 + int tx_fifo_len;
  35 + int tx_fifo[NUM_PACKETS];
  36 + int rx_fifo_len;
  37 + int rx_fifo[NUM_PACKETS];
  38 + /* Packet buffer memory. */
  39 + uint8_t data[2048][NUM_PACKETS];
  40 + uint8_t int_level;
  41 + uint8_t int_mask;
  42 + uint8_t macaddr[6];
  43 +} smc91c111_state;
  44 +
  45 +#define RCR_SOFT_RST 0x8000
  46 +#define RCR_STRIP_CRC 0x0200
  47 +#define RCR_RXEN 0x0100
  48 +
  49 +#define TCR_EPH_LOOP 0x2000
  50 +#define TCR_NOCRC 0x0100
  51 +#define TCR_PAD_EN 0x0080
  52 +#define TCR_FORCOL 0x0004
  53 +#define TCR_LOOP 0x0002
  54 +#define TCR_TXEN 0x0001
  55 +
  56 +#define INT_MD 0x80
  57 +#define INT_ERCV 0x40
  58 +#define INT_EPH 0x20
  59 +#define INT_RX_OVRN 0x10
  60 +#define INT_ALLOC 0x08
  61 +#define INT_TX_EMPTY 0x04
  62 +#define INT_TX 0x02
  63 +#define INT_RCV 0x01
  64 +
  65 +#define CTR_AUTO_RELEASE 0x0800
  66 +#define CTR_RELOAD 0x0002
  67 +#define CTR_STORE 0x0001
  68 +
  69 +#define RS_ALGNERR 0x8000
  70 +#define RS_BRODCAST 0x4000
  71 +#define RS_BADCRC 0x2000
  72 +#define RS_ODDFRAME 0x1000
  73 +#define RS_TOOLONG 0x0800
  74 +#define RS_TOOSHORT 0x0400
  75 +#define RS_MULTICAST 0x0001
  76 +
  77 +/* Update interrupt status. */
  78 +static void smc91c111_update(smc91c111_state *s)
  79 +{
  80 + int level;
  81 +
  82 + if (s->tx_fifo_len == 0)
  83 + s->int_level |= INT_TX_EMPTY;
  84 + level = (s->int_level & s->int_mask) != 0;
  85 + pic_set_irq_new(s->pic, s->irq, level);
  86 +}
  87 +
  88 +/* Try to allocate a packet. Returns 0x80 on failure. */
  89 +static int smc91c111_allocate_packet(smc91c111_state *s)
  90 +{
  91 + int i;
  92 + if (s->allocated == (1 << NUM_PACKETS) - 1) {
  93 + return 0x80;
  94 + }
  95 +
  96 + for (i = 0; i < NUM_PACKETS; i++) {
  97 + if ((s->allocated & (1 << i)) == 0)
  98 + break;
  99 + }
  100 + s->allocated |= 1 << i;
  101 + return i;
  102 +}
  103 +
  104 +
  105 +/* Process a pending TX allocate. */
  106 +static void smc91c111_tx_alloc(smc91c111_state *s)
  107 +{
  108 + s->tx_alloc = smc91c111_allocate_packet(s);
  109 + if (s->tx_alloc == 0x80)
  110 + return;
  111 + s->int_level |= INT_ALLOC;
  112 + smc91c111_update(s);
  113 +}
  114 +
  115 +/* Remove and item from the RX FIFO. */
  116 +static void smc91c111_pop_rx_fifo(smc91c111_state *s)
  117 +{
  118 + int i;
  119 +
  120 + s->rx_fifo_len--;
  121 + if (s->rx_fifo_len) {
  122 + for (i = 0; i < s->rx_fifo_len; i++)
  123 + s->rx_fifo[i] = s->rx_fifo[i + 1];
  124 + s->int_level |= INT_RCV;
  125 + } else {
  126 + s->int_level &= ~INT_RCV;
  127 + }
  128 + smc91c111_update(s);
  129 +}
  130 +
  131 +/* Release the memory allocated to a packet. */
  132 +static void smc91c111_release_packet(smc91c111_state *s, int packet)
  133 +{
  134 + s->allocated &= ~(1 << packet);
  135 + if (s->tx_alloc == 0x80)
  136 + smc91c111_tx_alloc(s);
  137 +}
  138 +
  139 +/* Flush the TX FIFO. */
  140 +static void smc91c111_do_tx(smc91c111_state *s)
  141 +{
  142 + int i;
  143 + int len;
  144 + int control;
  145 + int add_crc;
  146 + uint32_t crc;
  147 + int packetnum;
  148 + uint8_t *p;
  149 +
  150 + if ((s->tcr & TCR_TXEN) == 0)
  151 + return;
  152 + if (s->tx_fifo_len == 0)
  153 + return;
  154 + for (i = 0; i < s->tx_fifo_len; i++) {
  155 + packetnum = s->tx_fifo[i];
  156 + p = &s->data[packetnum][0];
  157 + /* Set status word. */
  158 + *(p++) = 0x01;
  159 + *(p++) = 0x40;
  160 + len = *(p++);
  161 + len |= ((int)*(p++)) << 8;
  162 + len -= 6;
  163 + control = p[len + 1];
  164 + if (control & 0x20)
  165 + len++;
  166 + /* ??? This overwrites the data following the buffer.
  167 + Don't know what real hardware does. */
  168 + if (len < 64 && (s->tcr & TCR_PAD_EN)) {
  169 + memset(p + len, 0, 64 - len);
  170 + len = 64;
  171 + }
  172 +#if 0
  173 + /* The card is supposed to append the CRC to the frame. However
  174 + none of the other network traffic has the CRC appended.
  175 + Suspect this is low level ethernet detail we don't need to worry
  176 + about. */
  177 + add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
  178 + if (add_crc) {
  179 + crc = crc32(~0, p, len);
  180 + memcpy(p + len, &crc, 4);
  181 + len += 4;
  182 + }
  183 +#else
  184 + add_crc = 0;
  185 +#endif
  186 + if (s->ctr & CTR_AUTO_RELEASE)
  187 + smc91c111_release_packet(s, packetnum);
  188 + qemu_send_packet(s->vc, p, len);
  189 + }
  190 + s->tx_fifo_len = 0;
  191 + if ((s->ctr & CTR_AUTO_RELEASE) == 0)
  192 + s->int_level |= INT_TX;
  193 + smc91c111_update(s);
  194 +}
  195 +
  196 +/* Add a packet to the TX FIFO. */
  197 +static void smc91c111_queue_tx(smc91c111_state *s, int packet)
  198 +{
  199 + if (s->tx_fifo_len == NUM_PACKETS)
  200 + return;
  201 + s->tx_fifo[s->tx_fifo_len++] = packet;
  202 + smc91c111_do_tx(s);
  203 +}
  204 +
  205 +static void smc91c111_reset(smc91c111_state *s)
  206 +{
  207 + s->bank = 0;
  208 + s->tx_fifo_len = 0;
  209 + s->rx_fifo_len = 0;
  210 + s->allocated = 0;
  211 + s->packet_num = 0;
  212 + s->tx_alloc = 0;
  213 + s->tcr = 0;
  214 + s->rcr = 0;
  215 + s->cr = 0xa0b1;
  216 + s->ctr = 0x1210;
  217 + s->ptr = 0;
  218 + s->ercv = 0x1f;
  219 + s->int_level = INT_TX_EMPTY;
  220 + s->int_mask = 0;
  221 + smc91c111_update(s);
  222 +}
  223 +
  224 +#define SET_LOW(name, val) s->name = (s->name & 0xff00) | val
  225 +#define SET_HIGH(name, val) s->name = (s->name & 0xff) | (val << 8)
  226 +
  227 +static void smc91c111_writeb(void *opaque, target_phys_addr_t offset,
  228 + uint32_t value)
  229 +{
  230 + smc91c111_state *s = (smc91c111_state *)opaque;
  231 +
  232 + offset -= s->base;
  233 + if (offset == 14) {
  234 + s->bank = value;
  235 + return;
  236 + }
  237 + if (offset == 15)
  238 + return;
  239 + switch (s->bank) {
  240 + case 0:
  241 + switch (offset) {
  242 + case 0: /* TCR */
  243 + SET_LOW(tcr, value);
  244 + return;
  245 + case 1:
  246 + SET_HIGH(tcr, value);
  247 + return;
  248 + case 4: /* RCR */
  249 + SET_LOW(rcr, value);
  250 + return;
  251 + case 5:
  252 + SET_HIGH(rcr, value);
  253 + if (s->rcr & RCR_SOFT_RST)
  254 + smc91c111_reset(s);
  255 + return;
  256 + case 10: case 11: /* RPCR */
  257 + /* Ignored */
  258 + return;
  259 + }
  260 + break;
  261 +
  262 + case 1:
  263 + switch (offset) {
  264 + case 0: /* CONFIG */
  265 + SET_LOW(cr, value);
  266 + return;
  267 + case 1:
  268 + SET_HIGH(cr,value);
  269 + return;
  270 + case 2: case 3: /* BASE */
  271 + case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
  272 + /* Not implemented. */
  273 + return;
  274 + case 10: /* Genral Purpose */
  275 + SET_LOW(gpr, value);
  276 + return;
  277 + case 11:
  278 + SET_HIGH(gpr, value);
  279 + return;
  280 + case 12: /* Control */
  281 + if (value & 1)
  282 + fprintf(stderr, "smc91c111:EEPROM store not implemented\n");
  283 + if (value & 2)
  284 + fprintf(stderr, "smc91c111:EEPROM reload not implemented\n");
  285 + value &= ~3;
  286 + SET_LOW(ctr, value);
  287 + return;
  288 + case 13:
  289 + SET_HIGH(ctr, value);
  290 + return;
  291 + }
  292 + break;
  293 +
  294 + case 2:
  295 + switch (offset) {
  296 + case 0: /* MMU Command */
  297 + switch (value >> 5) {
  298 + case 0: /* no-op */
  299 + break;
  300 + case 1: /* Allocate for TX. */
  301 + s->tx_alloc = 0x80;
  302 + s->int_level &= ~INT_ALLOC;
  303 + smc91c111_update(s);
  304 + smc91c111_tx_alloc(s);
  305 + break;
  306 + case 2: /* Reset MMU. */
  307 + s->allocated = 0;
  308 + s->tx_fifo_len = 0;
  309 + s->rx_fifo_len = 0;
  310 + s->tx_alloc = 0;
  311 + break;
  312 + case 3: /* Remove from RX FIFO. */
  313 + smc91c111_pop_rx_fifo(s);
  314 + break;
  315 + case 4: /* Remove from RX FIFO and release. */
  316 + if (s->rx_fifo_len > 0) {
  317 + smc91c111_release_packet(s, s->rx_fifo[0]);
  318 + }
  319 + smc91c111_pop_rx_fifo(s);
  320 + break;
  321 + case 5: /* Release. */
  322 + smc91c111_release_packet(s, s->packet_num);
  323 + break;
  324 + case 6: /* Add to TX FIFO. */
  325 + smc91c111_queue_tx(s, s->packet_num);
  326 + break;
  327 + case 7: /* Reset TX FIFO. */
  328 + s->tx_fifo_len = 0;
  329 + break;
  330 + }
  331 + return;
  332 + case 1:
  333 + /* Ignore. */
  334 + return;
  335 + case 2: /* Packet Number Register */
  336 + s->packet_num = value;
  337 + return;
  338 + case 3: case 4: case 5:
  339 + /* Should be readonly, but linux writes to them anyway. Ignore. */
  340 + return;
  341 + case 6: /* Pointer */
  342 + SET_LOW(ptr, value);
  343 + return;
  344 + case 7:
  345 + SET_HIGH(ptr, value);
  346 + return;
  347 + case 8: case 9: case 10: case 11: /* Data */
  348 + {
  349 + int p;
  350 + int n;
  351 +
  352 + if (s->ptr & 0x8000)
  353 + n = s->rx_fifo[0];
  354 + else
  355 + n = s->packet_num;
  356 + p = s->ptr & 0x07ff;
  357 + if (s->ptr & 0x4000) {
  358 + s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x7ff);
  359 + } else {
  360 + p += (offset & 3);
  361 + }
  362 + s->data[n][p] = value;
  363 + }
  364 + return;
  365 + case 12: /* Interrupt ACK. */
  366 + s->int_level &= ~(value & 0xd6);
  367 + smc91c111_update(s);
  368 + return;
  369 + case 13: /* Interrupt mask. */
  370 + s->int_mask = value;
  371 + smc91c111_update(s);
  372 + return;
  373 + }
  374 + break;;
  375 +
  376 + case 3:
  377 + switch (offset) {
  378 + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
  379 + /* Multicast table. */
  380 + /* Not implemented. */
  381 + return;
  382 + case 8: case 9: /* Management Interface. */
  383 + /* Not implemented. */
  384 + return;
  385 + case 12: /* Early receive. */
  386 + s->ercv = value & 0x1f;
  387 + case 13:
  388 + /* Ignore. */
  389 + return;
  390 + }
  391 + break;
  392 + }
  393 + cpu_abort (cpu_single_env, "smc91c111_write: Bad reg %d:%x\n",
  394 + s->bank, offset);
  395 +}
  396 +
  397 +static uint32_t smc91c111_readb(void *opaque, target_phys_addr_t offset)
  398 +{
  399 + smc91c111_state *s = (smc91c111_state *)opaque;
  400 +
  401 + offset -= s->base;
  402 + if (offset == 14) {
  403 + return s->bank;
  404 + }
  405 + if (offset == 15)
  406 + return 0x33;
  407 + switch (s->bank) {
  408 + case 0:
  409 + switch (offset) {
  410 + case 0: /* TCR */
  411 + return s->tcr & 0xff;
  412 + case 1:
  413 + return s->tcr >> 8;
  414 + case 2: /* EPH Status */
  415 + return 0;
  416 + case 3:
  417 + return 0x40;
  418 + case 4: /* RCR */
  419 + return s->rcr & 0xff;
  420 + case 5:
  421 + return s->rcr >> 8;
  422 + case 6: /* Counter */
  423 + case 7:
  424 + /* Not implemented. */
  425 + return 0;
  426 + case 8: /* Free memory available. */
  427 + {
  428 + int i;
  429 + int n;
  430 + n = 0;
  431 + for (i = 0; i < NUM_PACKETS; i++) {
  432 + if (s->allocated & (1 << i))
  433 + n++;
  434 + }
  435 + return n;
  436 + }
  437 + case 9: /* Memory size. */
  438 + return NUM_PACKETS;
  439 + case 10: case 11: /* RPCR */
  440 + /* Not implemented. */
  441 + return 0;
  442 + }
  443 + break;
  444 +
  445 + case 1:
  446 + switch (offset) {
  447 + case 0: /* CONFIG */
  448 + return s->cr & 0xff;
  449 + case 1:
  450 + return s->cr >> 8;
  451 + case 2: case 3: /* BASE */
  452 + /* Not implemented. */
  453 + return 0;
  454 + case 4: case 5: case 6: case 7: case 8: case 9: /* IA */
  455 + return s->macaddr[offset - 4];
  456 + case 10: /* General Purpose */
  457 + return s->gpr & 0xff;
  458 + case 11:
  459 + return s->gpr >> 8;
  460 + case 12: /* Control */
  461 + return s->ctr & 0xff;
  462 + case 13:
  463 + return s->ctr >> 8;
  464 + }
  465 + break;
  466 +
  467 + case 2:
  468 + switch (offset) {
  469 + case 0: case 1: /* MMUCR Busy bit. */
  470 + return 0;
  471 + case 2: /* Packet Number. */
  472 + return s->packet_num;
  473 + case 3: /* Allocation Result. */
  474 + return s->tx_alloc;
  475 + case 4: /* TX FIFO */
  476 + if (s->tx_fifo_len == 0)
  477 + return 0x80;
  478 + else
  479 + return s->tx_fifo[0];
  480 + case 5: /* RX FIFO */
  481 + if (s->rx_fifo_len == 0)
  482 + return 0x80;
  483 + else
  484 + return s->rx_fifo[0];
  485 + case 6: /* Pointer */
  486 + return s->ptr & 0xff;
  487 + case 7:
  488 + return (s->ptr >> 8) & 0xf7;
  489 + case 8: case 9: case 10: case 11: /* Data */
  490 + {
  491 + int p;
  492 + int n;
  493 +
  494 + if (s->ptr & 0x8000)
  495 + n = s->rx_fifo[0];
  496 + else
  497 + n = s->packet_num;
  498 + p = s->ptr & 0x07ff;
  499 + if (s->ptr & 0x4000) {
  500 + s->ptr = (s->ptr & 0xf800) | ((s->ptr + 1) & 0x07ff);
  501 + } else {
  502 + p += (offset & 3);
  503 + }
  504 + return s->data[n][p];
  505 + }
  506 + case 12: /* Interrupt status. */
  507 + return s->int_level;
  508 + case 13: /* Interrupt mask. */
  509 + return s->int_mask;
  510 + }
  511 + break;
  512 +
  513 + case 3:
  514 + switch (offset) {
  515 + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
  516 + /* Multicast table. */
  517 + /* Not implemented. */
  518 + return 0;
  519 + case 8: /* Management Interface. */
  520 + /* Not implemented. */
  521 + return 0x30;
  522 + case 9:
  523 + return 0x33;
  524 + case 10: /* Revision. */
  525 + return 0x91;
  526 + case 11:
  527 + return 0x33;
  528 + case 12:
  529 + return s->ercv;
  530 + case 13:
  531 + return 0;
  532 + }
  533 + break;
  534 + }
  535 + cpu_abort (cpu_single_env, "smc91c111_read: Bad reg %d:%x\n",
  536 + s->bank, offset);
  537 + return 0;
  538 +}
  539 +
  540 +static void smc91c111_writew(void *opaque, target_phys_addr_t offset,
  541 + uint32_t value)
  542 +{
  543 + smc91c111_writeb(opaque, offset, value & 0xff);
  544 + smc91c111_writeb(opaque, offset + 1, value >> 8);
  545 +}
  546 +
  547 +static void smc91c111_writel(void *opaque, target_phys_addr_t offset,
  548 + uint32_t value)
  549 +{
  550 + smc91c111_state *s = (smc91c111_state *)opaque;
  551 + /* 32-bit writes to offset 0xc only actually write to the bank select
  552 + register (offset 0xe) */
  553 + if (offset != s->base + 0xc)
  554 + smc91c111_writew(opaque, offset, value & 0xffff);
  555 + smc91c111_writew(opaque, offset + 2, value >> 16);
  556 +}
  557 +
  558 +static uint32_t smc91c111_readw(void *opaque, target_phys_addr_t offset)
  559 +{
  560 + uint32_t val;
  561 + val = smc91c111_readb(opaque, offset);
  562 + val |= smc91c111_readb(opaque, offset + 1) << 8;
  563 + return val;
  564 +}
  565 +
  566 +static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset)
  567 +{
  568 + uint32_t val;
  569 + val = smc91c111_readw(opaque, offset);
  570 + val |= smc91c111_readw(opaque, offset + 2) << 16;
  571 + return val;
  572 +}
  573 +
  574 +static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
  575 +{
  576 + smc91c111_state *s = (smc91c111_state *)opaque;
  577 + int status;
  578 + int packetsize;
  579 + uint32_t crc;
  580 + int packetnum;
  581 + uint8_t *p;
  582 +
  583 + if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
  584 + return;
  585 + /* Short packets are padded with zeros. Recieveing a packet
  586 + < 64 bytes long is considered an error condition. */
  587 + if (size < 64)
  588 + packetsize = 64;
  589 + else
  590 + packetsize = (size & ~1);
  591 + packetsize += 6;
  592 + crc = (s->rcr & RCR_STRIP_CRC) == 0;
  593 + if (crc)
  594 + packetsize += 4;
  595 + /* TODO: Flag overrun and receive errors. */
  596 + if (packetsize > 2048)
  597 + return;
  598 + packetnum = smc91c111_allocate_packet(s);
  599 + if (packetnum == 0x80)
  600 + return;
  601 + s->rx_fifo[s->rx_fifo_len++] = packetnum;
  602 +
  603 + p = &s->data[packetnum][0];
  604 + /* ??? Multicast packets? */
  605 + status = 0;
  606 + if (size > 1518)
  607 + status |= RS_TOOLONG;
  608 + if (size & 1)
  609 + status |= RS_ODDFRAME;
  610 + *(p++) = status & 0xff;
  611 + *(p++) = status >> 8;
  612 + *(p++) = packetsize & 0xff;
  613 + *(p++) = packetsize >> 8;
  614 + memcpy(p, buf, size & ~1);
  615 + p += (size & ~1);
  616 + /* Pad short packets. */
  617 + if (size < 64) {
  618 + int pad;
  619 +
  620 + if (size & 1)
  621 + *(p++) = buf[size - 1];
  622 + pad = 64 - size;
  623 + memset(p, 0, pad);
  624 + p += pad;
  625 + size = 64;
  626 + }
  627 + /* It's not clear if the CRC should go before or after the last byte in
  628 + odd sized packets. Linux disables the CRC, so that's no help.
  629 + The pictures in the documentation show the CRC aligned on a 16-bit
  630 + boundary before the last odd byte, so that's what we do. */
  631 + if (crc) {
  632 + crc = crc32(~0, buf, size);
  633 + *(p++) = crc & 0xff; crc >>= 8;
  634 + *(p++) = crc & 0xff; crc >>= 8;
  635 + *(p++) = crc & 0xff; crc >>= 8;
  636 + *(p++) = crc & 0xff; crc >>= 8;
  637 + }
  638 + if (size & 1) {
  639 + *(p++) = buf[size - 1];
  640 + *(p++) = 0x60;
  641 + } else {
  642 + *(p++) = 0;
  643 + *(p++) = 0x40;
  644 + }
  645 + /* TODO: Raise early RX interrupt? */
  646 + s->int_level |= INT_RCV;
  647 + smc91c111_update(s);
  648 +}
  649 +
  650 +static CPUReadMemoryFunc *smc91c111_readfn[] = {
  651 + smc91c111_readb,
  652 + smc91c111_readw,
  653 + smc91c111_readl
  654 +};
  655 +
  656 +static CPUWriteMemoryFunc *smc91c111_writefn[] = {
  657 + smc91c111_writeb,
  658 + smc91c111_writew,
  659 + smc91c111_writel
  660 +};
  661 +
  662 +void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq)
  663 +{
  664 + smc91c111_state *s;
  665 + int iomemtype;
  666 +
  667 + s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state));
  668 + iomemtype = cpu_register_io_memory(0, smc91c111_readfn,
  669 + smc91c111_writefn, s);
  670 + cpu_register_physical_memory(base, 16, iomemtype);
  671 + s->base = base;
  672 + s->pic = pic;
  673 + s->irq = irq;
  674 + memcpy(s->macaddr, nd->macaddr, 6);
  675 +
  676 + smc91c111_reset(s);
  677 +
  678 + s->vc = qemu_new_vlan_client(nd->vlan, smc91c111_receive, s);
  679 + /* ??? Save/restore. */
  680 +}
... ...
... ... @@ -939,6 +939,9 @@ void ps2_write_keyboard(void *, int val);
939 939 uint32_t ps2_read_data(void *);
940 940 void ps2_queue(void *, int b);
941 941  
  942 +/* smc91c111.c */
  943 +void smc91c111_init(NICInfo *, uint32_t, void *, int);
  944 +
942 945 #endif /* defined(QEMU_TOOL) */
943 946  
944 947 /* monitor.c */
... ...