staticint greth_debug = -1; /* -1 == use GRETH_DEF_MSG_ENABLE as value */
module_param(greth_debug, int, 0);
MODULE_PARM_DESC(greth_debug, "GRETH bitmapped debugging message enable value");
/* Accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */ staticint macaddr[6];
module_param_array(macaddr, int, NULL, 0);
MODULE_PARM_DESC(macaddr, "GRETH Ethernet MAC address");
staticint greth_edcl = 1;
module_param(greth_edcl, int, 0);
MODULE_PARM_DESC(greth_edcl, "GRETH EDCL usage indicator. Set to 1 if EDCL is used.");
staticinlinevoid greth_enable_tx_and_irq(struct greth_private *greth)
{
wmb(); /* BDs must been written to memory before enabling TX */
GRETH_REGORIN(greth->regs->control, GRETH_TXEN | GRETH_TXI);
}
/* Write descriptor control word and enable transmission */
greth_write_bd(&bdp->stat, status);
spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
greth_enable_tx(greth);
spin_unlock_irqrestore(&greth->devlock, flags);
if (netif_msg_pktdata(greth))
greth_print_tx_packet(skb);
if (unlikely(skb->len > MAX_FRAME_SIZE)) {
dev->stats.tx_errors++; goto len_error;
}
/* Save skb pointer. */
greth->tx_skbuff[greth->tx_next] = skb;
/* Linear buf */ if (nr_frags != 0)
status = GRETH_TXBD_MORE; else
status = GRETH_BD_IE;
if (skb->ip_summed == CHECKSUM_PARTIAL)
status |= GRETH_TXBD_CSALL;
status |= skb_headlen(skb) & GRETH_BD_LEN; if (greth->tx_next == GRETH_TXBD_NUM_MASK)
status |= GRETH_BD_WR;
if (unlikely(dma_mapping_error(greth->dev, dma_addr))) goto frag_map_error;
greth_write_bd(&bdp->addr, dma_addr);
curr_tx = NEXT_TX(curr_tx);
}
wmb();
/* Enable the descriptor chain by enabling the first descriptor */
bdp = greth->tx_bd_base + greth->tx_next;
greth_write_bd(&bdp->stat,
greth_read_bd(&bdp->stat) | GRETH_BD_EN);
/* Get the interrupt events that caused us to be here. */
status = GRETH_REGLOAD(greth->regs->status);
/* Must see if interrupts are enabled also, INT_TX|INT_RX flags may be *setregardlessofwhetherIRQisenabledornot.Especially *importantwhensharedIRQ.
*/
ctrl = GRETH_REGLOAD(greth->regs->control);
tx_last = NEXT_TX(tx_last);
}
dev_kfree_skb(skb);
} if (skb) { /* skb is set only if the above while loop was entered */
wmb();
greth->tx_last = tx_last;
if (netif_queue_stopped(dev) &&
(greth_num_free_bds(tx_last, greth->tx_next) >
(MAX_SKB_FRAGS+1)))
netif_wake_queue(dev);
}
}
staticint greth_rx(struct net_device *dev, int limit)
{ struct greth_private *greth; struct greth_bd *bdp; struct sk_buff *skb; int pkt_len; int bad, count;
u32 status, dma_addr; unsignedlong flags;
/* Check status for errors. */ if (unlikely(status & GRETH_RXBD_STATUS)) { if (status & GRETH_RXBD_ERR_FT) {
dev->stats.rx_length_errors++;
bad = 1;
} if (status & (GRETH_RXBD_ERR_AE | GRETH_RXBD_ERR_OE)) {
dev->stats.rx_frame_errors++;
bad = 1;
} if (status & GRETH_RXBD_ERR_CRC) {
dev->stats.rx_crc_errors++;
bad = 1;
}
} if (unlikely(bad)) {
dev->stats.rx_errors++;
spin_lock_irqsave(&greth->devlock, flags); /* save from XMIT */
greth_enable_rx(greth);
spin_unlock_irqrestore(&greth->devlock, flags);
greth->rx_cur = NEXT_RX(greth->rx_cur);
}
return count;
}
staticinlineint hw_checksummed(u32 status)
{
if (status & GRETH_RXBD_IP_FRAG) return0;
if (status & GRETH_RXBD_IP && status & GRETH_RXBD_IP_CSERR) return0;
if (status & GRETH_RXBD_UDP && status & GRETH_RXBD_UDP_CSERR) return0;
if (status & GRETH_RXBD_TCP && status & GRETH_RXBD_TCP_CSERR) return0;
return1;
}
staticint greth_rx_gbit(struct net_device *dev, int limit)
{ struct greth_private *greth; struct greth_bd *bdp; struct sk_buff *skb, *newskb; int pkt_len; int bad, count = 0;
u32 status, dma_addr; unsignedlong flags;
greth = netdev_priv(dev);
for (count = 0; count < limit; ++count) {
bdp = greth->rx_bd_base + greth->rx_cur;
skb = greth->rx_skbuff[greth->rx_cur];
GRETH_REGSAVE(greth->regs->status, GRETH_INT_RE | GRETH_INT_RX);
mb();
status = greth_read_bd(&bdp->stat);
bad = 0;
if (status & GRETH_BD_EN) break;
/* Check status for errors. */ if (unlikely(status & GRETH_RXBD_STATUS)) {
if (status & GRETH_RXBD_ERR_FT) {
dev->stats.rx_length_errors++;
bad = 1;
} elseif (status &
(GRETH_RXBD_ERR_AE | GRETH_RXBD_ERR_OE | GRETH_RXBD_ERR_LE)) {
dev->stats.rx_frame_errors++;
bad = 1;
} elseif (status & GRETH_RXBD_ERR_CRC) {
dev->stats.rx_crc_errors++;
bad = 1;
}
}
/* Allocate new skb to replace current, not needed if the
* current skb can be reused */ if (!bad && (newskb=netdev_alloc_skb(dev, MAX_FRAME_SIZE + NET_IP_ALIGN))) {
skb_reserve(newskb, NET_IP_ALIGN);
greth->rx_skbuff[greth->rx_cur] = newskb;
greth_write_bd(&bdp->addr, dma_addr);
} else { if (net_ratelimit())
dev_warn(greth->dev, "Could not create DMA mapping, dropping packet\n");
dev_kfree_skb(newskb); /* reusing current skb, so it is a drop */
dev->stats.rx_dropped++;
}
} elseif (bad) { /* Bad Frame transfer, the skb is reused */
dev->stats.rx_dropped++;
} else { /* Failed Allocating a new skb. This is rather stupid *butthecurrent"filled"skbisreused,asif *transferfailure.OnecouldarguethatRXdescriptor *tablehandlingshouldbedividedintocleaningand *fillingastheTXpartofthedriver
*/ if (net_ratelimit())
dev_warn(greth->dev, "Could not allocate SKB, dropping packet\n"); /* reusing current skb, so it is a drop */
dev->stats.rx_dropped++;
}
status = GRETH_BD_EN | GRETH_BD_IE; if (greth->rx_cur == GRETH_RXBD_NUM_MASK) {
status |= GRETH_BD_WR;
}
if (phydev->link != greth->link) { if (!phydev->link) {
greth->speed = 0;
greth->duplex = -1;
}
greth->link = phydev->link;
status_change = 1;
}
spin_unlock_irqrestore(&greth->devlock, flags);
if (status_change) { if (phydev->link)
pr_debug("%s: link up (%d/%s)\n",
dev->name, phydev->speed,
DUPLEX_FULL == phydev->duplex ? "Full" : "Half"); else
pr_debug("%s: link down\n", dev->name);
}
}
/* Find the first PHY */
phy = phy_find_first(greth->mdio);
if (!phy) { if (netif_msg_probe(greth))
dev_err(&dev->dev, "no PHY found\n"); return -ENXIO;
}
ret = phy_connect_direct(dev, phy, &greth_link_change,
greth->gbit_mac ? PHY_INTERFACE_MODE_GMII : PHY_INTERFACE_MODE_MII); if (ret) { if (netif_msg_ifup(greth))
dev_err(&dev->dev, "could not attach to PHY\n"); return ret;
}
if (greth->gbit_mac)
phy_set_max_speed(phy, SPEED_1000); else
phy_set_max_speed(phy, SPEED_100);
ret = mdiobus_register(greth->mdio); if (ret) { goto error;
}
ret = greth_mdio_probe(greth->netdev); if (ret) { if (netif_msg_probe(greth))
dev_err(&greth->netdev->dev, "failed to probe MDIO bus\n"); goto unreg_mdio;
}
phy_start(ndev->phydev);
/* If Ethernet debug link is used make autoneg happen right away */ if (greth->edcl && greth_edcl == 1) {
phy_start_aneg(ndev->phydev);
timeout = jiffies + 6*HZ; while (!phy_aneg_done(ndev->phydev) &&
time_before(jiffies, timeout)) {
}
phy_read_status(ndev->phydev);
greth_link_change(greth->netdev);
}
if (netif_msg_probe(greth))
dev_dbg(greth->dev, "resetting controller.\n");
/* Reset the controller. */
GRETH_REGSAVE(regs->control, GRETH_RESET);
/* Wait for MAC to reset itself */
timeout = jiffies + HZ/100; while (GRETH_REGLOAD(regs->control) & GRETH_RESET) { if (time_after(jiffies, timeout)) {
err = -EIO; if (netif_msg_probe(greth))
dev_err(greth->dev, "timeout when waiting for reset.\n"); goto error2;
}
}
/* If we have EDCL we disable the EDCL speed-duplex FSM so
* it doesn't interfere with the software */ if (greth->edcl != 0)
GRETH_REGORIN(regs->control, GRETH_CTRL_DISDUPLEX);
/* Check if MAC can handle MDIO interrupts */
greth->mdio_int_en = (tmp >> 26) & 1;
err = greth_mdio_init(greth); if (err) { if (netif_msg_probe(greth))
dev_err(greth->dev, "failed to register MDIO bus\n"); goto error2;
}
/* Allocate TX descriptor ring in coherent memory */
greth->tx_bd_base = dma_alloc_coherent(greth->dev, 1024,
&greth->tx_bd_base_phys,
GFP_KERNEL); if (!greth->tx_bd_base) {
err = -ENOMEM; goto error3;
}
/* Allocate RX descriptor ring in coherent memory */
greth->rx_bd_base = dma_alloc_coherent(greth->dev, 1024,
&greth->rx_bd_base_phys,
GFP_KERNEL); if (!greth->rx_bd_base) {
err = -ENOMEM; goto error4;
}
/* Get MAC address from: module param, OF property or ID prom */ for (i = 0; i < 6; i++) { if (macaddr[i] != 0) break;
} if (i == 6) {
err = of_get_mac_address(ofdev->dev.of_node, addr); if (!err) { for (i = 0; i < 6; i++)
macaddr[i] = (unsignedint) addr[i];
} else { #ifdef CONFIG_SPARC for (i = 0; i < 6; i++)
macaddr[i] = (unsignedint) idprom->id_ethaddr[i]; #endif
}
}
for (i = 0; i < 6; i++)
addr[i] = macaddr[i];
eth_hw_addr_set(dev, addr);
macaddr[5]++;
if (!is_valid_ether_addr(&dev->dev_addr[0])) { if (netif_msg_probe(greth))
dev_err(greth->dev, "no valid ethernet address, aborting.\n");
err = -EINVAL; goto error5;
}
MODULE_AUTHOR("Aeroflex Gaisler AB.");
MODULE_DESCRIPTION("Aeroflex Gaisler Ethernet MAC driver");
MODULE_LICENSE("GPL");
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.14Bemerkung:
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.