if_lancepci.c
来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,324 行 · 第 1/4 页
C
1,324 行
for (device_index = 0;
device_index < CYGNUM_DEVS_ETH_AMD_LANCEPCI_DEV_COUNT;
device_index++) {
struct lancepci_priv_data* cpd = lancepci_priv_array[device_index];
cpd->index = device_index;
// See above for find_lancepci_match_func - it selects any of several
// variants. This is necessary in case we have multiple mixed-type
// devices on one board in arbitrary orders.
if (cyg_pci_find_matching( &find_lancepci_match_func, NULL, &devid )) {
#if DEBUG & 8
db_printf("eth%d = lancepci\n", device_index);
#endif
cyg_pci_get_device_info(devid, &dev_info);
cpd->interrupt_handle = 0; // Flag not attached.
if (cyg_pci_translate_interrupt(&dev_info, &cpd->interrupt)) {
#if DEBUG & 8
db_printf(" Wired to HAL vector %d\n", cpd->interrupt);
#endif
cyg_drv_interrupt_create(
cpd->interrupt,
1, // Priority - unused
(cyg_addrword_t)cpd,// Data item passed to ISR & DSR
lancepci_isr, // ISR
lancepci_dsr, // DSR
&cpd->interrupt_handle, // handle to intr obj
&cpd->interrupt_object ); // space for int obj
cyg_drv_interrupt_attach(cpd->interrupt_handle);
// Don't unmask the interrupt yet, that could get us into a
// race.
}
else {
cpd->interrupt = 0;
#if DEBUG & 8
db_printf(" Does not generate interrupts.\n");
#endif
}
if (cyg_pci_configure_device(&dev_info)) {
#if DEBUG & 8
int i;
db_printf("Found device on bus %d, devfn 0x%02x:\n",
CYG_PCI_DEV_GET_BUS(devid),
CYG_PCI_DEV_GET_DEVFN(devid));
if (dev_info.command & CYG_PCI_CFG_COMMAND_ACTIVE) {
db_printf(" Note that board is active. Probed"
" sizes and CPU addresses invalid!\n");
}
db_printf(" Vendor 0x%04x", dev_info.vendor);
db_printf("\n Device 0x%04x", dev_info.device);
db_printf("\n Command 0x%04x, Status 0x%04x\n",
dev_info.command, dev_info.status);
db_printf(" Class/Rev 0x%08x", dev_info.class_rev);
db_printf("\n Header 0x%02x\n", dev_info.header_type);
db_printf(" SubVendor 0x%04x, Sub ID 0x%04x\n",
dev_info.header.normal.sub_vendor,
dev_info.header.normal.sub_id);
for(i = 0; i < CYG_PCI_MAX_BAR; i++) {
db_printf(" BAR[%d] 0x%08x /", i, dev_info.base_address[i]);
db_printf(" probed size 0x%08x / CPU addr 0x%08x\n",
dev_info.base_size[i], dev_info.base_map[i]);
}
db_printf(" eth%d configured\n", device_index);
#endif
found_devices++;
cpd->found = 1;
cpd->active = 0;
cpd->devid = devid;
cpd->base = (unsigned char*) dev_info.base_map[0];
#if DEBUG & 8
db_printf(" I/O address = 0x%08x\n", cpd->base);
#endif
// Don't use cyg_pci_set_device_info since it clears
// some of the fields we want to print out below.
cyg_pci_read_config_uint16(dev_info.devid,
CYG_PCI_CFG_COMMAND, &cmd);
cmd |= (CYG_PCI_CFG_COMMAND_IO // enable I/O space
| CYG_PCI_CFG_COMMAND_MEMORY // enable memory space
| CYG_PCI_CFG_COMMAND_MASTER); // enable bus master
cyg_pci_write_config_uint16(dev_info.devid,
CYG_PCI_CFG_COMMAND, cmd);
// This is the indicator for "uses an interrupt"
if (cpd->interrupt_handle != 0) {
cyg_drv_interrupt_acknowledge(cpd->interrupt);
cyg_drv_interrupt_unmask(cpd->interrupt);
#if DEBUG & 8
db_printf(" Enabled interrupt %d\n", cpd->interrupt);
#endif
}
#if DEBUG & 8
db_printf(" **** Device enabled for I/O and Memory "
"and Bus Master\n");
#endif
}
else {
cpd->found = 0;
cpd->active = 0;
#if DEBUG & 8
db_printf("Failed to configure device %d\n", device_index);
#endif
}
}
else {
cpd->found = 0;
cpd->active = 0;
#if DEBUG & 8
db_printf("eth%d not found\n", device_index);
#endif
}
}
if (0 == found_devices)
return 0;
return 1;
}
static bool
amd_lancepci_init(struct cyg_netdevtab_entry *tab)
{
static int initialized = 0; // only probe PCI et al *once*
struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
struct lancepci_priv_data *cpd =
(struct lancepci_priv_data *)sc->driver_private;
cyg_uint16 val;
cyg_uint32 b;
cyg_uint8* p;
cyg_uint8* d;
int i;
DEBUG_FUNCTION();
if ( 0 == initialized++ ) {
// then this is the first time ever:
if ( ! pci_init_find_lancepci() ) {
#if DEBUG & 8
db_printf( "pci_init_find_lancepci failed" );
#endif
return false;
}
}
// If this device is not present, exit
if (0 == cpd->found)
return 0;
#if DEBUG & 8
db_printf("lancepci at base 0x%08x, EEPROM key 0x%04x\n",
cpd->base, _SU16(cpd->base, LANCE_IO_ID));
#endif
#if 0
// FIXME: Doesn't work with non-conforming EEPROMS
if (LANCE_IO_ID_KEY != _SU16(cpd->base, LANCE_IO_ID) ) {
db_printf("Lance EPROM key not found\n");
return false;
}
#endif
#if DEBUG & 9
db_printf("pcimem : %08x size: %08x\n", lancepci_heap_base, lancepci_heap_size);
#endif
// Prepare ESA
if (!cpd->hardwired_esa) {
// Don't use the address from the EEPROM for VMware
// Use the address that VMware prepares in CSR_PAR registers
// if You want to be able to use NAT networking. (iz@elsis.si Feb 27 04)
//
// p = cpd->base + LANCE_IO_EEPROM;
// for (i = 0; i < 6; i++)
// cpd->esa[i] = *p++;
put_reg(sc, LANCE_CSR_CSCR, LANCE_CSR_CSCR_STOP);
for (i = 0; i < sizeof(cpd->esa); i += 2) {
cyg_uint16 z = get_reg(sc, LANCE_CSR_PAR0+i/2 );
cpd->esa[i] = (cyg_uint8)(0xff & z);
cpd->esa[i+1] = (cyg_uint8)(0xff & (z >> 8));
}
}
#if DEBUG & 9
db_printf("Lance - %s ESA: %02x:%02x:%02x:%02x:%02x:%02x\n",
(cpd->hardwired_esa) ? "static" : "eeprom",
cpd->esa[0], cpd->esa[1], cpd->esa[2],
cpd->esa[3], cpd->esa[4], cpd->esa[5] );
#endif
// Prepare RX and TX rings
p = cpd->rx_ring = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc((1<<cpd->rx_ring_log_cnt)*LANCE_RD_SIZE));
memset(cpd->rx_ring,0,(1<<cpd->rx_ring_log_cnt)*LANCE_RD_SIZE);
d = cpd->rx_buffers = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc(_BUF_SIZE*cpd->rx_ring_cnt));
memset(cpd->rx_buffers,0,_BUF_SIZE*cpd->rx_ring_cnt);
for (i = 0; i < cpd->rx_ring_cnt; i++) {
HAL_PCI_CPU_TO_BUS(d, (cyg_uint8 *)b);
_SU32(p, LANCE_RD_PTR) = (b & LANCE_RD_PTR_MASK) | LANCE_RD_PTR_OWN;
_SU16(p, LANCE_RD_BLEN) = (-_BUF_SIZE);
p += LANCE_RD_SIZE;
d += _BUF_SIZE;
}
cpd->rx_ring_next = 0;
p = cpd->tx_ring = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc((1<<cpd->tx_ring_log_cnt)*LANCE_TD_SIZE));
memset(cpd->tx_ring,0,(1<<cpd->tx_ring_log_cnt)*LANCE_TD_SIZE);
d = cpd->tx_buffers = (cyg_uint8*) CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc(_BUF_SIZE*cpd->tx_ring_cnt));
for (i = 0; i < cpd->tx_ring_cnt; i++) {
HAL_PCI_CPU_TO_BUS(d, (cyg_uint8 *)b);
_SU32(p, LANCE_RD_PTR) = b & LANCE_TD_PTR_MASK;
p += LANCE_TD_SIZE;
d += _BUF_SIZE;
}
cpd->tx_ring_free = cpd->tx_ring_alloc = cpd->tx_ring_owned = 0;
// Initialization table
cpd->init_table = (cyg_uint8*)CYGARC_UNCACHED_ADDRESS((cyg_uint32)pciwindow_mem_alloc(LANCE_IB_SIZE));
_SU16(cpd->init_table, LANCE_IB_MODE) = 0x0000;
for (i = 0; i < 6; i++)
_SU8(cpd->init_table, LANCE_IB_PADR0+i) = cpd->esa[i];
for (i = 0; i < 8; i++)
_SU8(cpd->init_table, LANCE_IB_LADRF0+i) = 0;
HAL_PCI_CPU_TO_BUS(cpd->rx_ring, (cyg_uint8 *)b);
_SU32(cpd->init_table, LANCE_IB_RDRA) = ((b & LANCE_IB_RDRA_PTR_mask)
| (cpd->rx_ring_log_cnt << LANCE_IB_RDRA_CNT_shift));
HAL_PCI_CPU_TO_BUS(cpd->tx_ring, (cyg_uint8 *)b);
_SU32(cpd->init_table, LANCE_IB_TDRA) = ((b & LANCE_IB_TDRA_PTR_mask)
| (cpd->tx_ring_log_cnt << LANCE_IB_TDRA_CNT_shift));
#if DEBUG & 9
db_printf("Loading up lance controller from table at 0x%08x\n", cpd->init_table);
db_printf(" Mode 0x%04x\n", _SU16(cpd->init_table, LANCE_IB_MODE));
db_printf(" PADR %02x:%02x:%02x:%02x:%02x:%02x ",
_SU8(cpd->init_table, LANCE_IB_PADR0+0), _SU8(cpd->init_table, LANCE_IB_PADR0+1),
_SU8(cpd->init_table, LANCE_IB_PADR0+2), _SU8(cpd->init_table, LANCE_IB_PADR0+3),
_SU8(cpd->init_table, LANCE_IB_PADR0+4), _SU8(cpd->init_table, LANCE_IB_PADR0+5));
db_printf("LADR %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
_SU8(cpd->init_table, LANCE_IB_LADRF0+0), _SU8(cpd->init_table, LANCE_IB_LADRF0+1),
_SU8(cpd->init_table, LANCE_IB_LADRF0+2), _SU8(cpd->init_table, LANCE_IB_LADRF0+3),
_SU8(cpd->init_table, LANCE_IB_LADRF0+4), _SU8(cpd->init_table, LANCE_IB_LADRF0+5),
_SU8(cpd->init_table, LANCE_IB_LADRF0+5), _SU8(cpd->init_table, LANCE_IB_LADRF0+7));
db_printf(" RX 0x%08x (len %d) TX 0x%08x (len %d)\n",
_SU32(cpd->init_table, LANCE_IB_RDRA) & 0x1fffffff,
(_SU32(cpd->init_table, LANCE_IB_RDRA) >> LANCE_IB_RDRA_CNT_shift) & 7,
_SU32(cpd->init_table, LANCE_IB_TDRA) & 0x1fffffff,
(_SU32(cpd->init_table, LANCE_IB_TDRA) >> LANCE_IB_TDRA_CNT_shift) & 7);
#endif
// Reset chip
HAL_PCI_IO_READ_UINT16(cpd->base+LANCE_IO_RESET, val);
// Load up chip with buffers.
// Note: There is a 16M limit on the addresses used by the driver
// since the top 8 bits of the init_table address is appended to
// all other addresses used by the controller.
HAL_PCI_CPU_TO_BUS(cpd->init_table, (cyg_uint8 *)b);
put_reg(sc, LANCE_CSR_IBA0, (b >> 0) & 0xffff);
put_reg(sc, LANCE_CSR_IBA1, (b >> 16) & 0xffff);
// Disable automatic TX polling (_send will force a poll), pad
// XT frames to legal length, mask status interrupts.
put_reg(sc, LANCE_CSR_TFC, (LANCE_CSR_TFC_TXDPOLL | LANCE_CSR_TFC_APAD_XMT
| LANCE_CSR_TFC_MFCOM | LANCE_CSR_TFC_RCVCCOM
| LANCE_CSR_TFC_TXSTRTM));
// Recover after TX FIFO underflow
put_reg(sc, LANCE_CSR_IM, LANCE_CSR_IM_DXSUFLO);
// Initialize controller - load up init_table
put_reg(sc, LANCE_CSR_CSCR, LANCE_CSR_CSCR_INIT);
while (0 == (get_reg(sc, LANCE_CSR_CSCR) & LANCE_CSR_CSCR_IDON));
// Stop controller
put_reg(sc, LANCE_CSR_CSCR, LANCE_CSR_CSCR_STOP);
#if DEBUG & 9
db_printf("lancepci controller state is now:\n");
db_printf(" Mode 0x%04x TFC 0x%04x\n", _SU16(cpd->init_table, LANCE_IB_MODE), get_reg(sc, LANCE_CSR_TFC));
db_printf(" PADR %04x:%04x:%04x ",
get_reg(sc, LANCE_CSR_PAR0),
get_reg(sc, LANCE_CSR_PAR1),
get_reg(sc, LANCE_CSR_PAR2));
db_printf("LADR %04x:%04x:%04x:%04x\n",
get_reg(sc, LANCE_CSR_LAR0),
get_reg(sc, LANCE_CSR_LAR1),
get_reg(sc, LANCE_CSR_LAR2),
get_reg(sc, LANCE_CSR_LAR3));
db_printf(" RX 0x%04x%04x (len 0x%04x) TX 0x%04x%04x (len 0x%04x)\n",
get_reg(sc, LANCE_CSR_BARRU), get_reg(sc, LANCE_CSR_BARRL),
get_reg(sc, LANCE_CSR_RRLEN),
get_reg(sc, LANCE_CSR_BATRU), get_reg(sc, LANCE_CSR_BATRL),
get_reg(sc, LANCE_CSR_TRLEN));
val = get_reg(sc, LANCE_CSR_ID_LO);
db_printf("lancepci ID 0x%04x (%s) ",
val,
(0x5003 == val) ? "Am79C973" : (0x7003 == val) ? "Am79C975" :
(0x1003 == val) ? "Am79C900 or wmWare VLANCE" : "Unknown");
val = get_reg(sc, LANCE_CSR_ID_HI);
db_printf("Part IDU 0x%03x Silicon rev %d\n",
val & 0x0fff, (val >> 12) & 0xf);
#endif
// and record the net dev pointer
cpd->ndp = (void *)tab;
cpd->active = 0;
oursc=sc;
// Initialize upper level driver
(sc->funs->eth_drv->init)(sc, cpd->esa);
cpd->txbusyh=cpd->txbusy=0;
cpd->event=0;
db_printf("Lancepci driver loaded and Init Done\n");
return true;
}
static void
lancepci_stop(struct eth_drv_sc *sc)
{
cyg_uint32 b;
struct lancepci_priv_data *cpd =
(struct lancepci_priv_data *)sc->driver_private;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?