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

📄 e100.c

📁 网卡的驱动程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		config->rx_discard_short_frames = 0x0;	/* 1=discard, 0=save */		config->promiscuous_mode = 0x1;		/* 1=on, 0=off */	}	if(nic->flags & multicast_all)		config->multicast_all = 0x1;		/* 1=accept, 0=no */	/* disable WoL when up */	if(netif_running(nic->netdev) || !(nic->flags & wol_magic))		config->magic_packet_disable = 0x1;	/* 1=off, 0=on */	if(nic->mac >= mac_82558_D101_A4) {		config->fc_disable = 0x1;	/* 1=Tx fc off, 0=Tx fc on */		config->mwi_enable = 0x1;	/* 1=enable, 0=disable */		config->standard_tcb = 0x0;	/* 1=standard, 0=extended */		config->rx_long_ok = 0x1;	/* 1=VLANs ok, 0=standard */		if(nic->mac >= mac_82559_D101M)			config->tno_intr = 0x1;		/* TCO stats enable */		else			config->standard_stat_counter = 0x0;	}	DPRINTK(HW, DEBUG, "[00-07]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",		c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);	DPRINTK(HW, DEBUG, "[08-15]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",		c[8], c[9], c[10], c[11], c[12], c[13], c[14], c[15]);	DPRINTK(HW, DEBUG, "[16-23]=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",		c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]);}static void e100_setup_iaaddr(struct nic *nic, struct cb *cb,	struct sk_buff *skb){	cb->command = cpu_to_le16(cb_iaaddr);	memcpy(cb->u.iaaddr, nic->netdev->dev_addr, ETH_ALEN);}static void e100_dump(struct nic *nic, struct cb *cb, struct sk_buff *skb){	cb->command = cpu_to_le16(cb_dump);	cb->u.dump_buffer_addr = cpu_to_le32(nic->dma_addr +		offsetof(struct mem, dump_buf));}#define NCONFIG_AUTO_SWITCH	0x0080#define MII_NSC_CONG		MII_RESV1#define NSC_CONG_ENABLE		0x0100#define NSC_CONG_TXREADY	0x0400#define ADVERTISE_FC_SUPPORTED	0x0400static int e100_phy_init(struct nic *nic){	struct net_device *netdev = nic->netdev;	u32 addr;	u16 bmcr, stat, id_lo, id_hi, cong;	/* Discover phy addr by searching addrs in order {1,0,2,..., 31} */	for(addr = 0; addr < 32; addr++) {		nic->mii.phy_id = (addr == 0) ? 1 : (addr == 1) ? 0 : addr;		bmcr = mdio_read(netdev, nic->mii.phy_id, MII_BMCR);		stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR);		stat = mdio_read(netdev, nic->mii.phy_id, MII_BMSR);		if(!((bmcr == 0xFFFF) || ((stat == 0) && (bmcr == 0))))			break;	}	DPRINTK(HW, DEBUG, "phy_addr = %d\n", nic->mii.phy_id);	if(addr == 32)		return -EAGAIN;	/* Selected the phy and isolate the rest */	for(addr = 0; addr < 32; addr++) {		if(addr != nic->mii.phy_id) {			mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE);		} else {			bmcr = mdio_read(netdev, addr, MII_BMCR);			mdio_write(netdev, addr, MII_BMCR,				bmcr & ~BMCR_ISOLATE);		}	}	/* Get phy ID */	id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1);	id_hi = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID2);	nic->phy = (u32)id_hi << 16 | (u32)id_lo;	DPRINTK(HW, DEBUG, "phy ID = 0x%08X\n", nic->phy);	/* Handle National tx phys */#define NCS_PHY_MODEL_MASK	0xFFF0FFFF	if((nic->phy & NCS_PHY_MODEL_MASK) == phy_nsc_tx) {		/* Disable congestion control */		cong = mdio_read(netdev, nic->mii.phy_id, MII_NSC_CONG);		cong |= NSC_CONG_TXREADY;		cong &= ~NSC_CONG_ENABLE;		mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong);	}	if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&	   (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000))) {		/* enable/disable MDI/MDI-X auto-switching.		   MDI/MDI-X auto-switching is disabled for 82551ER/QM chips */		if((nic->mac == mac_82551_E) || (nic->mac == mac_82551_F) ||		   (nic->mac == mac_82551_10) || (nic->mii.force_media) ||		   !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))			mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, 0);		else			mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, NCONFIG_AUTO_SWITCH);	}	return 0;}static int e100_hw_init(struct nic *nic){	int err;	e100_hw_reset(nic);	DPRINTK(HW, ERR, "e100_hw_init\n");	if(!in_interrupt() && (err = e100_self_test(nic)))		return err;	if((err = e100_phy_init(nic)))		return err;	if((err = e100_exec_cmd(nic, cuc_load_base, 0)))		return err;	if((err = e100_exec_cmd(nic, ruc_load_base, 0)))		return err;	if ((err = e100_exec_cb_wait(nic, NULL, e100_setup_ucode)))		return err;	if((err = e100_exec_cb(nic, NULL, e100_configure)))		return err;	if((err = e100_exec_cb(nic, NULL, e100_setup_iaaddr)))		return err;	if((err = e100_exec_cmd(nic, cuc_dump_addr,		nic->dma_addr + offsetof(struct mem, stats))))		return err;	if((err = e100_exec_cmd(nic, cuc_dump_reset, 0)))		return err;	e100_disable_irq(nic);	return 0;}static void e100_multi(struct nic *nic, struct cb *cb, struct sk_buff *skb){	struct net_device *netdev = nic->netdev;	struct dev_mc_list *list = netdev->mc_list;	u16 i, count = min(netdev->mc_count, E100_MAX_MULTICAST_ADDRS);	cb->command = cpu_to_le16(cb_multi);	cb->u.multi.count = cpu_to_le16(count * ETH_ALEN);	for(i = 0; list && i < count; i++, list = list->next)		memcpy(&cb->u.multi.addr[i*ETH_ALEN], &list->dmi_addr,			ETH_ALEN);}static void e100_set_multicast_list(struct net_device *netdev){	struct nic *nic = netdev_priv(netdev);	DPRINTK(HW, DEBUG, "mc_count=%d, flags=0x%04X\n",		netdev->mc_count, netdev->flags);	if(netdev->flags & IFF_PROMISC)		nic->flags |= promiscuous;	else		nic->flags &= ~promiscuous;	if(netdev->flags & IFF_ALLMULTI ||		netdev->mc_count > E100_MAX_MULTICAST_ADDRS)		nic->flags |= multicast_all;	else		nic->flags &= ~multicast_all;	e100_exec_cb(nic, NULL, e100_configure);	e100_exec_cb(nic, NULL, e100_multi);}static void e100_update_stats(struct nic *nic){	struct net_device_stats *ns = &nic->net_stats;	struct stats *s = &nic->mem->stats;	u32 *complete = (nic->mac < mac_82558_D101_A4) ? &s->fc_xmt_pause :		(nic->mac < mac_82559_D101M) ? (u32 *)&s->xmt_tco_frames :		&s->complete;	/* Device's stats reporting may take several microseconds to	 * complete, so where always waiting for results of the	 * previous command. */	if(*complete == le32_to_cpu(cuc_dump_reset_complete)) {		*complete = 0;		nic->tx_frames = le32_to_cpu(s->tx_good_frames);		nic->tx_collisions = le32_to_cpu(s->tx_total_collisions);		ns->tx_aborted_errors += le32_to_cpu(s->tx_max_collisions);		ns->tx_window_errors += le32_to_cpu(s->tx_late_collisions);		ns->tx_carrier_errors += le32_to_cpu(s->tx_lost_crs);		ns->tx_fifo_errors += le32_to_cpu(s->tx_underruns);		ns->collisions += nic->tx_collisions;		ns->tx_errors += le32_to_cpu(s->tx_max_collisions) +			le32_to_cpu(s->tx_lost_crs);		ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors) +			nic->rx_over_length_errors;		ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors);		ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors);		ns->rx_over_errors += le32_to_cpu(s->rx_overrun_errors);		ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors);		ns->rx_missed_errors += le32_to_cpu(s->rx_resource_errors);		ns->rx_errors += le32_to_cpu(s->rx_crc_errors) +			le32_to_cpu(s->rx_alignment_errors) +			le32_to_cpu(s->rx_short_frame_errors) +			le32_to_cpu(s->rx_cdt_errors);		nic->tx_deferred += le32_to_cpu(s->tx_deferred);		nic->tx_single_collisions +=			le32_to_cpu(s->tx_single_collisions);		nic->tx_multiple_collisions +=			le32_to_cpu(s->tx_multiple_collisions);		if(nic->mac >= mac_82558_D101_A4) {			nic->tx_fc_pause += le32_to_cpu(s->fc_xmt_pause);			nic->rx_fc_pause += le32_to_cpu(s->fc_rcv_pause);			nic->rx_fc_unsupported +=				le32_to_cpu(s->fc_rcv_unsupported);			if(nic->mac >= mac_82559_D101M) {				nic->tx_tco_frames +=					le16_to_cpu(s->xmt_tco_frames);				nic->rx_tco_frames +=					le16_to_cpu(s->rcv_tco_frames);			}		}	}	if(e100_exec_cmd(nic, cuc_dump_reset, 0))		DPRINTK(TX_ERR, DEBUG, "exec cuc_dump_reset failed\n");}static void e100_adjust_adaptive_ifs(struct nic *nic, int speed, int duplex){	/* Adjust inter-frame-spacing (IFS) between two transmits if	 * we're getting collisions on a half-duplex connection. */	if(duplex == DUPLEX_HALF) {		u32 prev = nic->adaptive_ifs;		u32 min_frames = (speed == SPEED_100) ? 1000 : 100;		if((nic->tx_frames / 32 < nic->tx_collisions) &&		   (nic->tx_frames > min_frames)) {			if(nic->adaptive_ifs < 60)				nic->adaptive_ifs += 5;		} else if (nic->tx_frames < min_frames) {			if(nic->adaptive_ifs >= 5)				nic->adaptive_ifs -= 5;		}		if(nic->adaptive_ifs != prev)			e100_exec_cb(nic, NULL, e100_configure);	}}static void e100_watchdog(unsigned long data){	struct nic *nic = (struct nic *)data;	struct ethtool_cmd cmd;	DPRINTK(TIMER, DEBUG, "right now = %ld\n", jiffies);	/* mii library handles link maintenance tasks */	mii_ethtool_gset(&nic->mii, &cmd);	if(mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) {		DPRINTK(LINK, INFO, "link up, %sMbps, %s-duplex\n",			cmd.speed == SPEED_100 ? "100" : "10",			cmd.duplex == DUPLEX_FULL ? "full" : "half");	} else if(!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) {		DPRINTK(LINK, INFO, "link down\n");	}	mii_check_link(&nic->mii);	/* Software generated interrupt to recover from (rare) Rx	 * allocation failure.	 * Unfortunately have to use a spinlock to not re-enable interrupts	 * accidentally, due to hardware that shares a register between the	 * interrupt mask bit and the SW Interrupt generation bit */	spin_lock_irq(&nic->cmd_lock);	writeb(readb(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi);	spin_unlock_irq(&nic->cmd_lock);	e100_write_flush(nic);	e100_update_stats(nic);	e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex);	if(nic->mac <= mac_82557_D100_C)		/* Issue a multicast command to workaround a 557 lock up */		e100_set_multicast_list(nic->netdev);	if(nic->flags & ich && cmd.speed==SPEED_10 && cmd.duplex==DUPLEX_HALF)		/* Need SW workaround for ICH[x] 10Mbps/half duplex Tx hang. */		nic->flags |= ich_10h_workaround;	else		nic->flags &= ~ich_10h_workaround;	mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD);}static void e100_xmit_prepare(struct nic *nic, struct cb *cb,	struct sk_buff *skb){	cb->command = nic->tx_command;	/* interrupt every 16 packets regardless of delay */	if((nic->cbs_avail & ~15) == nic->cbs_avail)		cb->command |= cpu_to_le16(cb_i);	cb->u.tcb.tbd_array = cb->dma_addr + offsetof(struct cb, u.tcb.tbd);	cb->u.tcb.tcb_byte_count = 0;	cb->u.tcb.threshold = nic->tx_threshold;	cb->u.tcb.tbd_count = 1;	cb->u.tcb.tbd.buf_addr = cpu_to_le32(pci_map_single(nic->pdev,		skb->data, skb->len, PCI_DMA_TODEVICE));	/* check for mapping failure? */	cb->u.tcb.tbd.size = cpu_to_le16(skb->len);}static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev){	struct nic *nic = netdev_priv(netdev);	int err;	if(nic->flags & ich_10h_workaround) {		/* SW workaround for ICH[x] 10Mbps/half duplex Tx hang.		   Issue a NOP command followed by a 1us delay before		   issuing the Tx command. */		if(e100_exec_cmd(nic, cuc_nop, 0))			DPRINTK(TX_ERR, DEBUG, "exec cuc_nop failed\n");		udelay(1);	}	err = e100_exec_cb(nic, skb, e100_xmit_prepare);	switch(err) {	case -ENOSPC:		/* We queued the skb, but now we're out of space. */		DPRINTK(TX_ERR, DEBUG, "No space for CB\n");		netif_stop_queue(netdev);		break;	case -ENOMEM:		/* This is a hard error - log it. */		DPRINTK(TX_ERR, DEBUG, "Out of Tx resources, returning skb\n");		netif_stop_queue(netdev);		return 1;	}	netdev->trans_start = jiffies;	return 0;}static int e100_tx_clean(struct nic *nic){	struct cb *cb;	int tx_cleaned = 0;	spin_lock(&nic->cb_lock);	/* Clean CBs marked complete */	for(cb = nic->cb_to_clean;	    cb->status & cpu_to_le16(cb_complete);	    cb = nic->cb_to_clean = cb->next) {		DPRINTK(TX_DONE, DEBUG, "cb[%d]->status = 0x%04X\n",		        (int)(((void*)cb - (void*)nic->cbs)/sizeof(struct cb)),		        cb->status);		if(likely(cb->skb != NULL)) {			nic->net_stats.tx_packets++;			nic->net_stats.tx_bytes += cb->skb->len;			pci_unmap_single(nic->pdev,				le32_to_cpu(cb->u.tcb.tbd.buf_addr),				le16_to_cpu(cb->u.tcb.tbd.size),				PCI_DMA_TODEVICE);			dev_kfree_skb_any(cb->skb);			cb->skb = NULL;			tx_cleaned = 1;		}		cb->status = 0;		nic->cbs_avail++;	}	spin_unlock(&nic->cb_lock);	/* Recover from running out of Tx resources in xmit_frame */	if(unlikely(tx_cleaned && netif_queue_stopped(nic->netdev)))		netif_wake_queue(nic->netdev);	return tx_cleaned;}static void e100_clean_cbs(struct nic *nic){	if(nic->cbs) {		while(nic->cbs_avail != nic->params.cbs.count) {			struct cb *cb = nic->cb_to_clean;			if(cb->skb) {				pci_unmap_single(nic->pdev,					le32_to_cpu(cb->u.tcb.tbd.buf_addr),					le16_to_cpu(cb->u.tcb.tbd.size),					PCI_DMA_TODEVICE);				dev_kfree_skb(cb->skb);			}			nic->cb_to_clean = nic->cb_to_clean->next;			nic->cbs_avail++;		}		pci_free_consistent(nic->pdev,			sizeof(struct cb) * nic->params.cbs.count,			nic->cbs, nic->cbs_dma_addr);		nic->cbs = NULL;		nic->cbs_avail = 0;	}	nic->cuc_cmd = cuc_start;	nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean =		nic->cbs;}static int e100_alloc_cbs(struct nic *nic){	struct cb *cb;	unsigned int i, count = nic->params.cbs.count;	nic->cuc_cmd = cuc_start;	nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = NULL;	nic->cbs_avail = 0;	nic->cbs = pci_alloc_consistent(nic->pdev,		sizeof(struct cb) * count, &nic->cbs_dma_addr);	if(!nic->cbs)		return -ENOMEM;	for(cb = nic->cbs, i = 0; i < count; cb++, i++) {		cb->next = (i + 1 < count) ? cb + 1 : nic->cbs;

⌨️ 快捷键说明

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