diff mbox

[V2,13/13] brcmfmac: add arp offload ip address table configuration support

Message ID 1449751392-32569-14-git-send-email-arend@broadcom.com (mailing list archive)
State Changes Requested
Delegated to: Kalle Valo
Headers show

Commit Message

Arend van Spriel Dec. 10, 2015, 12:43 p.m. UTC
From: Franky Lin <frankyl@broadcom.com>

Obtain ipv4 address through inetaddr notification for ARP offload host
ip table configuration.

Signed-off-by: Franky Lin <frankyl@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
---
 .../wireless/broadcom/brcm80211/brcmfmac/core.c    | 108 +++++++++++++++++++++
 .../wireless/broadcom/brcm80211/brcmfmac/core.h    |   2 +
 2 files changed, 110 insertions(+)

Comments

Arend van Spriel Dec. 11, 2015, 9:12 a.m. UTC | #1
On 12/10/2015 01:43 PM, Arend van Spriel wrote:
> From: Franky Lin <frankyl@broadcom.com>
>
> Obtain ipv4 address through inetaddr notification for ARP offload host
> ip table configuration.

Turns out this patch has a sparse warning, ie. would not work on 
big-endian system. We have a fix for that. Should I mark this patch as 
dropped in patchwork?

Regards,
Arend

> Signed-off-by: Franky Lin <frankyl@broadcom.com>
> Signed-off-by: Arend van Spriel <arend@broadcom.com>
> ---
>   .../wireless/broadcom/brcm80211/brcmfmac/core.c    | 108 +++++++++++++++++++++
>   .../wireless/broadcom/brcm80211/brcmfmac/core.h    |   2 +
>   2 files changed, 110 insertions(+)
>
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
> index 3a39192..2631f6f 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
> @@ -17,6 +17,7 @@
>   #include <linux/kernel.h>
>   #include <linux/etherdevice.h>
>   #include <linux/module.h>
> +#include <linux/inetdevice.h>
>   #include <net/cfg80211.h>
>   #include <net/rtnetlink.h>
>   #include <brcmu_utils.h>
> @@ -620,6 +621,8 @@ static int brcmf_netdev_stop(struct net_device *ndev)
>
>   	brcmf_cfg80211_down(ndev);
>
> +	brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear", NULL, 0);
> +
>   	brcmf_net_setcarrier(ifp, false);
>
>   	return 0;
> @@ -940,6 +943,98 @@ int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr)
>   	return available ? bsscfgidx : -ENOMEM;
>   }
>
> +#ifdef CONFIG_INET
> +#define ARPOL_MAX_ENTRIES	8
> +static int brcmf_inetaddr_changed(struct notifier_block *nb,
> +				  unsigned long action, void *data)
> +{
> +	struct brcmf_pub *drvr = container_of(nb, struct brcmf_pub,
> +					      inetaddr_notifier);
> +	struct in_ifaddr *ifa = data;
> +	struct net_device *ndev = ifa->ifa_dev->dev;
> +	struct brcmf_if *ifp;
> +	int idx, i, ret;
> +	u32 val;
> +	u32 addr_table[ARPOL_MAX_ENTRIES] = {0};
> +
> +	/* Find out if the notification is meant for us */
> +	for (idx = 0; idx < BRCMF_MAX_IFS; idx++) {
> +		ifp = drvr->iflist[idx];
> +		if (ifp && ifp->ndev == ndev)
> +			break;
> +		if (idx == BRCMF_MAX_IFS - 1)
> +			return NOTIFY_DONE;
> +	}
> +
> +	/* check if arp offload is supported */
> +	ret = brcmf_fil_iovar_int_get(ifp, "arpoe", &val);
> +	if (ret)
> +		return NOTIFY_OK;
> +
> +	/* old version only support primary index */
> +	ret = brcmf_fil_iovar_int_get(ifp, "arp_version", &val);
> +	if (ret)
> +		val = 1;
> +	if (val == 1)
> +		ifp = drvr->iflist[0];
> +
> +	/* retrieve the table from firmware */
> +	ret = brcmf_fil_iovar_data_get(ifp, "arp_hostip", addr_table,
> +				       sizeof(addr_table));
> +	if (ret) {
> +		brcmf_err("fail to get arp ip table err:%d\n", ret);
> +		return NOTIFY_OK;
> +	}
> +
> +	for (i = 0; i < ARPOL_MAX_ENTRIES; i++)
> +		if (ifa->ifa_address == addr_table[i])
> +			break;
> +
> +	switch (action) {
> +	case NETDEV_UP:
> +		if (i == ARPOL_MAX_ENTRIES) {
> +			brcmf_dbg(TRACE, "add %pI4 to arp table\n",
> +				  &ifa->ifa_address);
> +			/* set it directly */
> +			ret = brcmf_fil_iovar_int_set(ifp, "arp_hostip",
> +						      ifa->ifa_address);
> +			if (ret)
> +				brcmf_err("add arp ip err %d\n", ret);
> +		}
> +		break;
> +	case NETDEV_DOWN:
> +		if (i < ARPOL_MAX_ENTRIES) {
> +			addr_table[i] = 0;
> +			brcmf_dbg(TRACE, "remove %pI4 from arp table\n",
> +				  &ifa->ifa_address);
> +			/* clear the table in firmware */
> +			ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear",
> +						       NULL, 0);
> +			if (ret) {
> +				brcmf_err("fail to clear arp ip table err:%d\n",
> +					  ret);
> +				return NOTIFY_OK;
> +			}
> +			for (i = 0; i < ARPOL_MAX_ENTRIES; i++) {
> +				if (addr_table[i] != 0) {
> +					brcmf_fil_iovar_int_set(ifp,
> +								"arp_hostip",
> +								addr_table[i]);
> +					if (ret)
> +						brcmf_err("add arp ip err %d\n",
> +							  ret);
> +				}
> +			}
> +		}
> +		break;
> +	default:
> +		break;
> +	}
> +
> +	return NOTIFY_OK;
> +}
> +#endif
> +
>   int brcmf_attach(struct device *dev)
>   {
>   	struct brcmf_pub *drvr = NULL;
> @@ -1068,6 +1163,15 @@ int brcmf_bus_start(struct device *dev)
>   		if (p2p_ifp)
>   			ret = brcmf_net_p2p_attach(p2p_ifp);
>   	}
> +
> +	if (ret)
> +		goto fail;
> +
> +#ifdef CONFIG_INET
> +	drvr->inetaddr_notifier.notifier_call = brcmf_inetaddr_changed;
> +	ret = register_inetaddr_notifier(&drvr->inetaddr_notifier);
> +#endif
> +
>   fail:
>   	if (ret < 0) {
>   		brcmf_err("failed: %d\n", ret);
> @@ -1133,6 +1237,10 @@ void brcmf_detach(struct device *dev)
>   	if (drvr == NULL)
>   		return;
>
> +#ifdef CONFIG_INET
> +	unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
> +#endif
> +
>   	/* stop firmware event handling */
>   	brcmf_fweh_detach(drvr);
>   	if (drvr->config)
> diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
> index 77d8239..6018af7 100644
> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
> @@ -141,6 +141,8 @@ struct brcmf_pub {
>   #ifdef DEBUG
>   	struct dentry *dbgfs_dir;
>   #endif
> +
> +	struct notifier_block inetaddr_notifier;
>   };
>
>   /* forward declarations */
>

--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Kalle Valo Dec. 11, 2015, 9:29 a.m. UTC | #2
Arend van Spriel <arend@broadcom.com> writes:

> On 12/10/2015 01:43 PM, Arend van Spriel wrote:
>> From: Franky Lin <frankyl@broadcom.com>
>>
>> Obtain ipv4 address through inetaddr notification for ARP offload host
>> ip table configuration.
>
> Turns out this patch has a sparse warning, ie. would not work on
> big-endian system. We have a fix for that. Should I mark this patch as
> dropped in patchwork?

Yeah, that's the best way. For example you could use state "Changes
Requested" and then it automatically gets dropped from my queue.
Arend van Spriel Dec. 11, 2015, 9:42 a.m. UTC | #3
On 12/11/2015 10:29 AM, Kalle Valo wrote:
> Arend van Spriel <arend@broadcom.com> writes:
>
>> On 12/10/2015 01:43 PM, Arend van Spriel wrote:
>>> From: Franky Lin <frankyl@broadcom.com>
>>>
>>> Obtain ipv4 address through inetaddr notification for ARP offload host
>>> ip table configuration.
>>
>> Turns out this patch has a sparse warning, ie. would not work on
>> big-endian system. We have a fix for that. Should I mark this patch as
>> dropped in patchwork?
>
> Yeah, that's the best way. For example you could use state "Changes
> Requested" and then it automatically gets dropped from my queue.

will do that.

Thanks,
Arend


--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
index 3a39192..2631f6f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -17,6 +17,7 @@ 
 #include <linux/kernel.h>
 #include <linux/etherdevice.h>
 #include <linux/module.h>
+#include <linux/inetdevice.h>
 #include <net/cfg80211.h>
 #include <net/rtnetlink.h>
 #include <brcmu_utils.h>
@@ -620,6 +621,8 @@  static int brcmf_netdev_stop(struct net_device *ndev)
 
 	brcmf_cfg80211_down(ndev);
 
+	brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear", NULL, 0);
+
 	brcmf_net_setcarrier(ifp, false);
 
 	return 0;
@@ -940,6 +943,98 @@  int brcmf_get_next_free_bsscfgidx(struct brcmf_pub *drvr)
 	return available ? bsscfgidx : -ENOMEM;
 }
 
+#ifdef CONFIG_INET
+#define ARPOL_MAX_ENTRIES	8
+static int brcmf_inetaddr_changed(struct notifier_block *nb,
+				  unsigned long action, void *data)
+{
+	struct brcmf_pub *drvr = container_of(nb, struct brcmf_pub,
+					      inetaddr_notifier);
+	struct in_ifaddr *ifa = data;
+	struct net_device *ndev = ifa->ifa_dev->dev;
+	struct brcmf_if *ifp;
+	int idx, i, ret;
+	u32 val;
+	u32 addr_table[ARPOL_MAX_ENTRIES] = {0};
+
+	/* Find out if the notification is meant for us */
+	for (idx = 0; idx < BRCMF_MAX_IFS; idx++) {
+		ifp = drvr->iflist[idx];
+		if (ifp && ifp->ndev == ndev)
+			break;
+		if (idx == BRCMF_MAX_IFS - 1)
+			return NOTIFY_DONE;
+	}
+
+	/* check if arp offload is supported */
+	ret = brcmf_fil_iovar_int_get(ifp, "arpoe", &val);
+	if (ret)
+		return NOTIFY_OK;
+
+	/* old version only support primary index */
+	ret = brcmf_fil_iovar_int_get(ifp, "arp_version", &val);
+	if (ret)
+		val = 1;
+	if (val == 1)
+		ifp = drvr->iflist[0];
+
+	/* retrieve the table from firmware */
+	ret = brcmf_fil_iovar_data_get(ifp, "arp_hostip", addr_table,
+				       sizeof(addr_table));
+	if (ret) {
+		brcmf_err("fail to get arp ip table err:%d\n", ret);
+		return NOTIFY_OK;
+	}
+
+	for (i = 0; i < ARPOL_MAX_ENTRIES; i++)
+		if (ifa->ifa_address == addr_table[i])
+			break;
+
+	switch (action) {
+	case NETDEV_UP:
+		if (i == ARPOL_MAX_ENTRIES) {
+			brcmf_dbg(TRACE, "add %pI4 to arp table\n",
+				  &ifa->ifa_address);
+			/* set it directly */
+			ret = brcmf_fil_iovar_int_set(ifp, "arp_hostip",
+						      ifa->ifa_address);
+			if (ret)
+				brcmf_err("add arp ip err %d\n", ret);
+		}
+		break;
+	case NETDEV_DOWN:
+		if (i < ARPOL_MAX_ENTRIES) {
+			addr_table[i] = 0;
+			brcmf_dbg(TRACE, "remove %pI4 from arp table\n",
+				  &ifa->ifa_address);
+			/* clear the table in firmware */
+			ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip_clear",
+						       NULL, 0);
+			if (ret) {
+				brcmf_err("fail to clear arp ip table err:%d\n",
+					  ret);
+				return NOTIFY_OK;
+			}
+			for (i = 0; i < ARPOL_MAX_ENTRIES; i++) {
+				if (addr_table[i] != 0) {
+					brcmf_fil_iovar_int_set(ifp,
+								"arp_hostip",
+								addr_table[i]);
+					if (ret)
+						brcmf_err("add arp ip err %d\n",
+							  ret);
+				}
+			}
+		}
+		break;
+	default:
+		break;
+	}
+
+	return NOTIFY_OK;
+}
+#endif
+
 int brcmf_attach(struct device *dev)
 {
 	struct brcmf_pub *drvr = NULL;
@@ -1068,6 +1163,15 @@  int brcmf_bus_start(struct device *dev)
 		if (p2p_ifp)
 			ret = brcmf_net_p2p_attach(p2p_ifp);
 	}
+
+	if (ret)
+		goto fail;
+
+#ifdef CONFIG_INET
+	drvr->inetaddr_notifier.notifier_call = brcmf_inetaddr_changed;
+	ret = register_inetaddr_notifier(&drvr->inetaddr_notifier);
+#endif
+
 fail:
 	if (ret < 0) {
 		brcmf_err("failed: %d\n", ret);
@@ -1133,6 +1237,10 @@  void brcmf_detach(struct device *dev)
 	if (drvr == NULL)
 		return;
 
+#ifdef CONFIG_INET
+	unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
+#endif
+
 	/* stop firmware event handling */
 	brcmf_fweh_detach(drvr);
 	if (drvr->config)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
index 77d8239..6018af7 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
@@ -141,6 +141,8 @@  struct brcmf_pub {
 #ifdef DEBUG
 	struct dentry *dbgfs_dir;
 #endif
+
+	struct notifier_block inetaddr_notifier;
 };
 
 /* forward declarations */