/** * 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. */ static int arc_emac_stop(struct net_device *ndev) { struct arc_emac_priv *priv = netdev_priv(ndev); napi_disable(&priv->napi); netif_stop_queue(ndev); /* Disable interrupts */ arc_reg_clr(priv, R_ENABLE, RXINT_MASK | ERR_MASK); /* Disable EMAC */ arc_reg_clr(priv, R_CTRL, EN_MASK); return 0; }
/** * 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. */ static void arc_emac_set_rx_mode(struct net_device *ndev) { struct arc_emac_priv *priv = netdev_priv(ndev); if (ndev->flags & IFF_PROMISC) { arc_reg_or(priv, R_CTRL, PROM_MASK); } else { arc_reg_clr(priv, R_CTRL, PROM_MASK); if (ndev->flags & IFF_ALLMULTI) { arc_reg_set(priv, R_LAFL, ~0); arc_reg_set(priv, R_LAFH, ~0); } else if (ndev->flags & IFF_MULTICAST) { struct netdev_hw_addr *ha; unsigned int filter[2] = { 0, 0 }; int bit; netdev_for_each_mc_addr(ha, ndev) { bit = ether_crc_le(ETH_ALEN, ha->addr) >> 26; filter[bit >> 5] |= 1 << (bit & 31); } arc_reg_set(priv, R_LAFL, filter[0]); arc_reg_set(priv, R_LAFH, filter[1]); } else {
static void arc_emac_halt(struct eth_device *edev) { struct arc_emac_priv *priv = edev->priv; /* Disable EMAC */ arc_reg_clr(priv, R_CTRL, EN_MASK); }
/** * 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; unsigned int status; status = arc_reg_get(priv, R_STATUS); status &= ~MDIO_MASK; /* Reset all flags except "MDIO complete" */ arc_reg_set(priv, R_STATUS, status); if (status & (RXINT_MASK | TXINT_MASK)) { if (likely(napi_schedule_prep(&priv->napi))) { arc_reg_clr(priv, R_ENABLE, RXINT_MASK | TXINT_MASK); __napi_schedule(&priv->napi); } } if (status & ERR_MASK) { /* MSER/RXCR/RXFR/RXFL interrupt fires on corresponding * 8-bit error counter overrun. */ if (status & MSER_MASK) { stats->rx_missed_errors += 0x100; stats->rx_errors += 0x100; priv->rx_missed_errors += 0x100; napi_schedule(&priv->napi); } if (status & RXCR_MASK) { stats->rx_crc_errors += 0x100; stats->rx_errors += 0x100; } if (status & RXFR_MASK) { stats->rx_frame_errors += 0x100; stats->rx_errors += 0x100; } if (status & RXFL_MASK) { stats->rx_over_errors += 0x100; stats->rx_errors += 0x100; } } return IRQ_HANDLED; }