diff options
Diffstat (limited to 'drivers/net/ethernet/broadcom/asp2')
-rw-r--r-- | drivers/net/ethernet/broadcom/asp2/bcmasp.c | 232 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/asp2/bcmasp.h | 104 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c | 92 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c | 301 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/asp2/bcmasp_intf_defs.h | 3 |
5 files changed, 351 insertions, 381 deletions
diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.c b/drivers/net/ethernet/broadcom/asp2/bcmasp.c index 80245c65cc90..fd35f4b4dc50 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.c @@ -31,6 +31,20 @@ static void _intr2_mask_set(struct bcmasp_priv *priv, u32 mask) priv->irq_mask |= mask; } +void bcmasp_enable_phy_irq(struct bcmasp_intf *intf, int en) +{ + struct bcmasp_priv *priv = intf->parent; + + /* Only supported with internal phys */ + if (!intf->internal_phy) + return; + + if (en) + _intr2_mask_clear(priv, ASP_INTR2_PHY_EVENT(intf->channel)); + else + _intr2_mask_set(priv, ASP_INTR2_PHY_EVENT(intf->channel)); +} + void bcmasp_enable_tx_irq(struct bcmasp_intf *intf, int en) { struct bcmasp_priv *priv = intf->parent; @@ -79,6 +93,9 @@ static void bcmasp_intr2_handling(struct bcmasp_intf *intf, u32 status) __napi_schedule_irqoff(&intf->tx_napi); } } + + if (status & ASP_INTR2_PHY_EVENT(intf->channel)) + phy_mac_interrupt(intf->ndev->phydev); } static irqreturn_t bcmasp_isr(int irq, void *data) @@ -124,7 +141,7 @@ void bcmasp_flush_rx_port(struct bcmasp_intf *intf) return; } - rx_ctrl_core_wl(priv, mask, priv->hw_info->rx_ctrl_flush); + rx_ctrl_core_wl(priv, mask, ASP_RX_CTRL_FLUSH); } static void bcmasp_netfilt_hw_en_wake(struct bcmasp_priv *priv, @@ -501,7 +518,7 @@ void bcmasp_netfilt_suspend(struct bcmasp_intf *intf) int ret, i; /* Write all filters to HW */ - for (i = 0; i < NUM_NET_FILTERS; i++) { + for (i = 0; i < priv->num_net_filters; i++) { /* If the filter does not match the port, skip programming. */ if (!priv->net_filters[i].claimed || priv->net_filters[i].port != intf->port) @@ -534,7 +551,7 @@ int bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs, struct bcmasp_priv *priv = intf->parent; int j = 0, i; - for (i = 0; i < NUM_NET_FILTERS; i++) { + for (i = 0; i < priv->num_net_filters; i++) { if (!priv->net_filters[i].claimed || priv->net_filters[i].port != intf->port) continue; @@ -560,7 +577,7 @@ int bcmasp_netfilt_get_active(struct bcmasp_intf *intf) struct bcmasp_priv *priv = intf->parent; int cnt = 0, i; - for (i = 0; i < NUM_NET_FILTERS; i++) { + for (i = 0; i < priv->num_net_filters; i++) { if (!priv->net_filters[i].claimed || priv->net_filters[i].port != intf->port) continue; @@ -585,7 +602,7 @@ bool bcmasp_netfilt_check_dup(struct bcmasp_intf *intf, size_t fs_size = 0; int i; - for (i = 0; i < NUM_NET_FILTERS; i++) { + for (i = 0; i < priv->num_net_filters; i++) { if (!priv->net_filters[i].claimed || priv->net_filters[i].port != intf->port) continue; @@ -653,7 +670,7 @@ struct bcmasp_net_filter *bcmasp_netfilt_get_init(struct bcmasp_intf *intf, int i, open_index = -1; /* Check whether we exceed the filter table capacity */ - if (loc != RX_CLS_LOC_ANY && loc >= NUM_NET_FILTERS) + if (loc != RX_CLS_LOC_ANY && loc >= priv->num_net_filters) return ERR_PTR(-EINVAL); /* If the filter location is busy (already claimed) and we are initializing @@ -669,7 +686,7 @@ struct bcmasp_net_filter *bcmasp_netfilt_get_init(struct bcmasp_intf *intf, /* Initialize the loop index based on the desired location or from 0 */ i = loc == RX_CLS_LOC_ANY ? 0 : loc; - for ( ; i < NUM_NET_FILTERS; i++) { + for ( ; i < priv->num_net_filters; i++) { /* Found matching network filter */ if (!init && priv->net_filters[i].claimed && @@ -762,7 +779,7 @@ static void bcmasp_en_mda_filter(struct bcmasp_intf *intf, bool en, priv->mda_filters[i].en = en; priv->mda_filters[i].port = intf->port; - rx_filter_core_wl(priv, ((intf->channel + 8) | + rx_filter_core_wl(priv, ((intf->channel + priv->tx_chan_offset) | (en << ASP_RX_FILTER_MDA_CFG_EN_SHIFT) | ASP_RX_FILTER_MDA_CFG_UMC_SEL(intf->port)), ASP_RX_FILTER_MDA_CFG(i)); @@ -848,7 +865,7 @@ void bcmasp_disable_all_filters(struct bcmasp_intf *intf) res_count = bcmasp_total_res_mda_cnt(intf->parent); /* Disable all filters held by this port */ - for (i = res_count; i < NUM_MDA_FILTERS; i++) { + for (i = res_count; i < priv->num_mda_filters; i++) { if (priv->mda_filters[i].en && priv->mda_filters[i].port == intf->port) bcmasp_en_mda_filter(intf, 0, i); @@ -892,7 +909,7 @@ int bcmasp_set_en_mda_filter(struct bcmasp_intf *intf, unsigned char *addr, res_count = bcmasp_total_res_mda_cnt(intf->parent); - for (i = res_count; i < NUM_MDA_FILTERS; i++) { + for (i = res_count; i < priv->num_mda_filters; i++) { /* If filter not enabled or belongs to another port skip */ if (!priv->mda_filters[i].en || priv->mda_filters[i].port != intf->port) @@ -907,7 +924,7 @@ int bcmasp_set_en_mda_filter(struct bcmasp_intf *intf, unsigned char *addr, } /* Create new filter if possible */ - for (i = res_count; i < NUM_MDA_FILTERS; i++) { + for (i = res_count; i < priv->num_mda_filters; i++) { if (priv->mda_filters[i].en) continue; @@ -927,12 +944,12 @@ static void bcmasp_core_init_filters(struct bcmasp_priv *priv) /* Disable all filters and reset software view since the HW * can lose context while in deep sleep suspend states */ - for (i = 0; i < NUM_MDA_FILTERS; i++) { + for (i = 0; i < priv->num_mda_filters; i++) { rx_filter_core_wl(priv, 0x0, ASP_RX_FILTER_MDA_CFG(i)); priv->mda_filters[i].en = 0; } - for (i = 0; i < NUM_NET_FILTERS; i++) + for (i = 0; i < priv->num_net_filters; i++) rx_filter_core_wl(priv, 0x0, ASP_RX_FILTER_NET_CFG(i)); /* Top level filter enable bit should be enabled at all times, set @@ -949,18 +966,8 @@ static void bcmasp_core_init_filters(struct bcmasp_priv *priv) /* ASP core initialization */ static void bcmasp_core_init(struct bcmasp_priv *priv) { - tx_analytics_core_wl(priv, 0x0, ASP_TX_ANALYTICS_CTRL); - rx_analytics_core_wl(priv, 0x4, ASP_RX_ANALYTICS_CTRL); - - rx_edpkt_core_wl(priv, (ASP_EDPKT_HDR_SZ_128 << ASP_EDPKT_HDR_SZ_SHIFT), - ASP_EDPKT_HDR_CFG); - rx_edpkt_core_wl(priv, - (ASP_EDPKT_ENDI_BT_SWP_WD << ASP_EDPKT_ENDI_DESC_SHIFT), - ASP_EDPKT_ENDI); - rx_edpkt_core_wl(priv, 0x1b, ASP_EDPKT_BURST_BUF_PSCAL_TOUT); rx_edpkt_core_wl(priv, 0x3e8, ASP_EDPKT_BURST_BUF_WRITE_TOUT); - rx_edpkt_core_wl(priv, 0x3e8, ASP_EDPKT_BURST_BUF_READ_TOUT); rx_edpkt_core_wl(priv, ASP_EDPKT_ENABLE_EN, ASP_EDPKT_ENABLE); @@ -972,7 +979,26 @@ static void bcmasp_core_init(struct bcmasp_priv *priv) ASP_INTR2_CLEAR); } -static void bcmasp_core_clock_select(struct bcmasp_priv *priv, bool slow) +static void bcmasp_core_clock_select_many(struct bcmasp_priv *priv, bool slow) +{ + u32 reg; + + reg = ctrl2_core_rl(priv, ASP_CTRL2_CORE_CLOCK_SELECT); + if (slow) + reg &= ~ASP_CTRL2_CORE_CLOCK_SELECT_MAIN; + else + reg |= ASP_CTRL2_CORE_CLOCK_SELECT_MAIN; + ctrl2_core_wl(priv, reg, ASP_CTRL2_CORE_CLOCK_SELECT); + + reg = ctrl2_core_rl(priv, ASP_CTRL2_CPU_CLOCK_SELECT); + if (slow) + reg &= ~ASP_CTRL2_CPU_CLOCK_SELECT_MAIN; + else + reg |= ASP_CTRL2_CPU_CLOCK_SELECT_MAIN; + ctrl2_core_wl(priv, reg, ASP_CTRL2_CPU_CLOCK_SELECT); +} + +static void bcmasp_core_clock_select_one(struct bcmasp_priv *priv, bool slow) { u32 reg; @@ -984,6 +1010,18 @@ static void bcmasp_core_clock_select(struct bcmasp_priv *priv, bool slow) ctrl_core_wl(priv, reg, ASP_CTRL_CORE_CLOCK_SELECT); } +static void bcmasp_core_clock_select_one_ctrl2(struct bcmasp_priv *priv, bool slow) +{ + u32 reg; + + reg = ctrl2_core_rl(priv, ASP_CTRL2_CORE_CLOCK_SELECT); + if (slow) + reg &= ~ASP_CTRL2_CORE_CLOCK_SELECT_MAIN; + else + reg |= ASP_CTRL2_CORE_CLOCK_SELECT_MAIN; + ctrl2_core_wl(priv, reg, ASP_CTRL2_CORE_CLOCK_SELECT); +} + static void bcmasp_core_clock_set_ll(struct bcmasp_priv *priv, u32 clr, u32 set) { u32 reg; @@ -1072,7 +1110,7 @@ static int bcmasp_get_and_request_irq(struct bcmasp_priv *priv, int i) return irq; } -static void bcmasp_init_wol_shared(struct bcmasp_priv *priv) +static void bcmasp_init_wol(struct bcmasp_priv *priv) { struct platform_device *pdev = priv->pdev; struct device *dev = &pdev->dev; @@ -1089,7 +1127,7 @@ static void bcmasp_init_wol_shared(struct bcmasp_priv *priv) device_set_wakeup_capable(&pdev->dev, 1); } -static void bcmasp_enable_wol_shared(struct bcmasp_intf *intf, bool en) +void bcmasp_enable_wol(struct bcmasp_intf *intf, bool en) { struct bcmasp_priv *priv = intf->parent; struct device *dev = &priv->pdev->dev; @@ -1118,95 +1156,77 @@ static void bcmasp_enable_wol_shared(struct bcmasp_intf *intf, bool en) } } -static void bcmasp_wol_irq_destroy_shared(struct bcmasp_priv *priv) +static void bcmasp_wol_irq_destroy(struct bcmasp_priv *priv) { if (priv->wol_irq > 0) free_irq(priv->wol_irq, priv); } -static void bcmasp_init_wol_per_intf(struct bcmasp_priv *priv) +static void bcmasp_eee_fixup(struct bcmasp_intf *intf, bool en) { - struct platform_device *pdev = priv->pdev; - struct device *dev = &pdev->dev; - struct bcmasp_intf *intf; - int irq; + u32 reg, phy_lpi_overwrite; - list_for_each_entry(intf, &priv->intfs, list) { - irq = bcmasp_get_and_request_irq(priv, intf->port + 1); - if (irq < 0) { - dev_warn(dev, "Failed to init WoL irq(port %d): %d\n", - intf->port, irq); - continue; - } + reg = rx_edpkt_core_rl(intf->parent, ASP_EDPKT_SPARE_REG); + phy_lpi_overwrite = intf->internal_phy ? ASP_EDPKT_SPARE_REG_EPHY_LPI : + ASP_EDPKT_SPARE_REG_GPHY_LPI; - intf->wol_irq = irq; - intf->wol_irq_enabled = false; - device_set_wakeup_capable(&pdev->dev, 1); - } -} - -static void bcmasp_enable_wol_per_intf(struct bcmasp_intf *intf, bool en) -{ - struct device *dev = &intf->parent->pdev->dev; + if (en) + reg |= phy_lpi_overwrite; + else + reg &= ~phy_lpi_overwrite; - if (en ^ intf->wol_irq_enabled) - irq_set_irq_wake(intf->wol_irq, en); + rx_edpkt_core_wl(intf->parent, reg, ASP_EDPKT_SPARE_REG); - intf->wol_irq_enabled = en; - device_set_wakeup_enable(dev, en); + usleep_range(50, 100); } -static void bcmasp_wol_irq_destroy_per_intf(struct bcmasp_priv *priv) -{ - struct bcmasp_intf *intf; - - list_for_each_entry(intf, &priv->intfs, list) { - if (intf->wol_irq > 0) - free_irq(intf->wol_irq, priv); - } -} - -static struct bcmasp_hw_info v20_hw_info = { - .rx_ctrl_flush = ASP_RX_CTRL_FLUSH, - .umac2fb = UMAC2FB_OFFSET, - .rx_ctrl_fb_out_frame_count = ASP_RX_CTRL_FB_OUT_FRAME_COUNT, - .rx_ctrl_fb_filt_out_frame_count = ASP_RX_CTRL_FB_FILT_OUT_FRAME_COUNT, - .rx_ctrl_fb_rx_fifo_depth = ASP_RX_CTRL_FB_RX_FIFO_DEPTH, +static const struct bcmasp_plat_data v21_plat_data = { + .core_clock_select = bcmasp_core_clock_select_one, + .num_mda_filters = 32, + .num_net_filters = 32, + .tx_chan_offset = 8, + .rx_ctrl_offset = 0x0, }; -static const struct bcmasp_plat_data v20_plat_data = { - .init_wol = bcmasp_init_wol_per_intf, - .enable_wol = bcmasp_enable_wol_per_intf, - .destroy_wol = bcmasp_wol_irq_destroy_per_intf, - .hw_info = &v20_hw_info, +static const struct bcmasp_plat_data v22_plat_data = { + .core_clock_select = bcmasp_core_clock_select_many, + .eee_fixup = bcmasp_eee_fixup, + .num_mda_filters = 32, + .num_net_filters = 32, + .tx_chan_offset = 8, + .rx_ctrl_offset = 0x0, }; -static struct bcmasp_hw_info v21_hw_info = { - .rx_ctrl_flush = ASP_RX_CTRL_FLUSH_2_1, - .umac2fb = UMAC2FB_OFFSET_2_1, - .rx_ctrl_fb_out_frame_count = ASP_RX_CTRL_FB_OUT_FRAME_COUNT_2_1, - .rx_ctrl_fb_filt_out_frame_count = - ASP_RX_CTRL_FB_FILT_OUT_FRAME_COUNT_2_1, - .rx_ctrl_fb_rx_fifo_depth = ASP_RX_CTRL_FB_RX_FIFO_DEPTH_2_1, +static const struct bcmasp_plat_data v30_plat_data = { + .core_clock_select = bcmasp_core_clock_select_one_ctrl2, + .num_mda_filters = 20, + .num_net_filters = 16, + .tx_chan_offset = 0, + .rx_ctrl_offset = 0x10000, }; -static const struct bcmasp_plat_data v21_plat_data = { - .init_wol = bcmasp_init_wol_shared, - .enable_wol = bcmasp_enable_wol_shared, - .destroy_wol = bcmasp_wol_irq_destroy_shared, - .hw_info = &v21_hw_info, -}; +static void bcmasp_set_pdata(struct bcmasp_priv *priv, const struct bcmasp_plat_data *pdata) +{ + priv->core_clock_select = pdata->core_clock_select; + priv->eee_fixup = pdata->eee_fixup; + priv->num_mda_filters = pdata->num_mda_filters; + priv->num_net_filters = pdata->num_net_filters; + priv->tx_chan_offset = pdata->tx_chan_offset; + priv->rx_ctrl_offset = pdata->rx_ctrl_offset; +} static const struct of_device_id bcmasp_of_match[] = { - { .compatible = "brcm,asp-v2.0", .data = &v20_plat_data }, { .compatible = "brcm,asp-v2.1", .data = &v21_plat_data }, + { .compatible = "brcm,asp-v2.2", .data = &v22_plat_data }, + { .compatible = "brcm,asp-v3.0", .data = &v30_plat_data }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, bcmasp_of_match); static const struct of_device_id bcmasp_mdio_of_match[] = { { .compatible = "brcm,asp-v2.1-mdio", }, - { .compatible = "brcm,asp-v2.0-mdio", }, + { .compatible = "brcm,asp-v2.2-mdio", }, + { .compatible = "brcm,asp-v3.0-mdio", }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, bcmasp_mdio_of_match); @@ -1223,9 +1243,9 @@ static void bcmasp_remove_intfs(struct bcmasp_priv *priv) static int bcmasp_probe(struct platform_device *pdev) { - struct device_node *ports_node, *intf_node; const struct bcmasp_plat_data *pdata; struct device *dev = &pdev->dev; + struct device_node *ports_node; struct bcmasp_priv *priv; struct bcmasp_intf *intf; int ret = 0, count = 0; @@ -1265,16 +1285,13 @@ static int bcmasp_probe(struct platform_device *pdev) if (!pdata) return dev_err_probe(dev, -EINVAL, "unable to find platform data\n"); - priv->init_wol = pdata->init_wol; - priv->enable_wol = pdata->enable_wol; - priv->destroy_wol = pdata->destroy_wol; - priv->hw_info = pdata->hw_info; + bcmasp_set_pdata(priv, pdata); /* Enable all clocks to ensure successful probing */ bcmasp_core_clock_set(priv, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE, 0); /* Switch to the main clock */ - bcmasp_core_clock_select(priv, false); + priv->core_clock_select(priv, false); bcmasp_intr2_mask_set_all(priv); bcmasp_intr2_clear_all(priv); @@ -1291,6 +1308,17 @@ static int bcmasp_probe(struct platform_device *pdev) * how many interfaces come up. */ bcmasp_core_init(priv); + + priv->mda_filters = devm_kcalloc(dev, priv->num_mda_filters, + sizeof(*priv->mda_filters), GFP_KERNEL); + if (!priv->mda_filters) + return -ENOMEM; + + priv->net_filters = devm_kcalloc(dev, priv->num_net_filters, + sizeof(*priv->net_filters), GFP_KERNEL); + if (!priv->net_filters) + return -ENOMEM; + bcmasp_core_init_filters(priv); ports_node = of_find_node_by_name(dev->of_node, "ethernet-ports"); @@ -1300,12 +1328,12 @@ static int bcmasp_probe(struct platform_device *pdev) } i = 0; - for_each_available_child_of_node(ports_node, intf_node) { + for_each_available_child_of_node_scoped(ports_node, intf_node) { intf = bcmasp_interface_create(priv, intf_node, i); if (!intf) { dev_err(dev, "Cannot create eth interface %d\n", i); bcmasp_remove_intfs(priv); - of_node_put(intf_node); + ret = -ENOMEM; goto of_put_exit; } list_add_tail(&intf->list, &priv->intfs); @@ -1313,7 +1341,7 @@ static int bcmasp_probe(struct platform_device *pdev) } /* Check and enable WoL */ - priv->init_wol(priv); + bcmasp_init_wol(priv); /* Drop the clock reference count now and let ndo_open()/ndo_close() * manage it for us from now on. @@ -1330,7 +1358,7 @@ static int bcmasp_probe(struct platform_device *pdev) if (ret) { netdev_err(intf->ndev, "failed to register net_device: %d\n", ret); - priv->destroy_wol(priv); + bcmasp_wol_irq_destroy(priv); bcmasp_remove_intfs(priv); goto of_put_exit; } @@ -1351,7 +1379,7 @@ static void bcmasp_remove(struct platform_device *pdev) if (!priv) return; - priv->destroy_wol(priv); + bcmasp_wol_irq_destroy(priv); bcmasp_remove_intfs(priv); } @@ -1381,7 +1409,7 @@ static int __maybe_unused bcmasp_suspend(struct device *d) */ bcmasp_core_clock_set(priv, 0, ASP_CTRL_CLOCK_CTRL_ASP_TX_DISABLE); - bcmasp_core_clock_select(priv, true); + priv->core_clock_select(priv, true); clk_disable_unprepare(priv->clk); @@ -1399,7 +1427,7 @@ static int __maybe_unused bcmasp_resume(struct device *d) return ret; /* Switch to the main clock domain */ - bcmasp_core_clock_select(priv, false); + priv->core_clock_select(priv, false); /* Re-enable all clocks for re-initialization */ bcmasp_core_clock_set(priv, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE, 0); @@ -1426,7 +1454,7 @@ static SIMPLE_DEV_PM_OPS(bcmasp_pm_ops, static struct platform_driver bcmasp_driver = { .probe = bcmasp_probe, - .remove_new = bcmasp_remove, + .remove = bcmasp_remove, .shutdown = bcmasp_shutdown, .driver = { .name = "brcm,asp-v2", diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.h b/drivers/net/ethernet/broadcom/asp2/bcmasp.h index ec90add6b03e..74adfdb50e11 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.h +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.h @@ -19,6 +19,8 @@ #define ASP_INTR2_TX_DESC(intr) BIT((intr) + 14) #define ASP_INTR2_UMC0_WAKE BIT(22) #define ASP_INTR2_UMC1_WAKE BIT(28) +#define ASP_INTR2_PHY_EVENT(intr) ((intr) ? BIT(30) | BIT(31) : \ + BIT(24) | BIT(25)) #define ASP_WAKEUP_INTR2_OFFSET 0x1200 #define ASP_WAKEUP_INTR2_STATUS 0x0 @@ -33,6 +35,12 @@ #define ASP_WAKEUP_INTR2_FILT_1 BIT(3) #define ASP_WAKEUP_INTR2_FW BIT(4) +#define ASP_CTRL2_OFFSET 0x2000 +#define ASP_CTRL2_CORE_CLOCK_SELECT 0x0 +#define ASP_CTRL2_CORE_CLOCK_SELECT_MAIN BIT(0) +#define ASP_CTRL2_CPU_CLOCK_SELECT 0x4 +#define ASP_CTRL2_CPU_CLOCK_SELECT_MAIN BIT(0) + #define ASP_TX_ANALYTICS_OFFSET 0x4c000 #define ASP_TX_ANALYTICS_CTRL 0x0 @@ -45,22 +53,15 @@ #define ASP_RX_CTRL_FB_0_FRAME_COUNT 0x14 #define ASP_RX_CTRL_FB_1_FRAME_COUNT 0x18 #define ASP_RX_CTRL_FB_8_FRAME_COUNT 0x1c -/* asp2.1 diverges offsets here */ -/* ASP2.0 */ -#define ASP_RX_CTRL_FB_OUT_FRAME_COUNT 0x20 -#define ASP_RX_CTRL_FB_FILT_OUT_FRAME_COUNT 0x24 -#define ASP_RX_CTRL_FLUSH 0x28 -#define ASP_CTRL_UMAC0_FLUSH_MASK (BIT(0) | BIT(12)) -#define ASP_CTRL_UMAC1_FLUSH_MASK (BIT(1) | BIT(13)) -#define ASP_CTRL_SPB_FLUSH_MASK (BIT(8) | BIT(20)) -#define ASP_RX_CTRL_FB_RX_FIFO_DEPTH 0x30 -/* ASP2.1 */ -#define ASP_RX_CTRL_FB_9_FRAME_COUNT_2_1 0x20 -#define ASP_RX_CTRL_FB_10_FRAME_COUNT_2_1 0x24 -#define ASP_RX_CTRL_FB_OUT_FRAME_COUNT_2_1 0x28 -#define ASP_RX_CTRL_FB_FILT_OUT_FRAME_COUNT_2_1 0x2c -#define ASP_RX_CTRL_FLUSH_2_1 0x30 -#define ASP_RX_CTRL_FB_RX_FIFO_DEPTH_2_1 0x38 +#define ASP_RX_CTRL_FB_9_FRAME_COUNT 0x20 +#define ASP_RX_CTRL_FB_10_FRAME_COUNT 0x24 +#define ASP_RX_CTRL_FB_OUT_FRAME_COUNT 0x28 +#define ASP_RX_CTRL_FB_FILT_OUT_FRAME_COUNT 0x2c +#define ASP_RX_CTRL_FLUSH 0x30 +#define ASP_CTRL_UMAC0_FLUSH_MASK (BIT(0) | BIT(12)) +#define ASP_CTRL_UMAC1_FLUSH_MASK (BIT(1) | BIT(13)) +#define ASP_CTRL_SPB_FLUSH_MASK (BIT(8) | BIT(20)) +#define ASP_RX_CTRL_FB_RX_FIFO_DEPTH 0x38 #define ASP_RX_FILTER_OFFSET 0x80000 #define ASP_RX_FILTER_BLK_CTRL 0x0 @@ -134,8 +135,11 @@ enum asp_rx_net_filter_block { #define ASP_EDPKT_RX_PKT_CNT 0x138 #define ASP_EDPKT_HDR_EXTR_CNT 0x13c #define ASP_EDPKT_HDR_OUT_CNT 0x140 +#define ASP_EDPKT_SPARE_REG 0x174 +#define ASP_EDPKT_SPARE_REG_EPHY_LPI BIT(4) +#define ASP_EDPKT_SPARE_REG_GPHY_LPI BIT(3) -#define ASP_CTRL 0x101000 +#define ASP_CTRL_OFFSET 0x101000 #define ASP_CTRL_ASP_SW_INIT 0x04 #define ASP_CTRL_ASP_SW_INIT_ACPUSS_CORE BIT(0) #define ASP_CTRL_ASP_SW_INIT_ASP_TX BIT(1) @@ -306,6 +310,7 @@ struct bcmasp_intf { struct bcmasp_desc *rx_edpkt_cpu; dma_addr_t rx_edpkt_dma_addr; dma_addr_t rx_edpkt_dma_read; + dma_addr_t rx_edpkt_dma_valid; /* RX buffer prefetcher ring*/ void *rx_ring_cpu; @@ -333,11 +338,6 @@ struct bcmasp_intf { u32 wolopts; u8 sopass[SOPASS_MAX]; - /* Used if per intf wol irq */ - int wol_irq; - unsigned int wol_irq_enabled:1; - - struct ethtool_eee eee; }; #define NUM_NET_FILTERS 32 @@ -360,19 +360,13 @@ struct bcmasp_mda_filter { u8 mask[ETH_ALEN]; }; -struct bcmasp_hw_info { - u32 rx_ctrl_flush; - u32 umac2fb; - u32 rx_ctrl_fb_out_frame_count; - u32 rx_ctrl_fb_filt_out_frame_count; - u32 rx_ctrl_fb_rx_fifo_depth; -}; - struct bcmasp_plat_data { - void (*init_wol)(struct bcmasp_priv *priv); - void (*enable_wol)(struct bcmasp_intf *intf, bool en); - void (*destroy_wol)(struct bcmasp_priv *priv); - struct bcmasp_hw_info *hw_info; + void (*core_clock_select)(struct bcmasp_priv *priv, bool slow); + void (*eee_fixup)(struct bcmasp_intf *priv, bool en); + unsigned int num_mda_filters; + unsigned int num_net_filters; + unsigned int tx_chan_offset; + unsigned int rx_ctrl_offset; }; struct bcmasp_priv { @@ -387,16 +381,18 @@ struct bcmasp_priv { int wol_irq; unsigned long wol_irq_enabled_mask; - void (*init_wol)(struct bcmasp_priv *priv); - void (*enable_wol)(struct bcmasp_intf *intf, bool en); - void (*destroy_wol)(struct bcmasp_priv *priv); + void (*core_clock_select)(struct bcmasp_priv *priv, bool slow); + void (*eee_fixup)(struct bcmasp_intf *intf, bool en); + unsigned int num_mda_filters; + unsigned int num_net_filters; + unsigned int tx_chan_offset; + unsigned int rx_ctrl_offset; void __iomem *base; - struct bcmasp_hw_info *hw_info; struct list_head intfs; - struct bcmasp_mda_filter mda_filters[NUM_MDA_FILTERS]; + struct bcmasp_mda_filter *mda_filters; /* MAC destination address filters lock */ spinlock_t mda_lock; @@ -404,7 +400,7 @@ struct bcmasp_priv { /* Protects accesses to ASP_CTRL_CLOCK_CTRL */ spinlock_t clk_lock; - struct bcmasp_net_filter net_filters[NUM_NET_FILTERS]; + struct bcmasp_net_filter *net_filters; /* Network filter lock */ struct mutex net_lock; @@ -494,8 +490,8 @@ BCMASP_FP_IO_MACRO_Q(rx_edpkt_cfg); #define PKT_OFFLOAD_EPKT_IP(x) ((x) << 21) #define PKT_OFFLOAD_EPKT_TP(x) ((x) << 19) #define PKT_OFFLOAD_EPKT_LEN(x) ((x) << 16) -#define PKT_OFFLOAD_EPKT_CSUM_L3 BIT(15) -#define PKT_OFFLOAD_EPKT_CSUM_L2 BIT(14) +#define PKT_OFFLOAD_EPKT_CSUM_L4 BIT(15) +#define PKT_OFFLOAD_EPKT_CSUM_L3 BIT(14) #define PKT_OFFLOAD_EPKT_ID(x) ((x) << 12) #define PKT_OFFLOAD_EPKT_SEQ(x) ((x) << 10) #define PKT_OFFLOAD_EPKT_TS(x) ((x) << 8) @@ -527,10 +523,26 @@ BCMASP_CORE_IO_MACRO(intr2, ASP_INTR2_OFFSET); BCMASP_CORE_IO_MACRO(wakeup_intr2, ASP_WAKEUP_INTR2_OFFSET); BCMASP_CORE_IO_MACRO(tx_analytics, ASP_TX_ANALYTICS_OFFSET); BCMASP_CORE_IO_MACRO(rx_analytics, ASP_RX_ANALYTICS_OFFSET); -BCMASP_CORE_IO_MACRO(rx_ctrl, ASP_RX_CTRL_OFFSET); BCMASP_CORE_IO_MACRO(rx_filter, ASP_RX_FILTER_OFFSET); BCMASP_CORE_IO_MACRO(rx_edpkt, ASP_EDPKT_OFFSET); -BCMASP_CORE_IO_MACRO(ctrl, ASP_CTRL); +BCMASP_CORE_IO_MACRO(ctrl, ASP_CTRL_OFFSET); +BCMASP_CORE_IO_MACRO(ctrl2, ASP_CTRL2_OFFSET); + +#define BCMASP_CORE_IO_MACRO_OFFSET(name, offset) \ +static inline u32 name##_core_rl(struct bcmasp_priv *priv, \ + u32 off) \ +{ \ + u32 reg = readl_relaxed(priv->base + priv->name##_offset + \ + (offset) + off); \ + return reg; \ +} \ +static inline void name##_core_wl(struct bcmasp_priv *priv, \ + u32 val, u32 off) \ +{ \ + writel_relaxed(val, priv->base + priv->name##_offset + \ + (offset) + off); \ +} +BCMASP_CORE_IO_MACRO_OFFSET(rx_ctrl, ASP_RX_CTRL_OFFSET); struct bcmasp_intf *bcmasp_interface_create(struct bcmasp_priv *priv, struct device_node *ndev_dn, int i); @@ -541,6 +553,8 @@ void bcmasp_enable_tx_irq(struct bcmasp_intf *intf, int en); void bcmasp_enable_rx_irq(struct bcmasp_intf *intf, int en); +void bcmasp_enable_phy_irq(struct bcmasp_intf *intf, int en); + void bcmasp_flush_rx_port(struct bcmasp_intf *intf); extern const struct ethtool_ops bcmasp_ethtool_ops; @@ -582,5 +596,5 @@ int bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs, void bcmasp_netfilt_suspend(struct bcmasp_intf *intf); -void bcmasp_eee_enable_set(struct bcmasp_intf *intf, bool enable); +void bcmasp_enable_wol(struct bcmasp_intf *intf, bool en); #endif diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c index ce6a3d56fb23..4381a4cfd8c6 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #define pr_fmt(fmt) "bcmasp_ethtool: " fmt -#include <asm-generic/unaligned.h> +#include <linux/unaligned.h> #include <linux/ethtool.h> #include <linux/netdevice.h> #include <linux/platform_device.h> @@ -10,7 +10,6 @@ #include "bcmasp_intf_defs.h" enum bcmasp_stat_type { - BCMASP_STAT_RX_EDPKT, BCMASP_STAT_RX_CTRL, BCMASP_STAT_RX_CTRL_PER_INTF, BCMASP_STAT_SOFT, @@ -33,8 +32,6 @@ struct bcmasp_stats { .reg_offset = offset, \ } -#define STAT_BCMASP_RX_EDPKT(str, offset) \ - STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_EDPKT, offset) #define STAT_BCMASP_RX_CTRL(str, offset) \ STAT_BCMASP_OFFSET(str, BCMASP_STAT_RX_CTRL, offset) #define STAT_BCMASP_RX_CTRL_PER_INTF(str, offset) \ @@ -42,11 +39,6 @@ struct bcmasp_stats { /* Must match the order of struct bcmasp_mib_counters */ static const struct bcmasp_stats bcmasp_gstrings_stats[] = { - /* EDPKT counters */ - STAT_BCMASP_RX_EDPKT("RX Time Stamp", ASP_EDPKT_RX_TS_COUNTER), - STAT_BCMASP_RX_EDPKT("RX PKT Count", ASP_EDPKT_RX_PKT_CNT), - STAT_BCMASP_RX_EDPKT("RX PKT Buffered", ASP_EDPKT_HDR_EXTR_CNT), - STAT_BCMASP_RX_EDPKT("RX PKT Pushed to DRAM", ASP_EDPKT_HDR_OUT_CNT), /* ASP RX control */ STAT_BCMASP_RX_CTRL_PER_INTF("Frames From Unimac", ASP_RX_CTRL_UMAC_0_FRAME_COUNT), @@ -71,23 +63,6 @@ static const struct bcmasp_stats bcmasp_gstrings_stats[] = { #define BCMASP_STATS_LEN ARRAY_SIZE(bcmasp_gstrings_stats) -static u16 bcmasp_stat_fixup_offset(struct bcmasp_intf *intf, - const struct bcmasp_stats *s) -{ - struct bcmasp_priv *priv = intf->parent; - - if (!strcmp("Frames Out(Buffer)", s->stat_string)) - return priv->hw_info->rx_ctrl_fb_out_frame_count; - - if (!strcmp("Frames Out(Filters)", s->stat_string)) - return priv->hw_info->rx_ctrl_fb_filt_out_frame_count; - - if (!strcmp("RX Buffer FIFO Depth", s->stat_string)) - return priv->hw_info->rx_ctrl_fb_rx_fifo_depth; - - return s->reg_offset; -} - static int bcmasp_get_sset_count(struct net_device *dev, int string_set) { switch (string_set) { @@ -101,14 +76,14 @@ static int bcmasp_get_sset_count(struct net_device *dev, int string_set) static void bcmasp_get_strings(struct net_device *dev, u32 stringset, u8 *data) { + const char *str; unsigned int i; switch (stringset) { case ETH_SS_STATS: for (i = 0; i < BCMASP_STATS_LEN; i++) { - memcpy(data + i * ETH_GSTRING_LEN, - bcmasp_gstrings_stats[i].stat_string, - ETH_GSTRING_LEN); + str = bcmasp_gstrings_stats[i].stat_string; + ethtool_puts(&data, str); } break; default: @@ -126,13 +101,10 @@ static void bcmasp_update_mib_counters(struct bcmasp_intf *intf) char *p; s = &bcmasp_gstrings_stats[i]; - offset = bcmasp_stat_fixup_offset(intf, s); + offset = s->reg_offset; switch (s->type) { case BCMASP_STAT_SOFT: continue; - case BCMASP_STAT_RX_EDPKT: - val = rx_edpkt_core_rl(intf->parent, offset); - break; case BCMASP_STAT_RX_CTRL: val = rx_ctrl_core_rl(intf->parent, offset); break; @@ -215,7 +187,7 @@ static int bcmasp_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) memcpy(intf->sopass, wol->sopass, sizeof(wol->sopass)); mutex_lock(&priv->wol_lock); - priv->enable_wol(intf, !!intf->wolopts); + bcmasp_enable_wol(intf, !!intf->wolopts); mutex_unlock(&priv->wol_lock); return 0; @@ -289,7 +261,7 @@ static int bcmasp_flow_get(struct bcmasp_intf *intf, struct ethtool_rxnfc *cmd) memcpy(&cmd->fs, &nfilter->fs, sizeof(nfilter->fs)); - cmd->data = NUM_NET_FILTERS; + cmd->data = intf->parent->num_net_filters; return 0; } @@ -336,7 +308,7 @@ static int bcmasp_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, break; case ETHTOOL_GRXCLSRLALL: err = bcmasp_netfilt_get_all_active(intf, rule_locs, &cmd->rule_cnt); - cmd->data = NUM_NET_FILTERS; + cmd->data = intf->parent->num_net_filters; break; default: err = -EOPNOTSUPP; @@ -348,62 +320,19 @@ static int bcmasp_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, return err; } -void bcmasp_eee_enable_set(struct bcmasp_intf *intf, bool enable) +static int bcmasp_get_eee(struct net_device *dev, struct ethtool_keee *e) { - u32 reg; - - reg = umac_rl(intf, UMC_EEE_CTRL); - if (enable) - reg |= EEE_EN; - else - reg &= ~EEE_EN; - umac_wl(intf, reg, UMC_EEE_CTRL); - - intf->eee.eee_enabled = enable; - intf->eee.eee_active = enable; -} - -static int bcmasp_get_eee(struct net_device *dev, struct ethtool_eee *e) -{ - struct bcmasp_intf *intf = netdev_priv(dev); - struct ethtool_eee *p = &intf->eee; - if (!dev->phydev) return -ENODEV; - e->eee_enabled = p->eee_enabled; - e->eee_active = p->eee_active; - e->tx_lpi_enabled = p->tx_lpi_enabled; - e->tx_lpi_timer = umac_rl(intf, UMC_EEE_LPI_TIMER); - return phy_ethtool_get_eee(dev->phydev, e); } -static int bcmasp_set_eee(struct net_device *dev, struct ethtool_eee *e) +static int bcmasp_set_eee(struct net_device *dev, struct ethtool_keee *e) { - struct bcmasp_intf *intf = netdev_priv(dev); - struct ethtool_eee *p = &intf->eee; - int ret; - if (!dev->phydev) return -ENODEV; - if (!p->eee_enabled) { - bcmasp_eee_enable_set(intf, false); - } else { - ret = phy_init_eee(dev->phydev, 0); - if (ret) { - netif_err(intf, hw, dev, - "EEE initialization failed: %d\n", ret); - return ret; - } - - umac_wl(intf, e->tx_lpi_timer, UMC_EEE_LPI_TIMER); - intf->eee.eee_active = ret >= 0; - intf->eee.tx_lpi_enabled = e->tx_lpi_enabled; - bcmasp_eee_enable_set(intf, true); - } - return phy_ethtool_set_eee(dev->phydev, e); } @@ -500,4 +429,5 @@ const struct ethtool_ops bcmasp_ethtool_ops = { .get_strings = bcmasp_get_strings, .get_ethtool_stats = bcmasp_get_ethtool_stats, .get_sset_count = bcmasp_get_sset_count, + .get_ts_info = ethtool_op_get_ts_info, }; diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c index 6ad1366270f7..0d61b8580d72 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c @@ -180,14 +180,14 @@ static struct sk_buff *bcmasp_csum_offload(struct net_device *dev, case htons(ETH_P_IP): header |= PKT_OFFLOAD_HDR_SIZE_2((ip_hdrlen(skb) >> 8) & 0xf); header2 |= PKT_OFFLOAD_HDR2_SIZE_2(ip_hdrlen(skb) & 0xff); - epkt |= PKT_OFFLOAD_EPKT_IP(0) | PKT_OFFLOAD_EPKT_CSUM_L2; + epkt |= PKT_OFFLOAD_EPKT_IP(0); ip_proto = ip_hdr(skb)->protocol; header_cnt += 2; break; case htons(ETH_P_IPV6): header |= PKT_OFFLOAD_HDR_SIZE_2((IP6_HLEN >> 8) & 0xf); header2 |= PKT_OFFLOAD_HDR2_SIZE_2(IP6_HLEN & 0xff); - epkt |= PKT_OFFLOAD_EPKT_IP(1) | PKT_OFFLOAD_EPKT_CSUM_L2; + epkt |= PKT_OFFLOAD_EPKT_IP(1); ip_proto = ipv6_hdr(skb)->nexthdr; header_cnt += 2; break; @@ -198,12 +198,12 @@ static struct sk_buff *bcmasp_csum_offload(struct net_device *dev, switch (ip_proto) { case IPPROTO_TCP: header2 |= PKT_OFFLOAD_HDR2_SIZE_3(tcp_hdrlen(skb)); - epkt |= PKT_OFFLOAD_EPKT_TP(0) | PKT_OFFLOAD_EPKT_CSUM_L3; + epkt |= PKT_OFFLOAD_EPKT_TP(0) | PKT_OFFLOAD_EPKT_CSUM_L4; header_cnt++; break; case IPPROTO_UDP: header2 |= PKT_OFFLOAD_HDR2_SIZE_3(UDP_HLEN); - epkt |= PKT_OFFLOAD_EPKT_TP(1) | PKT_OFFLOAD_EPKT_CSUM_L3; + epkt |= PKT_OFFLOAD_EPKT_TP(1) | PKT_OFFLOAD_EPKT_CSUM_L4; header_cnt++; break; default: @@ -322,6 +322,7 @@ static netdev_tx_t bcmasp_xmit(struct sk_buff *skb, struct net_device *dev) } /* Rewind so we do not have a hole */ spb_index = intf->tx_spb_index; + dev_kfree_skb(skb); return NETDEV_TX_OK; } @@ -364,6 +365,9 @@ static netdev_tx_t bcmasp_xmit(struct sk_buff *skb, struct net_device *dev) intf->tx_spb_index = spb_index; intf->tx_spb_dma_valid = valid; + + skb_tx_timestamp(skb); + bcmasp_intf_tx_write(intf, intf->tx_spb_dma_valid); if (tx_spb_ring_full(intf, MAX_SKB_FRAGS + 1)) @@ -382,6 +386,7 @@ static void bcmasp_netif_start(struct net_device *dev) bcmasp_enable_rx_irq(intf, 1); bcmasp_enable_tx_irq(intf, 1); + bcmasp_enable_phy_irq(intf, 1); phy_start(dev->phydev); } @@ -391,7 +396,9 @@ static void umac_reset(struct bcmasp_intf *intf) umac_wl(intf, 0x0, UMC_CMD); umac_wl(intf, UMC_CMD_SW_RESET, UMC_CMD); usleep_range(10, 100); - umac_wl(intf, 0x0, UMC_CMD); + /* We hold the umac in reset and bring it out of + * reset when phy link is up. + */ } static void umac_set_hw_addr(struct bcmasp_intf *intf, @@ -411,6 +418,8 @@ static void umac_enable_set(struct bcmasp_intf *intf, u32 mask, u32 reg; reg = umac_rl(intf, UMC_CMD); + if (reg & UMC_CMD_SW_RESET) + return; if (enable) reg |= mask; else @@ -429,13 +438,10 @@ static void umac_init(struct bcmasp_intf *intf) umac_wl(intf, 0x800, UMC_FRM_LEN); umac_wl(intf, 0xffff, UMC_PAUSE_CNTRL); umac_wl(intf, 0x800, UMC_RX_MAX_PKT_SZ); - umac_enable_set(intf, UMC_CMD_PROMISC, 1); } -static int bcmasp_tx_poll(struct napi_struct *napi, int budget) +static int bcmasp_tx_reclaim(struct bcmasp_intf *intf) { - struct bcmasp_intf *intf = - container_of(napi, struct bcmasp_intf, tx_napi); struct bcmasp_intf_stats64 *stats = &intf->stats64; struct device *kdev = &intf->parent->pdev->dev; unsigned long read, released = 0; @@ -478,10 +484,16 @@ static int bcmasp_tx_poll(struct napi_struct *napi, int budget) DESC_RING_COUNT); } - /* Ensure all descriptors have been written to DRAM for the hardware - * to see updated contents. - */ - wmb(); + return released; +} + +static int bcmasp_tx_poll(struct napi_struct *napi, int budget) +{ + struct bcmasp_intf *intf = + container_of(napi, struct bcmasp_intf, tx_napi); + int released = 0; + + released = bcmasp_tx_reclaim(intf); napi_complete(&intf->tx_napi); @@ -656,10 +668,21 @@ static void bcmasp_adj_link(struct net_device *dev) UMC_CMD_HD_EN | UMC_CMD_RX_PAUSE_IGNORE | UMC_CMD_TX_PAUSE_IGNORE); reg |= cmd_bits; + if (reg & UMC_CMD_SW_RESET) { + reg &= ~UMC_CMD_SW_RESET; + umac_wl(intf, reg, UMC_CMD); + udelay(2); + reg |= UMC_CMD_TX_EN | UMC_CMD_RX_EN | UMC_CMD_PROMISC; + } umac_wl(intf, reg, UMC_CMD); - intf->eee.eee_active = phy_init_eee(phydev, 0) >= 0; - bcmasp_eee_enable_set(intf, intf->eee.eee_active); + umac_wl(intf, phydev->eee_cfg.tx_lpi_timer, UMC_EEE_LPI_TIMER); + reg = umac_rl(intf, UMC_EEE_CTRL); + if (phydev->enable_tx_lpi) + reg |= EEE_EN; + else + reg &= ~EEE_EN; + umac_wl(intf, reg, UMC_EEE_CTRL); } reg = rgmii_rl(intf, RGMII_OOB_CNTRL); @@ -673,40 +696,78 @@ static void bcmasp_adj_link(struct net_device *dev) phy_print_status(phydev); } -static int bcmasp_init_rx(struct bcmasp_intf *intf) +static int bcmasp_alloc_buffers(struct bcmasp_intf *intf) { struct device *kdev = &intf->parent->pdev->dev; struct page *buffer_pg; - dma_addr_t dma; - void *p; - u32 reg; - int ret; + /* Alloc RX */ intf->rx_buf_order = get_order(RING_BUFFER_SIZE); buffer_pg = alloc_pages(GFP_KERNEL, intf->rx_buf_order); if (!buffer_pg) return -ENOMEM; - dma = dma_map_page(kdev, buffer_pg, 0, RING_BUFFER_SIZE, - DMA_FROM_DEVICE); - if (dma_mapping_error(kdev, dma)) { - __free_pages(buffer_pg, intf->rx_buf_order); - return -ENOMEM; - } intf->rx_ring_cpu = page_to_virt(buffer_pg); - intf->rx_ring_dma = dma; - intf->rx_ring_dma_valid = intf->rx_ring_dma + RING_BUFFER_SIZE - 1; + intf->rx_ring_dma = dma_map_page(kdev, buffer_pg, 0, RING_BUFFER_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(kdev, intf->rx_ring_dma)) + goto free_rx_buffer; + + intf->rx_edpkt_cpu = dma_alloc_coherent(kdev, DESC_RING_SIZE, + &intf->rx_edpkt_dma_addr, GFP_KERNEL); + if (!intf->rx_edpkt_cpu) + goto free_rx_buffer_dma; + + /* Alloc TX */ + intf->tx_spb_cpu = dma_alloc_coherent(kdev, DESC_RING_SIZE, + &intf->tx_spb_dma_addr, GFP_KERNEL); + if (!intf->tx_spb_cpu) + goto free_rx_edpkt_dma; - p = dma_alloc_coherent(kdev, DESC_RING_SIZE, &intf->rx_edpkt_dma_addr, + intf->tx_cbs = kcalloc(DESC_RING_COUNT, sizeof(struct bcmasp_tx_cb), GFP_KERNEL); - if (!p) { - ret = -ENOMEM; - goto free_rx_ring; - } - intf->rx_edpkt_cpu = p; + if (!intf->tx_cbs) + goto free_tx_spb_dma; - netif_napi_add(intf->ndev, &intf->rx_napi, bcmasp_rx_poll); + return 0; + +free_tx_spb_dma: + dma_free_coherent(kdev, DESC_RING_SIZE, intf->tx_spb_cpu, + intf->tx_spb_dma_addr); +free_rx_edpkt_dma: + dma_free_coherent(kdev, DESC_RING_SIZE, intf->rx_edpkt_cpu, + intf->rx_edpkt_dma_addr); +free_rx_buffer_dma: + dma_unmap_page(kdev, intf->rx_ring_dma, RING_BUFFER_SIZE, + DMA_FROM_DEVICE); +free_rx_buffer: + __free_pages(buffer_pg, intf->rx_buf_order); + return -ENOMEM; +} + +static void bcmasp_reclaim_free_buffers(struct bcmasp_intf *intf) +{ + struct device *kdev = &intf->parent->pdev->dev; + + /* RX buffers */ + dma_free_coherent(kdev, DESC_RING_SIZE, intf->rx_edpkt_cpu, + intf->rx_edpkt_dma_addr); + dma_unmap_page(kdev, intf->rx_ring_dma, RING_BUFFER_SIZE, + DMA_FROM_DEVICE); + __free_pages(virt_to_page(intf->rx_ring_cpu), intf->rx_buf_order); + + /* TX buffers */ + dma_free_coherent(kdev, DESC_RING_SIZE, intf->tx_spb_cpu, + intf->tx_spb_dma_addr); + kfree(intf->tx_cbs); +} + +static void bcmasp_init_rx(struct bcmasp_intf *intf) +{ + /* Restart from index 0 */ + intf->rx_ring_dma_valid = intf->rx_ring_dma + RING_BUFFER_SIZE - 1; + intf->rx_edpkt_dma_valid = intf->rx_edpkt_dma_addr + (DESC_RING_SIZE - 1); intf->rx_edpkt_dma_read = intf->rx_edpkt_dma_addr; intf->rx_edpkt_index = 0; @@ -732,63 +793,23 @@ static int bcmasp_init_rx(struct bcmasp_intf *intf) rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr, RX_EDPKT_DMA_WRITE); rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr, RX_EDPKT_DMA_READ); rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr, RX_EDPKT_DMA_BASE); - rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr + (DESC_RING_SIZE - 1), - RX_EDPKT_DMA_END); - rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_addr + (DESC_RING_SIZE - 1), - RX_EDPKT_DMA_VALID); - - reg = UMAC2FB_CFG_DEFAULT_EN | - ((intf->channel + 11) << UMAC2FB_CFG_CHID_SHIFT); - reg |= (0xd << UMAC2FB_CFG_OK_SEND_SHIFT); - umac2fb_wl(intf, reg, UMAC2FB_CFG); + rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_valid, RX_EDPKT_DMA_END); + rx_edpkt_dma_wq(intf, intf->rx_edpkt_dma_valid, RX_EDPKT_DMA_VALID); - return 0; - -free_rx_ring: - dma_unmap_page(kdev, intf->rx_ring_dma, RING_BUFFER_SIZE, - DMA_FROM_DEVICE); - __free_pages(virt_to_page(intf->rx_ring_cpu), intf->rx_buf_order); - - return ret; + umac2fb_wl(intf, UMAC2FB_CFG_DEFAULT_EN | ((intf->channel + 11) << + UMAC2FB_CFG_CHID_SHIFT) | (0xd << UMAC2FB_CFG_OK_SEND_SHIFT), + UMAC2FB_CFG); } -static void bcmasp_reclaim_free_all_rx(struct bcmasp_intf *intf) -{ - struct device *kdev = &intf->parent->pdev->dev; - - dma_free_coherent(kdev, DESC_RING_SIZE, intf->rx_edpkt_cpu, - intf->rx_edpkt_dma_addr); - dma_unmap_page(kdev, intf->rx_ring_dma, RING_BUFFER_SIZE, - DMA_FROM_DEVICE); - __free_pages(virt_to_page(intf->rx_ring_cpu), intf->rx_buf_order); -} -static int bcmasp_init_tx(struct bcmasp_intf *intf) +static void bcmasp_init_tx(struct bcmasp_intf *intf) { - struct device *kdev = &intf->parent->pdev->dev; - void *p; - int ret; - - p = dma_alloc_coherent(kdev, DESC_RING_SIZE, &intf->tx_spb_dma_addr, - GFP_KERNEL); - if (!p) - return -ENOMEM; - - intf->tx_spb_cpu = p; + /* Restart from index 0 */ intf->tx_spb_dma_valid = intf->tx_spb_dma_addr + DESC_RING_SIZE - 1; intf->tx_spb_dma_read = intf->tx_spb_dma_addr; - - intf->tx_cbs = kcalloc(DESC_RING_COUNT, sizeof(struct bcmasp_tx_cb), - GFP_KERNEL); - if (!intf->tx_cbs) { - ret = -ENOMEM; - goto free_tx_spb; - } - intf->tx_spb_index = 0; intf->tx_spb_clean_index = 0; - - netif_napi_add_tx(intf->ndev, &intf->tx_napi, bcmasp_tx_poll); + memset(intf->tx_cbs, 0, sizeof(struct bcmasp_tx_cb) * DESC_RING_COUNT); /* Make sure channels are disabled */ tx_spb_ctrl_wl(intf, 0x0, TX_SPB_CTRL_ENABLE); @@ -797,34 +818,12 @@ static int bcmasp_init_tx(struct bcmasp_intf *intf) /* Tx SPB */ tx_spb_ctrl_wl(intf, ((intf->channel + 8) << TX_SPB_CTRL_XF_BID_SHIFT), TX_SPB_CTRL_XF_CTRL2); - tx_pause_ctrl_wl(intf, (1 << (intf->channel + 8)), TX_PAUSE_MAP_VECTOR); tx_spb_top_wl(intf, 0x1e, TX_SPB_TOP_BLKOUT); - tx_spb_top_wl(intf, 0x0, TX_SPB_TOP_SPRE_BW_CTRL); tx_spb_dma_wq(intf, intf->tx_spb_dma_addr, TX_SPB_DMA_READ); tx_spb_dma_wq(intf, intf->tx_spb_dma_addr, TX_SPB_DMA_BASE); tx_spb_dma_wq(intf, intf->tx_spb_dma_valid, TX_SPB_DMA_END); tx_spb_dma_wq(intf, intf->tx_spb_dma_valid, TX_SPB_DMA_VALID); - - return 0; - -free_tx_spb: - dma_free_coherent(kdev, DESC_RING_SIZE, intf->tx_spb_cpu, - intf->tx_spb_dma_addr); - - return ret; -} - -static void bcmasp_reclaim_free_all_tx(struct bcmasp_intf *intf) -{ - struct device *kdev = &intf->parent->pdev->dev; - - /* Free descriptors */ - dma_free_coherent(kdev, DESC_RING_SIZE, intf->tx_spb_cpu, - intf->tx_spb_dma_addr); - - /* Free cbs */ - kfree(intf->tx_cbs); } static void bcmasp_ephy_enable_set(struct bcmasp_intf *intf, bool enable) @@ -897,6 +896,8 @@ static void bcmasp_netif_deinit(struct net_device *dev) } while (timeout-- > 0); tx_spb_dma_wl(intf, 0x0, TX_SPB_DMA_FIFO_CTRL); + bcmasp_tx_reclaim(intf); + umac_enable_set(intf, UMC_CMD_TX_EN, 0); phy_stop(dev->phydev); @@ -912,12 +913,10 @@ static void bcmasp_netif_deinit(struct net_device *dev) /* Disable interrupts */ bcmasp_enable_tx_irq(intf, 0); bcmasp_enable_rx_irq(intf, 0); + bcmasp_enable_phy_irq(intf, 0); netif_napi_del(&intf->tx_napi); - bcmasp_reclaim_free_all_tx(intf); - netif_napi_del(&intf->rx_napi); - bcmasp_reclaim_free_all_rx(intf); } static int bcmasp_stop(struct net_device *dev) @@ -931,6 +930,8 @@ static int bcmasp_stop(struct net_device *dev) bcmasp_netif_deinit(dev); + bcmasp_reclaim_free_buffers(intf); + phy_disconnect(dev->phydev); /* Disable internal EPHY or external PHY */ @@ -1051,43 +1052,34 @@ static int bcmasp_netif_init(struct net_device *dev, bool phy_connect) goto err_phy_disable; } + if (intf->internal_phy) + dev->phydev->irq = PHY_MAC_INTERRUPT; + /* Indicate that the MAC is responsible for PHY PM */ phydev->mac_managed_pm = true; - } else if (!intf->wolopts) { - ret = phy_resume(dev->phydev); - if (ret) - goto err_phy_disable; + + /* Set phylib's copy of the LPI timer */ + phydev->eee_cfg.tx_lpi_timer = umac_rl(intf, UMC_EEE_LPI_TIMER); } umac_reset(intf); umac_init(intf); - /* Disable the UniMAC RX/TX */ - umac_enable_set(intf, (UMC_CMD_RX_EN | UMC_CMD_TX_EN), 0); - umac_set_hw_addr(intf, dev->dev_addr); intf->old_duplex = -1; intf->old_link = -1; intf->old_pause = -1; - ret = bcmasp_init_tx(intf); - if (ret) - goto err_phy_disconnect; - - /* Turn on asp */ + bcmasp_init_tx(intf); + netif_napi_add_tx(intf->ndev, &intf->tx_napi, bcmasp_tx_poll); bcmasp_enable_tx(intf, 1); - ret = bcmasp_init_rx(intf); - if (ret) - goto err_reclaim_tx; - + bcmasp_init_rx(intf); + netif_napi_add(intf->ndev, &intf->rx_napi, bcmasp_rx_poll); bcmasp_enable_rx(intf, 1); - /* Turn on UniMAC TX/RX */ - umac_enable_set(intf, (UMC_CMD_RX_EN | UMC_CMD_TX_EN), 1); - intf->crc_fwd = !!(umac_rl(intf, UMC_CMD) & UMC_CMD_CRC_FWD); bcmasp_netif_start(dev); @@ -1096,12 +1088,6 @@ static int bcmasp_netif_init(struct net_device *dev, bool phy_connect) return 0; -err_reclaim_tx: - netif_napi_del(&intf->tx_napi); - bcmasp_reclaim_free_all_tx(intf); -err_phy_disconnect: - if (phydev) - phy_disconnect(phydev); err_phy_disable: if (intf->internal_phy) bcmasp_ephy_enable_set(intf, false); @@ -1117,13 +1103,24 @@ static int bcmasp_open(struct net_device *dev) netif_dbg(intf, ifup, dev, "bcmasp open\n"); - ret = clk_prepare_enable(intf->parent->clk); + ret = bcmasp_alloc_buffers(intf); if (ret) return ret; - ret = bcmasp_netif_init(dev, true); + ret = clk_prepare_enable(intf->parent->clk); if (ret) + goto err_free_mem; + + ret = bcmasp_netif_init(dev, true); + if (ret) { clk_disable_unprepare(intf->parent->clk); + goto err_free_mem; + } + + return ret; + +err_free_mem: + bcmasp_reclaim_free_buffers(intf); return ret; } @@ -1186,7 +1183,7 @@ static void bcmasp_map_res(struct bcmasp_priv *priv, struct bcmasp_intf *intf) { /* Per port */ intf->res.umac = priv->base + UMC_OFFSET(intf); - intf->res.umac2fb = priv->base + (priv->hw_info->umac2fb + + intf->res.umac2fb = priv->base + (UMAC2FB_OFFSET + priv->rx_ctrl_offset + (intf->port * 0x4)); intf->res.rgmii = priv->base + RGMII_OFFSET(intf); @@ -1201,7 +1198,6 @@ static void bcmasp_map_res(struct bcmasp_priv *priv, struct bcmasp_intf *intf) intf->rx_edpkt_cfg = priv->base + RX_EDPKT_CFG_OFFSET(intf); } -#define MAX_IRQ_STR_LEN 64 struct bcmasp_intf *bcmasp_interface_create(struct bcmasp_priv *priv, struct device_node *ndev_dn, int i) { @@ -1324,7 +1320,14 @@ static void bcmasp_suspend_to_wol(struct bcmasp_intf *intf) if (intf->wolopts & WAKE_FILTER) bcmasp_netfilt_suspend(intf); - /* UniMAC receive needs to be turned on */ + /* Bring UniMAC out of reset if needed and enable RX */ + reg = umac_rl(intf, UMC_CMD); + if (reg & UMC_CMD_SW_RESET) + reg &= ~UMC_CMD_SW_RESET; + + reg |= UMC_CMD_RX_EN | UMC_CMD_PROMISC; + umac_wl(intf, reg, UMC_CMD); + umac_enable_set(intf, UMC_CMD_RX_EN, 1); if (intf->parent->wol_irq > 0) { @@ -1332,6 +1335,10 @@ static void bcmasp_suspend_to_wol(struct bcmasp_intf *intf) ASP_WAKEUP_INTR2_MASK_CLEAR); } + if (ndev->phydev && ndev->phydev->eee_cfg.eee_enabled && + intf->parent->eee_fixup) + intf->parent->eee_fixup(intf, true); + netif_dbg(intf, wol, ndev, "entered WOL mode\n"); } @@ -1339,7 +1346,6 @@ int bcmasp_interface_suspend(struct bcmasp_intf *intf) { struct device *kdev = &intf->parent->pdev->dev; struct net_device *dev = intf->ndev; - int ret = 0; if (!netif_running(dev)) return 0; @@ -1349,10 +1355,6 @@ int bcmasp_interface_suspend(struct bcmasp_intf *intf) bcmasp_netif_deinit(dev); if (!intf->wolopts) { - ret = phy_suspend(dev->phydev); - if (ret) - goto out; - if (intf->internal_phy) bcmasp_ephy_enable_set(intf, false); else @@ -1369,17 +1371,17 @@ int bcmasp_interface_suspend(struct bcmasp_intf *intf) clk_disable_unprepare(intf->parent->clk); - return ret; - -out: - bcmasp_netif_init(dev, false); - return ret; + return 0; } static void bcmasp_resume_from_wol(struct bcmasp_intf *intf) { u32 reg; + if (intf->ndev->phydev && intf->ndev->phydev->eee_cfg.eee_enabled && + intf->parent->eee_fixup) + intf->parent->eee_fixup(intf, false); + reg = umac_rl(intf, UMC_MPD_CTRL); reg &= ~UMC_MPD_CTRL_MPD_EN; umac_wl(intf, reg, UMC_MPD_CTRL); @@ -1408,9 +1410,6 @@ int bcmasp_interface_resume(struct bcmasp_intf *intf) bcmasp_resume_from_wol(intf); - if (intf->eee.eee_enabled) - bcmasp_eee_enable_set(intf, true); - netif_device_attach(dev); return 0; diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf_defs.h b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf_defs.h index ad742612895f..af7418348e81 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_intf_defs.h +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_intf_defs.h @@ -118,8 +118,7 @@ #define UMC_PSW_MS 0x624 #define UMC_PSW_LS 0x628 -#define UMAC2FB_OFFSET_2_1 0x9f044 -#define UMAC2FB_OFFSET 0x9f03c +#define UMAC2FB_OFFSET 0x9f044 #define UMAC2FB_CFG 0x0 #define UMAC2FB_CFG_OPUT_EN BIT(0) #define UMAC2FB_CFG_VLAN_EN BIT(1) |