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

📄 e100.c

📁 本源码是《ARM嵌入式LINUX设备驱动实例开发》一书的PCI设备驱动源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	   wait_after_win:1), pad15_1:1), ignore_ul_bit:1), crc_16_bit:1),	   pad15_2:1), crs_or_cdt:1);/*16*/	u8 fc_delay_lo;/*17*/	u8 fc_delay_hi;/*18*/	u8 X(X(X(X(X(rx_stripping:1, tx_padding:1), rx_crc_transfer:1),	   rx_long_ok:1), fc_priority_threshold:3), pad18:1);/*19*/	u8 X(X(X(X(X(X(X(addr_wake:1, magic_packet_disable:1),	   fc_disable:1), fc_restop:1), fc_restart:1), fc_reject:1),	   full_duplex_force:1), full_duplex_pin:1);/*20*/	u8 X(X(X(pad20_1:5, fc_priority_location:1), multi_ia:1), pad20_2:1);/*21*/	u8 X(X(pad21_1:3, multicast_all:1), pad21_2:4);/*22*/	u8 X(X(rx_d102_mode:1, rx_vlan_drop:1), pad22:6);	u8 pad_d102[9];};#define E100_MAX_MULTICAST_ADDRS	64struct multi {	u16 count;	u8 addr[E100_MAX_MULTICAST_ADDRS * ETH_ALEN + 2/*pad*/];};/* Important: keep total struct u32-aligned */#define UCODE_SIZE			134struct cb {	u16 status;	u16 command;	u32 link;	union {		u8 iaaddr[ETH_ALEN];		u32 ucode[UCODE_SIZE];		struct config config;		struct multi multi;		struct {			u32 tbd_array;			u16 tcb_byte_count;			u8 threshold;			u8 tbd_count;			struct {				u32 buf_addr;				u16 size;				u16 eol;			} tbd;		} tcb;		u32 dump_buffer_addr;	} u;	struct cb *next, *prev;	dma_addr_t dma_addr;	struct sk_buff *skb;};enum loopback {	lb_none = 0, lb_mac = 1, lb_phy = 3,};struct stats {	u32 tx_good_frames, tx_max_collisions, tx_late_collisions,		tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,		tx_multiple_collisions, tx_total_collisions;	u32 rx_good_frames, rx_crc_errors, rx_alignment_errors,		rx_resource_errors, rx_overrun_errors, rx_cdt_errors,		rx_short_frame_errors;	u32 fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported;	u16 xmt_tco_frames, rcv_tco_frames;	u32 complete;};struct mem {	struct {		u32 signature;		u32 result;	} selftest;	struct stats stats;	u8 dump_buf[596];};struct param_range {	u32 min;	u32 max;	u32 count;};struct params {	struct param_range rfds;	struct param_range cbs;};struct nic {	/* Begin: frequently used values: keep adjacent for cache effect */	u32 msg_enable				____cacheline_aligned;	struct net_device *netdev;	struct pci_dev *pdev;	struct rx *rxs				____cacheline_aligned;	struct rx *rx_to_use;	struct rx *rx_to_clean;	struct rfd blank_rfd;	enum ru_state ru_running;	spinlock_t cb_lock			____cacheline_aligned;	spinlock_t cmd_lock;	struct csr __iomem *csr;	enum scb_cmd_lo cuc_cmd;	unsigned int cbs_avail;	struct cb *cbs;	struct cb *cb_to_use;	struct cb *cb_to_send;	struct cb *cb_to_clean;	u16 tx_command;	/* End: frequently used values: keep adjacent for cache effect */	enum {		ich                = (1 << 0),		promiscuous        = (1 << 1),		multicast_all      = (1 << 2),		wol_magic          = (1 << 3),		ich_10h_workaround = (1 << 4),	} flags					____cacheline_aligned;	enum mac mac;	enum phy phy;	struct params params;	struct net_device_stats net_stats;	struct timer_list watchdog;	struct timer_list blink_timer;	struct mii_if_info mii;	struct work_struct tx_timeout_task;	enum loopback loopback;	struct mem *mem;	dma_addr_t dma_addr;	dma_addr_t cbs_dma_addr;	u8 adaptive_ifs;	u8 tx_threshold;	u32 tx_frames;	u32 tx_collisions;	u32 tx_deferred;	u32 tx_single_collisions;	u32 tx_multiple_collisions;	u32 tx_fc_pause;	u32 tx_tco_frames;	u32 rx_fc_pause;	u32 rx_fc_unsupported;	u32 rx_tco_frames;	u32 rx_over_length_errors;	u8 rev_id;	u16 leds;	u16 eeprom_wc;	u16 eeprom[256];	spinlock_t mdio_lock;};static inline void e100_write_flush(struct nic *nic){	/* Flush previous PCI writes through intermediate bridges	 * by doing a benign read */	(void)readb(&nic->csr->scb.status);}static void e100_enable_irq(struct nic *nic){	unsigned long flags;	spin_lock_irqsave(&nic->cmd_lock, flags);	writeb(irq_mask_none, &nic->csr->scb.cmd_hi);	e100_write_flush(nic);	spin_unlock_irqrestore(&nic->cmd_lock, flags);}static void e100_disable_irq(struct nic *nic){	unsigned long flags;	spin_lock_irqsave(&nic->cmd_lock, flags);	writeb(irq_mask_all, &nic->csr->scb.cmd_hi);	e100_write_flush(nic);	spin_unlock_irqrestore(&nic->cmd_lock, flags);}static void e100_hw_reset(struct nic *nic){	/* Put CU and RU into idle with a selective reset to get	 * device off of PCI bus */	writel(selective_reset, &nic->csr->port);	e100_write_flush(nic); udelay(20);	/* Now fully reset device */	writel(software_reset, &nic->csr->port);	e100_write_flush(nic); udelay(20);	/* Mask off our interrupt line - it's unmasked after reset */	e100_disable_irq(nic);}static int e100_self_test(struct nic *nic){	u32 dma_addr = nic->dma_addr + offsetof(struct mem, selftest);	/* Passing the self-test is a pretty good indication	 * that the device can DMA to/from host memory */	nic->mem->selftest.signature = 0;	nic->mem->selftest.result = 0xFFFFFFFF;	writel(selftest | dma_addr, &nic->csr->port);	e100_write_flush(nic);	/* Wait 10 msec for self-test to complete */	msleep(10);	/* Interrupts are enabled after self-test */	e100_disable_irq(nic);	/* Check results of self-test */	if(nic->mem->selftest.result != 0) {		DPRINTK(HW, ERR, "Self-test failed: result=0x%08X\n",			nic->mem->selftest.result);		return -ETIMEDOUT;	}	if(nic->mem->selftest.signature == 0) {		DPRINTK(HW, ERR, "Self-test failed: timed out\n");		return -ETIMEDOUT;	}	return 0;}static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data){	u32 cmd_addr_data[3];	u8 ctrl;	int i, j;	/* Three cmds: write/erase enable, write data, write/erase disable */	cmd_addr_data[0] = op_ewen << (addr_len - 2);	cmd_addr_data[1] = (((op_write << addr_len) | addr) << 16) |		cpu_to_le16(data);	cmd_addr_data[2] = op_ewds << (addr_len - 2);	/* Bit-bang cmds to write word to eeprom */	for(j = 0; j < 3; j++) {		/* Chip select */		writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo);		e100_write_flush(nic); udelay(4);		for(i = 31; i >= 0; i--) {			ctrl = (cmd_addr_data[j] & (1 << i)) ?				eecs | eedi : eecs;			writeb(ctrl, &nic->csr->eeprom_ctrl_lo);			e100_write_flush(nic); udelay(4);			writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);			e100_write_flush(nic); udelay(4);		}		/* Wait 10 msec for cmd to complete */		msleep(10);		/* Chip deselect */		writeb(0, &nic->csr->eeprom_ctrl_lo);		e100_write_flush(nic); udelay(4);	}};/* General technique stolen from the eepro100 driver - very clever */static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr){	u32 cmd_addr_data;	u16 data = 0;	u8 ctrl;	int i;	cmd_addr_data = ((op_read << *addr_len) | addr) << 16;	/* Chip select */	writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo);	e100_write_flush(nic); udelay(4);	/* Bit-bang to read word from eeprom */	for(i = 31; i >= 0; i--) {		ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs;		writeb(ctrl, &nic->csr->eeprom_ctrl_lo);		e100_write_flush(nic); udelay(4);		writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);		e100_write_flush(nic); udelay(4);		/* Eeprom drives a dummy zero to EEDO after receiving		 * complete address.  Use this to adjust addr_len. */		ctrl = readb(&nic->csr->eeprom_ctrl_lo);		if(!(ctrl & eedo) && i > 16) {			*addr_len -= (i - 16);			i = 17;		}		data = (data << 1) | (ctrl & eedo ? 1 : 0);	}	/* Chip deselect */	writeb(0, &nic->csr->eeprom_ctrl_lo);	e100_write_flush(nic); udelay(4);	return le16_to_cpu(data);};/* Load entire EEPROM image into driver cache and validate checksum */static int e100_eeprom_load(struct nic *nic){	u16 addr, addr_len = 8, checksum = 0;	/* Try reading with an 8-bit addr len to discover actual addr len */	e100_eeprom_read(nic, &addr_len, 0);	nic->eeprom_wc = 1 << addr_len;	for(addr = 0; addr < nic->eeprom_wc; addr++) {		nic->eeprom[addr] = e100_eeprom_read(nic, &addr_len, addr);		if(addr < nic->eeprom_wc - 1)			checksum += cpu_to_le16(nic->eeprom[addr]);	}	/* The checksum, stored in the last word, is calculated such that	 * the sum of words should be 0xBABA */	checksum = le16_to_cpu(0xBABA - checksum);	if(checksum != nic->eeprom[nic->eeprom_wc - 1]) {		DPRINTK(PROBE, ERR, "EEPROM corrupted\n");		if (!eeprom_bad_csum_allow)			return -EAGAIN;	}	return 0;}/* Save (portion of) driver EEPROM cache to device and update checksum */static int e100_eeprom_save(struct nic *nic, u16 start, u16 count){	u16 addr, addr_len = 8, checksum = 0;	/* Try reading with an 8-bit addr len to discover actual addr len */	e100_eeprom_read(nic, &addr_len, 0);	nic->eeprom_wc = 1 << addr_len;	if(start + count >= nic->eeprom_wc)		return -EINVAL;	for(addr = start; addr < start + count; addr++)		e100_eeprom_write(nic, addr_len, addr, nic->eeprom[addr]);	/* The checksum, stored in the last word, is calculated such that	 * the sum of words should be 0xBABA */	for(addr = 0; addr < nic->eeprom_wc - 1; addr++)		checksum += cpu_to_le16(nic->eeprom[addr]);	nic->eeprom[nic->eeprom_wc - 1] = le16_to_cpu(0xBABA - checksum);	e100_eeprom_write(nic, addr_len, nic->eeprom_wc - 1,		nic->eeprom[nic->eeprom_wc - 1]);	return 0;}#define E100_WAIT_SCB_TIMEOUT 20000 /* we might have to wait 100ms!!! */#define E100_WAIT_SCB_FAST 20       /* delay like the old code */static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr){	unsigned long flags;	unsigned int i;	int err = 0;	spin_lock_irqsave(&nic->cmd_lock, flags);	/* Previous command is accepted when SCB clears */	for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) {		if(likely(!readb(&nic->csr->scb.cmd_lo)))			break;		cpu_relax();		if(unlikely(i > E100_WAIT_SCB_FAST))			udelay(5);	}	if(unlikely(i == E100_WAIT_SCB_TIMEOUT)) {		err = -EAGAIN;		goto err_unlock;	}	if(unlikely(cmd != cuc_resume))		writel(dma_addr, &nic->csr->scb.gen_ptr);	writeb(cmd, &nic->csr->scb.cmd_lo);err_unlock:	spin_unlock_irqrestore(&nic->cmd_lock, flags);	return err;}static int e100_exec_cb(struct nic *nic, struct sk_buff *skb,	void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *)){	struct cb *cb;	unsigned long flags;	int err = 0;	spin_lock_irqsave(&nic->cb_lock, flags);	if(unlikely(!nic->cbs_avail)) {		err = -ENOMEM;		goto err_unlock;	}	cb = nic->cb_to_use;	nic->cb_to_use = cb->next;	nic->cbs_avail--;	cb->skb = skb;	if(unlikely(!nic->cbs_avail))		err = -ENOSPC;	cb_prepare(nic, cb, skb);	/* Order is important otherwise we'll be in a race with h/w:	 * set S-bit in current first, then clear S-bit in previous. */	cb->command |= cpu_to_le16(cb_s);	wmb();	cb->prev->command &= cpu_to_le16(~cb_s);	while(nic->cb_to_send != nic->cb_to_use) {		if(unlikely(e100_exec_cmd(nic, nic->cuc_cmd,			nic->cb_to_send->dma_addr))) {			/* Ok, here's where things get sticky.  It's			 * possible that we can't schedule the command			 * because the controller is too busy, so			 * let's just queue the command and try again			 * when another command is scheduled. */			if(err == -ENOSPC) {				//request a reset				schedule_work(&nic->tx_timeout_task);			}			break;

⌨️ 快捷键说明

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