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

📄 ibm_emac_core.c

📁 h内核
💻 C
📖 第 1 页 / 共 4 页
字号:
	 */	fep->tx_desc[tx_slot_first].ctrl |= MAL_TX_CTRL_READY;	/* Send the packet out. */	out_be32(&emacp->em0tmr0, EMAC_TMR0_XMIT);	fep->stats.tx_packets++;	fep->stats.tx_bytes += skb->len;	PKT_DEBUG(("emac_start_xmit() exitn"));	spin_unlock_irqrestore(&fep->lock, flags);	return 0;}static int emac_adjust_to_link(struct ocp_enet_private *fep){	emac_t *emacp = fep->emacp;	unsigned long mode_reg;	int full_duplex, speed;	full_duplex = 0;	speed = SPEED_10;	/* set mode register 1 defaults */	mode_reg = EMAC_M1_DEFAULT;	/* Read link mode on PHY */	if (fep->phy_mii.def->ops->read_link(&fep->phy_mii) == 0) {		/* If an error occurred, we don't deal with it yet */		full_duplex = (fep->phy_mii.duplex == DUPLEX_FULL);		speed = fep->phy_mii.speed;	}	/* set speed (default is 10Mb) */	switch (speed) {	case SPEED_1000:		mode_reg |= EMAC_M1_JUMBO_ENABLE | EMAC_M1_RFS_16K;		if (fep->rgmii_dev) {			struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(fep->rgmii_dev);			if ((rgmii->mode[fep->rgmii_input] == RTBI)			    || (rgmii->mode[fep->rgmii_input] == TBI))				mode_reg |= EMAC_M1_MF_1000GPCS;			else				mode_reg |= EMAC_M1_MF_1000MBPS;			emac_rgmii_port_speed(fep->rgmii_dev, fep->rgmii_input,					      1000);		}		break;	case SPEED_100:		mode_reg |= EMAC_M1_MF_100MBPS | EMAC_M1_RFS_4K;		if (fep->rgmii_dev)			emac_rgmii_port_speed(fep->rgmii_dev, fep->rgmii_input,					      100);		if (fep->zmii_dev)			emac_zmii_port_speed(fep->zmii_dev, fep->zmii_input,					     100);		break;	case SPEED_10:	default:		mode_reg = (mode_reg & ~EMAC_M1_MF_100MBPS) | EMAC_M1_RFS_4K;		if (fep->rgmii_dev)			emac_rgmii_port_speed(fep->rgmii_dev, fep->rgmii_input,					      10);		if (fep->zmii_dev)			emac_zmii_port_speed(fep->zmii_dev, fep->zmii_input,					     10);	}	if (full_duplex)		mode_reg |= EMAC_M1_FDE | EMAC_M1_EIFC | EMAC_M1_IST;	else		mode_reg &= ~(EMAC_M1_FDE | EMAC_M1_EIFC | EMAC_M1_ILE);	LINK_DEBUG(("%s: adjust to link, speed: %d, duplex: %d, opened: %d\n",		    fep->ndev->name, speed, full_duplex, fep->opened));	printk(KERN_INFO "%s: Speed: %d, %s duplex.\n",	       fep->ndev->name, speed, full_duplex ? "Full" : "Half");	if (fep->opened)		out_be32(&emacp->em0mr1, mode_reg);	return 0;}static int emac_set_mac_address(struct net_device *ndev, void *p){	struct ocp_enet_private *fep = ndev->priv;	emac_t *emacp = fep->emacp;	struct sockaddr *addr = p;	if (!is_valid_ether_addr(addr->sa_data))		return -EADDRNOTAVAIL;	memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);	/* set the high address */	out_be32(&emacp->em0iahr,		 (fep->ndev->dev_addr[0] << 8) | fep->ndev->dev_addr[1]);	/* set the low address */	out_be32(&emacp->em0ialr,		 (fep->ndev->dev_addr[2] << 24) | (fep->ndev->dev_addr[3] << 16)		 | (fep->ndev->dev_addr[4] << 8) | fep->ndev->dev_addr[5]);	return 0;}static int emac_change_mtu(struct net_device *dev, int new_mtu){	struct ocp_enet_private *fep = dev->priv;	int old_mtu = dev->mtu;	emac_t *emacp = fep->emacp;	u32 em0mr0;	int i, full;	unsigned long flags;	if ((new_mtu < EMAC_MIN_MTU) || (new_mtu > EMAC_MAX_MTU)) {		printk(KERN_ERR		       "emac: Invalid MTU setting, MTU must be between %d and %d\n",		       EMAC_MIN_MTU, EMAC_MAX_MTU);		return -EINVAL;	}	if (old_mtu != new_mtu && netif_running(dev)) {		/* Stop rx engine */		em0mr0 = in_be32(&emacp->em0mr0);		out_be32(&emacp->em0mr0, em0mr0 & ~EMAC_M0_RXE);		/* Wait for descriptors to be empty */		do {			full = 0;			for (i = 0; i < NUM_RX_BUFF; i++)				if (!(fep->rx_desc[i].ctrl & MAL_RX_CTRL_EMPTY)) {					printk(KERN_NOTICE					       "emac: RX ring is still full\n");					full = 1;				}		} while (full);		spin_lock_irqsave(&fep->lock, flags);		mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask);		/* Destroy all old rx skbs */		for (i = 0; i < NUM_RX_BUFF; i++) {			dma_unmap_single(&fep->ocpdev->dev,					 fep->rx_desc[i].data_ptr,					 fep->rx_desc[i].data_len,					 DMA_FROM_DEVICE);			dev_kfree_skb(fep->rx_skb[i]);			fep->rx_skb[i] = NULL;		}		/* Set new rx_buffer_size and advertise new mtu */		fep->rx_buffer_size =		    new_mtu + ENET_HEADER_SIZE + ENET_FCS_SIZE;		dev->mtu = new_mtu;		/* Re-init rx skbs */		fep->rx_slot = 0;		emac_rx_fill(dev, 0);		/* Restart the rx engine */		mal_enable_rx_channels(fep->mal, fep->commac.rx_chan_mask);		out_be32(&emacp->em0mr0, em0mr0 | EMAC_M0_RXE);		spin_unlock_irqrestore(&fep->lock, flags);	}	return 0;}static void __emac_set_multicast_list(struct net_device *dev){	struct ocp_enet_private *fep = dev->priv;	emac_t *emacp = fep->emacp;	u32 rmr = in_be32(&emacp->em0rmr);	/* First clear all special bits, they can be set later */	rmr &= ~(EMAC_RMR_PME | EMAC_RMR_PMME | EMAC_RMR_MAE);	if (dev->flags & IFF_PROMISC) {		rmr |= EMAC_RMR_PME;	} else if (dev->flags & IFF_ALLMULTI || 32 < dev->mc_count) {		/*		 * Must be setting up to use multicast		 * Now check for promiscuous multicast		 */		rmr |= EMAC_RMR_PMME;	} else if (dev->flags & IFF_MULTICAST && 0 < dev->mc_count) {		unsigned short em0gaht[4] = { 0, 0, 0, 0 };		struct dev_mc_list *dmi;		/* Need to hash on the multicast address. */		for (dmi = dev->mc_list; dmi; dmi = dmi->next) {			unsigned long mc_crc;			unsigned int bit_number;			mc_crc = ether_crc(6, (char *)dmi->dmi_addr);			bit_number = 63 - (mc_crc >> 26);	/* MSB: 0 LSB: 63 */			em0gaht[bit_number >> 4] |=			    0x8000 >> (bit_number & 0x0f);		}		emacp->em0gaht1 = em0gaht[0];		emacp->em0gaht2 = em0gaht[1];		emacp->em0gaht3 = em0gaht[2];		emacp->em0gaht4 = em0gaht[3];		/* Turn on multicast addressing */		rmr |= EMAC_RMR_MAE;	}	out_be32(&emacp->em0rmr, rmr);}static int emac_init_tah(struct ocp_enet_private *fep){	tah_t *tahp;	/* Initialize TAH and enable checksum verification */	tahp = (tah_t *) ioremap(fep->tah_dev->def->paddr, sizeof(*tahp));	if (tahp == NULL) {		printk(KERN_ERR "tah%d: Cannot ioremap TAH registers!\n",		       fep->tah_dev->def->index);		return -ENOMEM;	}	out_be32(&tahp->tah_mr, TAH_MR_SR);	/* wait for reset to complete */	while (in_be32(&tahp->tah_mr) & TAH_MR_SR) ;	/* 10KB TAH TX FIFO accomodates the max MTU of 9000 */	out_be32(&tahp->tah_mr,		 TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP |		 TAH_MR_DIG);	iounmap(&tahp);	return 0;}static void emac_init_rings(struct net_device *dev){	struct ocp_enet_private *ep = dev->priv;	int loop;	ep->tx_desc = (struct mal_descriptor *)((char *)ep->mal->tx_virt_addr +						(ep->mal_tx_chan *						 MAL_DT_ALIGN));	ep->rx_desc =	    (struct mal_descriptor *)((char *)ep->mal->rx_virt_addr +				      (ep->mal_rx_chan * MAL_DT_ALIGN));	/* Fill in the transmit descriptor ring. */	for (loop = 0; loop < NUM_TX_BUFF; loop++) {		if (ep->tx_skb[loop]) {			dma_unmap_single(&ep->ocpdev->dev,					 ep->tx_desc[loop].data_ptr,					 ep->tx_desc[loop].data_len,					 DMA_TO_DEVICE);			dev_kfree_skb_irq(ep->tx_skb[loop]);		}		ep->tx_skb[loop] = NULL;		ep->tx_desc[loop].ctrl = 0;		ep->tx_desc[loop].data_len = 0;		ep->tx_desc[loop].data_ptr = NULL;	}	ep->tx_desc[loop - 1].ctrl |= MAL_TX_CTRL_WRAP;	/* Format the receive descriptor ring. */	ep->rx_slot = 0;	/* Default is MTU=1500 + Ethernet overhead */	ep->rx_buffer_size = dev->mtu + ENET_HEADER_SIZE + ENET_FCS_SIZE;	emac_rx_fill(dev, 0);	if (ep->rx_slot != 0) {		printk(KERN_ERR		       "%s: Not enough mem for RxChain durning Open?\n",		       dev->name);		/*We couldn't fill the ring at startup?		 *We could clean up and fail to open but right now we will try to		 *carry on. It may be a sign of a bad NUM_RX_BUFF value		 */	}	ep->tx_cnt = 0;	ep->tx_slot = 0;	ep->ack_slot = 0;}static void emac_reset_configure(struct ocp_enet_private *fep){	emac_t *emacp = fep->emacp;	int i;	mal_disable_tx_channels(fep->mal, fep->commac.tx_chan_mask);	mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask);	/*	 * Check for a link, some PHYs don't provide a clock if	 * no link is present.  Some EMACs will not come out of	 * soft reset without a PHY clock present.	 */	if (fep->phy_mii.def->ops->poll_link(&fep->phy_mii)) {		/* Reset the EMAC */		out_be32(&emacp->em0mr0, EMAC_M0_SRST);		udelay(20);		for (i = 0; i < 100; i++) {			if ((in_be32(&emacp->em0mr0) & EMAC_M0_SRST) == 0)				break;			udelay(10);		}		if (i >= 100) {			printk(KERN_ERR "%s: Cannot reset EMAC\n",			       fep->ndev->name);			return;		}	}	/* Switch IRQs off for now */	out_be32(&emacp->em0iser, 0);	/* Configure MAL rx channel */	mal_set_rcbs(fep->mal, fep->mal_rx_chan, DESC_BUF_SIZE_REG);	/* set the high address */	out_be32(&emacp->em0iahr,		 (fep->ndev->dev_addr[0] << 8) | fep->ndev->dev_addr[1]);	/* set the low address */	out_be32(&emacp->em0ialr,		 (fep->ndev->dev_addr[2] << 24) | (fep->ndev->dev_addr[3] << 16)		 | (fep->ndev->dev_addr[4] << 8) | fep->ndev->dev_addr[5]);	/* Adjust to link */	if (netif_carrier_ok(fep->ndev))		emac_adjust_to_link(fep);	/* enable broadcast/individual address and RX FIFO defaults */	out_be32(&emacp->em0rmr, EMAC_RMR_DEFAULT);	/* set transmit request threshold register */	out_be32(&emacp->em0trtr, EMAC_TRTR_DEFAULT);	/* Reconfigure multicast */	__emac_set_multicast_list(fep->ndev);	/* Set receiver/transmitter defaults */	out_be32(&emacp->em0rwmr, EMAC_RWMR_DEFAULT);	out_be32(&emacp->em0tmr0, EMAC_TMR0_DEFAULT);	out_be32(&emacp->em0tmr1, EMAC_TMR1_DEFAULT);	/* set frame gap */	out_be32(&emacp->em0ipgvr, CONFIG_IBM_EMAC_FGAP);		/* set VLAN Tag Protocol Identifier */	out_be32(&emacp->em0vtpid, 0x8100);	/* Init ring buffers */	emac_init_rings(fep->ndev);}static void emac_kick(struct ocp_enet_private *fep){	emac_t *emacp = fep->emacp;	unsigned long emac_ier;	emac_ier = EMAC_ISR_PP | EMAC_ISR_BP | EMAC_ISR_RP |	    EMAC_ISR_SE | EMAC_ISR_PTLE | EMAC_ISR_ALE |	    EMAC_ISR_BFCS | EMAC_ISR_ORE | EMAC_ISR_IRE;	out_be32(&emacp->em0iser, emac_ier);	/* enable all MAL transmit and receive channels */	mal_enable_tx_channels(fep->mal, fep->commac.tx_chan_mask);	mal_enable_rx_channels(fep->mal, fep->commac.rx_chan_mask);	/* set transmit and receive enable */	out_be32(&emacp->em0mr0, EMAC_M0_TXE | EMAC_M0_RXE);}static voidemac_start_link(struct ocp_enet_private *fep, struct ethtool_cmd *ep){	u32 advertise;	int autoneg;	int forced_speed;	int forced_duplex;	/* Default advertise */	advertise = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |	    ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full |	    ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full;	autoneg = fep->want_autoneg;	forced_speed = fep->phy_mii.speed;	forced_duplex = fep->phy_mii.duplex;	/* Setup link parameters */	if (ep) {		if (ep->autoneg == AUTONEG_ENABLE) {			advertise = ep->advertising;			autoneg = 1;		} else {			autoneg = 0;			forced_speed = ep->speed;			forced_duplex = ep->duplex;		}	}	/* Configure PHY & start aneg */	fep->want_autoneg = autoneg;	if (autoneg) {		LINK_DEBUG(("%s: start link aneg, advertise: 0x%x\n",			    fep->ndev->name, advertise));		fep->phy_mii.def->ops->setup_aneg(&fep->phy_mii, advertise);	} else {		LINK_DEBUG(("%s: start link forced, speed: %d, duplex: %d\n",			    fep->ndev->name, forced_speed, forced_duplex));		fep->phy_mii.def->ops->setup_forced(&fep->phy_mii, forced_speed,						    forced_duplex);	}	fep->timer_ticks = 0;	mod_timer(&fep->link_timer, jiffies + HZ);}static void emac_link_timer(unsigned long data){	struct ocp_enet_private *fep = (struct ocp_enet_private *)data;	int link;	if (fep->going_away)		return;	spin_lock_irq(&fep->lock);	link = fep->phy_mii.def->ops->poll_link(&fep->phy_mii);	LINK_DEBUG(("%s: poll_link: %d\n", fep->ndev->name, link));	if (link == netif_carrier_ok(fep->ndev)) {		if (!link && fep->want_autoneg && (++fep->timer_ticks) > 10)			emac_start_link(fep, NULL);		goto out;	}	printk(KERN_INFO "%s: Link is %s\n", fep->ndev->name,	       link ? "Up" : "Down");	if (link) {		netif_carrier_on(fep->ndev);		/* Chip needs a full reset on config change. That sucks, so I		 * should ultimately move that to some tasklet to limit		 * latency peaks caused by this code		 */		emac_reset_configure(fep);		if (fep->opened)			emac_kick(fep);	} else {		fep->timer_ticks = 0;		netif_carrier_off(fep->ndev);	}      out:	mod_timer(&fep->link_timer, jiffies + HZ);	spin_unlock_irq(&fep->lock);}static void emac_set_multicast_list(struct net_device *dev){	struct ocp_enet_private *fep = dev->priv;	spin_lock_irq(&fep->lock);	__emac_set_multicast_list(dev);	spin_unlock_irq(&fep->lock);}static int emac_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd){	struct ocp_enet_private *fep = ndev->priv;	cmd->supported = fep->phy_mii.def->features;	cmd->port = PORT_MII;	cmd->transceiver = XCVR_EXTERNAL;	cmd->phy_address = fep->mii_phy_addr;	spin_lock_irq(&fep->lock);	cmd->autoneg = fep->want_autoneg;	cmd->speed = fep->phy_mii.speed;	cmd->duplex = fep->phy_mii.duplex;	spin_unlock_irq(&fep->lock);	return 0;}static int emac_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd){	struct ocp_enet_private *fep = ndev->priv;	unsigned long features = fep->phy_mii.def->features;	if (!capable(CAP_NET_ADMIN))		return -EPERM;

⌨️ 快捷键说明

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