static int bgmac_stop(struct net_device *net_dev) { struct bgmac *bgmac = netdev_priv(net_dev); netif_carrier_off(net_dev); phy_stop(bgmac->phy_dev); napi_disable(&bgmac->napi); bgmac_chip_intrs_off(bgmac); free_irq(bgmac->core->irq, net_dev); bgmac_chip_reset(bgmac); return 0; }
static irqreturn_t bgmac_interrupt(int irq, void *dev_id) { struct bgmac *bgmac = netdev_priv(dev_id); u32 int_status = bgmac_read(bgmac, BGMAC_INT_STATUS); int_status &= bgmac->int_mask; if (!int_status) return IRQ_NONE; int_status &= ~(BGMAC_IS_TX0 | BGMAC_IS_RX); if (int_status) bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", int_status); /* Disable new interrupts until handling existing ones */ bgmac_chip_intrs_off(bgmac); napi_schedule(&bgmac->napi); return IRQ_HANDLED; }
int bgmac_enet_suspend(struct bgmac *bgmac) { if (!netif_running(bgmac->net_dev)) return 0; phy_stop(bgmac->net_dev->phydev); netif_stop_queue(bgmac->net_dev); napi_disable(&bgmac->napi); netif_tx_lock(bgmac->net_dev); netif_device_detach(bgmac->net_dev); netif_tx_unlock(bgmac->net_dev); bgmac_chip_intrs_off(bgmac); bgmac_chip_reset(bgmac); bgmac_dma_cleanup(bgmac); return 0; }
static irqreturn_t bgmac_interrupt(int irq, void *dev_id) { struct bgmac *bgmac = netdev_priv(dev_id); u32 int_status = bgmac_read(bgmac, BGMAC_INT_STATUS); int_status &= bgmac->int_mask; if (!int_status) return IRQ_NONE; /* Ack */ bgmac_write(bgmac, BGMAC_INT_STATUS, int_status); /* Disable new interrupts until handling existing ones */ bgmac_chip_intrs_off(bgmac); bgmac->int_status = int_status; napi_schedule(&bgmac->napi); return IRQ_HANDLED; }
int bgmac_phy_connect_direct(struct bgmac *bgmac) { struct fixed_phy_status fphy_status = { .link = 1, .speed = SPEED_1000, .duplex = DUPLEX_FULL, }; struct phy_device *phy_dev; int err; phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, NULL); if (!phy_dev || IS_ERR(phy_dev)) { dev_err(bgmac->dev, "Failed to register fixed PHY device\n"); return -ENODEV; } err = phy_connect_direct(bgmac->net_dev, phy_dev, bgmac_adjust_link, PHY_INTERFACE_MODE_MII); if (err) { dev_err(bgmac->dev, "Connecting PHY failed\n"); return err; } return err; } EXPORT_SYMBOL_GPL(bgmac_phy_connect_direct); struct bgmac *bgmac_alloc(struct device *dev) { struct net_device *net_dev; struct bgmac *bgmac; /* Allocation and references */ net_dev = devm_alloc_etherdev(dev, sizeof(*bgmac)); if (!net_dev) return NULL; net_dev->netdev_ops = &bgmac_netdev_ops; net_dev->ethtool_ops = &bgmac_ethtool_ops; bgmac = netdev_priv(net_dev); bgmac->dev = dev; bgmac->net_dev = net_dev; return bgmac; } EXPORT_SYMBOL_GPL(bgmac_alloc); int bgmac_enet_probe(struct bgmac *bgmac) { struct net_device *net_dev = bgmac->net_dev; int err; bgmac_chip_intrs_off(bgmac); net_dev->irq = bgmac->irq; SET_NETDEV_DEV(net_dev, bgmac->dev); dev_set_drvdata(bgmac->dev, bgmac); if (!is_valid_ether_addr(net_dev->dev_addr)) { dev_err(bgmac->dev, "Invalid MAC addr: %pM\n", net_dev->dev_addr); eth_hw_addr_random(net_dev); dev_warn(bgmac->dev, "Using random MAC: %pM\n", net_dev->dev_addr); } /* This (reset &) enable is not preset in specs or reference driver but * Broadcom does it in arch PCI code when enabling fake PCI device. */ bgmac_clk_enable(bgmac, 0); /* This seems to be fixing IRQ by assigning OOB #6 to the core */ if (!(bgmac->feature_flags & BGMAC_FEAT_IDM_MASK)) { if (bgmac->feature_flags & BGMAC_FEAT_IRQ_ID_OOB_6) bgmac_idm_write(bgmac, BCMA_OOB_SEL_OUT_A30, 0x86); } bgmac_chip_reset(bgmac); err = bgmac_dma_alloc(bgmac); if (err) { dev_err(bgmac->dev, "Unable to alloc memory for DMA\n"); goto err_out; } bgmac->int_mask = BGMAC_IS_ERRMASK | BGMAC_IS_RX | BGMAC_IS_TX_MASK; if (bcm47xx_nvram_getenv("et0_no_txint", NULL, 0) == 0) bgmac->int_mask &= ~BGMAC_IS_TX_MASK; netif_napi_add(net_dev, &bgmac->napi, bgmac_poll, BGMAC_WEIGHT); err = bgmac_phy_connect(bgmac); if (err) { dev_err(bgmac->dev, "Cannot connect to phy\n"); goto err_dma_free; } net_dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; net_dev->hw_features = net_dev->features; net_dev->vlan_features = net_dev->features; err = register_netdev(bgmac->net_dev); if (err) { dev_err(bgmac->dev, "Cannot register net device\n"); goto err_phy_disconnect; } netif_carrier_off(net_dev); return 0; err_phy_disconnect: phy_disconnect(net_dev->phydev); err_dma_free: bgmac_dma_free(bgmac); err_out: return err; } EXPORT_SYMBOL_GPL(bgmac_enet_probe); void bgmac_enet_remove(struct bgmac *bgmac) { unregister_netdev(bgmac->net_dev); phy_disconnect(bgmac->net_dev->phydev); netif_napi_del(&bgmac->napi); bgmac_dma_free(bgmac); free_netdev(bgmac->net_dev); }