* [PATCH V5 net-next 3/3] net: cdc_ncm: remove non-standard NCM device IDs
From: Enrico Mioso @ 2013-09-30 4:50 UTC (permalink / raw)
To: Oliver Neukum, Greg Kroah-Hartman, David S. Miller,
Steve Glendinning, Robert de Vries, Hayes Wang, Freddy Xin,
Bjørn Mork, Liu Junliang, open list,
open list:USB NETWORKING DR..., open list:NETWORKING DRIVERS,
ModemManager-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
Cc: Enrico Mioso
In-Reply-To: <1380516609-31242-1-git-send-email-mrkiko.rs-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Remove device IDs of NCM-like (but not NCM-conformant) devices, that are
handled by the huawwei_cdc_ncm driver now.
Signed-off-by: Enrico Mioso <mrkiko.rs-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 62686be..31f43f7 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -1236,17 +1236,6 @@ static const struct usb_device_id cdc_devs[] = {
.driver_info = (unsigned long)&wwan_info,
},
- /* Huawei NCM devices disguised as vendor specific */
- { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x16),
- .driver_info = (unsigned long)&wwan_info,
- },
- { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x46),
- .driver_info = (unsigned long)&wwan_info,
- },
- { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x76),
- .driver_info = (unsigned long)&wwan_info,
- },
^ permalink raw reply related
* [PATCH V5 net-next 2/3] net: huawei_cdc_ncm: Introduce the huawei_cdc_ncm driver
From: Enrico Mioso @ 2013-09-30 4:50 UTC (permalink / raw)
To: Oliver Neukum, Greg Kroah-Hartman, David S. Miller,
Steve Glendinning, Robert de Vries, Hayes Wang, Freddy Xin,
Bjørn Mork, Liu Junliang, open list,
open list:USB NETWORKING DR..., open list:NETWORKING DRIVERS,
ModemManager-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
Cc: Enrico Mioso
In-Reply-To: <1380516609-31242-1-git-send-email-mrkiko.rs-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
This driver supports devices using the NCM protocol as an encapsulation layer
for other protocols, like the E3131 Huawei 3G modem. This drivers approach was
heavily inspired by the qmi_wwan/cdc_mbim approach & code model.
Suggested-by: Bjorn Mork <bjorn-yOkvZcmFvRU@public.gmane.org>
Signed-off-by: Enrico Mioso <mrkiko.rs-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
create mode 100644 drivers/net/usb/huawei_cdc_ncm.c
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 40db312..85e4a01 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -242,6 +242,21 @@ config USB_NET_CDC_NCM
* ST-Ericsson M343 HSPA Mobile Broadband Modem (reference design)
* Ericsson F5521gw Mobile Broadband Module
+config USB_NET_HUAWEI_CDC_NCM
+ tristate "Huawei NCM embedded AT channel support"
+ depends on USB_USBNET
+ select USB_WDM
+ select USB_NET_CDC_NCM
+ help
+ This driver supports huawei-style NCM devices, that use NCM as a
+ transport for other protocols, usually an embedded AT channel.
+ Good examples are:
+ * Huawei E3131
+ * Huawei E3251
+
+ To compile this driver as a module, choose M here: the module will be
+ called huawei_cdc_ncm.ko.
+
config USB_NET_CDC_MBIM
tristate "CDC MBIM support"
depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 8b342cf..b17b5e8 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_USB_IPHETH) += ipheth.o
obj-$(CONFIG_USB_SIERRA_NET) += sierra_net.o
obj-$(CONFIG_USB_NET_CX82310_ETH) += cx82310_eth.o
obj-$(CONFIG_USB_NET_CDC_NCM) += cdc_ncm.o
+obj-$(CONFIG_USB_NET_HUAWEI_CDC_NCM) += huawei_cdc_ncm.o
obj-$(CONFIG_USB_VL600) += lg-vl600.o
obj-$(CONFIG_USB_NET_QMI_WWAN) += qmi_wwan.o
obj-$(CONFIG_USB_NET_CDC_MBIM) += cdc_mbim.o
diff --git a/drivers/net/usb/huawei_cdc_ncm.c b/drivers/net/usb/huawei_cdc_ncm.c
new file mode 100644
index 0000000..ff07b18
--- /dev/null
+++ b/drivers/net/usb/huawei_cdc_ncm.c
@@ -0,0 +1,228 @@
+/* huawei_cdc_ncm.c - handles Huawei devices using the CDC NCM protocol as
+ * transport layer.
+ * Copyright (C) 2013 Enrico Mioso <mrkiko.rs-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ *
+ *
+ * ABSTRACT:
+ * This driver handles devices resembling the CDC NCM standard, but
+ * encapsulating another protocol inside it. An example are some Huawei 3G
+ * devices, exposing an embedded AT channel where you can set up the NCM
+ * connection.
+ * This code has been heavily inspired by the cdc_mbim.c driver, which is
+ * Copyright (c) 2012 Smith Micro Software, Inc.
+ * Copyright (c) 2012 Bjørn Mork <bjorn-yOkvZcmFvRU@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/usbnet.h>
+#include <linux/usb/cdc-wdm.h>
+#include <linux/usb/cdc_ncm.h>
+
+/* Driver data */
+struct huawei_cdc_ncm_state {
+ struct cdc_ncm_ctx *ctx;
+ atomic_t pmcount;
+ struct usb_driver *subdriver;
+ struct usb_interface *control;
+ struct usb_interface *data;
+};
+
+static int huawei_cdc_ncm_manage_power(struct usbnet *usbnet_dev, int on)
+{
+ struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
+ int rv = 0;
+
+ if ((on && atomic_add_return(1, &drvstate->pmcount) == 1) ||
+ (!on && atomic_dec_and_test(&drvstate->pmcount))) {
+ rv = usb_autopm_get_interface(usbnet_dev->intf);
+ if (rv < 0)
+ goto err;
+ usbnet_dev->intf->needs_remote_wakeup = on;
+ usb_autopm_put_interface(usbnet_dev->intf);
+ }
+err:
+ return rv;
+}
+
+static int huawei_cdc_ncm_wdm_manage_power(struct usb_interface *intf, int status)
+{
+ struct usbnet *usbnet_dev = usb_get_intfdata(intf);
+
+ /* can be called while disconnecting */
+ if (!usbnet_dev)
+ return 0;
+
+ return huawei_cdc_ncm_manage_power(usbnet_dev, status);
+}
+
+
+static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev, struct usb_interface *intf)
+{
+ struct cdc_ncm_ctx *ctx;
+ struct usb_driver *subdriver = ERR_PTR(-ENODEV);
+ int ret = -ENODEV;
+ struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
+
+ /* altsetting should always be 1 for NCM devices - so we hard-coded
+ * it here
+ */
+ ret = cdc_ncm_bind_common(usbnet_dev, intf, 1);
+ if (ret)
+ goto err;
+
+ ctx = drvstate->ctx;
+
+ if (usbnet_dev->status)
+ /* CDC-WMC r1.1 requires wMaxCommand to be "at least 256
+ * decimal (0x100)"
+ */
+ subdriver = usb_cdc_wdm_register(ctx->control,
+ &usbnet_dev->status->desc,
+ 256, /* wMaxCommand */
+ huawei_cdc_ncm_wdm_manage_power);
+ if (IS_ERR(subdriver)) {
+ ret = PTR_ERR(subdriver);
+ cdc_ncm_unbind(usbnet_dev, intf);
+ goto err;
+ }
+
+ /* Prevent usbnet from using the status descriptor */
+ usbnet_dev->status = NULL;
+
+ drvstate->subdriver = subdriver;
+
+err:
+ return ret;
+}
+
+static void huawei_cdc_ncm_unbind(struct usbnet *usbnet_dev, struct usb_interface *intf)
+{
+ struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
+ struct cdc_ncm_ctx *ctx = drvstate->ctx;
+
+ if (drvstate->subdriver && drvstate->subdriver->disconnect)
+ drvstate->subdriver->disconnect(ctx->control);
+ drvstate->subdriver = NULL;
+
+ cdc_ncm_unbind(usbnet_dev, intf);
+}
+
+static int huawei_cdc_ncm_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ int ret = 0;
+ struct usbnet *usbnet_dev = usb_get_intfdata(intf);
+ struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
+ struct cdc_ncm_ctx *ctx = drvstate->ctx;
+
+ if (ctx == NULL) {
+ ret = -1;
+ goto error;
+ }
+
+ ret = usbnet_suspend(intf, message);
+ if (ret < 0)
+ goto error;
+
+ if (intf == ctx->control &&
+ drvstate->subdriver &&
+ drvstate->subdriver->suspend)
+ ret = drvstate->subdriver->suspend(intf, message);
+ if (ret < 0)
+ usbnet_resume(intf);
+
+error:
+ return ret;
+}
+
+static int huawei_cdc_ncm_resume(struct usb_interface *intf)
+{
+ int ret = 0;
+ struct usbnet *usbnet_dev = usb_get_intfdata(intf);
+ struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
+ bool callsub;
+ struct cdc_ncm_ctx *ctx = drvstate->ctx;
+
+ /* should we call subdriver's resume function? */
+ callsub =
+ (intf == ctx->control &&
+ drvstate->subdriver &&
+ drvstate->subdriver->resume);
+
+ if (callsub)
+ ret = drvstate->subdriver->resume(intf);
+ if (ret < 0)
+ goto err;
+ ret = usbnet_resume(intf);
+ if (ret < 0 && callsub && drvstate->subdriver->suspend)
+ drvstate->subdriver->suspend(intf, PMSG_SUSPEND);
+err:
+ return ret;
+}
+
+static int huawei_cdc_ncm_check_connect(struct usbnet *usbnet_dev)
+{
+ struct cdc_ncm_ctx *ctx;
+
+ ctx = (struct cdc_ncm_ctx *)usbnet_dev->data[0];
+
+ if (ctx == NULL)
+ return 1; /* disconnected */
+
+ return !ctx->connected;
+}
+
+static const struct driver_info huawei_cdc_ncm_info = {
+ .description = "Huawei CDC NCM device",
+ .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN,
+ .bind = huawei_cdc_ncm_bind,
+ .unbind = huawei_cdc_ncm_unbind,
+ .check_connect = huawei_cdc_ncm_check_connect,
+ .manage_power = huawei_cdc_ncm_manage_power,
+ .rx_fixup = cdc_ncm_rx_fixup,
+ .tx_fixup = cdc_ncm_tx_fixup,
+};
+
+static const struct usb_device_id huawei_cdc_ncm_devs[] = {
+ /* Huawei NCM devices disguised as vendor specific */
+ { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x16),
+ .driver_info = (unsigned long)&huawei_cdc_ncm_info,
+ },
+ { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x46),
+ .driver_info = (unsigned long)&huawei_cdc_ncm_info,
+ },
+ { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, 0xff, 0x02, 0x76),
+ .driver_info = (unsigned long)&huawei_cdc_ncm_info,
+ },
+
+ /* Terminating entry */
+ {
+ },
+};
+MODULE_DEVICE_TABLE(usb, huawei_cdc_ncm_devs);
+
+static struct usb_driver huawei_cdc_ncm_driver = {
+ .name = "huawei_cdc_ncm",
+ .id_table = huawei_cdc_ncm_devs,
+ .probe = usbnet_probe,
+ .disconnect = usbnet_disconnect,
+ .suspend = huawei_cdc_ncm_suspend,
+ .resume = huawei_cdc_ncm_resume,
+ .reset_resume = huawei_cdc_ncm_resume,
+ .supports_autosuspend = 1,
+ .disable_hub_initiated_lpm = 1,
+};
+module_usb_driver(huawei_cdc_ncm_driver);
+MODULE_AUTHOR("Enrico Mioso <mrkiko.rs-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>");
+MODULE_DESCRIPTION("USB CDC NCM host driver with encapsulated protocol support");
+MODULE_LICENSE("GPL");
--
1.8.4
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [PATCH V5 net-next 1/3] net: cdc_ncm: Export cdc_ncm_{tx,rx}_fixup functions for re-use
From: Enrico Mioso @ 2013-09-30 4:50 UTC (permalink / raw)
To: Oliver Neukum, Greg Kroah-Hartman, David S. Miller,
Steve Glendinning, Robert de Vries, Hayes Wang, Freddy Xin,
Bjørn Mork, Liu Junliang, open list,
open list:USB NETWORKING DR..., open list:NETWORKING DRIVERS,
ModemManager-devel
Cc: Enrico Mioso
In-Reply-To: <1380516609-31242-1-git-send-email-mrkiko.rs@gmail.com>
Some drivers implementing NCM-like protocols, may re-use those functions, as is
the case in the huawei_cdc_ncm driver.
Export them via EXPORT_SYMBOL_GPL, in accordance with how other functions have
been exported.
Signed-off-by: Enrico Mioso <mrkiko.rs@gmail.com>
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index 43afde8..62686be 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -858,7 +858,7 @@ static void cdc_ncm_txpath_bh(unsigned long param)
}
}
-static struct sk_buff *
+struct sk_buff *
cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
struct sk_buff *skb_out;
@@ -885,6 +885,7 @@ error:
return NULL;
}
+EXPORT_SYMBOL_GPL(cdc_ncm_tx_fixup);
/* verify NTB header and return offset of first NDP, or negative error */
int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in)
@@ -965,7 +966,7 @@ error:
}
EXPORT_SYMBOL_GPL(cdc_ncm_rx_verify_ndp16);
-static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
+int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
{
struct sk_buff *skb;
struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
@@ -1040,6 +1041,7 @@ err_ndp:
error:
return 0;
}
+EXPORT_SYMBOL_GPL(cdc_ncm_rx_fixup);
static void
cdc_ncm_speed_change(struct cdc_ncm_ctx *ctx,
diff --git a/include/linux/usb/cdc_ncm.h b/include/linux/usb/cdc_ncm.h
index cc25b70..163244b 100644
--- a/include/linux/usb/cdc_ncm.h
+++ b/include/linux/usb/cdc_ncm.h
@@ -133,3 +133,6 @@ extern void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf);
extern struct sk_buff *cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb, __le32 sign);
extern int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in);
extern int cdc_ncm_rx_verify_ndp16(struct sk_buff *skb_in, int ndpoffset);
+struct sk_buff *
+cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags);
+int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in);
--
1.8.4
^ permalink raw reply related
* [PATCH V5 net-next 0/3] The huawei_cdc_ncm driver
From: Enrico Mioso @ 2013-09-30 4:50 UTC (permalink / raw)
To: Oliver Neukum, Greg Kroah-Hartman, David S. Miller,
Steve Glendinning, Robert de Vries, Hayes Wang, Freddy Xin,
Bjørn Mork, Liu Junliang, open list,
open list:USB NETWORKING DR..., open list:NETWORKING DRIVERS,
ModemManager-devel
Cc: Enrico Mioso
So this is a new, revised, edition of the huawei_cdc_ncm.c driver, which
supports devices resembling the NCM standard, but using it also as a mean
to encapsulate other protocols, as is the case for the Huawei E3131 and
E3251 modem devices.
Some precisations are needed however - and I encourage discussion on this: and
that's why I'm sending this message with a broader CC.
Merging those patches might change:
- the way Modem Manager interacts with those devices
- some regressions might be possible if there are some unknown firmware
variants around (Franko?)
First of all: I observed the behaviours of two devices.
Huawei E3131: this device doesn't accept NDIS setup requests unless they're
sent via the embedded AT channel exposed by this driver.
So actually we gain funcionality in this case!
The second case, is the Huawei E3251: which works with standard NCM driver,
still exposing an AT embedded channel. Whith this patch set applied, you gain
some funcionality, loosing the ability to catch standard NCM events for now.
The device will work in both ways with no problems, but this has to be
acknowledged and discussed. Might be we can develop this driver further to
change this, when more devices are tested.
We where thinking Huawei changed their interfaces on new devices - but probably
this driver only works around a nice firmware bug present in E3131, which
prevented the modem from being used in NDIS mode.
I think committing this is definitely wortth-while, since it will allow for
more Huawei devices to be used without serial connection. Some devices like the
E3251 also, reports some status information only via the embedded AT channel,
at least in my case.
Note: I'm not subscribed to any list except the Modem Manager's one, so please
CC me, thanks!!
Enrico Mioso (3):
net: cdc_ncm: Export cdc_ncm_{tx,rx}_fixup functions for re-use
net: huawei_cdc_ncm: Introduce the huawei_cdc_ncm driver
net: cdc_ncm: remove non-standard NCM device IDs
drivers/net/usb/Kconfig | 15 +++
drivers/net/usb/Makefile | 1 +
drivers/net/usb/cdc_ncm.c | 17 +--
drivers/net/usb/huawei_cdc_ncm.c | 228 +++++++++++++++++++++++++++++++++++++++
include/linux/usb/cdc_ncm.h | 3 +
5 files changed, 251 insertions(+), 13 deletions(-)
create mode 100644 drivers/net/usb/huawei_cdc_ncm.c
--
1.8.4
^ permalink raw reply
* Re: [PATCH v3] bgmac: add support for Byte Queue Limits
From: Eric Dumazet @ 2013-09-30 4:34 UTC (permalink / raw)
To: Hauke Mehrtens; +Cc: davem, zajec5, netdev
In-Reply-To: <1380455698-5897-1-git-send-email-hauke@hauke-m.de>
On Sun, 2013-09-29 at 13:54 +0200, Hauke Mehrtens wrote:
> This makes it possible to use some more advanced queuing
> techniques with this driver.
>
> When multi queue support will be added some changes to Byte Queue
> handling is needed.
>
> Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
> ---
Reviewed-by: Eric Dumazet <edumazet@google.com>
^ permalink raw reply
* [PATCH 2/3] net: ethernet: cpsw-phy-sel: Remove redundant of_match_ptr
From: Sachin Kamat @ 2013-09-30 4:25 UTC (permalink / raw)
To: netdev; +Cc: davem, sachin.kamat
In-Reply-To: <1380515114-2823-1-git-send-email-sachin.kamat@linaro.org>
The data structure of_match_ptr() protects is always compiled in.
Hence of_match_ptr() is not needed.
Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
---
drivers/net/ethernet/ti/cpsw-phy-sel.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/ti/cpsw-phy-sel.c b/drivers/net/ethernet/ti/cpsw-phy-sel.c
index e092ede..148da9a 100644
--- a/drivers/net/ethernet/ti/cpsw-phy-sel.c
+++ b/drivers/net/ethernet/ti/cpsw-phy-sel.c
@@ -152,7 +152,7 @@ static struct platform_driver cpsw_phy_sel_driver = {
.driver = {
.name = "cpsw-phy-sel",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(cpsw_phy_sel_id_table),
+ .of_match_table = cpsw_phy_sel_id_table,
},
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH 1/3] net: ethernet: cpsw: Remove redundant of_match_ptr
From: Sachin Kamat @ 2013-09-30 4:25 UTC (permalink / raw)
To: netdev; +Cc: davem, sachin.kamat
The data structure of_match_ptr() protects is always compiled in.
Hence of_match_ptr() is not needed.
Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
---
drivers/net/ethernet/ti/cpsw.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 5efb37b..7290f11 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -2217,7 +2217,7 @@ static struct platform_driver cpsw_driver = {
.name = "cpsw",
.owner = THIS_MODULE,
.pm = &cpsw_pm_ops,
- .of_match_table = of_match_ptr(cpsw_of_mtable),
+ .of_match_table = cpsw_of_mtable,
},
.probe = cpsw_probe,
.remove = cpsw_remove,
--
1.7.9.5
^ permalink raw reply related
* [PATCH 3/3] net: can: c_can_platform: Remove redundant of_match_ptr
From: Sachin Kamat @ 2013-09-30 4:25 UTC (permalink / raw)
To: netdev; +Cc: davem, sachin.kamat, Marc Kleine-Budde, linux-can
In-Reply-To: <1380515114-2823-1-git-send-email-sachin.kamat@linaro.org>
The data structure of_match_ptr() protects is always compiled in.
Hence of_match_ptr() is not needed.
Signed-off-by: Sachin Kamat <sachin.kamat@linaro.org>
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: linux-can@vger.kernel.org
---
drivers/net/can/c_can/c_can_platform.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/can/c_can/c_can_platform.c b/drivers/net/can/c_can/c_can_platform.c
index 294ced3..d66ac26 100644
--- a/drivers/net/can/c_can/c_can_platform.c
+++ b/drivers/net/can/c_can/c_can_platform.c
@@ -322,7 +322,7 @@ static struct platform_driver c_can_plat_driver = {
.driver = {
.name = KBUILD_MODNAME,
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(c_can_of_table),
+ .of_match_table = c_can_of_table,
},
.probe = c_can_plat_probe,
.remove = c_can_plat_remove,
--
1.7.9.5
^ permalink raw reply related
* [PATCH] drivers: net: phy: marvell.c: removed checkpatch.pl warnings
From: Avinash kumar @ 2013-09-30 4:06 UTC (permalink / raw)
To: davem; +Cc: michal.simek, lars, RHoover, netdev, Avinash kumar
removes following warnings-
drivers/net/phy/marvell.c:37: WARNING: Use #include <linux/io.h> instead of <asm/io.h>
drivers/net/phy/marvell.c:39: WARNING: Use #include <linux/uaccess.h> instead of <asm/uaccess.h>
Signed-off-by: Avinash Kumar <avi.kp.137@gmail.com>
---
drivers/net/phy/marvell.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 2e91477..2e3c778e 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -34,9 +34,9 @@
#include <linux/marvell_phy.h>
#include <linux/of.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#define MII_MARVELL_PHY_PAGE 22
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH 1/1] linux-firmware: Add Brocade FC/FCOE Adapter firmware files
From: Ben Hutchings @ 2013-09-30 3:57 UTC (permalink / raw)
To: Rasesh Mody; +Cc: dwmw2, netdev, linux-scsi
In-Reply-To: <1378854654-11398-1-git-send-email-rmody@brocade.com>
[-- Attachment #1: Type: text/plain, Size: 708 bytes --]
On Tue, 2013-09-10 at 16:10 -0700, Rasesh Mody wrote:
> This patch adds firmware files for Brocade HBA and CNA drivers(BFA and BNA).
>
> Signed-off-by: Rasesh Mody <rmody@brocade.com>
> ---
> WHENCE | 27 +++++++++++++++++++++++++++
> cbfw-3.2.1.1.bin | Bin 0 -> 412528 bytes
> ct2fw-3.2.1.1.bin | Bin 0 -> 582440 bytes
> ctfw-3.2.1.1.bin | Bin 0 -> 537160 bytes
> 4 files changed, 27 insertions(+)
> create mode 100644 cbfw-3.2.1.1.bin
> create mode 100644 ct2fw-3.2.1.1.bin
> create mode 100644 ctfw-3.2.1.1.bin
[...]
Applied, thanks. Sorry for the delay.
Ben.
--
Ben Hutchings
Life is like a sewer:
what you get out of it depends on what you put into it.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]
^ permalink raw reply
* Re: [PATCH net-next] virtio-net: switch to use XPS to choose txq
From: Jason Wang @ 2013-09-30 3:20 UTC (permalink / raw)
To: Rusty Russell, netdev, linux-kernel, virtualization; +Cc: Michael S. Tsirkin
In-Reply-To: <874n932obk.fsf@rustcorp.com.au>
On 09/30/2013 07:35 AM, Rusty Russell wrote:
> Jason Wang <jasowang@redhat.com> writes:
>> We used to use a percpu structure vq_index to record the cpu to queue
>> mapping, this is suboptimal since it duplicates the work of XPS and
>> loses all other XPS functionality such as allowing use to configure
>> their own transmission steering strategy.
>>
>> So this patch switches to use XPS and suggest a default mapping when
>> the number of cpus is equal to the number of queues. With XPS support,
>> there's no need for keeping per-cpu vq_index and .ndo_select_queue(),
>> so they were removed also.
>>
>> Cc: Rusty Russell <rusty@rustcorp.com.au>
>> Cc: Michael S. Tsirkin <mst@redhat.com>
>> Signed-off-by: Jason Wang <jasowang@redhat.com>
>> ---
>> drivers/net/virtio_net.c | 55 +++++++--------------------------------------
>> 1 files changed, 9 insertions(+), 46 deletions(-)
>>
>> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
>> index defec2b..4102c1b 100644
>> --- a/drivers/net/virtio_net.c
>> +++ b/drivers/net/virtio_net.c
>> @@ -127,9 +127,6 @@ struct virtnet_info {
>> /* Does the affinity hint is set for virtqueues? */
>> bool affinity_hint_set;
>>
>> - /* Per-cpu variable to show the mapping from CPU to virtqueue */
>> - int __percpu *vq_index;
>> -
>> /* CPU hot plug notifier */
>> struct notifier_block nb;
>> };
>> @@ -1063,7 +1060,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
>> static void virtnet_clean_affinity(struct virtnet_info *vi, long hcpu)
>> {
>> int i;
>> - int cpu;
>>
>> if (vi->affinity_hint_set) {
>> for (i = 0; i < vi->max_queue_pairs; i++) {
>> @@ -1073,20 +1069,11 @@ static void virtnet_clean_affinity(struct virtnet_info *vi, long hcpu)
>>
>> vi->affinity_hint_set = false;
>> }
>> -
>> - i = 0;
>> - for_each_online_cpu(cpu) {
>> - if (cpu == hcpu) {
>> - *per_cpu_ptr(vi->vq_index, cpu) = -1;
>> - } else {
>> - *per_cpu_ptr(vi->vq_index, cpu) =
>> - ++i % vi->curr_queue_pairs;
>> - }
>> - }
>> }
>>
>> static void virtnet_set_affinity(struct virtnet_info *vi)
>> {
>> + cpumask_var_t cpumask;
>> int i;
>> int cpu;
>>
>> @@ -1100,15 +1087,21 @@ static void virtnet_set_affinity(struct virtnet_info *vi)
>> return;
>> }
>>
>> + if (!alloc_cpumask_var(&cpumask, GFP_KERNEL))
>> + return;
>> +
>> i = 0;
>> for_each_online_cpu(cpu) {
>> virtqueue_set_affinity(vi->rq[i].vq, cpu);
>> virtqueue_set_affinity(vi->sq[i].vq, cpu);
>> - *per_cpu_ptr(vi->vq_index, cpu) = i;
>> + cpumask_clear(cpumask);
>> + cpumask_set_cpu(cpu, cpumask);
>> + netif_set_xps_queue(vi->dev, cpumask, i);
>> i++;
>> }
>>
>> vi->affinity_hint_set = true;
>> + free_cpumask_var(cpumask);
>> }
> Um, isn't this just cpumask_of(cpu)?
True, I thought it should be somewhat more easier.
Will post V2.
>
> Cheers,
> Rusty.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: [PATCH v5] IPv6 NAT: Do not drop DNATed 6to4/6rd packets
From: catab @ 2013-09-30 3:05 UTC (permalink / raw)
To: David Miller; +Cc: hannes, netdev, yoshfuji, joe
In-Reply-To: <20130928.155750.1130089685321379918.davem@davemloft.net>
On Sat, 28 Sep 2013, David Miller wrote:
> From: Hannes Frederic Sowa <hannes@stressinduktion.org>
> Date: Tue, 24 Sep 2013 23:36:06 +0200
>
>> On Mon, Sep 23, 2013 at 11:04:19PM +0300, Catalin(ux) M. BOIE wrote:
>>> When a router is doing DNAT for 6to4/6rd packets the latest anti-spoofing
>>> patch (218774dc) will drop them because the IPv6 address embedded
>>> does not match the IPv4 destination. This patch will allow them to
>>> pass by testing if we have an address that matches on 6to4/6rd interface.
>>> I have been hit by this problem using Fedora and IPV6TO4_IPV4ADDR.
>>> Also, log the dropped packets (with rate limit).
>>>
>>> Signed-off-by: Catalin(ux) M. BOIE <catab@embedromix.ro>
>>
>> Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
>
> Applied, but Catalin please strictly refer to changes in the following
> precise format:
>
> commit $SHA1_ID ("Commit message header line text")
>
> Because SHA1_IDs are ambiguous, especially when the change in question
> is backported into various -stable branches.
>
> The only way to resolve the ambiguity is to provide the commit message
> text (in parenthesis and double quotes).
Roger.
Should I resubmit it?
Should I send it also to 'stable'?
Thank you.
--
Catalin(ux) M. BOIE
http://kernel.embedromix.ro/
^ permalink raw reply
* Re: [PATCH v2.40 4/7] ofp-actions: Add separate OpenFlow 1.3 action parser
From: Ben Pfaff @ 2013-09-30 2:19 UTC (permalink / raw)
To: Simon Horman
Cc: dev-yBygre7rU0TnMu66kgdUjQ, Ravi K, netdev-u79uwXL29TY76Z2rM5mHXA,
Isaku Yamahata
In-Reply-To: <20130930021246.GC4768-/R6kz+dDXgpPR4JQBCEnsQ@public.gmane.org>
On Mon, Sep 30, 2013 at 11:12:49AM +0900, Simon Horman wrote:
> I have written an incremental patch to implement your suggestion
> and it seems that a helper function is not necessary.
>
> For reference the incremental change that I currently have is as follows.
> It is a bit noisy but seems clean to me.
A quick glance through the incremental shows that we are on the same
page. Thanks!
^ permalink raw reply
* Re: [PATCH v2.40 4/7] ofp-actions: Add separate OpenFlow 1.3 action parser
From: Simon Horman @ 2013-09-30 2:12 UTC (permalink / raw)
To: Ben Pfaff
Cc: dev-yBygre7rU0TnMu66kgdUjQ, Ravi K, netdev-u79uwXL29TY76Z2rM5mHXA,
Isaku Yamahata
In-Reply-To: <20130927194119.GC17506-l0M0P4e3n4LQT0dZR+AlfA@public.gmane.org>
On Fri, Sep 27, 2013 at 12:41:19PM -0700, Ben Pfaff wrote:
> On Fri, Sep 27, 2013 at 09:18:33AM +0900, Simon Horman wrote:
> > From: Joe Stringer <joe-Q1GJJQv1iO6lP80pJB477g@public.gmane.org>
> >
> > This patch adds new ofpact_from_openflow13() and
> > ofpacts_from_openflow13() functions parallel to the existing ofpact
> > handling code. In the OpenFlow 1.3 version, push_mpls is handled
> > differently, but all other actions are handled by the existing code.
> >
> > For push_mpls, ofpact_push_mpls.ofpact.compat is set to
> > OFPUTIL_OFPAT13_PUSH_MPLS, which allows correct VLAN+MPLS datapath
> > behaviour to be determined at odp translation time.
> >
> > Signed-off-by: Joe Stringer <joe-Q1GJJQv1iO6lP80pJB477g@public.gmane.org>
> > Signed-off-by: Simon Horman <horms-/R6kz+dDXgpPR4JQBCEnsQ@public.gmane.org>
>
> I am nervous about this idea of having ofpacts_pull_openflow11_actions()
> and ofpacts_pull_openflow11_instructions() try to figure out what
> version of OpenFlow is involved. It is a new and somewhat surprising
> requirements that the callers provide not just actions or instructions
> but a complete OpenFlow message. I see that the callers in ovs-ofctl.c
> don't satisfy this requirement.
Thanks, sorry for overlooking that.
I believe that Joe was worried about this at the time he implemented
this patch but for some reason I was not.
> I think that it would be better to make these functions' callers say
> what version of OpenFlow they are working with. One could provide a
> helper function like get_version_from_ofpbuf(), which should probably go
> in ofp-util.c, but I would want it to fail (assert-fail or segfault or
> whatever) if there is no L2 header pointer, instead of returning a
> default value (that, in this case anyway, we know must be wrong because
> OF1.0 never contains OF1.1+ actions or instructions).
I have written an incremental patch to implement your suggestion
and it seems that a helper function is not necessary.
For reference the incremental change that I currently have is as follows.
It is a bit noisy but seems clean to me.
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 0c4a98b..e94f189 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -1119,22 +1119,14 @@ get_actions_from_instruction(const struct ofp11_instruction *inst,
*n_actions = (ntohs(inst->len) - sizeof *inst) / OFP11_INSTRUCTION_ALIGN;
}
-static uint8_t
-get_version_from_ofpbuf(const struct ofpbuf *openflow)
-{
- if (openflow && openflow->l2) {
- struct ofp_header *oh = openflow->l2;
- return oh->version;
- }
-
- return OFP10_VERSION;
-}
-
-/* Attempts to convert 'actions_len' bytes of OpenFlow 1.1 actions from the
+/* Attempts to convert 'actions_len' bytes of OpenFlow actions from the
* front of 'openflow' into ofpacts. On success, replaces any existing content
* in 'ofpacts' by the converted ofpacts; on failure, clears 'ofpacts'.
* Returns 0 if successful, otherwise an OpenFlow error.
*
+ * Actions are processed according to their OpenFlow version which
+ * is provided in the 'version' parameter.
+ *
* In most places in OpenFlow 1.1 and 1.2, actions appear encapsulated in
* instructions, so you should call ofpacts_pull_openflow11_instructions()
* instead of this function.
@@ -1146,22 +1138,27 @@ get_version_from_ofpbuf(const struct ofpbuf *openflow)
* valid in a specific context. */
enum ofperr
ofpacts_pull_openflow11_actions(struct ofpbuf *openflow,
+ enum ofp_version version,
unsigned int actions_len,
struct ofpbuf *ofpacts)
{
- uint8_t version = get_version_from_ofpbuf(openflow);
-
- if (version < OFP13_VERSION) {
+ switch (version) {
+ case OFP10_VERSION:
+ case OFP11_VERSION:
+ case OFP12_VERSION:
return ofpacts_pull_actions(openflow, actions_len, ofpacts,
ofpacts_from_openflow11);
- } else {
+ case OFP13_VERSION:
return ofpacts_pull_actions(openflow, actions_len, ofpacts,
ofpacts_from_openflow13);
+ default:
+ NOT_REACHED();
}
}
enum ofperr
ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
+ enum ofp_version version,
unsigned int instructions_len,
struct ofpbuf *ofpacts)
{
@@ -1209,7 +1206,6 @@ ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
if (insts[OVSINST_OFPIT11_APPLY_ACTIONS]) {
const union ofp_action *actions;
size_t n_actions;
- uint8_t version = get_version_from_ofpbuf(openflow);
get_actions_from_instruction(insts[OVSINST_OFPIT11_APPLY_ACTIONS],
&actions, &n_actions);
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index 2184489..d67fc3f 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -511,9 +511,11 @@ enum ofperr ofpacts_pull_openflow10(struct ofpbuf *openflow,
unsigned int actions_len,
struct ofpbuf *ofpacts);
enum ofperr ofpacts_pull_openflow11_actions(struct ofpbuf *openflow,
+ enum ofp_version version,
unsigned int actions_len,
struct ofpbuf *ofpacts);
enum ofperr ofpacts_pull_openflow11_instructions(struct ofpbuf *openflow,
+ enum ofp_version version,
unsigned int instructions_len,
struct ofpbuf *ofpacts);
enum ofperr ofpacts_check(const struct ofpact[], size_t ofpacts_len,
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 6fe1cee..a0615b5 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -2224,7 +2224,7 @@ ofp_print_group_desc(struct ds *s, const struct ofp_header *oh)
struct ofputil_group_desc gd;
int retval;
- retval = ofputil_decode_group_desc_reply(&gd, &b);
+ retval = ofputil_decode_group_desc_reply(&gd, &b, oh->version);
if (retval) {
if (retval != EOF) {
ds_put_cstr(s, " ***parse error***");
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 173b534..570447a 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -1504,7 +1504,8 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
return error;
}
- error = ofpacts_pull_openflow11_instructions(&b, b.size, ofpacts);
+ error = ofpacts_pull_openflow11_instructions(&b, oh->version,
+ b.size, ofpacts);
if (error) {
return error;
}
@@ -2360,7 +2361,8 @@ ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *fs,
return EINVAL;
}
- if (ofpacts_pull_openflow11_instructions(msg, length - sizeof *ofs -
+ if (ofpacts_pull_openflow11_instructions(msg, oh->version,
+ length - sizeof *ofs -
padded_match_len, ofpacts)) {
VLOG_WARN_RL(&bad_ofmsg_rl, "OFPST_FLOW reply bad instructions");
return EINVAL;
@@ -3092,7 +3094,8 @@ ofputil_decode_packet_out(struct ofputil_packet_out *po,
return error;
}
- error = ofpacts_pull_openflow11_actions(&b, ntohs(opo->actions_len),
+ error = ofpacts_pull_openflow11_actions(&b, oh->version,
+ ntohs(opo->actions_len),
ofpacts);
if (error) {
return error;
@@ -5674,8 +5677,8 @@ ofputil_append_group_desc_reply(const struct ofputil_group_desc *gds,
}
static enum ofperr
-ofputil_pull_buckets(struct ofpbuf *msg, size_t buckets_length,
- struct list *buckets)
+ofputil_pull_buckets(struct ofpbuf *msg, enum ofp_version version,
+ size_t buckets_length, struct list *buckets)
{
struct ofp11_bucket *ob;
@@ -5708,8 +5711,8 @@ ofputil_pull_buckets(struct ofpbuf *msg, size_t buckets_length,
buckets_length -= ob_len;
ofpbuf_init(&ofpacts, 0);
- error = ofpacts_pull_openflow11_actions(msg, ob_len - sizeof *ob,
- &ofpacts);
+ error = ofpacts_pull_openflow11_actions(msg, version,
+ ob_len - sizeof *ob, &ofpacts);
if (error) {
ofpbuf_uninit(&ofpacts);
ofputil_bucket_list_destroy(buckets);
@@ -5745,7 +5748,7 @@ ofputil_pull_buckets(struct ofpbuf *msg, size_t buckets_length,
* otherwise a positive errno value. */
int
ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd,
- struct ofpbuf *msg)
+ struct ofpbuf *msg, enum ofp_version version)
{
struct ofp11_group_desc_stats *ogds;
size_t length;
@@ -5774,7 +5777,8 @@ ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd,
return OFPERR_OFPBRC_BAD_LEN;
}
- return ofputil_pull_buckets(msg, length - sizeof *ogds, &gd->buckets);
+ return ofputil_pull_buckets(msg, version, length - sizeof *ogds,
+ &gd->buckets);
}
/* Converts abstract group mod 'gm' into a message for OpenFlow version
@@ -5857,7 +5861,7 @@ ofputil_decode_group_mod(const struct ofp_header *oh,
gm->type = ogm->type;
gm->group_id = ntohl(ogm->group_id);
- return ofputil_pull_buckets(&msg, msg.size, &gm->buckets);
+ return ofputil_pull_buckets(&msg, oh->version, msg.size, &gm->buckets);
}
/* Parse a queue status request message into 'oqsr'.
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index d5f34d7..5fa8fee 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -973,7 +973,7 @@ int ofputil_decode_group_stats_reply(struct ofpbuf *,
struct ofputil_group_stats *);
int ofputil_decode_group_desc_reply(struct ofputil_group_desc *,
- struct ofpbuf *);
+ struct ofpbuf *, enum ofp_version);
void ofputil_append_group_desc_reply(const struct ofputil_group_desc *,
struct list *buckets,
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index c2cc1f6..00d35aa 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -2968,8 +2968,8 @@ ofctl_parse_ofp11_actions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
/* Convert to ofpacts. */
ofpbuf_init(&ofpacts, 0);
size = of11_in.size;
- error = ofpacts_pull_openflow11_actions(&of11_in, of11_in.size,
- &ofpacts);
+ error = ofpacts_pull_openflow11_actions(&of11_in, OFP11_VERSION,
+ of11_in.size, &ofpacts);
if (error) {
printf("bad OF1.1 actions: %s\n\n", ofperr_get_name(error));
ofpbuf_uninit(&ofpacts);
@@ -3036,8 +3036,8 @@ ofctl_parse_ofp11_instructions(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
/* Convert to ofpacts. */
ofpbuf_init(&ofpacts, 0);
size = of11_in.size;
- error = ofpacts_pull_openflow11_instructions(&of11_in, of11_in.size,
- &ofpacts);
+ error = ofpacts_pull_openflow11_instructions(&of11_in, OFP11_VERSION,
+ of11_in.size, &ofpacts);
if (!error) {
/* Verify actions. */
struct flow flow;
^ permalink raw reply related
* Re: [PATCH v2.40 3/7] ofp-actions: Add OFPUTIL_OFPAT13_PUSH_MPLS
From: Ben Pfaff @ 2013-09-30 2:00 UTC (permalink / raw)
To: Simon Horman
Cc: dev, netdev, Jesse Gross, Pravin B Shelar, Ravi K, Isaku Yamahata,
Joe Stringer
In-Reply-To: <20130930011344.GB4768@verge.net.au>
On Mon, Sep 30, 2013 at 10:13:44AM +0900, Simon Horman wrote:
> On Fri, Sep 27, 2013 at 12:30:10PM -0700, Ben Pfaff wrote:
> > On Fri, Sep 27, 2013 at 09:18:32AM +0900, Simon Horman wrote:
> > > From: Joe Stringer <joe@wand.net.nz>
> > >
> > > This patch adds a new compatibility enum for use with MPLS, so that the
> > > differing behaviour between OpenFlow 1.2 and 1.3 can be implemented in
> > > ofproto-dpif-xlate.
> >
> > It seems a little awkward to me to do this via a new OFPACT_, mostly
> > because there isn't currently any distinction between OF1.1 and OF1.3 in
> > terms of OFPACT_ definitions. Did you consider adding a new field to
> > struct ofpact_push_mpls that would say whether the label should be added
> > before or after a VLAN tag?
>
> I think that the main reason that Joe and I (probably much more I than Joe)
> chose to use OFPACT_ the way that we did is that it seemed to be in keeping
> with the way the code already works. Clearly you don't feel that is the
> case which seems entirely reasonable to me. I'll see about re-working the
> code as you have suggested.
Thanks. I think that it will make the code easier to understand.
^ permalink raw reply
* Re: [PATCH v2.40 3/7] ofp-actions: Add OFPUTIL_OFPAT13_PUSH_MPLS
From: Simon Horman @ 2013-09-30 1:13 UTC (permalink / raw)
To: Ben Pfaff
Cc: dev, netdev, Jesse Gross, Pravin B Shelar, Ravi K, Isaku Yamahata,
Joe Stringer
In-Reply-To: <20130927193010.GB17506@nicira.com>
On Fri, Sep 27, 2013 at 12:30:10PM -0700, Ben Pfaff wrote:
> On Fri, Sep 27, 2013 at 09:18:32AM +0900, Simon Horman wrote:
> > From: Joe Stringer <joe@wand.net.nz>
> >
> > This patch adds a new compatibility enum for use with MPLS, so that the
> > differing behaviour between OpenFlow 1.2 and 1.3 can be implemented in
> > ofproto-dpif-xlate.
>
> It seems a little awkward to me to do this via a new OFPACT_, mostly
> because there isn't currently any distinction between OF1.1 and OF1.3 in
> terms of OFPACT_ definitions. Did you consider adding a new field to
> struct ofpact_push_mpls that would say whether the label should be added
> before or after a VLAN tag?
Hi Ben,
I think that the main reason that Joe and I (probably much more I than Joe)
chose to use OFPACT_ the way that we did is that it seemed to be in keeping
with the way the code already works. Clearly you don't feel that is the
case which seems entirely reasonable to me. I'll see about re-working the
code as you have suggested.
^ permalink raw reply
* Re: [PATCH v2.40 2/7] odp: Allow VLAN actions after MPLS actions
From: Simon Horman @ 2013-09-30 1:10 UTC (permalink / raw)
To: Joe Stringer
Cc: Ben Pfaff, dev@openvswitch.org, netdev, Jesse Gross,
Pravin B Shelar, Ravi K, Isaku Yamahata
In-Reply-To: <CAOftzPg_FJoyS0oS8Ua7cpMaCh=BboWwyn8kVVoXGT9X9HQ0hg@mail.gmail.com>
On Sun, Sep 29, 2013 at 02:51:19PM +1300, Joe Stringer wrote:
> On Sat, Sep 28, 2013 at 7:21 AM, Ben Pfaff <blp@nicira.com> wrote:
>
> > On Fri, Sep 27, 2013 at 09:18:31AM +0900, Simon Horman wrote:
> > > From: Joe Stringer <joe@wand.net.nz>
> > >
> > > OpenFlow 1.2 and 1.3 differ on their handling of MPLS actions in the
> > > presence of VLAN tags. To allow correct behaviour to be committed in
> > > each situation, this patch adds a second round of VLAN tag action
> > > handling to commit_odp_actions(), which occurs after MPLS actions. This
> > > is implemented with a new field in 'struct xlate_in' called 'vlan_tci'.
> > >
> > > When an push_mpls action is composed, the flow's current VLAN state is
> > > stored into xin->vlan_tci, and flow->vlan_tci is set to 0 (pop_vlan). If
> > > a VLAN tag is present, it is stripped; if not, then there is no change.
> > > Any later modifications to the VLAN state is written to xin->vlan_tci.
> > > When committing the actions, flow->vlan_tci is used before MPLS actions,
> > > and xin->vlan_tci is used afterwards. This retains the current datapath
> > > behaviour, but allows VLAN actions to be applied in a more flexible
> > > manner.
> > >
> > > Signed-off-by: Joe Stringer <joe@wand.net.nz>
> > > Signed-off-by: Simon Horman <horms@verge.net.au>
> >
> > The commit message talks about handling OpenFlow 1.2 and 1.3 both
> > properly, but I don't see how the code distinguishes between the cases.
> > Can you explain? Maybe this is something added in a later patch, in
> > which case it would be nice to mention that in the commit message.
> >
>
> It is added in patch #5. IIRC this patch should cause no difference in
> behaviour, but set up infrastructure to be used later.
>
> There seems to be a typo in the comment in vlan_tci_restore() here:
> > > + /* If MPLS actions were executed after MPLS, copy the final
> > vlan_tci out
> > > + * and restore the intermediate VLAN state. */
> >
>
> Right, that should probably be "...executed after VLAN actions...".
>
> I was a little confused by the new local variable 'vlan_tci' in
> > do_xlate_actions(). Partly this was because the fact that I didn't find
> > it obvious that sometimes it points to different VLAN tags. I think
> > this would be easier to see if it were initially assigned just under the
> > big comment rather than in an initializer, so that one would know to
> > look at the comment.
> >
>
> Perhaps the big comment could be rearranged and put above the initialiser,
> something like the following:-
>
> /* VLAN actions are stored to '*vlan_tci'. This variable initially points
> to 'xin->flow->vlan_tci', so that
> * VLAN actions are applied before any MPLS actions. When an MPLS action is
> translated,
> * 'vlan_tci' is updated to point to 'xin->vlan_tci'. This causes later
> VLAN actions to be applied after MPLS actions.
> * Each time through the loop, 'xin->vlan_tci' is updated to reflect the
> final VLAN state of the flow. */
>
> Then, the place where 'xin->vlan_tci' is updated to '*vlan_tci' could have
> a simple comment to refer back:-
>
> /* Update the final vlan state to match the current state. */
>
> Simon, do you mind handling the change?
Not at all. I'll include this change the next time I post the series.
^ permalink raw reply
* Re: [PATCH net-next] virtio-net: switch to use XPS to choose txq
From: Rusty Russell @ 2013-09-29 23:35 UTC (permalink / raw)
To: Jason Wang, netdev, linux-kernel, virtualization
Cc: Jason Wang, Michael S. Tsirkin
In-Reply-To: <1380261444-40918-1-git-send-email-jasowang@redhat.com>
Jason Wang <jasowang@redhat.com> writes:
> We used to use a percpu structure vq_index to record the cpu to queue
> mapping, this is suboptimal since it duplicates the work of XPS and
> loses all other XPS functionality such as allowing use to configure
> their own transmission steering strategy.
>
> So this patch switches to use XPS and suggest a default mapping when
> the number of cpus is equal to the number of queues. With XPS support,
> there's no need for keeping per-cpu vq_index and .ndo_select_queue(),
> so they were removed also.
>
> Cc: Rusty Russell <rusty@rustcorp.com.au>
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Signed-off-by: Jason Wang <jasowang@redhat.com>
> ---
> drivers/net/virtio_net.c | 55 +++++++--------------------------------------
> 1 files changed, 9 insertions(+), 46 deletions(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index defec2b..4102c1b 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -127,9 +127,6 @@ struct virtnet_info {
> /* Does the affinity hint is set for virtqueues? */
> bool affinity_hint_set;
>
> - /* Per-cpu variable to show the mapping from CPU to virtqueue */
> - int __percpu *vq_index;
> -
> /* CPU hot plug notifier */
> struct notifier_block nb;
> };
> @@ -1063,7 +1060,6 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev,
> static void virtnet_clean_affinity(struct virtnet_info *vi, long hcpu)
> {
> int i;
> - int cpu;
>
> if (vi->affinity_hint_set) {
> for (i = 0; i < vi->max_queue_pairs; i++) {
> @@ -1073,20 +1069,11 @@ static void virtnet_clean_affinity(struct virtnet_info *vi, long hcpu)
>
> vi->affinity_hint_set = false;
> }
> -
> - i = 0;
> - for_each_online_cpu(cpu) {
> - if (cpu == hcpu) {
> - *per_cpu_ptr(vi->vq_index, cpu) = -1;
> - } else {
> - *per_cpu_ptr(vi->vq_index, cpu) =
> - ++i % vi->curr_queue_pairs;
> - }
> - }
> }
>
> static void virtnet_set_affinity(struct virtnet_info *vi)
> {
> + cpumask_var_t cpumask;
> int i;
> int cpu;
>
> @@ -1100,15 +1087,21 @@ static void virtnet_set_affinity(struct virtnet_info *vi)
> return;
> }
>
> + if (!alloc_cpumask_var(&cpumask, GFP_KERNEL))
> + return;
> +
> i = 0;
> for_each_online_cpu(cpu) {
> virtqueue_set_affinity(vi->rq[i].vq, cpu);
> virtqueue_set_affinity(vi->sq[i].vq, cpu);
> - *per_cpu_ptr(vi->vq_index, cpu) = i;
> + cpumask_clear(cpumask);
> + cpumask_set_cpu(cpu, cpumask);
> + netif_set_xps_queue(vi->dev, cpumask, i);
> i++;
> }
>
> vi->affinity_hint_set = true;
> + free_cpumask_var(cpumask);
> }
Um, isn't this just cpumask_of(cpu)?
Cheers,
Rusty.
^ permalink raw reply
* Re: [ipv4:PATCH] Allow userspace to specify primary or secondary ip on interface
From: David Miller @ 2013-09-29 21:59 UTC (permalink / raw)
To: vincent.mc.li; +Cc: netdev, linux-kernel
In-Reply-To: <1380056988-6717-1-git-send-email-vincent.mc.li@gmail.com>
From: Vincent Li <vincent.mc.li@gmail.com>
Date: Tue, 24 Sep 2013 14:09:48 -0700
> the reason for this patch is that we have a multi blade cluster platform
> sharing 'floating management ip' and also that each blade has its own
> management ip on the management interface, so whichever blade in the
> cluster becomes primary blade, the 'floating mangaement ip' follows it,
> and we want any of our traffic originated from the primary blade source from
> the 'floating management ip' for consistency. but in this case, since the local
> blade management ip is always the primary ip on the mangaement interface and
> 'floating management ip' is always secondary, kernel always choose the primary
> ip as source ip address. thus we would like to add the flexibility in kernel to
> allow us to specify which ip to be primary or secondary.
You have the flexibility already.
You can specify a specific source address ot use in routes.
^ permalink raw reply
* RE
From: amikam_t @ 2013-09-29 21:43 UTC (permalink / raw)
To: Recipients
I am christy walton i have a proposal for you
^ permalink raw reply
* Re: [PATCH V2 net-next] fib_trie: avoid a redundant bit judgement in inflate
From: David Miller @ 2013-09-29 21:31 UTC (permalink / raw)
To: baker.kernel; +Cc: kuznet, jmorris, yoshfuji, kaber, netdev, linux-kernel
In-Reply-To: <1380461518-10095-1-git-send-email-baker.kernel@gmail.com>
Based upon how quickly you sent these two patches, the first of which
wouldn't even compile, I have zero confidence that you actually
booted and tested this patch at all.
I'm not applying this until you take the time to boot and test the
change in some way, and say explicitly in your commit message how
you tested it.
^ permalink raw reply
* [PATCH 2/2] ipv6 mcast: use in6_dev_put in timer handlers instead of __in6_dev_put
From: Salam Noureddine @ 2013-09-29 20:41 UTC (permalink / raw)
To: David S. Miller, Alexey Kuznetsov, James Morris,
Hideaki YOSHIFUJI, Patrick McHardy, netdev
Cc: Salam Noureddine
It is possible for the timer handlers to run after the call to
ipv6_mc_down so use in6_dev_put instead of __in6_dev_put in the
handler function in order to do proper cleanup when the refcnt
reaches 0. Otherwise, the refcnt can reach zero without the
inet6_dev being destroyed and we end up leaking a reference to
the net_device and see messages like the following,
unregister_netdevice: waiting for eth0 to become free. Usage count = 1
Tested on linux-3.4.43.
Signed-off-by: Salam Noureddine <noureddine@aristanetworks.com>
---
net/ipv6/mcast.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 096cd67..d18f9f9 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -2034,7 +2034,7 @@ static void mld_dad_timer_expire(unsigned long data)
if (idev->mc_dad_count)
mld_dad_start_timer(idev, idev->mc_maxdelay);
}
- __in6_dev_put(idev);
+ in6_dev_put(idev);
}
static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,
@@ -2379,7 +2379,7 @@ static void mld_gq_timer_expire(unsigned long data)
idev->mc_gq_running = 0;
mld_send_report(idev, NULL);
- __in6_dev_put(idev);
+ in6_dev_put(idev);
}
static void mld_ifc_timer_expire(unsigned long data)
@@ -2392,7 +2392,7 @@ static void mld_ifc_timer_expire(unsigned long data)
if (idev->mc_ifc_count)
mld_ifc_start_timer(idev, idev->mc_maxdelay);
}
- __in6_dev_put(idev);
+ in6_dev_put(idev);
}
static void mld_ifc_event(struct inet6_dev *idev)
--
1.7.4.4
^ permalink raw reply related
* [PATCH 1/2] ipv4 igmp: use in_dev_put in timer handlers instead of __in_dev_put
From: Salam Noureddine @ 2013-09-29 20:39 UTC (permalink / raw)
To: David S. Miller, Alexey Kuznetsov, James Morris,
Hideaki YOSHIFUJI, Patrick McHardy, netdev
Cc: Salam Noureddine
It is possible for the timer handlers to run after the call to
ip_mc_down so use in_dev_put instead of __in_dev_put in the handler
function in order to do proper cleanup when the refcnt reaches 0.
Otherwise, the refcnt can reach zero without the in_device being
destroyed and we end up leaking a reference to the net_device and
see messages like the following,
unregister_netdevice: waiting for eth0 to become free. Usage count = 1
Tested on linux-3.4.43.
Signed-off-by: Salam Noureddine <noureddine@aristanetworks.com>
---
net/ipv4/igmp.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index dace87f..7defdc9 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -736,7 +736,7 @@ static void igmp_gq_timer_expire(unsigned long data)
in_dev->mr_gq_running = 0;
igmpv3_send_report(in_dev, NULL);
- __in_dev_put(in_dev);
+ in_dev_put(in_dev);
}
static void igmp_ifc_timer_expire(unsigned long data)
@@ -749,7 +749,7 @@ static void igmp_ifc_timer_expire(unsigned long data)
igmp_ifc_start_timer(in_dev,
unsolicited_report_interval(in_dev));
}
- __in_dev_put(in_dev);
+ in_dev_put(in_dev);
}
static void igmp_ifc_event(struct in_device *in_dev)
--
1.7.4.4
^ permalink raw reply related
* Re: [PATCH] can: add Renesas R-Car CAN driver
From: Marc Kleine-Budde @ 2013-09-29 19:03 UTC (permalink / raw)
To: Sergei Shtylyov; +Cc: netdev, wg, linux-can, linux-sh
In-Reply-To: <201309280211.39068.sergei.shtylyov@cogentembedded.com>
[-- Attachment #1: Type: text/plain, Size: 36209 bytes --]
On 09/28/2013 12:11 AM, Sergei Shtylyov wrote:
> Add support for the CAN controller found in Renesas R-Car SoCs.
Is there a public available datasheet for the CAN core? What
architecture are the Renesas R-Car SoCs? They're ARM, aren't they?
What's R-Car's status on device tree conversion?
More comments inline
> Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
>
> ---
> The patch is against the 'linux-can-next.git' repo.
>
> drivers/net/can/Kconfig | 9
> drivers/net/can/Makefile | 1
> drivers/net/can/rcar_can.c | 898 ++++++++++++++++++++++++++++++++++
> include/linux/can/platform/rcar_can.h | 15
> 4 files changed, 923 insertions(+)
>
> Index: linux-can-next/drivers/net/can/Kconfig
> ===================================================================
> --- linux-can-next.orig/drivers/net/can/Kconfig
> +++ linux-can-next/drivers/net/can/Kconfig
> @@ -125,6 +125,15 @@ config CAN_GRCAN
> endian syntheses of the cores would need some modifications on
> the hardware level to work.
>
> +config CAN_RCAR
> + tristate "Renesas R-Car CAN controller"
> + ---help---
> + Say Y here if you want to use CAN controller found on Renesas R-Car
> + SoCs.
> +
> + To compile this driver as a module, choose M here: the module will
> + be called rcar_can.
> +
> source "drivers/net/can/mscan/Kconfig"
>
> source "drivers/net/can/sja1000/Kconfig"
> Index: linux-can-next/drivers/net/can/Makefile
> ===================================================================
> --- linux-can-next.orig/drivers/net/can/Makefile
> +++ linux-can-next/drivers/net/can/Makefile
> @@ -25,5 +25,6 @@ obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ica
> obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
> obj-$(CONFIG_PCH_CAN) += pch_can.o
> obj-$(CONFIG_CAN_GRCAN) += grcan.o
> +obj-$(CONFIG_CAN_RCAR) += rcar_can.o
>
> ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
> Index: linux-can-next/drivers/net/can/rcar_can.c
> ===================================================================
> --- /dev/null
> +++ linux-can-next/drivers/net/can/rcar_can.c
> @@ -0,0 +1,898 @@
> +/*
> + * Renesas R-Car CAN device driver
> + *
> + * Copyright (C) 2013 Cogent Embedded, Inc. <source@cogentembedded.com>
> + * Copyright (C) 2013 Renesas Solutions Corp.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/types.h>
> +#include <linux/interrupt.h>
> +#include <linux/errno.h>
> +#include <linux/netdevice.h>
> +#include <linux/platform_device.h>
> +#include <linux/can/led.h>
> +#include <linux/can/dev.h>
> +#include <linux/clk.h>
> +#include <linux/can/platform/rcar_can.h>
> +
> +#define DRV_NAME "rcar_can"
> +
> +#define RCAR_CAN_MIER1 0x42C /* CANi Mailbox Interrupt Enable Register 1 */
> +#define RCAR_CAN_MKR(n) ((n) < 2 ? 0x430 + 4 * (n) : 0x400 + 4 * ((n) - 2))
> + /* CANi Mask Register */
> +#define RCAR_CAN_MKIVLR0 0x438 /* CANi Mask Invalid Register 0 */
> +#define RCAR_CAN_MIER0 0x43C /* CANi Mailbox Interrupt Enable Register 0 */
> +
> +#define RCAR_CAN_MCTL(n) (0x800 + (n)) /* CANi Message Control Register */
> +#define RCAR_CAN_CTLR 0x840 /* CANi Control Register */
> +#define RCAR_CAN_STR 0x842 /* CANi Status Register */
> +#define RCAR_CAN_BCR 0x844 /* CANi Bit Configuration Register */
> +#define RCAR_CAN_CLKR 0x847 /* CANi Clock Select Register */
> +#define RCAR_CAN_EIER 0x84C /* CANi Error Interrupt Enable Register */
> +#define RCAR_CAN_EIFR 0x84D /* CANi Err Interrupt Factor Judge Register */
> +#define RCAR_CAN_RECR 0x84E /* CANi Receive Error Count Register */
> +#define RCAR_CAN_TECR 0x84F /* CANi Transmit Error Count Register */
> +#define RCAR_CAN_ECSR 0x850 /* CANi Error Code Store Register */
> +#define RCAR_CAN_MSSR 0x852 /* CANi Mailbox Search Status Register */
> +#define RCAR_CAN_MSMR 0x853 /* CANi Mailbox Search Mode Register */
> +#define RCAR_CAN_TCR 0x858 /* CANi Test Control Register */
> +#define RCAR_CAN_IER 0x860 /* CANi Interrupt Enable Register */
> +#define RCAR_CAN_ISR 0x861 /* CANi Interrupt Status Register */
You might consider using an enum for the register offsets.
> +
> +/* Offsets of RCAR_CAN Mailbox Registers */
> +#define MBX_HDR_OFFSET 0x0
> +#define MBX_DLC_OFFSET 0x5
> +#define MBX_DATA_OFFSET 0x6
can you please add the RCAR_ prefix to all defines.
> +
> +#define RCAR_CAN_MBX_SIZE 0x10
> +
> +/* Control Register bits */
> +#define CTLR_SLPM BIT(10)
> +#define CTLR_HALT BIT(9)
> +#define CTLR_RESET BIT(8)
> +#define CTLR_FORCE_RESET (3 << 8)
> +#define CTLR_TPM BIT(4) /* Transmission Priority Mode Select Bit */
> +#define CTLR_IDFM_MIXED BIT(2) /* Mixed ID mode */
> +
> +/* Message Control Register bits */
> +#define MCTL_TRMREQ BIT(7)
> +#define MCTL_RECREQ BIT(6)
> +#define MCTL_ONESHOT BIT(4)
> +#define MCTL_SENTDATA BIT(0)
> +#define MCTL_NEWDATA BIT(0)
> +
> +#define N_RX_MKREGS 2 /* Number of mask registers */
> + /* for Rx mailboxes 0-31 */
> +
> +/* Bit Configuration Register settings */
> +#define BCR_TSEG1(x) (((x) & 0x0f) << 28)
> +#define BCR_BPR(x) (((x) & 0x3ff) << 16)
> +#define BCR_SJW(x) (((x) & 0x3) << 12)
> +#define BCR_TSEG2(x) (((x) & 0x07) << 8)
> +
> +/* Mailbox and Mask Registers bits */
> +#define RCAR_CAN_IDE BIT(31)
> +#define RCAR_CAN_RTR BIT(30)
> +#define RCAR_CAN_SID_SHIFT 18
> +
> +/* Interrupt Enable Register bits */
> +#define IER_ERSIE BIT(5) /* Error (ERS) Interrupt Enable Bit */
> +#define IER_RXM0IE BIT(2) /* Mailbox 0 Successful Reception (RXM0) */
> + /* Interrupt Enable Bit */
> +#define IER_RXM1IE BIT(1) /* Mailbox 1 Successful Reception (RXM0) */
> + /* Interrupt Enable Bit */
> +#define IER_TXMIE BIT(0) /* Mailbox 32 to 63 Successful Tx */
> + /* Interrupt Enable Bit */
> +
> +/* Interrupt Status Register bits */
> +#define ISR_ERSF BIT(5) /* Error (ERS) Interrupt Status Bit */
> +#define ISR_RXM0F BIT(2) /* Mailbox 0 Successful Reception (RXM0) */
> + /* Interrupt Status Bit */
> +#define ISR_RXM1F BIT(1) /* Mailbox 1 to 63 Successful Reception */
> + /* (RXM1) Interrupt Status Bit */
> +#define ISR_TXMF BIT(0) /* Mailbox 32 to 63 Successful Transmission */
> + /* (TXM) Interrupt Status Bit */
> +
> +/* Error Interrupt Enable Register bits */
> +#define EIER_BLIE BIT(7) /* Bus Lock Interrupt Enable */
> +#define EIER_OLIE BIT(6) /* Overload Frame Transmit Interrupt Enable */
> +#define EIER_ORIE BIT(5) /* Receive Overrun Interrupt Enable */
> +#define EIER_BORIE BIT(4) /* Bus-Off Recovery Interrupt Enable */
> +
> +#define EIER_BOEIE BIT(3) /* Bus-Off Entry Interrupt Enable */
> +#define EIER_EPIE BIT(2) /* Error Passive Interrupt Enable */
> +#define EIER_EWIE BIT(1) /* Error Warning Interrupt Enable */
> +#define EIER_BEIE BIT(0) /* Bus Error Interrupt Enable */
> +
> +/* Error Interrupt Factor Judge Register bits */
> +#define EIFR_BLIF BIT(7) /* Bus Lock Detect Flag */
> +#define EIFR_OLIF BIT(6) /* Overload Frame Transmission Detect Flag */
> +#define EIFR_ORIF BIT(5) /* Receive Overrun Detect Flag */
> +#define EIFR_BORIF BIT(4) /* Bus-Off Recovery Detect Flag */
> +#define EIFR_BOEIF BIT(3) /* Bus-Off Entry Detect Flag */
> +#define EIFR_EPIF BIT(2) /* Error Passive Detect Flag */
> +#define EIFR_EWIF BIT(1) /* Error Warning Detect Flag */
> +#define EIFR_BEIF BIT(0) /* Bus Error Detect Flag */
> +
> +/* Error Code Store Register bits */
> +#define ECSR_EDPM BIT(7) /* Error Display Mode Select Bit */
> +#define ECSR_ADEF BIT(6) /* ACK Delimiter Error Flag */
> +#define ECSR_BE0F BIT(5) /* Bit Error (dominant) Flag */
> +#define ECSR_BE1F BIT(4) /* Bit Error (recessive) Flag */
> +#define ECSR_CEF BIT(3) /* CRC Error Flag */
> +#define ECSR_AEF BIT(2) /* ACK Error Flag */
> +#define ECSR_FEF BIT(1) /* Form Error Flag */
> +#define ECSR_SEF BIT(0) /* Stuff Error Flag */
> +
> +/* Mailbox Search Status Register bits */
> +#define MSSR_SEST BIT(7) /* Search Result Status Bit */
> +#define MSSR_MBNST 0x3f /* Search Result Mailbox Number Status mask */
> +
> +/* Mailbox Search Mode Register values */
> +#define MSMR_TXMB 1 /* Transmit mailbox search mode */
> +#define MSMR_RXMB 0 /* Receive mailbox search mode */
> +
> +/* Mailbox configuration:
> + * mailbox 0 - not used
> + * mailbox 1-31 - Rx
> + * mailbox 32-63 - Tx
> + * no FIFO mailboxes
> + */
> +#define N_MBX 64
> +#define FIRST_TX_MB 32
> +#define RX_MBX_MASK 0xFFFFFFFE
> +
> +#define RCAR_CAN_NAPI_WEIGHT (FIRST_TX_MB - 1)
> +
> +struct rcar_can_priv {
> + struct can_priv can; /* Must be the first member! */
> + struct net_device *ndev;
> + struct napi_struct napi;
> + void __iomem *reg_base;
> + struct clk *clk;
> + spinlock_t mier_lock;
> + u8 clock_select;
> +};
> +
> +static const struct can_bittiming_const rcar_can_bittiming_const = {
> + .name = DRV_NAME,
> + .tseg1_min = 4,
> + .tseg1_max = 16,
> + .tseg2_min = 2,
> + .tseg2_max = 8,
> + .sjw_max = 4,
> + .brp_min = 1,
> + .brp_max = 1024,
> + .brp_inc = 1,
> +};
> +
If you use use an enum for the register offsets you can change the int
to that enum in the accessor functions.
> +static inline u32 rcar_can_readl(struct rcar_can_priv *priv, int reg)
> +{
> + return readl(priv->reg_base + reg);
> +}
> +
> +static inline u16 rcar_can_readw(struct rcar_can_priv *priv, int reg)
> +{
> + return readw(priv->reg_base + reg);
> +}
> +
> +static inline u8 rcar_can_readb(struct rcar_can_priv *priv, int reg)
> +{
> + return readb(priv->reg_base + reg);
> +}
> +
> +static inline void rcar_can_writel(struct rcar_can_priv *priv, int reg, u32 val)
> +{
> + writel(val, priv->reg_base + reg);
> +}
> +
> +static inline void rcar_can_writew(struct rcar_can_priv *priv, int reg, u16 val)
> +{
> + writew(val, priv->reg_base + reg);
> +}
> +
> +static inline void rcar_can_writeb(struct rcar_can_priv *priv, int reg, u8 val)
> +{
> + writeb(val, priv->reg_base + reg);
> +}
> +
> +static inline u32 rcar_can_mbx_readl(struct rcar_can_priv *priv,
> + u32 mbxno, u8 offset)
> +{
> + return rcar_can_readl(priv, RCAR_CAN_MBX_SIZE * mbxno + offset);
Can you define hide the RCAR_CAN_MBX_SIZE * mbxno into a macro?
Something like:
RCAR_CAN_MBX(mbxno)
> +}
> +
> +static inline u8 rcar_can_mbx_readb(struct rcar_can_priv *priv,
> + u32 mbxno, u8 offset)
> +{
> + return rcar_can_readb(priv, RCAR_CAN_MBX_SIZE * mbxno + offset);
> +}
> +
> +static inline void rcar_can_mbx_writel(struct rcar_can_priv *priv, u32 mbxno,
> + u8 offset, u32 val)
> +{
> + rcar_can_writel(priv, RCAR_CAN_MBX_SIZE * mbxno + offset, val);
> +}
> +
> +static inline void rcar_can_mbx_writeb(struct rcar_can_priv *priv, u32 mbxno,
> + u8 offset, u8 val)
> +{
> + rcar_can_writeb(priv, RCAR_CAN_MBX_SIZE * mbxno + offset, val);
> +}
> +
> +static void rcar_can_error(struct net_device *ndev)
> +{
> + struct rcar_can_priv *priv = netdev_priv(ndev);
> + struct net_device_stats *stats = &ndev->stats;
> + struct can_frame *cf;
> + struct sk_buff *skb;
> + u8 eifr;
> +
> + /* Propagate the error condition to the CAN stack */
> + skb = alloc_can_err_skb(ndev, &cf);
> + if (!skb) {
> + if (printk_ratelimit())
> + netdev_err(priv->ndev,
> + "%s: alloc_can_err_skb() failed\n",
> + __func__);
> + return;
> + }
> +
> + eifr = rcar_can_readb(priv, RCAR_CAN_EIFR);
> + if (eifr & EIFR_EWIF) {
> + netdev_dbg(priv->ndev, "Error warning interrupt\n");
> + priv->can.state = CAN_STATE_ERROR_WARNING;
> + priv->can.can_stats.error_warning++;
> + cf->can_id |= CAN_ERR_CRTL;
> + if (rcar_can_readb(priv, RCAR_CAN_TECR) > 96)
> + cf->data[1] |= CAN_ERR_CRTL_TX_WARNING;
> + if (rcar_can_readb(priv, RCAR_CAN_RECR) > 96)
> + cf->data[1] |= CAN_ERR_CRTL_RX_WARNING;
> + /* Clear interrupt condition */
> + rcar_can_writeb(priv, RCAR_CAN_EIFR, (u8)~EIFR_EWIF);
The cast is not needed.
> + }
> + if (eifr & EIFR_EPIF) {
> + netdev_dbg(priv->ndev, "Error passive interrupt\n");
> + priv->can.state = CAN_STATE_ERROR_PASSIVE;
> + priv->can.can_stats.error_passive++;
> + cf->can_id |= CAN_ERR_CRTL;
> + if (rcar_can_readb(priv, RCAR_CAN_TECR) > 127)
> + cf->data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
> + if (rcar_can_readb(priv, RCAR_CAN_RECR) > 127)
> + cf->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
> + /* Clear interrupt condition */
> + rcar_can_writeb(priv, RCAR_CAN_EIFR, (u8)~EIFR_EPIF);
> + }
> + if (eifr & EIFR_BOEIF) {
> + netdev_dbg(priv->ndev, "Bus-off entry interrupt\n");
> + priv->can.state = CAN_STATE_BUS_OFF;
> + cf->can_id |= CAN_ERR_BUSOFF;
> + /* Clear interrupt condition */
> + rcar_can_writeb(priv, RCAR_CAN_EIFR, (u8)~EIFR_BOEIF);
> + /* Disable all interrupts in bus-off to avoid int hog */
> + rcar_can_writeb(priv, RCAR_CAN_EIER, 0);
> + rcar_can_writeb(priv, RCAR_CAN_IER, 0);
> + can_bus_off(ndev);
How does the rcan recover from bus off?
> + }
> + if (eifr & EIFR_BEIF) {
> + int rx_errors = 0, tx_errors = 0, bus_errors = 0;
> + u8 ecsr;
> +
> + netdev_dbg(priv->ndev, "Bus error interrupt:\n");
> + cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
> + cf->data[2] = CAN_ERR_PROT_UNSPEC;
> +
> + ecsr = rcar_can_readb(priv, RCAR_CAN_ECSR);
> + if (ecsr & ECSR_ADEF) {
> + netdev_dbg(priv->ndev, "ACK Delimiter Error\n");
> + cf->data[3] |= CAN_ERR_PROT_LOC_ACK_DEL;
> + bus_errors++;
> + tx_errors++;
> + rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_ADEF);
> + }
> + if (ecsr & ECSR_BE0F) {
> + netdev_dbg(priv->ndev, "Bit Error (dominant)\n");
> + cf->data[2] |= CAN_ERR_PROT_BIT0;
> + bus_errors++;
> + tx_errors++;
> + rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_BE0F);
> + }
> + if (ecsr & ECSR_BE1F) {
> + netdev_dbg(priv->ndev, "Bit Error (recessive)\n");
> + cf->data[2] |= CAN_ERR_PROT_BIT1;
> + bus_errors++;
> + tx_errors++;
> + rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_BE1F);
> + }
> + if (ecsr & ECSR_CEF) {
> + netdev_dbg(priv->ndev, "CRC Error\n");
> + cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
> + bus_errors++;
> + rx_errors++;
> + rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_CEF);
> + }
> + if (ecsr & ECSR_AEF) {
> + netdev_dbg(priv->ndev, "ACK Error\n");
> + cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
> + bus_errors++;
> + tx_errors++;
> + rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_AEF);
> + }
> + if (ecsr & ECSR_FEF) {
> + netdev_dbg(priv->ndev, "Form Error\n");
> + cf->data[2] |= CAN_ERR_PROT_FORM;
> + bus_errors++;
> + rx_errors++;
> + rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_FEF);
> + }
> + if (ecsr & ECSR_SEF) {
> + netdev_dbg(priv->ndev, "Stuff Error\n");
> + cf->data[2] |= CAN_ERR_PROT_STUFF;
> + bus_errors++;
> + rx_errors++;
> + rcar_can_writeb(priv, RCAR_CAN_ECSR, (u8)~ECSR_SEF);
> + }
> +
> + priv->can.can_stats.bus_error += bus_errors;
> + ndev->stats.rx_errors += rx_errors;
> + ndev->stats.tx_errors += tx_errors;
> + rcar_can_writeb(priv, RCAR_CAN_EIFR, (u8)~EIFR_BEIF);
> + }
> + if (eifr & EIFR_ORIF) {
> + netdev_dbg(priv->ndev, "Receive overrun error interrupt\n");
> + cf->can_id |= CAN_ERR_CRTL;
> + cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
> + ndev->stats.rx_over_errors++;
> + ndev->stats.rx_errors++;
> + rcar_can_writeb(priv, RCAR_CAN_EIFR, (u8)~EIFR_ORIF);
> + }
> + if (eifr & EIFR_OLIF) {
> + netdev_dbg(priv->ndev,
> + "Overload Frame Transmission error interrupt\n");
> + cf->can_id |= CAN_ERR_PROT;
> + cf->data[2] |= CAN_ERR_PROT_OVERLOAD;
> + ndev->stats.rx_over_errors++;
> + ndev->stats.rx_errors++;
> + rcar_can_writeb(priv, RCAR_CAN_EIFR, (u8)~EIFR_OLIF);
> + }
> +
> + netif_rx(skb);
> + stats->rx_packets++;
> + stats->rx_bytes += cf->can_dlc;
> +}
> +
> +static irqreturn_t rcar_can_interrupt(int irq, void *dev_id)
> +{
> + struct net_device *ndev = (struct net_device *)dev_id;
> + struct rcar_can_priv *priv = netdev_priv(ndev);
> + struct net_device_stats *stats = &ndev->stats;
> + u8 isr;
> +
> + isr = rcar_can_readb(priv, RCAR_CAN_ISR);
> + if (isr & ISR_ERSF)
> + rcar_can_error(ndev);
> +
> + if (isr & ISR_TXMF) {
> + u32 ie_mask = 0;
> +
> + /* Set Transmit Mailbox Search Mode */
> + rcar_can_writeb(priv, RCAR_CAN_MSMR, MSMR_TXMB);
Can you please outline how to mailbox search mode works? What happens if
you activate tx mailbox search mode here and rx mailbox search mode below?
> + while (1) {
I presonally don't like while (1) loops in an interrupt handler, can you
rearange the code, so that you have an explizid loop termination?
> + u8 mctl, mbx;
> +
> + mbx = rcar_can_readb(priv, RCAR_CAN_MSSR);
> + if (mbx & MSSR_SEST)
> + break;
> + mbx &= MSSR_MBNST;
> + mctl = rcar_can_readb(priv, RCAR_CAN_MCTL(mbx));
> + /* Bits SENTDATA and TRMREQ cannot be
> + * set to 0 simultaneously
> + */
> + mctl &= ~MCTL_TRMREQ;
> + rcar_can_writeb(priv, RCAR_CAN_MCTL(mbx), mctl);
> + mctl &= ~MCTL_SENTDATA;
> + /* Clear interrupt */
> + rcar_can_writeb(priv, RCAR_CAN_MCTL(mbx), mctl);
Can you combine both writes to RCAR_CAN_MCTL(mbx) or does the hardware
require two separate writes?
> + ie_mask |= BIT(mbx - FIRST_TX_MB);
> + stats->tx_bytes += can_get_echo_skb(ndev,
> + mbx - FIRST_TX_MB);
Can you guarantee that you call can_get_echo_skb in the same order the
frames get send?
> + stats->tx_packets++;
> + can_led_event(ndev, CAN_LED_EVENT_TX);
> + }
> + /* Set receive mailbox search mode */
> + rcar_can_writeb(priv, RCAR_CAN_MSMR, MSMR_RXMB);
> + /* Disable mailbox interrupt, mark mailbox as free */
> + if (ie_mask) {
> + u32 mier1;
> +
> + spin_lock(&priv->mier_lock);
> + mier1 = rcar_can_readl(priv, RCAR_CAN_MIER1);
> + rcar_can_writel(priv, RCAR_CAN_MIER1, mier1 & ~ie_mask);
> + spin_unlock(&priv->mier_lock);
> + if (unlikely(netif_queue_stopped(ndev)))
> + netif_wake_queue(ndev);
You can call netif_wake_queue() unconditionally, it does the check for
queue stopped anyway.
> + }
> + }
> + if (isr & ISR_RXM1F) {
> + if (napi_schedule_prep(&priv->napi)) {
> + /* Disable Rx interrupts */
> + rcar_can_writeb(priv, RCAR_CAN_IER,
> + rcar_can_readb(priv, RCAR_CAN_IER) &
> + ~IER_RXM1IE);
> + __napi_schedule(&priv->napi);
> + }
> + }
> + return IRQ_HANDLED;
Do not return IRQ_HANDLED unconditionally. You should return IRQ_HANDLED
only if there really was a interrupt for your device.
> +}
> +
> +static int rcar_can_set_bittiming(struct net_device *dev)
> +{
> + struct rcar_can_priv *priv = netdev_priv(dev);
> + struct can_bittiming *bt = &priv->can.bittiming;
> + u32 bcr;
> + u16 ctlr;
> + u8 clkr;
> +
> + ctlr = rcar_can_readw(priv, RCAR_CAN_CTLR);
> + if (ctlr & CTLR_SLPM) {
> + /* Write to BCR in CAN reset mode or CAN halt mode */
> + return -EBUSY;
The framework guarantees that set_bittiming is only called when the
interface is down.
> + }
> + /* Don't overwrite CLKR with 32-bit BCR access */
> + /* CLKR has 8-bit access */
> + clkr = rcar_can_readb(priv, RCAR_CAN_CLKR);
> + bcr = BCR_TSEG1(bt->phase_seg1 + bt->prop_seg - 1) |
> + BCR_BPR(bt->brp - 1) | BCR_SJW(bt->sjw - 1) |
> + BCR_TSEG2(bt->phase_seg2 - 1);
> + rcar_can_writel(priv, RCAR_CAN_BCR, bcr);
> + rcar_can_writeb(priv, RCAR_CAN_CLKR, clkr);
> + return 0;
> +}
> +
> +static void rcar_can_start(struct net_device *ndev)
> +{
> + struct rcar_can_priv *priv = netdev_priv(ndev);
> + u16 ctlr, n;
> +
> + /* Set controller to known mode:
> + * - normal mailbox mode (no FIFO);
Does the controller support FIFO?
> + * - accept all messages (no filter).
> + * CAN is in sleep mode after MCU hardware or software reset.
> + */
> + ctlr = rcar_can_readw(priv, RCAR_CAN_CTLR);
> + ctlr &= ~CTLR_SLPM;
> + rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
> + /* Go to reset mode */
> + ctlr |= CTLR_FORCE_RESET;
> + rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
> + ctlr |= CTLR_IDFM_MIXED; /* Select mixed ID mode */
> + ctlr &= ~CTLR_TPM; /* Set ID priority transmit mode */
> + rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
> +
> + rcar_can_writeb(priv, RCAR_CAN_CLKR, priv->clock_select);
> +
> + /* Accept all SID and EID */
> + for (n = 0; n < N_RX_MKREGS; n++)
> + rcar_can_writel(priv, RCAR_CAN_MKR(n), 0);
> + rcar_can_writel(priv, RCAR_CAN_MKIVLR0, 0);
> +
> + rcar_can_set_bittiming(ndev);
> +
> + /* Initial value of MIER1 undefined. Mark all Tx mailboxes as free. */
> + rcar_can_writel(priv, RCAR_CAN_MIER1, 0);
> +
> + rcar_can_writeb(priv, RCAR_CAN_IER, IER_TXMIE | IER_ERSIE | IER_RXM1IE);
> +
> + /* Accumulate error codes */
> + rcar_can_writeb(priv, RCAR_CAN_ECSR, ECSR_EDPM);
> + /* Enable error interrupts */
> + rcar_can_writeb(priv, RCAR_CAN_EIER,
> + EIER_EWIE | EIER_EPIE | EIER_BOEIE | EIER_BEIE |
> + EIER_ORIE | EIER_OLIE);
> + /* Enable interrupts for RX mailboxes */
> + rcar_can_writel(priv, RCAR_CAN_MIER0, RX_MBX_MASK);
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> +
> + /* Write to the CiMCTLj register in CAN
> + * operation mode or CAN halt mode.
> + * Configure mailboxes 0-31 as Rx mailboxes.
> + * Configure mailboxes 32-63 as Tx mailboxes.
> + */
> + /* Go to halt mode */
> + ctlr |= CTLR_HALT;
> + ctlr &= ~CTLR_RESET;
> + rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
> + for (n = 0; n < FIRST_TX_MB; n++) {
> + /* According to documentation we should clear MCTL
> + * register before configuring mailbox.
> + */
> + rcar_can_writeb(priv, RCAR_CAN_MCTL(n), 0);
> + rcar_can_writeb(priv, RCAR_CAN_MCTL(n), MCTL_RECREQ);
> + rcar_can_writeb(priv, RCAR_CAN_MCTL(FIRST_TX_MB + n), 0);
> + }
> + /* Go to operation mode */
> + rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr & ~CTLR_FORCE_RESET);
> +}
> +
> +static int rcar_can_open(struct net_device *ndev)
> +{
> + struct rcar_can_priv *priv = netdev_priv(ndev);
> + int err;
> +
> + err = open_candev(ndev);
> + if (err) {
> + netdev_err(ndev, "open_candev() failed %d\n", err);
> + goto out;
> + }
> + napi_enable(&priv->napi);
> + err = request_irq(ndev->irq, rcar_can_interrupt, 0, ndev->name, ndev);
> + if (err) {
> + netdev_err(ndev, "error requesting interrupt %x\n", ndev->irq);
> + goto out_close;
> + }
> + can_led_event(ndev, CAN_LED_EVENT_OPEN);
> + rcar_can_start(ndev);
> + netif_start_queue(ndev);
> + return 0;
> +out_close:
> + napi_disable(&priv->napi);
> + close_candev(ndev);
> +out:
> + return err;
> +}
> +
> +static void rcar_can_stop(struct net_device *ndev)
> +{
> + struct rcar_can_priv *priv = netdev_priv(ndev);
> + u16 ctlr;
> +
> + /* Go to (force) reset mode */
> + ctlr = rcar_can_readw(priv, RCAR_CAN_CTLR);
> + rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr | CTLR_FORCE_RESET);
> + rcar_can_writel(priv, RCAR_CAN_MIER0, 0);
> + rcar_can_writel(priv, RCAR_CAN_MIER1, 0);
> + rcar_can_writeb(priv, RCAR_CAN_IER, 0);
> + rcar_can_writeb(priv, RCAR_CAN_EIER, 0);
> + priv->can.state = CAN_STATE_STOPPED;
> +}
> +
> +static int rcar_can_close(struct net_device *ndev)
> +{
> + struct rcar_can_priv *priv = netdev_priv(ndev);
> +
> + netif_stop_queue(ndev);
> + rcar_can_stop(ndev);
> + free_irq(ndev->irq, ndev);
> + napi_disable(&priv->napi);
> + close_candev(ndev);
> + can_led_event(ndev, CAN_LED_EVENT_STOP);
> + return 0;
> +}
> +
> +static netdev_tx_t rcar_can_start_xmit(struct sk_buff *skb,
> + struct net_device *ndev)
> +{
> + struct rcar_can_priv *priv = netdev_priv(ndev);
> + struct can_frame *cf = (struct can_frame *)skb->data;
> + u32 data, mier1, mbxno, i;
> + unsigned long flags;
> + u8 mctl;
> +
> + if (can_dropped_invalid_skb(ndev, skb))
> + return NETDEV_TX_OK;
> +
> + spin_lock_irqsave(&priv->mier_lock, flags);
> + mier1 = rcar_can_readl(priv, RCAR_CAN_MIER1);
> + if (unlikely(mier1 == ~0U)) {
> + spin_unlock_irqrestore(&priv->mier_lock, flags);
> + netif_stop_queue(ndev);
> + return NETDEV_TX_BUSY;
> + }
> + rcar_can_writel(priv, RCAR_CAN_MIER1, mier1 | (mier1 + 1));
> + spin_unlock_irqrestore(&priv->mier_lock, flags);
> + mbxno = ffz(mier1) + FIRST_TX_MB;
This smells fishy, for several reasons:
The driver should guarantee that the frames are send in the same order
as this function is called. If you pick the first free mailbox I suspect
the hardware send the first mailbox ready to send. I don't know the
hardware, but several CAN controllers I've worked with, function in that
way.
Then you should rethink your flow control. You should call
netif_stop_queue if all your hardware buffers are full, then the above
NETDEV_TX_BUSY should not happen.
> +
> + if (cf->can_id & CAN_EFF_FLAG) {
> + /* Extended frame format */
> + data = (cf->can_id & CAN_EFF_MASK) | RCAR_CAN_IDE;
> + } else {
> + /* Standard frame format */
> + data = (cf->can_id & CAN_SFF_MASK) << RCAR_CAN_SID_SHIFT;
> + }
> + if (cf->can_id & CAN_RTR_FLAG) {
> + /* Remote transmission request */
> + data |= RCAR_CAN_RTR;
> + }
> + rcar_can_mbx_writel(priv, mbxno, MBX_HDR_OFFSET, data);
> +
> + rcar_can_mbx_writeb(priv, mbxno, MBX_DLC_OFFSET, cf->can_dlc);
> +
> + for (i = 0; i < cf->can_dlc; i++)
> + rcar_can_mbx_writeb(priv, mbxno,
> + MBX_DATA_OFFSET + i, cf->data[i]);
> +
> + can_put_echo_skb(skb, ndev, mbxno - FIRST_TX_MB);
> +
> + rcar_can_writeb(priv, RCAR_CAN_IER,
> + rcar_can_readb(priv, RCAR_CAN_IER) | IER_TXMIE);
> +
> + mctl = rcar_can_readb(priv, RCAR_CAN_MCTL(mbxno));
Do you have to read mctl here?
> + if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
> + mctl |= MCTL_ONESHOT;
> + else
> + mctl &= ~MCTL_ONESHOT;
> + /* Start TX */
> + mctl |= MCTL_TRMREQ;
> + rcar_can_writeb(priv, RCAR_CAN_MCTL(mbxno), mctl);
> + return NETDEV_TX_OK;
> +}
> +
> +static const struct net_device_ops rcar_can_netdev_ops = {
> + .ndo_open = rcar_can_open,
> + .ndo_stop = rcar_can_close,
> + .ndo_start_xmit = rcar_can_start_xmit,
> +};
> +
> +static void rcar_can_rx_pkt(struct rcar_can_priv *priv, int mbx)
> +{
> + struct net_device_stats *stats = &priv->ndev->stats;
> + struct can_frame *cf;
> + struct sk_buff *skb;
> + u32 data;
> + u8 dlc;
> +
> + skb = alloc_can_skb(priv->ndev, &cf);
> + if (!skb) {
> + stats->rx_dropped++;
> + if (printk_ratelimit())
> + netdev_err(priv->ndev,
> + "%s: alloc_can_skb() failed\n", __func__);
> + return;
> + }
> +
> + data = rcar_can_mbx_readl(priv, mbx, MBX_HDR_OFFSET);
> + if (data & RCAR_CAN_IDE)
> + cf->can_id = (data & CAN_EFF_MASK) | CAN_EFF_FLAG;
> + else
> + cf->can_id = (data >> RCAR_CAN_SID_SHIFT) & CAN_SFF_MASK;
> + if (data & RCAR_CAN_RTR)
> + cf->can_id |= CAN_RTR_FLAG;
> +
> + dlc = rcar_can_mbx_readb(priv, mbx, MBX_DLC_OFFSET);
> + cf->can_dlc = get_can_dlc(dlc);
Please don't copy data on received RTR frames.
> + for (dlc = 0; dlc < cf->can_dlc; dlc++)
> + cf->data[dlc] = rcar_can_mbx_readb(priv, mbx,
> + MBX_DATA_OFFSET + dlc);
> +
> + can_led_event(priv->ndev, CAN_LED_EVENT_RX);
> +
> + netif_receive_skb(skb);
> + stats->rx_bytes += cf->can_dlc;
> + stats->rx_packets++;
> +}
> +
> +static int rcar_can_rx_poll(struct napi_struct *napi, int quota)
> +{
> + struct rcar_can_priv *priv = container_of(napi,
> + struct rcar_can_priv, napi);
> + u32 num_pkts = 0;
please make it an int
> +
> + /* Find mailbox */
> + while (1) {
please put the quota check into the while()
> + u8 mctl, mbx;
> +
> + mbx = rcar_can_readb(priv, RCAR_CAN_MSSR);
> + if (mbx & MSSR_SEST || num_pkts >= quota)
> + break;
> + mbx &= MSSR_MBNST;
> + mctl = rcar_can_readb(priv, RCAR_CAN_MCTL(mbx));
> + /* Clear interrupt */
> + rcar_can_writeb(priv, RCAR_CAN_MCTL(mbx),
> + mctl & ~MCTL_NEWDATA);
> + rcar_can_rx_pkt(priv, mbx);
Which instruction reenables the mailbox?
> + ++num_pkts;
> + }
> + /* All packets processed */
> + if (num_pkts < quota) {
> + u8 ier;
> +
> + napi_complete(napi);
> + ier = rcar_can_readb(priv, RCAR_CAN_IER);
> + rcar_can_writeb(priv, RCAR_CAN_IER, ier | IER_RXM1IE);
I the hardware doesn't modify the IER register, you can work on a shadow
copy and only write, but never need to read from the hardware.
> + }
> + return num_pkts;
> +}
> +
> +static int rcar_can_do_set_mode(struct net_device *ndev, enum can_mode mode)
> +{
> + switch (mode) {
> + case CAN_MODE_START:
> + rcar_can_start(ndev);
> + netif_wake_queue(ndev);
> + return 0;
> + default:
> + return -EOPNOTSUPP;
> + }
> +}
> +
> +static int rcar_can_get_berr_counter(const struct net_device *dev,
> + struct can_berr_counter *bec)
> +{
> + struct rcar_can_priv *priv = netdev_priv(dev);
> +
> + bec->txerr = rcar_can_readb(priv, RCAR_CAN_TECR);
> + bec->rxerr = rcar_can_readb(priv, RCAR_CAN_RECR);
> + return 0;
> +}
> +
> +static int rcar_can_probe(struct platform_device *pdev)
> +{
> + struct rcar_can_platform_data *pdata;
> + struct rcar_can_priv *priv;
> + struct net_device *ndev;
> + struct resource *mem;
> + void __iomem *addr;
> + int err = -ENODEV;
> + int irq;
> +
> + pdata = pdev->dev.platform_data;
please use dev_get_platdata()
> + if (!pdata) {
> + dev_err(&pdev->dev, "No platform data provided!\n");
> + goto fail;
> + }
> +
> + irq = platform_get_irq(pdev, 0);
> + if (!irq) {
> + dev_err(&pdev->dev, "No IRQ resource\n");
> + goto fail;
> + }
> +
> + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + addr = devm_ioremap_resource(&pdev->dev, mem);
> + if (IS_ERR(addr)) {
> + err = PTR_ERR(addr);
> + goto fail;
> + }
> +
> + ndev = alloc_candev(sizeof(struct rcar_can_priv), N_MBX - FIRST_TX_MB);
> + if (!ndev) {
> + dev_err(&pdev->dev, "alloc_candev failed\n");
> + err = -ENOMEM;
> + goto fail;
> + }
> +
> + priv = netdev_priv(ndev);
> +
> + priv->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(priv->clk)) {
> + err = PTR_ERR(priv->clk);
> + dev_err(&pdev->dev, "cannot get clock: %d\n", err);
> + goto fail_clk;
> + }
> + clk_enable(priv->clk);
You are missing the clock's prepare step. You should call
clk_prepare_enable(). Please move clock_prepare_enable() to the open()
(and the disable_unprepare() to the close() function) so tha the core is
not powered as long as the interface is down. You might have to enable
the clock in the rcar_can_get_berr_counter() as it may be called if the
interface is still down.
> +
> + ndev->netdev_ops = &rcar_can_netdev_ops;
> + ndev->irq = irq;
> + ndev->flags |= IFF_ECHO;
> + priv->ndev = ndev;
> + priv->reg_base = addr;
> + priv->clock_select = pdata->clock_select;
> + priv->can.clock.freq = clk_get_rate(priv->clk);
> + priv->can.bittiming_const = &rcar_can_bittiming_const;
> + priv->can.do_set_bittiming = rcar_can_set_bittiming;
No need to set this callback, as you're calling rcar_can_set_bittiming
explizidly.
> + priv->can.do_set_mode = rcar_can_do_set_mode;
> + priv->can.do_get_berr_counter = rcar_can_get_berr_counter;
> + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
> + CAN_CTRLMODE_ONE_SHOT;
You don't handle 3_SAMPLES. Have you tested your driver in ONE_SHOT
mode? How does the controller react if a frame cannot be send? Do you
clear the skb that has previously been can_put_echo_skb()?
> + platform_set_drvdata(pdev, ndev);
> + SET_NETDEV_DEV(ndev, &pdev->dev);
> + spin_lock_init(&priv->mier_lock);
> +
> + netif_napi_add(ndev, &priv->napi, rcar_can_rx_poll,
> + RCAR_CAN_NAPI_WEIGHT);
> + err = register_candev(ndev);
> + if (err) {
> + dev_err(&pdev->dev, "register_candev() failed\n");
> + goto fail_candev;
> + }
> +
> + devm_can_led_init(ndev);
> +
> + dev_info(&pdev->dev, "device registered (reg_base=%p, irq=%u)\n",
> + priv->reg_base, ndev->irq);
> +
> + return 0;
> +fail_candev:
> + netif_napi_del(&priv->napi);
> +fail_clk:
> + free_candev(ndev);
> +fail:
> + return err;
> +}
> +
> +static int rcar_can_remove(struct platform_device *pdev)
> +{
> + struct net_device *ndev = platform_get_drvdata(pdev);
> + struct rcar_can_priv *priv = netdev_priv(ndev);
> + u16 ctlr;
> +
> + unregister_candev(ndev);
> + netif_napi_del(&priv->napi);
> + /* Go to sleep mode */
> + ctlr = rcar_can_readw(priv, RCAR_CAN_CTLR);
> + rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr | CTLR_SLPM);
You should put the controller in to sleep mode in close()
> + clk_disable(priv->clk);
> + free_candev(ndev);
> + return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int rcar_can_suspend(struct device *dev)
> +{
> + struct net_device *ndev = dev_get_drvdata(dev);
> + struct rcar_can_priv *priv = netdev_priv(ndev);
> + u16 ctlr;
> +
> + if (netif_running(ndev)) {
> + netif_stop_queue(ndev);
> + netif_device_detach(ndev);
> + }
> + ctlr = rcar_can_readw(priv, RCAR_CAN_CTLR);
> + ctlr |= CTLR_HALT;
> + rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
> + ctlr |= CTLR_SLPM;
> + rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
> + priv->can.state = CAN_STATE_SLEEPING;
> +
> + clk_disable(priv->clk);
> + return 0;
> +}
> +
> +static int rcar_can_resume(struct device *dev)
> +{
> + struct net_device *ndev = dev_get_drvdata(dev);
> + struct rcar_can_priv *priv = netdev_priv(ndev);
> + u16 ctlr;
> +
> + clk_enable(priv->clk);
> +
> + ctlr = rcar_can_readw(priv, RCAR_CAN_CTLR);
> + ctlr &= ~CTLR_SLPM;
> + rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
> + ctlr &= ~CTLR_FORCE_RESET;
> + rcar_can_writew(priv, RCAR_CAN_CTLR, ctlr);
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> +
> + if (netif_running(ndev)) {
> + netif_device_attach(ndev);
> + netif_start_queue(ndev);
> + }
> + return 0;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(rcar_can_pm_ops, rcar_can_suspend, rcar_can_resume);
> +
> +static struct platform_driver rcar_can_driver = {
> + .driver = {
> + .name = DRV_NAME,
> + .owner = THIS_MODULE,
> + .pm = &rcar_can_pm_ops,
> + },
> + .probe = rcar_can_probe,
> + .remove = rcar_can_remove,
> +};
> +
> +module_platform_driver(rcar_can_driver);
> +
> +MODULE_AUTHOR("Cogent Embedded, Inc.");
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("CAN driver for Renesas R-Car SoC");
> +MODULE_ALIAS("platform:" DRV_NAME);
> Index: linux-can-next/include/linux/can/platform/rcar_can.h
> ===================================================================
> --- /dev/null
> +++ linux-can-next/include/linux/can/platform/rcar_can.h
> @@ -0,0 +1,15 @@
> +#ifndef _CAN_PLATFORM_RCAR_CAN_H_
> +#define _CAN_PLATFORM_RCAR_CAN_H_
> +
> +#include <linux/types.h>
> +
> +/* Clock Select Register settings */
> +#define CLKR_CLKEXT 3 /* Externally input clock */
> +#define CLKR_CLKP2 1 /* Peripheral clock (clkp2) */
> +#define CLKR_CLKP1 0 /* Peripheral clock (clkp1) */
Can this be handled by the clock framework and or Device Tree?
> +
> +struct rcar_can_platform_data {
> + u8 clock_select; /* Clock source select */
> +};
> +
> +#endif /* !_CAN_PLATFORM_RCAR_CAN_H_ */
> --
> To unsubscribe from this list: send the line "unsubscribe linux-can" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
Marc
--
Pengutronix e.K. | Marc Kleine-Budde |
Industrial Linux Solutions | Phone: +49-231-2826-924 |
Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 259 bytes --]
^ permalink raw reply
* [PATCH net-next] include/linux/skbuff.h: move CONFIG_XFRM check inside the skb_sec_path()
From: Denis Kirjanov @ 2013-09-29 14:07 UTC (permalink / raw)
To: netdev, davem; +Cc: Denis Kirjanov
And thus we have only one function definition
Signed-off-by: Denis Kirjanov <kda@linux-powerpc.org>
---
include/linux/skbuff.h | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 2ddb48d..7399045 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2736,17 +2736,14 @@ extern u16 __skb_tx_hash(const struct net_device *dev,
const struct sk_buff *skb,
unsigned int num_tx_queues);
-#ifdef CONFIG_XFRM
static inline struct sec_path *skb_sec_path(struct sk_buff *skb)
{
+#ifdef CONFIG_XFRM
return skb->sp;
-}
#else
-static inline struct sec_path *skb_sec_path(struct sk_buff *skb)
-{
return NULL;
-}
#endif
+}
/* Keeps track of mac header offset relative to skb->head.
* It is useful for TSO of Tunneling protocol. e.g. GRE.
--
1.8.0.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox