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

Commit 606a02c6 authored by Sunil Paidimarri's avatar Sunil Paidimarri
Browse files

net: stmmac: Configure vlan registers and channels



These are custom changes to configure QMI Over ethernet and bring
up VLAN interface and queue traffic to a particular channel.

Change-Id: I83bfb74875d05eefd7ce9ab595d5e75f7d07e97d
Acked-by: default avatarAbhishek Chauhan <abchauha@qti.qualcomm.com>
Signed-off-by: default avatarSunil Paidimarri <hisunil@codeaurora.org>
parent 8136c468
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -476,12 +476,20 @@ struct stmmac_dma_ops {

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 +631,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,
+161 −0
Original line number Diff line number Diff line
@@ -2341,6 +2341,158 @@ 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 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;
		}
	}

	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 int qcom_ethqos_probe(struct platform_device *pdev)
{
	struct device_node *np = pdev->dev.of_node;
@@ -2382,6 +2534,8 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
	ethqos_init_reqgulators(ethqos);
	ethqos_init_gpio(ethqos);

	ethqos_get_qoe_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");
@@ -2566,6 +2720,13 @@ static int qcom_ethqos_probe(struct platform_device *pdev)
		/*Set early eth parameters*/
		ethqos_set_early_eth_param(priv, ethqos);
	}

	if (ethqos->qoe_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;
+17 −0
Original line number Diff line number Diff line
@@ -398,6 +398,13 @@ enum current_phy_state {
	RGMII_IO_MACRO_CONFIG_RGWR(v);\
} while (0)

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 +461,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 +514,10 @@ 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;
};

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

#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
+16 −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)
+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