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

📄 acenic.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	memset(ap->rx_jumbo_ring, 0,	       RX_JUMBO_RING_ENTRIES * sizeof(struct rx_desc));	info->rx_mini_ctrl.max_len = 0;#if 0	set_aceaddr(&info->rx_mini_ctrl.rngptr, ap->rx_mini_ring);#else	set_aceaddr_bus(&info->rx_mini_ctrl.rngptr, 0);#endif	info->rx_mini_ctrl.flags = FLG_RNG_DISABLED;#if 0	memset(ap->rx_mini_ring, 0,	       RX_MINI_RING_ENTRIES * sizeof(struct rx_desc));#endif	set_aceaddr(&info->rx_return_ctrl.rngptr, ap->rx_return_ring);	info->rx_return_ctrl.flags = 0;	info->rx_return_ctrl.max_len = RX_RETURN_RING_ENTRIES;	memset(ap->rx_return_ring, 0,	       RX_RETURN_RING_ENTRIES * sizeof(struct rx_desc));	set_aceaddr(&info->rx_ret_prd_ptr, &ap->rx_ret_prd);	writel(TX_RING_BASE, &regs->WinBase);	ap->tx_ring = (struct tx_desc *)regs->Window;	for (i = 0; i < (TX_RING_ENTRIES * sizeof(struct tx_desc) / 4); i++){		writel(0, (unsigned long)ap->tx_ring + i * 4);	}	info->tx_ctrl.max_len = TX_RING_ENTRIES;	info->tx_ctrl.flags = 0;	set_aceaddr_bus(&info->tx_ctrl.rngptr, (void *)TX_RING_BASE);	set_aceaddr(&info->tx_csm_ptr, &ap->tx_csm);	/*	 * Potential item for tuning parameter	 */	writel(DMA_THRESH_8W, &regs->DmaReadCfg);	writel(DMA_THRESH_8W, &regs->DmaWriteCfg);	writel(0, &regs->MaskInt);	writel(1, &regs->IfIdx);	writel(1, &regs->AssistState);	writel(DEF_STAT, &regs->TuneStatTicks);	writel(DEF_TX_COAL, &regs->TuneTxCoalTicks);	writel(DEF_TX_MAX_DESC, &regs->TuneMaxTxDesc);	writel(DEF_RX_COAL, &regs->TuneRxCoalTicks);	writel(DEF_RX_MAX_DESC, &regs->TuneMaxRxDesc);	writel(DEF_TRACE, &regs->TuneTrace);	writel(DEF_TX_RATIO, &regs->TxBufRat);	if (board_idx >= 8) {		printk(KERN_WARNING "%s: more then 8 NICs detected, "		       "ignoring module parameters!\n", dev->name);		board_idx = -1;	}	if (board_idx >= 0) {		if (tx_coal_tick[board_idx])			writel(tx_coal_tick[board_idx],			       &regs->TuneTxCoalTicks);		if (max_tx_desc[board_idx])			writel(max_tx_desc[board_idx], &regs->TuneMaxTxDesc);		if (rx_coal_tick[board_idx])			writel(rx_coal_tick[board_idx],			       &regs->TuneRxCoalTicks);		if (max_rx_desc[board_idx])			writel(max_rx_desc[board_idx], &regs->TuneMaxRxDesc);		if (trace[board_idx])			writel(trace[board_idx], &regs->TuneTrace);		if ((tx_ratio[board_idx] >= 0) && (tx_ratio[board_idx] < 64))			writel(tx_ratio[board_idx], &regs->TxBufRat);	}	/*	 * Default link parameters	 */	tmp = LNK_ENABLE | LNK_FULL_DUPLEX | LNK_1000MB | LNK_100MB |		LNK_10MB | LNK_RX_FLOW_CTL_Y | LNK_NEG_FCTL | LNK_NEGOTIATE;	if(ap->version == 2)		tmp |= LNK_TX_FLOW_CTL_Y;	/*	 * Override link default parameters	 */	if ((board_idx >= 0) && link[board_idx]) {		int option = link[board_idx];		tmp = LNK_ENABLE;		if (option & 0x01){			printk(KERN_INFO "%s: Setting half duplex link\n",			       dev->name);			tmp &= ~LNK_FULL_DUPLEX;		}		if (option & 0x02)			tmp &= ~LNK_NEGOTIATE;		if (option & 0x10)			tmp |= LNK_10MB;		if (option & 0x20)			tmp |= LNK_100MB;		if (option & 0x40)			tmp |= LNK_1000MB;		if ((option & 0x70) == 0){			printk(KERN_WARNING "%s: No media speed specified, "			       "forcing auto negotiation\n", dev->name);			tmp |= LNK_NEGOTIATE | LNK_1000MB |				LNK_100MB | LNK_10MB;		}		if ((option & 0x100) == 0)			tmp |= LNK_NEG_FCTL;		else			printk(KERN_INFO "%s: Disabling flow control "			       "negotiation\n", dev->name);		if (option & 0x200)			tmp |= LNK_RX_FLOW_CTL_Y;		if ((option & 0x400) && (ap->version == 2)){			printk(KERN_INFO "%s: Enabling TX flow control\n",			       dev->name);			tmp |= LNK_TX_FLOW_CTL_Y;		}	}	writel(tmp, &regs->TuneLink);	if (ap->version == 2)		writel(tmp, &regs->TuneFastLink);	if (ap->version == 1)		writel(tigonFwStartAddr, &regs->Pc);	else if (ap->version == 2)		writel(tigon2FwStartAddr, &regs->Pc);	writel(0, &regs->Mb0Lo);	/*	 * Start the NIC CPU	 */	writel(readl(&regs->CpuCtrl) & ~(CPU_HALT|CPU_TRACE), &regs->CpuCtrl);	/*	 * Wait for the firmware to spin up - max 3 seconds.	 */	myjif = jiffies + 3 * HZ;	while (time_before(jiffies, myjif) && !ap->fw_running);	if (!ap->fw_running){		printk(KERN_ERR "%s: Firmware NOT running!\n", dev->name);		ace_dump_trace(ap);		writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);		return -EBUSY;	}	/*	 * We load the ring here as there seem to be no way to tell the	 * firmware to wipe the ring without re-initializing it.	 */	ace_load_std_rx_ring(dev);	return 0;}/* * Monitor the card to detect hangs. */static void ace_timer(unsigned long data){	struct device *dev = (struct device *)data;	struct ace_private *ap = (struct ace_private *)dev->priv;	struct ace_regs *regs = ap->regs;	/*	 * We haven't received a stats update event for more than 2.5	 * seconds and there is data in the transmit queue, thus we	 * asume the card is stuck.	 */	if (ap->tx_csm != ap->tx_ret_csm){		printk(KERN_WARNING "%s: Transmitter is stuck, %08x\n",		       dev->name, (unsigned int)readl(&regs->HostCtrl));	}	ap->timer.expires = jiffies + (5/2*HZ);	add_timer(&ap->timer);}/* * Copy the contents of the NIC's trace buffer to kernel memory. */static void ace_dump_trace(struct ace_private *ap){#if 0	if (!ap->trace_buf)		if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL)));		    return;#endif}/* * Load the standard rx ring. */static int ace_load_std_rx_ring(struct device *dev){	struct ace_private *ap;	struct ace_regs *regs;	struct ace_info *info;	unsigned long flags;	struct cmd cmd;	short i;	ap = (struct ace_private *)dev->priv;	regs = ap->regs;	info = ap->info;	spin_lock_irqsave(&ap->lock, flags);	/*	 * Set tx_csm before we start receiving interrupts, otherwise	 * the interrupt handler might think it is supposed to process	 * tx ints before we are up and running, which may cause a null	 * pointer access in the int handler.	 */	ap->tx_full = 0;	ap->cur_rx = ap->dirty_rx = 0;	ap->tx_prd = ap->tx_csm = ap->tx_ret_csm = 0;	writel(0, &regs->RxRetCsm);	for (i = 0; i < RX_RING_THRESH; i++) {		struct sk_buff *skb;		ap->rx_std_ring[i].flags = 0;		skb = alloc_skb(ACE_STD_MTU + ETH_HLEN + 6, GFP_ATOMIC);		ap->rx_std_skbuff[i] = skb;		/*		 * Make sure the data contents end up on an aligned address		 */		skb_reserve(skb, 2);		set_aceaddr(&ap->rx_std_ring[i].addr, skb->data);		ap->rx_std_ring[i].size = ACE_STD_MTU + ETH_HLEN + 4;		ap->rx_std_ring[i].flags = 0;		ap->rx_std_ring[i].type = DESC_RX;		ap->rx_std_ring[i].idx = i;	}	ap->rx_std_skbprd = i;	/*	 * The last descriptor needs to be marked as being special.	 */	ap->rx_std_ring[i-1].type = DESC_END;	cmd.evt = C_SET_RX_PRD_IDX;	cmd.code = 0;	cmd.idx = ap->rx_std_skbprd;	ace_issue_cmd(regs, &cmd);	spin_unlock_irqrestore(&ap->lock, flags);	return 0;}/* * Load the jumbo rx ring, this may happen at any time if the MTU * is changed to a value > 1500. */static int ace_load_jumbo_rx_ring(struct device *dev){	struct ace_private *ap;	struct ace_regs *regs;	struct cmd cmd;	unsigned long flags;	short i;	ap = (struct ace_private *)dev->priv;	regs = ap->regs;	spin_lock_irqsave(&ap->lock, flags);	for (i = 0; i < RX_RING_JUMBO_THRESH; i++) {		struct sk_buff *skb;		ap->rx_jumbo_ring[i].flags = 0;		skb = alloc_skb(ACE_JUMBO_MTU + ETH_HLEN + 6, GFP_ATOMIC);		ap->rx_jumbo_skbuff[i] = skb;		/*		 * Make sure the data contents end up on an aligned address		 */		skb_reserve(skb, 2);		set_aceaddr(&ap->rx_jumbo_ring[i].addr, skb->data);		ap->rx_jumbo_ring[i].size = ACE_JUMBO_MTU + ETH_HLEN + 4;		ap->rx_jumbo_ring[i].flags = DFLG_RX_JUMBO;		ap->rx_jumbo_ring[i].type = DESC_RX;		ap->rx_jumbo_ring[i].idx = i;	}	ap->rx_jumbo_skbprd = i;	/*	 * The last descriptor needs to be marked as being special.	 */	ap->rx_jumbo_ring[i-1].type = DESC_END;	cmd.evt = C_SET_RX_JUMBO_PRD_IDX;	cmd.code = 0;	cmd.idx = ap->rx_jumbo_skbprd;	ace_issue_cmd(regs, &cmd);	spin_unlock_irqrestore(&ap->lock, flags);	return 0;}/* * Tell the firmware not to accept jumbos and flush the jumbo ring. * This function must be called with the spinlock held. */static int ace_flush_jumbo_rx_ring(struct device *dev){	struct ace_private *ap;	struct ace_regs *regs;	struct cmd cmd;	short i;	ap = (struct ace_private *)dev->priv;	regs = ap->regs;	if (ap->jumbo){		cmd.evt = C_RESET_JUMBO_RNG;		cmd.code = 0;		cmd.idx = 0;		ace_issue_cmd(regs, &cmd);		for (i = 0; i < RX_JUMBO_RING_ENTRIES; i++) {			if (ap->rx_jumbo_skbuff[i]) {				ap->rx_jumbo_ring[i].size = 0;				set_aceaddr_bus(&ap->rx_jumbo_ring[i].addr, 0);				dev_kfree_skb(ap->rx_jumbo_skbuff[i]);			}		}	}else		printk(KERN_ERR "%s: Trying to flush Jumbo ring without "		       "Jumbo support enabled\n", dev->name);	return 0;}/* * All events are considered to be slow (RX/TX ints do not generate * events) and are handled here, outside the main interrupt handler, * to reduce the size of the handler. */static u32 ace_handle_event(struct device *dev, u32 evtcsm, u32 evtprd){	struct ace_private *ap;	ap = (struct ace_private *)dev->priv;	while (evtcsm != evtprd){		switch (ap->evt_ring[evtcsm].evt){		case E_FW_RUNNING:			printk(KERN_INFO "%s: Firmware up and running\n",			       dev->name);			ap->fw_running = 1;			break;		case E_STATS_UPDATED:			break;		case E_LNK_STATE:		{			u16 code = ap->evt_ring[evtcsm].code;			if (code == E_C_LINK_UP){				printk("%s: Optical link UP\n", dev->name);			}			else if (code == E_C_LINK_DOWN)				printk(KERN_INFO "%s: Optical link DOWN\n",				       dev->name);			else				printk(KERN_INFO "%s: Unknown optical link "				       "state %02x\n", dev->name, code);			break;		}		case E_ERROR:			switch(ap->evt_ring[evtcsm].code){			case E_C_ERR_INVAL_CMD:				printk(KERN_ERR "%s: invalid command error\n",				       dev->name);				break;			case E_C_ERR_UNIMP_CMD:				printk(KERN_ERR "%s: unimplemented command "				       "error\n", dev->name);				break;			case E_C_ERR_BAD_CFG:				printk(KERN_ERR "%s: bad config error\n",				       dev->name);				break;			default:				printk(KERN_ERR "%s: unknown error %02x\n",				       dev->name, ap->evt_ring[evtcsm].code);			}			break;		case E_RESET_JUMBO_RNG:			break;		default:			printk(KERN_ERR "%s: Unhandled event 0x%02x\n",			       dev->name, ap->evt_ring[evtcsm].evt);		}		evtcsm = (evtcsm + 1) % EVT_RING_ENTRIES;	}	return evtcsm;}static int ace_rx_int(struct device *dev, u32 rxretprd, u32 rxretcsm){	struct ace_private *ap = (struct ace_private *)dev->priv;	struct ace_regs *regs = ap->regs;	u32 idx, oldidx;	idx = rxretcsm;	while (idx != rxretprd){		struct sk_buff *skb, *newskb, *oldskb;		struct rx_desc *newrxdesc, *oldrxdesc;		u32 prdidx, size;		void *addr;		u16 csum;		int jumbo;		oldidx = ap->rx_return_ring[idx].idx;		jumbo = ap->rx_return_ring[idx].flags & DFLG_RX_JUMBO;		if (jumbo){			oldskb = ap->rx_jumbo_skbuff[oldidx];			prdidx = ap->rx_jumbo_skbprd;			newrxdesc = &ap->rx_jumbo_ring[prdidx];			oldrxdesc = &ap->rx_jumbo_ring[oldidx];		}else{			oldskb = ap->rx_std_skbuff[oldidx];			prdidx = ap->rx_std_skbprd;			newrxdesc = &ap->rx_std_ring[prdidx];			oldrxdesc = &ap->rx_std_ring[oldidx];		}		size = oldrxdesc->size;		if (size < PKT_COPY_THRESHOLD) {			skb = alloc_skb(size + 2, GFP_ATOMIC);			if (skb == NULL){				printk(KERN_ERR "%s: Out of memory\n",				       dev->name);				goto error;			}			/*			 * Make sure the real data is aligned			 */			skb_reserve(skb, 2);			memcpy(skb_put(skb, size), oldskb->data, size);			addr = get_aceaddr_bus(&oldrxdesc->addr);			newskb = oldskb;		}else{			skb = oldskb;			skb_put(skb, size);			newskb = alloc_skb(size + 2, GFP_ATOMIC);			if (newskb == NULL){				printk(KERN_ERR "%s: Out of memory\n",				       dev->name);				goto error;			}			/*			 * Make sure we DMA directly into nicely			 * aligned receive buffers			 */			skb_reserve(newskb, 2);			addr = (void *)virt_to_bus(newskb->data);		}		set_aceaddr_bus(&newrxdesc->addr, addr);		newrxdesc->size = size;		newrxdesc->flags = oldrxdesc->flags;		newrxdesc->idx = prdidx;		newrxdesc->type = DESC_RX;#if (BITS_PER_LONG == 32)		newrxdesc->addr.addrhi = 0;#endif		oldrxdesc->size = 0;		set_aceaddr_bus(&oldrxdesc->addr, 0);		if (jumbo){			ap->rx_jumbo_skbuff[oldidx] = NULL;			ap->rx_jumbo_skbuff[prdidx] = newskb;			prdidx = (prdidx + 1) % RX_JUMBO_RING_ENTRIES;			ap->rx_jumbo_skbprd = prdidx;		}else{			ap->rx_std_skbuff[oldidx] = NULL;			ap->rx_std_skbuff[prdidx] = newskb;			prdidx = (prdidx + 1) % RX_STD_RING_ENTRIES;			ap->rx_std_skbprd = prdidx;		}		/*		 * Fly baby, fly!		 */		csum = ap->rx_return_ring[idx].tcp_udp_csum;		skb->dev = dev;		skb->protocol = eth_type_trans(skb, dev);		/*		 * If the checksum is correct and this is not a		 * fragment, tell the stack that the data is correct.		 */		if(!(csum ^ 0xffff) &&		   (!(((struct iphdr *)skb->data)->frag_off &		      __constant_htons(IP_MF|IP_OFFSET))))			skb->ip_summed = CHECKSUM_UNNECESSARY;		else			skb->ip_summed = CHECKSUM_NONE;		netif_rx(skb);		/* send it up */		ap->stats.rx_packets++;		ap->stats.rx_bytes += skb->len;		if ((prdidx & 0x7) == 0){			struct cmd cmd;			if (jumbo)				cmd.evt = C_SET_RX_JUMBO_PRD_IDX;			else				cmd.evt = C_SET_RX_PRD_IDX;			cmd.code = 0;			cmd.idx = prdidx;			ace_issue_cmd(regs, &cmd);		}		idx = (idx + 1) % RX_RETURN_RING_ENTRIES;	} out:	/*	 * According to the documentation RxRetCsm is obsolete with	 * the 12.3.x Firmware - my Tigon I NIC's seem to disagree!	 */	writel(idx, &regs->RxRetCsm);	ap->cur_rx = idx;	return idx; error:	idx = rxretprd;	goto out;}static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs){	struct ace_private *ap;	struct ace_regs *regs;	struct device *dev = (struct device *)dev_id;	u32 txcsm, rxretcsm, rxretprd;	u32 evtcsm, evtprd;	ap = (struct ace_private *)dev->priv;	regs = ap->regs;	spin_lock(&ap->lock);	/*	 * In case of PCI shared interrupts or spurious interrupts,	 * we want to make sure it is actually our interrupt before	 * spending any time in here.	 */	if (!(readl(&regs->HostCtrl) & IN_INT)){		spin_unlock(&ap->lock);		return;	}	/*	 * Tell the card not to generate interrupts while we are in here.	 */	writel(1, &regs->Mb0Lo);	/*	 * Service RX ints before TX	 */	rxretprd = ap->rx_ret_prd;	rxretcsm = ap->cur_rx;	if (rxretprd != rxretcsm)		rxretprd = ace_rx_int(dev, rxretprd, rxretcsm);	txcsm = ap->tx_csm;	if (txcsm != ap->tx_ret_csm) {		u32 idx = ap->tx_ret_csm;		do {			ap->stats.tx_packets++;			ap->stats.tx_bytes += ap->tx_skbuff[idx]->len;			dev_kfree_skb(ap->tx_skbuff[idx]);			ap->tx_skbuff[idx] = NULL;

⌨️ 快捷键说明

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