⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ns83820_dev.c

📁 newos is new operation system
💻 C
字号:
/*** Copyright 2004, Travis Geiselbrecht. All rights reserved.** Distributed under the terms of the NewOS License.*/#include <kernel/kernel.h>#include <kernel/debug.h>#include <kernel/heap.h>#include <kernel/vm.h>#include <kernel/int.h>#include <kernel/lock.h>#include <kernel/sem.h>#include <kernel/time.h>#include <kernel/module.h>#include <kernel/arch/cpu.h>#include <kernel/arch/i386/cpu.h>#include <kernel/net/ethernet.h>#include <string.h>#include <kernel/bus/pci/pci.h>#include "ns83820_dev.h"#include "ns83820_priv.h"#define debug_level_flow 3#define debug_level_error 3#define debug_level_info 3#define DEBUG_MSG_PREFIX "NS83820 -- "#include <kernel/debug_ext.h>#if 0// macros to manipulate registers. Assumes a variable called ns of type ns83820 *#define NS_WRITE_32(reg, dat) ({ \	asm("wbinvd"); \	*(vuint32 *)((ns)->virt_base + (reg)) = (dat); \	dprintf("NS_WRITE_32: putting 0x%x at 0x%lx\n", dat, (ns)->virt_base + (reg)); \	asm("wbinvd"); \	})#define NS_READ_32(reg) ({ \	asm("wbinvd"); \	uint32 temp = *(vuint32 *)((ns)->virt_base + (reg)); \	dprintf("NS_READ_32: read 0x%x from 0x%lx\n", temp, (ns)->virt_base + (reg)); \	temp; \	})#else// macros to manipulate registers. Assumes a variable called ns of type ns83820 *#define NS_WRITE_32(reg, dat) ({ \	out32(dat, (ns)->io_port + (reg)); \	dprintf("NS_WRITE_32: putting 0x%x at 0x%lx\n", dat, (ns)->io_port + (reg)); \	})#define NS_READ_32(reg) ({ \	uint32 temp = in32((ns)->io_port + (reg)); \	dprintf("NS_READ_32: read 0x%x from 0x%lx\n", temp, (ns)->io_port + (reg)); \	temp; \	})#endifint ns83820_detect(ns83820 **_ns, int *num){	int i, j;	pci_module_hooks *pci;	pci_info pinfo;	bool foundit = false;	ns83820 *ns;	int err;	if(module_get(PCI_BUS_MODULE_NAME, 0, (void **)&pci) < 0) {		dprintf("ns83820_detect: no pci bus found..\n");		return -1;	}	j = 0;	for(i = 0; pci->get_nth_pci_info(i, &pinfo) >= NO_ERROR; i++) {		if(pinfo.vendor_id == NS_VENDOR_ID && pinfo.device_id == NS_DEVICE_ID_83820) {			if(j == *num) {				foundit = true;				break;			} else {				j++;			}		}	}	if(!foundit) {		dprintf("ns83820_detect: didn't find device on pci bus\n");		err = ERR_NOT_FOUND;		goto err;	}	// we found one	dprintf("ns83820_detect: found device at pci %d:%d:%d\n", pinfo.bus, pinfo.device, pinfo.function);	// increment the cookie that was passed to us so we wont find this device again	(*num)++;	ns = kmalloc(sizeof(ns83820));	if(ns == NULL) {		err = ERR_NO_MEMORY;		goto err;	}	memset(ns, 0, sizeof(ns83820));	ns->irq = pinfo.u.h0.interrupt_line;	// find the memory-mapped base	for(i=0; i<6; i++) {		if(pinfo.u.h0.base_registers[i] > 0xffff) {			ns->phys_base = pinfo.u.h0.base_registers[i];			ns->phys_size = pinfo.u.h0.base_register_sizes[i];			break;		} else if(pinfo.u.h0.base_registers[i] > 0) {			ns->io_port = pinfo.u.h0.base_registers[i];		}	}	if(ns->phys_base == 0) {		kfree(ns);		err = ERR_IO_ERROR;		goto err;	}	dprintf("detected ns83820 at irq %d, memory base 0x%lx, size 0x%lx, io base 0x%x\n", 		ns->irq, ns->phys_base, ns->phys_size, ns->io_port);	*_ns = ns;	err = NO_ERROR;err:	module_put(PCI_BUS_MODULE_NAME);	return err;}static int run_bist(ns83820 *ns, uint32 bist_enable_bit, uint32 bist_done_bit, uint32 bist_fail_bit){	// start the bist	NS_WRITE_32(REG_PTSCR, bist_enable_bit);	// wait for it to complete or fail	for(;;) {		uint32 val = NS_READ_32(REG_PTSCR);		if(val & bist_fail_bit)			return -1;		if(val & bist_done_bit)			return 0;		if((val & bist_enable_bit) == 0)			return -1;		thread_snooze(10);	}}int ns83820_init(ns83820 *ns){	bigtime_t time;	int err = -1;	addr_t temp;	int i;	SHOW_FLOW(1, "ns83820_init: ns %p", ns);	ns->region = vm_map_physical_memory(vm_get_kernel_aspace_id(), "ns83820_init", (void **)&ns->virt_base,		REGION_ADDR_ANY_ADDRESS, ns->phys_size, LOCK_KERNEL|LOCK_RW, ns->phys_base);	if(ns->region < 0) {		dprintf("ns83820_init: error creating memory mapped region\n");		err = -1;		goto err;	}	SHOW_FLOW(3, "ns83820 mapped at address 0x%lx", ns->virt_base);	// reset the chip	NS_WRITE_32(REG_CR, 0x100);	while(NS_READ_32(REG_CR) & 0x100)		;	SHOW_FLOW0(3, "chip is reset");	thread_snooze(100000);	// run the BISTs	NS_WRITE_32(REG_PTSCR, 1<<13); // RBIST_RST	run_bist(ns, 1<<10, 1<<9, 0x1b8); // RBIST_EN	run_bist(ns, 1<<1, 0, 1); // EEBIST_EN	run_bist(ns, 1<<2, 0, 0); // EELOAD_EN	// load the mac address	for(i = 0; i < 3; i++) {		uint16 temp;		NS_WRITE_32(REG_RFCR, i * 2);		temp = NS_READ_32(REG_RFDR);		ns->mac_addr[i*2] = temp & 0xff;		ns->mac_addr[i*2+1] = (temp >> 8) & 0xff;	}	SHOW_FLOW(1, "address %02x:%02x:%02x:%02x:%02x:%02x", 		ns->mac_addr[0], ns->mac_addr[1], ns->mac_addr[2], 		ns->mac_addr[3], ns->mac_addr[4], ns->mac_addr[5]);	// set up device here	return -1;	return 0;err1:	vm_delete_region(vm_get_kernel_aspace_id(), ns->region);err:	return err;}static void ns83820_stop(ns83820 *ns){#if 0	// stop the rx and tx and mask all interrupts	RTL_WRITE_8(rtl, RT_CHIPCMD, RT_CMD_RESET);	RTL_WRITE_16(rtl, RT_INTRMASK, 0);#endif}static void ns83820_resetrx(ns83820 *ns){#if 0	rtl8139_stop(rtl);	// reset the rx pointers	RTL_WRITE_16(rtl, RT_RXBUFTAIL, TAIL_TO_TAILREG(0));	RTL_WRITE_16(rtl, RT_RXBUFHEAD, 0);	// start it back up	RTL_WRITE_16(rtl, RT_INTRMASK, MYRT_INTS);	// Enable RX/TX once more	RTL_WRITE_8(rtl, RT_CHIPCMD, RT_CMD_RX_ENABLE | RT_CMD_TX_ENABLE);#endif}static void ns83820_dumptxstate(ns83820 *ns){#if 0	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));#endif}void ns83820_xmit(ns83820 *ns, const char *ptr, ssize_t len){#if 0#if 0	int i;#endif//restart:	sem_acquire(rtl->tx_sem, 1);	mutex_lock(&rtl->lock);#if 0	dprintf("XMIT %d %x (%d)\n",rtl->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(&rtl->reg_spinlock);#if 0	/* wait for clear-to-send */	if(!(RTL_READ_32(rtl, RT_TXSTATUS0 + rtl->txbn*4) & RT_TX_HOST_OWNS)) {		dprintf("rtl8139_xmit: no txbuf free\n");		rtl8139_dumptxstate(rtl);		release_spinlock(&rtl->reg_spinlock);		int_restore_interrupts();		mutex_unlock(&rtl->lock);		sem_release(rtl->tx_sem, 1);		goto restart;	}#endif	memcpy((void*)(rtl->txbuf + rtl->txbn * 0x800), ptr, len);	if(len < ETHERNET_MIN_SIZE)		len = ETHERNET_MIN_SIZE;	RTL_WRITE_32(rtl, RT_TXSTATUS0 + rtl->txbn*4, len | 0x80000);	if(++rtl->txbn >= 4)		rtl->txbn = 0;	release_spinlock(&rtl->reg_spinlock);	int_restore_interrupts();	mutex_unlock(&rtl->lock);#endif}typedef struct rx_entry {	volatile uint16 status;	volatile uint16 len;	volatile uint8 data[1];} rx_entry;ssize_t ns83820_rx(ns83820 *ns, char *buf, ssize_t buf_len){#if 0	rx_entry *entry;	uint32 tail;	uint16 len;	int rc;	bool release_sem = false;//	dprintf("rtl8139_rx: entry\n");	if(buf_len < 1500)		return -1;restart:	sem_acquire(rtl->rx_sem, 1);	mutex_lock(&rtl->lock);	int_disable_interrupts();	acquire_spinlock(&rtl->reg_spinlock);	tail = TAILREG_TO_TAIL(RTL_READ_16(rtl, RT_RXBUFTAIL));//	dprintf("tailreg = 0x%x, actual tail 0x%x\n", RTL_READ_16(rtl, RT_RXBUFTAIL), tail);	if(tail == RTL_READ_16(rtl, RT_RXBUFHEAD)) {		release_spinlock(&rtl->reg_spinlock);		int_restore_interrupts();		mutex_unlock(&rtl->lock);		goto restart;	}	if(RTL_READ_8(rtl, RT_CHIPCMD) & RT_CMD_RX_BUF_EMPTY) {		release_spinlock(&rtl->reg_spinlock);		int_restore_interrupts();		mutex_unlock(&rtl->lock);		goto restart;	}	// grab another buffer	entry = (rx_entry *)((uint8 *)rtl->rxbuf + tail);//	dprintf("entry->status = 0x%x\n", entry->status);//	dprintf("entry->len = 0x%x\n", entry->len);	// see if it's an unfinished buffer	if(entry->len == 0xfff0) {		release_spinlock(&rtl->reg_spinlock);		int_restore_interrupts();		mutex_unlock(&rtl->lock);		goto restart;	}	// figure the len that we need to copy	len = entry->len - 4; // minus the crc	// see if we got an error	if((entry->status & RT_RX_STATUS_OK) == 0 || len > ETHERNET_MAX_SIZE) {		// error, lets reset the card		rtl8139_resetrx(rtl);		release_spinlock(&rtl->reg_spinlock);		int_restore_interrupts();		mutex_unlock(&rtl->lock);		goto restart;	}	// copy the buffer	if(len > buf_len) {		dprintf("rtl8139_rx: packet too large for buffer (len %d, buf_len %ld)\n", len, (long)buf_len);		RTL_WRITE_16(rtl, RT_RXBUFTAIL, TAILREG_TO_TAIL(RTL_READ_16(rtl, RT_RXBUFHEAD)));		rc = ERR_TOO_BIG;		release_sem = true;		goto out;	}	if(tail + len > 0xffff) {//		dprintf("packet wraps around\n");		memcpy(buf, (const void *)&entry->data[0], 0x10000 - (tail + 4));		memcpy((uint8 *)buf + 0x10000 - (tail + 4), (const void *)rtl->rxbuf, len - (0x10000 - (tail + 4)));	} else {		memcpy(buf, (const void *)&entry->data[0], len);	}	rc = len;	// calculate the new tail	tail = ((tail + entry->len + 4 + 3) & ~3) % 0x10000;//	dprintf("new tail at 0x%x, tailreg will say 0x%x\n", tail, TAIL_TO_TAILREG(tail));	RTL_WRITE_16(rtl, RT_RXBUFTAIL, TAIL_TO_TAILREG(tail));	if(tail != RTL_READ_16(rtl, RT_RXBUFHEAD)) {		// we're at last one more packet behind		release_sem = true;	}out:	release_spinlock(&rtl->reg_spinlock);	int_restore_interrupts();	if(release_sem)		sem_release(rtl->rx_sem, 1);	mutex_unlock(&rtl->lock);#if 0{	int i;	dprintf("RX %x (%d)\n", buf, len);	dprintf("dumping packet:");	for(i=0; i<len; i++) {		if(i%8 == 0)			dprintf("\n");		dprintf("0x%02x ", buf[i]);	}	dprintf("\n");}#endif	return rc;#endif}static int ns83820_rxint(ns83820 *ns, uint16 int_status){#if 0	int rc = INT_NO_RESCHEDULE;//	dprintf("rx\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));//	dprintf("BUF_EMPTY = %d\n", RTL_READ_8(rtl, RT_CHIPCMD) & RT_CMD_RX_BUF_EMPTY);	if(!(RTL_READ_8(rtl, RT_CHIPCMD) & RT_CMD_RX_BUF_EMPTY)) {		sem_release_etc(rtl->rx_sem, 1, SEM_FLAG_NO_RESCHED);		rc = INT_RESCHEDULE;	}	return rc;#endif}static int ns83820_txint(ns83820 *ns, uint16 int_status){#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");		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;#endif}static int ns83820_int(void* data){#if 0	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;#endif}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -