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

Commit 6f0bd196 authored by Sunil Paidimarri's avatar Sunil Paidimarri Committed by Lakshit Tyagi
Browse files

data-kernel: EMAC: Assign ipv6 ULA address



Read static ipv6 address from flash memory as
part of early ethernet boot up and assign the
same to eth0 interface

Change-Id: I706d4f7f6fc529a12571a5e8a23d6645b23f6392
Signed-off-by: default avatarSunil Paidimarri <hisunil@codeaurora.org>
parent 4f873010
Loading
Loading
Loading
Loading
+16 −37
Original line number Diff line number Diff line
@@ -64,7 +64,6 @@ extern wait_queue_head_t avb_class_b_msg_wq;
#define DEFAULT_START_TIME 0x1900

static INT DWC_ETH_QOS_GSTATUS;
extern struct ip_params pparams;

/* SA(Source Address) operations on TX */
unsigned char mac_addr0[6] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 };
@@ -1835,38 +1834,6 @@ static void DWC_ETH_QOS_default_rx_confs(struct DWC_ETH_QOS_prv_data *pdata)
	DBGPR("<--DWC_ETH_QOS_default_rx_confs\n");
}

int DWC_ETH_QOS_add_ipv6addr(struct ip_params *ip_info, struct net_device *dev)
{
	int res=0;
#ifdef DWC_ETH_QOS_BUILTIN
	struct in6_ifreq ir6;
	char* prefix;

	/*For valid IPv6 address*/

	memset(&ir6, 0, sizeof(ir6));
	if (1 == in6_pton(ip_info->ipv6_addr, -1, (u8*)&ir6.ifr6_addr.s6_addr32, -1, NULL)) {
		EMACDBG( "Setup IPv6 address!\r\n");
		ir6.ifr6_ifindex = dev->ifindex;
		//ir6.ifr6_prefixlen = 0;
		if ((prefix = strchr(ip_info->ipv6_addr, '/')) == NULL)
			ir6.ifr6_prefixlen = 0;
		else {
			ir6.ifr6_prefixlen = simple_strtoul(prefix+1, NULL, 0);
			if (ir6.ifr6_prefixlen > 128)
				ir6.ifr6_prefixlen = 0;
		}
		res = addrconf_add_ifaddr(&init_net, (struct in6_ifreq __user *) &ir6);
		if (res)
			EMACERR( "Can't setup IPv6 address!\r\n");
		else
			EMACDBG("Assigned IPv6 address: %s\r\n", ip_info->ipv6_addr);

	}
#endif
	return res;
}

/*!
 * \brief API to open a device for data transmission & reception.
 *
@@ -1881,7 +1848,6 @@ int DWC_ETH_QOS_add_ipv6addr(struct ip_params *ip_info, struct net_device *dev)
 *
 * \retval 0 on success & negative number on failure.
 */

static int DWC_ETH_QOS_open(struct net_device *dev)
{
	struct DWC_ETH_QOS_prv_data *pdata = netdev_priv(dev);
@@ -1971,9 +1937,6 @@ static int DWC_ETH_QOS_open(struct net_device *dev)
	netif_tx_disable(dev);
#endif /* end of DWC_ETH_QOS_CONFIG_PGTEST */

	//if (pdata->res_data->early_eth_en)
		//DWC_ETH_QOS_add_ipv6addr(&pparams, dev);

	EMACDBG("<--DWC_ETH_QOS_open\n");

	return ret;
@@ -3002,6 +2965,10 @@ static void DWC_ETH_QOS_tx_interrupt(struct net_device *dev,
			pdata->xstats.q_tx_pkt_n[qinx]++;
			pdata->xstats.tx_pkt_n++;
			dev->stats.tx_packets++;
#ifdef DWC_ETH_QOS_BUILTIN
			if (dev->stats.tx_packets == 1)
				EMACINFO("Transmitted First Rx packet\n");
#endif
		}
#else
		if ((hw_if->get_tx_desc_ls(txptr)) && !(hw_if->get_tx_desc_ctxt(txptr))) {
@@ -3089,12 +3056,20 @@ static void DWC_ETH_QOS_receive_skb(struct DWC_ETH_QOS_prv_data *pdata,
				    struct net_device *dev, struct sk_buff *skb,
				    UINT qinx)
{
	static int cnt_ipv4 = 0, cnt_ipv6 = 0;
	struct DWC_ETH_QOS_rx_queue *rx_queue = GET_RX_QUEUE_PTR(qinx);

	skb_record_rx_queue(skb, qinx);
	skb->dev = dev;
	skb->protocol = eth_type_trans(skb, dev);

#ifdef DWC_ETH_QOS_BUILTIN
	if (skb->protocol == htons(ETH_P_IPV6) && (cnt_ipv6++ == 1)) {
		EMACINFO("Received first ipv6 packet\n");
	}
	if (skb->protocol == htons(ETH_P_IP) && (cnt_ipv4++ == 1))
		EMACINFO("Received first ipv4 packet\n");
#endif
	if (dev->features & NETIF_F_GRO) {
		napi_gro_receive(&rx_queue->napi, skb);
	}
@@ -3904,6 +3879,10 @@ static int DWC_ETH_QOS_clean_rx_irq(struct DWC_ETH_QOS_prv_data *pdata,
				/* update the statistics */
				dev->stats.rx_packets++;
				dev->stats.rx_bytes += skb->len;
#ifdef DWC_ETH_QOS_BUILTIN
				if (dev->stats.rx_packets == 1)
					EMACINFO("Received First Rx packet\n");
#endif
				DWC_ETH_QOS_receive_skb(pdata, dev, skb, qinx);
				received++;
			} else {
+96 −12
Original line number Diff line number Diff line
@@ -131,7 +131,7 @@ static int __init set_early_ethernet_ipv4(char *ipv4_addr_in)
		return ret;

	strlcpy(pparams.ipv4_addr_str, ipv4_addr_in, sizeof(pparams.ipv4_addr_str));
	EMACDBG("Early ethernet IPv4 addr assigned: %s\n", pparams.ipv4_addr_str);
	EMACDBG("Early ethernet IPv4 addr: %s\n", pparams.ipv4_addr_str);

	ret = in4_pton(pparams.ipv4_addr_str, -1,
				(u8*)&pparams.ipv4_addr.s_addr, -1, NULL);
@@ -153,9 +153,17 @@ static int __init set_early_ethernet_ipv6(char* ipv6_addr_in)
	if (!ipv6_addr_in)
		return ret;

	strlcpy(pparams.ipv6_addr, ipv6_addr_in, sizeof(pparams.ipv6_addr));
	EMACDBG("Early ethernet IPv6 addr assigned: %s\n", pparams.ipv6_addr);
	strlcpy(pparams.ipv6_addr_str, ipv6_addr_in, sizeof(pparams.ipv6_addr_str));
	EMACDBG("Early ethernet IPv6 addr: %s\n", pparams.ipv6_addr_str);

	ret = in6_pton(pparams.ipv6_addr_str, -1,
				   (u8 *)&pparams.ipv6_addr.ifr6_addr.s6_addr32, -1, NULL);
	if (ret != 1 || pparams.ipv6_addr.ifr6_addr.s6_addr32 == 0)  {
		EMACERR("Invalid ipv6 address programmed: %s\n", ipv6_addr_in);
		return ret;
	}

	pparams.is_valid_ipv6_addr = true;
	return ret;
}
__setup("eipv6=", set_early_ethernet_ipv6);
@@ -1469,27 +1477,93 @@ static struct of_device_id DWC_ETH_QOS_plat_drv_match[] = {
	{}
};

int DWC_ETH_QOS_add_ipaddr(struct ip_params *ip_info, struct net_device *dev)
void is_ipv6_NW_stack_ready(struct work_struct *work)
{
	struct delayed_work *dwork;
	struct DWC_ETH_QOS_prv_data *pdata;
	int ret;

	EMACDBG("\n");
	dwork = container_of(work, struct delayed_work, work);
	pdata = container_of(dwork, struct DWC_ETH_QOS_prv_data, ipv6_addr_assign_wq);

	ret = DWC_ETH_QOS_add_ipv6addr(pdata);
	if (ret)
		return;

	cancel_delayed_work_sync(&pdata->ipv6_addr_assign_wq);
	flush_delayed_work(&pdata->ipv6_addr_assign_wq);
	return;
}

int DWC_ETH_QOS_add_ipv6addr(struct DWC_ETH_QOS_prv_data *pdata)
{
	int ret = -EFAULT;;
#ifdef DWC_ETH_QOS_BUILTIN
	struct in6_ifreq ir6;
	char* prefix;
	struct ip_params *ip_info = &pparams;
	struct net *net = dev_net(pdata->dev);

	EMACDBG("\n");
	if (!net || !net->genl_sock || !net->genl_sock->sk_socket)
		EMACERR("Sock is null, unable to assign ipv6 address\n");

	if (!net->ipv6.devconf_dflt) {
		EMACDBG("ipv6.devconf_dflt is null, schedule wq\n");
		schedule_delayed_work(&pdata->ipv6_addr_assign_wq, msecs_to_jiffies(1000));
		return ret;
	}

	/*For valid IPv6 address*/
	memset(&ir6, 0, sizeof(ir6));
	memcpy(&ir6, &ip_info->ipv6_addr, sizeof(struct in6_ifreq));
	ir6.ifr6_ifindex = pdata->dev->ifindex;

	if ((prefix = strchr(ip_info->ipv6_addr_str, '/')) == NULL)
		ir6.ifr6_prefixlen = 0;
	else {
		ir6.ifr6_prefixlen = simple_strtoul(prefix + 1, NULL, 0);
		if (ir6.ifr6_prefixlen > 128)
			ir6.ifr6_prefixlen = 0;
	}

	ret = inet6_ioctl(net->genl_sock->sk_socket, SIOCSIFADDR, (unsigned long)(void *)&ir6);
	if (ret)
		EMACERR("Can't setup IPv6 address!\r\n");
	else
		EMACDBG("Assigned IPv6 address: %s\r\n", ip_info->ipv6_addr_str);
#endif
	return ret;
}

int DWC_ETH_QOS_add_ipaddr(struct DWC_ETH_QOS_prv_data *pdata)
{
	int res=0;
	int ret=0;
#ifdef DWC_ETH_QOS_BUILTIN
	struct ip_params *ip_info = &pparams;
	struct ifreq ir;
	struct sockaddr_in *sin = (void *) &ir.ifr_ifru.ifru_addr;
	struct net *net = dev_net(pdata->dev);

	if (!net || !net->genl_sock || !net->genl_sock->sk_socket)
		EMACERR("Sock is null, unable to assign ipv4 address\n");

	/*For valid Ipv4 address*/
	memset(&ir, 0, sizeof(ir));
	memcpy(&sin->sin_addr.s_addr, &ip_info->ipv4_addr,
		   sizeof(sin->sin_addr.s_addr));
	strlcpy(ir.ifr_ifrn.ifrn_name, dev->name, sizeof(ir.ifr_ifrn.ifrn_name) + 1);
	strlcpy(ir.ifr_ifrn.ifrn_name, pdata->dev->name, sizeof(ir.ifr_ifrn.ifrn_name) + 1);
	sin->sin_family = AF_INET;
	sin->sin_port = 0;
	res = devinet_ioctl(&init_net, SIOCSIFADDR, (struct ifreq __user *)&ir);
	if (res)
		EMACERR( "Can't setup IPv4 address!: %d\r\n", res);

	ret = inet_ioctl(net->genl_sock->sk_socket, SIOCSIFADDR, (unsigned long)(void *)&ir);
	if (ret)
		EMACERR( "Can't setup IPv4 address!: %d\r\n", ret);
	else
		EMACDBG("Assigned IPv4 address: %s\r\n", ip_info->ipv4_addr_str);
#endif
	return res;
	return ret;
}

static int DWC_ETH_QOS_configure_netdevice(struct platform_device *pdev)
@@ -1749,8 +1823,18 @@ static int DWC_ETH_QOS_configure_netdevice(struct platform_device *pdev)
		queue_work(system_wq, &pdata->qmp_mailbox_work);
	}

	if (pdata->res_data->early_eth_en)
		ret = DWC_ETH_QOS_add_ipaddr(&pparams, dev);
	if (pdata->res_data->early_eth_en) {
		if (pparams.is_valid_ipv4_addr)
			ret = DWC_ETH_QOS_add_ipaddr(pdata);

		if (pparams.is_valid_ipv6_addr) {
			INIT_DELAYED_WORK(&pdata->ipv6_addr_assign_wq, is_ipv6_NW_stack_ready);
			ret = DWC_ETH_QOS_add_ipv6addr(pdata);
			if (ret)
				schedule_delayed_work(&pdata->ipv6_addr_assign_wq, msecs_to_jiffies(1000));
		}

	}

	EMACDBG("<-- DWC_ETH_QOS_configure_netdevice\n");

+7 −4
Original line number Diff line number Diff line
@@ -126,7 +126,8 @@
#include <linux/mailbox_controller.h>
#include <linux/ipc_logging.h>
#include <linux/inetdevice.h>
#include <net/addrconf.h>
#include <net/inet_common.h>
#include <net/ipv6.h>
#include <linux/inet.h>
#include <asm/uaccess.h>

@@ -1868,6 +1869,7 @@ struct DWC_ETH_QOS_prv_data {
	struct cdev* avb_class_b_cdev;
	struct class* avb_class_b_class;

	struct delayed_work ipv6_addr_assign_wq;
};

struct ip_params {
@@ -1878,7 +1880,8 @@ struct ip_params {
	char ipv4_addr_str[32];
	struct in_addr ipv4_addr;
	bool is_valid_ipv4_addr;
	char ipv6_addr[48];
	char ipv6_addr_str[48];
	struct in6_ifreq ipv6_addr;
	bool is_valid_ipv6_addr;
};

@@ -2044,8 +2047,8 @@ irqreturn_t DWC_ETH_QOS_PHY_ISR(int irq, void *dev_id);

void DWC_ETH_QOS_dma_desc_stats_read(struct DWC_ETH_QOS_prv_data *pdata);
void DWC_ETH_QOS_dma_desc_stats_init(struct DWC_ETH_QOS_prv_data *pdata);
int DWC_ETH_QOS_add_ipaddr(struct ip_params *ip_info, struct net_device *dev);
int DWC_ETH_QOS_add_ipv6addr(struct ip_params *ip_info, struct net_device *dev);
int DWC_ETH_QOS_add_ipaddr(struct DWC_ETH_QOS_prv_data *);
int DWC_ETH_QOS_add_ipv6addr(struct DWC_ETH_QOS_prv_data *);

/* For debug prints*/
#define DRV_NAME "qcom-emac-dwc-eqos"