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

📄 w89c840.c

📁 i386的bootloader源码grub
💻 C
📖 第 1 页 / 共 2 页
字号:
                   nic->packet[4],  nic->packet[5],  nic->packet[6], nic->packet[7],                   nic->packet[8],  nic->packet[9],  nic->packet[10],                   nic->packet[11], nic->packet[12], nic->packet[13],                   nic->packet[14], nic->packet[15], nic->packet[16],                   nic->packet[17]);#endif        }        entry = (++w840private.cur_rx) % RX_RING_SIZE;        w840private.rx_head_desc = &w840private.rx_ring[entry];    } while (0);    if (intr_status & (AbnormalIntr | TxFIFOUnderflow | IntrPCIErr |TimerInt | IntrTxStopped)) {        handle_intr(intr_status);    }    return packet_received;}/**************************************************************************w89c840_transmit - Transmit a frame***************************************************************************/static void w89c840_transmit(    struct nic *nic,    const char *d,            /* Destination */    unsigned int t,            /* Type */    unsigned int s,            /* size */    const char *p)            /* Packet */{    /* send the packet to destination */    unsigned entry;    int transmit_status;    /* Caution: the write order is important here, set the field       with the "ownership" bits last. */    /* Fill in our transmit buffer */    entry = w840private.cur_tx % TX_RING_SIZE;    memcpy (tx_packet, d, ETH_ALEN);    /* dst */    memcpy (tx_packet + ETH_ALEN, nic->node_addr, ETH_ALEN);/* src */    *((char *) tx_packet + 12) = t >> 8;    /* type */    *((char *) tx_packet + 13) = t;    memcpy (tx_packet + ETH_HLEN, p, s);    s += ETH_HLEN;    while (s < ETH_ZLEN)    *((char *) tx_packet + ETH_HLEN + (s++)) = 0;    w840private.tx_ring[entry].buffer1 = virt_to_le32desc(tx_packet);    w840private.tx_ring[entry].length = (DescWholePkt | s);    if (entry >= TX_RING_SIZE-1)         /* Wrap ring */        w840private.tx_ring[entry].length |= (DescIntr | DescEndRing);    w840private.tx_ring[entry].status = (DescOwn);    w840private.cur_tx++;    w840private.tx_q_bytes += s;    writel(0, ioaddr + TxStartDemand);    /* Work around horrible bug in the chip by marking the queue as full       when we do not have FIFO room for a maximum sized packet. */    if ((w840private.drv_flags & HasBrokenTx) && w840private.tx_q_bytes > TX_BUG_FIFO_LIMIT) {        /* Actually this is left to help finding error tails later in debugging...         * See Linux kernel driver in winbond-840.c for details.         */        w840private.tx_full = 1;    }#if defined(W89C840_DEBUG)    printf("winbond-840 : Transmit frame # %d size %d queued in slot %d.\n", w840private.cur_tx, s, entry);#endif    /* Now wait for TX to complete. */    transmit_status = w840private.tx_ring[entry].status;    load_timer2(TX_TIMEOUT);    {        u32 intr_stat = 0;        while (1) {            intr_stat = readl(ioaddr + IntrStatus);#if defined(W89C840_DEBUG)            decode_interrupt(intr_stat);#endif            if (intr_stat & (NormalIntr | IntrTxDone)) {                while ( (transmit_status & DescOwn) && timer2_running()) {                    transmit_status = w840private.tx_ring[entry].status;                }                writel(intr_stat & 0x0001ffff, ioaddr + IntrStatus);                break;            }        }    }    if ((transmit_status & DescOwn) == 0) {#if defined(W89C840_DEBUG)        printf("winbond-840 : transmission complete after %d wait loop iterations, status %X\n",               TX_LOOP_COUNT - transmit_loop_counter, w840private.tx_ring[entry].status);#endif        return;    }    /* Transmit timed out... */    printf("winbond-840 : transmission TIMEOUT : status %X\n", w840private.tx_ring[entry].status);    return;}/**************************************************************************w89c840_disable - Turn off ethernet interface***************************************************************************/static void w89c840_disable(struct nic *nic){    /* Don't know what to do to disable the board. Is this needed at all? */    /* Yes, a live NIC can corrupt the loaded memory later [Ken] */    /* Stop the chip's Tx and Rx processes. */    writel(w840private.csr6 &= ~0x20FA, ioaddr + NetworkConfig);}/**************************************************************************w89c840_probe - Look for an adapter, this routine's visible to the outside***************************************************************************/struct nic *w89c840_probe(struct nic *nic, unsigned short *probe_addrs, struct pci_device *p){    u16 sum = 0;    int i, j, to;    unsigned short value;    int options;    int promisc;    if (probe_addrs == 0 || probe_addrs[0] == 0)        return 0;    ioaddr = probe_addrs[0]; /* Mask the bit that says "this is an io addr" */#if defined(W89C840_DEBUG)    printf("winbond-840: PCI bus %hhX device function %hhX: I/O address: %hX\n", p->bus, p->devfn, ioaddr);#endif    ioaddr = ioaddr & ~3; /* Mask the bit that says "this is an io addr" */    /* if probe_addrs is 0, then routine can use a hardwired default */    /* From Matt Hortman <mbhortman@acpthinclient.com> */    if (p->vendor == PCI_VENDOR_ID_WINBOND2        && p->dev_id == PCI_DEVICE_ID_WINBOND2_89C840) {        /* detected "Winbond W89c840 Fast Ethernet PCI NIC" */    } else if ( p->vendor == PCI_VENDOR_ID_COMPEX                && p->dev_id == PCI_DEVICE_ID_COMPEX_RL100ATX) {        /* detected "Compex RL100ATX Fast Ethernet PCI NIC" */    } else {        /* Gee, guess what? They missed again. */        printf("device ID : %X - is not a Compex RL100ATX NIC.\n", p->dev_id);        return 0;    }    printf(" %s\n", w89c840_version);    adjust_pci_device(p);    /* Ok. Got one. Read the eeprom. */    for (j = 0, i = 0; i < 0x40; i++) {        value = eeprom_read(ioaddr, i);        eeprom[i] = value;        sum += value;    }    for (i=0;i<ETH_ALEN;i++) {        nic->node_addr[i] =  (eeprom[i/2] >> (8*(i&1))) & 0xff;    }    printf ("Ethernet addr: %!\n", nic->node_addr);#if defined(W89C840_DEBUG)    printf("winbond-840: EEPROM checksum %hX, got eeprom", sum);#endif    /* Reset the chip to erase previous misconfiguration.       No hold time required! */    writel(0x00000001, ioaddr + PCIBusCfg);    if (driver_flags & CanHaveMII) {        int phy, phy_idx = 0;        for (phy = 1; phy < 32 && phy_idx < 4; phy++) {            int mii_status = mdio_read(ioaddr, phy, 1);            if (mii_status != 0xffff  &&  mii_status != 0x0000) {                w840private.phys[phy_idx++] = phy;                w840private.advertising = mdio_read(ioaddr, phy, 4);#if defined(W89C840_DEBUG)                printf("winbond-840 : MII PHY found at address %d, status "                       "%X advertising %hX.\n", phy, mii_status, w840private.advertising);#endif            }        }        w840private.mii_cnt = phy_idx;        if (phy_idx == 0) {                printf("winbond-840 : MII PHY not found -- this device may not operate correctly.\n");        }    }    /* point to NIC specific routines */    nic->reset = w89c840_reset;    nic->poll = w89c840_poll;    nic->transmit = w89c840_transmit;    nic->disable = w89c840_disable;    w89c840_reset(nic);    return nic;}/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces.  These are   often serial bit streams generated by the host processor.   The example below is for the common 93c46 EEPROM, 64 16 bit words. *//* Delay between EEPROM clock transitions.   No extra delay is needed with 33Mhz PCI, but future 66Mhz access may need   a delay.  Note that pre-2.0.34 kernels had a cache-alignment bug that   made udelay() unreliable.   The old method of using an ISA access as a delay, __SLOW_DOWN_IO__, is   depricated.*/#define eeprom_delay(ee_addr)    readl(ee_addr)enum EEPROM_Ctrl_Bits {    EE_ShiftClk=0x02, EE_Write0=0x801, EE_Write1=0x805,    EE_ChipSelect=0x801, EE_DataIn=0x08,};/* The EEPROM commands include the alway-set leading bit. */enum EEPROM_Cmds {    EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),};static int eeprom_read(long addr, int location){    int i;    int retval = 0;    int ee_addr = addr + EECtrl;    int read_cmd = location | EE_ReadCmd;    writel(EE_ChipSelect, ee_addr);    /* Shift the read command bits out. */    for (i = 10; i >= 0; i--) {        short dataval = (read_cmd & (1 << i)) ? EE_Write1 : EE_Write0;        writel(dataval, ee_addr);        eeprom_delay(ee_addr);        writel(dataval | EE_ShiftClk, ee_addr);        eeprom_delay(ee_addr);    }    writel(EE_ChipSelect, ee_addr);    for (i = 16; i > 0; i--) {        writel(EE_ChipSelect | EE_ShiftClk, ee_addr);        eeprom_delay(ee_addr);        retval = (retval << 1) | ((readl(ee_addr) & EE_DataIn) ? 1 : 0);        writel(EE_ChipSelect, ee_addr);        eeprom_delay(ee_addr);    }    /* Terminate the EEPROM access. */    writel(0, ee_addr);    return retval;}/*  MII transceiver control section.    Read and write the MII registers using software-generated serial    MDIO protocol.  See the MII specifications or DP83840A data sheet    for details.    The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually    met by back-to-back 33Mhz PCI cycles. */#define mdio_delay(mdio_addr) readl(mdio_addr)/* Set iff a MII transceiver on any interface requires mdio preamble.   This only set with older tranceivers, so the extra   code size of a per-interface flag is not worthwhile. */static char mii_preamble_required = 1;#define MDIO_WRITE0 (MDIO_EnbOutput)#define MDIO_WRITE1 (MDIO_DataOut | MDIO_EnbOutput)/* Generate the preamble required for initial synchronization and   a few older transceivers. */static void mdio_sync(long mdio_addr){    int bits = 32;    /* Establish sync by sending at least 32 logic ones. */    while (--bits >= 0) {        writel(MDIO_WRITE1, mdio_addr);        mdio_delay(mdio_addr);        writel(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);        mdio_delay(mdio_addr);    }}static int mdio_read(int base_address, int phy_id, int location){    long mdio_addr = base_address + MIICtrl;    int mii_cmd = (0xf6 << 10) | (phy_id << 5) | location;    int i, retval = 0;    if (mii_preamble_required)        mdio_sync(mdio_addr);    /* Shift the read command bits out. */    for (i = 15; i >= 0; i--) {        int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;        writel(dataval, mdio_addr);        mdio_delay(mdio_addr);        writel(dataval | MDIO_ShiftClk, mdio_addr);        mdio_delay(mdio_addr);    }    /* Read the two transition, 16 data, and wire-idle bits. */    for (i = 20; i > 0; i--) {        writel(MDIO_EnbIn, mdio_addr);        mdio_delay(mdio_addr);        retval = (retval << 1) | ((readl(mdio_addr) & MDIO_DataIn) ? 1 : 0);        writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);        mdio_delay(mdio_addr);    }    return (retval>>1) & 0xffff;}static void mdio_write(int base_address, int phy_id, int location, int value){    long mdio_addr = base_address + MIICtrl;    int mii_cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;    int i;    if (location == 4  &&  phy_id == w840private.phys[0])        w840private.advertising = value;    if (mii_preamble_required)        mdio_sync(mdio_addr);    /* Shift the command bits out. */    for (i = 31; i >= 0; i--) {        int dataval = (mii_cmd & (1 << i)) ? MDIO_WRITE1 : MDIO_WRITE0;        writel(dataval, mdio_addr);        mdio_delay(mdio_addr);        writel(dataval | MDIO_ShiftClk, mdio_addr);        mdio_delay(mdio_addr);    }    /* Clear out extra bits. */    for (i = 2; i > 0; i--) {        writel(MDIO_EnbIn, mdio_addr);        mdio_delay(mdio_addr);        writel(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);        mdio_delay(mdio_addr);    }    return;}static void check_duplex(void){    int mii_reg5 = mdio_read(ioaddr, w840private.phys[0], 5);    int negotiated =  mii_reg5 & w840private.advertising;    int duplex;    if (w840private.duplex_lock  ||  mii_reg5 == 0xffff)        return;    duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;    if (w840private.full_duplex != duplex) {        w840private.full_duplex = duplex;       #if defined(W89C840_DEBUG)        printf("winbond-840 : Setting %s-duplex based on MII # %d negotiated capability %X\n",               duplex ? "full" : "half", w840private.phys[0], negotiated);#endif        w840private.csr6 &= ~0x200;        w840private.csr6 |= duplex ? 0x200 : 0;    }}static void set_rx_mode(void){    u32 mc_filter[2];            /* Multicast hash filter */    u32 rx_mode;    /* Accept all multicasts from now on. */    memset(mc_filter, 0xff, sizeof(mc_filter));/* * Actually, should work OK with multicast enabled. -- iko *//* *  rx_mode = AcceptBroadcast | AcceptMyPhys | AcceptMulticast; */    rx_mode = AcceptBroadcast | AcceptMyPhys;    writel(mc_filter[0], ioaddr + MulticastFilter0);    writel(mc_filter[1], ioaddr + MulticastFilter1);    w840private.csr6 &= ~0x00F8;    w840private.csr6 |= rx_mode;    writel(w840private.csr6, ioaddr + NetworkConfig);#if defined(W89C840_DEBUG)    printf("winbond-840 : Done setting RX mode.\n");#endif}/* Initialize the Rx and Tx rings, along with various 'dev' bits. */static void init_ring(void){    int i;    char * p;    w840private.tx_full = 0;    w840private.tx_q_bytes = w840private.cur_rx = w840private.cur_tx = 0;    w840private.dirty_rx = w840private.dirty_tx = 0;    w840private.rx_buf_sz = PKT_BUF_SZ;    w840private.rx_head_desc = &w840private.rx_ring[0];    /* Initial all Rx descriptors. Fill in the Rx buffers. */    p = &rx_packet[0];    for (i = 0; i < RX_RING_SIZE; i++) {        w840private.rx_ring[i].length = w840private.rx_buf_sz;        w840private.rx_ring[i].status = 0;        w840private.rx_ring[i].next_desc = virt_to_le32desc(&w840private.rx_ring[i+1]);        w840private.rx_ring[i].buffer1 = virt_to_le32desc(p + (PKT_BUF_SZ * i));        w840private.rx_ring[i].status = DescOwn | DescIntr;    }    /* Mark the last entry as wrapping the ring. */    w840private.rx_ring[i-1].length |= DescEndRing;    w840private.rx_ring[i-1].next_desc = virt_to_le32desc(&w840private.rx_ring[0]);    w840private.dirty_rx = (unsigned int)(i - RX_RING_SIZE);    for (i = 0; i < TX_RING_SIZE; i++) {        w840private.tx_ring[i].status = 0;    }    return;}

⌨️ 快捷键说明

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