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

📄 i82559.c

📁 umon bootloader source code, support mips cpu.
💻 C
📖 第 1 页 / 共 2 页
字号:
//==========================================================================
//
//      i82559.c
//
//      i82559 Ethernet Code
//
// Author(s):    Michael Kelly, Cogent Computer Systems, Inc.
// Contributors: 
// Date:         05-26-2002
// Description:  This file contains PCI intialization and support routines 
//               for the i82559 PCI ethernet controller found on some
//				 CSB's.
//
//--------------------------------------------------------------------------

#include "config.h"
#include "cpuio.h"
#include "stddefs.h"
#include "genlib.h"
#include "pci.h"
#include "cpu_pci.h"
#include "ether.h"
#include "i82559.h"

extern void udelay(vulong);
extern vushort pci_cfg_read_word (vulong bus, vulong dev_func, vulong offset);
extern void pci_cfg_write_word (vulong bus, vulong dev_func, vulong offset, vushort data);

extern vulong sh_mem_base;			// shared memory base address for all PCI devices
extern vulong pci_dev;
extern pci_device_structure pci_dev_info[PCI_DEV_MAX];

#if INCLUDE_ETHERNET

// global 82559 pointers
vulong i82559_scb;			// Status/Command Block (internal to chip)
vulong i82559_psb;			// Port Status Block (in shared memory)
vulong i82559_cbl;			// Command Block List (in shared memory)
vulong i82559_tfd_base;		// Transmit Frame Descriptor base address (in shared memory)
vulong i82559_rfd_base;		// Receive Frame Descriptor base address (in shared memory)
vulong i82559_found;		// clear if no i82559 is found

//--------------------------------------------------------------------------
// i82559_init()
//
//  This code performs the following steps:
//
//	1. Find the first 82559 or 82559er.
//	2. Enable it for IO, MEM and Mastering.
//  3. Allocate space for the shared memory structures.
//  4. Perform Self Test.
//	5. Issue a Port Selective Reset to insure the i82559 is
//     in the idle state.
//
//  Notes:
//  1. We use a predefined "window" for all shared memory accesses
//     between the i82559 and the CPU.  The base address of this
//     window is defined by i82559_SM_BASE.
//  2. A simple static pointer is maintained to "allocate" memory
//     to the functions.  This pointer is sh_mem_base.
//
//
vulong i82559_init(void)
{
	int i, timeout;
	vushort temp16;
	vulong dev, func, bus, temp32;
	
	i82559_scb = 0;
	i82559_found = 0;
	// scan the pci_dev_info structure for the first 82559 or 82559er
	for (i = 0; i < pci_dev; i++){
		if ((pci_dev_info[i].ven_id == I82559_VENID) &&
			((pci_dev_info[i].dev_id == I82559_DEVID) ||
			 (pci_dev_info[i].dev_id == I82559ER_DEVID))){

			// get the MEM base from BAR 0  (we don't use the IO base from BAR 1)
			i82559_scb = pci_dev_info[i].bar_map[0];

			// enable the 82559
			bus = pci_dev_info[i].bus;
			dev = pci_dev_info[i].dev;
			func = pci_dev_info[i].func;
			temp16 = pci_cfg_read_word (bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_CMD_REG);
			temp16 = temp16 | PCI_CFG_CMD_MEM | PCI_CFG_CMD_MASTER;
			pci_cfg_write_word (bus, PCI_MAKE_DEV_FUNC(dev, func), PCI_CFG_CMD_REG, temp16);

			printf("Intel 82559 or 82559er Found in pci_dev_info\n");
			printf("PCI DEV %01d, @ 0x%08lx\n", i, i82559_scb);
			break;
		} // vendor and device id matched
	}  // pci_dev_info loop

	if(i82559_scb == 0){
		printf("Intel 82559 or 82559er not Found in pci_dev_info\n");
		return -1;
	}

	// grab space for the Port Status Block first since it must be 16 byte aligned		
	// all others are 32bit aligned		
	i82559_psb = sh_mem_base;		
	sh_mem_base = sh_mem_base + 1024;	// dump commands can return up to 600 bytes

	// Now get space enough for any Command Block List Command
	i82559_cbl = sh_mem_base;		
	sh_mem_base = sh_mem_base + 1024;

	// Reserve space for the Transmit and Receive Frame Descriptors		
	// allow for oversize frame reception
	i82559_rfd_base = sh_mem_base;		
	sh_mem_base = sh_mem_base + (RBUFCNT * RBUFSIZE);		

	i82559_tfd_base = sh_mem_base;		
	sh_mem_base = sh_mem_base + (XBUFCNT * XBUFSIZE);		

	// issue a self test to the i82559		
	WR_SM32(i82559_psb, 0xffffffff);		
	WR_SM32(i82559_psb + PORT_ST_STAT, 0xffffffff);		
	WR_SM32(i82559_scb + SCB_PORT, ((i82559_psb & 0x0fffffff) | SCB_PORT_ST));		

	// wait for i82559 to write the self test results
    timeout = 10000;
	while(timeout){
		// delay before each check
		udelay(10);
		RD_SM16(i82559_psb + PORT_ST_STAT, temp16);
    	if(temp16 != 0xffff) break; 
   		timeout--;
    }
	if (timeout == 0){
		printf("i82559 SelfTest Timed Out\n");	
		return SCB_PORT_ST_ERR;	
	}
	// Any bit status set means an error	
	RD_SM16(i82559_psb + PORT_ST_STAT, temp16);	
	if (temp16 & (PORT_ST_GEN | PORT_ST_DIAG | PORT_ST_REG | PORT_ST_ROM)){	
		printf("i82559 SelfTest Failed, Status = 0x%04x\n",temp16);	
		return SCB_PORT_ST_ERR;	
	}
	RD_SM32(i82559_psb, temp32);
	printf("i82559 SelfTest Passed, ROM Checksum = 0x%08lx\n", temp32);	

	// reset the i82559
	i82559_reset();
	 	
	// configure the i82559 via the Command Block List - Non-Promiscuous
	temp32 = i82559_cbl_cfg(0);
	if (temp32) return temp32;
			
	// set the mac address
	temp32 = i82559_cbl_ias(BinEnetAddr);
	if (temp32) return temp32;

	// setup a linked list of rx buffers
	i82559_rx_init();
			
	// we're done!	
	i82559_found = 1;
	return 0;	
}

//--------------------------------------------------------------------------
// i82559_cbl_cfg()
//
// This function sends a configuration block to the i82559.  It can be
// called with promiscuous modes enabled (promisc = nonzero) or
// disabled (promisc = zero).  It returns non-zero if the command
// failed to complete within the timeout or if it completed without
// the OK bit set.

vulong i82559_cbl_cfg(vulong promisc)
{
	vulong timeout;
	vushort temp16;
	vulong temp32;

	// Fill the i82559 Command Block List
	WR_SM16(i82559_cbl + CBL_STAT, 0);
	WR_SM16(i82559_cbl + CBL_CMD, (CBL_CMD_CFG | CBL_CMD_EL));
	WR_SM32(i82559_cbl + CBL_LINK, (i82559_cbl & 0x0fffffff));
	WR_SM8(i82559_cbl + CBL_DATA +  0, 0x13);
	WR_SM8(i82559_cbl + CBL_DATA +  1, 0x0c);
	WR_SM8(i82559_cbl + CBL_DATA +  2, 0x00);
	WR_SM8(i82559_cbl + CBL_DATA +  3, 0x00);
	WR_SM8(i82559_cbl + CBL_DATA +  4, 0x00);
	WR_SM8(i82559_cbl + CBL_DATA +  5, 0x00);
	WR_SM8(i82559_cbl + CBL_DATA +  6, 0x32 | (promisc ? 0x80 : 0x00));
	WR_SM8(i82559_cbl + CBL_DATA +  7, 0x00 | (promisc ? 0x01 : 0x00));
	WR_SM8(i82559_cbl + CBL_DATA +  8, 0x01);
	WR_SM8(i82559_cbl + CBL_DATA +  9, 0x00);
	WR_SM8(i82559_cbl + CBL_DATA + 10, 0x28);
	WR_SM8(i82559_cbl + CBL_DATA + 11, 0x00);
	WR_SM8(i82559_cbl + CBL_DATA + 12, 0x60);
	WR_SM8(i82559_cbl + CBL_DATA + 13, 0x00);
	WR_SM8(i82559_cbl + CBL_DATA + 14, 0x00);
	WR_SM8(i82559_cbl + CBL_DATA + 15, 0x80 | (promisc ? 0x01 : 0x00));
	WR_SM8(i82559_cbl + CBL_DATA + 16, 0x00);
	WR_SM8(i82559_cbl + CBL_DATA + 17, 0x40);
	WR_SM8(i82559_cbl + CBL_DATA + 18, 0x02);

	// wait for the CU to be idle
	temp32 = i82559_wait_for_cu_cmd();
	if (temp32) return temp32;

	// issue the command to the i82559
	WR_SM32(i82559_scb + SCB_PTR, (i82559_cbl & 0x0fffffff));
	RD_SM32(i82559_scb + SCB_PTR, temp32);
	WR_SM16(i82559_scb + SCB_CMD, SCB_CU_START | SCB_IM_M);
	RD_SM16(i82559_scb + SCB_CMD, temp16);

	// Now check the CBL Status word
    timeout = 10000;
	while(timeout){
		// delay before each check
		udelay(10);
		RD_SM16(i82559_cbl + CBL_STAT, temp16);
		if (temp16 & CBL_STAT_C){
			if (temp16 & CBL_STAT_OK){
				return 0;
			}
			else {
				printf("i82559 CBL Configure Command Returned Not OK\n");
				return CBL_CMD_CFG_ERR;
			}
		}
   		timeout--;
    }
	if (timeout == 0){
		printf("i82559 CBL Configure Command Timed Out\n");
		return CBL_CMD_CFG_TIMEOUT;	
	}
	return 0;
}

//--------------------------------------------------------------------------
// i82559_cbl_ias()
//
// This function sends a mac address to the i82559.  It returns
// non-zero if the command failed to complete within the timeout
// or if it completed without the OK bit set.

vulong i82559_cbl_ias(uchar *mac_addr)
{
	vulong timeout;
	vushort temp16;
	vulong temp32;

	// Fill the i82559 Command Block List
	WR_SM16(i82559_cbl + CBL_STAT, 0);
	WR_SM16(i82559_cbl + CBL_CMD, (CBL_CMD_IAS | CBL_CMD_EL));
	WR_SM32(i82559_cbl + CBL_LINK, (i82559_cbl & 0x0fffffff));
	WR_SM8(i82559_cbl + CBL_DATA +  0, mac_addr[0]);
	WR_SM8(i82559_cbl + CBL_DATA +  1, mac_addr[1]);
	WR_SM8(i82559_cbl + CBL_DATA +  2, mac_addr[2]);
	WR_SM8(i82559_cbl + CBL_DATA +  3, mac_addr[3]);
	WR_SM8(i82559_cbl + CBL_DATA +  4, mac_addr[4]);
	WR_SM8(i82559_cbl + CBL_DATA +  5, mac_addr[5]);
	WR_SM8(i82559_cbl + CBL_DATA +  6, 0);
	WR_SM8(i82559_cbl + CBL_DATA +  7, 0);

	// wait for the CU to be idle
	temp32 = i82559_wait_for_cu_cmd();
	if (temp32) return temp32;

	// issue the command to the i82559
	WR_SM32(i82559_scb + SCB_PTR, (i82559_cbl & 0x0fffffff));
	WR_SM16(i82559_scb + SCB_CMD, SCB_CU_START | SCB_IM_M);

	// Now check the CBL Status word
    timeout = 10000;
	while(timeout){
		// delay before each check
		udelay(10);
		RD_SM16(i82559_cbl + CBL_STAT, temp16);
		if (temp16 & CBL_STAT_C){
			if (temp16 & CBL_STAT_OK){
				return 0;
			}
			else {
				printf("i82559 CBL Configure Command Returned Not OK\n");
				return CBL_CMD_CFG_ERR;
			}
		}
   		timeout--;
    }
	if (timeout == 0){

⌨️ 快捷键说明

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