/* MIPSnet register offsets */#defineMIPSNET_DEV_ID0x00#defineMIPSNET_BUSY0x08#defineMIPSNET_RX_DATA_COUNT0x0c#defineMIPSNET_TX_DATA_COUNT0x10#defineMIPSNET_INT_CTL0x14#defineMIPSNET_INTCTL_TXDONE0x00000001#defineMIPSNET_INTCTL_RXDONE0x00000002#defineMIPSNET_INTCTL_TESTBIT0x80000000#defineMIPSNET_INTERRUPT_INFO0x18#defineMIPSNET_RX_DATA_BUFFER0x1c#defineMIPSNET_TX_DATA_BUFFER0x20#defineMAX_ETH_FRAME_SIZE1514typedefstructMIPSnetState{uint32_tbusy;uint32_trx_count;uint32_trx_read;uint32_ttx_count;uint32_ttx_written;uint32_tintctl;uint8_trx_buffer[MAX_ETH_FRAME_SIZE];uint8_ttx_buffer[MAX_ETH_FRAME_SIZE];qemu_irqirq;VLANClientState*vc;NICInfo*nd;}MIPSnetState;staticvoidmipsnet_reset(MIPSnetState*s){s->busy=1;s->rx_count=0;s->rx_read=0;s->tx_count=0;s->tx_written=0;s->intctl=0;memset(s->rx_buffer,0,MAX_ETH_FRAME_SIZE);memset(s->tx_buffer,0,MAX_ETH_FRAME_SIZE);}staticvoidmipsnet_update_irq(MIPSnetState*s){intisr=!!s->intctl;#ifdefDEBUG_MIPSNET_IRQprintf("mipsnet: Set IRQ to %d (%02x)\n",isr,s->intctl);#endifqemu_set_irq(s->irq,isr);}staticintmipsnet_buffer_full(MIPSnetState*s){if(s->rx_count>=MAX_ETH_FRAME_SIZE)return1;return0;}staticintmipsnet_can_receive(void*opaque){MIPSnetState*s=opaque;if(s->busy)return0;return!mipsnet_buffer_full(s);}staticvoidmipsnet_receive(void*opaque,constuint8_t*buf,intsize){MIPSnetState*s=opaque;#ifdefDEBUG_MIPSNET_RECEIVEprintf("mipsnet: receiving len=%d\n",size);#endifif(!mipsnet_can_receive(opaque))return;s->busy=1;/* Just accept everything. *//* Write packet data. */memcpy(s->rx_buffer,buf,size);s->rx_count=size;s->rx_read=0;/* Now we can signal we have received something. */s->intctl|=MIPSNET_INTCTL_RXDONE;mipsnet_update_irq(s);}staticuint32_tmipsnet_ioport_read(void*opaque,uint32_taddr){MIPSnetState*s=opaque;intret=0;addr&=0x3f;switch(addr){caseMIPSNET_DEV_ID:
break;caseMIPSNET_BUSY:ret=s->busy;break;caseMIPSNET_RX_DATA_COUNT:ret=s->rx_count;break;caseMIPSNET_TX_DATA_COUNT:ret=s->tx_count;break;caseMIPSNET_INT_CTL:ret=s->intctl;s->intctl&=~MIPSNET_INTCTL_TESTBIT;break;caseMIPSNET_INTERRUPT_INFO:/* XXX: This seems to be a per-VPE interrupt number. */ret=0;break;caseMIPSNET_RX_DATA_BUFFER:if(s->rx_count){s->rx_count--;ret=s->rx_buffer[s->rx_read++];}break;/* Reads as zero. */caseMIPSNET_TX_DATA_BUFFER:default:break;}#ifdefDEBUG_MIPSNET_DATAprintf("mipsnet: read addr=0x%02x val=0x%02x\n",addr,ret);#endifreturnret;}staticvoidmipsnet_ioport_write(void*opaque,uint32_taddr,uint32_tval){MIPSnetState*s=opaque;addr&=0x3f;#ifdefDEBUG_MIPSNET_DATAprintf("mipsnet: write addr=0x%02x val=0x%02x\n",addr,val);#endifswitch(addr){caseMIPSNET_TX_DATA_COUNT:s->tx_count=(val<=MAX_ETH_FRAME_SIZE)?val:0;s->tx_written=0;break;caseMIPSNET_INT_CTL:if(val&MIPSNET_INTCTL_TXDONE){s->intctl&=~MIPSNET_INTCTL_TXDONE;}elseif(val&MIPSNET_INTCTL_RXDONE){s->intctl&=~MIPSNET_INTCTL_RXDONE;}elseif(val&MIPSNET_INTCTL_TESTBIT){mipsnet_reset(s);s->intctl|=MIPSNET_INTCTL_TESTBIT;}elseif(!val){/* ACK testbit interrupt, flag was cleared on read. */}s->busy=!!s->intctl;mipsnet_update_irq(s);break;caseMIPSNET_TX_DATA_BUFFER:s->tx_buffer[s->tx_written++]=val;if(s->tx_written==s->tx_count){/* Send buffer. */#ifdefDEBUG_MIPSNET_SENDprintf("mipsnet: sending len=%d\n",s->tx_count);#endifqemu_send_packet(s->vc,s->tx_buffer,s->tx_count);s->tx_count=s->tx_written=0;s->intctl|=MIPSNET_INTCTL_TXDONE;s->busy=1;mipsnet_update_irq(s);}break;/* Read-only registers */caseMIPSNET_DEV_ID:caseMIPSNET_BUSY:caseMIPSNET_RX_DATA_COUNT:caseMIPSNET_INTERRUPT_INFO:caseMIPSNET_RX_DATA_BUFFER:default:break;}}staticvoidmipsnet_save(QEMUFile*f,void*opaque){MIPSnetState*s=opaque;qemu_put_be32s(f,&s->busy);qemu_put_be32s(f,&s->rx_count);qemu_put_be32s(f,&s->rx_read);qemu_put_be32s(f,&s->tx_count);qemu_put_be32s(f,&s->tx_written);qemu_put_be32s(f,&s->intctl);qemu_put_buffer(f,s->rx_buffer,MAX_ETH_FRAME_SIZE);qemu_put_buffer(f,s->tx_buffer,MAX_ETH_FRAME_SIZE);}staticintmipsnet_load(QEMUFile*f,void*opaque,intversion_id){MIPSnetState*s=opaque;if(version_id>0)return-EINVAL;qemu_get_be32s(f,&s->busy);qemu_get_be32s(f,&s->rx_count);qemu_get_be32s(f,&s->rx_read);qemu_get_be32s(f,&s->tx_count);qemu_get_be32s(f,&s->tx_written);qemu_get_be32s(f,&s->intctl);qemu_get_buffer(f,s->rx_buffer,MAX_ETH_FRAME_SIZE);qemu_get_buffer(f,s->tx_buffer,MAX_ETH_FRAME_SIZE);return0;}voidmipsnet_init(intbase,qemu_irqirq,NICInfo*nd){MIPSnetState*s;s=qemu_mallocz(sizeof(MIPSnetState));if(!s)return;register_ioport_write(base,36,1,mipsnet_ioport_write,s);register_ioport_read(base,36,1,mipsnet_ioport_read,s);register_ioport_write(base,36,2,mipsnet_ioport_write,s);register_ioport_read(base,36,2,mipsnet_ioport_read,s);register_ioport_write(base,36,4,mipsnet_ioport_write,s);register_ioport_read(base,36,4,mipsnet_ioport_read,s);s->irq=irq;s->nd=nd;if(nd&&nd->vlan){s->vc=qemu_new_vlan_client(nd->vlan,mipsnet_receive,mipsnet_can_receive,s);}else{s->vc=NULL;}snprintf(s->vc->info_str,sizeof(s->vc->info_str),"mipsnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x",s->nd->macaddr[0],s->nd->macaddr[1],s->nd->macaddr[2],s->nd->macaddr[3],s->nd->macaddr[4],s->nd->macaddr[5]);mipsnet_reset(s);register_savevm("mipsnet",0,0,mipsnet_save,mipsnet_load,s);}