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

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

Merge "net: stmmac: add support for v2x over ethernet config"

parents 6a662735 bad01cc0
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -472,16 +472,25 @@ 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;

struct vlan_filter_info {
	u16 vlan_id;
	u32 vlan_offset;
	u32 rx_queue;
};

/* Helpers to program the MAC core */
struct stmmac_ops {
	/* MAC core initialization */
	void (*core_init)(struct mac_device_info *hw, struct net_device *dev);
	/* Enable the MAC RX/TX */
	void (*set_mac)(void __iomem *ioaddr, bool enable);
	/* Enable the VLAN MAC configuration for DMA Queue*/
	void (*set_vlan)(struct vlan_filter_info *vlan, void __iomem *ioaddr);
	/* Enable and verify that the IPC module is supported */
	int (*rx_ipc)(struct mac_device_info *hw);
	/* Enable RX Queues */
@@ -623,6 +632,9 @@ void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
			 unsigned int high, unsigned int low);
void stmmac_set_mac(void __iomem *ioaddr, bool enable);

void stmmac_set_vlan_filter_rx_queue(struct vlan_filter_info *vlan,
				     void __iomem *ioaddr);

void stmmac_dwmac4_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
				unsigned int high, unsigned int low);
void stmmac_dwmac4_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
+265 −8
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;
}
@@ -2341,6 +2354,227 @@ bool qcom_ethqos_ipa_enabled(void)
	return false;
}

static ssize_t ethqos_read_dev_emac(struct file *filp, char __user *buf,
				    size_t count, loff_t *f_pos)
{
	unsigned int len = 0;
	char *temp_buf;
	ssize_t ret_cnt = 0;

	ret_cnt = simple_read_from_buffer(buf, count, f_pos, temp_buf, len);
	return ret_cnt;
}

static ssize_t ethqos_write_dev_emac(struct file *file,
				     const char __user *user_buf,
				     size_t count, loff_t *ppos)
{
	unsigned char in_buf[300] = {0};
	unsigned long ret;
	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;
	unsigned int number;

	if (sizeof(in_buf) < count) {
		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);

	if (ret)
		return -EFAULT;

	strlcpy(vlan_str, in_buf, sizeof(vlan_str));

	ETHQOSINFO("emac string is %s\n", vlan_str);

	if (strnstr(vlan_str, "QOE", sizeof(vlan_str))) {
		ethqos->qoe_vlan.available = true;
		vlan_filter_info.vlan_id = ethqos->qoe_vlan.vlan_id;
		vlan_filter_info.rx_queue = ethqos->qoe_vlan.rx_queue;
		vlan_filter_info.vlan_offset = ethqos->qoe_vlan.vlan_offset;
		priv->hw->mac->set_vlan(&vlan_filter_info, priv->ioaddr);
	}

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

	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;
}

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

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

	if (ethqos->qoe_mode) {
		res = of_property_read_u32(np, "qcom,qoe-queue",
					   &ethqos->qoe_vlan.rx_queue);
		if (res) {
			ETHQOSERR("qoe-queue not in dtsi for qoe_mode %u\n",
				  ethqos->qoe_mode);
			ethqos->qoe_vlan.rx_queue = QMI_TAG_TX_CHANNEL;
		}

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

static const struct file_operations emac_fops = {
	.owner = THIS_MODULE,
	.read = ethqos_read_dev_emac,
	.write = ethqos_write_dev_emac,
};

static int ethqos_create_emac_device_node(dev_t *emac_dev_t,
					  struct cdev **emac_cdev,
					  struct class **emac_class,
					  char *emac_dev_node_name)
{
	int ret;

	ret = alloc_chrdev_region(emac_dev_t, 0, 1,
				  emac_dev_node_name);
	if (ret) {
		ETHQOSERR("alloc_chrdev_region error for node %s\n",
			  emac_dev_node_name);
		goto alloc_chrdev1_region_fail;
	}

	*emac_cdev = cdev_alloc();
	if (!*emac_cdev) {
		ret = -ENOMEM;
		ETHQOSERR("failed to alloc cdev\n");
		goto fail_alloc_cdev;
	}
	cdev_init(*emac_cdev, &emac_fops);

	ret = cdev_add(*emac_cdev, *emac_dev_t, 1);
	if (ret < 0) {
		ETHQOSERR(":cdev_add err=%d\n", -ret);
		goto cdev1_add_fail;
	}

	*emac_class = class_create(THIS_MODULE, emac_dev_node_name);
	if (!*emac_class) {
		ret = -ENODEV;
		ETHQOSERR("failed to create class\n");
		goto fail_create_class;
	}

	if (!device_create(*emac_class, NULL,
			   *emac_dev_t, NULL, emac_dev_node_name)) {
		ret = -EINVAL;
		ETHQOSERR("failed to create device_create\n");
		goto fail_create_device;
	}

	return 0;

fail_create_device:
	class_destroy(*emac_class);
fail_create_class:
	cdev_del(*emac_cdev);
cdev1_add_fail:
fail_alloc_cdev:
	unregister_chrdev_region(*emac_dev_t, 1);
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;
@@ -2351,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"))
@@ -2382,12 +2616,24 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
	ethqos_init_reqgulators(ethqos);
	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)) {
		dev_err(&pdev->dev, "dt configuration failed\n");
		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");
@@ -2566,6 +2812,17 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
		/*Set early eth parameters*/
		ethqos_set_early_eth_param(priv, ethqos);
	}

	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,
					       "emac");
	}
#ifdef CONFIG_ETH_IPA_OFFLOAD
	ethqos->ipa_enabled = true;
	priv->rx_queue[IPA_DMA_RX_CH].skip_sw = true;
+27 −0
Original line number Diff line number Diff line
@@ -398,6 +398,19 @@ 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;
	u32 rx_queue;
	bool available;
};

struct ethqos_emac_por {
	unsigned int offset;
	unsigned int value;
@@ -454,6 +467,10 @@ struct qcom_ethqos {
	struct cdev *avb_class_b_cdev;
	struct class *avb_class_b_class;

	dev_t emac_dev_t;
	struct cdev *emac_cdev;
	struct class *emac_class;

	unsigned long avb_class_a_intr_cnt;
	unsigned long avb_class_b_intr_cnt;
	struct dentry *debugfs_dir;
@@ -503,6 +520,13 @@ struct qcom_ethqos {

	/* IO Macro parameters */
	struct ethqos_io_macro io_macro;

	/* 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 {
@@ -577,6 +601,9 @@ 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
#define CLASS_A_TRAFFIC_UCP 3
#define CLASS_A_TRAFFIC_TX_CHANNEL 3
+18 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#define GMAC_PACKET_FILTER		0x00000008
#define GMAC_HASH_TAB_0_31		0x00000010
#define GMAC_HASH_TAB_32_63		0x00000014
#define GMAC_VLAN_CTRL_TAG		0x00000050
#define GMAC_VLAN_DATA_TAG		0x00000054
#define GMAC_RX_FLOW_CTRL		0x00000090
#define GMAC_QX_TX_FLOW_CTRL(x)		(0x70 + x * 4)
#define GMAC_TXQ_PRTY_MAP0		0x98
@@ -43,6 +45,20 @@
#define GMAC_MDIO_DATA			0x00000204
#define GMAC_ADDR_HIGH(reg)		(0x300 + reg * 8)
#define GMAC_ADDR_LOW(reg)		(0x304 + reg * 8)
#define GMAC_MTL_RX_QMAP		0x00000c30

/*MAC VLAN CTRL Bit*/
#define GMAC_VLANTR_OB_MASK			(0x1)
#define GMAC_VLANTR_CT_MASKBIT			BIT(1)
#define GMAC_VLANTR_OFFSET_SHIFT		2
#define GMAC_VLANTR_VLAN_EN			BIT(16)
#define GMAC_VLANTR_VLAN_CMP			BIT(17)
#define GMAC_VLANTR_VLAN_CMP_DISABLE		BIT(18)
#define GMAC_VLANTR_DMA_CHAN_EN			BIT(24)
#define GMAC_VLANTR_DMA_CHAN_NUM		25

/*MTL Rx Queue Bit*/
#define GMAC_MTL_RXQ_DMACH		BIT(4)

/* RX Queues Routing */
#define GMAC_RXQCTRL_AVCPQ_MASK		GENMASK(2, 0)
@@ -259,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
+2 −0
Original line number Diff line number Diff line
@@ -699,6 +699,7 @@ static void dwmac4_debug(void __iomem *ioaddr, struct stmmac_extra_stats *x,
static const struct stmmac_ops dwmac4_ops = {
	.core_init = dwmac4_core_init,
	.set_mac = stmmac_set_mac,
	.set_vlan = stmmac_set_vlan_filter_rx_queue,
	.rx_ipc = dwmac4_rx_ipc_enable,
	.rx_queue_enable = dwmac4_rx_queue_enable,
	.rx_queue_prio = dwmac4_rx_queue_priority,
@@ -730,6 +731,7 @@ static const struct stmmac_ops dwmac4_ops = {
static const struct stmmac_ops dwmac410_ops = {
	.core_init = dwmac4_core_init,
	.set_mac = stmmac_dwmac4_set_mac,
	.set_vlan = stmmac_set_vlan_filter_rx_queue,
	.rx_ipc = dwmac4_rx_ipc_enable,
	.rx_queue_enable = dwmac4_rx_queue_enable,
	.rx_queue_prio = dwmac4_rx_queue_priority,
Loading