Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a12fe13 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "atlantic forwarding driver v1.0.25"

parents 2abbbf72 44ad1029
Loading
Loading
Loading
Loading
+14 −6
Original line number Diff line number Diff line
@@ -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"
@@ -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 {
@@ -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,
@@ -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),
@@ -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);
+18 −6
Original line number Diff line number Diff line
@@ -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)))
@@ -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;
@@ -207,7 +217,6 @@ do { \
	}								\
									\
	lstate->autoneg = true;						\
	(lstate)->advertized &= ATL_EEE_MASK;				\
	(lstate)->advertized |= atl_kernel_to_link(advertise, legacy);	\
									\
	fc->req = 0;							\
@@ -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),
@@ -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;
}

@@ -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;
@@ -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)
@@ -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);
+36 −16
Original line number Diff line number Diff line
@@ -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) {
@@ -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)
@@ -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;
	}

@@ -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);
@@ -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);
@@ -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,
@@ -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] = {
@@ -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),
	},
};
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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 {
@@ -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;
};

+123 −25
Original line number Diff line number Diff line
@@ -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);
@@ -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)
@@ -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;
@@ -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;
@@ -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));

@@ -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);
@@ -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)
@@ -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;
@@ -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);
@@ -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;
@@ -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