From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1L3ZW4-0007NX-LM for qemu-devel@nongnu.org; Fri, 21 Nov 2008 12:10:01 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1L3ZW2-0007Mi-4c for qemu-devel@nongnu.org; Fri, 21 Nov 2008 12:09:59 -0500 Received: from [199.232.76.173] (port=42074 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1L3ZW2-0007Mf-0B for qemu-devel@nongnu.org; Fri, 21 Nov 2008 12:09:58 -0500 Received: from e8.ny.us.ibm.com ([32.97.182.138]:56379) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1L3ZW1-0006Gg-Ne for qemu-devel@nongnu.org; Fri, 21 Nov 2008 12:09:58 -0500 Received: from d01relay02.pok.ibm.com (d01relay02.pok.ibm.com [9.56.227.234]) by e8.ny.us.ibm.com (8.13.1/8.13.1) with ESMTP id mALH5jnu012312 for ; Fri, 21 Nov 2008 12:05:45 -0500 Received: from d01av03.pok.ibm.com (d01av03.pok.ibm.com [9.56.224.217]) by d01relay02.pok.ibm.com (8.13.8/8.13.8/NCO v9.1) with ESMTP id mALH9uMV180698 for ; Fri, 21 Nov 2008 12:09:56 -0500 Received: from d01av03.pok.ibm.com (loopback [127.0.0.1]) by d01av03.pok.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id mALH9tIn016736 for ; Fri, 21 Nov 2008 12:09:55 -0500 Received: from [9.53.41.42] (slate.austin.ibm.com [9.53.41.42]) by d01av03.pok.ibm.com (8.12.11.20060308/8.12.11) with ESMTP id mALH9t5l016705 for ; Fri, 21 Nov 2008 12:09:55 -0500 Subject: Re: [Qemu-devel] PowerPC 4xx EMAC emulation From: Hollis Blanchard In-Reply-To: <169263.53603.qm@web27203.mail.ukl.yahoo.com> References: <169263.53603.qm@web27203.mail.ukl.yahoo.com> Content-Type: text/plain Date: Fri, 21 Nov 2008 11:09:55 -0600 Message-Id: <1227287395.26513.51.camel@localhost.localdomain> Mime-Version: 1.0 Content-Transfer-Encoding: 7bit Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org On Fri, 2008-11-21 at 01:53 +0000, Salvatore Lionetti wrote: > Index: hw/emac.c > =================================================================== > --- hw/emac.c (revision 0) > +++ hw/emac.c (revision 0) You should name this ppc4xx_emac.c to avoid confusion. > @@ -0,0 +1,797 @@ > +/* > + * QEMU EMAC emulation > + * > + * Copyright (c) 2008, Lionetti Salvatore salvatorelionetti@yahoo.it > + * > + * Permission is hereby granted, free of charge, to any person obtaining a copy > + * of this software and associated documentation files (the "Software"), to deal > + * in the Software without restriction, including without limitation the rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN > + * THE SOFTWARE. > + */ > + > +/* This module provide an emulation for ethernet onchip controller on ppc4xx cpu. > + * Tested on > + * - emulator of a NSN proprietary board, for 4G > + * - walnut board/u-boot-1.1.6 (whith some patch) > + * > + * TODO: > + * - >1 {tx, rx} channel > + * - can_receive() and buffer_full() too simple. > + */ > +#include "hw.h" > +#include "ppc.h" > +#include "ppc405.h" > +#include "pc.h" > +#include "qemu-timer.h" > +#include "sysemu.h" > +#include "net.h" > + > +/*#define DEBUG_EMAC*/ > +#ifdef DEBUG_EMAC > +#define DPRINT(fmt, args...) \ > + do { printf("%" PRIu64 " %s: " fmt , qemu_get_clock(rt_clock), __func__, ##args); } while (0) > +#else > +#define DPRINT(fmt, args...) > +#endif > + > +/* > + * Redefined because if !exist, linker gives a warning but produce qemu, > + * but on execution this call cause problem > + * (could be cygwin & mingw cohesistence?) > + */ > +#if (defined(WORDS_BIGENDIAN) && defined(TARGET_WORDS_BIGENDIAN)) || ((!defined(WORDS_BIGENDIAN) && !defined(TARGET_WORDS_BIGENDIAN))) > +#if 0 > +static unsigned long int htonl(unsigned long int hostlong); > +static unsigned short int htons(unsigned short int hostshort); > +#endif > +static unsigned long int ntohl(unsigned long int ing) { > + return ing; > +} > +static unsigned short int ntohs(unsigned short int ing) { > + return ing; > +} > +#else > +static unsigned long int ntohl(unsigned long int ing) { > + unsigned char tmp; > + unsigned char* tmpp = (unsigned char*)&ing; > + tmp=tmpp[0]; tmpp[0]=tmpp[3]; tmpp[3]=tmp; > + tmp=tmpp[1]; tmpp[1]=tmpp[2]; tmpp[2]=tmp; > + return *(unsigned long int*)tmpp; > +} > +static unsigned short int ntohs(unsigned short int ing) { > + return ((ing&0xFF)<<8) | ((ing&0xFF00)>>8); > +} > +#endif That comment makes me very nervous. At any rate, you don't need to invent your own byteswapping macros here; use the standard qemu ones. > +/* qemu initialization: > + * > + * parse command line: call net_client_init() for each -net, either for {if, collision domain} options. > + * ========== ================ > + * IF MAC=... <==== Vlan{Id,Ptr} ====> COLLISION DOMAIN (mean N-1 other IF MAC=...) > + * ========== ================ > + * -net nic[,...]: fill field onto nd_table[] {MAC(cl|auto), model, vlanPtr=f(vlanId)} > + * vlanPtr=f(vlanId)->guest++ > + * -net tap[,...]: vlanPtr=f(vlanId)->host ++ > + * tap_win32_init(vlanPtr, "ifname=tap..."): > + * qemu_new_vlan_client(vlanPtr,tap_receive, tap* opaque) RECV > + * qemu_add_wait_object(tap_sem, tap_w32_send, tap* opaque) SEND > + * > + * For each vlan created, > + * exit if no GUEST & some HOST > + * warn if some GUEST & no HOST > + * > + * start machine: Es ppc (also pc use n2000) call machine->init(): > + * isa_ne2000_init(base, irqno, &nd_table[i]) > + * register_ioport_write(base + ..., ne2000_asic_ioport_write, opaque NE2000State*); SEND > + * qemu_new_vlan_client(nd->vlan, ne2000_receive, ne2000_can_receive, opaque NE2000State*) RECV > + * > + * Done!!! This comment is way over 80 chars wide, and should be removed anyways. This is not the appropriate place to document qemu's initialization sequence. I also don't understand why you're talking about NE2000 in emac.c. > + * qemu runtime scenario: > + * > + * packet send from HOST: a signal (after exec() cycle) is sent to tap_sem => tap_w32_send() => tap_win32_read() > + * if some bytes returned => qemu_send_packet() => send to all 'client' (better peer) of > + * such vlan, different from itself => ne2000_receive() > + * > + * packet send from GUEST: in machine code we call qemu_send_packet() => (prec) => tap_receive() => tap_w32_write() > + * > + * > + * So onto VLAN actors always call qemu_send_packet() that dispatch packet to all peer attached to same vlan. > + * > + */ > +/* PPC405 layer 2, reversed MII mode: > + * > + * Register@0xEF600000 already mapped. > + * Configuration RW: > + * > + * Read(ind, data): > + * [EMAC0_STACR] <= (STACR_STAC_R | ind) > + * [EMAC0_STACR] & STACR_OC must goes to 0 > + * [EMAC0_STACR] => >>16 => data > + * > + * Write(ind, data) > + * [EMAC0_STACR] <= (STACR_STAC_W | ind | data<<16) > + * [EMAC0_STACR] & STACR_OC must goes to 0 > + * > + * Physical access: > + * Read(ind_phy, ind_reg, data) > + * [EMAC0_STACR] <= (STACR_STAC_W | TANTOS_REG_MIIAC | (ind_reg&0x1F | OP_READ | (ind_phy&0x1F)<<5))>>16 > + * [EMAC0_STACR] & STACR_OC must goes to 0 > + * > + * Verify: > + * [EMAC0_STACR] <= (STACR_STAC_R | TANTOS_REG_MIIRD) > + * [EMAC0_STACR] & STACR_OC must goes to 0 > + * [EMAC0_STACR] => data > + * data & STACR_PHYE should be 0 > + * data=data>>16 > + * > + * Tantos Stub Layer: (needed?) > + * > + * From mal we need > + * - MAL0_TXCTPxR > + * - MAL0_RXCTPxR > + * - MAL0_RCBS0 > + */ > +/* TODO: need interaction between device! > + * very difficult since all struct is in .c file */ Refactor it then. > +extern uint32_t txctpr[4]; > +extern uint32_t rxctpr[2]; > +extern uint32_t rcbs[2]; > +extern uint32_t *rxeobisr; /* With namespace, use & to automatize correlation.*/ > +extern uint32_t *txeobisr; These should not be not global. Pass a pointer to ppc40x_mal_t into the EMAC init code and access them that way. > +// For PPC405 > +#define EMAC0_BASE 0xEF600800 > +#define EMAC0_STACR_DISP 0x35 > +#define EMAC0_STACR (EMAC0_BASE + EMAC0_STACR_DISP) /* 4 byte addressing */ > +#define STACR_OC 0x00008000 /* Occupied flag */ > +#define STACR_PHYE 0x00004000 > +#define STACR_STAC_W 0x00002000 > +#define STACR_STAC_R 0x00001000 > + > +#define TANTOS_REG_MIIAC 0x120 /// TANTOS3G MII indirect acess registers > +#define TANTOS_REG_MIIWD 0x121 > +#define TANTOS_REG_MIIRD 0x122 > +#define OP_WRITE 0x0400 > +#define OP_READ 0x0800 > +#define MBUSY 0x8000 Probably all these Tantos references should be removed; they're not used in the code. > +/* WORDS_BIGENDIAN = FALSE su HOST i386, GUEST ppc > + * per cui e' l'architetura HOST > + */ Some Italian was left here. > +struct EmacMalRxDes { > +#ifndef WORDS_BIGENDIAN > + union { > + struct { /* Mal */ > + unsigned int emac1_nu : 2; > + unsigned int bit5_intr : 1; > + unsigned int bit4_first : 1; > + unsigned int bit3_last : 1; > + unsigned int bit2_contm : 1; > + unsigned int bit1_wrap : 1; > + unsigned int bit0_empty : 1; > + unsigned int emac2_nu : 8; > + } __attribute__ ((packed)) mal; > + struct { /* Status: Read access, error cause */ > + unsigned int bit7_pausepacket : 1; > + unsigned int bit6_overrun : 1; > + unsigned int mal_nu : 6; > + unsigned int bit15_inrange : 1; > + unsigned int bit14_outrange : 1; > + unsigned int bit13_longpacket : 1; > + unsigned int bit12_fcs : 1; > + unsigned int bit11_alignment : 1; > + unsigned int bit10_shortevent : 1; > + unsigned int bit9_runtpacket : 1; > + unsigned int bit8_badpacket : 1; > + } __attribute__ ((packed)) emac_errstatus; > + } __attribute__ ((packed)); > +#else > +#error "Host endianism BUG: To Test!!!" > +#endif > + unsigned short len; > + unsigned char* buf; > +} __attribute__ ((packed)); /* Host endianism, to be converted */ I worry a lot about this endianness handling. You should probably byteswap whole words *before* storing into this structure, so that you don't need to define two structures with different layouts. > +struct EmacMalTxDes { > +#ifndef WORDS_BIGENDIAN > + /* IN A HALF-WORD (16bits) > + * position position > + * in bitfield in value > + * from high from MSb > + * ========================= > + * 0 8 > + * 1 9 > + * 2 10 > + * 3 11 > + * 4 12 > + * 5 13 > + * 6 14 > + * 7 15 > + * 8 0 > + * 9 1 > + * 10 2 > + * 11 3 > + * 12 4 > + * 13 5 > + * 14 6 > + * 15 7 > + * > + * ===HOST LE, TARGET BE=== > + * IN A BYTE (8bits) > + * > + * IN A HALF-WORD (16bits) > + * 0-7 8-15 > + * 8-15 0-7 > + */ > + union { > + struct { /* Mal */ > + unsigned int emac1_nu : 2; > + unsigned int bit5_intr : 1; > + unsigned int bit4_resv : 1; > + unsigned int bit3_last : 1; > + unsigned int bit2_contm : 1; > + unsigned int bit1_wrap : 1; > + unsigned int bit0_ready : 1; > + unsigned int emac2_nu : 8; > + } __attribute__ ((packed)) mal; > + struct { /* Status: Read access, error cause */ > + unsigned int bit7_badpacket : 1; > + unsigned int bit6_badfsc : 1; > + unsigned int mal_nu : 6; > + unsigned int bit15_sqe : 1; > + unsigned int bit14_underrun : 1; > + unsigned int bit13_singlecoll : 1; > + unsigned int bit12_multiplecoll : 1; > + unsigned int bit11_latecoll : 1; > + unsigned int bit10_excessivecoll : 1; > + unsigned int bit9_excessivedeferral : 1; > + unsigned int bit8_lossofcarrier : 1; > + } __attribute__ ((packed)) emac_errorstatus; > + struct { /* Control: Write access */ > + unsigned int bit7_generatepad : 1; > + unsigned int bit6_generatefcs : 1; > + unsigned int mal_nu : 6; > + unsigned int emac_nu : 4; > + unsigned int bit11_vlantag_replace : 1; > + unsigned int bit10_vlantag_insert : 1; > + unsigned int bit9_sourceaddr_insert : 1; > + unsigned int bit8_sourceaddr_replace: 1; > + } __attribute__ ((packed)) emac_control; > + }; > +#else > +#error "Host endianism BUG: To Test!!!" > +#endif > + unsigned short len; > + unsigned char* buf; > +}__attribute__ ((packed)); /* Host endianism, to be converted */ > + > +/* Controlo Register definition */ > +struct EmacRegs { > +#if 0 > +#ifndef WORDS_BIGENDIAN > + struct Emac0_mr0 { > + unsigned int ; > + } __attribute__((packed)); > +#else > +#error "Host endianism BUG: To Test!!!" > +#endif > +#else > + /* 0 */ > + uint32_t mr0; > + uint32_t mr1; > + uint32_t tmr0; > + uint32_t tmr1; > + uint32_t rmr; > + uint32_t isr; > + uint32_t isre; > + uint32_t iahr; > + uint32_t ialr; > + uint32_t vtpid; > + /* 10 */ > + uint32_t vtci; > + uint32_t ptr; > + uint32_t iaht1; > + uint32_t iaht2; > + uint32_t iaht3; > + uint32_t iaht4; > + uint32_t gaht1; > + uint32_t gaht2; > + uint32_t gaht3; > + uint32_t gaht4; > + /* 20 */ > + uint32_t lsah; > + uint32_t lsal; > + uint32_t ipgvr; > + uint32_t stacr; > + uint32_t trtr; > + uint32_t rwmr; > + uint32_t octx; > + uint32_t ocrx; > + /* 28 reg */ > + > +#define RSTA mr0 & 0x20000000 > +#define TXEN mr0 & 0x10000000 > +#define RXEN mr0 & 0x08000000 > +#endif > +} __attribute__ ((packed)); > + > +typedef struct ppc4xx_emac_t ppc4xx_emac_t; > +struct ppc4xx_emac_t { > + /* Guest related */ > + target_phys_addr_t base; > + NICInfo nic; > + /* To remove, already defined in mal */ > + qemu_irq mal_irqs_txeob; > + qemu_irq mal_irqs_rxeob; > + qemu_irq mal_irqs_txerr; > + qemu_irq mal_irqs_rxerr; > + qemu_irq mal_irqs_syserr; > + > + struct EmacRegs reg, _reg; > + > + struct EmacMalTxDes* tx; > + struct EmacMalRxDes* rx; > + > + int txPos, rxPos; > + int txNum, rxNum; > + > + int rxLostNum, rxLostLimit; > + > + /* Host related */ > + VLANClientState *vc; > + QEMUTimer* tx_timer; > +}; > + > +#if 0 > +#define EMACMAL_EMPTY 0x8000 > +#define EMACMAL_WRAP 0x8000 > +#define EMACMAL_EMPTY 0x8000 > +#define EMACMAL_EMPTY 0x8000 > +void EmacMalDes_readFromTarget(struct EmacMalDes* host, struct EmacMalDes* guest) { > + > + host->status = ntohs(guest->status); > + host->len = ntohs(guest->len); > + host->buf = htol(guest->buf); > +} > +void EmacMalDes_writeToTarget(struct EmacMalDes* host, struct EmacMalDes* guest) { > +} > +#endif Remove #if 0 code. > +void EmacMalRxDes_dump(struct EmacMalRxDes* des) { > +#ifdef DEBUG_EMAC > + unsigned char* tdes = (unsigned char*) ((unsigned char*)des - phys_ram_base); > + printf("RXdes@%p={len%d,buf%p,empty%d wrap%d contm %d last%d first%d intr%d\n", > + tdes, ntohs(des->len), (unsigned char*) ntohl((unsigned long int)des->buf), > + des->mal.bit0_empty, des->mal.bit1_wrap, des->mal.bit2_contm, des->mal.bit3_last, des->mal.bit4_first, des->mal.bit5_intr); > +#endif > +} > +void EmacMalTxDes_dump(struct EmacMalTxDes* des) { > +#ifdef DEBUG_EMAC > + unsigned char* tdes = (unsigned char*)((unsigned char*)des - phys_ram_base); > + printf("TXdes@%p={len%d,buf%p,ready%d wrap%d contm %d last%d first%d intr%d\n", > + tdes, ntohs(des->len), (unsigned char*)ntohl((unsigned long int)des->buf), > + des->mal.bit0_ready, des->mal.bit1_wrap, des->mal.bit2_contm, des->mal.bit3_last, des->mal.bit4_resv, des->mal.bit5_intr); > +#endif > +} > +#if 0 > +static int emac_buffer_full(ppc4xx_emac_t *s) > +{ > +#if 0 > + int avail, index, boundary; > + > + index = s->curpag << 8; > + boundary = s->boundary << 8; > + if (index < boundary) > + avail = boundary - index; > + else > + avail = (s->stop - s->start) - (index - boundary); > + if (avail < (MAX_ETH_FRAME_SIZE + 4)) > + return 1; > +#endif > + return 0; > +} > + > +static int emac_can_receive(void *opaque) > +{ > +#if 0 > + NE2000State *s = opaque; > + > + if (s->cmd & E8390_STOP) > + return 1; > + return !ne2000_buffer_full(s); > +#endif > + return 0; > +} > +#endif Remove lots more #if 0 code. > +static void emac_receive(void *opaque, const uint8_t *buf, int size) > +{ > + ppc4xx_emac_t* emac = (ppc4xx_emac_t*) opaque; > + > + DPRINT("%d bytes\n", size); > + if (emac->reg.RXEN) { > + if (emac->rx->buf) { > + if (size<1520) { > + if (emac->rx[emac->rxPos].mal.bit0_empty) { > + /* data is allocated with the maximum possible length, on eth = 1520Bytes > + * len field represent packet size.*/ > + /* We !use Continuos mode, first & last field ignored */ > + unsigned char* dstG = (unsigned char*) ntohl((unsigned long int)emac->rx[emac->rxPos].buf); > + unsigned char* dstH= dstG+(unsigned int)phys_ram_base; > + unsigned short size16 = size; > + DPRINT(" Delivery message HOST %p-> GUEST %p,pos%d\n", dstH, dstG, emac->rxPos); > + EmacMalRxDes_dump(&emac->rx[emac->rxPos]); > + emac->reg.ocrx += size16; > + memcpy(dstH, buf, size); > + emac->rx[emac->rxPos].len = ntohs(size16); > + emac->rx[emac->rxPos].mal.bit0_empty = 0; > + if (emac->rx[emac->rxPos].mal.bit5_intr) { > + /* TODO: use appropriate channel */ > + *rxeobisr = 0xC0000000; > + qemu_irq_raise(emac->mal_irqs_rxeob); > + } > + > + emac->rxPos += (emac->rx[emac->rxPos].mal.bit1_wrap)? -(emac->rxPos) : 1; > + } else { > + if (++emac->rxLostNum == emac->rxLostLimit) { > + printf(" %d Message lost, board seem hung up!\n", emac->rxLostNum); > + emac->rxLostLimit*=10; > + } > + } > + } else { > + printf(" Message size > 1520, discarding packet\n"); > + } The indentation here looks pretty messed up. Also, what is the 1520 byte limitation? From a quick skim, I don't see mention of that in the user manual. > + } else { > + } > + } else { > + static int sndOrMore=0; > + if (!sndOrMore) { > + printf("emac/mal: Driver !command start yet\n"); > + sndOrMore=1; > + } > + } > +#if 0 > +#define MIN_BUF_SIZE 60 > + NE2000State *s = opaque; > + uint8_t *p; > + unsigned int total_len, next, avail, len, index, mcast_idx; > + uint8_t buf1[60]; > + static const uint8_t broadcast_macaddr[6] = > + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; > + > +#if defined(DEBUG_NE2000) > + printf("NE2000: received len=%d\n", size); > +#endif > + > + if (s->cmd & E8390_STOP || ne2000_bufstruct mal_emac_bdfer_full(s)) > + return; > + > + /* XXX: check this */ > + if (s->rxcr & 0x10) { > + /* promiscuous: receive all */ > + } else { > + if (!memcmp(buf, broadcast_macaddr, 6)) { > + /* broadcast address */ > + if (!(s->rxcr & 0x04)) > + return; > + } else if (buf[0] & 0x01) { > + /* multicast */ > + if (!(s->rxcr & 0x08)) > + return; > + mcast_idx = compute_mcast_idx(buf); > + if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) > + return; > + } else if (s->mem[0] == buf[0] && > + s->mem[2] == buf[1] && > + s->mem[4] == buf[2] && > + s->mem[6] == buf[3] && > + s->mem[8] == buf[4] && > + s->mem[10] == buf[5]) { > + /* match */ > + } else { > + return; > + } > + } > + > + > + /* if too small buffer, then expand it */ > + if (size < MIN_BUF_SIZE) { > + memcpy(buf1, buf, size); > + memset(buf1 + size, 0, MIN_BUF_SIZE - size); > + buf = buf1; > + size = MIN_BUF_SIZE; > + } > + > + index = s->curpag << 8; > + /* 4 bytes for header */ > + total_len = size + 4; > + /* address for next packet (4 bytes for CRC) */ > + next = index + ((total_len + 4 + 255) & ~0xff); > + if (next >= s->stop) > + next -= (s->stop - s->start); > + /* prepare packet header */ > + p = s->mem + index; > + s->rsr = ENRSR_RXOK; /* receive status */ > + /* XXX: check this */ > + if (buf[0] & 0x01) > + s->rsr |= ENRSR_PHY; > + p[0] = s->rsr; > + p[1] = next >> 8; > + p[2] = total_len; > + p[3] = total_len >> 8; > + index += 4; > + > + /* write packet data */ > + while (size > 0) { > + if (index <= s->stop) > + avail = s->stop - index; > + else > + avail = 0; > + len = size; > + if (len > avail) > + len = avail; > + memcpy(s->mem + index, buf, len); > + buf += len; > + index += len; > + if (index == s->stop) > + index = s->start; > + size -= len; > + } > + s->curpag = next >> 8; > + > + /* now we can signal we have received something */ > + s->isr |= ENISR_RX; > + ne2000_update_irq(s); > +#endif All that #if 0 code looks like it was copied directly from ne2000 emulation. Get rid of it. > +} > + > +void emac_ppc405_init(ppc4xx_emac_t* emac, NICInfo *nd) > +{ > + memcpy(&emac->nic, nd, sizeof(NICInfo)); > + /* We are only be able to receive. Sending packet mean receiver action get up */ I don't understand this comment at all. Is this function really specific to ppc405, or could it also apply to 440 SoCs with EMAC? > + emac->vc = qemu_new_vlan_client(nd->vlan, emac_receive, > + NULL/*emac_can_receive*/, emac); > + > + snprintf(emac->vc->info_str, sizeof(emac->vc->info_str), > + "emac macaddr=%02x:%02x:%02x:%02x:%02x:%02x", > + emac->nic.macaddr[0], > + emac->nic.macaddr[1], > + emac->nic.macaddr[2], > + emac->nic.macaddr[3], > + emac->nic.macaddr[4], > + emac->nic.macaddr[5]); > + printf("%s\n", emac->vc->info_str); > +} > + > +static void ppc4xx_emac_reset (void *opaque) > +{ > + ppc4xx_emac_t *emac; > + > + emac = opaque; > + emac->rx = NULL; > + emac->tx = NULL; > + emac->txPos = emac->rxPos = 0; > + emac->txNum = emac->rxNum = 0; > + emac->rxLostNum=0; > + emac->rxLostLimit=1; > + > + memset(&emac->reg, 0, sizeof(emac->reg)); > + emac->reg.mr0 = 0xC0000000; > + emac->reg.tmr1 = 0x380F0000; > + emac->reg.vtpid = 0x00008808; > + emac->reg.ptr = 0x0000FFFF; > + emac->reg.ipgvr = 0x00000004; > + emac->reg.stacr = 0x00008000; > + emac->reg.rwmr = 0x04001000; > + > + /* Now ready to issue mii control transfer */ > + emac->reg.stacr = 0; > +} > +/* It looks like a lot of Linux programs assume page size > + * is 4kB long. This is evil, but we have to deal with it... > + * > +#define TARGET_PAGE_BITS 12 TARGET_PAGE_BITS has no place here at all, and you never even use it anyways. > + * Here we have many register. > + * Do action only for reset or transmit command. > + * Other will be simple configuration latched during device emulation > + * es stop rx, allow pause packet. > + * > + * Another tip: > + * When possible only implemente the read of value, since using var read/write is target indep > + */ > +static uint32_t emac_readl (void *opaque, target_phys_addr_t addr) > +{ > + uint32_t value; > + ppc4xx_emac_t* emac = (ppc4xx_emac_t*)opaque; > + uint32_t ind = (addr-emac->base)>>2; > + /* Keep in a separate way, as stackable code */ > + if (ind>=28) { > + printf("emac: Out of range register %d!\n", ind); > + return 0; > + } > + value = ((uint32_t*)&emac->reg)[ind]; > + DPRINT("emac: [%d] => %x\n", ind, value); > + return value/*STACR_OC*/; > +} > + > +static void emac_writel (void *opaque, target_phys_addr_t addr, uint32_t value) > +{ > + ppc4xx_emac_t* emac = (ppc4xx_emac_t*)opaque; > + uint32_t ind = (addr-emac->base)>>2; > + > +/* printf("%s: " PADDRX " val %x\n",__func__, addr, value);*/ > + /* Exist some common code for this? */ > + if (ind>=28) { > + printf("emac: Out of range register %d!\n", ind); > + return; > + } > + switch (ind) { > + case 20: > + case 21: > + case 26: > + case 27: > + printf("emac: Attemping to write to read only reg!"); > + return; > + } > + DPRINT("emac: [%d] <= %x\n", ind, value); > + /* Keep in a separate way, as stackable code */ > + ((uint32_t*)&emac->reg)[ind] = value; > + if (ind==0) { > + emac->_reg.mr0 = value; > + /* soft reset */ > + if (emac->_reg.RSTA) { > + printf("emac: soft reset commanded!\n"); > + ppc4xx_emac_reset(emac);/* Should be protected with a semaphore, also in emac_receive()? */ > + value &= ~(emac->_reg.RSTA); /* Sw look for this bit go down */ > + } > + > + DPRINT("emac: St%s tx channel!\n", emac->_reg.TXEN?"arting":"opping"); > + DPRINT("emac: St%s rx channel!\n", emac->_reg.RXEN?"arting":"opping"); > + > + /* Suppose the mal reg was updated, seem a good approximation */ > + if (emac->_reg.TXEN && emac->tx==NULL) { > + int l=0; > + emac->tx = (struct EmacMalTxDes*) (txctpr[0] + phys_ram_base); > + do { EmacMalTxDes_dump(&emac->tx[l]); } while (!emac->tx[l].mal.bit1_wrap && l++<50); > + } > + if (emac->_reg.RXEN && emac->rx==NULL) { > + int l=0; > + emac->rx = (struct EmacMalRxDes*) (rxctpr[0] + phys_ram_base); > + do { EmacMalRxDes_dump(&emac->rx[l]); } while (!emac->rx[l].mal.bit1_wrap && l++<50); > + } > + /* A timer that periodically check packet to send > + emac->tx_timer = qemu_new_timer();*/ > + } > + if (ind==2) { > + if (value & 0xC0000000) { /* both channel */ > + if (emac->reg.TXEN) { > + if (emac->tx[emac->txPos].mal.bit0_ready) { > + unsigned char* dstG = (unsigned char*) ntohl((unsigned long int)emac->tx[emac->txPos].buf); > + unsigned char* dstH= dstG+(unsigned int)phys_ram_base; > + unsigned short size16 = ntohs(emac->tx[emac->txPos].len); > + > + DPRINT("Sending packet on pos %d\n", emac->txPos); > + qemu_send_packet(emac->vc, dstH, size16); > + emac->reg.octx += size16; > + if (emac->tx[emac->txPos].mal.bit5_intr) { > + /* TODO: use appropriate channel */ > + *txeobisr = 0xC0000000; > + qemu_irq_raise(emac->mal_irqs_txeob); > + } > + > + /* Clear status */ > + emac->tx[emac->txPos].mal.bit0_ready = 0; > + /* 0x808 is stucked at STACR_OC */ > + emac->txPos += (emac->tx[emac->txPos].mal.bit1_wrap)? -(emac->txPos) : 1; > + > + /* > + * u-boot driver (no os=>no task) poll this bit until became 0, > + * but in PPC405GPr User manual nothing said about this > + */ > + value &= ~0xC0000000; > + } else {printf("Processor goes crazy(ready bit was 0)!!! Stopping tx\n");} > + } else {DPRINT("Tx is disabled\n");} > + } > + } > + if (ind==23) { > + /* PPC405GPr_UM2004 say, on page 568: > + * 'EMAC sets EMAC0_STACR[OC] = 0 when the EMAC0_STACR is written to.' > + * 'EMAC then sets EMAC0_STACR[OC] = 1 to indicate that the data has been written to the PHY, or the data' > + * 'read from the PHY is valid. The device driver should poll for EMAC0_STACR[OC] = 1 before issuing a new' > + * 'command, or before using data read from the PHY' > + * > + * our approximation: > + * - initial condition 0 > + * - write(sw start some MII command) 1 (we end in the same cycle) > + * - read(poll status) 1 > + * - write(sw start new cmd | ...) 0 > + * > + * reg write clear (bit index is opposite then those reported by official manual) > + * PHYD bit 31:16 Data (RW) > + * OC bit 15 0 when this reg is addressed, 1 data written to PHY/data readed correctly from PHY > + * PHYE bit 14 1 PhyError during read > + * STAC bit 13:12 00 Reserved/01 Read/10 Write/11 Reserved > + * OPBC bit 11:10 OPB Bus clock freq. signal EMCMDCIk > + * PCDA bit 9:5 PHY Command destination address > + * PRA bit 4:0 PHY Register address > + * > + value &= ~(1<<15);*/ > + value ^= (1<<15); > + value &= ~(1<<14); > + } > + /* Keep in a separate way, as stackable code */ > + ((uint32_t*)&emac->reg)[ind] = value; > +} > +static uint32_t emac_readw (void *opaque, target_phys_addr_t addr) > +{ > + printf("Lettura a granularita' word su EMAC " PADDRX "\n",addr); > + return 0; > +} > + > +static void emac_writew (void *opaque, target_phys_addr_t addr, uint32_t value) > +{ > + printf("Scrittura a granularita' word su EMAC " PADDRX "\n",addr); > +} > + > +static uint32_t emac_readb (void *opaque, target_phys_addr_t addr) > +{ > + printf("Lettura a granularita' byte su EMAC " PADDRX "\n",addr); > + return 0; > +} > + > +static void emac_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) > +{ > + printf("Scrittura a granularita' byte su EMAC " PADDRX "\n",addr); > +} A lot of Italian in here. :) > + > +static CPUReadMemoryFunc *emac_read[] = { > + &emac_readb, > + &emac_readw, > + &emac_readl, > +}; > + > +static CPUWriteMemoryFunc *emac_write[] = { > + &emac_writeb, > + &emac_writew, > + &emac_writel, > +}; > +void ppc4xx_emac_init (CPUState *env, ppc4xx_mmio_t *mmio, target_phys_addr_t offset, NICInfo *nic, qemu_irq mal_irqs[4]) > +{ > + ppc4xx_emac_t *emac; > + > + emac = qemu_mallocz(sizeof(ppc4xx_emac_t)); > + if (emac != NULL) { > + emac->base = offset; > +#ifdef DEBUG_OPBA > + printf("%s: offset " PADDRX "\n", __func__, offset); > +#endif > + ppc4xx_mmio_register(env, mmio, offset, 0x70, > + emac_read, emac_write, emac); > + qemu_register_reset(ppc4xx_emac_reset, emac); > + > + /* One time configuration, HOST related */ > + emac_ppc405_init(emac, nic); > + > + emac->mal_irqs_txeob = mal_irqs[0]; > + emac->mal_irqs_rxeob = mal_irqs[1]; > + emac->mal_irqs_txerr = mal_irqs[2]; > + emac->mal_irqs_rxerr = mal_irqs[3]; > + > + /* N Time configuration, GUEST related */ > + ppc4xx_emac_reset(emac); > + } > +} I'm more interested in your EMAC work, so if you split that into a separate patch as you revise it, we may be able to get it cleaned up and usable sooner than later. -- Hollis Blanchard IBM Linux Technology Center