📄 sis900.c
字号:
{ int i = 0; u32 status = TxRCMP | RxRCMP; outl(0, ioaddr + ier); outl(0, ioaddr + imr); outl(0, ioaddr + rfcr); outl(RxRESET | TxRESET | RESET, ioaddr + cr); /* Check that the chip has finished the reset. */ while (status && (i++ < 1000)) { status ^= (inl(isr + ioaddr) & status); } outl(PESEL, ioaddr + cfg);}/* Function: sis_init_rxfilter * * Description: sets receive filter address to our MAC address * * Arguments: struct nic *nic: NIC data structure * * returns: void. */static voidsis900_init_rxfilter(struct nic *nic){ u32 rfcrSave; int i; rfcrSave = inl(rfcr + ioaddr); /* disable packet filtering before setting filter */ outl(rfcrSave & ~RFEN, rfcr); /* load MAC addr to filter data register */ for (i = 0 ; i < 3 ; i++) { u32 w; w = (u32) *((u16 *)(nic->node_addr)+i); outl((i << RFADDR_shift), ioaddr + rfcr); outl(w, ioaddr + rfdr); if (sis900_debug > 0) printf("sis900_init_rxfilter: Receive Filter Addrss[%d]=%X\n", i, inl(ioaddr + rfdr)); } /* enable packet filitering */ outl(rfcrSave | RFEN, rfcr + ioaddr);}/* * Function: sis_init_txd * * Description: initializes the Tx descriptor * * Arguments: struct nic *nic: NIC data structure * * returns: void. */static voidsis900_init_txd(struct nic *nic){ txd.link = (u32) 0; txd.cmdsts = (u32) 0; txd.bufptr = (u32) &txb[0]; /* load Transmit Descriptor Register */ outl((u32) &txd, ioaddr + txdp); if (sis900_debug > 0) printf("sis900_init_txd: TX descriptor register loaded with: %X\n", inl(ioaddr + txdp));}/* Function: sis_init_rxd * * Description: initializes the Rx descriptor ring * * Arguments: struct nic *nic: NIC data structure * * Returns: void. */static void sis900_init_rxd(struct nic *nic) { int i; cur_rx = 0; /* init RX descriptor */ for (i = 0; i < NUM_RX_DESC; i++) { rxd[i].link = (i+1 < NUM_RX_DESC) ? (u32) &rxd[i+1] : (u32) &rxd[0]; rxd[i].cmdsts = (u32) RX_BUF_SIZE; rxd[i].bufptr = (u32) &rxb[i*RX_BUF_SIZE]; if (sis900_debug > 0) printf("sis900_init_rxd: rxd[%d]=%X link=%X cmdsts=%X bufptr=%X\n", i, &rxd[i], rxd[i].link, rxd[i].cmdsts, rxd[i].bufptr); } /* load Receive Descriptor Register */ outl((u32) &rxd[0], ioaddr + rxdp); if (sis900_debug > 0) printf("sis900_init_rxd: RX descriptor register loaded with: %X\n", inl(ioaddr + rxdp));}/* Function: sis_init_rxd * * Description: * sets the receive mode to accept all broadcast packets and packets * with our MAC address, and reject all multicast packets. * * Arguments: struct nic *nic: NIC data structure * * Returns: void. */static void sis900_set_rx_mode(struct nic *nic){ int i; /* Configure Multicast Hash Table in Receive Filter to reject all MCAST packets */ for (i = 0; i < 8; i++) { /* why plus 0x04? That makes the correct value for hash table. */ outl((u32)(0x00000004+i) << RFADDR_shift, ioaddr + rfcr); outl((u32)(0x0), ioaddr + rfdr); } /* Accept Broadcast packets, destination addresses that match our MAC address */ outl(RFEN | RFAAB, ioaddr + rfcr); return;}/* Function: sis900_check_mode * * Description: checks the state of transmit and receive * parameters on the NIC, and updates NIC registers to match * * Arguments: struct nic *nic: NIC data structure * * Returns: void. */static voidsis900_check_mode (struct nic *nic){ int speed, duplex; u32 tx_flags = 0, rx_flags = 0; mii.chip_info->read_mode(nic, cur_phy, &speed, &duplex); tx_flags = TxATP | (TX_DMA_BURST << TxMXDMA_shift) | (TX_FILL_THRESH << TxFILLT_shift); rx_flags = RX_DMA_BURST << RxMXDMA_shift; if (speed == HW_SPEED_HOME || speed == HW_SPEED_10_MBPS) { rx_flags |= (RxDRNT_10 << RxDRNT_shift); tx_flags |= (TxDRNT_10 << TxDRNT_shift); } else { rx_flags |= (RxDRNT_100 << RxDRNT_shift); tx_flags |= (TxDRNT_100 << TxDRNT_shift); } if (duplex == FDX_CAPABLE_FULL_SELECTED) { tx_flags |= (TxCSI | TxHBI); rx_flags |= RxATX; } outl (tx_flags, ioaddr + txcfg); outl (rx_flags, ioaddr + rxcfg);}/* Function: sis900_read_mode * * Description: retrieves and displays speed and duplex * parameters from the NIC * * Arguments: struct nic *nic: NIC data structure * * Returns: void. */static voidsis900_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex){ int i = 0; u32 status; /* STSOUT register is Latched on Transition, read operation updates it */ while (i++ < 2) status = sis900_mdio_read(phy_addr, MII_STSOUT); if (status & MII_STSOUT_SPD) *speed = HW_SPEED_100_MBPS; else *speed = HW_SPEED_10_MBPS; if (status & MII_STSOUT_DPLX) *duplex = FDX_CAPABLE_FULL_SELECTED; else *duplex = FDX_CAPABLE_HALF_SELECTED; if (status & MII_STSOUT_LINK_FAIL) printf("sis900_read_mode: Media Link Off\n"); else printf("sis900_read_mode: Media Link On %s %s-duplex \n", *speed == HW_SPEED_100_MBPS ? "100mbps" : "10mbps", *duplex == FDX_CAPABLE_FULL_SELECTED ? "full" : "half");}/* Function: amd79c901_read_mode * * Description: retrieves and displays speed and duplex * parameters from the NIC * * Arguments: struct nic *nic: NIC data structure * * Returns: void. */static voidamd79c901_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex){ int i; u16 status; for (i = 0; i < 2; i++) status = sis900_mdio_read(phy_addr, MII_STATUS); if (status & MII_STAT_CAN_AUTO) { /* 10BASE-T PHY */ for (i = 0; i < 2; i++) status = sis900_mdio_read(phy_addr, MII_STATUS_SUMMARY); if (status & MII_STSSUM_SPD) *speed = HW_SPEED_100_MBPS; else *speed = HW_SPEED_10_MBPS; if (status & MII_STSSUM_DPLX) *duplex = FDX_CAPABLE_FULL_SELECTED; else *duplex = FDX_CAPABLE_HALF_SELECTED; if (status & MII_STSSUM_LINK) printf("amd79c901_read_mode: Media Link On %s %s-duplex \n", *speed == HW_SPEED_100_MBPS ? "100mbps" : "10mbps", *duplex == FDX_CAPABLE_FULL_SELECTED ? "full" : "half"); else printf("amd79c901_read_mode: Media Link Off\n"); } else { /* HomePNA */ *speed = HW_SPEED_HOME; *duplex = FDX_CAPABLE_HALF_SELECTED; if (status & MII_STAT_LINK) printf("amd79c901_read_mode:Media Link On 1mbps half-duplex \n"); else printf("amd79c901_read_mode: Media Link Off\n"); }}/** * ics1893_read_mode: - read media mode for ICS1893 PHY * @net_dev: the net device to read mode for * @phy_addr: mii phy address * @speed: the transmit speed to be determined * @duplex: the duplex mode to be determined * * ICS1893 PHY use Quick Poll Detailed Status register * to determine the speed and duplex mode for sis900 */static void ics1893_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex){ int i = 0; u32 status; /* MII_QPDSTS is Latched, read twice in succession will reflect the current state */ for (i = 0; i < 2; i++) status = sis900_mdio_read(phy_addr, MII_QPDSTS); if (status & MII_STSICS_SPD) *speed = HW_SPEED_100_MBPS; else *speed = HW_SPEED_10_MBPS; if (status & MII_STSICS_DPLX) *duplex = FDX_CAPABLE_FULL_SELECTED; else *duplex = FDX_CAPABLE_HALF_SELECTED; if (status & MII_STSICS_LINKSTS) printf("ics1893_read_mode: Media Link On %s %s-duplex \n", *speed == HW_SPEED_100_MBPS ? "100mbps" : "10mbps", *duplex == FDX_CAPABLE_FULL_SELECTED ? "full" : "half"); else printf("ics1893_read_mode: Media Link Off\n");}/** * rtl8201_read_mode: - read media mode for rtl8201 phy * @nic: the net device to read mode for * @phy_addr: mii phy address * @speed: the transmit speed to be determined * @duplex: the duplex mode to be determined * * read MII_STATUS register from rtl8201 phy * to determine the speed and duplex mode for sis900 */static void rtl8201_read_mode(struct nic *nic, int phy_addr, int *speed, int *duplex){ u32 status; status = sis900_mdio_read(phy_addr, MII_STATUS); if (status & MII_STAT_CAN_TX_FDX) { *speed = HW_SPEED_100_MBPS; *duplex = FDX_CAPABLE_FULL_SELECTED; } else if (status & MII_STAT_CAN_TX) { *speed = HW_SPEED_100_MBPS; *duplex = FDX_CAPABLE_HALF_SELECTED; } else if (status & MII_STAT_CAN_T_FDX) { *speed = HW_SPEED_10_MBPS; *duplex = FDX_CAPABLE_FULL_SELECTED; } else if (status & MII_STAT_CAN_T) { *speed = HW_SPEED_10_MBPS; *duplex = FDX_CAPABLE_HALF_SELECTED; } if (status & MII_STAT_LINK) printf("rtl8201_read_mode: Media Link On %s %s-duplex \n", *speed == HW_SPEED_100_MBPS ? "100mbps" : "10mbps", *duplex == FDX_CAPABLE_FULL_SELECTED ? "full" : "half"); else printf("rtl9201_read_config_mode: Media Link Off\n");}/* Function: sis900_transmit * * Description: transmits a packet and waits for completion or timeout. * * Arguments: char d[6]: destination ethernet address. * unsigned short t: ethernet protocol type. * unsigned short s: size of the data-part of the packet. * char *p: the data for the packet. * * Returns: void. */static voidsis900_transmit(struct nic *nic, const char *d, /* Destination */ unsigned int t, /* Type */ unsigned int s, /* size */ const char *p) /* Packet */{ u32 status, to, nstype; u32 tx_status; /* Stop the transmitter */ outl(TxDIS, ioaddr + cr); /* load Transmit Descriptor Register */ outl((u32) &txd, ioaddr + txdp); if (sis900_debug > 1) printf("sis900_transmit: TX descriptor register loaded with: %X\n", inl(ioaddr + txdp)); memcpy(txb, d, ETH_ALEN); memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN); nstype = htons(t); memcpy(txb + 2 * ETH_ALEN, (char*)&nstype, 2); memcpy(txb + ETH_HLEN, p, s); s += ETH_HLEN; s &= DSIZE; if (sis900_debug > 1) printf("sis900_transmit: sending %d bytes ethtype %hX\n", (int) s, t); /* pad to minimum packet size */ while (s < ETH_ZLEN) txb[s++] = '\0'; /* set the transmit buffer descriptor and enable Transmit State Machine */ txd.bufptr = (u32) &txb[0]; txd.cmdsts = (u32) OWN | s; /* restart the transmitter */ outl(TxENA, ioaddr + cr); if (sis900_debug > 1) printf("sis900_transmit: Queued Tx packet size %d.\n", (int) s); to = currticks() + TX_TIMEOUT; while ((((volatile u32) tx_status=txd.cmdsts) & OWN) && (currticks() < to)) /* wait */ ; if (currticks() >= to) { printf("sis900_transmit: TX Timeout! Tx status %X.\n", tx_status); } if (tx_status & (ABORT | UNDERRUN | OWCOLL)) { /* packet unsuccessfully transmited */ printf("sis900_transmit: Transmit error, Tx status %X.\n", tx_status); } /* Disable interrupts by clearing the interrupt mask. */ outl(0, ioaddr + imr);}/* Function: sis900_poll * * Description: checks for a received packet and returns it if found. * * Arguments: struct nic *nic: NIC data structure * * Returns: 1 if a packet was recieved. * 0 if no pacet was recieved. * * Side effects: * Returns (copies) the packet to the array nic->packet. * Returns the length of the packet in nic->packetlen. */static intsis900_poll(struct nic *nic){ u32 rx_status = rxd[cur_rx].cmdsts; int retstat = 0; if (sis900_debug > 2) printf("sis900_poll: cur_rx:%d, status:%X\n", cur_rx, rx_status); if (!(rx_status & OWN)) return retstat; if (sis900_debug > 1) printf("sis900_poll: got a packet: cur_rx:%d, status:%X\n", cur_rx, rx_status); nic->packetlen = (rx_status & DSIZE) - CRC_SIZE; if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) { /* corrupted packet received */ printf("sis900_poll: Corrupted packet received, buffer status = %X\n", rx_status); retstat = 0; } else { /* give packet to higher level routine */ memcpy(nic->packet, (rxb + cur_rx*RX_BUF_SIZE), nic->packetlen); retstat = 1; } /* return the descriptor and buffer to receive ring */ rxd[cur_rx].cmdsts = RX_BUF_SIZE; rxd[cur_rx].bufptr = (u32) &rxb[cur_rx*RX_BUF_SIZE]; if (++cur_rx == NUM_RX_DESC) cur_rx = 0; /* re-enable the potentially idle receive state machine */ outl(RxENA , ioaddr + cr); return retstat;}/* Function: sis900_disable * * Description: Turns off interrupts and stops Tx and Rx engines * * Arguments: struct nic *nic: NIC data structure * * Returns: void. */static voidsis900_disable(struct nic *nic){ /* Disable interrupts by clearing the interrupt mask. */ outl(0, ioaddr + imr); outl(0, ioaddr + ier); /* Stop the chip's Tx and Rx Status Machine */ outl(RxDIS | TxDIS, ioaddr + cr);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -