📄 ibm_ocp_enet.c
字号:
if (ctrl & EMAC_RX_ST_OE) fep->stats.rx_fifo_errors++; if (ctrl & EMAC_RX_ST_AE) fep->stats.rx_frame_errors++; if (ctrl & EMAC_RX_ST_BFCS) fep->stats.rx_crc_errors++; if (ctrl & (EMAC_RX_ST_RP | EMAC_RX_ST_PTL | EMAC_RX_ST_ORE | EMAC_RX_ST_IRE)) fep->stats.rx_length_errors++; } else { /* Send the skb up the chain. */ frame_length = fep->rx_desc[i].data_len - 4; skb_put(fep->rx_skb[i], frame_length); fep->rx_skb[i]->dev = dev; fep->rx_skb[i]->protocol = eth_type_trans(fep->rx_skb[i], dev); error = netif_rx(fep->rx_skb[i]); if ((error == NET_RX_DROP) || (error == NET_RX_BAD)) { fep->stats.rx_dropped++; } else { fep->stats.rx_packets++; fep->stats.rx_bytes += frame_length; } fep->rx_skb[i] = NULL; } skip: slots_walked = 1; } while ((i = (i + 1) % NUM_RX_BUFF) != fep->rx_slot); PKT_DEBUG(("emac_rx_clean() exit, rx_slot: %d\n", fep->rx_slot)); if (slots_walked && call_rx_fill) emac_rx_fill(dev, i);}static voidemac_rxeob_dev(void *param, u32 chanmask){ struct net_device *dev = param; struct ocp_enet_private *fep = dev->priv; unsigned long flags; spin_lock_irqsave(&fep->lock, flags); emac_rx_clean(dev, 1); spin_unlock_irqrestore(&fep->lock, flags);}/* * This interrupt should never occurr, we don't program * the MAL for contiunous mode. */static voidemac_txde_dev(void *param, u32 chanmask){ struct net_device *dev = param; struct ocp_enet_private *fep = dev->priv; printk(KERN_WARNING "%s: transmit descriptor error\n", dev->name); emac_mac_dump(dev); emac_mal_dump(dev); /* Reenable the transmit channel */ mal_enable_tx_channels(fep->mal, fep->commac.tx_chan_mask);}/* * This interrupt should be very rare at best. This occurs when * the hardware has a problem with the receive descriptors. The manual * states that it occurs when the hardware cannot the receive descriptor * empty bit is not set. The recovery mechanism will be to * traverse through the descriptors, handle any that are marked to be * handled and reinitialize each along the way. At that point the driver * will be restarted. */static voidemac_rxde_dev(void *param, u32 chanmask){ struct net_device *dev = param; struct ocp_enet_private *fep = dev->priv; unsigned long flags; printk(KERN_WARNING "%s: receive descriptor error\n", fep->ndev->name); emac_mac_dump(dev); emac_mal_dump(dev); emac_desc_dump(dev); /* Disable RX channel */ spin_lock_irqsave(&fep->lock, flags); mal_disable_rx_channels(fep->mal, fep->commac.rx_chan_mask); /* For now, charge the error against all emacs */ fep->stats.rx_errors++; /* so do we have any good packets still? */ emac_rx_clean(dev,0); /* When the interface is restarted it resets processing to the * first descriptor in the table. */ fep->rx_slot = 0; emac_rx_fill(dev, 0); set_mal_dcrn(fep->mal, DCRN_MALRXEOBISR, fep->commac.rx_chan_mask); set_mal_dcrn(fep->mal, DCRN_MALRXDEIR, fep->commac.rx_chan_mask); /* Reenable the receive channels */ mal_enable_rx_channels(fep->mal, fep->commac.rx_chan_mask); spin_unlock_irqrestore(&fep->lock, flags);}static voidemac_mac_irq(int irq, void *dev_instance, struct pt_regs *regs){ struct net_device *dev = dev_instance; struct ocp_enet_private *fep = dev->priv; volatile emac_t *emacp = fep->emacp; unsigned long tmp_em0isr; /* EMAC interrupt */ tmp_em0isr = in_be32(&emacp->em0isr); if (tmp_em0isr & (EMAC_ISR_TE0 | EMAC_ISR_TE1)) { /* This error is a hard transmit error - could retransmit */ fep->stats.tx_errors++; /* Reenable the transmit channel */ mal_enable_tx_channels(fep->mal, fep->commac.tx_chan_mask); } else { fep->stats.rx_errors++; } if (tmp_em0isr & EMAC_ISR_RP) fep->stats.rx_length_errors++; if (tmp_em0isr & EMAC_ISR_ALE) fep->stats.rx_frame_errors++; if (tmp_em0isr & EMAC_ISR_BFCS) fep->stats.rx_crc_errors++; if (tmp_em0isr & EMAC_ISR_PTLE) fep->stats.rx_length_errors++; if (tmp_em0isr & EMAC_ISR_ORE) fep->stats.rx_length_errors++; if (tmp_em0isr & EMAC_ISR_TE0) fep->stats.tx_aborted_errors++; emac_err_dump(dev, tmp_em0isr); out_be32(&emacp->em0isr, tmp_em0isr);}static intemac_start_xmit(struct sk_buff *skb, struct net_device *dev){ unsigned short ctrl; unsigned long flags; struct ocp_enet_private *fep = dev->priv; volatile emac_t *emacp = fep->emacp; spin_lock_irqsave(&fep->lock, flags); PKT_DEBUG(("emac_start_xmit() entry, queue stopped: %d, fep->tx_cnt: %d\n", netif_queue_stopped(dev), fep->tx_cnt)); /* That shouldn't happen... */ if (netif_queue_stopped(dev) || (fep->tx_cnt == NUM_TX_BUFF)) { printk("%s: start_xmit called on full queue !\n", dev->name); BUG(); } if (++fep->tx_cnt == NUM_TX_BUFF) { PKT_DEBUG(("emac_start_xmit() stopping queue\n")); netif_stop_queue(dev); } /* Store the skb buffer for later ack by the transmit end of buffer * interrupt. */ fep->tx_skb[fep->tx_slot] = skb; consistent_sync((void *) skb->data, skb->len, PCI_DMA_TODEVICE); ctrl = EMAC_TX_CTRL_DFLT; if ((NUM_TX_BUFF - 1) == fep->tx_slot) ctrl |= MAL_TX_CTRL_WRAP; fep->tx_desc[fep->tx_slot].data_ptr = (char *) virt_to_phys(skb->data); fep->tx_desc[fep->tx_slot].data_len = (short) skb->len; fep->tx_desc[fep->tx_slot].ctrl = ctrl; /* Send the packet out. */ out_be32(&emacp->em0tmr0, EMAC_TMR0_XMIT); if (++fep->tx_slot == NUM_TX_BUFF) fep->tx_slot = 0; 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 intemac_adjust_to_link(struct ocp_enet_private *fep){ volatile 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) */ if (speed == SPEED_100) { mode_reg |= EMAC_M1_MF_100MBPS; if (fep->zmii_dev) emac_zmii_port_speed(fep->zmii_dev, fep->zmii_input, 100); } else { mode_reg &= ~EMAC_M1_MF_100MBPS; 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: %s, %s duplex.\n", fep->ndev->name, speed == SPEED_100 ? "100" : "10", full_duplex ? "Full" : "Half"); if (fep->opened) out_be32(&emacp->em0mr1, mode_reg); return 0;}static void__emac_set_multicast_list(struct net_device *dev){ struct ocp_enet_private *fep = dev->priv; volatile 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 voidemac_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]) 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; 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 voidemac_reset_configure(struct ocp_enet_private *fep){ volatile 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); /* 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_OCP_ENET_GAP); /* Init ring buffers */ emac_init_rings(fep->ndev);}static voidemac_kick(struct ocp_enet_private *fep){ volatile 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; 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 voidemac_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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -