core.c

来自「linux 内核源代码」· C语言 代码 · 共 2,457 行 · 第 1/5 页

C
2,457
字号
	/* No link, force loopback */	if (!link)		mr1 = EMAC_MR1_FDE | EMAC_MR1_ILE;	/* Check for full duplex */	else if (dev->phy.duplex == DUPLEX_FULL)		mr1 |= EMAC_MR1_FDE | EMAC_MR1_MWSW_001;	/* Adjust fifo sizes, mr1 and timeouts based on link speed */	dev->stop_timeout = STOP_TIMEOUT_10;	switch (dev->phy.speed) {	case SPEED_1000:		if (emac_phy_gpcs(dev->phy.mode)) {			mr1 |= EMAC_MR1_MF_1000GPCS |				EMAC_MR1_MF_IPPA(dev->phy.address);			/* Put some arbitrary OUI, Manuf & Rev IDs so we can			 * identify this GPCS PHY later.			 */			out_be32(&p->ipcr, 0xdeadbeef);		} else			mr1 |= EMAC_MR1_MF_1000;		/* Extended fifo sizes */		tx_size = dev->tx_fifo_size_gige;		rx_size = dev->rx_fifo_size_gige;		if (dev->ndev->mtu > ETH_DATA_LEN) {			mr1 |= EMAC_MR1_JPSM;			dev->stop_timeout = STOP_TIMEOUT_1000_JUMBO;		} else			dev->stop_timeout = STOP_TIMEOUT_1000;		break;	case SPEED_100:		mr1 |= EMAC_MR1_MF_100;		dev->stop_timeout = STOP_TIMEOUT_100;		break;	default: /* make gcc happy */		break;	}	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))		rgmii_set_speed(dev->rgmii_dev, dev->rgmii_port,				dev->phy.speed);	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))		zmii_set_speed(dev->zmii_dev, dev->zmii_port, dev->phy.speed);	/* on 40x erratum forces us to NOT use integrated flow control,	 * let's hope it works on 44x ;)	 */	if (!emac_has_feature(dev, EMAC_FTR_NO_FLOW_CONTROL_40x) &&	    dev->phy.duplex == DUPLEX_FULL) {		if (dev->phy.pause)			mr1 |= EMAC_MR1_EIFC | EMAC_MR1_APP;		else if (dev->phy.asym_pause)			mr1 |= EMAC_MR1_APP;	}	/* Add base settings & fifo sizes & program MR1 */	mr1 |= emac_calc_base_mr1(dev, tx_size, rx_size);	out_be32(&p->mr1, mr1);	/* Set individual MAC address */	out_be32(&p->iahr, (ndev->dev_addr[0] << 8) | ndev->dev_addr[1]);	out_be32(&p->ialr, (ndev->dev_addr[2] << 24) |		 (ndev->dev_addr[3] << 16) | (ndev->dev_addr[4] << 8) |		 ndev->dev_addr[5]);	/* VLAN Tag Protocol ID */	out_be32(&p->vtpid, 0x8100);	/* Receive mode register */	r = emac_iff2rmr(ndev);	if (r & EMAC_RMR_MAE)		emac_hash_mc(dev);	out_be32(&p->rmr, r);	/* FIFOs thresholds */	if (emac_has_feature(dev, EMAC_FTR_EMAC4))		r = EMAC4_TMR1((dev->mal_burst_size / dev->fifo_entry_size) + 1,			       tx_size / 2 / dev->fifo_entry_size);	else		r = EMAC_TMR1((dev->mal_burst_size / dev->fifo_entry_size) + 1,			      tx_size / 2 / dev->fifo_entry_size);	out_be32(&p->tmr1, r);	out_be32(&p->trtr, emac_calc_trtr(dev, tx_size / 2));	/* PAUSE frame is sent when RX FIFO reaches its high-water mark,	   there should be still enough space in FIFO to allow the our link	   partner time to process this frame and also time to send PAUSE	   frame itself.	   Here is the worst case scenario for the RX FIFO "headroom"	   (from "The Switch Book") (100Mbps, without preamble, inter-frame gap):	   1) One maximum-length frame on TX                    1522 bytes	   2) One PAUSE frame time                                64 bytes	   3) PAUSE frame decode time allowance                   64 bytes	   4) One maximum-length frame on RX                    1522 bytes	   5) Round-trip propagation delay of the link (100Mb)    15 bytes	   ----------	   3187 bytes	   I chose to set high-water mark to RX_FIFO_SIZE / 4 (1024 bytes)	   low-water mark  to RX_FIFO_SIZE / 8 (512 bytes)	 */	r = emac_calc_rwmr(dev, rx_size / 8 / dev->fifo_entry_size,			   rx_size / 4 / dev->fifo_entry_size);	out_be32(&p->rwmr, r);	/* Set PAUSE timer to the maximum */	out_be32(&p->ptr, 0xffff);	/* IRQ sources */	r = EMAC_ISR_OVR | EMAC_ISR_BP | EMAC_ISR_SE |		EMAC_ISR_ALE | EMAC_ISR_BFCS | EMAC_ISR_PTLE | EMAC_ISR_ORE |		EMAC_ISR_IRE | EMAC_ISR_TE;	if (emac_has_feature(dev, EMAC_FTR_EMAC4))	    r |= EMAC4_ISR_TXPE | EMAC4_ISR_RXPE /* | EMAC4_ISR_TXUE |						  EMAC4_ISR_RXOE | */;	out_be32(&p->iser,  r);	/* We need to take GPCS PHY out of isolate mode after EMAC reset */	if (emac_phy_gpcs(dev->phy.mode))		emac_mii_reset_phy(&dev->phy);	return 0;}static void emac_reinitialize(struct emac_instance *dev){	DBG(dev, "reinitialize" NL);	emac_netif_stop(dev);	if (!emac_configure(dev)) {		emac_tx_enable(dev);		emac_rx_enable(dev);	}	emac_netif_start(dev);}static void emac_full_tx_reset(struct emac_instance *dev){	DBG(dev, "full_tx_reset" NL);	emac_tx_disable(dev);	mal_disable_tx_channel(dev->mal, dev->mal_tx_chan);	emac_clean_tx_ring(dev);	dev->tx_cnt = dev->tx_slot = dev->ack_slot = 0;	emac_configure(dev);	mal_enable_tx_channel(dev->mal, dev->mal_tx_chan);	emac_tx_enable(dev);	emac_rx_enable(dev);}static void emac_reset_work(struct work_struct *work){	struct emac_instance *dev = container_of(work, struct emac_instance, reset_work);	DBG(dev, "reset_work" NL);	mutex_lock(&dev->link_lock);	if (dev->opened) {		emac_netif_stop(dev);		emac_full_tx_reset(dev);		emac_netif_start(dev);	}	mutex_unlock(&dev->link_lock);}static void emac_tx_timeout(struct net_device *ndev){	struct emac_instance *dev = netdev_priv(ndev);	DBG(dev, "tx_timeout" NL);	schedule_work(&dev->reset_work);}static inline int emac_phy_done(struct emac_instance *dev, u32 stacr){	int done = !!(stacr & EMAC_STACR_OC);	if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))		done = !done;	return done;};static int __emac_mdio_read(struct emac_instance *dev, u8 id, u8 reg){	struct emac_regs __iomem *p = dev->emacp;	u32 r = 0;	int n, err = -ETIMEDOUT;	mutex_lock(&dev->mdio_lock);	DBG2(dev, "mdio_read(%02x,%02x)" NL, id, reg);	/* Enable proper MDIO port */	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))		zmii_get_mdio(dev->zmii_dev, dev->zmii_port);	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))		rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port);	/* Wait for management interface to become idle */	n = 10;	while (!emac_phy_done(dev, in_be32(&p->stacr))) {		udelay(1);		if (!--n) {			DBG2(dev, " -> timeout wait idle\n");			goto bail;		}	}	/* Issue read command */	if (emac_has_feature(dev, EMAC_FTR_EMAC4))		r = EMAC4_STACR_BASE(dev->opb_bus_freq);	else		r = EMAC_STACR_BASE(dev->opb_bus_freq);	if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))		r |= EMAC_STACR_OC;	if (emac_has_feature(dev, EMAC_FTR_HAS_NEW_STACR))		r |= EMACX_STACR_STAC_READ;	else		r |= EMAC_STACR_STAC_READ;	r |= (reg & EMAC_STACR_PRA_MASK)		| ((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT);	out_be32(&p->stacr, r);	/* Wait for read to complete */	n = 100;	while (!emac_phy_done(dev, (r = in_be32(&p->stacr)))) {		udelay(1);		if (!--n) {			DBG2(dev, " -> timeout wait complete\n");			goto bail;		}	}	if (unlikely(r & EMAC_STACR_PHYE)) {		DBG(dev, "mdio_read(%02x, %02x) failed" NL, id, reg);		err = -EREMOTEIO;		goto bail;	}	r = ((r >> EMAC_STACR_PHYD_SHIFT) & EMAC_STACR_PHYD_MASK);	DBG2(dev, "mdio_read -> %04x" NL, r);	err = 0; bail:	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))		rgmii_put_mdio(dev->rgmii_dev, dev->rgmii_port);	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))		zmii_put_mdio(dev->zmii_dev, dev->zmii_port);	mutex_unlock(&dev->mdio_lock);	return err == 0 ? r : err;}static void __emac_mdio_write(struct emac_instance *dev, u8 id, u8 reg,			      u16 val){	struct emac_regs __iomem *p = dev->emacp;	u32 r = 0;	int n, err = -ETIMEDOUT;	mutex_lock(&dev->mdio_lock);	DBG2(dev, "mdio_write(%02x,%02x,%04x)" NL, id, reg, val);	/* Enable proper MDIO port */	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))		zmii_get_mdio(dev->zmii_dev, dev->zmii_port);	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))		rgmii_get_mdio(dev->rgmii_dev, dev->rgmii_port);	/* Wait for management interface to be idle */	n = 10;	while (!emac_phy_done(dev, in_be32(&p->stacr))) {		udelay(1);		if (!--n) {			DBG2(dev, " -> timeout wait idle\n");			goto bail;		}	}	/* Issue write command */	if (emac_has_feature(dev, EMAC_FTR_EMAC4))		r = EMAC4_STACR_BASE(dev->opb_bus_freq);	else		r = EMAC_STACR_BASE(dev->opb_bus_freq);	if (emac_has_feature(dev, EMAC_FTR_STACR_OC_INVERT))		r |= EMAC_STACR_OC;	if (emac_has_feature(dev, EMAC_FTR_HAS_NEW_STACR))		r |= EMACX_STACR_STAC_WRITE;	else		r |= EMAC_STACR_STAC_WRITE;	r |= (reg & EMAC_STACR_PRA_MASK) |		((id & EMAC_STACR_PCDA_MASK) << EMAC_STACR_PCDA_SHIFT) |		(val << EMAC_STACR_PHYD_SHIFT);	out_be32(&p->stacr, r);	/* Wait for write to complete */	n = 100;	while (!emac_phy_done(dev, in_be32(&p->stacr))) {		udelay(1);		if (!--n) {			DBG2(dev, " -> timeout wait complete\n");			goto bail;		}	}	err = 0; bail:	if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII))		rgmii_put_mdio(dev->rgmii_dev, dev->rgmii_port);	if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))		zmii_put_mdio(dev->zmii_dev, dev->zmii_port);	mutex_unlock(&dev->mdio_lock);}static int emac_mdio_read(struct net_device *ndev, int id, int reg){	struct emac_instance *dev = netdev_priv(ndev);	int res;	res = __emac_mdio_read(dev->mdio_instance ? dev->mdio_instance : dev,			       (u8) id, (u8) reg);	return res;}static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val){	struct emac_instance *dev = netdev_priv(ndev);	__emac_mdio_write(dev->mdio_instance ? dev->mdio_instance : dev,			  (u8) id, (u8) reg, (u16) val);}/* Tx lock BH */static void __emac_set_multicast_list(struct emac_instance *dev){	struct emac_regs __iomem *p = dev->emacp;	u32 rmr = emac_iff2rmr(dev->ndev);	DBG(dev, "__multicast %08x" NL, rmr);	/* I decided to relax register access rules here to avoid	 * full EMAC reset.	 *	 * There is a real problem with EMAC4 core if we use MWSW_001 bit	 * in MR1 register and do a full EMAC reset.	 * One TX BD status update is delayed and, after EMAC reset, it	 * never happens, resulting in TX hung (it'll be recovered by TX	 * timeout handler eventually, but this is just gross).	 * So we either have to do full TX reset or try to cheat here :)	 *	 * The only required change is to RX mode register, so I *think* all	 * we need is just to stop RX channel. This seems to work on all	 * tested SoCs.                                                --ebs	 *	 * If we need the full reset, we might just trigger the workqueue	 * and do it async... a bit nasty but should work --BenH	 */	dev->mcast_pending = 0;	emac_rx_disable(dev);	if (rmr & EMAC_RMR_MAE)		emac_hash_mc(dev);	out_be32(&p->rmr, rmr);	emac_rx_enable(dev);}/* Tx lock BH */static void emac_set_multicast_list(struct net_device *ndev){	struct emac_instance *dev = netdev_priv(ndev);	DBG(dev, "multicast" NL);	BUG_ON(!netif_running(dev->ndev));	if (dev->no_mcast) {		dev->mcast_pending = 1;		return;	}	__emac_set_multicast_list(dev);}static int emac_resize_rx_ring(struct emac_instance *dev, int new_mtu){	int rx_sync_size = emac_rx_sync_size(new_mtu);	int rx_skb_size = emac_rx_skb_size(new_mtu);	int i, ret = 0;	mutex_lock(&dev->link_lock);	emac_netif_stop(dev);	emac_rx_disable(dev);	mal_disable_rx_channel(dev->mal, dev->mal_rx_chan);	if (dev->rx_sg_skb) {		++dev->estats.rx_dropped_resize;		dev_kfree_skb(dev->rx_sg_skb);		dev->rx_sg_skb = NULL;	}	/* Make a first pass over RX ring and mark BDs ready, dropping	 * non-processed packets on the way. We need this as a separate pass	 * to simplify error recovery in the case of allocation failure later.	 */	for (i = 0; i < NUM_RX_BUFF; ++i) {		if (dev->rx_desc[i].ctrl & MAL_RX_CTRL_FIRST)			++dev->estats.rx_dropped_resize;		dev->rx_desc[i].data_len = 0;		dev->rx_desc[i].ctrl = MAL_RX_CTRL_EMPTY |		    (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);	}	/* Reallocate RX ring only if bigger skb buffers are required */	if (rx_skb_size <= dev->rx_skb_size)		goto skip;	/* Second pass, allocate new skbs */	for (i = 0; i < NUM_RX_BUFF; ++i) {		struct sk_buff *skb = alloc_skb(rx_skb_size, GFP_ATOMIC);		if (!skb) {			ret = -ENOMEM;			goto oom;		}		BUG_ON(!dev->rx_skb[i]);		dev_kfree_skb(dev->rx_skb[i]);		skb_reserve(skb, EMAC_RX_SKB_HEADROOM + 2);		dev->rx_desc[i].data_ptr =		    dma_map_single(&dev->ofdev->dev, skb->data - 2, rx_sync_size,				   DMA_FROM_DEVICE) + 2;		dev->rx_skb[i] = skb;	} skip:	/* Check if we need to change "Jumbo" bit in MR1 */	if ((new_mtu > ETH_DATA_LEN) ^ (dev->ndev->mtu > ETH_DATA_LEN)) {		/* This is to prevent starting RX channel in emac_rx_enable() */		set_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);		dev->ndev->mtu = new_mtu;		emac_full_tx_reset(dev);	}	mal_set_rcbs(dev->mal, dev->mal_rx_chan, emac_rx_size(new_mtu)); oom:	/* Restart RX */	clear_bit(MAL_COMMAC_RX_STOPPED, &dev->commac.flags);	dev->rx_slot = 0;	mal_enable_rx_channel(dev->mal, dev->mal_rx_chan);	emac_rx_enable(dev);	emac_netif_start(dev);	mutex_unlock(&dev->link_lock);	return ret;}/* Process ctx, rtnl_lock semaphore */static int emac_change_mtu(struct net_device *ndev, int new_mtu){	struct emac_instance *dev = netdev_priv(ndev);	int ret = 0;	if (new_mtu < EMAC_MIN_MTU || new_mtu > dev->max_mtu)		return -EINVAL;	DBG(dev, "change_mtu(%d)" NL, new_mtu);	if (netif_running(ndev)) {		/* Check if we really need to reinitalize RX ring */		if (emac_rx_skb_size(ndev->mtu) != emac_rx_skb_size(new_mtu))			ret = emac_resize_rx_ring(dev, new_mtu);	}	if (!ret) {		ndev->mtu = new_mtu;		dev->rx_skb_size = emac_rx_skb_size(new_mtu);		dev->rx_sync_size = emac_rx_sync_size(new_mtu);	}	return ret;}

⌨️ 快捷键说明

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