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

📄 sundance.c

📁 linux下从网卡远程启动
💻 C
📖 第 1 页 / 共 2 页
字号:
	/* return true if there's an ethernet packet ready to read */	/* nic->packet should contain data on return */	/* nic->packetlen should contain length of data */	int entry = sdc->cur_rx % RX_RING_SIZE;	int boguscnt = 32;	int received = 0;	struct netdev_desc *desc = &(rx_ring[entry]);	u32 frame_status = le32_to_cpu(desc->status);	int pkt_len = 0;	if (--boguscnt < 0) {		goto not_done;	}	if (!(frame_status & DescOwn))		return 0;	pkt_len = frame_status & 0x1fff;	if (frame_status & 0x001f4000) {#ifdef EDEBUG		/* FIXME: Do we really care about this */		printf("There was an error\n");#endif	} else {		if (pkt_len < rx_copybreak) {			/* FIXME: What should happen Will this ever occur */			printf("Problem");		} else {			nic->packetlen = pkt_len;			memcpy(nic->packet, rxb +			       (sdc->cur_rx * PKT_BUF_SZ), nic->packetlen);		}	}	entry = (entry + 1) % RX_RING_SIZE;	received++;	sdc->cur_rx = entry;	refill_rx(nic);	sdc->budget -= received;	return 1;      not_done:	sdc->cur_rx = entry;	refill_rx(nic);	if (!received)		received = 1;	sdc->budget -= received;	if (sdc->budget <= 0)		sdc->budget = 32;#ifdef EDEBUG	printf("Not Done\n");#endif	return 0;}static void refill_rx(struct nic *nic __unused){	int entry;	int cnt = 0;	/* Refill the Rx ring buffers. */	for (;	     (sdc->cur_rx - sdc->dirty_rx + RX_RING_SIZE) % RX_RING_SIZE >	     0; sdc->dirty_rx = (sdc->dirty_rx + 1) % RX_RING_SIZE) {		entry = sdc->dirty_rx % RX_RING_SIZE;		/* Perhaps we need not reset this field. */		rx_ring[entry].length =		    cpu_to_le32(sdc->rx_buf_sz | LastFrag);		rx_ring[entry].status = 0;		cnt++;	}	return;}/**************************************************************************TRANSMIT - Transmit a frame***************************************************************************/static void sundance_transmit(struct nic *nic, const char *d,	/* Destination */			      unsigned int t,	/* Type */			      unsigned int s,	/* size */			      const char *p){				/* Packet */	u16 nstype;	u32 to;	/* Disable the Tx */	outw(TxDisable, BASE + MACCtrl1);	memcpy(txb, d, ETH_ALEN);	memcpy(txb + ETH_ALEN, nic->node_addr, ETH_ALEN);	nstype = htons((u16) t);	memcpy(txb + 2 * ETH_ALEN, (u8 *) & nstype, 2);	memcpy(txb + ETH_HLEN, p, s);	s += ETH_HLEN;	s &= 0x0FFF;	while (s < ETH_ZLEN)		txb[s++] = '\0';	/* Setup the transmit descriptor */	tx_ring[0].length = cpu_to_le32(s | LastFrag);	tx_ring[0].status = cpu_to_le32(0x00000001);	/* Point to transmit descriptor */	outl(virt_to_le32desc(&tx_ring[0]), BASE + TxListPtr);	/* Enable Tx */	outw(TxEnable, BASE + MACCtrl1);	outw(0, BASE + TxStatus);	to = currticks() + TX_TIME_OUT;	while(!(tx_ring[0].status & 0x00010000) &&  (currticks() < to))		; /* wait */ 	if (currticks() >= to) {		printf("TX Time Out");	}	/* Disable Tx */	outw(TxDisable, BASE + MACCtrl1);}/**************************************************************************DISABLE - Turn off ethernet interface***************************************************************************/static void sundance_disable(struct dev *dev){	/* put the card in its initial state */	/* This function serves 3 purposes.	 * This disables DMA and interrupts so we don't receive	 *  unexpected packets or interrupts from the card after	 *  etherboot has finished.	 * This frees resources so etherboot may use	 *  this driver on another interface	 * This allows etherboot to reinitialize the interface	 *  if something is something goes wrong.	 */	sundance_reset((struct nic *) dev); 	outw(0x0000, BASE + IntrEnable);	/* Stop the Chipchips Tx and Rx Status */	outw(TxDisable | RxDisable | StatsDisable, BASE + MACCtrl1);}/**************************************************************************PROBE - Look for an adapter, this routine's visible to the outside***************************************************************************/static int sundance_probe(struct dev *dev, struct pci_device *pci){	struct nic *nic = (struct nic *) dev;	int card_idx = 1;	u8 ee_data[EEPROM_SIZE];	int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;	if (pci->ioaddr == 0)		return 0;	/* BASE is used throughout to address the card */	BASE = pci->ioaddr;	printf("\n");	printf("sundance.c: %s, %s\n", drv_version, drv_date);	printf("%s: Probing for Vendor=%hX   Device=%hX\n",	       pci->name, pci->vendor, pci->dev_id);	/* Get the MAC Address by reading the EEPROM */	for (i = 0; i < 3; i++) {		((u16 *) ee_data)[i] =		    le16_to_cpu(eeprom_read(BASE, i + EEPROM_SA_OFFSET));	}	/* Update the nic structure with the MAC Address */	for (i = 0; i < ETH_ALEN; i++) {		nic->node_addr[i] = ee_data[i];	}	/* Print out some hardware info */	printf("%s: %! at ioaddr %hX\n", pci->name, nic->node_addr, BASE);	/* I really must find out what this does */	adjust_pci_device(pci);	/* point to private storage */	sdc = &sdx;	sdc->chip_id = 0;	/* Undefined */	sdc->drv_flags = 0;	/* Undefined */	sdc->rx_copybreak = rx_copybreak;	sdc->max_interrupt_word = max_interrupt_work;	sdc->multicast_filter_limit = multicast_filter_limit;	sdc->vendor_id = pci->vendor;	sdc->dev_id = pci->dev_id;	sdc->nic_name = pci->name;	sdc->mtu = mtu;	if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0) {		sdc->full_duplex = 1;#ifdef EDEBUG		printf("sdc->full_duplex = 1\n");#endif	}	if (sdc->full_duplex) {		sdc->medialock = 1;#ifdef EDEBUG		printf("sdc->media_lock = 1\n");#endif	}	if (1) {		int phy, phy_idx = 0;		sdc->phys[0] = 1;	/* Default Setting */		mii_preamble_required++;		for (phy = 1; phy < 32 && phy_idx < 4; phy++) {			int mii_status = mdio_read(nic, phy, 1);			if (mii_status != 0xffff && mii_status != 0x0000) {				sdc->phys[phy_idx++] = phy;				sdc->advertizing = mdio_read(nic, phy, 4);				if ((mii_status & 0x0040) == 0)					mii_preamble_required++;#ifdef EDEBUG				printf				    ("%s: MII PHY found at address %d, status "				     "%hX advertizing %hX\n",				     sdc->nic_name, phy, mii_status,				     sdc->advertizing);#endif			}		}		mii_preamble_required--;		sdc->mii_cnt = phy_idx;		if (phy_idx == 0)			printf("%s: No MII transceiver found!\n",			       sdc->nic_name);	}	/* Allow forcing the media type */	if (option > 0) {#ifdef EDEBUG		printf("Trying to force the media type\n");#endif		if (option & 0x220)			sdc->full_duplex = 1;		sdc->default_port = option & 0x3ff;		if (sdc->default_port & 0x330) {			sdc->medialock = 1;#ifdef EDEBUG			printf("Forcing %dMbs %s-duplex operation.\n",			       (option & 0x300 ? 100 : 10),			       (sdc->full_duplex ? "full" : "half"));#endif			if (sdc->mii_cnt)				mdio_write(nic, sdc->phys[0],					0, ((option & 0x300) ? 0x2000 : 0)					|	/* 100mbps */					(sdc->full_duplex ? 0x0100 : 0));	/* Full Duplex? */		}	}	/* Reset the chip to erase previous misconfiguration */#ifdef EDEBUG	printf("ASIC Control is %hX\n", (int) inl(BASE + ASICCtrl));#endif	outl(0x007f0000 | inl(BASE + ASICCtrl), BASE + ASICCtrl);#ifdef EDEBUG	printf("ASIC Control is now %hX\n", (int) inl(BASE + ASICCtrl));#endif	sundance_reset(nic);	/* point to NIC specific routines */	dev->disable = sundance_disable;	nic->poll = sundance_poll;	nic->transmit = sundance_transmit;	return 1;}/* Read the EEPROM and MII Management Data I/O (MDIO) interfaces. */static int eeprom_read(long ioaddr, int location){	int boguscnt = 2000;	/* Typical 190 ticks */	outw(0x0200 | (location & 0xff), ioaddr + EECtrl);	do {		if (!(inw(ioaddr + EECtrl) & 0x8000)) {			return inw(ioaddr + EEData);		}	}	while (--boguscnt > 0);	return 0;}/*  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 timing is decoupled from the processor clock by flushing the write	from the CPU write buffer with a following read, and using PCI	transaction time. */#define mdio_in(mdio_addr) inb(mdio_addr)#define mdio_out(value, mdio_addr) outb(value, mdio_addr)#define mdio_delay(mdio_addr) inb(mdio_addr)enum mii_reg_bits {	MDIO_ShiftClk = 0x0001, MDIO_Data = 0x0002, MDIO_EnbOutput =	    0x0004,};#define MDIO_EnbIn  (0)#define MDIO_WRITE0 (MDIO_EnbOutput)#define MDIO_WRITE1 (MDIO_Data | 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) {		mdio_out(MDIO_WRITE1, mdio_addr);		mdio_delay(mdio_addr);		mdio_out(MDIO_WRITE1 | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}}static intmdio_read(struct nic *nic __unused, int phy_id, unsigned int location){	long mdio_addr = BASE + 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;		mdio_out(dataval, mdio_addr);		mdio_delay(mdio_addr);		mdio_out(dataval | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}	/* Read the two transition, 16 data, and wire-idle bits. */	for (i = 19; i > 0; i--) {		mdio_out(MDIO_EnbIn, mdio_addr);		mdio_delay(mdio_addr);		retval = (retval << 1) | ((mdio_in(mdio_addr) & MDIO_Data)					  ? 1 : 0);		mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}	return (retval >> 1) & 0xffff;}static voidmdio_write(struct nic *nic __unused, int phy_id,	   unsigned int location, int value){	long mdio_addr = BASE + MIICtrl;	int mii_cmd =	    (0x5002 << 16) | (phy_id << 23) | (location << 18) | value;	int i;	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;		mdio_out(dataval, mdio_addr);		mdio_delay(mdio_addr);		mdio_out(dataval | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}	/* Clear out extra bits. */	for (i = 2; i > 0; i--) {		mdio_out(MDIO_EnbIn, mdio_addr);		mdio_delay(mdio_addr);		mdio_out(MDIO_EnbIn | MDIO_ShiftClk, mdio_addr);		mdio_delay(mdio_addr);	}	return;}/* The little-endian AUTODIN II ethernet CRC calculations.   A big-endian version is also available.   This is slow but compact code.  Do not use this routine for bulk data,   use a table-based routine instead.   This is common code and should be moved to net/core/crc.c.   Chips may use the upper or lower CRC bits, and may reverse and/or invert   them.  Select the endian-ness that results in minimal calculations.*/static unsigned const ethernet_polynomial_le = 0xedb88320U;static inline unsigned ether_crc_le(int length, unsigned char *data){	unsigned int crc = ~0;	/* Initial value. */	while (--length >= 0) {		unsigned char current_octet = *data++;		int bit;		for (bit = 8; --bit >= 0; current_octet >>= 1) {			if ((crc ^ current_octet) & 1) {				crc >>= 1;				crc ^= ethernet_polynomial_le;			} else				crc >>= 1;		}	}	return crc;}static void set_rx_mode(struct nic *nic __unused){	int i;	u16 mc_filter[4];	/* Multicast hash filter */	u32 rx_mode;	memset(mc_filter, 0xff, sizeof(mc_filter));	rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;		for(i = 0; i < 4; i++) 		outw(mc_filter[i], BASE + MulticastFilter0 + i*2);		outb(rx_mode, BASE + RxMode);	return;}static struct pci_id sundance_nics[] = {PCI_ROM(0x13f0, 0x0201, "sundance",  "ST201 Sundance 'Alta' based Adaptor"),PCI_ROM(0x1186, 0x1002, "dfe530txs", "D-Link DFE530TXS (Sundance ST201 Alta)"),};static struct pci_driver sundance_driver __pci_driver = {	.type = NIC_DRIVER,	.name = "SUNDANCE/PCI",	.probe = sundance_probe,	.ids = sundance_nics,	.id_count = sizeof(sundance_nics) / sizeof(sundance_nics[0]),	.class = 0,};

⌨️ 快捷键说明

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