symbian-qemu-0.9.1-12/qemu-symbian-svp/hw/mcf_fec.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * ColdFire Fast Ethernet Controller emulation.
       
     3  *
       
     4  * Copyright (c) 2007 CodeSourcery.
       
     5  *
       
     6  * This code is licenced under the GPL
       
     7  */
       
     8 #include "hw.h"
       
     9 #include "net.h"
       
    10 #include "mcf.h"
       
    11 /* For crc32 */
       
    12 #include <zlib.h>
       
    13 
       
    14 //#define DEBUG_FEC 1
       
    15 
       
    16 #ifdef DEBUG_FEC
       
    17 #define DPRINTF(fmt, args...) \
       
    18 do { printf("mcf_fec: " fmt , ##args); } while (0)
       
    19 #else
       
    20 #define DPRINTF(fmt, args...) do {} while(0)
       
    21 #endif
       
    22 
       
    23 #define FEC_MAX_FRAME_SIZE 2032
       
    24 
       
    25 typedef struct {
       
    26     qemu_irq *irq;
       
    27     VLANClientState *vc;
       
    28     uint32_t irq_state;
       
    29     uint32_t eir;
       
    30     uint32_t eimr;
       
    31     int rx_enabled;
       
    32     uint32_t rx_descriptor;
       
    33     uint32_t tx_descriptor;
       
    34     uint32_t ecr;
       
    35     uint32_t mmfr;
       
    36     uint32_t mscr;
       
    37     uint32_t rcr;
       
    38     uint32_t tcr;
       
    39     uint32_t tfwr;
       
    40     uint32_t rfsr;
       
    41     uint32_t erdsr;
       
    42     uint32_t etdsr;
       
    43     uint32_t emrbr;
       
    44     uint8_t macaddr[6];
       
    45 } mcf_fec_state;
       
    46 
       
    47 #define FEC_INT_HB   0x80000000
       
    48 #define FEC_INT_BABR 0x40000000
       
    49 #define FEC_INT_BABT 0x20000000
       
    50 #define FEC_INT_GRA  0x10000000
       
    51 #define FEC_INT_TXF  0x08000000
       
    52 #define FEC_INT_TXB  0x04000000
       
    53 #define FEC_INT_RXF  0x02000000
       
    54 #define FEC_INT_RXB  0x01000000
       
    55 #define FEC_INT_MII  0x00800000
       
    56 #define FEC_INT_EB   0x00400000
       
    57 #define FEC_INT_LC   0x00200000
       
    58 #define FEC_INT_RL   0x00100000
       
    59 #define FEC_INT_UN   0x00080000
       
    60 
       
    61 #define FEC_EN      2
       
    62 #define FEC_RESET   1
       
    63 
       
    64 /* Map interrupt flags onto IRQ lines.  */
       
    65 #define FEC_NUM_IRQ 13
       
    66 static const uint32_t mcf_fec_irq_map[FEC_NUM_IRQ] = {
       
    67     FEC_INT_TXF,
       
    68     FEC_INT_TXB,
       
    69     FEC_INT_UN,
       
    70     FEC_INT_RL,
       
    71     FEC_INT_RXF,
       
    72     FEC_INT_RXB,
       
    73     FEC_INT_MII,
       
    74     FEC_INT_LC,
       
    75     FEC_INT_HB,
       
    76     FEC_INT_GRA,
       
    77     FEC_INT_EB,
       
    78     FEC_INT_BABT,
       
    79     FEC_INT_BABR
       
    80 };
       
    81 
       
    82 /* Buffer Descriptor.  */
       
    83 typedef struct {
       
    84     uint16_t flags;
       
    85     uint16_t length;
       
    86     uint32_t data;
       
    87 } mcf_fec_bd;
       
    88 
       
    89 #define FEC_BD_R    0x8000
       
    90 #define FEC_BD_E    0x8000
       
    91 #define FEC_BD_O1   0x4000
       
    92 #define FEC_BD_W    0x2000
       
    93 #define FEC_BD_O2   0x1000
       
    94 #define FEC_BD_L    0x0800
       
    95 #define FEC_BD_TC   0x0400
       
    96 #define FEC_BD_ABC  0x0200
       
    97 #define FEC_BD_M    0x0100
       
    98 #define FEC_BD_BC   0x0080
       
    99 #define FEC_BD_MC   0x0040
       
   100 #define FEC_BD_LG   0x0020
       
   101 #define FEC_BD_NO   0x0010
       
   102 #define FEC_BD_CR   0x0004
       
   103 #define FEC_BD_OV   0x0002
       
   104 #define FEC_BD_TR   0x0001
       
   105 
       
   106 static void mcf_fec_read_bd(mcf_fec_bd *bd, uint32_t addr)
       
   107 {
       
   108     cpu_physical_memory_read(addr, (uint8_t *)bd, sizeof(*bd));
       
   109     be16_to_cpus(&bd->flags);
       
   110     be16_to_cpus(&bd->length);
       
   111     be32_to_cpus(&bd->data);
       
   112 }
       
   113 
       
   114 static void mcf_fec_write_bd(mcf_fec_bd *bd, uint32_t addr)
       
   115 {
       
   116     mcf_fec_bd tmp;
       
   117     tmp.flags = cpu_to_be16(bd->flags);
       
   118     tmp.length = cpu_to_be16(bd->length);
       
   119     tmp.data = cpu_to_be32(bd->data);
       
   120     cpu_physical_memory_write(addr, (uint8_t *)&tmp, sizeof(tmp));
       
   121 }
       
   122 
       
   123 static void mcf_fec_update(mcf_fec_state *s)
       
   124 {
       
   125     uint32_t active;
       
   126     uint32_t changed;
       
   127     uint32_t mask;
       
   128     int i;
       
   129 
       
   130     active = s->eir & s->eimr;
       
   131     changed = active ^s->irq_state;
       
   132     for (i = 0; i < FEC_NUM_IRQ; i++) {
       
   133         mask = mcf_fec_irq_map[i];
       
   134         if (changed & mask) {
       
   135             DPRINTF("IRQ %d = %d\n", i, (active & mask) != 0);
       
   136             qemu_set_irq(s->irq[i], (active & mask) != 0);
       
   137         }
       
   138     }
       
   139     s->irq_state = active;
       
   140 }
       
   141 
       
   142 static void mcf_fec_do_tx(mcf_fec_state *s)
       
   143 {
       
   144     uint32_t addr;
       
   145     mcf_fec_bd bd;
       
   146     int frame_size;
       
   147     int len;
       
   148     uint8_t frame[FEC_MAX_FRAME_SIZE];
       
   149     uint8_t *ptr;
       
   150 
       
   151     DPRINTF("do_tx\n");
       
   152     ptr = frame;
       
   153     frame_size = 0;
       
   154     addr = s->tx_descriptor;
       
   155     while (1) {
       
   156         mcf_fec_read_bd(&bd, addr);
       
   157         DPRINTF("tx_bd %x flags %04x len %d data %08x\n",
       
   158                 addr, bd.flags, bd.length, bd.data);
       
   159         if ((bd.flags & FEC_BD_R) == 0) {
       
   160             /* Run out of descriptors to transmit.  */
       
   161             break;
       
   162         }
       
   163         len = bd.length;
       
   164         if (frame_size + len > FEC_MAX_FRAME_SIZE) {
       
   165             len = FEC_MAX_FRAME_SIZE - frame_size;
       
   166             s->eir |= FEC_INT_BABT;
       
   167         }
       
   168         cpu_physical_memory_read(bd.data, ptr, len);
       
   169         ptr += len;
       
   170         frame_size += len;
       
   171         if (bd.flags & FEC_BD_L) {
       
   172             /* Last buffer in frame.  */
       
   173             DPRINTF("Sending packet\n");
       
   174             qemu_send_packet(s->vc, frame, len);
       
   175             ptr = frame;
       
   176             frame_size = 0;
       
   177             s->eir |= FEC_INT_TXF;
       
   178         }
       
   179         s->eir |= FEC_INT_TXB;
       
   180         bd.flags &= ~FEC_BD_R;
       
   181         /* Write back the modified descriptor.  */
       
   182         mcf_fec_write_bd(&bd, addr);
       
   183         /* Advance to the next descriptor.  */
       
   184         if ((bd.flags & FEC_BD_W) != 0) {
       
   185             addr = s->etdsr;
       
   186         } else {
       
   187             addr += 8;
       
   188         }
       
   189     }
       
   190     s->tx_descriptor = addr;
       
   191 }
       
   192 
       
   193 static void mcf_fec_enable_rx(mcf_fec_state *s)
       
   194 {
       
   195     mcf_fec_bd bd;
       
   196 
       
   197     mcf_fec_read_bd(&bd, s->rx_descriptor);
       
   198     s->rx_enabled = ((bd.flags & FEC_BD_E) != 0);
       
   199     if (!s->rx_enabled)
       
   200         DPRINTF("RX buffer full\n");
       
   201 }
       
   202 
       
   203 static void mcf_fec_reset(mcf_fec_state *s)
       
   204 {
       
   205     s->eir = 0;
       
   206     s->eimr = 0;
       
   207     s->rx_enabled = 0;
       
   208     s->ecr = 0;
       
   209     s->mscr = 0;
       
   210     s->rcr = 0x05ee0001;
       
   211     s->tcr = 0;
       
   212     s->tfwr = 0;
       
   213     s->rfsr = 0x500;
       
   214 }
       
   215 
       
   216 static uint32_t mcf_fec_read(void *opaque, target_phys_addr_t addr)
       
   217 {
       
   218     mcf_fec_state *s = (mcf_fec_state *)opaque;
       
   219     switch (addr & 0x3ff) {
       
   220     case 0x004: return s->eir;
       
   221     case 0x008: return s->eimr;
       
   222     case 0x010: return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
       
   223     case 0x014: return 0; /* TDAR */
       
   224     case 0x024: return s->ecr;
       
   225     case 0x040: return s->mmfr;
       
   226     case 0x044: return s->mscr;
       
   227     case 0x064: return 0; /* MIBC */
       
   228     case 0x084: return s->rcr;
       
   229     case 0x0c4: return s->tcr;
       
   230     case 0x0e4: /* PALR */
       
   231         return (s->macaddr[0] << 24) | (s->macaddr[1] << 16)
       
   232               | (s->macaddr[2] << 8) | s->macaddr[3];
       
   233         break;
       
   234     case 0x0e8: /* PAUR */
       
   235         return (s->macaddr[4] << 24) | (s->macaddr[5] << 16) | 0x8808;
       
   236     case 0x0ec: return 0x10000; /* OPD */
       
   237     case 0x118: return 0;
       
   238     case 0x11c: return 0;
       
   239     case 0x120: return 0;
       
   240     case 0x124: return 0;
       
   241     case 0x144: return s->tfwr;
       
   242     case 0x14c: return 0x600;
       
   243     case 0x150: return s->rfsr;
       
   244     case 0x180: return s->erdsr;
       
   245     case 0x184: return s->etdsr;
       
   246     case 0x188: return s->emrbr;
       
   247     default:
       
   248         cpu_abort(cpu_single_env, "mcf_fec_read: Bad address 0x%x\n",
       
   249                   (int)addr);
       
   250         return 0;
       
   251     }
       
   252 }
       
   253 
       
   254 static void mcf_fec_write(void *opaque, target_phys_addr_t addr, uint32_t value)
       
   255 {
       
   256     mcf_fec_state *s = (mcf_fec_state *)opaque;
       
   257     switch (addr & 0x3ff) {
       
   258     case 0x004:
       
   259         s->eir &= ~value;
       
   260         break;
       
   261     case 0x008:
       
   262         s->eimr = value;
       
   263         break;
       
   264     case 0x010: /* RDAR */
       
   265         if ((s->ecr & FEC_EN) && !s->rx_enabled) {
       
   266             DPRINTF("RX enable\n");
       
   267             mcf_fec_enable_rx(s);
       
   268         }
       
   269         break;
       
   270     case 0x014: /* TDAR */
       
   271         if (s->ecr & FEC_EN) {
       
   272             mcf_fec_do_tx(s);
       
   273         }
       
   274         break;
       
   275     case 0x024:
       
   276         s->ecr = value;
       
   277         if (value & FEC_RESET) {
       
   278             DPRINTF("Reset\n");
       
   279             mcf_fec_reset(s);
       
   280         }
       
   281         if ((s->ecr & FEC_EN) == 0) {
       
   282             s->rx_enabled = 0;
       
   283         }
       
   284         break;
       
   285     case 0x040:
       
   286         /* TODO: Implement MII.  */
       
   287         s->mmfr = value;
       
   288         break;
       
   289     case 0x044:
       
   290         s->mscr = value & 0xfe;
       
   291         break;
       
   292     case 0x064:
       
   293         /* TODO: Implement MIB.  */
       
   294         break;
       
   295     case 0x084:
       
   296         s->rcr = value & 0x07ff003f;
       
   297         /* TODO: Implement LOOP mode.  */
       
   298         break;
       
   299     case 0x0c4: /* TCR */
       
   300         /* We transmit immediately, so raise GRA immediately.  */
       
   301         s->tcr = value;
       
   302         if (value & 1)
       
   303             s->eir |= FEC_INT_GRA;
       
   304         break;
       
   305     case 0x0e4: /* PALR */
       
   306         s->macaddr[0] = value >> 24;
       
   307         s->macaddr[1] = value >> 16;
       
   308         s->macaddr[2] = value >> 8;
       
   309         s->macaddr[3] = value;
       
   310         break;
       
   311     case 0x0e8: /* PAUR */
       
   312         s->macaddr[4] = value >> 24;
       
   313         s->macaddr[5] = value >> 16;
       
   314         break;
       
   315     case 0x0ec:
       
   316         /* OPD */
       
   317         break;
       
   318     case 0x118:
       
   319     case 0x11c:
       
   320     case 0x120:
       
   321     case 0x124:
       
   322         /* TODO: implement MAC hash filtering.  */
       
   323         break;
       
   324     case 0x144:
       
   325         s->tfwr = value & 3;
       
   326         break;
       
   327     case 0x14c:
       
   328         /* FRBR writes ignored.  */
       
   329         break;
       
   330     case 0x150:
       
   331         s->rfsr = (value & 0x3fc) | 0x400;
       
   332         break;
       
   333     case 0x180:
       
   334         s->erdsr = value & ~3;
       
   335         s->rx_descriptor = s->erdsr;
       
   336         break;
       
   337     case 0x184:
       
   338         s->etdsr = value & ~3;
       
   339         s->tx_descriptor = s->etdsr;
       
   340         break;
       
   341     case 0x188:
       
   342         s->emrbr = value & 0x7f0;
       
   343         break;
       
   344     default:
       
   345         cpu_abort(cpu_single_env, "mcf_fec_write Bad address 0x%x\n",
       
   346                   (int)addr);
       
   347     }
       
   348     mcf_fec_update(s);
       
   349 }
       
   350 
       
   351 static int mcf_fec_can_receive(void *opaque)
       
   352 {
       
   353     mcf_fec_state *s = (mcf_fec_state *)opaque;
       
   354     return s->rx_enabled;
       
   355 }
       
   356 
       
   357 static void mcf_fec_receive(void *opaque, const uint8_t *buf, int size)
       
   358 {
       
   359     mcf_fec_state *s = (mcf_fec_state *)opaque;
       
   360     mcf_fec_bd bd;
       
   361     uint32_t flags = 0;
       
   362     uint32_t addr;
       
   363     uint32_t crc;
       
   364     uint32_t buf_addr;
       
   365     uint8_t *crc_ptr;
       
   366     unsigned int buf_len;
       
   367 
       
   368     DPRINTF("do_rx len %d\n", size);
       
   369     if (!s->rx_enabled) {
       
   370         fprintf(stderr, "mcf_fec_receive: Unexpected packet\n");
       
   371     }
       
   372     /* 4 bytes for the CRC.  */
       
   373     size += 4;
       
   374     crc = cpu_to_be32(crc32(~0, buf, size));
       
   375     crc_ptr = (uint8_t *)&crc;
       
   376     /* Huge frames are truncted.  */
       
   377     if (size > FEC_MAX_FRAME_SIZE) {
       
   378         size = FEC_MAX_FRAME_SIZE;
       
   379         flags |= FEC_BD_TR | FEC_BD_LG;
       
   380     }
       
   381     /* Frames larger than the user limit just set error flags.  */
       
   382     if (size > (s->rcr >> 16)) {
       
   383         flags |= FEC_BD_LG;
       
   384     }
       
   385     addr = s->rx_descriptor;
       
   386     while (size > 0) {
       
   387         mcf_fec_read_bd(&bd, addr);
       
   388         if ((bd.flags & FEC_BD_E) == 0) {
       
   389             /* No descriptors available.  Bail out.  */
       
   390             /* FIXME: This is wrong.  We should probably either save the
       
   391                remainder for when more RX buffers are available, or
       
   392                flag an error.  */
       
   393             fprintf(stderr, "mcf_fec: Lost end of frame\n");
       
   394             break;
       
   395         }
       
   396         buf_len = (size <= s->emrbr) ? size: s->emrbr;
       
   397         bd.length = buf_len;
       
   398         size -= buf_len;
       
   399         DPRINTF("rx_bd %x length %d\n", addr, bd.length);
       
   400         /* The last 4 bytes are the CRC.  */
       
   401         if (size < 4)
       
   402             buf_len += size - 4;
       
   403         buf_addr = bd.data;
       
   404         cpu_physical_memory_write(buf_addr, buf, buf_len);
       
   405         buf += buf_len;
       
   406         if (size < 4) {
       
   407             cpu_physical_memory_write(buf_addr + buf_len, crc_ptr, 4 - size);
       
   408             crc_ptr += 4 - size;
       
   409         }
       
   410         bd.flags &= ~FEC_BD_E;
       
   411         if (size == 0) {
       
   412             /* Last buffer in frame.  */
       
   413             bd.flags |= flags | FEC_BD_L;
       
   414             DPRINTF("rx frame flags %04x\n", bd.flags);
       
   415             s->eir |= FEC_INT_RXF;
       
   416         } else {
       
   417             s->eir |= FEC_INT_RXB;
       
   418         }
       
   419         mcf_fec_write_bd(&bd, addr);
       
   420         /* Advance to the next descriptor.  */
       
   421         if ((bd.flags & FEC_BD_W) != 0) {
       
   422             addr = s->erdsr;
       
   423         } else {
       
   424             addr += 8;
       
   425         }
       
   426     }
       
   427     s->rx_descriptor = addr;
       
   428     mcf_fec_enable_rx(s);
       
   429     mcf_fec_update(s);
       
   430 }
       
   431 
       
   432 static CPUReadMemoryFunc *mcf_fec_readfn[] = {
       
   433    mcf_fec_read,
       
   434    mcf_fec_read,
       
   435    mcf_fec_read
       
   436 };
       
   437 
       
   438 static CPUWriteMemoryFunc *mcf_fec_writefn[] = {
       
   439    mcf_fec_write,
       
   440    mcf_fec_write,
       
   441    mcf_fec_write
       
   442 };
       
   443 
       
   444 void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq)
       
   445 {
       
   446     mcf_fec_state *s;
       
   447     int iomemtype;
       
   448 
       
   449     s = (mcf_fec_state *)qemu_mallocz(sizeof(mcf_fec_state));
       
   450     s->irq = irq;
       
   451     iomemtype = cpu_register_io_memory(0, mcf_fec_readfn,
       
   452                                        mcf_fec_writefn, s);
       
   453     cpu_register_physical_memory(base, 0x400, iomemtype);
       
   454 
       
   455     s->vc = qemu_new_vlan_client(nd->vlan, mcf_fec_receive,
       
   456                                  mcf_fec_can_receive, s);
       
   457     memcpy(s->macaddr, nd->macaddr, 6);
       
   458 }