/** * arc_emac_tx_avail - Return the number of available slots in the tx ring. * @priv: Pointer to ARC EMAC private data structure. * * returns: the number of slots available for transmission in tx the ring.
*/ staticinlineint arc_emac_tx_avail(struct arc_emac_priv *priv)
{ return (priv->txbd_dirty + TX_BD_NUM - priv->txbd_curr - 1) % TX_BD_NUM;
}
/** * arc_emac_adjust_link - Adjust the PHY link duplex. * @ndev: Pointer to the net_device structure. * * This function is called to change the duplex setting after auto negotiation * is done by the PHY.
*/ staticvoid arc_emac_adjust_link(struct net_device *ndev)
{ struct arc_emac_priv *priv = netdev_priv(ndev); struct phy_device *phy_dev = ndev->phydev; unsignedint reg, state_changed = 0;
/* Ensure that txbd_dirty is visible to tx() before checking * for queue stopped.
*/
smp_mb();
if (netif_queue_stopped(ndev) && arc_emac_tx_avail(priv))
netif_wake_queue(ndev);
}
/** * arc_emac_rx - processing of Rx packets. * @ndev: Pointer to the network device. * @budget: How many BDs to process on 1 call. * * returns: Number of processed BDs * * Iterate through Rx BDs and deliver received packages to upper layer.
*/ staticint arc_emac_rx(struct net_device *ndev, int budget)
{ struct arc_emac_priv *priv = netdev_priv(ndev); struct device *dev = ndev->dev.parent; unsignedint work_done;
if (unlikely((info & OWN_MASK) == FOR_EMAC)) break;
/* Make a note that we saw a packet at this BD. * So next time, driver starts from this + 1
*/
*last_rx_bd = (*last_rx_bd + 1) % RX_BD_NUM;
if (unlikely((info & FIRST_OR_LAST_MASK) !=
FIRST_OR_LAST_MASK)) { /* We pre-allocate buffers of MTU size so incoming * packets won't be split/chained.
*/ if (net_ratelimit())
netdev_err(ndev, "incomplete packet received\n");
/* Prepare the BD for next cycle. netif_receive_skb() * only if new skb was allocated and mapped to avoid holes * in the RX fifo.
*/
skb = netdev_alloc_skb_ip_align(ndev, EMAC_BUFFER_SIZE); if (unlikely(!skb)) { if (net_ratelimit())
netdev_err(ndev, "cannot allocate skb\n"); /* Return ownership to EMAC */
rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE);
stats->rx_errors++;
stats->rx_dropped++; continue;
}
miss = arc_reg_get(priv, R_MISS); if (miss) {
stats->rx_errors += miss;
stats->rx_missed_errors += miss;
priv->rx_missed_errors += miss;
}
}
/** * arc_emac_rx_stall_check - check RX stall * @ndev: Pointer to the net_device structure. * @budget: How many BDs requested to process on 1 call. * @work_done: How many BDs processed * * Under certain conditions EMAC stop reception of incoming packets and * continuously increment R_MISS register instead of saving data into * provided buffer. This function detect that condition and restart * EMAC.
*/ staticvoid arc_emac_rx_stall_check(struct net_device *ndev, int budget, unsignedint work_done)
{ struct arc_emac_priv *priv = netdev_priv(ndev); struct arc_emac_bd *rxbd;
if (work_done)
priv->rx_missed_errors = 0;
if (priv->rx_missed_errors && budget) {
rxbd = &priv->rxbd[priv->last_rx_bd]; if (le32_to_cpu(rxbd->info) & FOR_EMAC) {
arc_emac_restart(ndev);
priv->rx_missed_errors = 0;
}
}
}
/** * arc_emac_poll - NAPI poll handler. * @napi: Pointer to napi_struct structure. * @budget: How many BDs to process on 1 call. * * returns: Number of processed BDs
*/ staticint arc_emac_poll(struct napi_struct *napi, int budget)
{ struct net_device *ndev = napi->dev; struct arc_emac_priv *priv = netdev_priv(ndev); unsignedint work_done;
/** * arc_emac_intr - Global interrupt handler for EMAC. * @irq: irq number. * @dev_instance: device instance. * * returns: IRQ_HANDLED for all cases. * * ARC EMAC has only 1 interrupt line, and depending on bits raised in * STATUS register we may tell what is a reason for interrupt to fire.
*/ static irqreturn_t arc_emac_intr(int irq, void *dev_instance)
{ struct net_device *ndev = dev_instance; struct arc_emac_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; unsignedint status;
status = arc_reg_get(priv, R_STATUS);
status &= ~MDIO_MASK;
/** * arc_emac_open - Open the network device. * @ndev: Pointer to the network device. * * returns: 0, on success or non-zero error value on failure. * * This function sets the MAC address, requests and enables an IRQ * for the EMAC device and starts the Tx queue. * It also connects to the phy device.
*/ staticint arc_emac_open(struct net_device *ndev)
{ struct arc_emac_priv *priv = netdev_priv(ndev); struct phy_device *phy_dev = ndev->phydev; struct device *dev = ndev->dev.parent; int i;
/* Set BD ring pointers for device side */
arc_reg_set(priv, R_RX_RING, (unsignedint)priv->rxbd_dma);
arc_reg_set(priv, R_TX_RING, (unsignedint)priv->txbd_dma);
/** * arc_emac_set_rx_mode - Change the receive filtering mode. * @ndev: Pointer to the network device. * * This function enables/disables promiscuous or all-multicast mode * and updates the multicast filtering list of the network device.
*/ staticvoid arc_emac_set_rx_mode(struct net_device *ndev)
{ struct arc_emac_priv *priv = netdev_priv(ndev);
/** * arc_free_tx_queue - free skb from tx queue * @ndev: Pointer to the network device. * * This function must be called while EMAC disable
*/ staticvoid arc_free_tx_queue(struct net_device *ndev)
{ struct arc_emac_priv *priv = netdev_priv(ndev); struct device *dev = ndev->dev.parent; unsignedint i;
for (i = 0; i < TX_BD_NUM; i++) { struct arc_emac_bd *txbd = &priv->txbd[i]; struct buffer_state *tx_buff = &priv->tx_buff[i];
if (tx_buff->skb) {
dma_unmap_single(dev,
dma_unmap_addr(tx_buff, addr),
dma_unmap_len(tx_buff, len),
DMA_TO_DEVICE);
/* return the sk_buff to system */
dev_kfree_skb_irq(tx_buff->skb);
}
/** * arc_free_rx_queue - free skb from rx queue * @ndev: Pointer to the network device. * * This function must be called while EMAC disable
*/ staticvoid arc_free_rx_queue(struct net_device *ndev)
{ struct arc_emac_priv *priv = netdev_priv(ndev); struct device *dev = ndev->dev.parent; unsignedint i;
for (i = 0; i < RX_BD_NUM; i++) { struct arc_emac_bd *rxbd = &priv->rxbd[i]; struct buffer_state *rx_buff = &priv->rx_buff[i];
if (rx_buff->skb) {
dma_unmap_single(dev,
dma_unmap_addr(rx_buff, addr),
dma_unmap_len(rx_buff, len),
DMA_FROM_DEVICE);
/* return the sk_buff to system */
dev_kfree_skb_irq(rx_buff->skb);
}
/** * arc_emac_stop - Close the network device. * @ndev: Pointer to the network device. * * This function stops the Tx queue, disables interrupts and frees the IRQ for * the EMAC device. * It also disconnects the PHY device associated with the EMAC device.
*/ staticint arc_emac_stop(struct net_device *ndev)
{ struct arc_emac_priv *priv = netdev_priv(ndev);
/** * arc_emac_tx - Starts the data transmission. * @skb: sk_buff pointer that contains data to be Transmitted. * @ndev: Pointer to net_device structure. * * returns: NETDEV_TX_OK, on success * NETDEV_TX_BUSY, if any of the descriptors are not free. * * This function is invoked from upper layers to initiate transmission.
*/ static netdev_tx_t arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
{ struct arc_emac_priv *priv = netdev_priv(ndev); unsignedint len, *txbd_curr = &priv->txbd_curr; struct net_device_stats *stats = &ndev->stats;
__le32 *info = &priv->txbd[*txbd_curr].info; struct device *dev = ndev->dev.parent;
dma_addr_t addr;
if (skb_padto(skb, ETH_ZLEN)) return NETDEV_TX_OK;
len = max_t(unsignedint, ETH_ZLEN, skb->len);
if (unlikely(!arc_emac_tx_avail(priv))) {
netif_stop_queue(ndev);
netdev_err(ndev, "BUG! Tx Ring full when queue awake!\n"); return NETDEV_TX_BUSY;
}
/* Increment index to point to the next BD */
*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
/* Ensure that tx_clean() sees the new txbd_curr before * checking the queue status. This prevents an unneeded wake * of the queue in tx_clean().
*/
smp_mb();
if (!arc_emac_tx_avail(priv)) {
netif_stop_queue(ndev); /* Refresh tx_dirty */
smp_mb(); if (arc_emac_tx_avail(priv))
netif_start_queue(ndev);
}
/** * arc_emac_set_address - Set the MAC address for this device. * @ndev: Pointer to net_device structure. * @p: 6 byte Address to be written as MAC address. * * This function copies the HW address from the sockaddr structure to the * net_device structure and updates the address in HW. * * returns: -EBUSY if the net device is busy or 0 if the address is set * successfully.
*/ staticint arc_emac_set_address(struct net_device *ndev, void *p)
{ struct sockaddr *addr = p;
if (netif_running(ndev)) return -EBUSY;
if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL;
eth_hw_addr_set(ndev, addr->sa_data);
arc_emac_set_address_internal(ndev);
return 0;
}
/** * arc_emac_restart - Restart EMAC * @ndev: Pointer to net_device structure. * * This function do hardware reset of EMAC in order to restore * network packets reception.
*/ staticvoid arc_emac_restart(struct net_device *ndev)
{ struct arc_emac_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; int i;
if (net_ratelimit())
netdev_warn(ndev, "restarting stalled EMAC\n");
/* Get PHY from device tree */
phy_node = of_parse_phandle(dev->of_node, "phy", 0); if (!phy_node) {
dev_err(dev, "failed to retrieve phy description from device tree\n"); return -ENODEV;
}
/* Get EMAC registers base address from device tree */
err = of_address_to_resource(dev->of_node, 0, &res_regs); if (err) {
dev_err(dev, "failed to retrieve registers base from device tree\n");
err = -ENODEV; goto out_put_node;
}
/* Get IRQ from device tree */
irq = irq_of_parse_and_map(dev->of_node, 0); if (!irq) {
dev_err(dev, "failed to retrieve <irq> value from device tree\n");
err = -ENODEV; goto out_put_node;
}
dev_dbg(dev, "Registers base address is 0x%p\n", priv->regs);
if (priv->clk) {
err = clk_prepare_enable(priv->clk); if (err) {
dev_err(dev, "failed to enable clock\n"); goto out_put_node;
}
clock_frequency = clk_get_rate(priv->clk);
} else { /* Get CPU clock frequency from device tree */ if (of_property_read_u32(dev->of_node, "clock-frequency",
&clock_frequency)) {
dev_err(dev, "failed to retrieve <clock-frequency> from device tree\n");
err = -EINVAL; goto out_put_node;
}
}
id = arc_reg_get(priv, R_ID);
/* Check for EMAC revision 5 or 7, magic number */ if (!(id == 0x0005fd02 || id == 0x0007fd02)) {
dev_err(dev, "ARC EMAC not detected, id=0x%x\n", id);
err = -ENODEV; goto out_clken;
}
dev_info(dev, "ARC EMAC detected with id: 0x%x\n", id);
/* Set poll rate so that it polls every 1 ms */
arc_reg_set(priv, R_POLLRATE, clock_frequency / 1000000);
ndev->irq = irq;
dev_info(dev, "IRQ is %d\n", ndev->irq);
/* Register interrupt handler for device */
err = devm_request_irq(dev, ndev->irq, arc_emac_intr, 0,
ndev->name, ndev); if (err) {
dev_err(dev, "could not allocate IRQ\n"); goto out_clken;
}
/* Get MAC address from device tree */
err = of_get_ethdev_address(dev->of_node, ndev); if (err)
eth_hw_addr_random(ndev);
arc_emac_set_address_internal(ndev);
dev_info(dev, "MAC address is now %pM\n", ndev->dev_addr);
/* Do 1 allocation instead of 2 separate ones for Rx and Tx BD rings */
priv->rxbd = dmam_alloc_coherent(dev, RX_RING_SZ + TX_RING_SZ,
&priv->rxbd_dma, GFP_KERNEL);
if (!priv->rxbd) {
dev_err(dev, "failed to allocate data buffers\n");
err = -ENOMEM; goto out_clken;
}
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.