Loading drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h +14 −6 Original line number Diff line number Diff line Loading @@ -18,9 +18,10 @@ #include <linux/netdevice.h> #include <linux/moduleparam.h> #define ATL_VERSION "1.0.23" #define ATL_VERSION "1.0.25" struct atl_nic; enum atl_fwd_notify; #include "atl_compat.h" #include "atl_hw.h" Loading Loading @@ -210,7 +211,7 @@ struct atl_fwd { unsigned long ring_map[ATL_FWDIR_NUM]; struct atl_fwd_ring *rings[ATL_FWDIR_NUM][ATL_NUM_FWD_RINGS]; unsigned long msi_map; void *private; struct blocking_notifier_head nh_clients; }; struct atl_nic { Loading Loading @@ -255,7 +256,9 @@ enum atl_nic_flags { enum atl_priv_flags { ATL_PF_LPB_SYS_PB, ATL_PF_LPB_SYS_DMA, /* ATL_PF_LPB_NET_DMA, */ ATL_PF_LPB_NET_DMA, ATL_PF_LPB_INT_PHY, ATL_PF_LPB_EXT_PHY, ATL_PF_LPI_RX_MAC, ATL_PF_LPI_TX_MAC, ATL_PF_LPI_RX_PHY, Loading @@ -268,10 +271,13 @@ enum atl_priv_flags { enum atl_priv_flag_bits { ATL_DEF_PF_BIT(LPB_SYS_PB), ATL_DEF_PF_BIT(LPB_SYS_DMA), /* ATL_DEF_PF_BIT(LPB_NET_DMA), */ ATL_DEF_PF_BIT(LPB_NET_DMA), ATL_DEF_PF_BIT(LPB_INT_PHY), ATL_DEF_PF_BIT(LPB_EXT_PHY), ATL_PF_LPB_MASK = ATL_PF_BIT(LPB_SYS_DMA) | ATL_PF_BIT(LPB_SYS_PB) /* | ATL_PF_BIT(LPB_NET_DMA) */, ATL_PF_LPB_MASK = ATL_PF_BIT(LPB_SYS_DMA) | ATL_PF_BIT(LPB_SYS_PB) | ATL_PF_BIT(LPB_NET_DMA) | ATL_PF_BIT(LPB_INT_PHY) | ATL_PF_BIT(LPB_EXT_PHY), ATL_DEF_PF_BIT(LPI_RX_MAC), ATL_DEF_PF_BIT(LPI_TX_MAC), Loading Loading @@ -400,8 +406,10 @@ void atl_adjust_eth_stats(struct atl_ether_stats *stats, struct atl_ether_stats *base, bool add); void atl_fwd_release_rings(struct atl_nic *nic); #ifdef CONFIG_ATLFWD_FWD int atl_fwd_suspend_rings(struct atl_nic *nic); int atl_fwd_resume_rings(struct atl_nic *nic); #else static inline int atl_fwd_suspend_rings(struct atl_nic *nic) { return 0; } static inline int atl_fwd_resume_rings(struct atl_nic *nic) { return 0; } #endif int atl_get_lpi_timer(struct atl_nic *nic, uint32_t *lpi_delay); Loading drivers/net/ethernet/aquantia/atlantic-fwd/atl_ethtool.c +18 −6 Original line number Diff line number Diff line Loading @@ -169,8 +169,10 @@ static int atl_set_fixed_speed(struct atl_hw *hw, unsigned int speed) { struct atl_link_state *lstate = &hw->link_state; struct atl_link_type *type; unsigned long tmp; int i; lstate->advertized &= ~ATL_EEE_MASK; atl_for_each_rate(i, type) if (type->speed == speed) { if (!(lstate->supported & BIT(i))) Loading @@ -180,6 +182,14 @@ static int atl_set_fixed_speed(struct atl_hw *hw, unsigned int speed) break; } if (lstate->eee_enabled) { atl_link_to_kernel(lstate->supported >> ATL_EEE_BIT_OFFT, &tmp, true); /* advertize the supported links */ tmp = atl_kernel_to_link(&tmp, true); lstate->advertized |= tmp << ATL_EEE_BIT_OFFT; } lstate->autoneg = false; hw->mcp.ops->set_link(hw, false); return 0; Loading Loading @@ -207,7 +217,6 @@ do { \ } \ \ lstate->autoneg = true; \ (lstate)->advertized &= ATL_EEE_MASK; \ (lstate)->advertized |= atl_kernel_to_link(advertise, legacy); \ \ fc->req = 0; \ Loading Loading @@ -611,7 +620,9 @@ static const struct atl_stat_desc eth_stat_descs[] = { static const char atl_priv_flags[][ETH_GSTRING_LEN] = { ATL_PRIV_FLAG(PKTSystemLoopback, LPB_SYS_PB), ATL_PRIV_FLAG(DMASystemLoopback, LPB_SYS_DMA), /* ATL_PRIV_FLAG(DMANetworkLoopback, LPB_NET_DMA), */ ATL_PRIV_FLAG(DMANetworkLoopback, LPB_NET_DMA), ATL_PRIV_FLAG(PHYInternalLoopback, LPB_INT_PHY), ATL_PRIV_FLAG(PHYExternalLoopback, LPB_EXT_PHY), ATL_PRIV_FLAG(RX_LPI_MAC, LPI_RX_MAC), ATL_PRIV_FLAG(TX_LPI_MAC, LPI_TX_MAC), ATL_PRIV_FLAG(RX_LPI_PHY, LPI_RX_PHY), Loading Loading @@ -891,13 +902,14 @@ static int atl_set_priv_flags(struct net_device *ndev, uint32_t flags) return -EINVAL; } nic->priv_flags = flags; if (curr) atl_set_loopback(nic, ffs(curr) - 1, false); if (lpb) atl_set_loopback(nic, ffs(lpb) - 1, true); nic->priv_flags = flags; return 0; } Loading Loading @@ -1288,7 +1300,7 @@ static uint32_t atl_rxf_find_vid(struct atl_nic *nic, uint16_t vid, if (!(cmd & ATL_RXF_EN)) { if (free == ATL_RXF_VLAN_MAX) { free = idx; if (vid == -1) if (vid == 0xffff) break; } continue; Loading Loading @@ -1321,7 +1333,7 @@ static uint16_t atl_rxf_vid(struct atl_rxf_vlan *vlan, int idx) { uint32_t cmd = vlan->cmd[idx]; return cmd & ATL_RXF_EN ? cmd & ATL_VLAN_VID_MASK : -1; return cmd & ATL_RXF_EN ? cmd & ATL_VLAN_VID_MASK : 0xffff; } static int atl_rxf_dup_vid(struct atl_rxf_vlan *vlan, int idx, uint16_t vid) Loading Loading @@ -1361,7 +1373,7 @@ static int atl_rxf_set_vlan(const struct atl_rxf_flt_desc *desc, } old_vid = atl_rxf_vid(vlan, idx); if (old_vid != -1 && vid != old_vid && if (old_vid != 0xffff && vid != old_vid && test_bit(old_vid, vlan->map)) { atl_nic_err("Can't overwrite Linux VLAN filter @%d VID %hd with a different VID %hd\n", idx, old_vid, vid); Loading drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c +36 −16 Original line number Diff line number Diff line Loading @@ -205,6 +205,7 @@ static int __atl_fw2_get_link_caps(struct atl_hw *hw) mcp->caps_low = caps[0]; mcp->caps_high = caps[1]; mcp->caps_ex = caps_ex; mcp->wdog_disabled = !(mcp->caps_ex & atl_fw2_ex_caps_mac_heartbeat); atl_dev_dbg("Got link caps: %#x %#x %#x\n", caps[0], caps[1], caps_ex); atl_for_each_rate(i, rate) { Loading Loading @@ -372,7 +373,8 @@ static void atl_fw2_set_default_link(struct atl_hw *hw) atl_fw1_set_default_link(hw); lstate->fc.req = atl_fc_full; lstate->eee_enabled = 1; lstate->eee_enabled = 0; lstate->advertized &= ~ATL_EEE_MASK; } static int atl_fw1_enable_wol(struct atl_hw *hw, unsigned int wol_mode) Loading @@ -385,22 +387,15 @@ static int atl_fw2_enable_wol(struct atl_hw *hw, unsigned int wol_mode) struct offloadInfo *info; struct drvIface *msg = NULL; uint32_t val, wol_bits = 0, req_high = hw->mcp.req_high; uint32_t low_req; uint32_t low_req, wol_ex_flags = 0; atl_lock_fw(hw); if (hw->mcp.caps_ex & atl_fw2_ex_caps_wol_ex) { ret = atl_write_fwsettings_word(hw, atl_fw2_setings_wol_ex, atl_fw2_wol_ex_wake_on_link_keep_rate | atl_fw2_wol_ex_wake_on_magic_keep_rate); if (ret) return ret; } low_req = atl_read(hw, ATL_MCP_SCRATCH(FW2_LINK_REQ_LOW)); if (wol_mode & atl_fw_wake_on_link) { wol_bits |= atl_fw2_wake_on_link; wol_ex_flags |= atl_fw2_wol_ex_wake_on_link_keep_rate; low_req &= ~atl_fw2_wake_on_link_force; } Loading @@ -411,6 +406,7 @@ static int atl_fw2_enable_wol(struct atl_hw *hw, unsigned int wol_mode) if (wol_mode & atl_fw_wake_on_magic) { wol_bits |= atl_fw2_nic_proxy | atl_fw2_wol; wol_ex_flags |= atl_fw2_wol_ex_wake_on_magic_keep_rate; ret = -ENOMEM; msg = kzalloc(sizeof(*msg), GFP_KERNEL); Loading @@ -431,6 +427,13 @@ static int atl_fw2_enable_wol(struct atl_hw *hw, unsigned int wol_mode) } } if (hw->mcp.caps_ex & atl_fw2_ex_caps_wol_ex) { ret = atl_write_fwsettings_word(hw, atl_fw2_setings_wol_ex, wol_ex_flags); if (ret) goto unlock_free; } req_high |= wol_bits; req_high &= ~atl_fw2_link_drop; atl_write(hw, ATL_MCP_SCRATCH(FW2_LINK_REQ_LOW), low_req); Loading Loading @@ -581,6 +584,27 @@ static int atl_fw2_restore_cfg(struct atl_hw *hw) return 0; } static int atl_fw2_set_phy_loopback(struct atl_nic *nic, u32 mode) { bool on = !!(nic->priv_flags & BIT(mode)); struct atl_hw *hw = &nic->hw; atl_lock_fw(hw); switch (mode) { case ATL_PF_LPB_INT_PHY: atl_write_bit(hw, ATL_MCP_SCRATCH(FW2_LINK_REQ_HIGH), 27, on); break; case ATL_PF_LPB_EXT_PHY: atl_write_bit(hw, ATL_MCP_SCRATCH(FW2_LINK_REQ_HIGH), 26, on); break; } atl_unlock_fw(hw); return 0; } static struct atl_fw_ops atl_fw_ops[2] = { [0] = { .__wait_fw_init = __atl_fw1_wait_fw_init, Loading @@ -593,6 +617,7 @@ static struct atl_fw_ops atl_fw_ops[2] = { .get_phy_temperature = (void *)atl_fw1_unsupported, .dump_cfg = atl_fw1_unsupported, .restore_cfg = atl_fw1_unsupported, .set_phy_loopback = (void *)atl_fw1_unsupported, .efuse_shadow_addr_reg = ATL_MCP_SCRATCH(FW1_EFUSE_SHADOW), }, [1] = { Loading @@ -606,6 +631,7 @@ static struct atl_fw_ops atl_fw_ops[2] = { .get_phy_temperature = atl_fw2_get_phy_temperature, .dump_cfg = atl_fw2_dump_cfg, .restore_cfg = atl_fw2_restore_cfg, .set_phy_loopback = atl_fw2_set_phy_loopback, .efuse_shadow_addr_reg = ATL_MCP_SCRATCH(FW2_EFUSE_SHADOW), }, }; Loading Loading @@ -912,12 +938,6 @@ void atl_fw_watchdog(struct atl_hw *hw) goto out; } if (hbeat == 0 && mcp->phy_hbeat == 0) { atl_dev_warn("FW heartbeat stuck at 0, probably not provisioned. Disabling watchdog.\n"); mcp->wdog_disabled = true; goto out; } if (hbeat == mcp->phy_hbeat) { atl_dev_err("FW watchdog: FW hang (PHY heartbeat stuck at %hd), resetting\n", hbeat); set_bit(ATL_ST_RESET_NEEDED, &hw->state); Loading drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.h +2 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ enum atl_fw2_opts { enum atl_fw2_ex_caps { atl_define_bit(atl_fw2_ex_caps_wol_ex, 23) atl_define_bit(atl_fw2_ex_caps_mac_heartbeat, 25) }; enum atl_fw2_wol_ex { Loading Loading @@ -156,6 +157,7 @@ struct atl_fw_ops { int (*get_phy_temperature)(struct atl_hw *hw, int *temp); int (*dump_cfg)(struct atl_hw *hw); int (*restore_cfg)(struct atl_hw *hw); int (*set_phy_loopback)(struct atl_nic *nic, u32 mode); unsigned efuse_shadow_addr_reg; }; Loading drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c +123 −25 Original line number Diff line number Diff line Loading @@ -78,13 +78,16 @@ static void atl_fwd_free_bufs(struct atl_fwd_ring *ring) struct atl_fwd_bufs *bufs = ring->bufs; struct atl_fwd_mem_ops *ops = ring->mem_ops; int ring_size = ring->hw.size; int order = bufs->order; size_t frag_size = bufs->frag_size; int order; size_t frag_size; int i; if (!bufs) return; order = bufs->order; frag_size = bufs->frag_size; if (bufs->daddr_vec) dma_free_coherent(dev, ring_size * sizeof(dma_addr_t), bufs->daddr_vec, bufs->daddr_vec_base); Loading Loading @@ -197,8 +200,10 @@ static int atl_fwd_alloc_bufs(struct atl_fwd_ring *ring, int order) } else bufs->vaddr_vec = atl_fwd_frag_vaddr(frag, ops); if (!(want_dvec || want_vvec)) return 0; for (i = 0; i < ring_size; i++) { union atl_desc *desc = &ring->hw.descs[i]; dma_addr_t daddr = frag->daddr + pg_off; if (want_dvec) Loading @@ -207,13 +212,6 @@ static int atl_fwd_alloc_bufs(struct atl_fwd_ring *ring, int order) bufs->vaddr_vec[i] = atl_fwd_frag_vaddr(frag, ops) + pg_off; if (!(ring->flags & ATL_FWR_DONT_DMA_MAP)) { if (atl_fwd_ring_tx(ring)) desc->tx.daddr = daddr; else desc->rx.daddr = daddr; } pg_off += buf_size; if (pg_off + buf_size <= frag_size) continue; Loading Loading @@ -242,6 +240,50 @@ static void atl_fwd_update_im(struct atl_fwd_ring *ring) (ring->intr_mod_min / 2) << 8 | 2); } static void atl_fwd_init_descr(struct atl_fwd_ring *fwd_ring) { struct atl_hw_ring *ring = &fwd_ring->hw; int dir_tx = atl_fwd_ring_tx(fwd_ring); struct atl_fwd_buf_frag *frag = NULL; int buf_size = fwd_ring->buf_size; int ring_size = ring->size; size_t frag_size = 0; unsigned int pg_off; int i; memset(ring->descs, 0, ring_size * sizeof(*ring->descs)); if (!(fwd_ring->flags & ATL_FWR_ALLOC_BUFS)) return; frag = &fwd_ring->bufs->frags[0]; frag_size = fwd_ring->bufs->frag_size; if (!(fwd_ring->flags & ATL_FWR_DONT_DMA_MAP)) { for (pg_off = 0, i = 0; i < ring_size; i++) { union atl_desc *desc = &ring->descs[i]; dma_addr_t daddr = frag->daddr + pg_off; if (dir_tx) { /* init both daddr and dd for both cases: * daddr for head pointer writeback * dd for the descriptor writeback */ desc->tx.daddr = daddr; desc->tx.dd = 1; } else { desc->rx.daddr = daddr; } pg_off += buf_size; if (pg_off + buf_size <= frag_size) continue; frag++; pg_off = 0; } } } static void atl_fwd_init_ring(struct atl_fwd_ring *fwd_ring) { struct atl_hw *hw = &fwd_ring->nic->hw; Loading @@ -251,6 +293,9 @@ static void atl_fwd_init_ring(struct atl_fwd_ring *fwd_ring) int idx = fwd_ring->idx; int lxo_bit = !!(flags & ATL_FWR_LXO); /* Reinit descriptors as they could be stale after hardware reset */ atl_fwd_init_descr(fwd_ring); atl_write(hw, ATL_RING_BASE_LSW(ring), ring->daddr); atl_write(hw, ATL_RING_BASE_MSW(ring), upper_32_bits(ring->daddr)); Loading Loading @@ -417,7 +462,6 @@ struct atl_fwd_ring *atl_fwd_request_ring(struct net_device *ndev, goto free_ring; } memset(hwring->descs, 0, hwring->size * sizeof(*hwring->descs)); hwring->reg_base = dir_tx ? ATL_TX_RING(idx) : ATL_RX_RING(idx); ret = atl_fwd_alloc_bufs(ring, page_order); Loading Loading @@ -489,12 +533,14 @@ EXPORT_SYMBOL(atl_fwd_set_ring_intr_mod); void atl_fwd_release_rings(struct atl_nic *nic) { struct atl_fwd_ring **rings = nic->fwd.rings[0]; struct atl_fwd_ring *ring; int i; for (i = 0; i < ATL_NUM_FWD_RINGS * 2; i++) if (rings[i]) atl_fwd_release_ring(rings[i]); for (i = 0; i < ATL_NUM_FWD_RINGS * ATL_FWDIR_NUM; i++) { ring = nic->fwd.rings[i % ATL_FWDIR_NUM][i / ATL_FWDIR_NUM]; if (ring) atl_fwd_release_ring(ring); } } int atl_fwd_enable_ring(struct atl_fwd_ring *ring) Loading @@ -502,6 +548,7 @@ int atl_fwd_enable_ring(struct atl_fwd_ring *ring) struct atl_hw *hw = &ring->nic->hw; atl_set_bits(hw, ATL_RING_CTL(&ring->hw), BIT(31)); atl_clear_bits(hw, ATL_RING_CTL(&ring->hw), BIT(30)); ring->state |= ATL_FWR_ST_ENABLED; return 0; Loading @@ -516,6 +563,7 @@ void atl_fwd_disable_ring(struct atl_fwd_ring *ring) return; atl_clear_bits(hw, ATL_RING_CTL(&ring->hw), BIT(31)); atl_set_bits(hw, ATL_RING_CTL(&ring->hw), BIT(30)); ring->state &= ~ATL_FWR_ST_ENABLED; } EXPORT_SYMBOL(atl_fwd_disable_ring); Loading Loading @@ -742,14 +790,39 @@ int atl_fwd_transmit_skb(struct net_device *ndev, struct sk_buff *skb) } EXPORT_SYMBOL(atl_fwd_transmit_skb); int atl_fwd_resume_rings(struct atl_nic *nic) int atl_fwd_register_notifier(struct net_device *ndev, struct notifier_block *n) { struct atl_nic *nic = netdev_priv(ndev); struct atl_fwd *fwd = &nic->fwd; return blocking_notifier_chain_register(&fwd->nh_clients, n); } EXPORT_SYMBOL(atl_fwd_register_notifier); int atl_fwd_unregister_notifier(struct net_device *ndev, struct notifier_block *n) { struct atl_fwd_ring **rings = nic->fwd.rings[0]; struct atl_nic *nic = netdev_priv(ndev); struct atl_fwd *fwd = &nic->fwd; return blocking_notifier_chain_unregister(&fwd->nh_clients, n); } EXPORT_SYMBOL(atl_fwd_unregister_notifier); void atl_fwd_notify(struct atl_nic *nic, enum atl_fwd_notify notif) { blocking_notifier_call_chain(&nic->fwd.nh_clients, notif, NULL); } int atl_fwd_reconfigure_rings(struct atl_nic *nic) { struct atl_fwd_ring *ring; int i; int ret; for (i = 0; i < ATL_NUM_FWD_RINGS * 2; i++) { struct atl_fwd_ring *ring = rings[i]; for (i = 0; i < ATL_NUM_FWD_RINGS * ATL_FWDIR_NUM; i++) { ring = nic->fwd.rings[i % ATL_FWDIR_NUM][i / ATL_FWDIR_NUM]; if (!ring) continue; Loading @@ -767,14 +840,39 @@ int atl_fwd_resume_rings(struct atl_nic *nic) return ret; } } if (ring->state & ATL_FWR_ST_ENABLED) { ret = atl_fwd_enable_ring(ring); if (ret) return ret; } return 0; } int atl_fwd_suspend_rings(struct atl_nic *nic) { atl_fwd_notify(nic, ATL_FWD_NOTIFY_RESET_PREPARE); return 0; } int atl_fwd_resume_rings(struct atl_nic *nic) { struct atl_fwd_ring *ring; int i; int ret; ret = atl_fwd_reconfigure_rings(nic); if (ret) goto err; atl_fwd_notify(nic, ATL_FWD_NOTIFY_RESET_COMPLETE); for (i = 0; i < ATL_NUM_FWD_RINGS * ATL_FWDIR_NUM; i++) { ring = nic->fwd.rings[i % ATL_FWDIR_NUM][i / ATL_FWDIR_NUM]; if (!ring) continue; if ((ring->state & ATL_FWR_ST_ENABLED)) atl_fwd_enable_ring(ring); } err: return ret; } Loading
drivers/net/ethernet/aquantia/atlantic-fwd/atl_common.h +14 −6 Original line number Diff line number Diff line Loading @@ -18,9 +18,10 @@ #include <linux/netdevice.h> #include <linux/moduleparam.h> #define ATL_VERSION "1.0.23" #define ATL_VERSION "1.0.25" struct atl_nic; enum atl_fwd_notify; #include "atl_compat.h" #include "atl_hw.h" Loading Loading @@ -210,7 +211,7 @@ struct atl_fwd { unsigned long ring_map[ATL_FWDIR_NUM]; struct atl_fwd_ring *rings[ATL_FWDIR_NUM][ATL_NUM_FWD_RINGS]; unsigned long msi_map; void *private; struct blocking_notifier_head nh_clients; }; struct atl_nic { Loading Loading @@ -255,7 +256,9 @@ enum atl_nic_flags { enum atl_priv_flags { ATL_PF_LPB_SYS_PB, ATL_PF_LPB_SYS_DMA, /* ATL_PF_LPB_NET_DMA, */ ATL_PF_LPB_NET_DMA, ATL_PF_LPB_INT_PHY, ATL_PF_LPB_EXT_PHY, ATL_PF_LPI_RX_MAC, ATL_PF_LPI_TX_MAC, ATL_PF_LPI_RX_PHY, Loading @@ -268,10 +271,13 @@ enum atl_priv_flags { enum atl_priv_flag_bits { ATL_DEF_PF_BIT(LPB_SYS_PB), ATL_DEF_PF_BIT(LPB_SYS_DMA), /* ATL_DEF_PF_BIT(LPB_NET_DMA), */ ATL_DEF_PF_BIT(LPB_NET_DMA), ATL_DEF_PF_BIT(LPB_INT_PHY), ATL_DEF_PF_BIT(LPB_EXT_PHY), ATL_PF_LPB_MASK = ATL_PF_BIT(LPB_SYS_DMA) | ATL_PF_BIT(LPB_SYS_PB) /* | ATL_PF_BIT(LPB_NET_DMA) */, ATL_PF_LPB_MASK = ATL_PF_BIT(LPB_SYS_DMA) | ATL_PF_BIT(LPB_SYS_PB) | ATL_PF_BIT(LPB_NET_DMA) | ATL_PF_BIT(LPB_INT_PHY) | ATL_PF_BIT(LPB_EXT_PHY), ATL_DEF_PF_BIT(LPI_RX_MAC), ATL_DEF_PF_BIT(LPI_TX_MAC), Loading Loading @@ -400,8 +406,10 @@ void atl_adjust_eth_stats(struct atl_ether_stats *stats, struct atl_ether_stats *base, bool add); void atl_fwd_release_rings(struct atl_nic *nic); #ifdef CONFIG_ATLFWD_FWD int atl_fwd_suspend_rings(struct atl_nic *nic); int atl_fwd_resume_rings(struct atl_nic *nic); #else static inline int atl_fwd_suspend_rings(struct atl_nic *nic) { return 0; } static inline int atl_fwd_resume_rings(struct atl_nic *nic) { return 0; } #endif int atl_get_lpi_timer(struct atl_nic *nic, uint32_t *lpi_delay); Loading
drivers/net/ethernet/aquantia/atlantic-fwd/atl_ethtool.c +18 −6 Original line number Diff line number Diff line Loading @@ -169,8 +169,10 @@ static int atl_set_fixed_speed(struct atl_hw *hw, unsigned int speed) { struct atl_link_state *lstate = &hw->link_state; struct atl_link_type *type; unsigned long tmp; int i; lstate->advertized &= ~ATL_EEE_MASK; atl_for_each_rate(i, type) if (type->speed == speed) { if (!(lstate->supported & BIT(i))) Loading @@ -180,6 +182,14 @@ static int atl_set_fixed_speed(struct atl_hw *hw, unsigned int speed) break; } if (lstate->eee_enabled) { atl_link_to_kernel(lstate->supported >> ATL_EEE_BIT_OFFT, &tmp, true); /* advertize the supported links */ tmp = atl_kernel_to_link(&tmp, true); lstate->advertized |= tmp << ATL_EEE_BIT_OFFT; } lstate->autoneg = false; hw->mcp.ops->set_link(hw, false); return 0; Loading Loading @@ -207,7 +217,6 @@ do { \ } \ \ lstate->autoneg = true; \ (lstate)->advertized &= ATL_EEE_MASK; \ (lstate)->advertized |= atl_kernel_to_link(advertise, legacy); \ \ fc->req = 0; \ Loading Loading @@ -611,7 +620,9 @@ static const struct atl_stat_desc eth_stat_descs[] = { static const char atl_priv_flags[][ETH_GSTRING_LEN] = { ATL_PRIV_FLAG(PKTSystemLoopback, LPB_SYS_PB), ATL_PRIV_FLAG(DMASystemLoopback, LPB_SYS_DMA), /* ATL_PRIV_FLAG(DMANetworkLoopback, LPB_NET_DMA), */ ATL_PRIV_FLAG(DMANetworkLoopback, LPB_NET_DMA), ATL_PRIV_FLAG(PHYInternalLoopback, LPB_INT_PHY), ATL_PRIV_FLAG(PHYExternalLoopback, LPB_EXT_PHY), ATL_PRIV_FLAG(RX_LPI_MAC, LPI_RX_MAC), ATL_PRIV_FLAG(TX_LPI_MAC, LPI_TX_MAC), ATL_PRIV_FLAG(RX_LPI_PHY, LPI_RX_PHY), Loading Loading @@ -891,13 +902,14 @@ static int atl_set_priv_flags(struct net_device *ndev, uint32_t flags) return -EINVAL; } nic->priv_flags = flags; if (curr) atl_set_loopback(nic, ffs(curr) - 1, false); if (lpb) atl_set_loopback(nic, ffs(lpb) - 1, true); nic->priv_flags = flags; return 0; } Loading Loading @@ -1288,7 +1300,7 @@ static uint32_t atl_rxf_find_vid(struct atl_nic *nic, uint16_t vid, if (!(cmd & ATL_RXF_EN)) { if (free == ATL_RXF_VLAN_MAX) { free = idx; if (vid == -1) if (vid == 0xffff) break; } continue; Loading Loading @@ -1321,7 +1333,7 @@ static uint16_t atl_rxf_vid(struct atl_rxf_vlan *vlan, int idx) { uint32_t cmd = vlan->cmd[idx]; return cmd & ATL_RXF_EN ? cmd & ATL_VLAN_VID_MASK : -1; return cmd & ATL_RXF_EN ? cmd & ATL_VLAN_VID_MASK : 0xffff; } static int atl_rxf_dup_vid(struct atl_rxf_vlan *vlan, int idx, uint16_t vid) Loading Loading @@ -1361,7 +1373,7 @@ static int atl_rxf_set_vlan(const struct atl_rxf_flt_desc *desc, } old_vid = atl_rxf_vid(vlan, idx); if (old_vid != -1 && vid != old_vid && if (old_vid != 0xffff && vid != old_vid && test_bit(old_vid, vlan->map)) { atl_nic_err("Can't overwrite Linux VLAN filter @%d VID %hd with a different VID %hd\n", idx, old_vid, vid); Loading
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.c +36 −16 Original line number Diff line number Diff line Loading @@ -205,6 +205,7 @@ static int __atl_fw2_get_link_caps(struct atl_hw *hw) mcp->caps_low = caps[0]; mcp->caps_high = caps[1]; mcp->caps_ex = caps_ex; mcp->wdog_disabled = !(mcp->caps_ex & atl_fw2_ex_caps_mac_heartbeat); atl_dev_dbg("Got link caps: %#x %#x %#x\n", caps[0], caps[1], caps_ex); atl_for_each_rate(i, rate) { Loading Loading @@ -372,7 +373,8 @@ static void atl_fw2_set_default_link(struct atl_hw *hw) atl_fw1_set_default_link(hw); lstate->fc.req = atl_fc_full; lstate->eee_enabled = 1; lstate->eee_enabled = 0; lstate->advertized &= ~ATL_EEE_MASK; } static int atl_fw1_enable_wol(struct atl_hw *hw, unsigned int wol_mode) Loading @@ -385,22 +387,15 @@ static int atl_fw2_enable_wol(struct atl_hw *hw, unsigned int wol_mode) struct offloadInfo *info; struct drvIface *msg = NULL; uint32_t val, wol_bits = 0, req_high = hw->mcp.req_high; uint32_t low_req; uint32_t low_req, wol_ex_flags = 0; atl_lock_fw(hw); if (hw->mcp.caps_ex & atl_fw2_ex_caps_wol_ex) { ret = atl_write_fwsettings_word(hw, atl_fw2_setings_wol_ex, atl_fw2_wol_ex_wake_on_link_keep_rate | atl_fw2_wol_ex_wake_on_magic_keep_rate); if (ret) return ret; } low_req = atl_read(hw, ATL_MCP_SCRATCH(FW2_LINK_REQ_LOW)); if (wol_mode & atl_fw_wake_on_link) { wol_bits |= atl_fw2_wake_on_link; wol_ex_flags |= atl_fw2_wol_ex_wake_on_link_keep_rate; low_req &= ~atl_fw2_wake_on_link_force; } Loading @@ -411,6 +406,7 @@ static int atl_fw2_enable_wol(struct atl_hw *hw, unsigned int wol_mode) if (wol_mode & atl_fw_wake_on_magic) { wol_bits |= atl_fw2_nic_proxy | atl_fw2_wol; wol_ex_flags |= atl_fw2_wol_ex_wake_on_magic_keep_rate; ret = -ENOMEM; msg = kzalloc(sizeof(*msg), GFP_KERNEL); Loading @@ -431,6 +427,13 @@ static int atl_fw2_enable_wol(struct atl_hw *hw, unsigned int wol_mode) } } if (hw->mcp.caps_ex & atl_fw2_ex_caps_wol_ex) { ret = atl_write_fwsettings_word(hw, atl_fw2_setings_wol_ex, wol_ex_flags); if (ret) goto unlock_free; } req_high |= wol_bits; req_high &= ~atl_fw2_link_drop; atl_write(hw, ATL_MCP_SCRATCH(FW2_LINK_REQ_LOW), low_req); Loading Loading @@ -581,6 +584,27 @@ static int atl_fw2_restore_cfg(struct atl_hw *hw) return 0; } static int atl_fw2_set_phy_loopback(struct atl_nic *nic, u32 mode) { bool on = !!(nic->priv_flags & BIT(mode)); struct atl_hw *hw = &nic->hw; atl_lock_fw(hw); switch (mode) { case ATL_PF_LPB_INT_PHY: atl_write_bit(hw, ATL_MCP_SCRATCH(FW2_LINK_REQ_HIGH), 27, on); break; case ATL_PF_LPB_EXT_PHY: atl_write_bit(hw, ATL_MCP_SCRATCH(FW2_LINK_REQ_HIGH), 26, on); break; } atl_unlock_fw(hw); return 0; } static struct atl_fw_ops atl_fw_ops[2] = { [0] = { .__wait_fw_init = __atl_fw1_wait_fw_init, Loading @@ -593,6 +617,7 @@ static struct atl_fw_ops atl_fw_ops[2] = { .get_phy_temperature = (void *)atl_fw1_unsupported, .dump_cfg = atl_fw1_unsupported, .restore_cfg = atl_fw1_unsupported, .set_phy_loopback = (void *)atl_fw1_unsupported, .efuse_shadow_addr_reg = ATL_MCP_SCRATCH(FW1_EFUSE_SHADOW), }, [1] = { Loading @@ -606,6 +631,7 @@ static struct atl_fw_ops atl_fw_ops[2] = { .get_phy_temperature = atl_fw2_get_phy_temperature, .dump_cfg = atl_fw2_dump_cfg, .restore_cfg = atl_fw2_restore_cfg, .set_phy_loopback = atl_fw2_set_phy_loopback, .efuse_shadow_addr_reg = ATL_MCP_SCRATCH(FW2_EFUSE_SHADOW), }, }; Loading Loading @@ -912,12 +938,6 @@ void atl_fw_watchdog(struct atl_hw *hw) goto out; } if (hbeat == 0 && mcp->phy_hbeat == 0) { atl_dev_warn("FW heartbeat stuck at 0, probably not provisioned. Disabling watchdog.\n"); mcp->wdog_disabled = true; goto out; } if (hbeat == mcp->phy_hbeat) { atl_dev_err("FW watchdog: FW hang (PHY heartbeat stuck at %hd), resetting\n", hbeat); set_bit(ATL_ST_RESET_NEEDED, &hw->state); Loading
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fw.h +2 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ enum atl_fw2_opts { enum atl_fw2_ex_caps { atl_define_bit(atl_fw2_ex_caps_wol_ex, 23) atl_define_bit(atl_fw2_ex_caps_mac_heartbeat, 25) }; enum atl_fw2_wol_ex { Loading Loading @@ -156,6 +157,7 @@ struct atl_fw_ops { int (*get_phy_temperature)(struct atl_hw *hw, int *temp); int (*dump_cfg)(struct atl_hw *hw); int (*restore_cfg)(struct atl_hw *hw); int (*set_phy_loopback)(struct atl_nic *nic, u32 mode); unsigned efuse_shadow_addr_reg; }; Loading
drivers/net/ethernet/aquantia/atlantic-fwd/atl_fwd.c +123 −25 Original line number Diff line number Diff line Loading @@ -78,13 +78,16 @@ static void atl_fwd_free_bufs(struct atl_fwd_ring *ring) struct atl_fwd_bufs *bufs = ring->bufs; struct atl_fwd_mem_ops *ops = ring->mem_ops; int ring_size = ring->hw.size; int order = bufs->order; size_t frag_size = bufs->frag_size; int order; size_t frag_size; int i; if (!bufs) return; order = bufs->order; frag_size = bufs->frag_size; if (bufs->daddr_vec) dma_free_coherent(dev, ring_size * sizeof(dma_addr_t), bufs->daddr_vec, bufs->daddr_vec_base); Loading Loading @@ -197,8 +200,10 @@ static int atl_fwd_alloc_bufs(struct atl_fwd_ring *ring, int order) } else bufs->vaddr_vec = atl_fwd_frag_vaddr(frag, ops); if (!(want_dvec || want_vvec)) return 0; for (i = 0; i < ring_size; i++) { union atl_desc *desc = &ring->hw.descs[i]; dma_addr_t daddr = frag->daddr + pg_off; if (want_dvec) Loading @@ -207,13 +212,6 @@ static int atl_fwd_alloc_bufs(struct atl_fwd_ring *ring, int order) bufs->vaddr_vec[i] = atl_fwd_frag_vaddr(frag, ops) + pg_off; if (!(ring->flags & ATL_FWR_DONT_DMA_MAP)) { if (atl_fwd_ring_tx(ring)) desc->tx.daddr = daddr; else desc->rx.daddr = daddr; } pg_off += buf_size; if (pg_off + buf_size <= frag_size) continue; Loading Loading @@ -242,6 +240,50 @@ static void atl_fwd_update_im(struct atl_fwd_ring *ring) (ring->intr_mod_min / 2) << 8 | 2); } static void atl_fwd_init_descr(struct atl_fwd_ring *fwd_ring) { struct atl_hw_ring *ring = &fwd_ring->hw; int dir_tx = atl_fwd_ring_tx(fwd_ring); struct atl_fwd_buf_frag *frag = NULL; int buf_size = fwd_ring->buf_size; int ring_size = ring->size; size_t frag_size = 0; unsigned int pg_off; int i; memset(ring->descs, 0, ring_size * sizeof(*ring->descs)); if (!(fwd_ring->flags & ATL_FWR_ALLOC_BUFS)) return; frag = &fwd_ring->bufs->frags[0]; frag_size = fwd_ring->bufs->frag_size; if (!(fwd_ring->flags & ATL_FWR_DONT_DMA_MAP)) { for (pg_off = 0, i = 0; i < ring_size; i++) { union atl_desc *desc = &ring->descs[i]; dma_addr_t daddr = frag->daddr + pg_off; if (dir_tx) { /* init both daddr and dd for both cases: * daddr for head pointer writeback * dd for the descriptor writeback */ desc->tx.daddr = daddr; desc->tx.dd = 1; } else { desc->rx.daddr = daddr; } pg_off += buf_size; if (pg_off + buf_size <= frag_size) continue; frag++; pg_off = 0; } } } static void atl_fwd_init_ring(struct atl_fwd_ring *fwd_ring) { struct atl_hw *hw = &fwd_ring->nic->hw; Loading @@ -251,6 +293,9 @@ static void atl_fwd_init_ring(struct atl_fwd_ring *fwd_ring) int idx = fwd_ring->idx; int lxo_bit = !!(flags & ATL_FWR_LXO); /* Reinit descriptors as they could be stale after hardware reset */ atl_fwd_init_descr(fwd_ring); atl_write(hw, ATL_RING_BASE_LSW(ring), ring->daddr); atl_write(hw, ATL_RING_BASE_MSW(ring), upper_32_bits(ring->daddr)); Loading Loading @@ -417,7 +462,6 @@ struct atl_fwd_ring *atl_fwd_request_ring(struct net_device *ndev, goto free_ring; } memset(hwring->descs, 0, hwring->size * sizeof(*hwring->descs)); hwring->reg_base = dir_tx ? ATL_TX_RING(idx) : ATL_RX_RING(idx); ret = atl_fwd_alloc_bufs(ring, page_order); Loading Loading @@ -489,12 +533,14 @@ EXPORT_SYMBOL(atl_fwd_set_ring_intr_mod); void atl_fwd_release_rings(struct atl_nic *nic) { struct atl_fwd_ring **rings = nic->fwd.rings[0]; struct atl_fwd_ring *ring; int i; for (i = 0; i < ATL_NUM_FWD_RINGS * 2; i++) if (rings[i]) atl_fwd_release_ring(rings[i]); for (i = 0; i < ATL_NUM_FWD_RINGS * ATL_FWDIR_NUM; i++) { ring = nic->fwd.rings[i % ATL_FWDIR_NUM][i / ATL_FWDIR_NUM]; if (ring) atl_fwd_release_ring(ring); } } int atl_fwd_enable_ring(struct atl_fwd_ring *ring) Loading @@ -502,6 +548,7 @@ int atl_fwd_enable_ring(struct atl_fwd_ring *ring) struct atl_hw *hw = &ring->nic->hw; atl_set_bits(hw, ATL_RING_CTL(&ring->hw), BIT(31)); atl_clear_bits(hw, ATL_RING_CTL(&ring->hw), BIT(30)); ring->state |= ATL_FWR_ST_ENABLED; return 0; Loading @@ -516,6 +563,7 @@ void atl_fwd_disable_ring(struct atl_fwd_ring *ring) return; atl_clear_bits(hw, ATL_RING_CTL(&ring->hw), BIT(31)); atl_set_bits(hw, ATL_RING_CTL(&ring->hw), BIT(30)); ring->state &= ~ATL_FWR_ST_ENABLED; } EXPORT_SYMBOL(atl_fwd_disable_ring); Loading Loading @@ -742,14 +790,39 @@ int atl_fwd_transmit_skb(struct net_device *ndev, struct sk_buff *skb) } EXPORT_SYMBOL(atl_fwd_transmit_skb); int atl_fwd_resume_rings(struct atl_nic *nic) int atl_fwd_register_notifier(struct net_device *ndev, struct notifier_block *n) { struct atl_nic *nic = netdev_priv(ndev); struct atl_fwd *fwd = &nic->fwd; return blocking_notifier_chain_register(&fwd->nh_clients, n); } EXPORT_SYMBOL(atl_fwd_register_notifier); int atl_fwd_unregister_notifier(struct net_device *ndev, struct notifier_block *n) { struct atl_fwd_ring **rings = nic->fwd.rings[0]; struct atl_nic *nic = netdev_priv(ndev); struct atl_fwd *fwd = &nic->fwd; return blocking_notifier_chain_unregister(&fwd->nh_clients, n); } EXPORT_SYMBOL(atl_fwd_unregister_notifier); void atl_fwd_notify(struct atl_nic *nic, enum atl_fwd_notify notif) { blocking_notifier_call_chain(&nic->fwd.nh_clients, notif, NULL); } int atl_fwd_reconfigure_rings(struct atl_nic *nic) { struct atl_fwd_ring *ring; int i; int ret; for (i = 0; i < ATL_NUM_FWD_RINGS * 2; i++) { struct atl_fwd_ring *ring = rings[i]; for (i = 0; i < ATL_NUM_FWD_RINGS * ATL_FWDIR_NUM; i++) { ring = nic->fwd.rings[i % ATL_FWDIR_NUM][i / ATL_FWDIR_NUM]; if (!ring) continue; Loading @@ -767,14 +840,39 @@ int atl_fwd_resume_rings(struct atl_nic *nic) return ret; } } if (ring->state & ATL_FWR_ST_ENABLED) { ret = atl_fwd_enable_ring(ring); if (ret) return ret; } return 0; } int atl_fwd_suspend_rings(struct atl_nic *nic) { atl_fwd_notify(nic, ATL_FWD_NOTIFY_RESET_PREPARE); return 0; } int atl_fwd_resume_rings(struct atl_nic *nic) { struct atl_fwd_ring *ring; int i; int ret; ret = atl_fwd_reconfigure_rings(nic); if (ret) goto err; atl_fwd_notify(nic, ATL_FWD_NOTIFY_RESET_COMPLETE); for (i = 0; i < ATL_NUM_FWD_RINGS * ATL_FWDIR_NUM; i++) { ring = nic->fwd.rings[i % ATL_FWDIR_NUM][i / ATL_FWDIR_NUM]; if (!ring) continue; if ((ring->state & ATL_FWR_ST_ENABLED)) atl_fwd_enable_ring(ring); } err: return ret; }