* [PATCH] net/can: add driver for mscan family & mpc52xx_mscan
From: Wolfram Sang @ 2009-11-13 16:14 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA
Cc: Grant Likely, socketcan-core-0fE9KPoRgkgATYTw5x5z8w,
linuxppc-dev-mnsaURCQ41sdnm+yROfE0A, David Miller,
Wolfgang Grandegger
Taken from socketcan-svn, fixed remaining todos, cleaned up, tested with a
phyCORE-MPC5200B-IO and a custom board.
Signed-off-by: Wolfram Sang <w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Cc: Wolfgang Grandegger <wg-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
Cc: Grant Likely <grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org>
Cc: David Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
---
This patch is based on net-next as of yesterday.
To make the review easier for those who are already familiar with earlier
versions of this driver (especially for Wolfgang), I put my development branch
online, so you can check my changes incrementally:
http://git.pengutronix.de/?p=wsa/linux-2.6.git;a=summary
Documentation/powerpc/dts-bindings/fsl/mpc5200.txt | 9 +
drivers/net/can/Kconfig | 19 +
drivers/net/can/Makefile | 1 +
drivers/net/can/mscan/Makefile | 5 +
drivers/net/can/mscan/mpc52xx_can.c | 279 ++++++++
drivers/net/can/mscan/mscan.c | 699 ++++++++++++++++++++
drivers/net/can/mscan/mscan.h | 262 ++++++++
7 files changed, 1274 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/can/mscan/Makefile
create mode 100644 drivers/net/can/mscan/mpc52xx_can.c
create mode 100644 drivers/net/can/mscan/mscan.c
create mode 100644 drivers/net/can/mscan/mscan.h
diff --git a/Documentation/powerpc/dts-bindings/fsl/mpc5200.txt b/Documentation/powerpc/dts-bindings/fsl/mpc5200.txt
index 8447fd7..b151fb1 100644
--- a/Documentation/powerpc/dts-bindings/fsl/mpc5200.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/mpc5200.txt
@@ -178,3 +178,12 @@ External interrupts:
external irq3: interrupts = <1 3 n>;
'n' is sense (0: level high, 1: edge rising, 2: edge falling 3: level low)
+fsl,mpc5200-mscan nodes
+-----------------------
+In addition to the required compatible-, reg- and interrupt-properites, you can
+also specify which clock shall be used for the bus:
+
+- fsl,mscan-clk-src - a string describing the clock source. Valid values
+ are "ip" for IP_CLK and "sys" for SYS_XTAL.
+ "sys" is the default in case the property is not
+ present.
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index b819cc2..c16e6ff 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -108,6 +108,25 @@ config CAN_MCP251X
---help---
Driver for the Microchip MCP251x SPI CAN controllers.
+config CAN_MSCAN
+ depends on CAN_DEV && (PPC || M68K || M68KNOMMU)
+ tristate "Support for Freescale MSCAN based chips"
+ ---help---
+ The Motorola Scalable Controller Area Network (MSCAN) definition
+ is based on the MSCAN12 definition which is the specific
+ implementation of the Motorola Scalable CAN concept targeted for
+ the Motorola MC68HC12 Microcontroller Family.
+
+config CAN_MPC52XX
+ tristate "Freescale MPC5xxx onboard CAN controller"
+ depends on CAN_MSCAN && PPC_MPC52xx
+ ---help---
+ If you say yes here you get support for Freescale's MPC52xx
+ onboard dualCAN controller.
+
+ This driver can also be built as a module. If so, the module
+ will be called mpc5xxx_can.
+
config CAN_DEBUG_DEVICES
bool "CAN devices debugging messages"
depends on CAN
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 1489181..56899fe 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -10,6 +10,7 @@ can-dev-y := dev.o
obj-y += usb/
obj-$(CONFIG_CAN_SJA1000) += sja1000/
+obj-$(CONFIG_CAN_MSCAN) += mscan/
obj-$(CONFIG_CAN_AT91) += at91_can.o
obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o
obj-$(CONFIG_CAN_MCP251X) += mcp251x.o
diff --git a/drivers/net/can/mscan/Makefile b/drivers/net/can/mscan/Makefile
new file mode 100644
index 0000000..2bd9f04
--- /dev/null
+++ b/drivers/net/can/mscan/Makefile
@@ -0,0 +1,5 @@
+
+obj-$(CONFIG_CAN_MPC52XX) += mscan-mpc52xx.o
+mscan-mpc52xx-objs := mscan.o mpc52xx_can.o
+
+ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/mscan/mpc52xx_can.c b/drivers/net/can/mscan/mpc52xx_can.c
new file mode 100644
index 0000000..4707a82
--- /dev/null
+++ b/drivers/net/can/mscan/mpc52xx_can.c
@@ -0,0 +1,279 @@
+/*
+ * CAN bus driver for the Freescale MPC5xxx embedded CPU.
+ *
+ * Copyright (C) 2004-2005 Andrey Volkov <avolkov-ppI4tVfbJvJWk0Htik3J/w@public.gmane.org>,
+ * Varma Electronics Oy
+ * Copyright (C) 2008-2009 Wolfgang Grandegger <wg-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
+ * Copyright (C) 2009 Wolfram Sang, Pengutronix <w.sang-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/of_platform.h>
+#include <sysdev/fsl_soc.h>
+#include <linux/io.h>
+#include <asm/mpc52xx.h>
+
+#include "mscan.h"
+
+
+#define DRV_NAME "mpc5xxx_can"
+
+static struct of_device_id mpc52xx_cdm_ids[] __devinitdata = {
+ { .compatible = "fsl,mpc5200-cdm", },
+ { .compatible = "fsl,mpc5200b-cdm", },
+ {}
+};
+
+/*
+ * Get the frequency of the external oscillator clock connected
+ * to the SYS_XTAL_IN pin, or return 0 if it cannot be determined.
+ */
+static unsigned int __devinit mpc52xx_can_xtal_freq(struct of_device *of)
+{
+ struct mpc52xx_cdm __iomem *cdm;
+ struct device_node *np_cdm;
+ unsigned int freq;
+ u32 val;
+
+ freq = mpc5xxx_get_bus_frequency(of->node);
+ if (!freq)
+ return 0;
+
+ /*
+ * Determine SYS_XTAL_IN frequency from the clock domain settings
+ */
+ np_cdm = of_find_matching_node(NULL, mpc52xx_cdm_ids);
+ if (!np_cdm) {
+ dev_err(&of->dev, "can't get clock node!\n");
+ return 0;
+ }
+ cdm = of_iomap(np_cdm, 0);
+ of_node_put(np_cdm);
+
+ if (in_8(&cdm->ipb_clk_sel) & 0x1)
+ freq *= 2;
+ val = in_be32(&cdm->rstcfg);
+ if (val & (1 << 5))
+ freq *= 8;
+ else
+ freq *= 4;
+ if (val & (1 << 6))
+ freq /= 12;
+ else
+ freq /= 16;
+
+ iounmap(cdm);
+
+ return freq;
+}
+
+/*
+ * Get frequency of the MSCAN clock source
+ *
+ * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock (IP_CLK)
+ * can be selected. According to the MPC5200 user's manual, the oscillator
+ * clock is the better choice as it has less jitter but due to a hardware
+ * bug, it can not be selected for the old MPC5200 Rev. A chips.
+ */
+
+static unsigned int __devinit mpc52xx_can_clock_freq(struct of_device *of,
+ int clock_src)
+{
+ unsigned int pvr;
+
+ pvr = mfspr(SPRN_PVR);
+
+ if (clock_src == MSCAN_CLKSRC_BUS || pvr == 0x80822011)
+ return mpc5xxx_get_bus_frequency(of->node);
+
+ return mpc52xx_can_xtal_freq(of);
+}
+
+static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
+ const struct of_device_id *id)
+{
+ struct device_node *np = ofdev->node;
+ struct net_device *dev;
+ struct mscan_priv *priv;
+ void __iomem *base;
+ const char *clk_src;
+ int err, irq, clock_src;
+
+ base = of_iomap(ofdev->node, 0);
+ if (!base) {
+ dev_err(&ofdev->dev, "couldn't ioremap\n");
+ err = -ENOMEM;
+ goto exit_release_mem;
+ }
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq) {
+ dev_err(&ofdev->dev, "no irq found\n");
+ err = -ENODEV;
+ goto exit_unmap_mem;
+ }
+
+ dev = alloc_mscandev();
+ if (!dev) {
+ err = -ENOMEM;
+ goto exit_dispose_irq;
+ }
+
+ priv = netdev_priv(dev);
+ priv->reg_base = base;
+ dev->irq = irq;
+
+ /*
+ * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock
+ * (IP_CLK) can be selected as MSCAN clock source. According to
+ * the MPC5200 user's manual, the oscillator clock is the better
+ * choice as it has less jitter. For this reason, it is selected
+ * by default.
+ */
+ clk_src = of_get_property(np, "fsl,mscan-clk-src", NULL);
+ if (clk_src && strcmp(clk_src, "ip") == 0)
+ clock_src = MSCAN_CLKSRC_BUS;
+ else
+ clock_src = MSCAN_CLKSRC_XTAL;
+ priv->can.clock.freq = mpc52xx_can_clock_freq(ofdev, clock_src);
+ if (!priv->can.clock.freq) {
+ dev_err(&ofdev->dev, "couldn't get MSCAN clock frequency\n");
+ err = -ENODEV;
+ goto exit_free_mscan;
+ }
+
+ SET_NETDEV_DEV(dev, &ofdev->dev);
+
+ err = register_mscandev(dev, clock_src);
+ if (err) {
+ dev_err(&ofdev->dev, "registering %s failed (err=%d)\n",
+ DRV_NAME, err);
+ goto exit_free_mscan;
+ }
+
+ dev_set_drvdata(&ofdev->dev, dev);
+
+ dev_info(&ofdev->dev, "MSCAN at 0x%p, irq %d, clock %d Hz\n",
+ priv->reg_base, dev->irq, priv->can.clock.freq);
+
+ return 0;
+
+exit_free_mscan:
+ free_candev(dev);
+exit_dispose_irq:
+ irq_dispose_mapping(irq);
+exit_unmap_mem:
+ iounmap(base);
+exit_release_mem:
+ return err;
+}
+
+static int __devexit mpc5xxx_can_remove(struct of_device *ofdev)
+{
+ struct net_device *dev = dev_get_drvdata(&ofdev->dev);
+ struct mscan_priv *priv = netdev_priv(dev);
+
+ dev_set_drvdata(&ofdev->dev, NULL);
+
+ unregister_mscandev(dev);
+ iounmap(priv->reg_base);
+ irq_dispose_mapping(dev->irq);
+ free_candev(dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static struct mscan_regs saved_regs;
+static int mpc5xxx_can_suspend(struct of_device *ofdev, pm_message_t state)
+{
+ struct net_device *dev = dev_get_drvdata(&ofdev->dev);
+ struct mscan_priv *priv = netdev_priv(dev);
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+
+ _memcpy_fromio(&saved_regs, regs, sizeof(*regs));
+
+ return 0;
+}
+
+static int mpc5xxx_can_resume(struct of_device *ofdev)
+{
+ struct net_device *dev = dev_get_drvdata(&ofdev->dev);
+ struct mscan_priv *priv = netdev_priv(dev);
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+
+ regs->canctl0 |= MSCAN_INITRQ;
+ while ((regs->canctl1 & MSCAN_INITAK) == 0)
+ udelay(10);
+
+ regs->canctl1 = saved_regs.canctl1;
+ regs->canbtr0 = saved_regs.canbtr0;
+ regs->canbtr1 = saved_regs.canbtr1;
+ regs->canidac = saved_regs.canidac;
+
+ /* restore masks, buffers etc. */
+ _memcpy_toio(®s->canidar1_0, (void *)&saved_regs.canidar1_0,
+ sizeof(*regs) - offsetof(struct mscan_regs, canidar1_0));
+
+ regs->canctl0 &= ~MSCAN_INITRQ;
+ regs->cantbsel = saved_regs.cantbsel;
+ regs->canrier = saved_regs.canrier;
+ regs->cantier = saved_regs.cantier;
+ regs->canctl0 = saved_regs.canctl0;
+
+ return 0;
+}
+#endif
+
+static struct of_device_id __devinitdata mpc5xxx_can_table[] = {
+ {.compatible = "fsl,mpc5200-mscan"},
+ {.compatible = "fsl,mpc5200b-mscan"},
+ {},
+};
+
+static struct of_platform_driver mpc5xxx_can_driver = {
+ .owner = THIS_MODULE,
+ .name = "mpc5xxx_can",
+ .probe = mpc5xxx_can_probe,
+ .remove = __devexit_p(mpc5xxx_can_remove),
+#ifdef CONFIG_PM
+ .suspend = mpc5xxx_can_suspend,
+ .resume = mpc5xxx_can_resume,
+#endif
+ .match_table = mpc5xxx_can_table,
+};
+
+static int __init mpc5xxx_can_init(void)
+{
+ return of_register_platform_driver(&mpc5xxx_can_driver);
+}
+module_init(mpc5xxx_can_init);
+
+static void __exit mpc5xxx_can_exit(void)
+{
+ return of_unregister_platform_driver(&mpc5xxx_can_driver);
+};
+module_exit(mpc5xxx_can_exit);
+
+MODULE_AUTHOR("Wolfgang Grandegger <wg-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>");
+MODULE_DESCRIPTION("Freescale MPC5200 CAN driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/can/mscan/mscan.c b/drivers/net/can/mscan/mscan.c
new file mode 100644
index 0000000..49542ca
--- /dev/null
+++ b/drivers/net/can/mscan/mscan.c
@@ -0,0 +1,699 @@
+/*
+ * CAN bus driver for the alone generic (as possible as) MSCAN controller.
+ *
+ * Copyright (C) 2005-2006 Andrey Volkov <avolkov-ppI4tVfbJvJWk0Htik3J/w@public.gmane.org>,
+ * Varma Electronics Oy
+ * Copyright (C) 2008-2009 Wolfgang Grandegger <wg-5Yr1BZd7O62+XT7JhA+gdA@public.gmane.org>
+ * Copytight (C) 2008-2009 Pengutronix <kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/list.h>
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+#include <linux/io.h>
+
+#include "mscan.h"
+
+#define MSCAN_NORMAL_MODE 0
+#define MSCAN_SLEEP_MODE MSCAN_SLPRQ
+#define MSCAN_INIT_MODE (MSCAN_INITRQ | MSCAN_SLPRQ)
+#define MSCAN_POWEROFF_MODE (MSCAN_CSWAI | MSCAN_SLPRQ)
+#define MSCAN_SET_MODE_RETRIES 255
+#define MSCAN_ECHO_SKB_MAX 3
+
+#define BTR0_BRP_MASK 0x3f
+#define BTR0_SJW_SHIFT 6
+#define BTR0_SJW_MASK (0x3 << BTR0_SJW_SHIFT)
+
+#define BTR1_TSEG1_MASK 0xf
+#define BTR1_TSEG2_SHIFT 4
+#define BTR1_TSEG2_MASK (0x7 << BTR1_TSEG2_SHIFT)
+#define BTR1_SAM_SHIFT 7
+
+#define BTR0_SET_BRP(brp) (((brp) - 1) & BTR0_BRP_MASK)
+#define BTR0_SET_SJW(sjw) ((((sjw) - 1) << BTR0_SJW_SHIFT) & \
+ BTR0_SJW_MASK)
+
+#define BTR1_SET_TSEG1(tseg1) (((tseg1) - 1) & BTR1_TSEG1_MASK)
+#define BTR1_SET_TSEG2(tseg2) ((((tseg2) - 1) << BTR1_TSEG2_SHIFT) & \
+ BTR1_TSEG2_MASK)
+#define BTR1_SET_SAM(sam) ((sam) ? 1 << BTR1_SAM_SHIFT : 0)
+
+static struct can_bittiming_const mscan_bittiming_const = {
+ .name = "mscan",
+ .tseg1_min = 4,
+ .tseg1_max = 16,
+ .tseg2_min = 2,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 64,
+ .brp_inc = 1,
+};
+
+struct mscan_state {
+ u8 mode;
+ u8 canrier;
+ u8 cantier;
+};
+
+#define F_RX_PROGRESS 0
+#define F_TX_PROGRESS 1
+#define F_TX_WAIT_ALL 2
+
+static enum can_state state_map[] = {
+ CAN_STATE_ERROR_ACTIVE,
+ CAN_STATE_ERROR_WARNING,
+ CAN_STATE_ERROR_PASSIVE,
+ CAN_STATE_BUS_OFF
+};
+
+static int mscan_set_mode(struct net_device *dev, u8 mode)
+{
+ struct mscan_priv *priv = netdev_priv(dev);
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ int ret = 0;
+ int i;
+ u8 canctl1;
+
+ if (mode != MSCAN_NORMAL_MODE) {
+
+ if (priv->tx_active) {
+ /* Abort transfers before going to sleep */#
+ out_8(®s->cantarq, priv->tx_active);
+ /* Suppress TX done interrupts */
+ out_8(®s->cantier, 0);
+ }
+
+ canctl1 = in_8(®s->canctl1);
+ if ((mode & MSCAN_SLPRQ) && (canctl1 & MSCAN_SLPAK) == 0) {
+ out_8(®s->canctl0,
+ in_8(®s->canctl0) | MSCAN_SLPRQ);
+ for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) {
+ if (in_8(®s->canctl1) & MSCAN_SLPAK)
+ break;
+ udelay(100);
+ }
+ /*
+ * The mscan controller will fail to enter sleep mode,
+ * while there are irregular activities on bus, like
+ * somebody keeps retransmitting. This behavior is
+ * undocumented and seems to differ between mscan built
+ * in mpc5200b and mpc5200. We proceed in that case,
+ * since otherwise the slprq will be kept set and the
+ * controller will get stuck. NOTE: INITRQ or CSWAI
+ * will abort all active transmit actions, if still
+ * any, at once.
+ */
+ if (i >= MSCAN_SET_MODE_RETRIES)
+ dev_dbg(dev->dev.parent,
+ "device failed to enter sleep mode. "
+ "We proceed anyhow.\n");
+ else
+ priv->can.state = CAN_STATE_SLEEPING;
+ }
+
+ if ((mode & MSCAN_INITRQ) && (canctl1 & MSCAN_INITAK) == 0) {
+ out_8(®s->canctl0,
+ in_8(®s->canctl0) | MSCAN_INITRQ);
+ for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) {
+ if (in_8(®s->canctl1) & MSCAN_INITAK)
+ break;
+ }
+ if (i >= MSCAN_SET_MODE_RETRIES)
+ ret = -ENODEV;
+ }
+ if (!ret)
+ priv->can.state = CAN_STATE_STOPPED;
+
+ if (mode & MSCAN_CSWAI)
+ out_8(®s->canctl0,
+ in_8(®s->canctl0) | MSCAN_CSWAI);
+
+ } else {
+ canctl1 = in_8(®s->canctl1);
+ if (canctl1 & (MSCAN_SLPAK | MSCAN_INITAK)) {
+ out_8(®s->canctl0, in_8(®s->canctl0) &
+ ~(MSCAN_SLPRQ | MSCAN_INITRQ));
+ for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) {
+ canctl1 = in_8(®s->canctl1);
+ if (!(canctl1 & (MSCAN_INITAK | MSCAN_SLPAK)))
+ break;
+ }
+ if (i >= MSCAN_SET_MODE_RETRIES)
+ ret = -ENODEV;
+ else
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ }
+ }
+ return ret;
+}
+
+static int mscan_start(struct net_device *dev)
+{
+ struct mscan_priv *priv = netdev_priv(dev);
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ u8 canrflg;
+ int err;
+
+ out_8(®s->canrier, 0);
+
+ INIT_LIST_HEAD(&priv->tx_head);
+ priv->prev_buf_id = 0;
+ priv->cur_pri = 0;
+ priv->tx_active = 0;
+ priv->shadow_canrier = 0;
+ priv->flags = 0;
+
+ err = mscan_set_mode(dev, MSCAN_NORMAL_MODE);
+ if (err)
+ return err;
+
+ canrflg = in_8(®s->canrflg);
+ priv->shadow_statflg = canrflg & MSCAN_STAT_MSK;
+ priv->can.state = state_map[max(MSCAN_STATE_RX(canrflg),
+ MSCAN_STATE_TX(canrflg))];
+ out_8(®s->cantier, 0);
+
+ /* Enable receive interrupts. */
+ out_8(®s->canrier, MSCAN_OVRIE | MSCAN_RXFIE | MSCAN_CSCIE |
+ MSCAN_RSTATE1 | MSCAN_RSTATE0 | MSCAN_TSTATE1 | MSCAN_TSTATE0);
+
+ return 0;
+}
+
+static netdev_tx_t mscan_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct can_frame *frame = (struct can_frame *)skb->data;
+ struct mscan_priv *priv = netdev_priv(dev);
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ int i, rtr, buf_id;
+ u32 can_id;
+
+ if (frame->can_dlc > 8)
+ return -EINVAL;
+
+ out_8(®s->cantier, 0);
+
+ i = ~priv->tx_active & MSCAN_TXE;
+ buf_id = ffs(i) - 1;
+ switch (hweight8(i)) {
+ case 0:
+ netif_stop_queue(dev);
+ dev_err(dev->dev.parent, "Tx Ring full when queue awake!\n");
+ return NETDEV_TX_BUSY;
+ case 1:
+ /*
+ * if buf_id < 3, then current frame will be send out of order,
+ * since buffer with lower id have higher priority (hell..)
+ */
+ netif_stop_queue(dev);
+ case 2:
+ if (buf_id < priv->prev_buf_id) {
+ priv->cur_pri++;
+ if (priv->cur_pri == 0xff) {
+ set_bit(F_TX_WAIT_ALL, &priv->flags);
+ netif_stop_queue(dev);
+ }
+ }
+ set_bit(F_TX_PROGRESS, &priv->flags);
+ break;
+ }
+ priv->prev_buf_id = buf_id;
+ out_8(®s->cantbsel, i);
+
+ rtr = frame->can_id & CAN_RTR_FLAG;
+
+ if (frame->can_id & CAN_EFF_FLAG) {
+ can_id = (frame->can_id & CAN_EFF_MASK) << 1;
+ if (rtr)
+ can_id |= 1;
+ out_be16(®s->tx.idr3_2, can_id);
+
+ can_id >>= 16;
+ can_id = (can_id & 0x7) | ((can_id << 2) & 0xffe0) | (3 << 3);
+ } else {
+ can_id = (frame->can_id & CAN_SFF_MASK) << 5;
+ if (rtr)
+ can_id |= 1 << 4;
+ }
+ out_be16(®s->tx.idr1_0, can_id);
+
+ if (!rtr) {
+ void __iomem *data = ®s->tx.dsr1_0;
+ u16 *payload = (u16 *) frame->data;
+ /* It is safe to write into dsr[dlc+1] */
+ for (i = 0; i < (frame->can_dlc + 1) / 2; i++) {
+ out_be16(data, *payload++);
+ data += 2 + _MSCAN_RESERVED_DSR_SIZE;
+ }
+ }
+
+ out_8(®s->tx.dlr, frame->can_dlc);
+ out_8(®s->tx.tbpr, priv->cur_pri);
+
+ /* Start transmission. */
+ out_8(®s->cantflg, 1 << buf_id);
+
+ if (!test_bit(F_TX_PROGRESS, &priv->flags))
+ dev->trans_start = jiffies;
+
+ list_add_tail(&priv->tx_queue[buf_id].list, &priv->tx_head);
+
+ can_put_echo_skb(skb, dev, buf_id);
+
+ /* Enable interrupt. */
+ priv->tx_active |= 1 << buf_id;
+ out_8(®s->cantier, priv->tx_active);
+
+ return NETDEV_TX_OK;
+}
+
+/* This function returns the old state to see where we came from */
+static enum can_state check_set_state(struct net_device *dev, u8 canrflg)
+{
+ struct mscan_priv *priv = netdev_priv(dev);
+ enum can_state state, old_state = priv->can.state;
+
+ if (canrflg & MSCAN_CSCIF && old_state <= CAN_STATE_BUS_OFF) {
+ state = state_map[max(MSCAN_STATE_RX(canrflg),
+ MSCAN_STATE_TX(canrflg))];
+ priv->can.state = state;
+ }
+ return old_state;
+}
+
+static void mscan_get_rx_frame(struct net_device *dev, struct can_frame *frame)
+{
+ struct mscan_priv *priv = netdev_priv(dev);
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ u32 can_id;
+ int i;
+
+ can_id = in_be16(®s->rx.idr1_0);
+ if (can_id & (1 << 3)) {
+ frame->can_id = CAN_EFF_FLAG;
+ can_id = ((can_id << 16) | in_be16(®s->rx.idr3_2));
+ can_id = ((can_id & 0xffe00000) |
+ ((can_id & 0x7ffff) << 2)) >> 2;
+ } else {
+ can_id >>= 4;
+ frame->can_id = 0;
+ }
+
+ frame->can_id |= can_id >> 1;
+ if (can_id & 1)
+ frame->can_id |= CAN_RTR_FLAG;
+ frame->can_dlc = in_8(®s->rx.dlr) & 0xf;
+
+ if (!(frame->can_id & CAN_RTR_FLAG)) {
+ void __iomem *data = ®s->rx.dsr1_0;
+ u16 *payload = (u16 *) frame->data;
+ for (i = 0; i < (frame->can_dlc + 1) / 2; i++) {
+ *payload++ = in_be16(data);
+ data += 2 + _MSCAN_RESERVED_DSR_SIZE;
+ }
+ }
+
+ out_8(®s->canrflg, MSCAN_RXF);
+}
+
+static void mscan_get_err_frame(struct net_device *dev, struct can_frame *frame,
+ u8 canrflg)
+{
+ struct mscan_priv *priv = netdev_priv(dev);
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct net_device_stats *stats = &dev->stats;
+ enum can_state old_state;
+
+ dev_dbg(dev->dev.parent, "error interrupt (canrflg=%#x)\n", canrflg);
+ frame->can_id = CAN_ERR_FLAG;
+
+ if (canrflg & MSCAN_OVRIF) {
+ frame->can_id |= CAN_ERR_CRTL;
+ frame->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+ stats->rx_over_errors++;
+ stats->rx_errors++;
+ } else
+ frame->data[1] = 0;
+
+ old_state = check_set_state(dev, canrflg);
+ /* State changed */
+ if (old_state != priv->can.state) {
+ switch (priv->can.state) {
+ case CAN_STATE_ERROR_WARNING:
+ frame->can_id |= CAN_ERR_CRTL;
+ priv->can.can_stats.error_warning++;
+ if ((priv->shadow_statflg & MSCAN_RSTAT_MSK) <
+ (canrflg & MSCAN_RSTAT_MSK))
+ frame->data[1] |= CAN_ERR_CRTL_RX_WARNING;
+
+ if ((priv->shadow_statflg & MSCAN_TSTAT_MSK) <
+ (canrflg & MSCAN_TSTAT_MSK))
+ frame->data[1] |= CAN_ERR_CRTL_TX_WARNING;
+ break;
+ case CAN_STATE_ERROR_PASSIVE:
+ frame->can_id |= CAN_ERR_CRTL;
+ priv->can.can_stats.error_passive++;
+ frame->data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+ break;
+ case CAN_STATE_BUS_OFF:
+ frame->can_id |= CAN_ERR_BUSOFF;
+ /*
+ * The MSCAN on the MPC5200 does recover from bus-off
+ * automatically. To avoid that we stop the chip doing
+ * a light-weight stop (we are in irq-context).
+ */
+ out_8(®s->cantier, 0);
+ out_8(®s->canrier, 0);
+ out_8(®s->canctl0, in_8(®s->canctl0) |
+ MSCAN_SLPRQ | MSCAN_INITRQ);
+ can_bus_off(dev);
+ break;
+ default:
+ break;
+ }
+ }
+ priv->shadow_statflg = canrflg & MSCAN_STAT_MSK;
+ frame->can_dlc = CAN_ERR_DLC;
+ out_8(®s->canrflg, MSCAN_ERR_IF);
+}
+
+static int mscan_rx_poll(struct napi_struct *napi, int quota)
+{
+ struct mscan_priv *priv = container_of(napi, struct mscan_priv, napi);
+ struct net_device *dev = napi->dev;
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct net_device_stats *stats = &dev->stats;
+ int npackets = 0;
+ int ret = 1;
+ struct sk_buff *skb;
+ struct can_frame *frame;
+ u8 canrflg;
+
+ while (npackets < quota && ((canrflg = in_8(®s->canrflg)) &
+ (MSCAN_RXF | MSCAN_ERR_IF))) {
+
+ skb = alloc_can_skb(dev, &frame);
+ if (!skb) {
+ if (printk_ratelimit())
+ dev_notice(dev->dev.parent, "packet dropped\n");
+ stats->rx_dropped++;
+ out_8(®s->canrflg, canrflg);
+ continue;
+ }
+
+ if (canrflg & MSCAN_RXF)
+ mscan_get_rx_frame(dev, frame);
+ else if (canrflg & MSCAN_ERR_IF)
+ mscan_get_err_frame(dev, frame, canrflg);
+
+ stats->rx_packets++;
+ stats->rx_bytes += frame->can_dlc;
+ npackets++;
+ netif_receive_skb(skb);
+ }
+
+ if (!(in_8(®s->canrflg) & (MSCAN_RXF | MSCAN_ERR_IF))) {
+ napi_complete(&priv->napi);
+ clear_bit(F_RX_PROGRESS, &priv->flags);
+ if (priv->can.state < CAN_STATE_BUS_OFF)
+ out_8(®s->canrier, priv->shadow_canrier);
+ ret = 0;
+ }
+ return ret;
+}
+
+static irqreturn_t mscan_isr(int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct mscan_priv *priv = netdev_priv(dev);
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct net_device_stats *stats = &dev->stats;
+ u8 cantier, cantflg, canrflg;
+ irqreturn_t ret = IRQ_NONE;
+
+ cantier = in_8(®s->cantier) & MSCAN_TXE;
+ cantflg = in_8(®s->cantflg) & cantier;
+
+ if (cantier && cantflg) {
+
+ struct list_head *tmp, *pos;
+
+ list_for_each_safe(pos, tmp, &priv->tx_head) {
+ struct tx_queue_entry *entry =
+ list_entry(pos, struct tx_queue_entry, list);
+ u8 mask = entry->mask;
+
+ if (!(cantflg & mask))
+ continue;
+
+ out_8(®s->cantbsel, mask);
+ stats->tx_bytes += in_8(®s->tx.dlr);
+ stats->tx_packets++;
+ can_get_echo_skb(dev, entry->id);
+ priv->tx_active &= ~mask;
+ list_del(pos);
+ }
+
+ if (list_empty(&priv->tx_head)) {
+ clear_bit(F_TX_WAIT_ALL, &priv->flags);
+ clear_bit(F_TX_PROGRESS, &priv->flags);
+ priv->cur_pri = 0;
+ } else
+ dev->trans_start = jiffies;
+
+ if (!test_bit(F_TX_WAIT_ALL, &priv->flags))
+ netif_wake_queue(dev);
+
+ out_8(®s->cantier, priv->tx_active);
+ ret = IRQ_HANDLED;
+ }
+
+ canrflg = in_8(®s->canrflg);
+ if ((canrflg & ~MSCAN_STAT_MSK) &&
+ !test_and_set_bit(F_RX_PROGRESS, &priv->flags)) {
+ if (canrflg & ~MSCAN_STAT_MSK) {
+ priv->shadow_canrier = in_8(®s->canrier);
+ out_8(®s->canrier, 0);
+ napi_schedule(&priv->napi);
+ ret = IRQ_HANDLED;
+ } else
+ clear_bit(F_RX_PROGRESS, &priv->flags);
+ }
+ return ret;
+}
+
+static int mscan_do_set_mode(struct net_device *dev, enum can_mode mode)
+{
+
+ struct mscan_priv *priv = netdev_priv(dev);
+ int ret = 0;
+
+ if (!priv->open_time)
+ return -EINVAL;
+
+ switch (mode) {
+ case CAN_MODE_SLEEP:
+ case CAN_MODE_STOP:
+ netif_stop_queue(dev);
+ mscan_set_mode(dev,
+ (mode ==
+ CAN_MODE_STOP) ? MSCAN_INIT_MODE :
+ MSCAN_SLEEP_MODE);
+ break;
+ case CAN_MODE_START:
+ if (priv->can.state <= CAN_STATE_BUS_OFF)
+ mscan_set_mode(dev, MSCAN_INIT_MODE);
+ ret = mscan_start(dev);
+ if (ret)
+ break;
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+ break;
+
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ return ret;
+}
+
+static int mscan_do_set_bittiming(struct net_device *dev)
+{
+ struct mscan_priv *priv = netdev_priv(dev);
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ struct can_bittiming *bt = &priv->can.bittiming;
+ u8 btr0, btr1;
+
+ btr0 = BTR0_SET_BRP(bt->brp) | BTR0_SET_SJW(bt->sjw);
+ btr1 = (BTR1_SET_TSEG1(bt->prop_seg + bt->phase_seg1) |
+ BTR1_SET_TSEG2(bt->phase_seg2) |
+ BTR1_SET_SAM(priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES));
+
+ dev_info(dev->dev.parent, "setting BTR0=0x%02x BTR1=0x%02x\n",
+ btr0, btr1);
+
+ out_8(®s->canbtr0, btr0);
+ out_8(®s->canbtr1, btr1);
+
+ return 0;
+}
+
+static int mscan_open(struct net_device *dev)
+{
+ int ret;
+ struct mscan_priv *priv = netdev_priv(dev);
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+
+ /* common open */
+ ret = open_candev(dev);
+ if (ret)
+ return ret;
+
+ napi_enable(&priv->napi);
+
+ ret = request_irq(dev->irq, mscan_isr, 0, dev->name, dev);
+ if (ret < 0) {
+ napi_disable(&priv->napi);
+ printk(KERN_ERR "%s - failed to attach interrupt\n",
+ dev->name);
+ return ret;
+ }
+
+ priv->open_time = jiffies;
+
+ out_8(®s->canctl1, in_8(®s->canctl1) & ~MSCAN_LISTEN);
+
+ ret = mscan_start(dev);
+ if (ret)
+ return ret;
+
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static int mscan_close(struct net_device *dev)
+{
+ struct mscan_priv *priv = netdev_priv(dev);
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+
+ netif_stop_queue(dev);
+ napi_disable(&priv->napi);
+
+ out_8(®s->cantier, 0);
+ out_8(®s->canrier, 0);
+ mscan_set_mode(dev, MSCAN_INIT_MODE);
+ close_candev(dev);
+ free_irq(dev->irq, dev);
+ priv->open_time = 0;
+
+ return 0;
+}
+
+static const struct net_device_ops mscan_netdev_ops = {
+ .ndo_open = mscan_open,
+ .ndo_stop = mscan_close,
+ .ndo_start_xmit = mscan_start_xmit,
+};
+
+int register_mscandev(struct net_device *dev, int clock_src)
+{
+ struct mscan_priv *priv = netdev_priv(dev);
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ u8 ctl1;
+
+ ctl1 = in_8(®s->canctl1);
+ if (clock_src)
+ ctl1 |= MSCAN_CLKSRC;
+ else
+ ctl1 &= ~MSCAN_CLKSRC;
+
+ ctl1 |= MSCAN_CANE;
+ out_8(®s->canctl1, ctl1);
+ udelay(100);
+
+ /* acceptance mask/acceptance code (accept everything) */
+ out_be16(®s->canidar1_0, 0);
+ out_be16(®s->canidar3_2, 0);
+ out_be16(®s->canidar5_4, 0);
+ out_be16(®s->canidar7_6, 0);
+
+ out_be16(®s->canidmr1_0, 0xffff);
+ out_be16(®s->canidmr3_2, 0xffff);
+ out_be16(®s->canidmr5_4, 0xffff);
+ out_be16(®s->canidmr7_6, 0xffff);
+ /* Two 32 bit Acceptance Filters */
+ out_8(®s->canidac, MSCAN_AF_32BIT);
+
+ mscan_set_mode(dev, MSCAN_INIT_MODE);
+
+ return register_candev(dev);
+}
+EXPORT_SYMBOL_GPL(register_mscandev);
+
+void unregister_mscandev(struct net_device *dev)
+{
+ struct mscan_priv *priv = netdev_priv(dev);
+ struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
+ mscan_set_mode(dev, MSCAN_INIT_MODE);
+ out_8(®s->canctl1, in_8(®s->canctl1) & ~MSCAN_CANE);
+ unregister_candev(dev);
+}
+EXPORT_SYMBOL_GPL(unregister_mscandev);
+
+struct net_device *alloc_mscandev(void)
+{
+ struct net_device *dev;
+ struct mscan_priv *priv;
+ int i;
+
+ dev = alloc_candev(sizeof(struct mscan_priv), MSCAN_ECHO_SKB_MAX);
+ if (!dev)
+ return NULL;
+ priv = netdev_priv(dev);
+
+ dev->netdev_ops = &mscan_netdev_ops;
+
+ dev->flags |= IFF_ECHO; /* we support local echo */
+
+ netif_napi_add(dev, &priv->napi, mscan_rx_poll, 8);
+
+ priv->can.bittiming_const = &mscan_bittiming_const;
+ priv->can.do_set_bittiming = mscan_do_set_bittiming;
+ priv->can.do_set_mode = mscan_do_set_mode;
+
+ for (i = 0; i < TX_QUEUE_SIZE; i++) {
+ priv->tx_queue[i].id = i;
+ priv->tx_queue[i].mask = 1 << i;
+ }
+
+ return dev;
+}
+EXPORT_SYMBOL_GPL(alloc_mscandev);
+
+MODULE_AUTHOR("Andrey Volkov <avolkov-ppI4tVfbJvJWk0Htik3J/w@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("CAN port driver for a MSCAN based chips");
diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h
new file mode 100644
index 0000000..57820f5
--- /dev/null
+++ b/drivers/net/can/mscan/mscan.h
@@ -0,0 +1,262 @@
+/*
+ * Definitions of consts/structs to drive the Freescale MSCAN.
+ *
+ * Copyright (C) 2005-2006 Andrey Volkov <avolkov-ppI4tVfbJvJWk0Htik3J/w@public.gmane.org>,
+ * Varma Electronics Oy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the version 2 of the GNU General Public License
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __MSCAN_H__
+#define __MSCAN_H__
+
+#include <linux/types.h>
+
+/* MSCAN control register 0 (CANCTL0) bits */
+#define MSCAN_RXFRM 0x80
+#define MSCAN_RXACT 0x40
+#define MSCAN_CSWAI 0x20
+#define MSCAN_SYNCH 0x10
+#define MSCAN_TIME 0x08
+#define MSCAN_WUPE 0x04
+#define MSCAN_SLPRQ 0x02
+#define MSCAN_INITRQ 0x01
+
+/* MSCAN control register 1 (CANCTL1) bits */
+#define MSCAN_CANE 0x80
+#define MSCAN_CLKSRC 0x40
+#define MSCAN_LOOPB 0x20
+#define MSCAN_LISTEN 0x10
+#define MSCAN_WUPM 0x04
+#define MSCAN_SLPAK 0x02
+#define MSCAN_INITAK 0x01
+
+/* Use the MPC5200 MSCAN variant? */
+#ifdef CONFIG_PPC
+#define MSCAN_FOR_MPC5200
+#endif
+
+#ifdef MSCAN_FOR_MPC5200
+#define MSCAN_CLKSRC_BUS 0
+#define MSCAN_CLKSRC_XTAL MSCAN_CLKSRC
+#else
+#define MSCAN_CLKSRC_BUS MSCAN_CLKSRC
+#define MSCAN_CLKSRC_XTAL 0
+#endif
+
+/* MSCAN receiver flag register (CANRFLG) bits */
+#define MSCAN_WUPIF 0x80
+#define MSCAN_CSCIF 0x40
+#define MSCAN_RSTAT1 0x20
+#define MSCAN_RSTAT0 0x10
+#define MSCAN_TSTAT1 0x08
+#define MSCAN_TSTAT0 0x04
+#define MSCAN_OVRIF 0x02
+#define MSCAN_RXF 0x01
+#define MSCAN_ERR_IF (MSCAN_OVRIF | MSCAN_CSCIF)
+#define MSCAN_RSTAT_MSK (MSCAN_RSTAT1 | MSCAN_RSTAT0)
+#define MSCAN_TSTAT_MSK (MSCAN_TSTAT1 | MSCAN_TSTAT0)
+#define MSCAN_STAT_MSK (MSCAN_RSTAT_MSK | MSCAN_TSTAT_MSK)
+
+#define MSCAN_STATE_BUS_OFF (MSCAN_RSTAT1 | MSCAN_RSTAT0 | \
+ MSCAN_TSTAT1 | MSCAN_TSTAT0)
+#define MSCAN_STATE_TX(canrflg) (((canrflg)&MSCAN_TSTAT_MSK)>>2)
+#define MSCAN_STATE_RX(canrflg) (((canrflg)&MSCAN_RSTAT_MSK)>>4)
+#define MSCAN_STATE_ACTIVE 0
+#define MSCAN_STATE_WARNING 1
+#define MSCAN_STATE_PASSIVE 2
+#define MSCAN_STATE_BUSOFF 3
+
+/* MSCAN receiver interrupt enable register (CANRIER) bits */
+#define MSCAN_WUPIE 0x80
+#define MSCAN_CSCIE 0x40
+#define MSCAN_RSTATE1 0x20
+#define MSCAN_RSTATE0 0x10
+#define MSCAN_TSTATE1 0x08
+#define MSCAN_TSTATE0 0x04
+#define MSCAN_OVRIE 0x02
+#define MSCAN_RXFIE 0x01
+
+/* MSCAN transmitter flag register (CANTFLG) bits */
+#define MSCAN_TXE2 0x04
+#define MSCAN_TXE1 0x02
+#define MSCAN_TXE0 0x01
+#define MSCAN_TXE (MSCAN_TXE2 | MSCAN_TXE1 | MSCAN_TXE0)
+
+/* MSCAN transmitter interrupt enable register (CANTIER) bits */
+#define MSCAN_TXIE2 0x04
+#define MSCAN_TXIE1 0x02
+#define MSCAN_TXIE0 0x01
+#define MSCAN_TXIE (MSCAN_TXIE2 | MSCAN_TXIE1 | MSCAN_TXIE0)
+
+/* MSCAN transmitter message abort request (CANTARQ) bits */
+#define MSCAN_ABTRQ2 0x04
+#define MSCAN_ABTRQ1 0x02
+#define MSCAN_ABTRQ0 0x01
+
+/* MSCAN transmitter message abort ack (CANTAAK) bits */
+#define MSCAN_ABTAK2 0x04
+#define MSCAN_ABTAK1 0x02
+#define MSCAN_ABTAK0 0x01
+
+/* MSCAN transmit buffer selection (CANTBSEL) bits */
+#define MSCAN_TX2 0x04
+#define MSCAN_TX1 0x02
+#define MSCAN_TX0 0x01
+
+/* MSCAN ID acceptance control register (CANIDAC) bits */
+#define MSCAN_IDAM1 0x20
+#define MSCAN_IDAM0 0x10
+#define MSCAN_IDHIT2 0x04
+#define MSCAN_IDHIT1 0x02
+#define MSCAN_IDHIT0 0x01
+
+#define MSCAN_AF_32BIT 0x00
+#define MSCAN_AF_16BIT MSCAN_IDAM0
+#define MSCAN_AF_8BIT MSCAN_IDAM1
+#define MSCAN_AF_CLOSED (MSCAN_IDAM0|MSCAN_IDAM1)
+#define MSCAN_AF_MASK (~(MSCAN_IDAM0|MSCAN_IDAM1))
+
+/* MSCAN Miscellaneous Register (CANMISC) bits */
+#define MSCAN_BOHOLD 0x01
+
+#ifdef MSCAN_FOR_MPC5200
+#define _MSCAN_RESERVED_(n, num) u8 _res##n[num]
+#define _MSCAN_RESERVED_DSR_SIZE 2
+#else
+#define _MSCAN_RESERVED_(n, num)
+#define _MSCAN_RESERVED_DSR_SIZE 0
+#endif
+
+/* Structure of the hardware registers */
+struct mscan_regs {
+ /* (see doc S12MSCANV3/D) MPC5200 MSCAN */
+ u8 canctl0; /* + 0x00 0x00 */
+ u8 canctl1; /* + 0x01 0x01 */
+ _MSCAN_RESERVED_(1, 2); /* + 0x02 */
+ u8 canbtr0; /* + 0x04 0x02 */
+ u8 canbtr1; /* + 0x05 0x03 */
+ _MSCAN_RESERVED_(2, 2); /* + 0x06 */
+ u8 canrflg; /* + 0x08 0x04 */
+ u8 canrier; /* + 0x09 0x05 */
+ _MSCAN_RESERVED_(3, 2); /* + 0x0a */
+ u8 cantflg; /* + 0x0c 0x06 */
+ u8 cantier; /* + 0x0d 0x07 */
+ _MSCAN_RESERVED_(4, 2); /* + 0x0e */
+ u8 cantarq; /* + 0x10 0x08 */
+ u8 cantaak; /* + 0x11 0x09 */
+ _MSCAN_RESERVED_(5, 2); /* + 0x12 */
+ u8 cantbsel; /* + 0x14 0x0a */
+ u8 canidac; /* + 0x15 0x0b */
+ u8 reserved; /* + 0x16 0x0c */
+ _MSCAN_RESERVED_(6, 5); /* + 0x17 */
+#ifndef MSCAN_FOR_MPC5200
+ u8 canmisc; /* 0x0d */
+#endif
+ u8 canrxerr; /* + 0x1c 0x0e */
+ u8 cantxerr; /* + 0x1d 0x0f */
+ _MSCAN_RESERVED_(7, 2); /* + 0x1e */
+ u16 canidar1_0; /* + 0x20 0x10 */
+ _MSCAN_RESERVED_(8, 2); /* + 0x22 */
+ u16 canidar3_2; /* + 0x24 0x12 */
+ _MSCAN_RESERVED_(9, 2); /* + 0x26 */
+ u16 canidmr1_0; /* + 0x28 0x14 */
+ _MSCAN_RESERVED_(10, 2); /* + 0x2a */
+ u16 canidmr3_2; /* + 0x2c 0x16 */
+ _MSCAN_RESERVED_(11, 2); /* + 0x2e */
+ u16 canidar5_4; /* + 0x30 0x18 */
+ _MSCAN_RESERVED_(12, 2); /* + 0x32 */
+ u16 canidar7_6; /* + 0x34 0x1a */
+ _MSCAN_RESERVED_(13, 2); /* + 0x36 */
+ u16 canidmr5_4; /* + 0x38 0x1c */
+ _MSCAN_RESERVED_(14, 2); /* + 0x3a */
+ u16 canidmr7_6; /* + 0x3c 0x1e */
+ _MSCAN_RESERVED_(15, 2); /* + 0x3e */
+ struct {
+ u16 idr1_0; /* + 0x40 0x20 */
+ _MSCAN_RESERVED_(16, 2); /* + 0x42 */
+ u16 idr3_2; /* + 0x44 0x22 */
+ _MSCAN_RESERVED_(17, 2); /* + 0x46 */
+ u16 dsr1_0; /* + 0x48 0x24 */
+ _MSCAN_RESERVED_(18, 2); /* + 0x4a */
+ u16 dsr3_2; /* + 0x4c 0x26 */
+ _MSCAN_RESERVED_(19, 2); /* + 0x4e */
+ u16 dsr5_4; /* + 0x50 0x28 */
+ _MSCAN_RESERVED_(20, 2); /* + 0x52 */
+ u16 dsr7_6; /* + 0x54 0x2a */
+ _MSCAN_RESERVED_(21, 2); /* + 0x56 */
+ u8 dlr; /* + 0x58 0x2c */
+ u8:8; /* + 0x59 0x2d */
+ _MSCAN_RESERVED_(22, 2); /* + 0x5a */
+ u16 time; /* + 0x5c 0x2e */
+ } rx;
+ _MSCAN_RESERVED_(23, 2); /* + 0x5e */
+ struct {
+ u16 idr1_0; /* + 0x60 0x30 */
+ _MSCAN_RESERVED_(24, 2); /* + 0x62 */
+ u16 idr3_2; /* + 0x64 0x32 */
+ _MSCAN_RESERVED_(25, 2); /* + 0x66 */
+ u16 dsr1_0; /* + 0x68 0x34 */
+ _MSCAN_RESERVED_(26, 2); /* + 0x6a */
+ u16 dsr3_2; /* + 0x6c 0x36 */
+ _MSCAN_RESERVED_(27, 2); /* + 0x6e */
+ u16 dsr5_4; /* + 0x70 0x38 */
+ _MSCAN_RESERVED_(28, 2); /* + 0x72 */
+ u16 dsr7_6; /* + 0x74 0x3a */
+ _MSCAN_RESERVED_(29, 2); /* + 0x76 */
+ u8 dlr; /* + 0x78 0x3c */
+ u8 tbpr; /* + 0x79 0x3d */
+ _MSCAN_RESERVED_(30, 2); /* + 0x7a */
+ u16 time; /* + 0x7c 0x3e */
+ } tx;
+ _MSCAN_RESERVED_(31, 2); /* + 0x7e */
+} __attribute__ ((packed));
+
+#undef _MSCAN_RESERVED_
+#define MSCAN_REGION sizeof(struct mscan)
+
+#define TX_QUEUE_SIZE 3
+
+struct tx_queue_entry {
+ struct list_head list;
+ u8 mask;
+ u8 id;
+};
+
+struct mscan_priv {
+ struct can_priv can; /* must be the first member */
+ long open_time;
+ unsigned long flags;
+ void __iomem *reg_base; /* ioremap'ed address to registers */
+ u8 shadow_statflg;
+ u8 shadow_canrier;
+ u8 cur_pri;
+ u8 prev_buf_id;
+ u8 tx_active;
+
+ struct list_head tx_head;
+ struct tx_queue_entry tx_queue[TX_QUEUE_SIZE];
+ struct napi_struct napi;
+};
+
+struct net_device *alloc_mscandev(void);
+/*
+ * clock_src:
+ * 1 = The MSCAN clock source is the onchip Bus Clock.
+ * 0 = The MSCAN clock source is the chip Oscillator Clock.
+ */
+extern int register_mscandev(struct net_device *dev, int clock_src);
+extern void unregister_mscandev(struct net_device *dev);
+
+#endif /* __MSCAN_H__ */
--
1.6.3.3
^ permalink raw reply related
* Re: Documentation: rw_lock lessons learned
From: William Allen Simpson @ 2009-11-13 16:15 UTC (permalink / raw)
To: Stefan Richter
Cc: Stephen Hemminger, sclark46, Paul E. McKenney, Linus Torvalds,
Linux Kernel Developers, Linux Kernel Network Developers,
Eric Dumazet
In-Reply-To: <4AFD1FF1.7080906@s5r6.in-berlin.de>
Stefan Richter wrote:
> Stephen Hemminger wrote:
>> On Thu, 12 Nov 2009 14:13:03 -0500
>> Stephen Clark <sclark46@earthlink.net> wrote:
>>> How up to date is this doc?
>>>
>>> http://www.kernel.org/pub/linux/kernel/people/rusty/kernel-locking/index.html
>>>
>> Out of date.
>> 1. Missing mutex's which have largely replaced semaphores.
>>
>> 2. Missing change to lock initialization in later kernels.
>>
>> 3. Missing description of lock dependency checker which should be in same guide.
>
> 4. The section on atomic reference counting should refer to <linux/kref.h>.
I'd also read that, and that's where I got some of my wrong thinking. But
that does point to Documentation/spin_locks.txt, which I took to be
authoritative (and followed). That's the reason spin_locks.txt should be
updated, as others are having the same problems....
Anybody have answers/updates to Linus's concerns about "pretty old and
bogus language"?
^ permalink raw reply
* Re: [PATCH] ifb: add multi-queue support
From: Stephen Hemminger @ 2009-11-13 16:15 UTC (permalink / raw)
To: Changli Gao
Cc: Jarek Poplawski, Eric Dumazet, David S. Miller, Patrick McHardy,
Tom Herbert, netdev
In-Reply-To: <412e6f7f0911130138td181935w36cab3119972753e@mail.gmail.com>
On Fri, 13 Nov 2009 17:38:56 +0800
Changli Gao <xiaosuo@gmail.com> wrote:
> On Fri, Nov 13, 2009 at 5:18 PM, Jarek Poplawski <jarkao2@gmail.com> wrote:
> > On Fri, Nov 13, 2009 at 04:54:50PM +0800, Changli Gao wrote:
> >> On Fri, Nov 13, 2009 at 3:45 PM, Jarek Poplawski <jarkao2@gmail.com> wrote:
> >>
> >> I have done a simple test. I run a simple program on computer A, which
> >> sends SYN packets with random source ports to Computer B's 80 port (No
> >> socket listens on that port, so tcp reset packets will be sent) in
> >> 90kpps. On computer B, I redirect the traffic to IFB. At the same
> >> time, I ping from B to A to get the RTT between them. I can't see any
> >> difference between the original IFB and my MQ version. They are both:
> >>
> >> CPU idle: 50%
> >> Latency: 0.3-0.4ms, burst 2ms.
> >>
> >
> > I'm mostly concerned with routers doing forwarding with 1Gb or 10Gb
> > NICs (including multiqueue). Alas/happily I don't have such a problem,
> > but can't help you with testing either.
> >
>
> Oh, :) . I know more than one companies use kernel threads to forward
> packets, and there isn't explicit extra overhead at all. And as you
> know, as throughput increases, NAPI will bind the NIC to a CPU, and
> softirqd will be waked up to do the work, which should be done in
> SoftIRQ context. At that time, there isn't any difference between my
> approach and the current kernel's.
>
>
Why not make IFB a NAPI device. This would get rid of the extra soft-irq
round trip from going through netif_rx(). It would also behave like
regular multi-queue recieive device, and eliminate need for seperate
tasklets or threads.
^ permalink raw reply
* Re: large packet loss take2 2.6.31.x
From: Caleb Cushing @ 2009-11-13 16:25 UTC (permalink / raw)
To: Jarek Poplawski; +Cc: Frans Pop, Andi Kleen, linux-kernel, netdev
In-Reply-To: <4AFC5C58.9030207@gmail.com>
> So I assume it's your only network device on this box and according
> to these reports it's 192.168.1.3 with 192.168.1.1 as the gateway,
> and your only change is kernel on this 192.168.1.3 box, right?
yes, and semi obviously that router is my box (LinkSys wrt 54gl
openwrt kamikaze 8.09.1.
> Since the loss is seen on the first hop already, it seems it should be
> enough to query 192.168.1.1 only - did you try this? If so, does this
> happen from the beginning of the test or after many loops? Could you
> try to repeat this wireshark dump with more data than before (but just
> to be sure there are a few unanswered pings). If possible it would be
> nice to have wireshark or tcpdump data from 192.168.1.1 too, while
> pinged from 192.168.1.3. Please, send it gzipped to bugzilla only plus
> ifconfig eth0 before and after the test (and let us know here).
same bug? or new bug? I can see what I can do to get a tcpdump from
the router. yes I tried that, I can tell within the first 10 pings. I
should say I don't notice it on every kernel boot, it's ~80% of
reboots (but that's pulled from my behind). but I haven't noticed it
on gfa31221 at all. it's reproducible in 31.6 too (arch just added
that).
> Btw, mtr has text reporting too (--report). Larger things send to
> bugzilla only.
didn't know that, although I should have guessed (or rtfm), thanks.
--
Caleb Cushing
http://xenoterracide.blogspot.com
^ permalink raw reply
* Re: [net-next-2.6 PATCH v6 5/7 RFC] TCPCT part 1e: implement socket option TCP_COOKIE_TRANSACTIONS
From: William Allen Simpson @ 2009-11-13 16:32 UTC (permalink / raw)
To: Andi Kleen; +Cc: Linux Kernel Network Developers
In-Reply-To: <87bpj6tszv.fsf@basil.nowhere.org>
Andi Kleen wrote:
> BTW if you add new socket options you should always submit a manpage
> patch to linux-man@vger.kernel.org too
>
Thanks muchly, I'd wondered where one does that! I'll do that as soon
as the code goes into the net tree (rather than net-next) for staging
out to the main line, as otherwise that could be pretty confusing for
others (non-existent options).
I'd found Documentation/networking/ip-sysctl.txt, updated in part 1c.
Any technical corrections to this patch (or part 1c)?
^ permalink raw reply
* [PATCH net-next-2.6] vlan: Use __vlan_hwaccel_put_tag() in rx
From: Eric Dumazet @ 2009-11-13 16:33 UTC (permalink / raw)
To: David S. Miller; +Cc: Linux Netdev List
Commit 05423b241311c9380 (vlan: allow null VLAN ID to be used)
forgot to update __vlan_hwaccel_rx() & vlan_gro_common()
We need to set VLAN_TAG_PRESENT flag in skb->vlan_tci
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
net/8021q/vlan_core.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 8d5ca2a..971d375 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -14,7 +14,7 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
if (skb_bond_should_drop(skb))
goto drop;
- skb->vlan_tci = vlan_tci;
+ __vlan_hwaccel_put_tag(skb, vlan_tci);
skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK);
if (!skb->dev)
@@ -83,7 +83,7 @@ vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp,
if (skb_bond_should_drop(skb))
goto drop;
- skb->vlan_tci = vlan_tci;
+ __vlan_hwaccel_put_tag(skb, vlan_tci);
skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK);
if (!skb->dev)
^ permalink raw reply related
* Re: [net-next-2.6 PATCH] net: fast consecutive name allocation
From: Ben Greear @ 2009-11-13 16:40 UTC (permalink / raw)
To: Octavian Purdila; +Cc: Eric Dumazet, netdev
In-Reply-To: <200911131155.43714.opurdila@ixiacom.com>
Octavian Purdila wrote:
> On Friday 13 November 2009 08:12:35 you wrote:
>
>> Octavian Purdila a écrit :
>>
>>> On Friday 13 November 2009 07:01:14 you wrote:
>>>
>>>> This patch speeds up the network device name allocation for the case
>>>> where a significant number of devices of the same type are created
>>>> consecutively.
>>>>
>>>> Tests performed on a PPC750 @ 800Mhz machine with per device sysctl
>>>> and sysfs entries disabled:
>>>>
>>>> Without the patch With the patch
>>>>
>>>> real 0m 43.43s real 0m 0.49s
>>>> user 0m 0.00s user 0m 0.00s
>>>> sys 0m 43.43s sys 0m 0.48s
>>>>
>>> Oops, pasting root prompts (e.g. # modprobe ....) directly into the git
>>> commit message is not a good idea :) Here it is again, with the full
>>> commit message.
>>>
>>> [net-next-2.6 PATCH] net: fast consecutive name allocation
>>>
>>> This patch speeds up the network device name allocation for the case
>>> where a significant number of devices of the same type are created
>>> consecutively.
>>>
>>> Tests performed on a PPC750 @ 800Mhz machine with per device sysctl
>>> and sysfs entries disabled:
>>>
>>> $ time insmod /lib/modules/dummy.ko numdummies=8000
>>>
>>> Without the patch With the patch
>>>
>>> real 0m 43.43s real 0m 0.49s
>>> user 0m 0.00s user 0m 0.00s
>>> sys 0m 43.43s sys 0m 0.48s
>>>
>>> Signed-off-by: Octavian Purdila <opurdila@ixiacom.com>
>>> ---
>>>
>> Honestly I dont like this bloat.
>>
>> Changing dummy.c is trivial, and you can allocate 100.000.000 dummies if
>> you want now :)
>>
>>
>
> Yep we can do that - actually we are doing exactly this in our drivers. But in
> that way, you get to "bloat" every driver which needs this.
>
For mac-vlans, .1q vlans, VETH, at least, you can choose the name when
you create them
via 'ip'. So, you can do the logic in user-space.
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* Re: [RFC] vlan: GRO rx statistics
From: Eric Dumazet @ 2009-11-13 16:41 UTC (permalink / raw)
To: David S. Miller; +Cc: Herbert Xu, Linux Netdev List
In-Reply-To: <4AF99A50.5080301@gmail.com>
Eric Dumazet a écrit :
> It seems vlan interfaces with hardware-assisted VLAN reception
> dont have rx statistics.
>
> Following patch cures the problem for me but I have no idea
> if it is correct ?
>
> Another problem about all rx stats is about multi rx queues devices.
> Several cpus can access these counters in parallel ?
>
>
> diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
> index 8d5ca2a..e13b007 100644
> --- a/net/8021q/vlan_core.c
> +++ b/net/8021q/vlan_core.c
> @@ -89,6 +89,11 @@ vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp,
> if (!skb->dev)
> goto drop;
>
> + skb->dev->stats.rx_packets++;
> + skb->dev->stats.rx_bytes += skb->len;
> + if (skb->pkt_type == PACKET_MULTICAST)
> + skb->dev->stats.multicast++;
> +
> for (p = napi->gro_list; p; p = p->next) {
> NAPI_GRO_CB(p)->same_flow =
> p->dev == skb->dev && !compare_ether_header(
>
Replying to myself, I found root of the problem and posted a fix.
Still the race while updating dev->stats.tx_{bytes|packets} should be addressed eventually...
^ permalink raw reply
* Re: [RFC] vlan: GRO rx statistics
From: Eric Dumazet @ 2009-11-13 16:44 UTC (permalink / raw)
To: David S. Miller; +Cc: Herbert Xu, Linux Netdev List
In-Reply-To: <4AFD8C31.10703@gmail.com>
Eric Dumazet a écrit :
> Still the race while updating dev->stats.tx_{bytes|packets} should be addressed eventually...
Sorry, I meant dev->stats.rx_{bytes|packets}, since tx side is protected by txq spinlock.
^ permalink raw reply
* Re: [net-next-2.6 PATCH v6 6/7 RFC] TCPCT part 1f: Initiator Cookie => Responder
From: William Allen Simpson @ 2009-11-13 16:51 UTC (permalink / raw)
To: Linux Kernel Network Developers; +Cc: Eric Dumazet, Joe Perches
In-Reply-To: <4AFCF134.2060208@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 148 bytes --]
Moving the initialization (and destruction) to part 1d makes this about as
short and easy to analyze as possible. Any more technical observations?
[-- Attachment #2: TCPCT+1f6+.patch --]
[-- Type: text/plain, Size: 9516 bytes --]
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index e59fa5a..e1553d3 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -370,15 +370,45 @@ static inline int tcp_urg_mode(const struct tcp_sock *tp)
#define OPTION_TS (1 << 1)
#define OPTION_MD5 (1 << 2)
#define OPTION_WSCALE (1 << 3)
+#define OPTION_COOKIE_EXTENSION (1 << 4)
struct tcp_out_options {
u8 options; /* bit field of OPTION_* */
u8 ws; /* window scale, 0 to disable */
u8 num_sack_blocks; /* number of SACK blocks to include */
+ u8 hash_size; /* bytes in hash_location */
u16 mss; /* 0 to disable */
__u32 tsval, tsecr; /* need to include OPTION_TS */
+ __u8 *hash_location; /* temporary pointer, overloaded */
};
+/* The sysctl int routines are generic, so check consistency here.
+ */
+static u8 tcp_cookie_size_check(u8 desired)
+{
+ if (desired > 0) {
+ /* previously specified */
+ return desired;
+ }
+ if (sysctl_tcp_cookie_size <= 0) {
+ /* no default specified */
+ return 0;
+ }
+ if (sysctl_tcp_cookie_size < TCP_COOKIE_MIN) {
+ /* value too small, increase to minimum */
+ return TCP_COOKIE_MIN;
+ }
+ if (sysctl_tcp_cookie_size > TCP_COOKIE_MAX) {
+ /* value too large, decrease to maximum */
+ return TCP_COOKIE_MAX;
+ }
+ if (0x1 & sysctl_tcp_cookie_size) {
+ /* 8-bit multiple, illegal, fix it */
+ return (u8)(sysctl_tcp_cookie_size + 0x1);
+ }
+ return (u8)sysctl_tcp_cookie_size;
+}
+
/* Write previously computed TCP options to the packet.
*
* Beware: Something in the Internet is very sensitive to the ordering of
@@ -393,17 +423,34 @@ struct tcp_out_options {
* (but it may well be that other scenarios fail similarly).
*/
static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
- const struct tcp_out_options *opts,
- __u8 **md5_hash) {
- if (unlikely(OPTION_MD5 & opts->options)) {
- *ptr++ = htonl((TCPOPT_NOP << 24) |
- (TCPOPT_NOP << 16) |
- (TCPOPT_MD5SIG << 8) |
- TCPOLEN_MD5SIG);
- *md5_hash = (__u8 *)ptr;
+ struct tcp_out_options *opts)
+{
+ u8 options = opts->options; /* mungable copy */
+
+ /* Having both authentication and cookies for security is redundant,
+ * and there's certainly not enough room. Instead, the cookie-less
+ * extension variant is proposed.
+ *
+ * Consider the pessimal case with authentication. The options
+ * could look like:
+ * COOKIE|MD5(20) + MSS(4) + SACK|TS(12) + WSCALE(4) == 40
+ */
+ if (unlikely(OPTION_MD5 & options)) {
+ if (unlikely(OPTION_COOKIE_EXTENSION & options)) {
+ *ptr++ = htonl((TCPOPT_COOKIE << 24) |
+ (TCPOLEN_COOKIE_BASE << 16) |
+ (TCPOPT_MD5SIG << 8) |
+ TCPOLEN_MD5SIG);
+ } else {
+ *ptr++ = htonl((TCPOPT_NOP << 24) |
+ (TCPOPT_NOP << 16) |
+ (TCPOPT_MD5SIG << 8) |
+ TCPOLEN_MD5SIG);
+ }
+ options &= ~OPTION_COOKIE_EXTENSION;
+ /* overload cookie hash location */
+ opts->hash_location = (__u8 *)ptr;
ptr += 4;
- } else {
- *md5_hash = NULL;
}
if (unlikely(opts->mss)) {
@@ -412,12 +459,13 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
opts->mss);
}
- if (likely(OPTION_TS & opts->options)) {
- if (unlikely(OPTION_SACK_ADVERTISE & opts->options)) {
+ if (likely(OPTION_TS & options)) {
+ if (unlikely(OPTION_SACK_ADVERTISE & options)) {
*ptr++ = htonl((TCPOPT_SACK_PERM << 24) |
(TCPOLEN_SACK_PERM << 16) |
(TCPOPT_TIMESTAMP << 8) |
TCPOLEN_TIMESTAMP);
+ options &= ~OPTION_SACK_ADVERTISE;
} else {
*ptr++ = htonl((TCPOPT_NOP << 24) |
(TCPOPT_NOP << 16) |
@@ -428,15 +476,52 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
*ptr++ = htonl(opts->tsecr);
}
- if (unlikely(OPTION_SACK_ADVERTISE & opts->options &&
- !(OPTION_TS & opts->options))) {
+ /* Specification requires after timestamp, so do it now.
+ *
+ * Consider the pessimal case without authentication. The options
+ * could look like:
+ * MSS(4) + SACK|TS(12) + COOKIE(20) + WSCALE(4) == 40
+ */
+ if (unlikely(OPTION_COOKIE_EXTENSION & options)) {
+ __u8 *cookie_copy = opts->hash_location;
+ u8 cookie_size = opts->hash_size;
+
+ if (unlikely(0x1 & cookie_size)) {
+ /* 8-bit multiple, illegal, ignore */
+ cookie_size = 0;
+ } else if (likely(0x2 & cookie_size)) {
+ __u8 *p = (__u8 *)ptr;
+
+ /* 16-bit multiple */
+ *p++ = TCPOPT_COOKIE;
+ *p++ = TCPOLEN_COOKIE_BASE + cookie_size;
+ *p++ = *cookie_copy++;
+ *p++ = *cookie_copy++;
+ ptr++;
+ cookie_size -= 2;
+ } else {
+ /* 32-bit multiple */
+ *ptr++ = htonl(((TCPOPT_NOP << 24) |
+ (TCPOPT_NOP << 16) |
+ (TCPOPT_COOKIE << 8) |
+ TCPOLEN_COOKIE_BASE) +
+ cookie_size);
+ }
+
+ if (cookie_size > 0) {
+ memcpy(ptr, cookie_copy, cookie_size);
+ ptr += (cookie_size >> 2);
+ }
+ }
+
+ if (unlikely(OPTION_SACK_ADVERTISE & options)) {
*ptr++ = htonl((TCPOPT_NOP << 24) |
(TCPOPT_NOP << 16) |
(TCPOPT_SACK_PERM << 8) |
TCPOLEN_SACK_PERM);
}
- if (unlikely(OPTION_WSCALE & opts->options)) {
+ if (unlikely(OPTION_WSCALE & options)) {
*ptr++ = htonl((TCPOPT_NOP << 24) |
(TCPOPT_WINDOW << 16) |
(TCPOLEN_WINDOW << 8) |
@@ -471,8 +556,12 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
struct tcp_out_options *opts,
struct tcp_md5sig_key **md5) {
struct tcp_sock *tp = tcp_sk(sk);
- unsigned size = 0;
+ struct tcp_cookie_values *cvp = tp->cookie_values;
struct dst_entry *dst = __sk_dst_get(sk);
+ unsigned size = 0;
+ u8 cookie_size = (!tp->rx_opt.cookie_out_never && cvp != NULL)
+ ? tcp_cookie_size_check(cvp->cookie_desired)
+ : 0;
#ifdef CONFIG_TCP_MD5SIG
*md5 = tp->af_specific->md5_lookup(sk, sk);
@@ -517,6 +606,53 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb,
size += TCPOLEN_SACKPERM_ALIGNED;
}
+ /* Note that timestamps are required by the specification.
+ *
+ * Odd numbers of bytes are prohibited by the specification, ensuring
+ * that the cookie is 16-bit aligned, and the resulting cookie pair is
+ * 32-bit aligned.
+ */
+ if (*md5 == NULL
+ && (OPTION_TS & opts->options)
+ && cookie_size > 0) {
+ int need = TCPOLEN_COOKIE_BASE + cookie_size;
+ int remaining = MAX_TCP_OPTION_SPACE - size;
+
+ if (0x2 & need) {
+ /* 32-bit multiple */
+ need += 2; /* NOPs */
+
+ if (need > remaining) {
+ /* try shrinking cookie to fit */
+ cookie_size -= 2;
+ need -= 4;
+ }
+ }
+ while (need > remaining && TCP_COOKIE_MIN <= cookie_size) {
+ cookie_size -= 4;
+ need -= 4;
+ }
+ if (TCP_COOKIE_MIN <= cookie_size) {
+ opts->options |= OPTION_COOKIE_EXTENSION;
+ opts->hash_location = (__u8 *)&cvp->cookie_pair[0];
+ opts->hash_size = cookie_size;
+
+ /* Remember for future incarnations. */
+ cvp->cookie_desired = cookie_size;
+
+ if (cvp->cookie_desired != cvp->cookie_pair_size) {
+ /* Currently use random bytes as a nonce,
+ * assuming these are completely unpredictable
+ * by hostile users of the same system.
+ */
+ get_random_bytes(&cvp->cookie_pair[0],
+ cookie_size);
+ cvp->cookie_pair_size = cookie_size;
+ }
+
+ size += need;
+ }
+ }
return size;
}
@@ -632,7 +768,6 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
struct tcp_out_options opts;
unsigned tcp_options_size, tcp_header_size;
struct tcp_md5sig_key *md5;
- __u8 *md5_hash_location;
struct tcphdr *th;
int err;
@@ -703,7 +838,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
}
}
- tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location);
+ tcp_options_write((__be32 *)(th + 1), tp, &opts);
if (likely((tcb->flags & TCPCB_FLAG_SYN) == 0))
TCP_ECN_send(sk, skb, tcp_header_size);
@@ -711,7 +846,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
/* Calculate the MD5 hash, as we have all we need now */
if (md5) {
sk->sk_route_caps &= ~NETIF_F_GSO_MASK;
- tp->af_specific->calc_md5_hash(md5_hash_location,
+ tp->af_specific->calc_md5_hash(opts.hash_location,
md5, sk, NULL, skb);
}
#endif
@@ -2235,14 +2370,13 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
struct request_sock *req,
struct request_values *rvp)
{
+ struct tcp_out_options opts;
struct inet_request_sock *ireq = inet_rsk(req);
struct tcp_sock *tp = tcp_sk(sk);
struct tcphdr *th;
- int tcp_header_size;
- struct tcp_out_options opts;
struct sk_buff *skb;
struct tcp_md5sig_key *md5;
- __u8 *md5_hash_location;
+ int tcp_header_size;
int mss;
skb = sock_wmalloc(sk, MAX_TCP_HEADER + 15, 1, GFP_ATOMIC);
@@ -2303,14 +2437,14 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
/* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */
th->window = htons(min(req->rcv_wnd, 65535U));
- tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location);
+ tcp_options_write((__be32 *)(th + 1), tp, &opts);
th->doff = (tcp_header_size >> 2);
TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS);
#ifdef CONFIG_TCP_MD5SIG
/* Okay, we have all we need - do the md5 hash if needed */
if (md5) {
- tcp_rsk(req)->af_specific->calc_md5_hash(md5_hash_location,
+ tcp_rsk(req)->af_specific->calc_md5_hash(opts.hash_location,
md5, NULL, req, skb);
}
#endif
--
1.6.3.3
^ permalink raw reply related
* Lots of tcp_recvmsg warnings in kerneloops list
From: Stephen Hemminger @ 2009-11-13 17:10 UTC (permalink / raw)
To: Ilpo Järvinen, David Miller; +Cc: netdev
Has anyone looked into this? Is there a fix? Should it be sent to stable?
http://kerneloops.org/searchweek.php?search=tcp_recvmsg
^ permalink raw reply
* Re: large packet loss take2 2.6.31.x
From: Caleb Cushing @ 2009-11-13 17:21 UTC (permalink / raw)
To: Jarek Poplawski; +Cc: Frans Pop, Andi Kleen, linux-kernel, netdev
In-Reply-To: <81bfc67a0911130825o6d9b93b2he70677157ad889f2@mail.gmail.com>
any specific switches I should run tcpdump with? or any other tests I
should be trying while capturing? (on either end).
--
Caleb Cushing
http://xenoterracide.blogspot.com
^ permalink raw reply
* Re: Lots of tcp_recvmsg warnings in kerneloops list
From: Eric Dumazet @ 2009-11-13 17:34 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: Ilpo Järvinen, David Miller, netdev, Herbert Xu
In-Reply-To: <20091113091013.2bef993e@s6510>
Stephen Hemminger a écrit :
> Has anyone looked into this? Is there a fix? Should it be sent to stable?
>
> http://kerneloops.org/searchweek.php?search=tcp_recvmsg
> --
Only debugging AFAIK, no discoveries yet.
commit c62f4c453ab4b0240ab857bfd089da2c01ad91e7
Author: Arjan van de Ven <arjan@linux.intel.com>
Date: Thu Oct 22 21:37:56 2009 -0700
net: use WARN() for the WARN_ON in commit b6b39e8f3fbbb
Commit b6b39e8f3fbbb (tcp: Try to catch MSG_PEEK bug) added a printk()
to the WARN_ON() that's in tcp.c. This patch changes this combination
to WARN(); the advantage of WARN() is that the printk message shows up
inside the message, so that kerneloops.org will collect the message.
In addition, this gets rid of an extra if() statement.
Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
commit b6b39e8f3fbbb31001b836afec87bcaf4811a7bf
Author: Herbert Xu <herbert@gondor.apana.org.au>
Date: Mon Oct 19 19:41:06 2009 +0000
tcp: Try to catch MSG_PEEK bug
This patch tries to print out more information when we hit the
MSG_PEEK bug in tcp_recvmsg. It's been around since at least
2005 and it's about time that we finally fix it.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
^ permalink raw reply
* Re: [PATCH] net/can: add driver for mscan family & mpc52xx_mscan
From: Grant Likely @ 2009-11-13 17:39 UTC (permalink / raw)
To: Wolfram Sang
Cc: netdev, socketcan-core, linuxppc-dev, Wolfgang Grandegger,
David Miller
In-Reply-To: <1258128892-28800-1-git-send-email-w.sang@pengutronix.de>
On Fri, Nov 13, 2009 at 9:14 AM, Wolfram Sang <w.sang@pengutronix.de> wrote:
> Taken from socketcan-svn, fixed remaining todos, cleaned up, tested with a
> phyCORE-MPC5200B-IO and a custom board.
>
> Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
> Cc: Wolfgang Grandegger <wg@grandegger.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: David Miller <davem@davemloft.net>
I don't see any locking in this driver. What keeps the mscan_isr or
other routines from conflicting with each other? What is the
concurrency model for CAN devices?
More comments below. I don't have the background to delve into the
CAN details, but I can make some comments on the general structure of
the driver.
g.
> ---
>
> +static struct of_device_id mpc52xx_cdm_ids[] __devinitdata = {
> + { .compatible = "fsl,mpc5200-cdm", },
> + { .compatible = "fsl,mpc5200b-cdm", },
> + {}
> +};
You can drop the 'b' line. The 'b' version is compatible with the
original, and all in-tree 5200b files claim compatibility with the
non-'b' version.
> +
> +/*
> + * Get the frequency of the external oscillator clock connected
> + * to the SYS_XTAL_IN pin, or return 0 if it cannot be determined.
> + */
> +static unsigned int __devinit mpc52xx_can_xtal_freq(struct of_device *of)
> +{
> + struct mpc52xx_cdm __iomem *cdm;
> + struct device_node *np_cdm;
> + unsigned int freq;
> + u32 val;
> +
> + freq = mpc5xxx_get_bus_frequency(of->node);
> + if (!freq)
> + return 0;
> +
> + /*
> + * Determine SYS_XTAL_IN frequency from the clock domain settings
> + */
> + np_cdm = of_find_matching_node(NULL, mpc52xx_cdm_ids);
> + if (!np_cdm) {
> + dev_err(&of->dev, "can't get clock node!\n");
> + return 0;
> + }
> + cdm = of_iomap(np_cdm, 0);
> + of_node_put(np_cdm);
> +
> + if (in_8(&cdm->ipb_clk_sel) & 0x1)
> + freq *= 2;
> + val = in_be32(&cdm->rstcfg);
> + if (val & (1 << 5))
> + freq *= 8;
> + else
> + freq *= 4;
freq *= (val & (1 << 5)) ? 8 : 4;
> + if (val & (1 << 6))
> + freq /= 12;
> + else
> + freq /= 16;
Ditto.
> +
> + iounmap(cdm);
> +
> + return freq;
> +}
> +
> +/*
> + * Get frequency of the MSCAN clock source
> + *
> + * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock (IP_CLK)
> + * can be selected. According to the MPC5200 user's manual, the oscillator
> + * clock is the better choice as it has less jitter but due to a hardware
> + * bug, it can not be selected for the old MPC5200 Rev. A chips.
> + */
> +
> +static unsigned int __devinit mpc52xx_can_clock_freq(struct of_device *of,
> + int clock_src)
> +{
> + unsigned int pvr;
> +
> + pvr = mfspr(SPRN_PVR);
> +
> + if (clock_src == MSCAN_CLKSRC_BUS || pvr == 0x80822011)
> + return mpc5xxx_get_bus_frequency(of->node);
> +
> + return mpc52xx_can_xtal_freq(of);
> +}
mpc52xx_can_xtal_freq() is only used by this function. Do they need
to be separate?
> +static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
> + const struct of_device_id *id)
> +{
> + struct device_node *np = ofdev->node;
> + struct net_device *dev;
> + struct mscan_priv *priv;
> + void __iomem *base;
> + const char *clk_src;
> + int err, irq, clock_src;
> +
> + base = of_iomap(ofdev->node, 0);
> + if (!base) {
> + dev_err(&ofdev->dev, "couldn't ioremap\n");
> + err = -ENOMEM;
> + goto exit_release_mem;
> + }
> +
> + irq = irq_of_parse_and_map(np, 0);
> + if (!irq) {
> + dev_err(&ofdev->dev, "no irq found\n");
> + err = -ENODEV;
> + goto exit_unmap_mem;
> + }
> +
> + dev = alloc_mscandev();
> + if (!dev) {
> + err = -ENOMEM;
> + goto exit_dispose_irq;
> + }
> +
> + priv = netdev_priv(dev);
> + priv->reg_base = base;
> + dev->irq = irq;
> +
> + /*
> + * Either the oscillator clock (SYS_XTAL_IN) or the IP bus clock
> + * (IP_CLK) can be selected as MSCAN clock source. According to
> + * the MPC5200 user's manual, the oscillator clock is the better
> + * choice as it has less jitter. For this reason, it is selected
> + * by default.
> + */
> + clk_src = of_get_property(np, "fsl,mscan-clk-src", NULL);
> + if (clk_src && strcmp(clk_src, "ip") == 0)
Should protect against non-null. strncmp() maybe?
> +static struct of_device_id __devinitdata mpc5xxx_can_table[] = {
> + {.compatible = "fsl,mpc5200-mscan"},
> + {.compatible = "fsl,mpc5200b-mscan"},
> + {},
> +};
Ditto here; the 'b' version can be dropped.
> +static int mscan_set_mode(struct net_device *dev, u8 mode)
> +{
> + struct mscan_priv *priv = netdev_priv(dev);
> + struct mscan_regs *regs = (struct mscan_regs *)priv->reg_base;
> + int ret = 0;
> + int i;
> + u8 canctl1;
> +
> + if (mode != MSCAN_NORMAL_MODE) {
> +
> + if (priv->tx_active) {
> + /* Abort transfers before going to sleep */#
> + out_8(®s->cantarq, priv->tx_active);
> + /* Suppress TX done interrupts */
> + out_8(®s->cantier, 0);
> + }
> +
> + canctl1 = in_8(®s->canctl1);
> + if ((mode & MSCAN_SLPRQ) && (canctl1 & MSCAN_SLPAK) == 0) {
> + out_8(®s->canctl0,
> + in_8(®s->canctl0) | MSCAN_SLPRQ);
> + for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) {
> + if (in_8(®s->canctl1) & MSCAN_SLPAK)
> + break;
> + udelay(100);
Ugh. Can you sleep instead? This burns a lot of CPU cycles to no purpose.
> + }
> + /*
> + * The mscan controller will fail to enter sleep mode,
> + * while there are irregular activities on bus, like
> + * somebody keeps retransmitting. This behavior is
> + * undocumented and seems to differ between mscan built
> + * in mpc5200b and mpc5200. We proceed in that case,
> + * since otherwise the slprq will be kept set and the
> + * controller will get stuck. NOTE: INITRQ or CSWAI
> + * will abort all active transmit actions, if still
> + * any, at once.
> + */
> + if (i >= MSCAN_SET_MODE_RETRIES)
> + dev_dbg(dev->dev.parent,
> + "device failed to enter sleep mode. "
> + "We proceed anyhow.\n");
> + else
> + priv->can.state = CAN_STATE_SLEEPING;
> + }
> +
> + if ((mode & MSCAN_INITRQ) && (canctl1 & MSCAN_INITAK) == 0) {
> + out_8(®s->canctl0,
> + in_8(®s->canctl0) | MSCAN_INITRQ);
> + for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) {
> + if (in_8(®s->canctl1) & MSCAN_INITAK)
> + break;
> + }
> + if (i >= MSCAN_SET_MODE_RETRIES)
> + ret = -ENODEV;
> + }
> + if (!ret)
> + priv->can.state = CAN_STATE_STOPPED;
> +
> + if (mode & MSCAN_CSWAI)
> + out_8(®s->canctl0,
> + in_8(®s->canctl0) | MSCAN_CSWAI);
> +
> + } else {
> + canctl1 = in_8(®s->canctl1);
> + if (canctl1 & (MSCAN_SLPAK | MSCAN_INITAK)) {
> + out_8(®s->canctl0, in_8(®s->canctl0) &
> + ~(MSCAN_SLPRQ | MSCAN_INITRQ));
> + for (i = 0; i < MSCAN_SET_MODE_RETRIES; i++) {
> + canctl1 = in_8(®s->canctl1);
> + if (!(canctl1 & (MSCAN_INITAK | MSCAN_SLPAK)))
> + break;
> + }
> + if (i >= MSCAN_SET_MODE_RETRIES)
> + ret = -ENODEV;
> + else
> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
> + }
> + }
> + return ret;
> +}
[snip]
> +static int mscan_do_set_mode(struct net_device *dev, enum can_mode mode)
> +{
> +
> + struct mscan_priv *priv = netdev_priv(dev);
> + int ret = 0;
> +
> + if (!priv->open_time)
> + return -EINVAL;
> +
> + switch (mode) {
> + case CAN_MODE_SLEEP:
> + case CAN_MODE_STOP:
> + netif_stop_queue(dev);
> + mscan_set_mode(dev,
> + (mode ==
> + CAN_MODE_STOP) ? MSCAN_INIT_MODE :
> + MSCAN_SLEEP_MODE);
A little hard on the eyes. Can you rework to not spill over 4 lines?
(ie. calc mode flag on the line above?)
> + break;
> + case CAN_MODE_START:
> + if (priv->can.state <= CAN_STATE_BUS_OFF)
> + mscan_set_mode(dev, MSCAN_INIT_MODE);
> + ret = mscan_start(dev);
> + if (ret)
> + break;
> + if (netif_queue_stopped(dev))
> + netif_wake_queue(dev);
> + break;
> +
> + default:
> + ret = -EOPNOTSUPP;
> + break;
> + }
> + return ret;
> +}
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* [PATCH]remove deprecated and not used: print_mac()
From: Marin Mitov @ 2009-11-13 17:58 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, linux-kernel
Hi all,
The function print_mac in net/ethernet/eth.c is marked __deprecated
and not used. Remove it.
The patch is against 2.6.32-rc7.
Signed-off-by: Marin Mitov <mitov@issp.bas.bg>
=====================================================================
--- a/include/linux/if_ether.h 2009-11-13 19:16:15.000000000 +0200
+++ b/include/linux/if_ether.h 2009-11-13 19:18:25.000000000 +0200
@@ -136,10 +136,6 @@
extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len);
-/*
- * Display a 6 byte device address (MAC) in a readable format.
- */
-extern char *print_mac(char *buf, const unsigned char *addr) __deprecated;
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
#define MAC_BUF_SIZE 18
#define DECLARE_MAC_BUF(var) char var[MAC_BUF_SIZE]
--- a/net/ethernet/eth.c 2009-11-13 19:16:30.000000000 +0200
+++ b/net/ethernet/eth.c 2009-11-13 19:20:31.000000000 +0200
@@ -393,10 +393,3 @@
return ((ssize_t) l);
}
EXPORT_SYMBOL(sysfs_format_mac);
-
-char *print_mac(char *buf, const unsigned char *addr)
-{
- _format_mac_addr(buf, MAC_BUF_SIZE, addr, ETH_ALEN);
- return buf;
-}
-EXPORT_SYMBOL(print_mac);
^ permalink raw reply
* Re: [net-next-2.6 PATCH v6 2/7 RFC] TCPCT part 1b: generate Responder Cookie
From: Joe Perches @ 2009-11-13 18:04 UTC (permalink / raw)
To: William Allen Simpson
Cc: Linux Kernel Network Developers, Eric Dumazet, Paul E. McKenney
In-Reply-To: <4AFD728F.4030206@gmail.com>
On Fri, 2009-11-13 at 09:51 -0500, William Allen Simpson wrote:
> Since Eric says it can be inside the locked path, I can do away with
> that entirely, and just use the result (bakery) pointer itself. Saves a
> memcpy, too.
> Here's my revised attempt (untested). Any other technical corrections?
Just one, thanks for persisting.
> + if (unlikely(time_after_eq(jiffy, tcp_secret_generating->expires))) {
> + spin_lock_bh(&tcp_secret_locker);
> + if (!time_after_eq(jiffy, tcp_secret_generating->expires)) {
[]
> + spin_unlock_bh(&tcp_secret_locker);
> + } else {
[]
> + spin_unlock_bh(&tcp_secret_locker);
[removed comments]
> + }
perhaps deleting the two unlocks above and moving it
to the same indent level here is trivially better.
spin_unlock_bh(&tcp_secret_locker);
^ permalink raw reply
* Re: [net-next-2.6 PATCH v6 3/7 RFC] TCPCT part 1c: sysctl_tcp_cookie_size, socket option TCP_COOKIE_TRANSACTIONS
From: Joe Perches @ 2009-11-13 18:37 UTC (permalink / raw)
To: William Allen Simpson; +Cc: Linux Kernel Network Developers
In-Reply-To: <4AFCE13B.4060006@gmail.com>
On Thu, 2009-11-12 at 23:31 -0500, William Allen Simpson wrote:
> Define sysctl (tcp_cookie_size) to turn on and off the cookie option
> default globally, instead of a compiled configuration option.
[]
> +#define TCP_COOKIE_MIN 8 /* 64-bits */
> +#define TCP_COOKIE_MAX 16 /* 128-bits */
perhaps something like:
static const int TCP_COOKIE_MIN = 8;
static const int TCP_COOKIE_MAX = 16;
[]
> --- a/net/ipv4/sysctl_net_ipv4.c
> +++ b/net/ipv4/sysctl_net_ipv4.c
> @@ -714,6 +714,14 @@ static struct ctl_table ipv4_table[] = {
> },
> {
> .ctl_name = CTL_UNNUMBERED,
> + .procname = "tcp_cookie_size",
> + .data = &sysctl_tcp_cookie_size,
> + .maxlen = sizeof(int),
> + .mode = 0644,
> + .proc_handler = proc_dointvec
with proc_dointvec_minmax
.extra1 = &TCP_COOKIE_MIN,
.extra2 = &TCP_COOKIE_MAX,
or even adding proc_dointvec_minmax_even
might save some cycles during cookie handling.
^ permalink raw reply
* Re: [net-next-2.6 PATCH v6 3/7 RFC] TCPCT part 1c: sysctl_tcp_cookie_size, socket option TCP_COOKIE_TRANSACTIONS
From: William Allen Simpson @ 2009-11-13 19:45 UTC (permalink / raw)
To: Joe Perches; +Cc: Linux Kernel Network Developers
In-Reply-To: <1258137443.16857.124.camel@Joe-Laptop.home>
Joe Perches wrote:
> On Thu, 2009-11-12 at 23:31 -0500, William Allen Simpson wrote:
>> Define sysctl (tcp_cookie_size) to turn on and off the cookie option
>> default globally, instead of a compiled configuration option.
> []
>
>> +#define TCP_COOKIE_MIN 8 /* 64-bits */
>> +#define TCP_COOKIE_MAX 16 /* 128-bits */
>
> perhaps something like:
>
> static const int TCP_COOKIE_MIN = 8;
> static const int TCP_COOKIE_MAX = 16;
>
> []
>
>> --- a/net/ipv4/sysctl_net_ipv4.c
>> +++ b/net/ipv4/sysctl_net_ipv4.c
>> @@ -714,6 +714,14 @@ static struct ctl_table ipv4_table[] = {
>> },
>> {
>> .ctl_name = CTL_UNNUMBERED,
>> + .procname = "tcp_cookie_size",
>> + .data = &sysctl_tcp_cookie_size,
>> + .maxlen = sizeof(int),
>> + .mode = 0644,
>> + .proc_handler = proc_dointvec
>
> with proc_dointvec_minmax
>
> .extra1 = &TCP_COOKIE_MIN,
> .extra2 = &TCP_COOKIE_MAX,
>
> or even adding proc_dointvec_minmax_even
> might save some cycles during cookie handling.
>
Well, that would have to be proc_dointvec_minmax_even_zero(), as the
valid values can be 0, 8, 10, 12, 14, or 16. But my guess (based on
experience owning an ISP and teaching student operators) is that folks
will remember to turn it off (0) or on (1) or "bigger" (255), and not
really care about the finer gradations.
Error messages have a tendency to scroll off the screen and be forgotten.
And it seems to me a case of "premature optimization" -- it might save
1 or 2 tests in the order I've listed them in tcp_cookie_size_check(),
those tests only happen on the SYN the first time the _client_ calls,
and the result is saved for the future. See part 1f:
+ u8 cookie_size = (!tp->rx_opt.cookie_out_never && cvp != NULL)
+ ? tcp_cookie_size_check(cvp->cookie_desired)
+ : 0;
[]
+ /* Remember for future incarnations. */
+ cvp->cookie_desired = cookie_size;
On the server side, we have to test during parsing anyway. I never trust
any data that comes over the network....
^ permalink raw reply
* [PATCH 0/3] macvlan: support for guest vm direct rx/tx
From: Patrick Mullaney @ 2009-11-13 19:55 UTC (permalink / raw)
To: kaber, netdev; +Cc: alacrityvm-devel, linux-kernel, arnd, bridge
In-Reply-To: <4AFAD86A.9070506@trash.net>
(Applies to net-2.6.git/master:1dfc5827)
These patches allow other modules to override the receive
path of a macvlan. This is being done to support guest
VMs operating directly over a macvlan. Routines to allow
creation and deletion of macvlans from in-kernel modules
were also exposed/added.
---
Patrick Mullaney (3):
macvlan: allow in-kernel modules to create and manage macvlan devices
macvlan: derived from Arnd Bergmann's patch for macvtap
netdevice: provide common routine for macvlan and vlan operstate management
drivers/net/macvlan.c | 135 ++++++++++++++++++++++-----------------------
include/linux/macvlan.h | 41 ++++++++++++++
include/linux/netdevice.h | 3 +
net/8021q/vlan.c | 29 +---------
net/core/dev.c | 27 +++++++++
5 files changed, 142 insertions(+), 93 deletions(-)
create mode 100644 include/linux/macvlan.h
^ permalink raw reply
* [PATCH 1/3] netdevice: provide common routine for macvlan and vlan operstate management
From: Patrick Mullaney @ 2009-11-13 19:55 UTC (permalink / raw)
To: kaber, netdev; +Cc: alacrityvm-devel, linux-kernel, arnd, bridge
In-Reply-To: <20091113195201.11184.25766.stgit@mimic.site>
Provide common routine for the transition of operational state for a leaf
device during a root device transition.
Signed-off-by: Patrick Mullaney <pmullaney@novell.com>
---
drivers/net/macvlan.c | 24 +++---------------------
include/linux/netdevice.h | 3 +++
net/8021q/vlan.c | 29 ++++-------------------------
net/core/dev.c | 27 +++++++++++++++++++++++++++
4 files changed, 37 insertions(+), 46 deletions(-)
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 3aabfd9..41dc71f 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -455,25 +455,6 @@ static void macvlan_port_destroy(struct net_device *dev)
kfree(port);
}
-static void macvlan_transfer_operstate(struct net_device *dev)
-{
- struct macvlan_dev *vlan = netdev_priv(dev);
- const struct net_device *lowerdev = vlan->lowerdev;
-
- if (lowerdev->operstate == IF_OPER_DORMANT)
- netif_dormant_on(dev);
- else
- netif_dormant_off(dev);
-
- if (netif_carrier_ok(lowerdev)) {
- if (!netif_carrier_ok(dev))
- netif_carrier_on(dev);
- } else {
- if (netif_carrier_ok(dev))
- netif_carrier_off(dev);
- }
-}
-
static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
{
if (tb[IFLA_ADDRESS]) {
@@ -551,7 +532,7 @@ static int macvlan_newlink(struct net_device *dev,
return err;
list_add_tail(&vlan->list, &port->vlans);
- macvlan_transfer_operstate(dev);
+ netif_stacked_transfer_operstate(dev, lowerdev);
return 0;
}
@@ -591,7 +572,8 @@ static int macvlan_device_event(struct notifier_block *unused,
switch (event) {
case NETDEV_CHANGE:
list_for_each_entry(vlan, &port->vlans, list)
- macvlan_transfer_operstate(vlan->dev);
+ netif_stacked_transfer_operstate(vlan->dev,
+ vlan->lowerdev);
break;
case NETDEV_FEAT_CHANGE:
list_for_each_entry(vlan, &port->vlans, list) {
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 812a5f3..1587715 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1914,6 +1914,9 @@ unsigned long netdev_increment_features(unsigned long all, unsigned long one,
unsigned long mask);
unsigned long netdev_fix_features(unsigned long features, const char *name);
+void netif_stacked_transfer_operstate(const struct net_device *rootdev,
+ struct net_device *dev);
+
static inline int net_gso_ok(int features, int gso_type)
{
int feature = gso_type << NETIF_F_GSO_SHIFT;
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 8836575..8157b32 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -183,27 +183,6 @@ void unregister_vlan_dev(struct net_device *dev)
dev_put(real_dev);
}
-static void vlan_transfer_operstate(const struct net_device *dev,
- struct net_device *vlandev)
-{
- /* Have to respect userspace enforced dormant state
- * of real device, also must allow supplicant running
- * on VLAN device
- */
- if (dev->operstate == IF_OPER_DORMANT)
- netif_dormant_on(vlandev);
- else
- netif_dormant_off(vlandev);
-
- if (netif_carrier_ok(dev)) {
- if (!netif_carrier_ok(vlandev))
- netif_carrier_on(vlandev);
- } else {
- if (netif_carrier_ok(vlandev))
- netif_carrier_off(vlandev);
- }
-}
-
int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id)
{
const char *name = real_dev->name;
@@ -261,7 +240,7 @@ int register_vlan_dev(struct net_device *dev)
/* Account for reference in struct vlan_dev_info */
dev_hold(real_dev);
- vlan_transfer_operstate(real_dev, dev);
+ netif_stacked_transfer_operstate(real_dev, dev);
linkwatch_fire_event(dev); /* _MUST_ call rfc2863_policy() */
/* So, got the sucker initialized, now lets place
@@ -447,7 +426,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
if (!vlandev)
continue;
- vlan_transfer_operstate(dev, vlandev);
+ netif_stacked_transfer_operstate(dev, vlandev);
}
break;
@@ -503,7 +482,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
continue;
dev_change_flags(vlandev, flgs & ~IFF_UP);
- vlan_transfer_operstate(dev, vlandev);
+ netif_stacked_transfer_operstate(dev, vlandev);
}
break;
@@ -519,7 +498,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
continue;
dev_change_flags(vlandev, flgs | IFF_UP);
- vlan_transfer_operstate(dev, vlandev);
+ netif_stacked_transfer_operstate(dev, vlandev);
}
break;
diff --git a/net/core/dev.c b/net/core/dev.c
index b8f74cf..21e6f09 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4746,6 +4746,33 @@ unsigned long netdev_fix_features(unsigned long features, const char *name)
EXPORT_SYMBOL(netdev_fix_features);
/**
+ * netif_stacked_transfer_operstate - transfer operstate
+ * @rootdev: the root or lower level device to transfer state from
+ * @dev: the device to transfer operstate to
+ *
+ * Transfer operational state from root to device. This is normally
+ * called when a stacking relationship exists between the root
+ * device and the device(a leaf device).
+ */
+void netif_stacked_transfer_operstate(const struct net_device *rootdev,
+ struct net_device *dev)
+{
+ if (rootdev->operstate == IF_OPER_DORMANT)
+ netif_dormant_on(dev);
+ else
+ netif_dormant_off(dev);
+
+ if (netif_carrier_ok(rootdev)) {
+ if (!netif_carrier_ok(dev))
+ netif_carrier_on(dev);
+ } else {
+ if (netif_carrier_ok(dev))
+ netif_carrier_off(dev);
+ }
+}
+EXPORT_SYMBOL(netif_stacked_transfer_operstate);
+
+/**
* register_netdevice - register a network device
* @dev: device to register
*
^ permalink raw reply related
* [PATCH 2/3] macvlan: derived from Arnd Bergmann's patch for macvtap
From: Patrick Mullaney @ 2009-11-13 19:55 UTC (permalink / raw)
To: kaber, netdev; +Cc: alacrityvm-devel, linux-kernel, arnd, bridge
In-Reply-To: <20091113195201.11184.25766.stgit@mimic.site>
This patch includes only the basic framework for overriding the
receive path and the macvlan header was moved to allow modules
outside of driver/net to use it.
Signed-off-by: Patrick Mullaney <pmullaney@novell.com>
---
drivers/net/macvlan.c | 41 ++++++++++++++++-------------------------
include/linux/macvlan.h | 37 +++++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+), 25 deletions(-)
create mode 100644 include/linux/macvlan.h
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 41dc71f..3425e12 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -30,22 +30,7 @@
#include <linux/if_macvlan.h>
#include <net/rtnetlink.h>
-#define MACVLAN_HASH_SIZE (1 << BITS_PER_BYTE)
-
-struct macvlan_port {
- struct net_device *dev;
- struct hlist_head vlan_hash[MACVLAN_HASH_SIZE];
- struct list_head vlans;
-};
-
-struct macvlan_dev {
- struct net_device *dev;
- struct list_head list;
- struct hlist_node hlist;
- struct macvlan_port *port;
- struct net_device *lowerdev;
-};
-
+#include <linux/macvlan.h>
static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,
const unsigned char *addr)
@@ -135,7 +120,7 @@ static void macvlan_broadcast(struct sk_buff *skb,
else
nskb->pkt_type = PACKET_MULTICAST;
- netif_rx(nskb);
+ vlan->receive(nskb);
}
}
}
@@ -180,12 +165,12 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
skb->dev = dev;
skb->pkt_type = PACKET_HOST;
- netif_rx(skb);
+ vlan->receive(skb);
return NULL;
}
-static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
+netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
+ struct net_device *dev)
{
int i = skb_get_queue_mapping(skb);
struct netdev_queue *txq = netdev_get_tx_queue(dev, i);
@@ -204,6 +189,7 @@ static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
+EXPORT_SYMBOL_GPL(macvlan_start_xmit);
static int macvlan_hard_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, const void *daddr,
@@ -414,7 +400,7 @@ static const struct net_device_ops macvlan_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
};
-static void macvlan_setup(struct net_device *dev)
+void macvlan_setup(struct net_device *dev)
{
ether_setup(dev);
@@ -425,6 +411,7 @@ static void macvlan_setup(struct net_device *dev)
dev->ethtool_ops = &macvlan_ethtool_ops;
dev->tx_queue_len = 0;
}
+EXPORT_SYMBOL_GPL(macvlan_setup);
static int macvlan_port_create(struct net_device *dev)
{
@@ -455,7 +442,7 @@ static void macvlan_port_destroy(struct net_device *dev)
kfree(port);
}
-static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
+int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
{
if (tb[IFLA_ADDRESS]) {
if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
@@ -465,6 +452,7 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
}
return 0;
}
+EXPORT_SYMBOL_GPL(macvlan_validate);
static int macvlan_get_tx_queues(struct net *net,
struct nlattr *tb[],
@@ -485,8 +473,8 @@ static int macvlan_get_tx_queues(struct net *net,
return 0;
}
-static int macvlan_newlink(struct net_device *dev,
- struct nlattr *tb[], struct nlattr *data[])
+int macvlan_newlink(struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[])
{
struct macvlan_dev *vlan = netdev_priv(dev);
struct macvlan_port *port;
@@ -526,6 +514,7 @@ static int macvlan_newlink(struct net_device *dev,
vlan->lowerdev = lowerdev;
vlan->dev = dev;
vlan->port = port;
+ vlan->receive = netif_rx;
err = register_netdevice(dev);
if (err < 0)
@@ -535,8 +524,9 @@ static int macvlan_newlink(struct net_device *dev,
netif_stacked_transfer_operstate(dev, lowerdev);
return 0;
}
+EXPORT_SYMBOL_GPL(macvlan_newlink);
-static void macvlan_dellink(struct net_device *dev)
+void macvlan_dellink(struct net_device *dev)
{
struct macvlan_dev *vlan = netdev_priv(dev);
struct macvlan_port *port = vlan->port;
@@ -547,6 +537,7 @@ static void macvlan_dellink(struct net_device *dev)
if (list_empty(&port->vlans))
macvlan_port_destroy(port->dev);
}
+EXPORT_SYMBOL_GPL(macvlan_dellink);
static struct rtnl_link_ops macvlan_link_ops __read_mostly = {
.kind = "macvlan",
diff --git a/include/linux/macvlan.h b/include/linux/macvlan.h
new file mode 100644
index 0000000..3f3c6c3
--- /dev/null
+++ b/include/linux/macvlan.h
@@ -0,0 +1,37 @@
+#ifndef _MACVLAN_H
+#define _MACVLAN_H
+
+#include <linux/netdevice.h>
+#include <linux/netlink.h>
+#include <linux/list.h>
+
+#define MACVLAN_HASH_SIZE (1 << BITS_PER_BYTE)
+
+struct macvlan_port {
+ struct net_device *dev;
+ struct hlist_head vlan_hash[MACVLAN_HASH_SIZE];
+ struct list_head vlans;
+};
+
+struct macvlan_dev {
+ struct net_device *dev;
+ struct list_head list;
+ struct hlist_node hlist;
+ struct macvlan_port *port;
+ struct net_device *lowerdev;
+
+ int (*receive)(struct sk_buff *skb);
+};
+
+extern int macvlan_start_xmit(struct sk_buff *skb, struct net_device *dev);
+
+extern void macvlan_setup(struct net_device *dev);
+
+extern int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]);
+
+extern int macvlan_newlink(struct net_device *dev,
+ struct nlattr *tb[], struct nlattr *data[]);
+
+extern void macvlan_dellink(struct net_device *dev);
+
+#endif /* _MACVLAN_H */
^ permalink raw reply related
* [PATCH 3/3] macvlan: allow in-kernel modules to create and manage macvlan devices
From: Patrick Mullaney @ 2009-11-13 19:55 UTC (permalink / raw)
To: kaber, netdev; +Cc: alacrityvm-devel, linux-kernel, arnd, bridge
In-Reply-To: <20091113195201.11184.25766.stgit@mimic.site>
The macvlan driver didn't allow for creation/deletion of devices
by other in-kernel modules. This patch provides common routines
for both in-kernel and netlink based management. This patch
also enables macvlan device support for gro for lower level
devices that support gro.
Signed-off-by: Patrick Mullaney <pmullaney@novell.com>
---
drivers/net/macvlan.c | 72 ++++++++++++++++++++++++++++++++---------------
include/linux/macvlan.h | 4 +++
2 files changed, 53 insertions(+), 23 deletions(-)
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 3425e12..bb180d0 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -210,7 +210,7 @@ static const struct header_ops macvlan_hard_header_ops = {
.cache_update = eth_header_cache_update,
};
-static int macvlan_open(struct net_device *dev)
+int macvlan_open(struct net_device *dev)
{
struct macvlan_dev *vlan = netdev_priv(dev);
struct net_device *lowerdev = vlan->lowerdev;
@@ -237,7 +237,7 @@ out:
return err;
}
-static int macvlan_stop(struct net_device *dev)
+int macvlan_stop(struct net_device *dev)
{
struct macvlan_dev *vlan = netdev_priv(dev);
struct net_device *lowerdev = vlan->lowerdev;
@@ -318,7 +318,7 @@ static struct lock_class_key macvlan_netdev_addr_lock_key;
#define MACVLAN_FEATURES \
(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
- NETIF_F_TSO_ECN | NETIF_F_TSO6)
+ NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO)
#define MACVLAN_STATE_MASK \
((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
@@ -454,6 +454,44 @@ int macvlan_validate(struct nlattr *tb[], struct nlattr *data[])
}
EXPORT_SYMBOL_GPL(macvlan_validate);
+int macvlan_link_lowerdev(struct net_device *dev,
+ struct net_device *lowerdev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ struct macvlan_port *port;
+ int err = 0;
+
+ if (lowerdev->macvlan_port == NULL) {
+ err = macvlan_port_create(lowerdev);
+ if (err < 0)
+ return err;
+ }
+ port = lowerdev->macvlan_port;
+
+ vlan->lowerdev = lowerdev;
+ vlan->dev = dev;
+ vlan->port = port;
+ vlan->receive = netif_rx;
+
+ macvlan_init(dev);
+
+ list_add_tail(&vlan->list, &port->vlans);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(macvlan_link_lowerdev);
+
+void macvlan_unlink_lowerdev(struct net_device *dev)
+{
+ struct macvlan_dev *vlan = netdev_priv(dev);
+ struct macvlan_port *port = vlan->port;
+
+ list_del(&vlan->list);
+
+ if (list_empty(&port->vlans))
+ macvlan_port_destroy(port->dev);
+}
+EXPORT_SYMBOL_GPL(macvlan_unlink_lowerdev);
+
static int macvlan_get_tx_queues(struct net *net,
struct nlattr *tb[],
unsigned int *num_tx_queues,
@@ -504,38 +542,26 @@ int macvlan_newlink(struct net_device *dev,
if (!tb[IFLA_ADDRESS])
random_ether_addr(dev->dev_addr);
- if (lowerdev->macvlan_port == NULL) {
- err = macvlan_port_create(lowerdev);
- if (err < 0)
- return err;
- }
- port = lowerdev->macvlan_port;
-
- vlan->lowerdev = lowerdev;
- vlan->dev = dev;
- vlan->port = port;
- vlan->receive = netif_rx;
+ err = macvlan_link_lowerdev(dev, lowerdev);
+ if (err < 0)
+ return err;
err = register_netdevice(dev);
- if (err < 0)
+ if (err < 0) {
+ macvlan_unlink_lowerdev(dev);
return err;
+ }
- list_add_tail(&vlan->list, &port->vlans);
netif_stacked_transfer_operstate(dev, lowerdev);
+
return 0;
}
EXPORT_SYMBOL_GPL(macvlan_newlink);
void macvlan_dellink(struct net_device *dev)
{
- struct macvlan_dev *vlan = netdev_priv(dev);
- struct macvlan_port *port = vlan->port;
-
- list_del(&vlan->list);
+ macvlan_unlink_lowerdev(dev);
unregister_netdevice(dev);
-
- if (list_empty(&port->vlans))
- macvlan_port_destroy(port->dev);
}
EXPORT_SYMBOL_GPL(macvlan_dellink);
diff --git a/include/linux/macvlan.h b/include/linux/macvlan.h
index 3f3c6c3..27f56d9 100644
--- a/include/linux/macvlan.h
+++ b/include/linux/macvlan.h
@@ -24,6 +24,10 @@ struct macvlan_dev {
};
extern int macvlan_start_xmit(struct sk_buff *skb, struct net_device *dev);
+extern int macvlan_link_lowerdev(struct net_device *dev,
+ struct net_device *lowerdev);
+
+extern void macvlan_unlink_lowerdev(struct net_device *dev);
extern void macvlan_setup(struct net_device *dev);
^ permalink raw reply related
* r8169: Fix receive buffer length when MTU is between 1515 and 1536 (Was: r8169: fix driver drop incoming packets >= 1515 ...)
From: Raimonds Cicans @ 2009-11-13 20:52 UTC (permalink / raw)
To: romieu; +Cc: netdev
[-- Attachment #1: Type: text/plain, Size: 0 bytes --]
[-- Attachment #2: r8169-mtu1536-v2.patch --]
[-- Type: text/plain, Size: 1443 bytes --]
In r8169 driver MTU is used to calculate receive buffer size.
Receive buffer size is used to configure hardware incoming packet filter.
For jumbo frames:
Receive buffer size = Max frame size = MTU + 14 (ethernet header) + 4
(vlan header) + 4 (ethernet checksum) = MTU + 22
Bug:
driver for all MTU up to 1536 use receive buffer size 1536
As you can see from formula, this mean all IP packets > 1536 - 22
(for vlan tagged, 1536 - 18 for not tagged) are dropped by hardware
filter.
Example:
host_good> ifconfig eth0 mtu 1536
host_r8169> ifconfig eth0 mtu 1536
host_good> ping host_r8169
Ok
host_good> ping -s 1500 host_r8169
Fail
host_good> ifconfig eth0 mtu 7000
host_r8169> ifconfig eth0 mtu 7000
host_good> ping -s 1500 host_r8169
Ok
Bonus: got rid of magic number 8
Signed-off-by: Raimonds Cicans <ray@apollo.lv>
---
--- linux-2.6.31/drivers/net/r8169.c.orig 2009-11-06 21:52:12.722326601 +0200
+++ linux-2.6.31/drivers/net/r8169.c 2009-11-06 22:09:17.242224014 +0200
@@ -2229,9 +2229,9 @@ static void __devexit rtl8169_remove_one
static void rtl8169_set_rxbufsize(struct rtl8169_private *tp,
struct net_device *dev)
{
- unsigned int mtu = dev->mtu;
+ unsigned int max_frame = dev->mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
- tp->rx_buf_sz = (mtu > RX_BUF_SIZE) ? mtu + ETH_HLEN + 8 : RX_BUF_SIZE;
+ tp->rx_buf_sz = (max_frame > RX_BUF_SIZE) ? max_frame : RX_BUF_SIZE;
}
static int rtl8169_open(struct net_device *dev)
^ permalink raw reply
* Re: large packet loss take2 2.6.31.x
From: Jarek Poplawski @ 2009-11-13 21:16 UTC (permalink / raw)
To: Caleb Cushing; +Cc: Frans Pop, Andi Kleen, linux-kernel, netdev
In-Reply-To: <81bfc67a0911130825o6d9b93b2he70677157ad889f2@mail.gmail.com>
On Fri, Nov 13, 2009 at 11:25:25AM -0500, Caleb Cushing wrote:
> > So I assume it's your only network device on this box and according
> > to these reports it's 192.168.1.3 with 192.168.1.1 as the gateway,
> > and your only change is kernel on this 192.168.1.3 box, right?
>
> yes, and semi obviously that router is my box (LinkSys wrt 54gl
> openwrt kamikaze 8.09.1.
>
> > Since the loss is seen on the first hop already, it seems it should be
> > enough to query 192.168.1.1 only - did you try this? If so, does this
> > happen from the beginning of the test or after many loops? Could you
> > try to repeat this wireshark dump with more data than before (but just
> > to be sure there are a few unanswered pings). If possible it would be
> > nice to have wireshark or tcpdump data from 192.168.1.1 too, while
> > pinged from 192.168.1.3. Please, send it gzipped to bugzilla only plus
> > ifconfig eth0 before and after the test (and let us know here).
>
> same bug? or new bug? I can see what I can do to get a tcpdump from
> the router. yes I tried that, I can tell within the first 10 pings. I
> should say I don't notice it on every kernel boot, it's ~80% of
> reboots (but that's pulled from my behind). but I haven't noticed it
> on gfa31221 at all. it's reproducible in 31.6 too (arch just added
> that).
Might be the same bugzilla report, I guess. We need to establish if
these pings reach 192.168.1.1, so a short test and tcpdump without any
special options just to get a few lost cases as seen on both sides.
(And ifconfigs before and after the test.)
Btw, could you check with lsmod if usbserial module is loaded before
this test? I'd like to verify this git bisection result. (If the
module is loaded or you have CONFIG_USB_SERIAL=y instead of m, try to
recompile the kernel with this option turned off, for this test.)
Thanks,
Jarek P.
^ permalink raw reply
* Re: [PATCH 0/3] macvlan: support for guest vm direct rx/tx
From: Stephen Hemminger @ 2009-11-13 21:27 UTC (permalink / raw)
To: Patrick Mullaney
Cc: kaber, netdev, alacrityvm-devel, linux-kernel, arnd, bridge
In-Reply-To: <20091113195201.11184.25766.stgit@mimic.site>
On Fri, 13 Nov 2009 14:55:06 -0500
Patrick Mullaney <pmullaney@novell.com> wrote:
> These patches allow other modules to override the receive
> path of a macvlan. This is being done to support guest
> VMs operating directly over a macvlan. Routines to allow
> creation and deletion of macvlans from in-kernel modules
> were also exposed/added.
Which guest VM, how will it use it? The kernel is not in the business
of providing infrastructure for out of tree patches.
Also, macvlan should really being calling netif_receive_skb()
not going through another queue/softirq cycle.
^ permalink raw reply
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