?? rtl8139.c
字號:
uint32_t RxMissed; uint16_t CSCR; uint8_t Cfg9346; uint8_t Config0; uint8_t Config1; uint8_t Config3; uint8_t Config4; uint8_t Config5; uint8_t clock_enabled; uint8_t bChipCmdState; uint16_t MultiIntr; uint16_t BasicModeCtrl; uint16_t BasicModeStatus; uint16_t NWayAdvert; uint16_t NWayLPAR; uint16_t NWayExpansion; uint16_t CpCmd; uint8_t TxThresh; PCIDevice *pci_dev; VLANClientState *vc; uint8_t macaddr[6]; int rtl8139_mmio_io_addr; /* C ring mode */ uint32_t currTxDesc; /* C+ mode */ uint32_t currCPlusRxDesc; uint32_t currCPlusTxDesc; uint32_t RxRingAddrLO; uint32_t RxRingAddrHI; EEprom9346 eeprom; uint32_t TCTR; uint32_t TimerInt; int64_t TCTR_base; /* Tally counters */ RTL8139TallyCounters tally_counters; /* Non-persistent data */ uint8_t *cplus_txbuffer; int cplus_txbuffer_len; int cplus_txbuffer_offset; /* PCI interrupt timer */ QEMUTimer *timer;} RTL8139State;static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command){ DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command)); switch (command & Chip9346_op_mask) { case Chip9346_op_read: { eeprom->address = command & EEPROM_9346_ADDR_MASK; eeprom->output = eeprom->contents[eeprom->address]; eeprom->eedo = 0; eeprom->tick = 0; eeprom->mode = Chip9346_data_read; DEBUG_PRINT(("RTL8139: eeprom read from address 0x%02x data=0x%04x\n", eeprom->address, eeprom->output)); } break; case Chip9346_op_write: { eeprom->address = command & EEPROM_9346_ADDR_MASK; eeprom->input = 0; eeprom->tick = 0; eeprom->mode = Chip9346_none; /* Chip9346_data_write */ DEBUG_PRINT(("RTL8139: eeprom begin write to address 0x%02x\n", eeprom->address)); } break; default: eeprom->mode = Chip9346_none; switch (command & Chip9346_op_ext_mask) { case Chip9346_op_write_enable: DEBUG_PRINT(("RTL8139: eeprom write enabled\n")); break; case Chip9346_op_write_all: DEBUG_PRINT(("RTL8139: eeprom begin write all\n")); break; case Chip9346_op_write_disable: DEBUG_PRINT(("RTL8139: eeprom write disabled\n")); break; } break; }}static void prom9346_shift_clock(EEprom9346 *eeprom){ int bit = eeprom->eedi?1:0; ++ eeprom->tick; DEBUG_PRINT(("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo)); switch (eeprom->mode) { case Chip9346_enter_command_mode: if (bit) { eeprom->mode = Chip9346_read_command; eeprom->tick = 0; eeprom->input = 0; DEBUG_PRINT(("eeprom: +++ synchronized, begin command read\n")); } break; case Chip9346_read_command: eeprom->input = (eeprom->input << 1) | (bit & 1); if (eeprom->tick == 8) { prom9346_decode_command(eeprom, eeprom->input & 0xff); } break; case Chip9346_data_read: eeprom->eedo = (eeprom->output & 0x8000)?1:0; eeprom->output <<= 1; if (eeprom->tick == 16) {#if 1 // the FreeBSD drivers (rl and re) don't explicitly toggle // CS between reads (or does setting Cfg9346 to 0 count too?), // so we need to enter wait-for-command state here eeprom->mode = Chip9346_enter_command_mode; eeprom->input = 0; eeprom->tick = 0; DEBUG_PRINT(("eeprom: +++ end of read, awaiting next command\n"));#else // original behaviour ++eeprom->address; eeprom->address &= EEPROM_9346_ADDR_MASK; eeprom->output = eeprom->contents[eeprom->address]; eeprom->tick = 0; DEBUG_PRINT(("eeprom: +++ read next address 0x%02x data=0x%04x\n", eeprom->address, eeprom->output));#endif } break; case Chip9346_data_write: eeprom->input = (eeprom->input << 1) | (bit & 1); if (eeprom->tick == 16) { DEBUG_PRINT(("RTL8139: eeprom write to address 0x%02x data=0x%04x\n", eeprom->address, eeprom->input)); eeprom->contents[eeprom->address] = eeprom->input; eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */ eeprom->tick = 0; eeprom->input = 0; } break; case Chip9346_data_write_all: eeprom->input = (eeprom->input << 1) | (bit & 1); if (eeprom->tick == 16) { int i; for (i = 0; i < EEPROM_9346_SIZE; i++) { eeprom->contents[i] = eeprom->input; } DEBUG_PRINT(("RTL8139: eeprom filled with data=0x%04x\n", eeprom->input)); eeprom->mode = Chip9346_enter_command_mode; eeprom->tick = 0; eeprom->input = 0; } break; default: break; }}static int prom9346_get_wire(RTL8139State *s){ EEprom9346 *eeprom = &s->eeprom; if (!eeprom->eecs) return 0; return eeprom->eedo;}/* FIXME: This should be merged into/replaced by eeprom93xx.c. */static void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi){ EEprom9346 *eeprom = &s->eeprom; uint8_t old_eecs = eeprom->eecs; uint8_t old_eesk = eeprom->eesk; eeprom->eecs = eecs; eeprom->eesk = eesk; eeprom->eedi = eedi; DEBUG_PRINT(("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n", eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo)); if (!old_eecs && eecs) { /* Synchronize start */ eeprom->tick = 0; eeprom->input = 0; eeprom->output = 0; eeprom->mode = Chip9346_enter_command_mode; DEBUG_PRINT(("=== eeprom: begin access, enter command mode\n")); } if (!eecs) { DEBUG_PRINT(("=== eeprom: end access\n")); return; } if (!old_eesk && eesk) { /* SK front rules */ prom9346_shift_clock(eeprom); }}static void rtl8139_update_irq(RTL8139State *s){ int isr; isr = (s->IntrStatus & s->IntrMask) & 0xffff; DEBUG_PRINT(("RTL8139: Set IRQ to %d (%04x %04x)\n", isr ? 1 : 0, s->IntrStatus, s->IntrMask)); qemu_set_irq(s->pci_dev->irq[0], (isr != 0));}#define POLYNOMIAL 0x04c11db6/* From FreeBSD *//* XXX: optimize */static int compute_mcast_idx(const uint8_t *ep){ uint32_t crc; int carry, i, j; uint8_t b; crc = 0xffffffff; for (i = 0; i < 6; i++) { b = *ep++; for (j = 0; j < 8; j++) { carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); crc <<= 1; b >>= 1; if (carry) crc = ((crc ^ POLYNOMIAL) | carry); } } return (crc >> 26);}static int rtl8139_RxWrap(RTL8139State *s){ /* wrapping enabled; assume 1.5k more buffer space if size < 65536 */ return (s->RxConfig & (1 << 7));}static int rtl8139_receiver_enabled(RTL8139State *s){ return s->bChipCmdState & CmdRxEnb;}static int rtl8139_transmitter_enabled(RTL8139State *s){ return s->bChipCmdState & CmdTxEnb;}static int rtl8139_cp_receiver_enabled(RTL8139State *s){ return s->CpCmd & CPlusRxEnb;}static int rtl8139_cp_transmitter_enabled(RTL8139State *s){ return s->CpCmd & CPlusTxEnb;}static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size){ if (s->RxBufAddr + size > s->RxBufferSize) { int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize); /* write packet data */ if (wrapped && !(s->RxBufferSize < 65536 && rtl8139_RxWrap(s))) { DEBUG_PRINT((">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped)); if (size > wrapped) { cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, buf, size-wrapped ); } /* reset buffer pointer */ s->RxBufAddr = 0; cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, buf + (size-wrapped), wrapped ); s->RxBufAddr = wrapped; return; } } /* non-wrapping path or overwrapping enabled */ cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, buf, size ); s->RxBufAddr += size;}#define MIN_BUF_SIZE 60static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high){#if TARGET_PHYS_ADDR_BITS > 32 return low | ((target_phys_addr_t)high << 32);#else return low;#endif}static int rtl8139_can_receive(void *opaque){ RTL8139State *s = opaque; int avail; /* Receive (drop) packets if card is disabled. */ if (!s->clock_enabled) return 1; if (!rtl8139_receiver_enabled(s)) return 1; if (rtl8139_cp_receiver_enabled(s)) { /* ??? Flow control not implemented in c+ mode. This is a hack to work around slirp deficiencies anyway. */ return 1; } else { avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize); return (avail == 0 || avail >= 1514); }}static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int do_interrupt){ RTL8139State *s = opaque; uint32_t packet_header = 0; uint8_t buf1[60]; static const uint8_t broadcast_macaddr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; DEBUG_PRINT((">>> RTL8139: received len=%d\n", size)); /* test if board clock is stopped */ if (!s->clock_enabled) { DEBUG_PRINT(("RTL8139: stopped ==========================\n")); return; } /* first check if receiver is enabled */ if (!rtl8139_receiver_enabled(s)) { DEBUG_PRINT(("RTL8139: receiver disabled ================\n")); return; } /* XXX: check this */ if (s->RxConfig & AcceptAllPhys) { /* promiscuous: receive all */ DEBUG_PRINT((">>> RTL8139: packet received in promiscuous mode\n")); } else { if (!memcmp(buf, broadcast_macaddr, 6)) { /* broadcast address */ if (!(s->RxConfig & AcceptBroadcast)) { DEBUG_PRINT((">>> RTL8139: broadcast packet rejected\n")); /* update tally counter */ ++s->tally_counters.RxERR; return; } packet_header |= RxBroadcast; DEBUG_PRINT((">>> RTL8139: broadcast packet received\n")); /* update tally counter */ ++s->tally_counters.RxOkBrd; } else if (buf[0] & 0x01) { /* multicast */ if (!(s->RxConfig & AcceptMulticast)) { DEBUG_PRINT((">>> RTL8139: multicast packet rejected\n")); /* update tally counter */ ++s->tally_counters.RxERR; return; } int mcast_idx = compute_mcast_idx(buf); if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) {
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -