📄 i82559.c
字号:
//==========================================================================
//
// 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 + -