📄 sis900.c
字号:
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 __unused, int phy_addr, int *speed, int *duplex){ int i = 0; u32 status; u16 phy_id0, phy_id1; /* STSOUT register is Latched on Transition, read operation updates it */ while (i++ < 2) status = sis900_mdio_read(phy_addr, MII_STSOUT); *speed = HW_SPEED_10_MBPS; *duplex = FDX_CAPABLE_HALF_SELECTED; if (status & (MII_NWAY_TX | MII_NWAY_TX_FDX)) *speed = HW_SPEED_100_MBPS; if (status & ( MII_NWAY_TX_FDX | MII_NWAY_T_FDX)) *duplex = FDX_CAPABLE_FULL_SELECTED; /* Workaround for Realtek RTL8201 PHY issue */ phy_id0 = sis900_mdio_read(phy_addr, MII_PHY_ID0); phy_id1 = sis900_mdio_read(phy_addr, MII_PHY_ID1); if((phy_id0 == 0x0000) && ((phy_id1 & 0xFFF0) == 0x8200)){ if(sis900_mdio_read(phy_addr, MII_CONTROL) & MII_CNTL_FDX) *duplex = FDX_CAPABLE_FULL_SELECTED; if(sis900_mdio_read(phy_addr, 0x0019) & 0x01) *speed = HW_SPEED_100_MBPS; } 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 __unused, 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 __unused, 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 __unused, 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("rtl8201_read_config_mode: Media Link Off\n");}/** * vt6103_read_mode: - read media mode for vt6103 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 vt6103_read_mode(struct nic *nic __unused, 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("vt6103_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("vt6103_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 to, nstype; u32 tx_status; /* Stop the transmitter */ outl(TxDIS | inl(ioaddr + cr), ioaddr + cr); /* load Transmit Descriptor Register */ outl(virt_to_bus(&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 = virt_to_bus(&txb[0]); txd.cmdsts = (u32) OWN | s; /* restart the transmitter */ outl(TxENA | inl(ioaddr + cr), 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 = virt_to_bus(&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 | inl(ioaddr + cr), 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 dev *dev){ struct nic *nic = (struct nic *)dev; /* merge reset and disable */ sis900_init(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 | inl(ioaddr + cr), ioaddr + cr);}static struct pci_id sis900_nics[] = {PCI_ROM(0x1039, 0x0900, "sis900", "SIS900"),PCI_ROM(0x1039, 0x7016, "sis7016", "SIS7016"),};static struct pci_driver sis900_driver __pci_driver = { .type = NIC_DRIVER, .name = "SIS900", .probe = sis900_probe, .ids = sis900_nics, .id_count = sizeof(sis900_nics)/sizeof(sis900_nics[0]), .class = 0,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -