static void rtl8139_dumptxstate(rtl8139 *rtl) { dprintf("tx state:\n"); dprintf("\ttxbn %d\n", rtl->txbn); dprintf("\ttxstatus 0 0x%x\n", RTL_READ_32(rtl, RT_TXSTATUS0)); dprintf("\ttxstatus 1 0x%x\n", RTL_READ_32(rtl, RT_TXSTATUS1)); dprintf("\ttxstatus 2 0x%x\n", RTL_READ_32(rtl, RT_TXSTATUS2)); dprintf("\ttxstatus 3 0x%x\n", RTL_READ_32(rtl, RT_TXSTATUS3)); }
static void rhine_dumptxstate(rhine *r) { PANIC_UNIMPLEMENTED(); #if 0 dprintf("tx state:\n"); dprintf("\ttxbn %d\n", r->txbn); dprintf("\ttxstatus 0 0x%x\n", RTL_READ_32(r, RT_TXSTATUS0)); dprintf("\ttxstatus 1 0x%x\n", RTL_READ_32(r, RT_TXSTATUS1)); dprintf("\ttxstatus 2 0x%x\n", RTL_READ_32(r, RT_TXSTATUS2)); dprintf("\ttxstatus 3 0x%x\n", RTL_READ_32(r, RT_TXSTATUS3)); #endif }
static int rhine_txint(rhine *r, uint16 int_status) { PANIC_UNIMPLEMENTED(); #if 0 uint32 txstat; int i; int rc = INT_NO_RESCHEDULE; // transmit ok // dprintf("tx %d\n", int_status); if(int_status & RT_INT_TX_ERR) { dprintf("err tx int:\n"); rhine_dumptxstate(r); } for(i=0; i<4; i++) { if(i > 0 && r->last_txbn == r->txbn) break; txstat = RTL_READ_32(r, RT_TXSTATUS0 + r->last_txbn*4); // dprintf("txstat[%d] = 0x%x\n", r->last_txbn, txstat); if((txstat & (RT_TX_STATUS_OK | RT_TX_UNDERRUN | RT_TX_ABORTED)) == 0) break; if(++r->last_txbn >= 4) r->last_txbn = 0; sem_release_etc(r->tx_sem, 1, SEM_FLAG_NO_RESCHED); rc = INT_RESCHEDULE; } return rc; #endif }
static int rtl8139_txint(rtl8139 *rtl, uint16 int_status) { uint32 txstat; int i; int rc = INT_NO_RESCHEDULE; // transmit ok // dprintf("tx %d\n", int_status); if(int_status & RT_INT_TX_ERR) { dprintf("err tx int:\n"); rtl8139_dumptxstate(rtl); } for(i=0; i<4; i++) { if(i > 0 && rtl->last_txbn == rtl->txbn) break; txstat = RTL_READ_32(rtl, RT_TXSTATUS0 + rtl->last_txbn*4); // dprintf("txstat[%d] = 0x%x\n", rtl->last_txbn, txstat); if((txstat & (RT_TX_STATUS_OK | RT_TX_UNDERRUN | RT_TX_ABORTED)) == 0) break; if(++rtl->last_txbn >= 4) rtl->last_txbn = 0; sem_release_etc(rtl->tx_sem, 1, SEM_FLAG_NO_RESCHED); rc = INT_RESCHEDULE; } return rc; }
void rhine_xmit(rhine *r, const char *ptr, ssize_t len) { #if 0 PANIC_UNIMPLEMENTED(); #if 0 int i; #endif //restart: sem_acquire(r->tx_sem, 1); mutex_lock(&r->lock); #if 0 dprintf("XMIT %d %x (%d)\n",r->txbn, ptr, len); dprintf("dumping packet:"); for(i=0; i<len; i++) { if(i%8 == 0) dprintf("\n"); dprintf("0x%02x ", ptr[i]); } dprintf("\n"); #endif int_disable_interrupts(); acquire_spinlock(&r->reg_spinlock); #if 0 /* wait for clear-to-send */ if(!(RTL_READ_32(r, RT_TXSTATUS0 + r->txbn*4) & RT_TX_HOST_OWNS)) { dprintf("rhine_xmit: no txbuf free\n"); rhine_dumptxstate(r); release_spinlock(&r->reg_spinlock); int_restore_interrupts(); mutex_unlock(&r->lock); sem_release(r->tx_sem, 1); goto restart; } #endif memcpy((void*)(r->txbuf + r->txbn * 0x800), ptr, len); if(len < ETHERNET_MIN_SIZE) len = ETHERNET_MIN_SIZE; RTL_WRITE_32(r, RT_TXSTATUS0 + r->txbn*4, len | 0x80000); if(++r->txbn >= 4) r->txbn = 0; release_spinlock(&r->reg_spinlock); int_restore_interrupts(); mutex_unlock(&r->lock); #endif }
static int rtl8139_int(void* data) { int rc = INT_NO_RESCHEDULE; rtl8139 *rtl = (rtl8139 *)data; acquire_spinlock(&rtl->reg_spinlock); // Disable interrupts RTL_WRITE_16(rtl, RT_INTRMASK, 0); for(;;) { uint16 status = RTL_READ_16(rtl, RT_INTRSTATUS); if(status) RTL_WRITE_16(rtl, RT_INTRSTATUS, status); else break; if(status & RT_INT_TX_OK || status & RT_INT_TX_ERR) { if(rtl8139_txint(rtl, status) == INT_RESCHEDULE) rc = INT_RESCHEDULE; } if(status & RT_INT_RX_ERR || status & RT_INT_RX_OK) { if(rtl8139_rxint(rtl, status) == INT_RESCHEDULE) rc = INT_RESCHEDULE; } if(status & RT_INT_RXBUF_OVERFLOW) { dprintf("RX buffer overflow!\n"); dprintf("buf 0x%x, head 0x%x, tail 0x%x\n", RTL_READ_32(rtl, RT_RXBUF), RTL_READ_16(rtl, RT_RXBUFHEAD), RTL_READ_16(rtl, RT_RXBUFTAIL)); RTL_WRITE_32(rtl, RT_RXMISSED, 0); RTL_WRITE_16(rtl, RT_RXBUFTAIL, TAIL_TO_TAILREG(RTL_READ_16(rtl, RT_RXBUFHEAD))); } if(status & RT_INT_RXFIFO_OVERFLOW) { dprintf("RX fifo overflow!\n"); } if(status & RT_INT_RXFIFO_UNDERRUN) { dprintf("RX fifo underrun\n"); } } // reenable interrupts RTL_WRITE_16(rtl, RT_INTRMASK, MYRT_INTS); release_spinlock(&rtl->reg_spinlock); return rc; }
static int rhine_int(void* data) { int rc = INT_NO_RESCHEDULE; rhine *r = (rhine *)data; uint16 istat; acquire_spinlock(&r->reg_spinlock); istat = RHINE_READ_16(r, RHINE_ISR0); dprintf("rhine_int: istat 0x%x\n", istat); if (istat == 0) goto done; if (istat & 0x1) { // packet received with no errors dprintf("packet received: status 0x%x, framelen 0x%x\n", RXDESC(r, r->rx_head).status, RXDESC(r, r->rx_head).framelen); r->rx_head++; } RHINE_WRITE_16(r, RHINE_ISR0, istat); #if 0 // Disable interrupts RTL_WRITE_16(r, RT_INTRMASK, 0); for(;;) { uint16 status = RTL_READ_16(r, RT_INTRSTATUS); if(status) RTL_WRITE_16(r, RT_INTRSTATUS, status); else break; if(status & RT_INT_TX_OK || status & RT_INT_TX_ERR) { if(rhine_txint(r, status) == INT_RESCHEDULE) rc = INT_RESCHEDULE; } if(status & RT_INT_RX_ERR || status & RT_INT_RX_OK) { if(rhine_rxint(r, status) == INT_RESCHEDULE) rc = INT_RESCHEDULE; } if(status & RT_INT_RXBUF_OVERFLOW) { dprintf("RX buffer overflow!\n"); dprintf("buf 0x%x, head 0x%x, tail 0x%x\n", RTL_READ_32(r, RT_RXBUF), RTL_READ_16(r, RT_RXBUFHEAD), RTL_READ_16(r, RT_RXBUFTAIL)); RTL_WRITE_32(r, RT_RXMISSED, 0); RTL_WRITE_16(r, RT_RXBUFTAIL, TAIL_TO_TAILREG(RTL_READ_16(r, RT_RXBUFHEAD))); } if(status & RT_INT_RXFIFO_OVERFLOW) { dprintf("RX fifo overflow!\n"); } if(status & RT_INT_RXFIFO_UNDERRUN) { dprintf("RX fifo underrun\n"); } } // reenable interrupts RTL_WRITE_16(r, RT_INTRMASK, MYRT_INTS); #endif done: release_spinlock(&r->reg_spinlock); return rc; }
int rhine_init(rhine *r) { bigtime_t time; int err = -1; addr_t temp; int i; dprintf("rhine_init: r %p\n", r); r->region = vm_map_physical_memory(vm_get_kernel_aspace_id(), "rhine_region", (void **)&r->virt_base, REGION_ADDR_ANY_ADDRESS, r->phys_size, LOCK_KERNEL|LOCK_RW, r->phys_base); if(r->region < 0) { dprintf("rhine_init: error creating memory mapped region\n"); err = -1; goto err; } dprintf("rhine mapped at address 0x%lx\n", r->virt_base); /* create regions for tx and rx descriptors */ r->rxdesc_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "rhine_rxdesc", (void **)&r->rxdesc, REGION_ADDR_ANY_ADDRESS, RXDESC_COUNT * sizeof(struct rhine_rx_desc), REGION_WIRING_WIRED_CONTIG, LOCK_KERNEL|LOCK_RW); r->rxdesc_phys = vtophys(r->rxdesc); dprintf("rhine: rx descriptors at %p, phys 0x%x\n", r->rxdesc, r->rxdesc_phys); r->txdesc_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "rhine_txdesc", (void **)&r->txdesc, REGION_ADDR_ANY_ADDRESS, TXDESC_COUNT * sizeof(struct rhine_tx_desc), REGION_WIRING_WIRED_CONTIG, LOCK_KERNEL|LOCK_RW); r->txdesc_phys = vtophys(r->txdesc); dprintf("rhine: tx descriptors at %p, phys 0x%x\n", r->txdesc, r->txdesc_phys); r->reg_spinlock = 0; /* stick all rx and tx buffers in a circular buffer */ for (i=0; i < RXDESC_COUNT; i++) { RXDESC(r, i).status = 0; RXDESC(r, i).framelen = 0; RXDESC(r, i).buflen = 0; RXDESC(r, i).ptr = 0; if (i == RXDESC_COUNT-1) RXDESC(r, i).next = RXDESC_PHYS(r, 0); else RXDESC(r, i).next = RXDESC_PHYS(r, i + 1); } // XXX do same for tx r->rx_head = r->rx_tail = 0; /* reset the chip */ time = system_time(); RHINE_WRITE_16(r, RHINE_CR0, 0x8000); // reset the chip do { thread_snooze(10000); // 10ms if(system_time() - time > 1000000) { break; } } while(RHINE_READ_16(r, RHINE_CR0) & 0x8000); if (RHINE_READ_16(r, RHINE_CR0) & 0x8000) { dprintf("chip didn't reset, trying alternate method\n"); RHINE_SETBITS_8(r, RHINE_MISC_CR1, 0x40); thread_snooze(10000); } /* read in the mac address */ RHINE_WRITE_8(r, RHINE_EECSR, RHINE_READ_8(r, RHINE_EECSR) | (1<<5)); r->mac_addr[0] = RHINE_READ_8(r, RHINE_PAR0); r->mac_addr[1] = RHINE_READ_8(r, RHINE_PAR1); r->mac_addr[2] = RHINE_READ_8(r, RHINE_PAR2); r->mac_addr[3] = RHINE_READ_8(r, RHINE_PAR3); r->mac_addr[4] = RHINE_READ_8(r, RHINE_PAR4); r->mac_addr[5] = RHINE_READ_8(r, RHINE_PAR5); dprintf("rhine: mac addr %x:%x:%x:%x:%x:%x\n", r->mac_addr[0], r->mac_addr[1], r->mac_addr[2], r->mac_addr[3], r->mac_addr[4], r->mac_addr[5]); /* set up the rx state */ /* 64 byte fifo threshold, all physical/broadcast/multicast/small/error packets accepted */ RHINE_WRITE_8(r, RHINE_RCR, (0<<5) | (1<<4) | (1<<3) | (1<<2) | (1<<1) | (1<<0)); RHINE_WRITE_32(r, RHINE_RDA0, RXDESC_PHYS(r, r->rx_head)); /* set up tx state */ /* 64 byte fifo, default backup, default loopback mode */ RHINE_WRITE_8(r, RHINE_TCR, 0); /* mask all interrupts */ RHINE_WRITE_16(r, RHINE_IMR0, 0); /* clear all pending interrupts */ RHINE_WRITE_16(r, RHINE_ISR0, 0xffff); /* set up the interrupt handler */ int_set_io_interrupt_handler(r->irq, &rhine_int, r, "rhine"); { static uint8 buf[2048]; RXDESC(r, r->rx_tail).ptr = vtophys(buf); RXDESC(r, r->rx_tail).buflen = sizeof(buf); RXDESC(r, r->rx_tail).status = 0; RXDESC(r, r->rx_tail).framelen = RHINE_RX_OWNER; r->rx_tail++; RHINE_WRITE_16(r, RHINE_CR0, (1<<1) | (1<<3) | (1<<6)); } /* unmask all interrupts */ RHINE_WRITE_16(r, RHINE_IMR0, 0xffff); #if 0 // try to reset the device time = system_time(); RTL_WRITE_8(r, RT_CHIPCMD, RT_CMD_RESET); do { thread_snooze(10000); // 10ms if(system_time() - time > 1000000) { err = -1; goto err1; } } while((RTL_READ_8(r, RT_CHIPCMD) & RT_CMD_RESET)); // create a rx and tx buf r->rxbuf_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "rhine_rxbuf", (void **)&r->rxbuf, REGION_ADDR_ANY_ADDRESS, 64*1024 + 16, REGION_WIRING_WIRED_CONTIG, LOCK_KERNEL|LOCK_RW); r->txbuf_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "rhine_txbuf", (void **)&r->txbuf, REGION_ADDR_ANY_ADDRESS, 8*1024, REGION_WIRING_WIRED, LOCK_KERNEL|LOCK_RW); // set up the transmission buf and sem r->tx_sem = sem_create(4, "rhine_txsem"); mutex_init(&r->lock, "rhine"); r->txbn = 0; r->last_txbn = 0; r->rx_sem = sem_create(0, "rhine_rxsem"); r->reg_spinlock = 0; // set up the interrupt handler int_set_io_interrupt_handler(r->irq, &rhine_int, r, "rhine"); // read the mac address r->mac_addr[0] = RTL_READ_8(r, RT_IDR0); r->mac_addr[1] = RTL_READ_8(r, RT_IDR0 + 1); r->mac_addr[2] = RTL_READ_8(r, RT_IDR0 + 2); r->mac_addr[3] = RTL_READ_8(r, RT_IDR0 + 3); r->mac_addr[4] = RTL_READ_8(r, RT_IDR0 + 4); r->mac_addr[5] = RTL_READ_8(r, RT_IDR0 + 5); dprintf("rhine: mac addr %x:%x:%x:%x:%x:%x\n", r->mac_addr[0], r->mac_addr[1], r->mac_addr[2], r->mac_addr[3], r->mac_addr[4], r->mac_addr[5]); // enable writing to the config registers RTL_WRITE_8(r, RT_CFG9346, 0xc0); // reset config 1 RTL_WRITE_8(r, RT_CONFIG1, 0); // Enable receive and transmit functions RTL_WRITE_8(r, RT_CHIPCMD, RT_CMD_RX_ENABLE | RT_CMD_TX_ENABLE); // Set Rx FIFO threashold to 256, Rx size to 64k+16, 256 byte DMA burst RTL_WRITE_32(r, RT_RXCONFIG, 0x00009c00); // Set Tx 256 byte DMA burst RTL_WRITE_32(r, RT_TXCONFIG, 0x03000400); // Turn off lan-wake and set the driver-loaded bit RTL_WRITE_8(r, RT_CONFIG1, (RTL_READ_8(r, RT_CONFIG1) & ~0x30) | 0x20); // Enable FIFO auto-clear RTL_WRITE_8(r, RT_CONFIG4, RTL_READ_8(r, RT_CONFIG4) | 0x80); // go back to normal mode RTL_WRITE_8(r, RT_CFG9346, 0); // Setup RX buffers *(int *)r->rxbuf = 0; vm_get_page_mapping(vm_get_kernel_aspace_id(), r->rxbuf, &temp); dprintf("rx buffer will be at 0x%lx\n", temp); RTL_WRITE_32(r, RT_RXBUF, temp); // Setup TX buffers dprintf("tx buffer (virtual) is at 0x%lx\n", r->txbuf); *(int *)r->txbuf = 0; vm_get_page_mapping(vm_get_kernel_aspace_id(), r->txbuf, &temp); RTL_WRITE_32(r, RT_TXADDR0, temp); RTL_WRITE_32(r, RT_TXADDR1, temp + 2*1024); dprintf("first half of txbuf at 0x%lx\n", temp); *(int *)(r->txbuf + 4*1024) = 0; vm_get_page_mapping(vm_get_kernel_aspace_id(), r->txbuf + 4*1024, &temp); RTL_WRITE_32(r, RT_TXADDR2, temp); RTL_WRITE_32(r, RT_TXADDR3, temp + 2*1024); dprintf("second half of txbuf at 0x%lx\n", temp); /* RTL_WRITE_32(r, RT_TXSTATUS0, RTL_READ_32(r, RT_TXSTATUS0) | 0xfffff000); RTL_WRITE_32(r, RT_TXSTATUS1, RTL_READ_32(r, RT_TXSTATUS1) | 0xfffff000); RTL_WRITE_32(r, RT_TXSTATUS2, RTL_READ_32(r, RT_TXSTATUS2) | 0xfffff000); RTL_WRITE_32(r, RT_TXSTATUS3, RTL_READ_32(r, RT_TXSTATUS3) | 0xfffff000); */ // Reset RXMISSED counter RTL_WRITE_32(r, RT_RXMISSED, 0); // Enable receiving broadcast and physical match packets // RTL_WRITE_32(r, RT_RXCONFIG, RTL_READ_32(r, RT_RXCONFIG) | 0x0000000a); RTL_WRITE_32(r, RT_RXCONFIG, RTL_READ_32(r, RT_RXCONFIG) | 0x0000000f); // Filter out all multicast packets RTL_WRITE_32(r, RT_MAR0, 0); RTL_WRITE_32(r, RT_MAR0 + 4, 0); // Disable all multi-interrupts RTL_WRITE_16(r, RT_MULTIINTR, 0); RTL_WRITE_16(r, RT_INTRMASK, MYRT_INTS); // RTL_WRITE_16(r, RT_INTRMASK, 0x807f); // Enable RX/TX once more RTL_WRITE_8(r, RT_CHIPCMD, RT_CMD_RX_ENABLE | RT_CMD_TX_ENABLE); RTL_WRITE_8(r, RT_CFG9346, 0); #endif return 0; err1: vm_delete_region(vm_get_kernel_aspace_id(), r->region); err: return err; }
static int rtl8169_init(rtl8169 *r) { //bigtime_t time; int err = -1; //addr_t temp; //int i; hal_mutex_init(&r->lock,DEBUG_MSG_PREFIX); SHOW_FLOW(2, "rtl8169_init: r %p\n", r); /* r->region = vm_map_physical_memory(vm_get_kernel_aspace_id(), "rtl8169_region", (void **)&r->virt_base, REGION_ADDR_ANY_ADDRESS, r->phys_size, LOCK_KERNEL|LOCK_RW, r->phys_base); if(r->region < 0) { SHOW_ERROR0(1, "rtl8169_init: error creating memory mapped region\n"); err = -1; goto err; }*/ size_t n_pages = BYTES_TO_PAGES(r->phys_size); hal_alloc_vaddress( (void **)&r->virt_base, n_pages); // alloc address of a page, but not memory hal_pages_control_etc( r->phys_base, (void *)r->virt_base, n_pages, page_map_io, page_rw, 0 ); SHOW_INFO(2, "rtl8169 mapped at address 0x%lx\n", r->virt_base); #if 0 /* create regions for tx and rx descriptors */ r->rxdesc_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "rtl8169_rxdesc", (void **)&r->rxdesc, REGION_ADDR_ANY_ADDRESS, NUM_RX_DESCRIPTORS * DESCRIPTOR_LEN, REGION_WIRING_WIRED_CONTIG, LOCK_KERNEL|LOCK_RW); r->rxdesc_phys = vtophys(r->rxdesc); SHOW_INFO(2, "rtl8169: rx descriptors at %p, phys 0x%x\n", r->rxdesc, r->rxdesc_phys); r->txdesc_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "rtl8169_txdesc", (void **)&r->txdesc, REGION_ADDR_ANY_ADDRESS, NUM_TX_DESCRIPTORS * DESCRIPTOR_LEN, REGION_WIRING_WIRED_CONTIG, LOCK_KERNEL|LOCK_RW); r->txdesc_phys = vtophys(r->txdesc); SHOW_INFO(2, "rtl8169: tx descriptors at %p, phys 0x%x\n", r->txdesc, r->txdesc_phys); r->reg_spinlock = 0; /* create a large tx and rx buffer for the descriptors to point to */ r->rxbuf_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "rtl8169_rxbuf", (void **)&r->rxbuf, REGION_ADDR_ANY_ADDRESS, NUM_RX_DESCRIPTORS * BUFSIZE_PER_FRAME, REGION_WIRING_WIRED, LOCK_KERNEL|LOCK_RW); r->txbuf_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "rtl8169_txbuf", (void **)&r->txbuf, REGION_ADDR_ANY_ADDRESS, NUM_TX_DESCRIPTORS * BUFSIZE_PER_FRAME, REGION_WIRING_WIRED, LOCK_KERNEL|LOCK_RW); #endif hal_pv_alloc( &r->rxdesc_phys, (void**)&r->rxdesc, NUM_RX_DESCRIPTORS * DESCRIPTOR_LEN ); hal_pv_alloc( &r->txdesc_phys, (void**)&r->txdesc, NUM_TX_DESCRIPTORS * DESCRIPTOR_LEN ); SHOW_INFO(2, "rx descriptors at %p, phys 0x%x\n", r->rxdesc, r->rxdesc_phys); SHOW_INFO(2, "tx descriptors at %p, phys 0x%x\n", r->txdesc, r->txdesc_phys); hal_pv_alloc( &r->rxbuf_phys, (void**)&r->rxbuf, NUM_RX_DESCRIPTORS * BUFSIZE_PER_FRAME ); hal_pv_alloc( &r->txbuf_phys, (void**)&r->txbuf, NUM_TX_DESCRIPTORS * BUFSIZE_PER_FRAME ); /* create a receive sem */ hal_sem_init( &r->rx_sem, "rtl8169 rx_sem"); /* transmit sem */ hal_sem_init( &r->tx_sem, "rtl8169 tx_sem"); /* reset the chip */ int repeats = 100; RTL_WRITE_8(r, REG_CR, (1<<4)); // reset the chip, disable tx/rx do { hal_sleep_msec(10); // 10ms if(repeats -- <= 0 ) break; } while(RTL_READ_8(r, REG_CR) & (1<<4)); /* read in the mac address */ r->mac_addr[0] = RTL_READ_8(r, REG_IDR0); r->mac_addr[1] = RTL_READ_8(r, REG_IDR1); r->mac_addr[2] = RTL_READ_8(r, REG_IDR2); r->mac_addr[3] = RTL_READ_8(r, REG_IDR3); r->mac_addr[4] = RTL_READ_8(r, REG_IDR4); r->mac_addr[5] = RTL_READ_8(r, REG_IDR5); SHOW_INFO(2, "rtl8169: mac addr %x:%x:%x:%x:%x:%x\n", r->mac_addr[0], r->mac_addr[1], r->mac_addr[2], r->mac_addr[3], r->mac_addr[4], r->mac_addr[5]); /* some voodoo from BSD driver */ RTL_WRITE_16(r, REG_CCR, RTL_READ_16(r, REG_CCR)); RTL_SETBITS_16(r, REG_CCR, 0x3); /* mask all interrupts */ RTL_WRITE_16(r, REG_IMR, 0); /* set up the tx/rx descriptors */ rtl8169_setup_descriptors(r); /* enable tx/rx */ RTL_SETBITS_8(r, REG_CR, (1<<3)|(1<<2)); /* set up the rx state */ /* 1024 byte dma threshold, 1024 dma max burst, CRC calc 8 byte+, accept all packets */ RTL_WRITE_32(r, REG_RCR, (1<<16) | (6<<13) | (6<<8) | (0xf << 0)); RTL_SETBITS_16(r, REG_CCR, (1<<5)); // rx checksum enable RTL_WRITE_16(r, REG_RMS, 1518); // rx mtu /* set up the tx state */ RTL_WRITE_32(r, REG_TCR, (RTL_READ_32(r, REG_TCR) & ~0x1ff) | (6<<8)); // 1024 max burst dma RTL_WRITE_8(r, REG_MTPS, 0x3f); // max tx packet size (must be careful to not actually transmit more than mtu) /* set up the interrupt handler */ //int_set_io_interrupt_handler(r->irq, &rtl8169_int, r, "rtl8169"); if(hal_irq_alloc( r->irq, &rtl8169_int, r, HAL_IRQ_SHAREABLE )) { SHOW_ERROR( 0, "unable to allocate irq %d", r->irq ); goto err1; } /* clear all pending interrupts */ RTL_WRITE_16(r, REG_ISR, 0xffff); /* unmask interesting interrupts */ RTL_WRITE_16(r, REG_IMR, IMR_SYSERR | IMR_LINKCHG | IMR_TER | IMR_TOK | IMR_RER | IMR_ROK | IMR_RXOVL); return 0; err1: // TODO free what? //vm_delete_region(vm_get_kernel_aspace_id(), r->region); //err: return err; }
int rtl8169_init(rtl8169 *r) { bigtime_t time; int err = -1; addr_t temp; int i; SHOW_FLOW(2, "rtl8169_init: r %p\n", r); r->region = vm_map_physical_memory(vm_get_kernel_aspace_id(), "rtl8169_region", (void **)&r->virt_base, REGION_ADDR_ANY_ADDRESS, r->phys_size, LOCK_KERNEL|LOCK_RW, r->phys_base); if(r->region < 0) { SHOW_ERROR0(1, "rtl8169_init: error creating memory mapped region\n"); err = -1; goto err; } SHOW_INFO(2, "rtl8169 mapped at address 0x%lx\n", r->virt_base); /* create regions for tx and rx descriptors */ r->rxdesc_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "rtl8169_rxdesc", (void **)&r->rxdesc, REGION_ADDR_ANY_ADDRESS, NUM_RX_DESCRIPTORS * DESCRIPTOR_LEN, REGION_WIRING_WIRED_CONTIG, LOCK_KERNEL|LOCK_RW); r->rxdesc_phys = vtophys(r->rxdesc); SHOW_INFO(2, "rtl8169: rx descriptors at %p, phys 0x%x\n", r->rxdesc, r->rxdesc_phys); r->txdesc_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "rtl8169_txdesc", (void **)&r->txdesc, REGION_ADDR_ANY_ADDRESS, NUM_TX_DESCRIPTORS * DESCRIPTOR_LEN, REGION_WIRING_WIRED_CONTIG, LOCK_KERNEL|LOCK_RW); r->txdesc_phys = vtophys(r->txdesc); SHOW_INFO(2, "rtl8169: tx descriptors at %p, phys 0x%x\n", r->txdesc, r->txdesc_phys); r->reg_spinlock = 0; /* create a large tx and rx buffer for the descriptors to point to */ r->rxbuf_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "rtl8169_rxbuf", (void **)&r->rxbuf, REGION_ADDR_ANY_ADDRESS, NUM_RX_DESCRIPTORS * BUFSIZE_PER_FRAME, REGION_WIRING_WIRED, LOCK_KERNEL|LOCK_RW); r->txbuf_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "rtl8169_txbuf", (void **)&r->txbuf, REGION_ADDR_ANY_ADDRESS, NUM_TX_DESCRIPTORS * BUFSIZE_PER_FRAME, REGION_WIRING_WIRED, LOCK_KERNEL|LOCK_RW); /* create a receive sem */ r->rx_sem = sem_create(0, "rtl8169 rx_sem"); /* transmit sem */ r->tx_sem = sem_create(1, "rtl8169 tx_sem"); /* reset the chip */ time = system_time(); RTL_WRITE_8(r, REG_CR, (1<<4)); // reset the chip, disable tx/rx do { thread_snooze(10000); // 10ms if(system_time() - time > 1000000) { break; } } while(RTL_READ_8(r, REG_CR) & (1<<4)); /* read in the mac address */ r->mac_addr[0] = RTL_READ_8(r, REG_IDR0); r->mac_addr[1] = RTL_READ_8(r, REG_IDR1); r->mac_addr[2] = RTL_READ_8(r, REG_IDR2); r->mac_addr[3] = RTL_READ_8(r, REG_IDR3); r->mac_addr[4] = RTL_READ_8(r, REG_IDR4); r->mac_addr[5] = RTL_READ_8(r, REG_IDR5); SHOW_INFO(2, "rtl8169: mac addr %x:%x:%x:%x:%x:%x\n", r->mac_addr[0], r->mac_addr[1], r->mac_addr[2], r->mac_addr[3], r->mac_addr[4], r->mac_addr[5]); /* some voodoo from BSD driver */ RTL_WRITE_16(r, REG_CCR, RTL_READ_16(r, REG_CCR)); RTL_SETBITS_16(r, REG_CCR, 0x3); /* mask all interrupts */ RTL_WRITE_16(r, REG_IMR, 0); /* set up the tx/rx descriptors */ rtl8169_setup_descriptors(r); /* enable tx/rx */ RTL_SETBITS_8(r, REG_CR, (1<<3)|(1<<2)); /* set up the rx state */ /* 1024 byte dma threshold, 1024 dma max burst, CRC calc 8 byte+, accept all packets */ RTL_WRITE_32(r, REG_RCR, (1<<16) | (6<<13) | (6<<8) | (0xf << 0)); RTL_SETBITS_16(r, REG_CCR, (1<<5)); // rx checksum enable RTL_WRITE_16(r, REG_RMS, 1518); // rx mtu /* set up the tx state */ RTL_WRITE_32(r, REG_TCR, (RTL_READ_32(r, REG_TCR) & ~0x1ff) | (6<<8)); // 1024 max burst dma RTL_WRITE_8(r, REG_MTPS, 0x3f); // max tx packet size (must be careful to not actually transmit more than mtu) /* set up the interrupt handler */ int_set_io_interrupt_handler(r->irq, &rtl8169_int, r, "rtl8169"); /* clear all pending interrupts */ RTL_WRITE_16(r, REG_ISR, 0xffff); /* unmask interesting interrupts */ RTL_WRITE_16(r, REG_IMR, IMR_SYSERR | IMR_LINKCHG | IMR_TER | IMR_TOK | IMR_RER | IMR_ROK | IMR_RXOVL); return 0; err1: vm_delete_region(vm_get_kernel_aspace_id(), r->region); err: return err; }
int rtl8139_init(rtl8139 *rtl) { bigtime_t time; int err = -1; addr_t temp; dprintf("rtl8139_init: rtl %p\n", rtl); rtl->region = vm_map_physical_memory(vm_get_kernel_aspace_id(), "rtl8139_region", (void **)&rtl->virt_base, REGION_ADDR_ANY_ADDRESS, rtl->phys_size, LOCK_KERNEL|LOCK_RW, rtl->phys_base); if(rtl->region < 0) { dprintf("rtl8139_init: error creating memory mapped region\n"); err = -1; goto err; } dprintf("rtl8139 mapped at address 0x%lx\n", rtl->virt_base); // try to reset the device time = system_time(); RTL_WRITE_8(rtl, RT_CHIPCMD, RT_CMD_RESET); do { thread_snooze(10000); // 10ms if(system_time() - time > 1000000) { err = -1; goto err1; } } while((RTL_READ_8(rtl, RT_CHIPCMD) & RT_CMD_RESET)); // create a rx and tx buf rtl->rxbuf_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "rtl8139_rxbuf", (void **)&rtl->rxbuf, REGION_ADDR_ANY_ADDRESS, 64*1024 + 16, REGION_WIRING_WIRED_CONTIG, LOCK_KERNEL|LOCK_RW); rtl->txbuf_region = vm_create_anonymous_region(vm_get_kernel_aspace_id(), "rtl8139_txbuf", (void **)&rtl->txbuf, REGION_ADDR_ANY_ADDRESS, 8*1024, REGION_WIRING_WIRED, LOCK_KERNEL|LOCK_RW); // set up the transmission buf and sem rtl->tx_sem = sem_create(4, "rtl8139_txsem"); mutex_init(&rtl->lock, "rtl8139"); rtl->txbn = 0; rtl->last_txbn = 0; rtl->rx_sem = sem_create(0, "rtl8139_rxsem"); rtl->reg_spinlock = 0; // set up the interrupt handler int_set_io_interrupt_handler(rtl->irq, &rtl8139_int, rtl, "rtl8139"); // read the mac address rtl->mac_addr[0] = RTL_READ_8(rtl, RT_IDR0); rtl->mac_addr[1] = RTL_READ_8(rtl, RT_IDR0 + 1); rtl->mac_addr[2] = RTL_READ_8(rtl, RT_IDR0 + 2); rtl->mac_addr[3] = RTL_READ_8(rtl, RT_IDR0 + 3); rtl->mac_addr[4] = RTL_READ_8(rtl, RT_IDR0 + 4); rtl->mac_addr[5] = RTL_READ_8(rtl, RT_IDR0 + 5); dprintf("rtl8139: mac addr %x:%x:%x:%x:%x:%x\n", rtl->mac_addr[0], rtl->mac_addr[1], rtl->mac_addr[2], rtl->mac_addr[3], rtl->mac_addr[4], rtl->mac_addr[5]); // enable writing to the config registers RTL_WRITE_8(rtl, RT_CFG9346, 0xc0); // reset config 1 RTL_WRITE_8(rtl, RT_CONFIG1, 0); // Enable receive and transmit functions RTL_WRITE_8(rtl, RT_CHIPCMD, RT_CMD_RX_ENABLE | RT_CMD_TX_ENABLE); // Set Rx FIFO threashold to 256, Rx size to 64k+16, 256 byte DMA burst RTL_WRITE_32(rtl, RT_RXCONFIG, 0x00009c00); // Set Tx 256 byte DMA burst RTL_WRITE_32(rtl, RT_TXCONFIG, 0x03000400); // Turn off lan-wake and set the driver-loaded bit RTL_WRITE_8(rtl, RT_CONFIG1, (RTL_READ_8(rtl, RT_CONFIG1) & ~0x30) | 0x20); // Enable FIFO auto-clear RTL_WRITE_8(rtl, RT_CONFIG4, RTL_READ_8(rtl, RT_CONFIG4) | 0x80); // go back to normal mode RTL_WRITE_8(rtl, RT_CFG9346, 0); // Setup RX buffers *(int *)rtl->rxbuf = 0; vm_get_page_mapping(vm_get_kernel_aspace_id(), rtl->rxbuf, &temp); dprintf("rx buffer will be at 0x%lx\n", temp); RTL_WRITE_32(rtl, RT_RXBUF, temp); // Setup TX buffers dprintf("tx buffer (virtual) is at 0x%lx\n", rtl->txbuf); *(int *)rtl->txbuf = 0; vm_get_page_mapping(vm_get_kernel_aspace_id(), rtl->txbuf, &temp); RTL_WRITE_32(rtl, RT_TXADDR0, temp); RTL_WRITE_32(rtl, RT_TXADDR1, temp + 2*1024); dprintf("first half of txbuf at 0x%lx\n", temp); *(int *)(rtl->txbuf + 4*1024) = 0; vm_get_page_mapping(vm_get_kernel_aspace_id(), rtl->txbuf + 4*1024, &temp); RTL_WRITE_32(rtl, RT_TXADDR2, temp); RTL_WRITE_32(rtl, RT_TXADDR3, temp + 2*1024); dprintf("second half of txbuf at 0x%lx\n", temp); /* RTL_WRITE_32(rtl, RT_TXSTATUS0, RTL_READ_32(rtl, RT_TXSTATUS0) | 0xfffff000); RTL_WRITE_32(rtl, RT_TXSTATUS1, RTL_READ_32(rtl, RT_TXSTATUS1) | 0xfffff000); RTL_WRITE_32(rtl, RT_TXSTATUS2, RTL_READ_32(rtl, RT_TXSTATUS2) | 0xfffff000); RTL_WRITE_32(rtl, RT_TXSTATUS3, RTL_READ_32(rtl, RT_TXSTATUS3) | 0xfffff000); */ // Reset RXMISSED counter RTL_WRITE_32(rtl, RT_RXMISSED, 0); // Enable receiving broadcast and physical match packets // RTL_WRITE_32(rtl, RT_RXCONFIG, RTL_READ_32(rtl, RT_RXCONFIG) | 0x0000000a); RTL_WRITE_32(rtl, RT_RXCONFIG, RTL_READ_32(rtl, RT_RXCONFIG) | 0x0000000f); // Filter out all multicast packets RTL_WRITE_32(rtl, RT_MAR0, 0); RTL_WRITE_32(rtl, RT_MAR0 + 4, 0); // Disable all multi-interrupts RTL_WRITE_16(rtl, RT_MULTIINTR, 0); RTL_WRITE_16(rtl, RT_INTRMASK, MYRT_INTS); // RTL_WRITE_16(rtl, RT_INTRMASK, 0x807f); // Enable RX/TX once more RTL_WRITE_8(rtl, RT_CHIPCMD, RT_CMD_RX_ENABLE | RT_CMD_TX_ENABLE); RTL_WRITE_8(rtl, RT_CFG9346, 0); return 0; err1: vm_delete_region(vm_get_kernel_aspace_id(), rtl->region); err: return err; }