📄 e100.c
字号:
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 + -