* [PATCH 3/7] mfd: core: copy DMA mask and params from parent
From: Benedikt Spranger @ 2013-08-13 9:08 UTC (permalink / raw)
To: netdev
Cc: Alexander Frank, Sebastian Andrzej Siewior, Benedikt Spranger,
Samuel Ortiz, Lee Jones, Holger Dengler
In-Reply-To: <1376384922-8519-1-git-send-email-b.spranger@linutronix.de>
The child device intends to perform DMA operations then it needs a dma
mask and params set. This patches copies them from the parent device.
Cc: Samuel Ortiz <sameo@linux.intel.com>
Cc: Lee Jones <lee.jones@linaro.org>
Signed-off-by: Benedikt Spranger <b.spranger@linutronix.de>
Signed-off-by: Holger Dengler <dengler@linutronix.de>
---
drivers/mfd/mfd-core.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index 7604f4e..f421586 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -96,6 +96,8 @@ static int mfd_add_device(struct device *parent, int id,
pdev->dev.parent = parent;
pdev->dev.type = &mfd_dev_type;
+ pdev->dev.dma_mask = parent->dma_mask;
+ pdev->dev.dma_parms = parent->dma_parms;
if (parent->of_node && cell->of_compatible) {
for_each_child_of_node(parent->of_node, np) {
--
1.8.4.rc2
^ permalink raw reply related
* [PATCH 2/7] uio: Allow to create custom UIO attributes
From: Benedikt Spranger @ 2013-08-13 9:08 UTC (permalink / raw)
To: netdev
Cc: Alexander Frank, Sebastian Andrzej Siewior, Benedikt Spranger,
Hans J. Koch, Greg Kroah-Hartman, Holger Dengler
In-Reply-To: <1376384922-8519-1-git-send-email-b.spranger@linutronix.de>
This patch the struct uio_attribute which represents a custom UIO
attribute. The non-standard attributes are stored in a "attr" directory.
This will be used by the flexcard driver which creates a UIO device that
is using the "uio_pdrv" and requires one additional value to be read /
written by the user.
Cc: "Hans J. Koch" <hjk@hansjkoch.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Benedikt Spranger <b.spranger@linutronix.de>
Signed-off-by: Holger Dengler <dengler@linutronix.de>
---
drivers/uio/uio.c | 106 ++++++++++++++++++++++++++++++++++++++++++++-
include/linux/uio_driver.h | 36 +++++++++++----
2 files changed, 133 insertions(+), 9 deletions(-)
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 9a95220..d66784a 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -39,6 +39,7 @@ struct uio_device {
struct uio_info *info;
struct kobject *map_dir;
struct kobject *portio_dir;
+ struct kobject attr_dir;
};
static int uio_major;
@@ -252,6 +253,49 @@ static struct device_attribute uio_class_attributes[] = {
{}
};
+static ssize_t uio_type_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct uio_device *idev;
+ struct uio_info *info;
+ struct uio_attribute *entry;
+
+ idev = container_of(kobj, struct uio_device, attr_dir);
+ info = idev->info;
+ entry = container_of(attr, struct uio_attribute, attr);
+
+ if (!entry->show)
+ return -EIO;
+
+ return entry->show(info, buf);
+}
+
+static ssize_t uio_type_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
+{
+ struct uio_device *idev;
+ struct uio_info *info;
+ struct uio_attribute *entry;
+
+ idev = container_of(kobj, struct uio_device, attr_dir);
+ info = idev->info;
+ entry = container_of(attr, struct uio_attribute, attr);
+
+ if (!entry->store)
+ return -EIO;
+
+ return entry->store(info, buf, count);
+}
+
+static const struct sysfs_ops uio_sysfs_ops = {
+ .show = uio_type_show,
+ .store = uio_type_store,
+};
+
+static struct kobj_type uio_attr_type = {
+ .sysfs_ops = &uio_sysfs_ops,
+};
+
/* UIO class infrastructure */
static struct class uio_class = {
.name = "uio",
@@ -323,8 +367,16 @@ static int uio_dev_add_attributes(struct uio_device *idev)
goto err_portio;
}
+ ret = kobject_init_and_add(&idev->attr_dir, &uio_attr_type,
+ &idev->dev->kobj, "attr");
+ if (ret)
+ goto err_attr;
+
return 0;
+err_attr:
+ kobject_put(&idev->attr_dir);
+
err_portio:
for (pi--; pi >= 0; pi--) {
port = &idev->info->port[pi];
@@ -364,6 +416,7 @@ static void uio_dev_del_attributes(struct uio_device *idev)
kobject_put(&port->portio->kobj);
}
kobject_put(idev->portio_dir);
+ kobject_put(&idev->attr_dir);
}
static int uio_get_minor(struct uio_device *idev)
@@ -391,6 +444,50 @@ static void uio_free_minor(struct uio_device *idev)
}
/**
+ * uio_add_user_attributes - add an extra UIO attribute
+ * @info: UIO device capabilities
+ */
+static int uio_add_user_attributes(struct uio_info *info)
+{
+ struct uio_device *idev = info->uio_dev;
+ const struct uio_attribute **uio_attr;
+ int i;
+ int ret = 0;
+
+ uio_attr = info->attributes;
+ if (!uio_attr)
+ return 0;
+
+ for (i = 0; uio_attr[i]; i++) {
+
+ ret = sysfs_create_file(&idev->attr_dir, &uio_attr[i]->attr);
+ if (ret)
+ break;
+ }
+ if (ret) {
+ while (--i >= 0)
+ sysfs_remove_file(&idev->attr_dir, &uio_attr[i]->attr);
+ }
+ return ret;
+}
+
+/**
+ * uio_del_user_attributes - delete an extra UIO attribute
+ * @info: UIO device capabilities
+ */
+static void uio_del_user_attributes(struct uio_info *info)
+{
+ struct uio_device *idev = info->uio_dev;
+ const struct uio_attribute **uio_attr;
+ int i;
+
+ uio_attr = info->attributes;
+
+ for (i = 0; uio_attr[i]; i++)
+ sysfs_remove_file(&idev->attr_dir, &uio_attr[i]->attr);
+}
+
+/**
* uio_event_notify - trigger an interrupt event
* @info: UIO device capabilities
*/
@@ -846,8 +943,14 @@ int __uio_register_device(struct module *owner,
goto err_request_irq;
}
- return 0;
+ ret = uio_add_user_attributes(info);
+ if (ret)
+ goto err_free_irq;
+ return 0;
+err_free_irq:
+ if (info->irq && (info->irq != UIO_IRQ_CUSTOM))
+ free_irq(info->irq, idev);
err_request_irq:
uio_dev_del_attributes(idev);
err_uio_dev_add_attributes:
@@ -881,6 +984,7 @@ void uio_unregister_device(struct uio_info *info)
free_irq(info->irq, idev);
uio_dev_del_attributes(idev);
+ uio_del_user_attributes(idev->info);
device_destroy(&uio_class, MKDEV(uio_major, idev->minor));
kfree(idev);
diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h
index 99f1696..2e7543e 100644
--- a/include/linux/uio_driver.h
+++ b/include/linux/uio_driver.h
@@ -64,6 +64,7 @@ struct uio_port {
#define MAX_UIO_PORT_REGIONS 5
struct uio_device;
+struct uio_attribute;
/**
* struct uio_info - UIO device capabilities
@@ -72,6 +73,7 @@ struct uio_device;
* @version: device driver version
* @mem: list of mappable memory regions, size==0 for end of list
* @port: list of port regions, size==0 for end of list
+ * @attributes: list of additional attributes, NULL for end of list
* @irq: interrupt number or UIO_IRQ_CUSTOM
* @irq_flags: flags for request_irq()
* @priv: optional private data
@@ -83,14 +85,15 @@ struct uio_device;
* @owner: module which created the uio device incase
*/
struct uio_info {
- struct uio_device *uio_dev;
- const char *name;
- const char *version;
- struct uio_mem mem[MAX_UIO_MAPS];
- struct uio_port port[MAX_UIO_PORT_REGIONS];
- long irq;
- unsigned long irq_flags;
- void *priv;
+ struct uio_device *uio_dev;
+ const char *name;
+ const char *version;
+ struct uio_mem mem[MAX_UIO_MAPS];
+ struct uio_port port[MAX_UIO_PORT_REGIONS];
+ const struct uio_attribute **attributes;
+ long irq;
+ unsigned long irq_flags;
+ void *priv;
irqreturn_t (*handler)(int irq, struct uio_info *dev_info);
int (*mmap)(struct uio_info *info, struct vm_area_struct *vma);
int (*open)(struct uio_info *info, struct inode *inode);
@@ -99,6 +102,23 @@ struct uio_info {
struct module *owner;
};
+/**
+ * struct uio_attribute - UIO attribute
+ * @attr: the attribute
+ * @show: attribute show function
+ * @store: attribute store function
+ */
+struct uio_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct uio_info *info, char *buf);
+ ssize_t (*store)(struct uio_info *info, const char *buf, size_t count);
+};
+
+#define UIO_ATTR(_name, _mode, _show, _store) \
+ struct uio_attribute uio_attr_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+
extern int __must_check
__uio_register_device(struct module *owner,
struct device *parent,
--
1.8.4.rc2
^ permalink raw reply related
* [PATCH 1/7] uio: add module owner to prevent inappropriate module unloading
From: Benedikt Spranger @ 2013-08-13 9:08 UTC (permalink / raw)
To: netdev
Cc: Alexander Frank, Sebastian Andrzej Siewior, Benedikt Spranger,
Hans J. Koch, Greg Kroah-Hartman, Holger Dengler
In-Reply-To: <1376384922-8519-1-git-send-email-b.spranger@linutronix.de>
If an UIO device is created by another driver (MFD for instance) it has to be
ensured that the MFD driver isn't removed while the UIO is still in use.
This patch adds a reference to the parent driver which does module refcounting
in order to avoid an too early removal.
Cc: "Hans J. Koch" <hjk@hansjkoch.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Benedikt Spranger <b.spranger@linutronix.de>
Signed-off-by: Holger Dengler <dengler@linutronix.de>
---
drivers/uio/uio.c | 9 +++++++++
include/linux/uio_driver.h | 2 ++
2 files changed, 11 insertions(+)
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index 3b96f18..9a95220 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -444,6 +444,11 @@ static int uio_open(struct inode *inode, struct file *filep)
goto out;
}
+ if (!try_module_get(idev->info->owner)) {
+ ret = -ENODEV;
+ goto err_get_module;
+ }
+
listener = kmalloc(sizeof(*listener), GFP_KERNEL);
if (!listener) {
ret = -ENOMEM;
@@ -465,6 +470,9 @@ err_infoopen:
kfree(listener);
err_alloc_listener:
+ module_put(idev->info->owner);
+
+err_get_module:
module_put(idev->owner);
out:
@@ -488,6 +496,7 @@ static int uio_release(struct inode *inode, struct file *filep)
if (idev->info->release)
ret = idev->info->release(idev->info, inode);
+ module_put(idev->info->owner);
module_put(idev->owner);
kfree(listener);
return ret;
diff --git a/include/linux/uio_driver.h b/include/linux/uio_driver.h
index 1ad4724..99f1696 100644
--- a/include/linux/uio_driver.h
+++ b/include/linux/uio_driver.h
@@ -80,6 +80,7 @@ struct uio_device;
* @open: open operation for this uio device
* @release: release operation for this uio device
* @irqcontrol: disable/enable irqs when 0/1 is written to /dev/uioX
+ * @owner: module which created the uio device incase
*/
struct uio_info {
struct uio_device *uio_dev;
@@ -95,6 +96,7 @@ struct uio_info {
int (*open)(struct uio_info *info, struct inode *inode);
int (*release)(struct uio_info *info, struct inode *inode);
int (*irqcontrol)(struct uio_info *info, s32 irq_on);
+ struct module *owner;
};
extern int __must_check
--
1.8.4.rc2
^ permalink raw reply related
* [PATCH 0/7] add FlexRay support
From: Benedikt Spranger @ 2013-08-13 9:08 UTC (permalink / raw)
To: netdev; +Cc: Alexander Frank, Sebastian Andrzej Siewior, Benedikt Spranger
In-Reply-To: <1376384922-8519-1-git-send-email-b.spranger@linutronix.de>
This series adds FlexRay support to the Linux Kernel. FlexRay is designed and
used as a successor of Controller Area Network (CAN) in the automotive fields.
FlexRay is specified in ISO 10681. A quick overview is available here:
http://en.wikipedia.org/wiki/FlexRay
The driver implementation adds support for the Eberspaecher Electronics
FlexCard. The FlexCard is a PCI Mezzanine Card with piggybacks for automotive
buses like CAN, LIN and FlexRay. A implementation based on multifunctional
devices (MFD) was choosen. The independant IP cores (FlexRay, CAN, etc) can be
supported by separate drivers. In addition to the automotive busses the
FlexCard provides some generic functions coverd by the clocksoure and the UIO
drivers. The AF_FLEXRAY protocol can be used to send and receive flexray frames
from the userland.
Benedikt Spranger (7):
uio: add module owner to prevent inappropriate module unloading
uio: Allow to create custom UIO attributes
mfd: core: copy DMA mask and params from parent
mfd: add MFD based flexcard driver
clocksource: Add flexcard support
net: add the AF_FLEXRAY protocol
net: add a flexray driver
Documentation/networking/00-INDEX | 2 +
Documentation/networking/flexray.txt | 24 +
drivers/clocksource/Kconfig | 13 +
drivers/clocksource/Makefile | 2 +
drivers/clocksource/flexcard_clk.c | 297 +++
drivers/clocksource/flexcard_evt.c | 161 ++
drivers/mfd/Kconfig | 42 +
drivers/mfd/Makefile | 2 +
drivers/mfd/flexcard-core.c | 1059 +++++++++++
drivers/mfd/flexcard-dma.c | 561 ++++++
drivers/mfd/flexcard-irq.c | 333 ++++
drivers/mfd/flexcard.h | 8 +
drivers/mfd/mfd-core.c | 2 +
drivers/net/Makefile | 1 +
drivers/net/flexray/Kconfig | 41 +
drivers/net/flexray/Makefile | 12 +
drivers/net/flexray/dev.c | 700 +++++++
drivers/net/flexray/flexcard_fr.c | 2480 +++++++++++++++++++++++++
drivers/net/flexray/vflexray.c | 99 +
drivers/uio/uio.c | 115 +-
include/linux/eray.h | 650 +++++++
include/linux/flexcard.h | 95 +
include/linux/flexray.h | 168 ++
include/linux/flexray/core.h | 45 +
include/linux/flexray/dev.h | 64 +
include/linux/socket.h | 4 +-
include/linux/uio_driver.h | 38 +-
include/uapi/linux/Kbuild | 2 +
include/uapi/linux/eray.h | 34 +
include/uapi/linux/flexcard.h | 429 +++++
include/uapi/linux/flexray/Kbuild | 4 +
include/uapi/linux/flexray/flexcard_netlink.h | 53 +
include/uapi/linux/flexray/netlink.h | 203 ++
include/uapi/linux/flexray/raw.h | 16 +
include/uapi/linux/if_arp.h | 1 +
include/uapi/linux/if_ether.h | 1 +
net/Kconfig | 1 +
net/Makefile | 1 +
net/core/sock.c | 9 +-
net/flexray/Kconfig | 30 +
net/flexray/Makefile | 9 +
net/flexray/af_flexray.c | 548 ++++++
net/flexray/af_flexray.h | 59 +
net/flexray/proc.c | 196 ++
net/flexray/raw.c | 446 +++++
45 files changed, 9047 insertions(+), 13 deletions(-)
create mode 100644 Documentation/networking/flexray.txt
create mode 100644 drivers/clocksource/flexcard_clk.c
create mode 100644 drivers/clocksource/flexcard_evt.c
create mode 100644 drivers/mfd/flexcard-core.c
create mode 100644 drivers/mfd/flexcard-dma.c
create mode 100644 drivers/mfd/flexcard-irq.c
create mode 100644 drivers/mfd/flexcard.h
create mode 100644 drivers/net/flexray/Kconfig
create mode 100644 drivers/net/flexray/Makefile
create mode 100644 drivers/net/flexray/dev.c
create mode 100644 drivers/net/flexray/flexcard_fr.c
create mode 100644 drivers/net/flexray/vflexray.c
create mode 100644 include/linux/eray.h
create mode 100644 include/linux/flexcard.h
create mode 100644 include/linux/flexray.h
create mode 100644 include/linux/flexray/core.h
create mode 100644 include/linux/flexray/dev.h
create mode 100644 include/uapi/linux/eray.h
create mode 100644 include/uapi/linux/flexcard.h
create mode 100644 include/uapi/linux/flexray/Kbuild
create mode 100644 include/uapi/linux/flexray/flexcard_netlink.h
create mode 100644 include/uapi/linux/flexray/netlink.h
create mode 100644 include/uapi/linux/flexray/raw.h
create mode 100644 net/flexray/Kconfig
create mode 100644 net/flexray/Makefile
create mode 100644 net/flexray/af_flexray.c
create mode 100644 net/flexray/af_flexray.h
create mode 100644 net/flexray/proc.c
create mode 100644 net/flexray/raw.c
--
1.8.4.rc2
^ permalink raw reply
* [PATCH 0/7] add FlexRay support
From: Benedikt Spranger @ 2013-08-13 9:08 UTC (permalink / raw)
To: netdev; +Cc: Alexander Frank, Sebastian Andrzej Siewior, Benedikt Spranger
This series adds FlexRay support to the Linux Kernel. FlexRay is designed and
used as a successor of Controller Area Network (CAN) in the automotive fields.
FlexRay is specified in ISO 10681. A quick overview is available here:
http://en.wikipedia.org/wiki/FlexRay
The driver implementation adds support for the Eberspaecher Electronics
FlexCard. The FlexCard is a PCI Mezzanine Card with piggybacks for automotive
buses like CAN, LIN and FlexRay. An implementation based on multifunctional
devices (MFD) was choosen. The independant IP cores (FlexRay, CAN, etc) can be
supported by separate drivers. In addition to the automotive busses the
FlexCard provides some generic functions coverd by the clocksoure and the UIO
drivers. The AF_FLEXRAY protocol can be used to send and receive flexray frames
from the userland.
Benedikt Spranger (7):
uio: add module owner to prevent inappropriate module unloading
uio: Allow to create custom UIO attributes
mfd: core: copy DMA mask and params from parent
mfd: add MFD based flexcard driver
clocksource: Add flexcard support
net: add the AF_FLEXRAY protocol
net: add a flexray driver
Documentation/networking/00-INDEX | 2 +
Documentation/networking/flexray.txt | 24 +
drivers/clocksource/Kconfig | 13 +
drivers/clocksource/Makefile | 2 +
drivers/clocksource/flexcard_clk.c | 297 +++
drivers/clocksource/flexcard_evt.c | 161 ++
drivers/mfd/Kconfig | 42 +
drivers/mfd/Makefile | 2 +
drivers/mfd/flexcard-core.c | 1059 +++++++++++
drivers/mfd/flexcard-dma.c | 561 ++++++
drivers/mfd/flexcard-irq.c | 333 ++++
drivers/mfd/flexcard.h | 8 +
drivers/mfd/mfd-core.c | 2 +
drivers/net/Makefile | 1 +
drivers/net/flexray/Kconfig | 41 +
drivers/net/flexray/Makefile | 12 +
drivers/net/flexray/dev.c | 700 +++++++
drivers/net/flexray/flexcard_fr.c | 2480 +++++++++++++++++++++++++
drivers/net/flexray/vflexray.c | 99 +
drivers/uio/uio.c | 115 +-
include/linux/eray.h | 650 +++++++
include/linux/flexcard.h | 95 +
include/linux/flexray.h | 168 ++
include/linux/flexray/core.h | 45 +
include/linux/flexray/dev.h | 64 +
include/linux/socket.h | 4 +-
include/linux/uio_driver.h | 38 +-
include/uapi/linux/Kbuild | 2 +
include/uapi/linux/eray.h | 34 +
include/uapi/linux/flexcard.h | 429 +++++
include/uapi/linux/flexray/Kbuild | 4 +
include/uapi/linux/flexray/flexcard_netlink.h | 53 +
include/uapi/linux/flexray/netlink.h | 203 ++
include/uapi/linux/flexray/raw.h | 16 +
include/uapi/linux/if_arp.h | 1 +
include/uapi/linux/if_ether.h | 1 +
net/Kconfig | 1 +
net/Makefile | 1 +
net/core/sock.c | 9 +-
net/flexray/Kconfig | 30 +
net/flexray/Makefile | 9 +
net/flexray/af_flexray.c | 548 ++++++
net/flexray/af_flexray.h | 59 +
net/flexray/proc.c | 196 ++
net/flexray/raw.c | 446 +++++
45 files changed, 9047 insertions(+), 13 deletions(-)
create mode 100644 Documentation/networking/flexray.txt
create mode 100644 drivers/clocksource/flexcard_clk.c
create mode 100644 drivers/clocksource/flexcard_evt.c
create mode 100644 drivers/mfd/flexcard-core.c
create mode 100644 drivers/mfd/flexcard-dma.c
create mode 100644 drivers/mfd/flexcard-irq.c
create mode 100644 drivers/mfd/flexcard.h
create mode 100644 drivers/net/flexray/Kconfig
create mode 100644 drivers/net/flexray/Makefile
create mode 100644 drivers/net/flexray/dev.c
create mode 100644 drivers/net/flexray/flexcard_fr.c
create mode 100644 drivers/net/flexray/vflexray.c
create mode 100644 include/linux/eray.h
create mode 100644 include/linux/flexcard.h
create mode 100644 include/linux/flexray.h
create mode 100644 include/linux/flexray/core.h
create mode 100644 include/linux/flexray/dev.h
create mode 100644 include/uapi/linux/eray.h
create mode 100644 include/uapi/linux/flexcard.h
create mode 100644 include/uapi/linux/flexray/Kbuild
create mode 100644 include/uapi/linux/flexray/flexcard_netlink.h
create mode 100644 include/uapi/linux/flexray/netlink.h
create mode 100644 include/uapi/linux/flexray/raw.h
create mode 100644 net/flexray/Kconfig
create mode 100644 net/flexray/Makefile
create mode 100644 net/flexray/af_flexray.c
create mode 100644 net/flexray/af_flexray.h
create mode 100644 net/flexray/proc.c
create mode 100644 net/flexray/raw.c
--
1.8.4.rc2
^ permalink raw reply
* Re: [PATCH net-next 1/3] net/usb/r8152: support aggregation
From: Oliver Neukum @ 2013-08-13 8:49 UTC (permalink / raw)
To: Hayes Wang
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1376378913-879-1-git-send-email-hayeswang-Rasf1IRRPZFBDgjK7y7TUQ@public.gmane.org>
On Tue, 2013-08-13 at 15:28 +0800, Hayes Wang wrote:
> +
> +static void rx_bottom(struct r8152 *tp)
> +{
> + struct net_device_stats *stats;
> + struct net_device *netdev;
> + struct rx_agg *agg;
> + struct rx_desc *rx_desc;
> + unsigned long lockflags;
> + struct list_head *cursor, *next;
> + struct sk_buff *skb;
> + struct urb *urb;
> + unsigned pkt_len;
> + int len_used;
> + u8 *rx_data;
> + int ret;
> +
> + netdev = tp->netdev;
> +
> + if (!netif_running(netdev))
> return;
> - dev_kfree_skb_irq(tp->tx_skb);
> - if (!netif_device_present(tp->netdev))
> +
> + stats = rtl8152_get_stats(netdev);
> +
> + spin_lock_irqsave(&tp->rx_lock, lockflags);
> + list_for_each_safe(cursor, next, &tp->rx_done) {
> + list_del_init(cursor);
> + spin_unlock_irqrestore(&tp->rx_lock, lockflags);
> +
> + agg = list_entry(cursor, struct rx_agg, list);
> + urb = agg->urb;
> + if (urb->actual_length < ETH_ZLEN) {
> + ret = r8152_submit_rx(tp, agg, GFP_ATOMIC);
> + spin_lock_irqsave(&tp->rx_lock, lockflags);
> + if (ret && ret != -ENODEV) {
> + list_add_tail(&agg->list, next);
> + tasklet_schedule(&tp->tl);
> + }
> + continue;
> + }
> +
> + len_used = 0;
> + rx_desc = agg->head;
> + rx_data = agg->head;
> + smp_wmb();
> + pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
> + len_used += sizeof(struct rx_desc) + pkt_len;
> +
> + while (urb->actual_length >= len_used) {
> + if (pkt_len < ETH_ZLEN)
> + break;
> +
> + pkt_len -= 4; /* CRC */
> + rx_data += sizeof(struct rx_desc);
> +
> + skb = netdev_alloc_skb_ip_align(netdev,
> pkt_len);
> + if (!skb) {
> + stats->rx_dropped++;
> + break;
> + }
> + memcpy(skb->data, rx_data, pkt_len);
> + skb_put(skb, pkt_len);
> + skb->protocol = eth_type_trans(skb, netdev);
> + netif_rx(skb);
> + stats->rx_packets++;
> + stats->rx_bytes += pkt_len;
> +
> + rx_data = rx_agg_align(rx_data + pkt_len + 4);
> + rx_desc = (struct rx_desc *)rx_data;
> + smp_wmb();
Against what is the memory barrier?
> + pkt_len = le32_to_cpu(rx_desc->opts1) &
> RX_LEN_MASK;
> + len_used = (int)(rx_data - (u8 *)agg->head);
> + len_used += sizeof(struct rx_desc) + pkt_len;
> + }
> +
> + ret = r8152_submit_rx(tp, agg, GFP_ATOMIC);
> + spin_lock_irqsave(&tp->rx_lock, lockflags);
> + if (ret && ret != -ENODEV) {
> + list_add_tail(&agg->list, next);
> + tasklet_schedule(&tp->tl);
> + }
> + }
> + spin_unlock_irqrestore(&tp->rx_lock, lockflags);
> +}
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH net] ip_tunnel: Do not use inner ip-header-id for tunnel ip-header-id.
From: Pravin B Shelar @ 2013-08-13 8:41 UTC (permalink / raw)
To: netdev; +Cc: Pravin B Shelar, Jarno Rajahalme, Ansis Atteka
Using inner-id for tunnel id is not safe in some rare cases.
E.g. packets coming from multiple sources entering same tunnel
can have same id. Therefore on tunnel packet receive we
could have packets from two different stream but with same
source and dst IP with same ip-id which could confuse ip packet
reassembly.
Following patch reverts optimization from commit
490ab08127 (IP_GRE: Fix IP-Identification.)
CC: Jarno Rajahalme <jrajahalme@nicira.com>
CC: Ansis Atteka <aatteka@nicira.com>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
---
include/net/ip_tunnels.h | 14 --------------
net/ipv4/ip_tunnel_core.c | 4 +---
2 files changed, 1 insertions(+), 17 deletions(-)
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 781b3cf..a354db5 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -145,20 +145,6 @@ static inline u8 ip_tunnel_ecn_encap(u8 tos, const struct iphdr *iph,
return INET_ECN_encapsulate(tos, inner);
}
-static inline void tunnel_ip_select_ident(struct sk_buff *skb,
- const struct iphdr *old_iph,
- struct dst_entry *dst)
-{
- struct iphdr *iph = ip_hdr(skb);
-
- /* Use inner packet iph-id if possible. */
- if (skb->protocol == htons(ETH_P_IP) && old_iph->id)
- iph->id = old_iph->id;
- else
- __ip_select_ident(iph, dst,
- (skb_shinfo(skb)->gso_segs ?: 1) - 1);
-}
-
int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto);
int iptunnel_xmit(struct net *net, struct rtable *rt,
struct sk_buff *skb,
diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c
index 7167b08..850525b 100644
--- a/net/ipv4/ip_tunnel_core.c
+++ b/net/ipv4/ip_tunnel_core.c
@@ -76,9 +76,7 @@ int iptunnel_xmit(struct net *net, struct rtable *rt,
iph->daddr = dst;
iph->saddr = src;
iph->ttl = ttl;
- tunnel_ip_select_ident(skb,
- (const struct iphdr *)skb_inner_network_header(skb),
- &rt->dst);
+ __ip_select_ident(iph, &rt->dst, (skb_shinfo(skb)->gso_segs ?: 1) - 1);
err = ip_local_out(skb);
if (unlikely(net_xmit_eval(err)))
--
1.7.1
^ permalink raw reply related
* [GLIBC Patch] inet: avoid redefinition of some structs in kernel
From: Cong Wang @ 2013-08-13 8:37 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Thomas Backlund, libc-alpha, YOSHIFUJI Hideaki,
Carlos O'Donell, Cong Wang
In-Reply-To: <1376383054-9184-1-git-send-email-amwang@redhat.com>
From: Carlos O'Donell <carlos@redhat.com>
- Synchronize linux's `include/uapi/linux/in6.h'
with glibc's `inet/netinet/in.h'.
- Synchronize glibc's `inet/netinet/in.h with linux's
`include/uapi/linux/in6.h'.
- Allow including the headers in either other.
- First header included defines the structures and macros.
Notes:
- You want netinet/in.h to include bits/in.h as early as possible,
but it needs in_addr so define in_addr early.
- You want bits/in.h included as early as possible so you can use
the linux specific code to define __USE_KERNEL_DEFS based on
the _UAPI_* macro definition and use those to cull in.h.
- glibc was missing IPPROTO_MH, added here.
Reported-by: Thomas Backlund <tmb@mageia.org>
Cc: Thomas Backlund <tmb@mageia.org>
Cc: libc-alpha@sourceware.org
Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Cong Wang <amwang@redhat.com>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
diff --git a/ChangeLog b/ChangeLog
index bf48b5d..9de6536 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2013-08-13 Carlos O'Donell <carlos@redhat.com>
+ Cong Wang <amwang@redhat.com>
+
+ * sysdeps/unix/sysv/linux/bits/in.h
+ [_UAPI_LINUX_IN6_H]: Define __USE_KERNEL_IPV6_DEFS.
+ * inet/netinet/in.h: Move in_addr definition and bits/in.h inclusion
+ before __USE_KERNEL_IPV6_DEFS uses.
+ * inet/netinet/in.h [!__USE_KERNEL_IPV6_DEFS]: Define IPPROTO_MH, and
+ IPPROTO_BEETPH.
+ [__USE_KERNEL_IPV6_DEFS]: Don't define any of IPPROTO_*, in6_addr,
+ sockaddr_in6, or ipv6_mreq.
+
2013-08-13 Andreas Schwab <schwab@suse.de>
[BZ #15749]
diff --git a/inet/netinet/in.h b/inet/netinet/in.h
index 89e3813..05c77e2 100644
--- a/inet/netinet/in.h
+++ b/inet/netinet/in.h
@@ -26,13 +26,21 @@
__BEGIN_DECLS
+/* Internet address. */
+typedef uint32_t in_addr_t;
+struct in_addr
+ {
+ in_addr_t s_addr;
+ };
+
+/* Get system-specific definitions. */
+#include <bits/in.h>
+
/* Standard well-defined IP protocols. */
enum
{
IPPROTO_IP = 0, /* Dummy protocol for TCP. */
#define IPPROTO_IP IPPROTO_IP
- IPPROTO_HOPOPTS = 0, /* IPv6 Hop-by-Hop options. */
-#define IPPROTO_HOPOPTS IPPROTO_HOPOPTS
IPPROTO_ICMP = 1, /* Internet Control Message Protocol. */
#define IPPROTO_ICMP IPPROTO_ICMP
IPPROTO_IGMP = 2, /* Internet Group Management Protocol. */
@@ -55,10 +63,6 @@ enum
#define IPPROTO_DCCP IPPROTO_DCCP
IPPROTO_IPV6 = 41, /* IPv6 header. */
#define IPPROTO_IPV6 IPPROTO_IPV6
- IPPROTO_ROUTING = 43, /* IPv6 routing header. */
-#define IPPROTO_ROUTING IPPROTO_ROUTING
- IPPROTO_FRAGMENT = 44, /* IPv6 fragmentation header. */
-#define IPPROTO_FRAGMENT IPPROTO_FRAGMENT
IPPROTO_RSVP = 46, /* Reservation Protocol. */
#define IPPROTO_RSVP IPPROTO_RSVP
IPPROTO_GRE = 47, /* General Routing Encapsulation. */
@@ -67,14 +71,10 @@ enum
#define IPPROTO_ESP IPPROTO_ESP
IPPROTO_AH = 51, /* authentication header. */
#define IPPROTO_AH IPPROTO_AH
- IPPROTO_ICMPV6 = 58, /* ICMPv6. */
-#define IPPROTO_ICMPV6 IPPROTO_ICMPV6
- IPPROTO_NONE = 59, /* IPv6 no next header. */
-#define IPPROTO_NONE IPPROTO_NONE
- IPPROTO_DSTOPTS = 60, /* IPv6 destination options. */
-#define IPPROTO_DSTOPTS IPPROTO_DSTOPTS
IPPROTO_MTP = 92, /* Multicast Transport Protocol. */
#define IPPROTO_MTP IPPROTO_MTP
+ IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET. */
+#define IPPROTO_BEETPH IPPROTO_BEETPH
IPPROTO_ENCAP = 98, /* Encapsulation Header. */
#define IPPROTO_ENCAP IPPROTO_ENCAP
IPPROTO_PIM = 103, /* Protocol Independent Multicast. */
@@ -90,6 +90,28 @@ enum
IPPROTO_MAX
};
+/* If __USER_KERNEL_IPV6_DEFS is defined then the user has included the kernel
+ network headers first and we should use those ABI-identical definitions
+ instead of our own. */
+#ifndef __USE_KERNEL_IPV6_DEFS
+enum
+ {
+ IPPROTO_HOPOPTS = 0, /* IPv6 Hop-by-Hop options. */
+#define IPPROTO_HOPOPTS IPPROTO_HOPOPTS
+ IPPROTO_ROUTING = 43, /* IPv6 routing header. */
+#define IPPROTO_ROUTING IPPROTO_ROUTING
+ IPPROTO_FRAGMENT = 44, /* IPv6 fragmentation header. */
+#define IPPROTO_FRAGMENT IPPROTO_FRAGMENT
+ IPPROTO_ICMPV6 = 58, /* ICMPv6. */
+#define IPPROTO_ICMPV6 IPPROTO_ICMPV6
+ IPPROTO_NONE = 59, /* IPv6 no next header. */
+#define IPPROTO_NONE IPPROTO_NONE
+ IPPROTO_DSTOPTS = 60, /* IPv6 destination options. */
+#define IPPROTO_DSTOPTS IPPROTO_DSTOPTS
+ IPPROTO_MH = 135, /* IPv6 mobility header. */
+#define IPPROTO_MH IPPROTO_MH
+ };
+#endif /* !__USE_KERNEL_IPV6_DEFS */
/* Type to represent a port. */
typedef uint16_t in_port_t;
@@ -134,15 +156,6 @@ enum
IPPORT_USERRESERVED = 5000
};
-
-/* Internet address. */
-typedef uint32_t in_addr_t;
-struct in_addr
- {
- in_addr_t s_addr;
- };
-
-
/* Definitions of the bits in an Internet address integer.
On subnets, host and network parts are found according to
@@ -191,7 +204,7 @@ struct in_addr
#define INADDR_ALLRTRS_GROUP ((in_addr_t) 0xe0000002) /* 224.0.0.2 */
#define INADDR_MAX_LOCAL_GROUP ((in_addr_t) 0xe00000ff) /* 224.0.0.255 */
-
+#ifndef __USE_KERNEL_IPV6_DEFS
/* IPv6 address */
struct in6_addr
{
@@ -209,6 +222,7 @@ struct in6_addr
# define s6_addr32 __in6_u.__u6_addr32
#endif
};
+#endif /* !__USE_KERNEL_IPV6_DEFS */
extern const struct in6_addr in6addr_any; /* :: */
extern const struct in6_addr in6addr_loopback; /* ::1 */
@@ -233,6 +247,7 @@ struct sockaddr_in
sizeof (struct in_addr)];
};
+#ifndef __USE_KERNEL_IPV6_DEFS
/* Ditto, for IPv6. */
struct sockaddr_in6
{
@@ -242,7 +257,7 @@ struct sockaddr_in6
struct in6_addr sin6_addr; /* IPv6 address */
uint32_t sin6_scope_id; /* IPv6 scope-id */
};
-
+#endif /* !__USE_KERNEL_IPV6_DEFS */
#if defined __USE_MISC || defined __USE_GNU
/* IPv4 multicast request. */
@@ -268,7 +283,7 @@ struct ip_mreq_source
};
#endif
-
+#ifndef __USE_KERNEL_IPV6_DEFS
/* Likewise, for IPv6. */
struct ipv6_mreq
{
@@ -278,7 +293,7 @@ struct ipv6_mreq
/* local interface */
unsigned int ipv6mr_interface;
};
-
+#endif /* !__USE_KERNEL_IPV6_DEFS */
#if defined __USE_MISC || defined __USE_GNU
/* Multicast group request. */
@@ -349,10 +364,6 @@ struct group_filter
* sizeof (struct sockaddr_storage)))
#endif
-
-/* Get system-specific definitions. */
-#include <bits/in.h>
-
/* Functions to convert between host and network byte order.
Please note that these functions normally take `unsigned long int' or
diff --git a/sysdeps/unix/sysv/linux/bits/in.h b/sysdeps/unix/sysv/linux/bits/in.h
index e959b33..d763ce9 100644
--- a/sysdeps/unix/sysv/linux/bits/in.h
+++ b/sysdeps/unix/sysv/linux/bits/in.h
@@ -21,6 +21,18 @@
# error "Never use <bits/in.h> directly; include <netinet/in.h> instead."
#endif
+/* If the application has already included linux/in6.h from a linux-based
+ kernel then we will not define the IPv6 IPPROTO_* defines, in6_addr (nor the
+ defines), sockaddr_in6, or ipv6_mreq. The ABI used by the linux-kernel and
+ glibc match exactly. Neither the linux kernel nor glibc should break this
+ ABI without coordination. */
+#ifdef _UAPI_LINUX_IN6_H
+/* This is not quite the same API since the kernel always defines s6_addr16 and
+ s6_addr32. This is not a violation of POSIX since POSIX says "at least the
+ following member" and that holds true. */
+# define __USE_KERNEL_IPV6_DEFS
+#endif
+
/* Options for use with `getsockopt' and `setsockopt' at the IP level.
The first word in the comment at the right is the data type used;
"bool" means a boolean value stored in an `int'. */
^ permalink raw reply related
* [Patch net-next] net: sync some IP headers with glibc
From: Cong Wang @ 2013-08-13 8:37 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Thomas Backlund, libc-alpha, YOSHIFUJI Hideaki,
Carlos O'Donell, Cong Wang
From: Carlos O'Donell <carlos@redhat.com>
Solution:
=========
- Synchronize linux's `include/uapi/linux/in6.h'
with glibc's `inet/netinet/in.h'.
- Synchronize glibc's `inet/netinet/in.h with linux's
`include/uapi/linux/in6.h'.
- Allow including the headers in either other.
- First header included defines the structures and macros.
Details:
========
The kernel promises not to break the UAPI ABI so I don't
see why we can't just have the two userspace headers
coordinate?
If you include the kernel headers first you get those,
and if you include the glibc headers first you get those,
and the following patch arranges a coordination and
synchronization between the two.
Let's handle `include/uapi/linux/in6.h' from linux,
and `inet/netinet/in.h' from glibc and ensure they compile
in any order and preserve the required ABI.
These two patches pass the following compile tests:
cat >> test1.c <<EOF
#include <netinet/in.h>
#include <linux/in6.h>
int main (void) {
return 0;
}
EOF
gcc -c test1.c
cat >> test2.c <<EOF
#include <linux/in6.h>
#include <netinet/in.h>
int main (void) {
return 0;
}
EOF
gcc -c test2.c
One wrinkle is that the kernel has a different name for one of
the members in ipv6_mreq. In the kernel patch we create a macro
to cover the uses of the old name, and while that's not entirely
clean it's one of the best solutions (aside from an anonymous
union which has other issues).
I've reviewed the code and it looks to me like the ABI is
assured and everything matches on both sides.
Notes:
- You want netinet/in.h to include bits/in.h as early as possible,
but it needs in_addr so define in_addr early.
- You want bits/in.h included as early as possible so you can use
the linux specific code to define __USE_KERNEL_DEFS based on
the _UAPI_* macro definition and use those to cull in.h.
- glibc was missing IPPROTO_MH, added here.
Compile tested and inspected.
Reported-by: Thomas Backlund <tmb@mageia.org>
Cc: Thomas Backlund <tmb@mageia.org>
Cc: libc-alpha@sourceware.org
Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Cc: David S. Miller <davem@davemloft.net>
Tested-by: Cong Wang <amwang@redhat.com>
Signed-off-by: Carlos O'Donell <carlos@redhat.com>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 997f9f2..e7c94ee 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -227,6 +227,7 @@ header-y += kvm_para.h
endif
header-y += l2tp.h
+header-y += libc-compat.h
header-y += limits.h
header-y += llc.h
header-y += loop.h
diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h
index 9edb441..16d95d6 100644
--- a/include/uapi/linux/in.h
+++ b/include/uapi/linux/in.h
@@ -23,31 +23,54 @@
/* Standard well-defined IP protocols. */
enum {
- IPPROTO_IP = 0, /* Dummy protocol for TCP */
- IPPROTO_ICMP = 1, /* Internet Control Message Protocol */
- IPPROTO_IGMP = 2, /* Internet Group Management Protocol */
- IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */
- IPPROTO_TCP = 6, /* Transmission Control Protocol */
- IPPROTO_EGP = 8, /* Exterior Gateway Protocol */
- IPPROTO_PUP = 12, /* PUP protocol */
- IPPROTO_UDP = 17, /* User Datagram Protocol */
- IPPROTO_IDP = 22, /* XNS IDP protocol */
- IPPROTO_DCCP = 33, /* Datagram Congestion Control Protocol */
- IPPROTO_RSVP = 46, /* RSVP protocol */
- IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */
-
- IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */
-
- IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */
- IPPROTO_AH = 51, /* Authentication Header protocol */
- IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */
- IPPROTO_PIM = 103, /* Protocol Independent Multicast */
-
- IPPROTO_COMP = 108, /* Compression Header protocol */
- IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */
- IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */
-
- IPPROTO_RAW = 255, /* Raw IP packets */
+ IPPROTO_IP = 0, /* Dummy protocol for TCP. */
+#define IPPROTO_IP IPPROTO_IP
+ IPPROTO_ICMP = 1, /* Internet Control Message Protocol. */
+#define IPPROTO_ICMP IPPROTO_ICMP
+ IPPROTO_IGMP = 2, /* Internet Group Management Protocol. */
+#define IPPROTO_IGMP IPPROTO_IGMP
+ IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94). */
+#define IPPROTO_IPIP IPPROTO_IPIP
+ IPPROTO_TCP = 6, /* Transmission Control Protocol. */
+#define IPPROTO_TCP IPPROTO_TCP
+ IPPROTO_EGP = 8, /* Exterior Gateway Protocol. */
+#define IPPROTO_EGP IPPROTO_EGP
+ IPPROTO_PUP = 12, /* PUP protocol. */
+#define IPPROTO_PUP IPPROTO_PUP
+ IPPROTO_UDP = 17, /* User Datagram Protocol. */
+#define IPPROTO_UDP IPPROTO_UDP
+ IPPROTO_IDP = 22, /* XNS IDP protocol. */
+#define IPPROTO_IDP IPPROTO_IDP
+ IPPROTO_TP = 29, /* SO Transport Protocol Class 4. */
+#define IPPROTO_TP IPPROTO_TP
+ IPPROTO_DCCP = 33, /* Datagram Congestion Control Protocol. */
+#define IPPROTO_DCCP IPPROTO_DCCP
+ IPPROTO_IPV6 = 41, /* IPv6 header. */
+#define IPPROTO_IPV6 IPPROTO_IPV6
+ IPPROTO_RSVP = 46, /* Reservation Protocol. */
+#define IPPROTO_RSVP IPPROTO_RSVP
+ IPPROTO_GRE = 47, /* General Routing Encapsulation. */
+#define IPPROTO_GRE IPPROTO_GRE
+ IPPROTO_ESP = 50, /* encapsulating security payload. */
+#define IPPROTO_ESP IPPROTO_ESP
+ IPPROTO_AH = 51, /* authentication header. */
+#define IPPROTO_AH IPPROTO_AH
+ IPPROTO_MTP = 92, /* Multicast Transport Protocol. */
+#define IPPROTO_MTP IPPROTO_MTP
+ IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET. */
+#define IPPROTO_BEETPH IPPROTO_BEETPH
+ IPPROTO_ENCAP = 98, /* Encapsulation Header. */
+#define IPPROTO_ENCAP IPPROTO_ENCAP
+ IPPROTO_PIM = 103, /* Protocol Independent Multicast. */
+#define IPPROTO_PIM IPPROTO_PIM
+ IPPROTO_COMP = 108, /* Compression Header Protocol. */
+#define IPPROTO_COMP IPPROTO_COMP
+ IPPROTO_SCTP = 132, /* Stream Control Transmission Protocol. */
+#define IPPROTO_SCTP IPPROTO_SCTP
+ IPPROTO_UDPLITE = 136, /* UDP-Lite protocol. */
+#define IPPROTO_UDPLITE IPPROTO_UDPLITE
+ IPPROTO_RAW = 255, /* Raw IP packets. */
+#define IPPROTO_RAW IPPROTO_RAW
IPPROTO_MAX
};
diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h
index 53b1d56..d7ab44c 100644
--- a/include/uapi/linux/in6.h
+++ b/include/uapi/linux/in6.h
@@ -22,22 +22,29 @@
#define _UAPI_LINUX_IN6_H
#include <linux/types.h>
+#include <linux/libc-compat.h>
/*
* IPv6 address structure
*/
-
+#if __UAPI_DEF_IN6_ADDR
struct in6_addr {
union {
__u8 u6_addr8[16];
+#if __UAPI_DEF_IN6_ADDR
__be16 u6_addr16[8];
__be32 u6_addr32[4];
+#endif
} in6_u;
#define s6_addr in6_u.u6_addr8
+#if __UAPI_DEF_IN6_ADDR_ALT
#define s6_addr16 in6_u.u6_addr16
#define s6_addr32 in6_u.u6_addr32
+#endif
};
+#endif /* __UAPI_DEF_IN6_ADDR */
+#if __UAPI_DEF_SOCKADDR_IN6
struct sockaddr_in6 {
unsigned short int sin6_family; /* AF_INET6 */
__be16 sin6_port; /* Transport layer port # */
@@ -45,7 +52,9 @@ struct sockaddr_in6 {
struct in6_addr sin6_addr; /* IPv6 address */
__u32 sin6_scope_id; /* scope id (new in RFC2553) */
};
+#endif /* __UAPI_DEF_SOCKADDR_IN6 */
+#if __UAPI_DEF_IPV6_MREQ
struct ipv6_mreq {
/* IPv6 multicast address of group */
struct in6_addr ipv6mr_multiaddr;
@@ -53,6 +62,7 @@ struct ipv6_mreq {
/* local IPv6 address of interface */
int ipv6mr_ifindex;
};
+#endif /* __UAPI_DEF_IVP6_MREQ */
#define ipv6mr_acaddr ipv6mr_multiaddr
@@ -114,13 +124,24 @@ struct in6_flowlabel_req {
/*
* IPV6 extension headers
*/
-#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */
-#define IPPROTO_ROUTING 43 /* IPv6 routing header */
-#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */
-#define IPPROTO_ICMPV6 58 /* ICMPv6 */
-#define IPPROTO_NONE 59 /* IPv6 no next header */
-#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */
-#define IPPROTO_MH 135 /* IPv6 mobility header */
+#if __UAPI_DEF_IPPROTO_V6
+enum {
+ IPPROTO_HOPOPTS = 0, /* IPv6 hop-by-hop options */
+#define IPPROTO_HOPOPTS IPPROTO_HOPOPTS
+ IPPROTO_ROUTING = 43, /* IPv6 routing header */
+#define IPPROTO_ROUTING IPPROTO_ROUTING
+ IPPROTO_FRAGMENT = 44, /* IPv6 fragmentation header */
+#define IPPROTO_FRAGMENT IPPROTO_FRAGMENT
+ IPPROTO_ICMPV6 = 58, /* ICMPv6 */
+#define IPPROTO_ICMPV6 IPPROTO_ICMPV6
+ IPPROTO_NONE = 59, /* IPv6 no next header */
+#define IPPROTO_NONE IPPROTO_NONE
+ IPPROTO_DSTOPTS = 60, /* IPv6 destination options */
+#define IPPROTO_DSTOPTS IPPROTO_DSTOPTS
+ IPPROTO_MH = 135, /* IPv6 mobility header */
+#define IPPROTO_MH IPPROTO_MH
+};
+#endif /* __UAPI_DEF_IPPROTO_V6 */
/*
* IPv6 TLV options.
diff --git a/include/uapi/linux/libc-compat.h b/include/uapi/linux/libc-compat.h
new file mode 100644
index 0000000..335e8a7
--- /dev/null
+++ b/include/uapi/linux/libc-compat.h
@@ -0,0 +1,103 @@
+/*
+ * Compatibility interface for userspace libc header coordination:
+ *
+ * Define compatibility macros that are used to control the inclusion or
+ * exclusion of UAPI structures and definitions in coordination with another
+ * userspace C library.
+ *
+ * This header is intended to solve the problem of UAPI definitions that
+ * conflict with userspace definitions. If a UAPI header has such conflicting
+ * definitions then the solution is as follows:
+ *
+ * * Synchronize the UAPI header and the libc headers so either one can be
+ * used and such that the ABI is preserved. If this is not possible then
+ * no simple compatibility interface exists (you need to write translating
+ * wrappers and rename things) and you can't use this interface.
+ *
+ * Then follow this process:
+ *
+ * (a) Include libc-compat.h in the UAPI header.
+ * e.g. #include <linux/libc-compat.h>
+ * This include must be as early as possible.
+ *
+ * (b) In libc-compat.h add enough code to detect that the comflicting
+ * userspace libc header has been included first.
+ *
+ * (c) If the userspace libc header has been included first define a set of
+ * guard macros of the form __UAPI_DEF_FOO and set their values to 1, else
+ * set their values to 0.
+ *
+ * (d) Back in the UAPI header with the conflicting definitions, guard the
+ * definitions with:
+ * #if __UAPI_DEF_FOO
+ * ...
+ * #endif
+ *
+ * This fixes the situation where the linux headers are included *after* the
+ * libc headers. To fix the problem with the inclusion in the other order the
+ * userspace libc headers must be fixed like this:
+ *
+ * * For all definitions that conflict with kernel definitions wrap those
+ * defines in the following:
+ * #if !__UAPI_DEF_FOO
+ * ...
+ * #endif
+ *
+ * This prevents the redefinition of a construct already defined by the kernel.
+ */
+#ifndef _UAPI_LIBC_COMPAT_H
+#define _UAPI_LIBC_COMPAT_H
+
+/* We have included glibc headers... */
+#if defined(__GLIBC__)
+
+/* Coordinate with glibc netinet/in.h header. */
+#if defined(_NETINET_IN_H)
+
+/* GLIBC headers included first so don't define anything
+ * that would already be defined. */
+#define __UAPI_DEF_IN6_ADDR 0
+/* The exception is the in6_addr macros which must be defined
+ * if the glibc code didn't define them. This guard matches
+ * the guard in glibc/inet/netinet/in.h which defines the
+ * additional in6_addr macros e.g. s6_addr16, and s6_addr32. */
+#if defined(__USE_MISC) || defined (__USE_GNU)
+#define __UAPI_DEF_IN6_ADDR_ALT 0
+#else
+#define __UAPI_DEF_IN6_ADDR_ALT 1
+#endif
+#define __UAPI_DEF_SOCKADDR_IN6 0
+#define __UAPI_DEF_IPV6_MREQ 0
+#define __UAPI_DEF_IPPROTO_V6 0
+
+#else
+
+/* Linux headers included first, and we must define everything
+ * we need. The expectation is that glibc will check the
+ * __UAPI_DEF_* defines and adjust appropriately. */
+#define __UAPI_DEF_IN6_ADDR 1
+/* We unconditionally define the in6_addr macros and glibc must
+ * coordinate. */
+#define __UAPI_DEF_IN6_ADDR_ALT 1
+#define __UAPI_DEF_SOCKADDR_IN6 1
+#define __UAPI_DEF_IPV6_MREQ 1
+#define __UAPI_DEF_IPPROTO_V6 1
+
+#endif /* _NETINET_IN_H */
+
+
+/* If we did not see any headers from any supported C libraries,
+ * or we are being included in the kernel, then define everything
+ * that we need. */
+#else /* !defined(__GLIBC__) */
+
+/* Definitions for in6.h */
+#define __UAPI_DEF_IN6_ADDR 1
+#define __UAPI_DEF_IN6_ADDR_ALT 1
+#define __UAPI_DEF_SOCKADDR_IN6 1
+#define __UAPI_DEF_IPV6_MREQ 1
+#define __UAPI_DEF_IPPROTO_V6 1
+
+#endif /* __GLIBC__ */
+
+#endif /* _UAPI_LIBC_COMPAT_H */
^ permalink raw reply related
* Re: [PATCHv2 net-next] xfrm: Make xfrm_state timer monotonic
From: Fan Du @ 2013-08-13 8:37 UTC (permalink / raw)
To: Steffen Klassert; +Cc: davem, netdev
In-Reply-To: <20130813075519.GN25511@secunet.com>
On 2013年08月13日 15:55, Steffen Klassert wrote:
> On Mon, Aug 12, 2013 at 01:40:07PM +0800, Fan Du wrote:
>>
>>
>> On 2013年08月06日 17:22, Steffen Klassert wrote:
>>> On Tue, Aug 06, 2013 at 02:57:05PM +0800, Fan Du wrote:
>>>> xfrm_state timer should be independent of system clock change,
>>>> so switch to monotonic clock base.
>>>>
>>>
>>> I think a monotonic timer will reintroduce a bug on suspend/resume
>>> that was fixed by commit 9e0d57fd6
>>> (xfrm: SAD entries do not expire correctly after suspend-resume)
>>>
>>> Please make sure that this does not happen.
>>
>> What about using CLOCK_BOOTTIME? it's monotonic, but includes suspend time as well.
>
> As I said, I'm open to everything that fixes your problem and does not
> introduce a regression. I'll consider applying after some testing
> if noone else has objections.
Hi, Steffen
Thanks for your understanding! :)
I happened to bump into CLOCK_BOOTTIME several days ago, so apologize for
eating my words earlier. Changing xfrm_state timer to monotonic does not
solve the problem I've described earlier in:
http://www.spinics.net/lists/netdev/msg245019.html (*1*)
So is there any light of hope for the proposal in (*1*) by using CLOCK_BOOTTIME
instead?
> Thanks!
>
>
--
浮沉随浪只记今朝笑
--fan
^ permalink raw reply
* Re: [PATCH 3/4] drivers/net: enic: Make ASIC information available to USNIC
From: Ben Hutchings @ 2013-08-13 8:31 UTC (permalink / raw)
To: Nishank Trivedi
Cc: Stephen Hemminger, Neel Patel, netdev, Christian Benvenuti,
Upinder Malhi (umalhi)
In-Reply-To: <5209BFB2.2090003@cisco.com>
On Mon, 2013-08-12 at 22:10 -0700, Nishank Trivedi wrote:
> On 8/10/13 9:13 AM, Ben Hutchings wrote:
> > On Fri, 2013-08-09 at 15:21 -0700, Stephen Hemminger wrote:
> >> On Fri, 9 Aug 2013 11:12:20 -0700
> >> Neel Patel <neepatel@cisco.com> wrote:
> >>
> >>> This patch provides asic information via ethtool.
> > [...]
> >>> --- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c
> >>> +++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
> >>> @@ -19,6 +19,7 @@
> >>> #include <linux/netdevice.h>
> >>> #include <linux/ethtool.h>
> >>>
> >>> +#include "driver_utils.h"
> >>> #include "enic_res.h"
> >>> #include "enic.h"
> >>> #include "enic_dev.h"
> >>> @@ -116,6 +117,9 @@ static void enic_get_drvinfo(struct net_device *netdev,
> >>> sizeof(drvinfo->fw_version));
> >>> strlcpy(drvinfo->bus_info, pci_name(enic->pdev),
> >>> sizeof(drvinfo->bus_info));
> >>> + memset(drvinfo->reserved1, 0, sizeof(drvinfo->reserved1));
> >>> + driver_encode_asic_info(drvinfo->reserved1, sizeof(drvinfo->reserved1),
> >>> + fw_info->asic_type, fw_info->asic_rev);
> >>> }
> >>
> >> If you want to use a reserved field, then make it a first class citizen.
> >> Rename it to asic_info, make sure the result is okay for other drivers
> >> and add send patch so Ben can make it part of normal ethtool support.
> >>
> >> Otherwise, this code is likely to break when someone else actually unreserves
> >> that field.
> >
> > Right. I bet this is redundant with the IDs that lspci can show,
> > anyway.
>
> Thanks Stephen, Ben for your input, they are valid points. Neel would
> send a new patch series minus 3/4 for now.
>
> While you are right that lspci or sysfs can be used to get same info, we
> were trying to use asic info (encoded with type and version) within
> drvinfo so as to use one string to achieve same effect as reading PCI
> subsystem id and revision explicitly. Instead of going to different tool
> (lspci), ethtool would be enough to unqiuely identify the device. Asic
> version along with already existing firmware version, driver version,
> etc seems natural.
Well we've managed without this for the last 15 years, so it seems like
it's not that much of a problem to run lspci too.
Sure, it's an extra command for users to run, but if you're trying to
get diagnostic information from them there's a *lot* more you'll want to
gather.
We could do something in the ethtool *command* to report what the device
is (if bus_info matches PCI address format), which would then work for
every PCI network driver.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [PATCH net] ipv6: don't stop backtracking in fib6_lookup_1 if subtree does not match
From: David Miller @ 2013-08-13 8:15 UTC (permalink / raw)
To: teco; +Cc: hannes, netdev
In-Reply-To: <190D21D2-F86E-46D2-93E8-3050F57FE622@inf-net.nl>
From: Teco Boot <teco@inf-net.nl>
Date: Tue, 13 Aug 2013 10:02:08 +0200
> It is an important element in my work for v6 multi-homed networks
> (IETF Homenet WG).
You are one person. -stable inclusion is decided based how important the
fix is to everyone in both good (fixes a bug) and bad (might cause a
regression) terms.
So "this is important for my work" is never a good reason for a patch
to be included into -stable.
To convince us, you're going to have to present an argument that
exists outside the very limited scope of your own self-interests.
And "other people might/will use my important work in the future"
is not sufficient either.
Thanks.
^ permalink raw reply
* [PATCH 1/3 v2] ipv6: do not disable temp_address when reaching max_address
From: Ding Tianhong @ 2013-08-13 7:57 UTC (permalink / raw)
To: David S. Miller, Alexey Kuznetsov, James Morris,
Hideaki YOSHIFUJI, Patrick McHardy, Netdev
A LAN user can remotely disable temporary address which may lead
to privacy violatins and information disclosure.
The reason is that the linux kernel uses the 'ipv6.max_addresses'
option to specify how many ipv6 addresses and interface may have.
The 'ipv6.regen_max_retry' (default value 3) option specifies
how many times the kernel will try to create a new address.
But the kernel is not distinguish between the event of reaching
max_addresses for an interface and failing to generate a new address.
the kernel disable the temporary address after regenerate a new
address 'regen_max_retry' times.
According RFC4941 3.3.7:
---------------------------------------
If DAD indicates the address is already in use,
the node must generate a new randomized interface
identifier as described in section 3.2 above, and
repeat the previous steps as appropriate up to
TEMP_IDGEN_RETRIES times.
If after TEMP_IDGEN_RETRIES consecutive attempts no
non-unique address was generated, the node must log
a system error and must not attempt to generate
temporary address for that interface.
------------------------------------------
RFC4941 3.3.7 specifies that disabling the temp_address must happen
upon the address is already in use, not reach the max_address,
So we have to check the return err and distinguish the correct retry path.
This fixes CVE-2013-0343
Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
Tested-by: Wang Weidong <wangweidong1@huawei.com>
Cc: David S. Miller <davem@davemloft.net>
---
net/ipv6/addrconf.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index da4241c..72911fd 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1134,10 +1134,27 @@ retry:
if (IS_ERR_OR_NULL(ift)) {
in6_ifa_put(ifp);
in6_dev_put(idev);
- pr_info("%s: retry temporary address regeneration\n", __func__);
- tmpaddr = &addr;
- write_lock(&idev->lock);
- goto retry;
+
+ /* According RFC4941 3.3.7:
+ * If DAD indicates the address is already in use,
+ * the node must generate a new randomized interface
+ * identifier as described in section 3.2 above, and
+ * repeat the previous steps as appropriate up to
+ * TEMP_IDGEN_RETRIES times.
+ * If after TEMP_IDGEN_RETRIES consecutive attempts no
+ * non-unique address was generated, the node must log
+ * a system error and must not attempt to generate
+ * temporary address for that interface.
+ * So we have to check the return err and distinguish
+ * the correct retry path.
+ */
+ if (PTR_ERR(ift) == -EEXIST) {
+ pr_info("%s: retry temporary address regeneration\n", __func__);
+ tmpaddr = &addr;
+ write_lock(&idev->lock);
+ goto retry;
+ } else
+ goto out;
}
spin_lock_bh(&ift->lock);
--
1.8.2.1
^ permalink raw reply related
* [PATCH 2/3 v2] ipv6: rename ADBG() to pr_xxx()
From: Ding Tianhong @ 2013-08-13 7:57 UTC (permalink / raw)
To: David S. Miller, Alexey Kuznetsov, James Morris,
Hideaki YOSHIFUJI, Netdev, Patrick McHardy, Joe Perches
According to Joe Perches opinions, the ADBG() was tedious and it is
better to remove the KERN_<LEVEL>s and use the pr_xxx() instead of ADBG().
Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
Cc: Joe Perches <joe@perches.com>
---
net/ipv6/addrconf.c | 29 +++++++++--------------------
1 file changed, 9 insertions(+), 20 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 72911fd..2333fa7 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -95,15 +95,6 @@
#include <linux/seq_file.h>
#include <linux/export.h>
-/* Set to 3 to get tracing... */
-#define ACONF_DEBUG 2
-
-#if ACONF_DEBUG >= 3
-#define ADBG(x) printk x
-#else
-#define ADBG(x)
-#endif
-
#define INFINITY_LIFE_TIME 0xFFFFFFFF
static inline u32 cstamp_delta(unsigned long cstamp)
@@ -369,9 +360,8 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
dev_hold(dev);
if (snmp6_alloc_dev(ndev) < 0) {
- ADBG((KERN_WARNING
- "%s: cannot allocate memory for statistics; dev=%s.\n",
- __func__, dev->name));
+ pr_warning("%s: cannot allocate memory for statistics; dev=%s.\n",
+ __func__, dev->name);
neigh_parms_release(&nd_tbl, ndev->nd_parms);
dev_put(dev);
kfree(ndev);
@@ -379,9 +369,8 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
}
if (snmp6_register_dev(ndev) < 0) {
- ADBG((KERN_WARNING
- "%s: cannot create /proc/net/dev_snmp6/%s\n",
- __func__, dev->name));
+ pr_warning("%s: cannot create /proc/net/dev_snmp6/%s\n",
+ __func__, dev->name);
neigh_parms_release(&nd_tbl, ndev->nd_parms);
ndev->dead = 1;
in6_dev_finish_destroy(ndev);
@@ -844,7 +833,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
/* Ignore adding duplicate addresses on an interface */
if (ipv6_chk_same_addr(dev_net(idev->dev), addr, idev->dev)) {
- ADBG(("ipv6_add_addr: already assigned\n"));
+ pr_err("ipv6_add_addr: already assigned\n");
err = -EEXIST;
goto out;
}
@@ -852,7 +841,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
ifa = kzalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC);
if (ifa == NULL) {
- ADBG(("ipv6_add_addr: malloc failed\n"));
+ pr_err("ipv6_add_addr: malloc failed\n");
err = -ENOBUFS;
goto out;
}
@@ -2069,7 +2058,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
pinfo = (struct prefix_info *) opt;
if (len < sizeof(struct prefix_info)) {
- ADBG(("addrconf: prefix option too short\n"));
+ pr_err("addrconf: prefix option too short\n");
return;
}
@@ -3649,8 +3638,8 @@ restart:
if (time_before(next_sched, jiffies + ADDRCONF_TIMER_FUZZ_MAX))
next_sched = jiffies + ADDRCONF_TIMER_FUZZ_MAX;
- ADBG((KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n",
- now, next, next_sec, next_sched));
+ pr_debug("now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n",
+ now, next, next_sec, next_sched);
addr_chk_timer.expires = next_sched;
add_timer(&addr_chk_timer);
--
1.8.2.1
^ permalink raw reply related
* [PATCH 3/3 v2] ipv6: fix checkpatch errors in net/ipv6/addrconf.c
From: Ding Tianhong @ 2013-08-13 7:57 UTC (permalink / raw)
To: David S. Miller, Alexey Kuznetsov, James Morris,
Hideaki YOSHIFUJI, Netdev, Patrick McHardy
ERROR: code indent should use tabs where possible
+^I idev->cnf.dad_transmits *$
ERROR: code indent should use tabs where possible
+^I idev->nd_parms->retrans_time / HZ;$
Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
---
net/ipv6/addrconf.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 2333fa7..08dd643 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1094,8 +1094,8 @@ retry:
spin_unlock_bh(&ifp->lock);
regen_advance = idev->cnf.regen_max_retry *
- idev->cnf.dad_transmits *
- idev->nd_parms->retrans_time / HZ;
+ idev->cnf.dad_transmits *
+ idev->nd_parms->retrans_time / HZ;
write_unlock(&idev->lock);
/* A temporary address is created only if this calculated Preferred
--
1.8.2.1
^ permalink raw reply related
* Re: [PATCH net] ipv6: don't stop backtracking in fib6_lookup_1 if subtree does not match
From: Teco Boot @ 2013-08-13 8:02 UTC (permalink / raw)
To: Hannes Frederic Sowa, David Miller; +Cc: netdev
In-Reply-To: <20130810120348.GP14001@order.stressinduktion.org>
Was it to later to include in 3.11-rc5?
For me, this fix is important. I would like to so this patch in [all|recent] stable kernels quite soon. It is an important element in my work for v6 multi-homed networks (IETF Homenet WG).
Thanks, Teco
Op 10 aug. 2013, om 14:03 heeft Hannes Frederic Sowa <hannes@stressinduktion.org> het volgende geschreven:
> On Sat, Aug 10, 2013 at 01:39:12PM +0200, Teco Boot wrote:
>> OK, I went back to kernel where I had the ipv6 sadr lookup in cache problem.
>> There I patched the ip6_fib.c.
>> Patch works !!
>>
>> The hang problem in 3.8.0-28 has lower priority for me. Maybe I'll check current -net-next later. Don't hold your breath.
>>
>> Now this patch should go mainline and older kernels, I think.
>> What is the next step?
>
> That already happend. Patch is queued up for inclusion in 3.11 and is sitting
> in the stable queue:
> <http://patchwork.ozlabs.org/bundle/davem/stable/?state=*>
>
> Thanks for testing,
>
> Hannes
>
^ permalink raw reply
* Re: ipsec smp scalability and cpu use fairness (softirqs)
From: Timo Teras @ 2013-08-13 7:57 UTC (permalink / raw)
To: Steffen Klassert; +Cc: Andrew Collins, netdev
In-Reply-To: <20130813074614.GM25511@secunet.com>
On Tue, 13 Aug 2013 09:46:14 +0200
Steffen Klassert <steffen.klassert@secunet.com> wrote:
> On Tue, Aug 13, 2013 at 09:23:12AM +0300, Timo Teras wrote:
> >
> > For my scenario it will be usually even same SPI. So even if flow
> > dissector learns ESP and uses SPI in hash, I'd need a way to balance
> > traffic to multiple SAs.
> >
> > I guess the place where I'd want to see the distribution to cores is
> > crypto_aead_*() calls. In fact, it seems there's code infracture
> > already for it: crypto/cryptd.c. Seems it needs to be manually
> > configured and only few places e.g. aesni gcm parts use it.
> >
> > I'm wondering if it'd make sense to patch net/xfrm/xfrm_algo.c to
> > use cryptd? Or at least have a Kconfig or sysctl option make it do
> > so.
>
> It is possible to configure the used crypto algorithm from userspace
> with the crypto user configuration API, see crypto/crypto_user.c.
>
> I wrote to tool that usses this API some time ago, it is still
> a bit rudimentary but it does the job. You can find it at:
> https://sourceforge.net/projects/crconf/
Exactly what I was looking for! Thanks!
> Also, if you want parallelism, you could use the pcrypt algorithm.
> It sends the crypto requests asynchronously round robin to a
> configurable set of cpus. Finaly it takes care to bring the
> served crypto requests back into the order they were submitted
> to avoid packet reordering.
Right. Looks like this helps a lot.
Perhaps it would be worth to experiment also with RPS type hash based
cpu selection?
> Currently we have only one systemwide workqueue for encryption
> and one decryption. So all IPsec packets are send to the same
> workqueue, regardless which state they use.
>
> I have patches that make it possible to configure a separate
> workqueue for each state or to group some states to a specific
> workqueue. These patches are still unpublished because they
> have not much testing yet, but I could send them after some
> polishing for review or testing if you are interested.
Yes, I'd be interested.
Thanks!
^ permalink raw reply
* Re: [PATCHv2 net-next] xfrm: Make xfrm_state timer monotonic
From: Steffen Klassert @ 2013-08-13 7:55 UTC (permalink / raw)
To: Fan Du; +Cc: davem, netdev
In-Reply-To: <52087537.6060200@windriver.com>
On Mon, Aug 12, 2013 at 01:40:07PM +0800, Fan Du wrote:
>
>
> On 2013年08月06日 17:22, Steffen Klassert wrote:
> >On Tue, Aug 06, 2013 at 02:57:05PM +0800, Fan Du wrote:
> >>xfrm_state timer should be independent of system clock change,
> >>so switch to monotonic clock base.
> >>
> >
> >I think a monotonic timer will reintroduce a bug on suspend/resume
> >that was fixed by commit 9e0d57fd6
> >(xfrm: SAD entries do not expire correctly after suspend-resume)
> >
> >Please make sure that this does not happen.
>
> What about using CLOCK_BOOTTIME? it's monotonic, but includes suspend time as well.
As I said, I'm open to everything that fixes your problem and does not
introduce a regression. I'll consider applying after some testing
if noone else has objections.
Thanks!
^ permalink raw reply
* Re: ipsec smp scalability and cpu use fairness (softirqs)
From: Steffen Klassert @ 2013-08-13 7:46 UTC (permalink / raw)
To: Timo Teras; +Cc: Andrew Collins, netdev
In-Reply-To: <20130813092312.2493354e@vostro>
On Tue, Aug 13, 2013 at 09:23:12AM +0300, Timo Teras wrote:
>
> For my scenario it will be usually even same SPI. So even if flow
> dissector learns ESP and uses SPI in hash, I'd need a way to balance
> traffic to multiple SAs.
>
> I guess the place where I'd want to see the distribution to cores is
> crypto_aead_*() calls. In fact, it seems there's code infracture
> already for it: crypto/cryptd.c. Seems it needs to be manually
> configured and only few places e.g. aesni gcm parts use it.
>
> I'm wondering if it'd make sense to patch net/xfrm/xfrm_algo.c to use
> cryptd? Or at least have a Kconfig or sysctl option make it do so.
>
It is possible to configure the used crypto algorithm from userspace
with the crypto user configuration API, see crypto/crypto_user.c.
I wrote to tool that usses this API some time ago, it is still
a bit rudimentary but it does the job. You can find it at:
https://sourceforge.net/projects/crconf/
Also, if you want parallelism, you could use the pcrypt algorithm.
It sends the crypto requests asynchronously round robin to a
configurable set of cpus. Finaly it takes care to bring the
served crypto requests back into the order they were submitted
to avoid packet reordering.
Currently we have only one systemwide workqueue for encryption
and one decryption. So all IPsec packets are send to the same
workqueue, regardless which state they use.
I have patches that make it possible to configure a separate
workqueue for each state or to group some states to a specific
workqueue. These patches are still unpublished because they
have not much testing yet, but I could send them after some
polishing for review or testing if you are interested.
^ permalink raw reply
* [PATCH net-next 3/3] net/usb/r8152: enable interrupt transfer
From: Hayes Wang @ 2013-08-13 7:28 UTC (permalink / raw)
To: netdev; +Cc: linux-kernel, linux-usb, Hayes Wang
In-Reply-To: <1376378913-879-1-git-send-email-hayeswang@realtek.com>
Use the interrupt transfer to replace polling link status. Delay
to update the link down status, because some of them result from
the change of speed.
Signed-off-by: Hayes Wang <hayeswang@realtek.com>
---
drivers/net/usb/r8152.c | 134 ++++++++++++++++++++++++++++++++++++++----------
1 file changed, 107 insertions(+), 27 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 5d9d949..32af41a 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -272,6 +272,9 @@ enum rtl_register_content {
#define RTL8152_MAX_TX 10
#define RTL8152_MAX_RX 10
+#define INTBUFSIZE 2
+
+#define INTR_LINK 0x0004
#define RTL8152_REQT_READ 0xc0
#define RTL8152_REQT_WRITE 0x40
@@ -292,7 +295,8 @@ enum rtl_register_content {
enum rtl8152_flags {
RTL8152_UNPLUG = 0,
RTL8152_SET_RX_MODE,
- WORK_ENABLE
+ WORK_ENABLE,
+ RTL8152_LINK_CHG,
};
/* Define these values to match your device */
@@ -349,7 +353,9 @@ struct r8152 {
unsigned long flags;
struct usb_device *udev;
struct tasklet_struct tl;
+ struct usb_interface *intf;
struct net_device *netdev;
+ struct urb *intr_urb;
struct tx_agg tx_info[RTL8152_MAX_TX];
struct rx_agg rx_info[RTL8152_MAX_RX];
struct list_head rx_done, tx_free;
@@ -357,8 +363,10 @@ struct r8152 {
spinlock_t rx_lock, tx_lock;
struct delayed_work schedule;
struct mii_if_info mii;
+ int intr_interval;
u32 msg_enable;
u16 ocp_base;
+ u8 *intr_buff;
u8 version;
u8 speed;
};
@@ -855,6 +863,56 @@ static void write_bulk_callback(struct urb *urb)
tasklet_schedule(&tp->tl);
}
+static void intr_callback(struct urb *urb)
+{
+ struct r8152 *tp;
+ __u16 *d;
+ int status = urb->status;
+ int res;
+
+ tp = urb->context;
+ if (!tp)
+ return;
+
+ switch (status) {
+ case 0: /* success */
+ break;
+ case -ECONNRESET: /* unlink */
+ case -ESHUTDOWN:
+ netif_device_detach(tp->netdev);
+ case -ENOENT:
+ return;
+ case -EOVERFLOW:
+ netif_info(tp, intr, tp->netdev, "intr status -EOVERFLOW\n");
+ goto resubmit;
+ /* -EPIPE: should clear the halt */
+ default:
+ netif_info(tp, intr, tp->netdev, "intr status %d\n", status);
+ goto resubmit;
+ }
+
+ d = urb->transfer_buffer;
+ if (INTR_LINK & __le16_to_cpu(d[0])) {
+ if (!(tp->speed & LINK_STATUS)) {
+ set_bit(RTL8152_LINK_CHG, &tp->flags);
+ schedule_delayed_work(&tp->schedule, 0);
+ }
+ } else {
+ if (tp->speed & LINK_STATUS) {
+ set_bit(RTL8152_LINK_CHG, &tp->flags);
+ schedule_delayed_work(&tp->schedule, 5 * HZ);
+ }
+ }
+
+resubmit:
+ res = usb_submit_urb(urb, GFP_ATOMIC);
+ if (res == -ENODEV)
+ netif_device_detach(tp->netdev);
+ else if (res)
+ netif_err(tp, intr, tp->netdev,
+ "can't resubmit intr, status %d\n", res);
+}
+
static inline void *rx_agg_align(void *data)
{
return (void *)ALIGN((uintptr_t)data, 8);
@@ -894,11 +952,24 @@ static void free_all_mem(struct r8152 *tp)
tp->tx_info[i].head = tp->tx_info[i].data = NULL;
}
}
+
+ if (tp->intr_urb) {
+ usb_free_urb(tp->intr_urb);
+ tp->intr_urb = NULL;
+ }
+
+ if (tp->intr_buff) {
+ kfree(tp->intr_buff);
+ tp->intr_buff = NULL;
+ }
}
static int alloc_all_mem(struct r8152 *tp)
{
struct net_device *netdev = tp->netdev;
+ struct usb_interface *intf = tp->intf;
+ struct usb_host_interface *alt = intf->cur_altsetting;
+ struct usb_host_endpoint *ep_intr = alt->endpoint + 2;
struct urb *urb;
int node, i;
u8 *buf;
@@ -964,6 +1035,19 @@ static int alloc_all_mem(struct r8152 *tp)
list_add_tail(&tp->tx_info[i].list, &tp->tx_free);
}
+ tp->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!tp->intr_urb)
+ goto err1;
+
+ tp->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);
+ if (!tp->intr_buff)
+ goto err1;
+
+ tp->intr_interval = (int)ep_intr->desc.bInterval;
+ usb_fill_int_urb(tp->intr_urb, tp->udev, usb_rcvintpipe(tp->udev, 3),
+ tp->intr_buff, INTBUFSIZE, intr_callback,
+ tp, tp->intr_interval);
+
return 0;
err1:
@@ -1221,8 +1305,10 @@ static void rtl8152_set_rx_mode(struct net_device *netdev)
{
struct r8152 *tp = netdev_priv(netdev);
- if (tp->speed & LINK_STATUS)
+ if (tp->speed & LINK_STATUS) {
set_bit(RTL8152_SET_RX_MODE, &tp->flags);
+ schedule_delayed_work(&tp->schedule, 0);
+ }
}
static void _rtl8152_set_rx_mode(struct net_device *netdev)
@@ -1633,7 +1719,6 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex)
r8152_mdio_write(tp, MII_BMCR, bmcr);
out:
- schedule_delayed_work(&tp->schedule, 5 * HZ);
return ret;
}
@@ -1656,6 +1741,7 @@ static void set_carrier(struct r8152 *tp)
struct net_device *netdev = tp->netdev;
u8 speed;
+ clear_bit(RTL8152_LINK_CHG, &tp->flags);
speed = rtl8152_get_speed(tp);
if (speed & LINK_STATUS) {
@@ -1683,13 +1769,12 @@ static void rtl_work_func_t(struct work_struct *work)
if (test_bit(RTL8152_UNPLUG, &tp->flags))
goto out1;
- set_carrier(tp);
+ if (test_bit(RTL8152_LINK_CHG, &tp->flags))
+ set_carrier(tp);
if (test_bit(RTL8152_SET_RX_MODE, &tp->flags))
_rtl8152_set_rx_mode(tp->netdev);
- schedule_delayed_work(&tp->schedule, HZ);
-
out1:
return;
}
@@ -1699,28 +1784,20 @@ static int rtl8152_open(struct net_device *netdev)
struct r8152 *tp = netdev_priv(netdev);
int res = 0;
- tp->speed = rtl8152_get_speed(tp);
- if (tp->speed & LINK_STATUS) {
- res = rtl8152_enable(tp);
- if (res) {
- if (res == -ENODEV)
- netif_device_detach(tp->netdev);
-
- netif_err(tp, ifup, netdev,
- "rtl8152_open failed: %d\n", res);
- return res;
- }
-
- netif_carrier_on(netdev);
- } else {
- netif_stop_queue(netdev);
- netif_carrier_off(netdev);
+ res = usb_submit_urb(tp->intr_urb, GFP_KERNEL);
+ if (res) {
+ if (res == -ENODEV)
+ netif_device_detach(tp->netdev);
+ netif_warn(tp, ifup, netdev,
+ "intr_urb submit failed: %d\n", res);
+ return res;
}
rtl8152_set_speed(tp, AUTONEG_ENABLE, SPEED_100, DUPLEX_FULL);
+ tp->speed = 0;
+ netif_carrier_off(netdev);
netif_start_queue(netdev);
set_bit(WORK_ENABLE, &tp->flags);
- schedule_delayed_work(&tp->schedule, 0);
return res;
}
@@ -1730,6 +1807,7 @@ static int rtl8152_close(struct net_device *netdev)
struct r8152 *tp = netdev_priv(netdev);
int res = 0;
+ usb_kill_urb(tp->intr_urb);
clear_bit(WORK_ENABLE, &tp->flags);
cancel_delayed_work_sync(&tp->schedule);
netif_stop_queue(netdev);
@@ -1852,6 +1930,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
netif_device_detach(tp->netdev);
if (netif_running(tp->netdev)) {
+ usb_kill_urb(tp->intr_urb);
clear_bit(WORK_ENABLE, &tp->flags);
cancel_delayed_work_sync(&tp->schedule);
}
@@ -1868,10 +1947,11 @@ static int rtl8152_resume(struct usb_interface *intf)
r8152b_init(tp);
netif_device_attach(tp->netdev);
if (netif_running(tp->netdev)) {
- rtl8152_enable(tp);
+ rtl8152_set_speed(tp, AUTONEG_ENABLE, SPEED_100, DUPLEX_FULL);
+ tp->speed = 0;
+ netif_carrier_off(tp->netdev);
set_bit(WORK_ENABLE, &tp->flags);
- set_bit(RTL8152_SET_RX_MODE, &tp->flags);
- schedule_delayed_work(&tp->schedule, 0);
+ usb_submit_urb(tp->intr_urb, GFP_KERNEL);
}
return 0;
@@ -2006,13 +2086,13 @@ static int rtl8152_probe(struct usb_interface *intf,
tp->udev = udev;
tp->netdev = netdev;
+ tp->intf = intf;
netdev->netdev_ops = &rtl8152_netdev_ops;
netdev->watchdog_timeo = RTL8152_TX_TIMEOUT;
netdev->features |= NETIF_F_IP_CSUM;
netdev->hw_features = NETIF_F_IP_CSUM;
SET_ETHTOOL_OPS(netdev, &ops);
- tp->speed = 0;
tp->mii.dev = netdev;
tp->mii.mdio_read = read_mii_word;
--
1.8.3.1
^ permalink raw reply related
* [PATCH net-next 2/3] net/usb/r8152: enable tx checksum
From: Hayes Wang @ 2013-08-13 7:28 UTC (permalink / raw)
To: netdev; +Cc: linux-kernel, linux-usb, Hayes Wang
In-Reply-To: <1376378913-879-1-git-send-email-hayeswang@realtek.com>
Enable tx checksum.
Signed-off-by: Hayes Wang <hayeswang@realtek.com>
---
drivers/net/usb/r8152.c | 63 +++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 58 insertions(+), 5 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index c6c5aa2..5d9d949 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -20,6 +20,8 @@
#include <linux/if_vlan.h>
#include <linux/uaccess.h>
#include <linux/list.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
/* Version Information */
#define DRIVER_VERSION "v1.01.0 (2013/08/12)"
@@ -314,8 +316,13 @@ struct tx_desc {
u32 opts1;
#define TX_FS (1 << 31) /* First segment of a packet */
#define TX_LS (1 << 30) /* Final segment of a packet */
-#define TX_LEN_MASK 0xffff
+#define TX_LEN_MASK 0x3ffff
+
u32 opts2;
+#define UDP_CS (1 << 31) /* Calculate UDP/IP checksum */
+#define TCP_CS (1 << 30) /* Calculate TCP/IP checksum */
+#define IPV4_CS (1 << 29) /* Calculate IPv4 checksum */
+#define IPV6_CS (1 << 28) /* Calculate IPv6 checksum */
};
struct rx_agg {
@@ -964,6 +971,51 @@ err1:
return -ENOMEM;
}
+static void
+r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb)
+{
+ memset(desc, 0, sizeof(*desc));
+
+ desc->opts1 = cpu_to_le32((skb->len & TX_LEN_MASK) | TX_FS | TX_LS);
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ __be16 protocol;
+ u8 ip_protocol;
+ u32 opts2 = 0;
+
+ if (skb->protocol == htons(ETH_P_8021Q))
+ protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
+ else
+ protocol = skb->protocol;
+
+ switch (protocol) {
+ case htons(ETH_P_IP):
+ opts2 |= IPV4_CS;
+ ip_protocol = ip_hdr(skb)->protocol;
+ break;
+
+ case htons(ETH_P_IPV6):
+ opts2 |= IPV6_CS;
+ ip_protocol = ipv6_hdr(skb)->nexthdr;
+ break;
+
+ default:
+ ip_protocol = IPPROTO_RAW;
+ break;
+ }
+
+ if (ip_protocol == IPPROTO_TCP) {
+ opts2 |= TCP_CS;
+ opts2 |= (skb_transport_offset(skb) & 0x7fff) << 17;
+ } else if (ip_protocol == IPPROTO_UDP) {
+ opts2 |= UDP_CS;
+ } else
+ WARN_ON_ONCE(1);
+
+ desc->opts2 = cpu_to_le32(opts2);
+ }
+}
+
static void rx_bottom(struct r8152 *tp)
{
struct net_device_stats *stats;
@@ -1100,8 +1152,7 @@ next_agg:
tx_desc = (struct tx_desc *)agg->data;
agg->data += sizeof(*tx_desc);
- tx_desc->opts1 = cpu_to_le32((skb->len & TX_LEN_MASK) | TX_FS |
- TX_LS);
+ r8152_tx_csum(tp, tx_desc, skb);
memcpy(agg->data, skb->data, len);
agg->skb_num++;
agg->skb_len += len;
@@ -1249,7 +1300,7 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
agg->skb_num = agg->skb_len = 0;
len = skb->len;
- tx_desc->opts1 = cpu_to_le32((skb->len & TX_LEN_MASK) | TX_FS | TX_LS);
+ r8152_tx_csum(tp, tx_desc, skb);
memcpy(agg->data, skb->data, len);
dev_kfree_skb_any(skb);
agg->skb_num++;
@@ -1957,7 +2008,9 @@ static int rtl8152_probe(struct usb_interface *intf,
tp->netdev = netdev;
netdev->netdev_ops = &rtl8152_netdev_ops;
netdev->watchdog_timeo = RTL8152_TX_TIMEOUT;
- netdev->features &= ~NETIF_F_IP_CSUM;
+
+ netdev->features |= NETIF_F_IP_CSUM;
+ netdev->hw_features = NETIF_F_IP_CSUM;
SET_ETHTOOL_OPS(netdev, &ops);
tp->speed = 0;
--
1.8.3.1
^ permalink raw reply related
* [PATCH net-next 1/3] net/usb/r8152: support aggregation
From: Hayes Wang @ 2013-08-13 7:28 UTC (permalink / raw)
To: netdev; +Cc: linux-kernel, linux-usb, Hayes Wang
Enable the tx/rx aggregation which could contain one or more packets
for each bulk in/out. This could reduce the loading of the host
controller by sending less bulk transfer.
The rx packets in the bulk in buffer should be 8-byte aligned, and
the tx packets in the bulk out buffer should be 4-byte aligned.
Signed-off-by: Hayes Wang <hayeswang@realtek.com>
---
drivers/net/usb/r8152.c | 627 +++++++++++++++++++++++++++++++++++-------------
1 file changed, 466 insertions(+), 161 deletions(-)
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index 11c51f2..c6c5aa2 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -19,9 +19,10 @@
#include <linux/crc32.h>
#include <linux/if_vlan.h>
#include <linux/uaccess.h>
+#include <linux/list.h>
/* Version Information */
-#define DRIVER_VERSION "v1.0.0 (2013/05/03)"
+#define DRIVER_VERSION "v1.01.0 (2013/08/12)"
#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
#define DRIVER_DESC "Realtek RTL8152 Based USB 2.0 Ethernet Adapters"
#define MODULENAME "r8152"
@@ -267,6 +268,9 @@ enum rtl_register_content {
FULL_DUP = 0x01,
};
+#define RTL8152_MAX_TX 10
+#define RTL8152_MAX_RX 10
+
#define RTL8152_REQT_READ 0xc0
#define RTL8152_REQT_WRITE 0x40
#define RTL8152_REQ_GET_REGS 0x05
@@ -285,7 +289,6 @@ enum rtl_register_content {
/* rtl8152 flags */
enum rtl8152_flags {
RTL8152_UNPLUG = 0,
- RX_URB_FAIL,
RTL8152_SET_RX_MODE,
WORK_ENABLE
};
@@ -315,13 +318,36 @@ struct tx_desc {
u32 opts2;
};
+struct rx_agg {
+ struct list_head list;
+ struct urb *urb;
+ void *context;
+ void *buffer;
+ void *head;
+ u8 *data;
+};
+
+struct tx_agg {
+ struct list_head list;
+ struct urb *urb;
+ void *context;
+ void *buffer;
+ void *head;
+ u8 *data;
+ u32 skb_num;
+ u32 skb_len;
+};
+
struct r8152 {
unsigned long flags;
struct usb_device *udev;
struct tasklet_struct tl;
struct net_device *netdev;
- struct urb *rx_urb, *tx_urb;
- struct sk_buff *tx_skb, *rx_skb;
+ struct tx_agg tx_info[RTL8152_MAX_TX];
+ struct rx_agg rx_info[RTL8152_MAX_RX];
+ struct list_head rx_done, tx_free;
+ struct sk_buff_head tx_queue;
+ spinlock_t rx_lock, tx_lock;
struct delayed_work schedule;
struct mii_if_info mii;
u32 msg_enable;
@@ -340,6 +366,7 @@ enum rtl_version {
* The RTL chips use a 64 element hash table based on the Ethernet CRC.
*/
static const int multicast_filter_limit = 32;
+static unsigned int rx_buf_sz = 16384;
static
int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data)
@@ -686,6 +713,9 @@ static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data)
ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data);
}
+static
+int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags);
+
static inline void set_ethernet_addr(struct r8152 *tp)
{
struct net_device *dev = tp->netdev;
@@ -716,26 +746,6 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p)
return 0;
}
-static int alloc_all_urbs(struct r8152 *tp)
-{
- tp->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!tp->rx_urb)
- return 0;
- tp->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!tp->tx_urb) {
- usb_free_urb(tp->rx_urb);
- return 0;
- }
-
- return 1;
-}
-
-static void free_all_urbs(struct r8152 *tp)
-{
- usb_free_urb(tp->rx_urb);
- usb_free_urb(tp->tx_urb);
-}
-
static struct net_device_stats *rtl8152_get_stats(struct net_device *dev)
{
return &dev->stats;
@@ -743,129 +753,417 @@ static struct net_device_stats *rtl8152_get_stats(struct net_device *dev)
static void read_bulk_callback(struct urb *urb)
{
- struct r8152 *tp;
- unsigned pkt_len;
- struct sk_buff *skb;
struct net_device *netdev;
- struct net_device_stats *stats;
+ unsigned long lockflags;
int status = urb->status;
+ struct rx_agg *agg;
+ struct r8152 *tp;
int result;
- struct rx_desc *rx_desc;
- tp = urb->context;
+ agg = urb->context;
+ if (!agg)
+ return;
+
+ tp = agg->context;
if (!tp)
return;
+
if (test_bit(RTL8152_UNPLUG, &tp->flags))
return;
+
netdev = tp->netdev;
if (!netif_device_present(netdev))
return;
- stats = rtl8152_get_stats(netdev);
switch (status) {
case 0:
- break;
+ if (urb->actual_length < ETH_ZLEN)
+ break;
+
+ spin_lock_irqsave(&tp->rx_lock, lockflags);
+ list_add_tail(&agg->list, &tp->rx_done);
+ spin_unlock_irqrestore(&tp->rx_lock, lockflags);
+ tasklet_schedule(&tp->tl);
+ return;
case -ESHUTDOWN:
set_bit(RTL8152_UNPLUG, &tp->flags);
netif_device_detach(tp->netdev);
+ return;
case -ENOENT:
return; /* the urb is in unlink state */
case -ETIME:
pr_warn_ratelimited("may be reset is needed?..\n");
- goto goon;
+ break;
default:
pr_warn_ratelimited("Rx status %d\n", status);
- goto goon;
+ break;
}
- /* protect against short packets (tell me why we got some?!?) */
- if (urb->actual_length < sizeof(*rx_desc))
- goto goon;
-
-
- rx_desc = (struct rx_desc *)urb->transfer_buffer;
- pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
- if (urb->actual_length < sizeof(struct rx_desc) + pkt_len)
- goto goon;
-
- skb = netdev_alloc_skb_ip_align(netdev, pkt_len);
- if (!skb)
- goto goon;
-
- memcpy(skb->data, tp->rx_skb->data + sizeof(struct rx_desc), pkt_len);
- skb_put(skb, pkt_len);
- skb->protocol = eth_type_trans(skb, netdev);
- netif_rx(skb);
- stats->rx_packets++;
- stats->rx_bytes += pkt_len;
-goon:
- usb_fill_bulk_urb(tp->rx_urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1),
- tp->rx_skb->data, RTL8152_RMS + sizeof(struct rx_desc),
- (usb_complete_t)read_bulk_callback, tp);
- result = usb_submit_urb(tp->rx_urb, GFP_ATOMIC);
+ result = r8152_submit_rx(tp, agg, GFP_ATOMIC);
if (result == -ENODEV) {
netif_device_detach(tp->netdev);
} else if (result) {
- set_bit(RX_URB_FAIL, &tp->flags);
- goto resched;
- } else {
- clear_bit(RX_URB_FAIL, &tp->flags);
+ spin_lock_irqsave(&tp->rx_lock, lockflags);
+ list_add_tail(&agg->list, &tp->rx_done);
+ spin_unlock_irqrestore(&tp->rx_lock, lockflags);
+ tasklet_schedule(&tp->tl);
}
-
- return;
-resched:
- tasklet_schedule(&tp->tl);
}
-static void rx_fixup(unsigned long data)
+static void write_bulk_callback(struct urb *urb)
{
+ struct net_device_stats *stats;
+ unsigned long lockflags;
+ struct tx_agg *agg;
struct r8152 *tp;
- int status;
+ int status = urb->status;
- tp = (struct r8152 *)data;
- if (!test_bit(WORK_ENABLE, &tp->flags))
+ agg = urb->context;
+ if (!agg)
return;
- status = usb_submit_urb(tp->rx_urb, GFP_ATOMIC);
- if (status == -ENODEV) {
- netif_device_detach(tp->netdev);
- } else if (status) {
- set_bit(RX_URB_FAIL, &tp->flags);
- goto tlsched;
+ tp = agg->context;
+ if (!tp)
+ return;
+
+ stats = rtl8152_get_stats(tp->netdev);
+ if (status) {
+ pr_warn_ratelimited("Tx status %d\n", status);
+ stats->tx_errors += agg->skb_num;
} else {
- clear_bit(RX_URB_FAIL, &tp->flags);
+ stats->tx_packets += agg->skb_num;
+ stats->tx_bytes += agg->skb_len;
}
- return;
-tlsched:
- tasklet_schedule(&tp->tl);
+ if (!netif_device_present(tp->netdev))
+ return;
+
+ agg->data = agg->head;
+ agg->skb_num = agg->skb_len = 0;
+ spin_lock_irqsave(&tp->tx_lock, lockflags);
+ list_add_tail(&agg->list, &tp->tx_free);
+ spin_unlock_irqrestore(&tp->tx_lock, lockflags);
+
+ if (!skb_queue_empty(&tp->tx_queue))
+ tasklet_schedule(&tp->tl);
}
-static void write_bulk_callback(struct urb *urb)
+static inline void *rx_agg_align(void *data)
{
- struct r8152 *tp;
- int status = urb->status;
+ return (void *)ALIGN((uintptr_t)data, 8);
+}
- tp = urb->context;
- if (!tp)
+static inline void *tx_agg_align(void *data)
+{
+ return (void *)ALIGN((uintptr_t)data, 4);
+}
+
+static void free_all_mem(struct r8152 *tp)
+{
+ int i;
+
+ for (i = 0; i < RTL8152_MAX_RX; i++) {
+ if (tp->rx_info[i].urb) {
+ usb_free_urb(tp->rx_info[i].urb);
+ tp->rx_info[i].urb = NULL;
+ }
+
+ if (tp->rx_info[i].buffer) {
+ kfree(tp->rx_info[i].buffer);
+ tp->rx_info[i].buffer = NULL;
+ tp->rx_info[i].head = tp->rx_info[i].data = NULL;
+ }
+ }
+
+ for (i = 0; i < RTL8152_MAX_TX; i++) {
+ if (tp->tx_info[i].urb) {
+ usb_free_urb(tp->tx_info[i].urb);
+ tp->tx_info[i].urb = NULL;
+ }
+
+ if (tp->tx_info[i].buffer) {
+ kfree(tp->tx_info[i].buffer);
+ tp->tx_info[i].buffer = NULL;
+ tp->tx_info[i].head = tp->tx_info[i].data = NULL;
+ }
+ }
+}
+
+static int alloc_all_mem(struct r8152 *tp)
+{
+ struct net_device *netdev = tp->netdev;
+ struct urb *urb;
+ int node, i;
+ u8 *buf;
+
+ node = netdev->dev.parent ? dev_to_node(netdev->dev.parent) : -1;
+
+ spin_lock_init(&tp->rx_lock);
+ INIT_LIST_HEAD(&tp->rx_done);
+
+ for (i = 0; i < RTL8152_MAX_RX; i++) {
+ buf = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
+ if (!buf)
+ goto err1;
+
+ if (buf != rx_agg_align(buf)) {
+ kfree(buf);
+ buf = kmalloc_node(rx_buf_sz + 8, GFP_KERNEL, node);
+ if (!buf)
+ goto err1;
+ }
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ kfree(buf);
+ goto err1;
+ }
+
+ INIT_LIST_HEAD(&tp->rx_info[i].list);
+ tp->rx_info[i].context = tp;
+ tp->rx_info[i].urb = urb;
+ tp->rx_info[i].buffer = buf;
+ tp->rx_info[i].head = tp->rx_info[i].data = rx_agg_align(buf);
+ }
+
+ spin_lock_init(&tp->tx_lock);
+ INIT_LIST_HEAD(&tp->tx_free);
+ skb_queue_head_init(&tp->tx_queue);
+
+ for (i = 0; i < RTL8152_MAX_TX; i++) {
+ buf = kmalloc_node(rx_buf_sz, GFP_KERNEL, node);
+ if (!buf)
+ goto err1;
+
+ if (buf != tx_agg_align(buf)) {
+ kfree(buf);
+ buf = kmalloc_node(rx_buf_sz + 4, GFP_KERNEL, node);
+ if (!buf)
+ goto err1;
+ }
+
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ kfree(buf);
+ goto err1;
+ }
+
+ INIT_LIST_HEAD(&tp->tx_info[i].list);
+ tp->tx_info[i].context = tp;
+ tp->tx_info[i].urb = urb;
+ tp->tx_info[i].buffer = buf;
+ tp->tx_info[i].head = tp->tx_info[i].data = tx_agg_align(buf);
+
+ list_add_tail(&tp->tx_info[i].list, &tp->tx_free);
+ }
+
+ return 0;
+
+err1:
+ free_all_mem(tp);
+ return -ENOMEM;
+}
+
+static void rx_bottom(struct r8152 *tp)
+{
+ struct net_device_stats *stats;
+ struct net_device *netdev;
+ struct rx_agg *agg;
+ struct rx_desc *rx_desc;
+ unsigned long lockflags;
+ struct list_head *cursor, *next;
+ struct sk_buff *skb;
+ struct urb *urb;
+ unsigned pkt_len;
+ int len_used;
+ u8 *rx_data;
+ int ret;
+
+ netdev = tp->netdev;
+
+ if (!netif_running(netdev))
return;
- dev_kfree_skb_irq(tp->tx_skb);
- if (!netif_device_present(tp->netdev))
+
+ stats = rtl8152_get_stats(netdev);
+
+ spin_lock_irqsave(&tp->rx_lock, lockflags);
+ list_for_each_safe(cursor, next, &tp->rx_done) {
+ list_del_init(cursor);
+ spin_unlock_irqrestore(&tp->rx_lock, lockflags);
+
+ agg = list_entry(cursor, struct rx_agg, list);
+ urb = agg->urb;
+ if (urb->actual_length < ETH_ZLEN) {
+ ret = r8152_submit_rx(tp, agg, GFP_ATOMIC);
+ spin_lock_irqsave(&tp->rx_lock, lockflags);
+ if (ret && ret != -ENODEV) {
+ list_add_tail(&agg->list, next);
+ tasklet_schedule(&tp->tl);
+ }
+ continue;
+ }
+
+ len_used = 0;
+ rx_desc = agg->head;
+ rx_data = agg->head;
+ smp_wmb();
+ pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
+ len_used += sizeof(struct rx_desc) + pkt_len;
+
+ while (urb->actual_length >= len_used) {
+ if (pkt_len < ETH_ZLEN)
+ break;
+
+ pkt_len -= 4; /* CRC */
+ rx_data += sizeof(struct rx_desc);
+
+ skb = netdev_alloc_skb_ip_align(netdev, pkt_len);
+ if (!skb) {
+ stats->rx_dropped++;
+ break;
+ }
+ memcpy(skb->data, rx_data, pkt_len);
+ skb_put(skb, pkt_len);
+ skb->protocol = eth_type_trans(skb, netdev);
+ netif_rx(skb);
+ stats->rx_packets++;
+ stats->rx_bytes += pkt_len;
+
+ rx_data = rx_agg_align(rx_data + pkt_len + 4);
+ rx_desc = (struct rx_desc *)rx_data;
+ smp_wmb();
+ pkt_len = le32_to_cpu(rx_desc->opts1) & RX_LEN_MASK;
+ len_used = (int)(rx_data - (u8 *)agg->head);
+ len_used += sizeof(struct rx_desc) + pkt_len;
+ }
+
+ ret = r8152_submit_rx(tp, agg, GFP_ATOMIC);
+ spin_lock_irqsave(&tp->rx_lock, lockflags);
+ if (ret && ret != -ENODEV) {
+ list_add_tail(&agg->list, next);
+ tasklet_schedule(&tp->tl);
+ }
+ }
+ spin_unlock_irqrestore(&tp->rx_lock, lockflags);
+}
+
+static void tx_bottom(struct r8152 *tp)
+{
+ struct net_device_stats *stats;
+ struct net_device *netdev;
+ struct tx_agg *agg;
+ unsigned long lockflags;
+ u32 remain, total;
+ int res;
+
+ netdev = tp->netdev;
+
+ if (!netif_running(netdev))
return;
- if (status)
- dev_info(&urb->dev->dev, "%s: Tx status %d\n",
- tp->netdev->name, status);
- tp->netdev->trans_start = jiffies;
- netif_wake_queue(tp->netdev);
+
+next_agg:
+ agg = NULL;
+ spin_lock_irqsave(&tp->tx_lock, lockflags);
+ if (!skb_queue_empty(&tp->tx_queue) && !list_empty(&tp->tx_free)) {
+ struct list_head *cursor;
+
+ cursor = tp->tx_free.next;
+ list_del_init(cursor);
+ agg = list_entry(cursor, struct tx_agg, list);
+ }
+ spin_unlock_irqrestore(&tp->tx_lock, lockflags);
+
+ if (!agg)
+ return;
+
+ agg->data = agg->head;
+ agg->skb_num = agg->skb_len = 0;
+ remain = rx_buf_sz - sizeof(struct tx_desc);
+ total = 0;
+
+ while (remain >= ETH_ZLEN) {
+ struct tx_desc *tx_desc;
+ struct sk_buff *skb;
+ unsigned int len;
+
+ skb = skb_dequeue(&tp->tx_queue);
+ if (!skb)
+ break;
+
+ len = skb->len;
+ if (remain < len) {
+ skb_queue_head(&tp->tx_queue, skb);
+ break;
+ }
+
+ agg->data = tx_agg_align(agg->data);
+ tx_desc = (struct tx_desc *)agg->data;
+ agg->data += sizeof(*tx_desc);
+
+ tx_desc->opts1 = cpu_to_le32((skb->len & TX_LEN_MASK) | TX_FS |
+ TX_LS);
+ memcpy(agg->data, skb->data, len);
+ agg->skb_num++;
+ agg->skb_len += len;
+ dev_kfree_skb_any(skb);
+
+ agg->data += len;
+ remain = rx_buf_sz - sizeof(*tx_desc) -
+ (u32)(tx_agg_align(agg->data) - agg->head);
+ }
+
+ usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2),
+ agg->head, (int)(agg->data - (u8 *)agg->head),
+ (usb_complete_t)write_bulk_callback, agg);
+ res = usb_submit_urb(agg->urb, GFP_ATOMIC);
+
+ stats = rtl8152_get_stats(netdev);
+
+ if (res) {
+ /* Can we get/handle EPIPE here? */
+ if (res == -ENODEV) {
+ netif_device_detach(tp->netdev);
+ } else {
+ netif_warn(tp, tx_err, netdev,
+ "failed tx_urb %d\n", res);
+ stats->tx_dropped += agg->skb_num;
+ agg->data = agg->head;
+ spin_lock_irqsave(&tp->tx_lock, lockflags);
+ list_add_tail(&agg->list, &tp->tx_free);
+ spin_unlock_irqrestore(&tp->tx_lock, lockflags);
+ }
+ return;
+ }
+ goto next_agg;
+}
+
+static void bottom_half(unsigned long data)
+{
+ struct r8152 *tp;
+
+ tp = (struct r8152 *)data;
+ rx_bottom(tp);
+ tx_bottom(tp);
+}
+
+static
+int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
+{
+ usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1),
+ agg->head, rx_buf_sz,
+ (usb_complete_t)read_bulk_callback, agg);
+
+ return usb_submit_urb(agg->urb, mem_flags);
}
static void rtl8152_tx_timeout(struct net_device *netdev)
{
struct r8152 *tp = netdev_priv(netdev);
- struct net_device_stats *stats = rtl8152_get_stats(netdev);
+ int i;
+
netif_warn(tp, tx_err, netdev, "Tx timeout.\n");
- usb_unlink_urb(tp->tx_urb);
- stats->tx_errors++;
+ for (i = 0; i < RTL8152_MAX_TX; i++)
+ usb_unlink_urb(tp->tx_info[i].urb);
}
static void rtl8152_set_rx_mode(struct net_device *netdev)
@@ -923,33 +1221,43 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
{
struct r8152 *tp = netdev_priv(netdev);
struct net_device_stats *stats = rtl8152_get_stats(netdev);
+ unsigned long lockflags;
+ struct tx_agg *agg = NULL;
struct tx_desc *tx_desc;
unsigned int len;
int res;
- netif_stop_queue(netdev);
- len = skb->len;
- if (skb_header_cloned(skb) || skb_headroom(skb) < sizeof(*tx_desc)) {
- struct sk_buff *tx_skb;
+ skb_tx_timestamp(skb);
- tx_skb = skb_copy_expand(skb, sizeof(*tx_desc), 0, GFP_ATOMIC);
- dev_kfree_skb_any(skb);
- if (!tx_skb) {
- stats->tx_dropped++;
- netif_wake_queue(netdev);
- return NETDEV_TX_OK;
- }
- skb = tx_skb;
+ spin_lock_irqsave(&tp->tx_lock, lockflags);
+ if (!list_empty(&tp->tx_free) && skb_queue_empty(&tp->tx_queue)) {
+ struct list_head *cursor;
+
+ cursor = tp->tx_free.next;
+ list_del_init(cursor);
+ agg = list_entry(cursor, struct tx_agg, list);
}
- tx_desc = (struct tx_desc *)skb_push(skb, sizeof(*tx_desc));
- memset(tx_desc, 0, sizeof(*tx_desc));
- tx_desc->opts1 = cpu_to_le32((len & TX_LEN_MASK) | TX_FS | TX_LS);
- tp->tx_skb = skb;
- skb_tx_timestamp(skb);
- usb_fill_bulk_urb(tp->tx_urb, tp->udev, usb_sndbulkpipe(tp->udev, 2),
- skb->data, skb->len,
- (usb_complete_t)write_bulk_callback, tp);
- res = usb_submit_urb(tp->tx_urb, GFP_ATOMIC);
+ spin_unlock_irqrestore(&tp->tx_lock, lockflags);
+
+ if (!agg) {
+ skb_queue_tail(&tp->tx_queue, skb);
+ return NETDEV_TX_OK;
+ }
+
+ tx_desc = (struct tx_desc *)agg->head;
+ agg->data = agg->head + sizeof(*tx_desc);
+ agg->skb_num = agg->skb_len = 0;
+
+ len = skb->len;
+ tx_desc->opts1 = cpu_to_le32((skb->len & TX_LEN_MASK) | TX_FS | TX_LS);
+ memcpy(agg->data, skb->data, len);
+ dev_kfree_skb_any(skb);
+ agg->skb_num++;
+ agg->skb_len += len;
+ usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2),
+ agg->head, len + sizeof(*tx_desc),
+ (usb_complete_t)write_bulk_callback, agg);
+ res = usb_submit_urb(agg->urb, GFP_ATOMIC);
if (res) {
/* Can we get/handle EPIPE here? */
if (res == -ENODEV) {
@@ -957,12 +1265,12 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
} else {
netif_warn(tp, tx_err, netdev,
"failed tx_urb %d\n", res);
- stats->tx_errors++;
- netif_start_queue(netdev);
+ stats->tx_dropped++;
+ agg->data = agg->head;
+ spin_lock_irqsave(&tp->tx_lock, lockflags);
+ list_add_tail(&agg->list, &tp->tx_free);
+ spin_unlock_irqrestore(&tp->tx_lock, lockflags);
}
- } else {
- stats->tx_packets++;
- stats->tx_bytes += skb->len;
}
return NETDEV_TX_OK;
@@ -999,17 +1307,18 @@ static inline u8 rtl8152_get_speed(struct r8152 *tp)
static int rtl8152_enable(struct r8152 *tp)
{
- u32 ocp_data;
+ u32 ocp_data;
+ int i, ret;
u8 speed;
speed = rtl8152_get_speed(tp);
- if (speed & _100bps) {
+ if (speed & _10bps) {
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
- ocp_data &= ~EEEP_CR_EEEP_TX;
+ ocp_data |= EEEP_CR_EEEP_TX;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
} else {
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR);
- ocp_data |= EEEP_CR_EEEP_TX;
+ ocp_data &= ~EEEP_CR_EEEP_TX;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data);
}
@@ -1023,23 +1332,26 @@ static int rtl8152_enable(struct r8152 *tp)
ocp_data &= ~RXDY_GATED_EN;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data);
- usb_fill_bulk_urb(tp->rx_urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1),
- tp->rx_skb->data, RTL8152_RMS + sizeof(struct rx_desc),
- (usb_complete_t)read_bulk_callback, tp);
+ for (i = 0; i < RTL8152_MAX_RX; i++) {
+ ret = r8152_submit_rx(tp, &tp->rx_info[i], GFP_KERNEL);
+ if (ret)
+ break;
+ }
- return usb_submit_urb(tp->rx_urb, GFP_KERNEL);
+ return ret;
}
static void rtl8152_disable(struct r8152 *tp)
{
- u32 ocp_data;
- int i;
+ u32 ocp_data;
+ int i;
ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR);
ocp_data &= ~RCR_ACPT_ALL;
ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data);
- usb_kill_urb(tp->tx_urb);
+ for (i = 0; i < RTL8152_MAX_TX; i++)
+ usb_kill_urb(tp->tx_info[i].urb);
ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1);
ocp_data |= RXDY_GATED_EN;
@@ -1058,7 +1370,8 @@ static void rtl8152_disable(struct r8152 *tp)
mdelay(1);
}
- usb_kill_urb(tp->rx_urb);
+ for (i = 0; i < RTL8152_MAX_RX; i++)
+ usb_kill_urb(tp->rx_info[i].urb);
rtl8152_nic_reset(tp);
}
@@ -1429,8 +1742,8 @@ static void r8152b_hw_phy_cfg(struct r8152 *tp)
static void r8152b_init(struct r8152 *tp)
{
- u32 ocp_data;
- int i;
+ u32 ocp_data;
+ int i;
rtl_clear_bp(tp);
@@ -1475,9 +1788,9 @@ static void r8152b_init(struct r8152 *tp)
break;
}
- /* disable rx aggregation */
+ /* enable rx aggregation */
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL);
- ocp_data |= RX_AGG_DISABLE;
+ ocp_data &= ~RX_AGG_DISABLE;
ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data);
}
@@ -1619,6 +1932,7 @@ static int rtl8152_probe(struct usb_interface *intf,
struct usb_device *udev = interface_to_usbdev(intf);
struct r8152 *tp;
struct net_device *netdev;
+ int ret;
if (udev->actconfig->desc.bConfigurationValue != 1) {
usb_driver_set_configuration(udev, 1);
@@ -1631,10 +1945,12 @@ static int rtl8152_probe(struct usb_interface *intf,
return -ENOMEM;
}
+ SET_NETDEV_DEV(netdev, &intf->dev);
tp = netdev_priv(netdev);
+ memset(tp, 0, sizeof(*tp));
tp->msg_enable = 0x7FFF;
- tasklet_init(&tp->tl, rx_fixup, (unsigned long)tp);
+ tasklet_init(&tp->tl, bottom_half, (unsigned long)tp);
INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t);
tp->udev = udev;
@@ -1657,37 +1973,27 @@ static int rtl8152_probe(struct usb_interface *intf,
r8152b_init(tp);
set_ethernet_addr(tp);
- if (!alloc_all_urbs(tp)) {
- netif_err(tp, probe, netdev, "out of memory");
+ ret = alloc_all_mem(tp);
+ if (ret)
goto out;
- }
-
- tp->rx_skb = netdev_alloc_skb(netdev,
- RTL8152_RMS + sizeof(struct rx_desc));
- if (!tp->rx_skb)
- goto out1;
usb_set_intfdata(intf, tp);
- SET_NETDEV_DEV(netdev, &intf->dev);
-
- if (register_netdev(netdev) != 0) {
+ ret = register_netdev(netdev);
+ if (ret != 0) {
netif_err(tp, probe, netdev, "couldn't register the device");
- goto out2;
+ goto out1;
}
netif_info(tp, probe, netdev, "%s", DRIVER_VERSION);
return 0;
-out2:
- usb_set_intfdata(intf, NULL);
- dev_kfree_skb(tp->rx_skb);
out1:
- free_all_urbs(tp);
+ usb_set_intfdata(intf, NULL);
out:
free_netdev(netdev);
- return -EIO;
+ return ret;
}
static void rtl8152_unload(struct r8152 *tp)
@@ -1715,9 +2021,7 @@ static void rtl8152_disconnect(struct usb_interface *intf)
tasklet_kill(&tp->tl);
unregister_netdev(tp->netdev);
rtl8152_unload(tp);
- free_all_urbs(tp);
- if (tp->rx_skb)
- dev_kfree_skb(tp->rx_skb);
+ free_all_mem(tp);
free_netdev(tp->netdev);
}
}
@@ -1732,11 +2036,12 @@ MODULE_DEVICE_TABLE(usb, rtl8152_table);
static struct usb_driver rtl8152_driver = {
.name = MODULENAME,
+ .id_table = rtl8152_table,
.probe = rtl8152_probe,
.disconnect = rtl8152_disconnect,
- .id_table = rtl8152_table,
.suspend = rtl8152_suspend,
- .resume = rtl8152_resume
+ .resume = rtl8152_resume,
+ .reset_resume = rtl8152_resume,
};
module_usb_driver(rtl8152_driver);
--
1.8.3.1
^ permalink raw reply related
* [PATCH 3.11 v3] genetlink: fix family dump race
From: Johannes Berg @ 2013-08-13 7:04 UTC (permalink / raw)
To: netdev; +Cc: linux-wireless, Johannes Berg
From: Johannes Berg <johannes.berg@intel.com>
When dumping generic netlink families, only the first dump call
is locked with genl_lock(), which protects the list of families,
and thus subsequent calls can access the data without locking,
racing against family addition/removal. This can cause a crash.
Fix it - the locking needs to be conditional because the first
time around it's already locked.
A similar bug was reported to me on an old kernel (3.4.47) but
the exact scenario that happened there is no longer possible,
on those kernels the first round wasn't locked either. Looking
at the current code I found the race described above, which had
also existed on the old kernel.
Cc: stable@vger.kernel.org
Reported-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/netlink/genetlink.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index 2fd6dbe..6b6a03a 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -789,6 +789,10 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
struct net *net = sock_net(skb->sk);
int chains_to_skip = cb->args[0];
int fams_to_skip = cb->args[1];
+ bool need_locking = chains_to_skip || fams_to_skip;
+
+ if (need_locking)
+ genl_lock();
for (i = chains_to_skip; i < GENL_FAM_TAB_SIZE; i++) {
n = 0;
@@ -810,6 +814,9 @@ errout:
cb->args[0] = i;
cb->args[1] = n;
+ if (need_locking)
+ genl_unlock();
+
return skb->len;
}
--
1.8.0
^ permalink raw reply related
* Re: [PATCH 2/2] ipv6: fix checkpatch errors in net/ipv6/addrconf.c
From: Ding Tianhong @ 2013-08-13 6:54 UTC (permalink / raw)
To: Joe Perches
Cc: David S. Miller, Alexey Kuznetsov, James Morris,
Hideaki YOSHIFUJI, Patrick McHardy, Netdev
In-Reply-To: <1376375456.1949.22.camel@joe-AO722>
On 2013/8/13 14:30, Joe Perches wrote:
> On Tue, 2013-08-13 at 14:15 +0800, Ding Tianhong wrote:
>> ERROR: Macros with complex values should be enclosed in parenthesis
>> +#define ADBG(x) printk x
> []
>> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> []
>> @@ -99,7 +99,7 @@
> []
>> -#define ADBG(x) printk x
>> +#define ADBG(x) (printk x)
>
> A better way to fix this would be
> to convert the uses of ADBG and remove
> the superfluous parentheses.
>
> Something like the below but it might
> even better to remove the KERN_<LEVEL>s and
> just use pr_debug instead of ADBG...
> ---
thanks for your opinion. I think it's time to remove the tedious code and replace with pr_debug and pr_warning, I will send v2 to fix it.
^ permalink raw reply
* Re: question about netif_rx
From: David Shwatrz @ 2013-08-13 6:53 UTC (permalink / raw)
To: Julia Lawall
Cc: Francois Romieu, grant.likely, rob.herring, netdev, linux-kernel,
devicetree
In-Reply-To: <alpine.DEB.2.02.1308130828550.1997@localhost6.localdomain6>
Hello,
Sorry. I still don't understand what checksum has to do with it.
Does GRO depends on Rx/Tx checksum ? I don't think so.
In the napi_gro_receive() we check that the device supports
NETIF_F_GRO, but I don't see that we inspect checksum or that
NETIF_F_GRO is depends on checksum.
Can you please explain how checsum offload is related ?
rgs
David
On Tue, Aug 13, 2013 at 9:29 AM, Julia Lawall <julia.lawall@lip6.fr> wrote:
> On Tue, 13 Aug 2013, Francois Romieu wrote:
>
>> Julia Lawall <julia.lawall@lip6.fr> :
>> > François Romieu <romieu@fr.zoreil.com> :
>> [...]
>> > > Can you send a netif_receive_skb replacement patch for it ?
>> >
>> > Just to be sure, I just replace netif_rx by netif_receive_skb, nothing
>> > else?
>>
>> Yes. It should imho be fine with a comment incluing your analysis and a
>> few words about the current state of checksum offloading support.
>
> I wouldn't know what to say about the checksum part. It is not supported
> so I should use netif_receive_skb?
>
> thanks,
> julia
^ 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