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 + -
显示快捷键?