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

Commit bad01cc0 authored by Sunil Paidimarri's avatar Sunil Paidimarri
Browse files

net: stmmac: add support for v2x over ethernet config



Add new variables cv2x_mode for new config.
Store MAC address and Vlan id from /dev/emac to driver data.
Select right TX queue for cv2x AP and MDM mode.
Config HW register for cv2x vlan filtering.
Confgi HW register to disable checksum for CV2X queue.

Change-Id: I74b78f12e1277cddaa0fdae017f79c6b3020a36e
Acked-by: default avatarNing Cai <ncai@qti.qualcomm.com>
Signed-off-by: default avatarSunil Paidimarri <hisunil@codeaurora.org>
parent 606a02c6
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -472,6 +472,7 @@ struct stmmac_dma_ops {
	void (*set_rx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
	void (*set_tx_tail_ptr)(void __iomem *ioaddr, u32 tail_ptr, u32 chan);
	void (*enable_tso)(void __iomem *ioaddr, bool en, u32 chan);
	void (*enable_rx_fep)(void __iomem *ioaddr, bool en, u32 chan);
};

struct mac_device_info;
+106 −10
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/rtnetlink.h>
#include <linux/if_vlan.h>

#include "stmmac.h"
#include "stmmac_platform.h"
#include "dwmac-qcom-ethqos.h"
@@ -60,6 +62,7 @@ struct qcom_ethqos *pethqos;
struct stmmac_emb_smmu_cb_ctx stmmac_emb_smmu_ctx = {0};
static unsigned char dev_addr[ETH_ALEN] = {
	0, 0x55, 0x7b, 0xb5, 0x7d, 0xf7};
static unsigned char config_dev_addr[ETH_ALEN] = {0};

void *ipc_stmmac_log_ctxt;
void *ipc_stmmac_log_ctxt_low;
@@ -110,13 +113,28 @@ u16 dwmac_qcom_select_queue(
	select_queue_fallback_t fallback)
{
	u16 txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL;
	unsigned int eth_type, priority;
	unsigned int eth_type, priority, vlan_id;
	bool ipa_enabled = pethqos->ipa_enabled;

	/* Retrieve ETH type */
	eth_type = dwmac_qcom_get_eth_type(skb->data);

	if (eth_type == ETH_P_TSN) {
	if (pethqos->cv2x_mode == CV2X_MODE_AP) {
		if (skb_vlan_tag_present(skb)) {
			vlan_id = skb_vlan_tag_get_id(skb);
			if (vlan_id == pethqos->cv2x_vlan.vlan_id)
				txqueue_select = CV2X_TAG_TX_CHANNEL;
			else if (vlan_id == pethqos->qoe_vlan.vlan_id)
				txqueue_select = QMI_TAG_TX_CHANNEL;
			else
				txqueue_select =
				ALL_OTHER_TX_TRAFFIC_IPA_DISABLED;
		} else {
			txqueue_select = ALL_OTHER_TX_TRAFFIC_IPA_DISABLED;
		}
	} else if (pethqos->cv2x_mode == CV2X_MODE_MDM) {
		txqueue_select = ALL_OTHER_TRAFFIC_TX_CHANNEL;
	} else if (eth_type == ETH_P_TSN) {
		/* Read VLAN priority field from skb->data */
		priority = dwmac_qcom_get_vlan_ucp(skb->data);

@@ -140,11 +158,6 @@ u16 dwmac_qcom_select_queue(
			txqueue_select = ALL_OTHER_TX_TRAFFIC_IPA_DISABLED;
	}

	if (ipa_enabled && txqueue_select == IPA_DMA_TX_CH) {
		ETHQOSERR("TX Channel [%d] is not a valid for SW path\n",
			  txqueue_select);
		WARN_ON(1);
	}
	ETHQOSDBG("tx_queue %d\n", txqueue_select);
	return txqueue_select;
}
@@ -2361,6 +2374,7 @@ static ssize_t ethqos_write_dev_emac(struct file *file,
	struct qcom_ethqos *ethqos = pethqos;
	struct stmmac_priv *priv = qcom_ethqos_get_priv(pethqos);
	struct vlan_filter_info vlan_filter_info;
	char mac_str[30] = {0};
	char vlan_str[30] = {0};
	char *prefix = NULL;
	u32 err;
@@ -2370,7 +2384,6 @@ static ssize_t ethqos_write_dev_emac(struct file *file,
		ETHQOSERR("emac string is too long - count=%u\n", count);
		return -EFAULT;
	}

	memset(in_buf, 0,  sizeof(in_buf));
	ret = copy_from_user(in_buf, user_buf, count);

@@ -2400,6 +2413,45 @@ static ssize_t ethqos_write_dev_emac(struct file *file,
		}
	}

	if (strnstr(vlan_str, "Cv2X", strlen(vlan_str))) {
		ETHQOSDBG("Cv2X supported mode is %u\n", ethqos->cv2x_mode);
		ethqos->cv2x_vlan.available = true;
		vlan_filter_info.vlan_id = ethqos->cv2x_vlan.vlan_id;
		vlan_filter_info.rx_queue = ethqos->cv2x_vlan.rx_queue;
		vlan_filter_info.vlan_offset = ethqos->cv2x_vlan.vlan_offset;
		priv->hw->mac->set_vlan(&vlan_filter_info, priv->ioaddr);
	}

	if (strnstr(vlan_str, "cvlanid=", strlen(vlan_str))) {
		prefix = strnchr(vlan_str, strlen(vlan_str), '=');
		ETHQOSDBG("Cv2X vlanid data written is %s\n", prefix + 1);
		if (prefix) {
			err = kstrtouint(prefix + 1, 0, &number);
			if (!err)
				ethqos->cv2x_vlan.vlan_id = number;
		}
	}

	if (strnstr(in_buf, "cmac_id=", strlen(in_buf))) {
		prefix = strnchr(in_buf, strlen(in_buf), '=');
		if (prefix) {
			memcpy(mac_str, (char *)prefix + 1, 30);

			if (!mac_pton(mac_str, config_dev_addr)) {
				ETHQOSERR("Invalid mac addr in /dev/emac\n");
				return count;
			}

			if (!is_valid_ether_addr(config_dev_addr)) {
				ETHQOSERR("Invalid/Multcast mac addr found\n");
				return count;
			}

			ether_addr_copy(dev_addr, config_dev_addr);
			memcpy(ethqos->cv2x_dev_addr, dev_addr, ETH_ALEN);
		}
	}

	return count;
}

@@ -2493,6 +2545,36 @@ static int ethqos_create_emac_device_node(dev_t *emac_dev_t,
alloc_chrdev1_region_fail:
		return ret;
}

static void ethqos_get_cv2x_dt(struct qcom_ethqos *ethqos,
			       struct device_node *np)
{
	int res;

	res = of_property_read_u32(np, "qcom,cv2x_mode", &ethqos->cv2x_mode);
	if (res) {
		ETHQOSDBG("cv2x_mode not in dtsi\n");
		ethqos->cv2x_mode = CV2X_MODE_DISABLE;
	}

	if (ethqos->cv2x_mode != CV2X_MODE_DISABLE) {
		res = of_property_read_u32(np, "qcom,cv2x-queue",
					   &ethqos->cv2x_vlan.rx_queue);
		if (res) {
			ETHQOSERR("cv2x-queue not in dtsi for cv2x_mode %u\n",
				  ethqos->cv2x_mode);
			ethqos->cv2x_vlan.rx_queue = CV2X_TAG_TX_CHANNEL;
		}

		res = of_property_read_u32(np, "qcom,cv2x-vlan-offset",
					   &ethqos->cv2x_vlan.vlan_offset);
		if (res) {
			ETHQOSERR("cv2x-vlan-offset not in dtsi\n");
			ethqos->cv2x_vlan.vlan_offset = 1;
		}
	}
}

static int qcom_ethqos_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
@@ -2503,7 +2585,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
	struct resource *res;
	struct net_device *ndev;
	struct stmmac_priv *priv;
	int ret;
	int ret, i;

	if (of_device_is_compatible(pdev->dev.of_node,
				    "qcom,emac-smmu-embedded"))
@@ -2535,6 +2617,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
	ethqos_init_gpio(ethqos);

	ethqos_get_qoe_dt(ethqos, np);
	ethqos_get_cv2x_dt(ethqos, np);

	plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
	if (IS_ERR(plat_dat)) {
@@ -2542,6 +2625,15 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
		return PTR_ERR(plat_dat);
	}

	if (ethqos->cv2x_mode == CV2X_MODE_MDM ||
	    ethqos->cv2x_mode == CV2X_MODE_AP) {
		for (i = 0; i < plat_dat->rx_queues_to_use; i++) {
			if (plat_dat->rx_queues_cfg[i].pkt_route ==
			    PACKET_AVCPQ)
				plat_dat->rx_queues_cfg[i].pkt_route = 0;
		}
	}

	if (plat_dat->tx_sched_algorithm == MTL_TX_ALGORITHM_WFQ ||
	    plat_dat->tx_sched_algorithm == MTL_TX_ALGORITHM_DWRR) {
		ETHQOSERR("WFO and DWRR TX Algorithm is not supported\n");
@@ -2721,7 +2813,11 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
		ethqos_set_early_eth_param(priv, ethqos);
	}

	if (ethqos->qoe_mode) {
	if (ethqos->cv2x_mode)
		for (i = 0; i < plat_dat->rx_queues_to_use; i++)
			priv->rx_queue[i].en_fep = true;

	if (ethqos->qoe_mode || ethqos->cv2x_mode) {
		ethqos_create_emac_device_node(&ethqos->emac_dev_t,
					       &ethqos->emac_cdev,
					       &ethqos->emac_class,
+10 −0
Original line number Diff line number Diff line
@@ -398,6 +398,12 @@ enum current_phy_state {
	RGMII_IO_MACRO_CONFIG_RGWR(v);\
} while (0)

enum CV2X_MODE {
	CV2X_MODE_DISABLE = 0x0,
	CV2X_MODE_MDM,
	CV2X_MODE_AP
};

struct ethqos_vlan_info {
	u16 vlan_id;
	u32 vlan_offset;
@@ -518,6 +524,9 @@ struct qcom_ethqos {
	/* QMI over ethernet parameter */
	u32 qoe_mode;
	struct ethqos_vlan_info qoe_vlan;
	u32 cv2x_mode;
	struct ethqos_vlan_info cv2x_vlan;
	unsigned char cv2x_dev_addr[ETH_ALEN];
};

struct pps_cfg {
@@ -592,6 +601,7 @@ u16 dwmac_qcom_select_queue(
#define IPA_DMA_TX_CH 0
#define IPA_DMA_RX_CH 0

#define CV2X_TAG_TX_CHANNEL 3
#define QMI_TAG_TX_CHANNEL 2

#define VLAN_TAG_UCP_SHIFT 13
+2 −0
Original line number Diff line number Diff line
@@ -275,6 +275,8 @@ enum power_event {
#define MTL_OP_MODE_RFA_SHIFT		8

#define MTL_OP_MODE_EHFC		BIT(7)
#define MTL_OP_MODE_FEP			BIT(4)
#define MTL_OP_MODE_FUP			BIT(3)

#define MTL_OP_MODE_RTC_MASK		0x18
#define MTL_OP_MODE_RTC_SHIFT		3
+19 −0
Original line number Diff line number Diff line
@@ -396,6 +396,23 @@ static void dwmac4_enable_tso(void __iomem *ioaddr, bool en, u32 chan)
	}
}

static void dwmac4_dma_rx_chan_fep(void __iomem *ioaddr, bool en, u32 chan)
{
	u32 value;

	if (en) {
		/* enable FEP */
		value = readl_relaxed(ioaddr + MTL_CHAN_RX_OP_MODE(chan));
		writel_relaxed(value | MTL_OP_MODE_FEP,
			       ioaddr + MTL_CHAN_RX_OP_MODE(chan));
	} else {
		/* disable FEP */
		value = readl_relaxed(ioaddr + MTL_CHAN_RX_OP_MODE(chan));
		writel_relaxed(value & ~MTL_OP_MODE_FEP,
			       ioaddr + MTL_CHAN_RX_OP_MODE(chan));
	}
}

const struct stmmac_dma_ops dwmac4_dma_ops = {
	.reset = dwmac4_dma_reset,
	.init = dwmac4_dma_init,
@@ -420,6 +437,7 @@ const struct stmmac_dma_ops dwmac4_dma_ops = {
	.set_rx_tail_ptr = dwmac4_set_rx_tail_ptr,
	.set_tx_tail_ptr = dwmac4_set_tx_tail_ptr,
	.enable_tso = dwmac4_enable_tso,
	.enable_rx_fep = dwmac4_dma_rx_chan_fep,
};

const struct stmmac_dma_ops dwmac410_dma_ops = {
@@ -446,4 +464,5 @@ const struct stmmac_dma_ops dwmac410_dma_ops = {
	.set_rx_tail_ptr = dwmac4_set_rx_tail_ptr,
	.set_tx_tail_ptr = dwmac4_set_tx_tail_ptr,
	.enable_tso = dwmac4_enable_tso,
	.enable_rx_fep = dwmac4_dma_rx_chan_fep,
};
Loading