📄 ibm_emac_core.c
字号:
*/ 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 + -