* Understanding/reimplementing forwarding acceleration used by Broadcom (ctf)
From: Rafał Miłecki @ 2013-08-24 15:19 UTC (permalink / raw)
To: OpenWrt Development List, Network Development
[-- Attachment #1: Type: text/plain, Size: 2885 bytes --]
Recently I've finally discovered what makes packets forwarding much
faster when using Broadcom's firmware for their routers. It seems
pretty obvious for some DD-WRT guys, but I guess noone of us knew
about it.
It's the magic ctf.ko module that does the trick. It's a closed source
kernel module, that interferences with kernel using simple symbol
exported in setup.c:
ctf_attach_t ctf_attach_fn = NULL;
EXPORT_SYMBOL(ctf_attach_fn);
CTF probably stands for Cut-Through Forwarding.
Removing this module (rmmod ctf) resulted in performance drop on my
WNDR4500 from 505 Mbits/sec to 379 Mbits/sec for LAN to WAN
iperf-tested traffic. My friend tested this on his BCM4706-based
router and removing ctf.ko module resulted in 850Mb/s to 120Mb/s drop.
When ctf.ko gets loaded, it probably just replaces NULL with it's
struct allowing kernel to use it's mysterious API. If you wonder what
part of Linux kernel was modified to make use of ctf.ko, see attached
diff, that's what Broadcom modified in the net tree.
I don't have so good understanding of the net layer, so your help on
that would be more than appreciated.
AFAIK this magic kernel module allows some packets forwarding to be
done directly, with skipping packets analyze in the OS. It means some
features can't be used with it (like QoS), but it still looks like a
nice solution for basic routing.
It looks for me that ctf uses two connections types:
1) brc which may stand for Bridge Connection
2) ipc which may stand for IP Connection
You can see struct ctf_brc and struct ctf_ipc in the attached
hndctf.h. I didn't focus on ctf_brc yet, but I tried to analyze
ctf_ipc. It contains set of data allowing detection of the specific IP
connection. Pretty obviously, it means storing protocol, source (MAC,
IP, port), destination (MAC, IP, port) and few others (like VLAN id,
NAT rules, target interface) values. I guess that ctf.ko analyzes
every received packet using rules stored in struct ctf_ipc. When it
gets some packet covered in it's struct ctf_ipc database, it doesn't
pass it to the OS, but modifies it itself (if needed) and transmits to
the target.
You can see that nf_nat_packet was modified to call
ip_conntrack_ipct_add which tests if the packets matches it's
requirements. If it does, a new IP forwarding rule is added using
ctf_ipc_add.
I wonder what do you think about this solution. Is this something we
could try to implement ourself? Is it worth it? Is there some existing
project doing similar thing?
While ctf.ko module is closed source, it should be possible to
re-implement it. It probably just keeps a list of rules and does some
simple modifications of the received packets (like VLAN id change,
IP/port hacking for SNAT/DNAT), etc.
I don't have any experience in hacking net layer, so any comments on
that would be great!
--
Rafał
[-- Attachment #2: hndctf.h --]
[-- Type: text/x-chdr, Size: 10072 bytes --]
/*
* Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: hndctf.h 371260 2012-11-27 19:42:11Z $
*/
#ifndef _HNDCTF_H_
#define _HNDCTF_H_
#include <bcmutils.h>
#include <proto/bcmip.h>
#include <proto/ethernet.h>
#include <proto/vlan.h>
/*
* Define to enable couting VLAN tx and rx packets and bytes. This could be
* disabled if the functionality has impact on performance.
*/
#define CTFVLSTATS
#define CTF_ENAB(ci) (((ci) != NULL) && (ci)->_ctf)
#define CTF_ACTION_TAG (1 << 0)
#define CTF_ACTION_UNTAG (1 << 1)
#define CTF_ACTION_SNAT (1 << 2)
#define CTF_ACTION_DNAT (1 << 3)
#define CTF_ACTION_SUSPEND (1 << 4)
#define CTF_ACTION_TOS (1 << 5)
#define CTF_ACTION_MARK (1 << 6)
#define CTF_ACTION_BYTECNT (1 << 7)
#define CTF_ACTION_PPPOE_ADD (1 << 8)
#define CTF_ACTION_PPPOE_DEL (1 << 9)
#define ctf_attach(osh, n, m, c, a) \
(ctf_attach_fn ? ctf_attach_fn(osh, n, m, c, a) : NULL)
#define ctf_forward(ci, p, d) (ci)->fn.forward(ci, p, d)
#define ctf_isenabled(ci, d) (CTF_ENAB(ci) ? (ci)->fn.isenabled(ci, d) : FALSE)
#define ctf_isbridge(ci, d) (CTF_ENAB(ci) ? (ci)->fn.isbridge(ci, d) : FALSE)
#define ctf_enable(ci, d, e, b) (CTF_ENAB(ci) ? (ci)->fn.enable(ci, d, e, b) : BCME_OK)
#define ctf_brc_add(ci, b) (CTF_ENAB(ci) ? (ci)->fn.brc_add(ci, b) : BCME_OK)
#define ctf_brc_delete(ci, e) (CTF_ENAB(ci) ? (ci)->fn.brc_delete(ci, e) : BCME_OK)
#define ctf_brc_update(ci, b) (CTF_ENAB(ci) ? (ci)->fn.brc_update(ci, b) : BCME_OK)
#define ctf_brc_lkup(ci, e) (CTF_ENAB(ci) ? (ci)->fn.brc_lkup(ci, e) : NULL)
#define ctf_ipc_add(ci, i, v6) (CTF_ENAB(ci) ? (ci)->fn.ipc_add(ci, i, v6) : BCME_OK)
#define ctf_ipc_delete(ci, i, v6) \
(CTF_ENAB(ci) ? (ci)->fn.ipc_delete(ci, i, v6) : BCME_OK)
#define ctf_ipc_count_get(ci, i) \
(CTF_ENAB(ci) ? (ci)->fn.ipc_count_get(ci, i) : BCME_OK)
#define ctf_ipc_delete_multi(ci, i, im, v6) \
(CTF_ENAB(ci) ? (ci)->fn.ipc_delete_multi(ci, i, im, v6) : BCME_OK)
#define ctf_ipc_delete_range(ci, s, e, v6) \
(CTF_ENAB(ci) ? (ci)->fn.ipc_delete_range(ci, s, e, v6) : BCME_OK)
#define ctf_ipc_action(ci, s, e, am, v6) \
(CTF_ENAB(ci) ? (ci)->fn.ipc_action(ci, s, e, am, v6) : BCME_OK)
#define ctf_ipc_lkup(ci, i, v6) \
(CTF_ENAB(ci) ? (ci)->fn.ipc_lkup(ci, i, v6) : NULL)
#ifdef CTF_IPV6
#define ctf_ipc_lkup_l4proto(ci, iph, l4p) (CTF_ENAB(ci) && (ci)->fn.ipc_lkup_l4proto? \
(ci)->fn.ipc_lkup_l4proto((uint8 *)iph, l4p) : NULL)
#else
#define ctf_ipc_lkup_l4proto(ci, iph, l4p) (NULL)
#endif /* CTF_IPV6 */
#define ctf_dev_register(ci, d, b) \
(CTF_ENAB(ci) ? (ci)->fn.dev_register(ci, d, b) : BCME_OK)
#define ctf_dev_vlan_add(ci, d, vid, vd) \
(CTF_ENAB(ci) ? (ci)->fn.dev_vlan_add(ci, d, vid, vd) : BCME_OK)
#define ctf_dev_vlan_delete(ci, d, vid) \
(CTF_ENAB(ci) ? (ci)->fn.dev_vlan_delete(ci, d, vid) : BCME_OK)
#define ctf_detach(ci) if (CTF_ENAB(ci)) (ci)->fn.detach(ci)
#define ctf_dump(ci, b) if (CTF_ENAB(ci)) (ci)->fn.dump(ci, b)
#define ctf_dev_unregister(ci, d) if (CTF_ENAB(ci)) (ci)->fn.dev_unregister(ci, d)
#define CTFCNTINCR(s) ((s)++)
#define CTFCNTADD(s, c) ((s) += (c))
#define PPPOE_ETYPE_OFFSET 12
#define PPPOE_VER_OFFSET 14
#define PPPOE_SESID_OFFSET 16
#define PPPOE_LEN_OFFSET 18
#define PPPOE_HLEN 20
#define PPPOE_PROT_PPP 0x0021
typedef struct ctf_pub ctf_t;
typedef struct ctf_brc ctf_brc_t;
typedef struct ctf_ipc ctf_ipc_t;
typedef struct ctf_conn_tuple ctf_conn_tuple_t;
typedef struct ctf_brc_hot ctf_brc_hot_t;
typedef void (*ctf_detach_cb_t)(ctf_t *ci, void *arg);
typedef ctf_t * (*ctf_attach_t)(osl_t *osh, uint8 *name, uint32 *msg_level,
ctf_detach_cb_t cb, void *arg);
typedef void (*ctf_detach_t)(ctf_t *ci);
typedef int32 (*ctf_forward_t)(ctf_t *ci, void *p, void *rxifp);
typedef bool (*ctf_isenabled_t)(ctf_t *ci, void *dev);
typedef bool (*ctf_isbridge_t)(ctf_t *ci, void *dev);
typedef int32 (*ctf_brc_add_t)(ctf_t *ci, ctf_brc_t *brc);
typedef int32 (*ctf_brc_delete_t)(ctf_t *ci, uint8 *ea);
typedef int32 (*ctf_brc_update_t)(ctf_t *ci, ctf_brc_t *brc);
typedef ctf_brc_t * (*ctf_brc_lkup_t)(ctf_t *ci, uint8 *da);
typedef int32 (*ctf_ipc_add_t)(ctf_t *ci, ctf_ipc_t *ipc, bool v6);
typedef int32 (*ctf_ipc_delete_t)(ctf_t *ci, ctf_ipc_t *ipc, bool v6);
typedef int32 (*ctf_ipc_count_get_t)(ctf_t *ci);
typedef int32 (*ctf_ipc_delete_multi_t)(ctf_t *ci, ctf_ipc_t *ipc,
ctf_ipc_t *ipcm, bool v6);
typedef int32 (*ctf_ipc_delete_range_t)(ctf_t *ci, ctf_ipc_t *start,
ctf_ipc_t *end, bool v6);
typedef int32 (*ctf_ipc_action_t)(ctf_t *ci, ctf_ipc_t *start,
ctf_ipc_t *end, uint32 action_mask, bool v6);
typedef ctf_ipc_t * (*ctf_ipc_lkup_t)(ctf_t *ci, ctf_ipc_t *ipc, bool v6);
typedef uint8 * (*ctf_ipc_lkup_l4proto_t)(uint8 *iph, uint8 *proto_num);
typedef int32 (*ctf_enable_t)(ctf_t *ci, void *dev, bool enable, ctf_brc_hot_t **brc_hot);
typedef int32 (*ctf_dev_register_t)(ctf_t *ci, void *dev, bool br);
typedef void (*ctf_dev_unregister_t)(ctf_t *ci, void *dev);
typedef int32 (*ctf_dev_vlan_add_t)(ctf_t *ci, void *dev, uint16 vid, void *vldev);
typedef int32 (*ctf_dev_vlan_delete_t)(ctf_t *ci, void *dev, uint16 vid);
typedef void (*ctf_dump_t)(ctf_t *ci, struct bcmstrbuf *b);
struct ctf_brc_hot {
struct ether_addr ea; /* Dest address */
ctf_brc_t *brcp; /* BRC entry corresp to dest mac */
};
typedef struct ctf_fn {
ctf_detach_t detach;
ctf_forward_t forward;
ctf_isenabled_t isenabled;
ctf_isbridge_t isbridge;
ctf_brc_add_t brc_add;
ctf_brc_delete_t brc_delete;
ctf_brc_update_t brc_update;
ctf_brc_lkup_t brc_lkup;
ctf_ipc_add_t ipc_add;
ctf_ipc_delete_t ipc_delete;
ctf_ipc_count_get_t ipc_count_get;
ctf_ipc_delete_multi_t ipc_delete_multi;
ctf_ipc_delete_range_t ipc_delete_range;
ctf_ipc_action_t ipc_action;
ctf_ipc_lkup_t ipc_lkup;
ctf_ipc_lkup_l4proto_t ipc_lkup_l4proto;
ctf_enable_t enable;
ctf_dev_register_t dev_register;
ctf_dev_unregister_t dev_unregister;
ctf_detach_cb_t detach_cb;
void *detach_cb_arg;
ctf_dev_vlan_add_t dev_vlan_add;
ctf_dev_vlan_delete_t dev_vlan_delete;
ctf_dump_t dump;
} ctf_fn_t;
struct ctf_pub {
bool _ctf; /* Global CTF enable/disable */
ctf_fn_t fn; /* Exported functions */
};
struct ctf_mark; /* Connection Mark */
struct ctf_brc {
struct ctf_brc *next; /* Pointer to brc entry */
struct ether_addr dhost; /* MAC addr of host */
uint16 vid; /* VLAN id to use on txif */
void *txifp; /* Interface connected to host */
uint32 action; /* Tag or untag the frames */
uint32 live; /* Counter used to expire the entry */
uint32 hits; /* Num frames matching brc entry */
uint64 *bytecnt_ptr; /* Pointer to the byte counter */
};
#ifdef CTF_IPV6
#define IPADDR_U32_SZ (IPV6_ADDR_LEN / sizeof(uint32))
#else
#define IPADDR_U32_SZ 1
#endif
struct ctf_conn_tuple {
uint32 sip[IPADDR_U32_SZ], dip[IPADDR_U32_SZ];
uint16 sp, dp;
uint8 proto;
};
typedef struct ctf_nat {
uint32 ip;
uint16 port;
} ctf_nat_t;
struct ctf_ipc {
struct ctf_ipc *next; /* Pointer to ipc entry */
ctf_conn_tuple_t tuple; /* Tuple to uniquely id the flow */
uint16 vid; /* VLAN id to use on txif */
struct ether_addr dhost; /* Destination MAC address */
struct ether_addr shost; /* Source MAC address */
void *txif; /* Target interface to send */
uint32 action; /* NAT and/or VLAN actions */
ctf_brc_t *brcp; /* BRC entry corresp to source mac */
uint32 live; /* Counter used to expire the entry */
struct ctf_nat nat; /* Manip data for SNAT, DNAT */
struct ether_addr sa; /* MAC address of sender */
uint8 tos; /* IPv4 tos or IPv6 traffic class field with ECN cleared */
uint16 pppoe_sid; /* PPPOE session to use */
void *ppp_ifp; /* PPP interface handle */
uint32 hits; /* Num frames matching ipc entry */
uint64 *bytecnt_ptr; /* Pointer to the byte counter */
struct ctf_mark mark; /* Mark value to use for the connection */
};
extern ctf_t *ctf_kattach(osl_t *osh, uint8 *name);
extern void ctf_kdetach(ctf_t *kci);
extern ctf_attach_t ctf_attach_fn;
extern ctf_t *_ctf_attach(osl_t *osh, uint8 *name, uint32 *msg_level,
ctf_detach_cb_t cb, void *arg);
extern ctf_t *kcih;
/* Hot bridge cache lkup */
#define MAXBRCHOT 4
#define MAXBRCHOTIF 4
#define CTF_BRC_HOT_HASH(da) ((((uint8 *)da)[4] ^ ((uint8 *)da)[5]) & (MAXBRCHOT - 1))
#define CTF_HOTBRC_CMP(hbrc, da, rxifp) \
({ \
ctf_brc_hot_t *bh = (hbrc) + CTF_BRC_HOT_HASH(da); \
((eacmp((bh)->ea.octet, (da)) == 0) && (bh->brcp->txifp != (rxifp))); \
})
/* Header prep for packets matching hot bridge cache entry */
#define CTF_HOTBRC_L2HDR_PREP(osh, hbrc, prio, data, p) \
do { \
uint8 *l2h; \
ctf_brc_hot_t *bh = (hbrc) + CTF_BRC_HOT_HASH(data); \
ASSERT(*(uint16 *)((data) + VLAN_TPID_OFFSET) == HTON16(ETHER_TYPE_8021Q)); \
if (bh->brcp->action & CTF_ACTION_UNTAG) { \
/* Remove vlan header */ \
l2h = PKTPULL((osh), (p), VLAN_TAG_LEN); \
ether_rcopy(l2h - VLAN_TAG_LEN + ETHER_ADDR_LEN, \
l2h + ETHER_ADDR_LEN); \
ether_rcopy(l2h - VLAN_TAG_LEN, l2h); \
} else { \
/* Update vlan header */ \
l2h = (data); \
*(uint16 *)(l2h + VLAN_TCI_OFFSET) = \
HTON16((prio) << VLAN_PRI_SHIFT | bh->brcp->vid); \
} \
} while (0)
#endif /* _HNDCTF_H_ */
[-- Attachment #3: ctf.diff --]
[-- Type: application/octet-stream, Size: 35155 bytes --]
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 4732432..9856941 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -46,6 +46,7 @@ union nf_conntrack_expect_proto {
#include <linux/netfilter/nf_conntrack_pptp.h>
#include <linux/netfilter/nf_conntrack_h323.h>
#include <linux/netfilter/nf_conntrack_sane.h>
+#include <linux/netfilter/nf_conntrack_autofw.h>
/* per conntrack: application helper private data */
union nf_conntrack_help {
@@ -54,6 +55,7 @@ union nf_conntrack_help {
struct nf_ct_pptp_master ct_pptp_info;
struct nf_ct_h323_master ct_h323_info;
struct nf_ct_sane_master ct_sane_info;
+ struct nf_ct_autofw_master ct_autofw_info;
};
#include <linux/types.h>
@@ -86,6 +88,12 @@ struct nf_conn_help {
unsigned int expecting;
};
+#ifdef HNDCTF
+#define CTF_FLAGS_CACHED (1 << 31) /* Indicates cached connection */
+#define CTF_FLAGS_EXCLUDED (1 << 30)
+#define CTF_FLAGS_REPLY_CACHED (1 << 1)
+#define CTF_FLAGS_ORG_CACHED (1 << 0)
+#endif
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
@@ -96,7 +104,6 @@ struct nf_conn
plus 1 for any connection(s) we are `master' for */
struct nf_conntrack ct_general;
- /* XXX should I move this to the tail ? - Y.K */
/* These are my tuples; original and reply */
struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
@@ -128,6 +135,14 @@ struct nf_conn
u_int32_t secmark;
#endif
+#ifdef HNDCTF
+ /* Timeout for the connection */
+ u_int32_t expire_jiffies;
+
+ /* Flags for connection attributes */
+ u_int32_t ctf_flags;
+#endif /* HNDCTF */
+
/* Storage reserved for other modules: */
union nf_conntrack_proto proto;
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index de78c9d..443285d 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -35,6 +35,9 @@
#include <linux/if_vlan.h>
#include "vlan.h"
#include "vlanproc.h"
+#ifdef HNDCTF
+#include <ctf/hndctf.h>
+#endif /* HNDCTF */
#define DRV_VERSION "1.8"
@@ -246,6 +249,9 @@ static int unregister_vlan_dev(struct net_device *real_dev,
vlan_group_set_device(grp, vlan_id, NULL);
synchronize_net();
+#ifdef HNDCTF
+ (void)ctf_dev_vlan_delete(kcih, real_dev, vlan_id);
+#endif /* HNDCTF */
/* Caller unregisters (and if necessary, puts)
* VLAN device, but we get rid of the reference to
@@ -530,6 +536,10 @@ static struct net_device *register_vlan_device(const char *eth_IF_name,
if (register_netdevice(new_dev))
goto out_free_newdev;
+#ifdef HNDCTF
+ (void)ctf_dev_vlan_add(kcih, real_dev, VLAN_ID, new_dev);
+#endif /* HNDCTF */
+
lockdep_set_class(&new_dev->_xmit_lock, &vlan_netdev_xmit_lock_key);
new_dev->iflink = real_dev->ifindex;
diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
index d216a64..f823fc8 100644
--- a/net/8021q/vlanproc.c
+++ b/net/8021q/vlanproc.c
@@ -44,6 +44,9 @@ static void *vlan_seq_start(struct seq_file *seq, loff_t *pos);
static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos);
static void vlan_seq_stop(struct seq_file *seq, void *);
static int vlandev_seq_show(struct seq_file *seq, void *v);
+#ifdef CONFIG_INET_GRO
+static int gro_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos);
+#endif /* CONFIG_INET_GRO */
/*
* Global Data
@@ -98,10 +101,75 @@ static int vlandev_seq_open(struct inode *inode, struct file *file)
return single_open(file, vlandev_seq_show, PDE(inode)->data);
}
+#ifdef CONFIG_INET_GRO
+int gro_timer_init;
+struct timer_list gro_timer;
+spinlock_t gro_lock;
+int gro_timer_interval;
+
+static void gro_watchdog(ulong data)
+{
+ struct net_device *gro_dev = (struct net_device *)data;
+ spin_lock_bh(&gro_lock);
+
+ if (gro_dev->features & NETIF_F_GRO) {
+ gro_timer.expires = jiffies + gro_timer_interval;
+ add_timer(&gro_timer);
+ }
+
+ napi_gro_flush(gro_dev);
+
+ spin_unlock_bh(&gro_lock);
+}
+
+static int gro_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
+{
+ struct seq_file *seq = (struct seq_file *)file->private_data;
+ struct net_device *gro_dev = seq->private;
+
+ if (gro_timer_init == 0) {
+ spin_lock_init(&gro_lock);
+
+ init_timer(&gro_timer);
+ gro_timer.function = gro_watchdog;
+ gro_timer_init = 1;
+ }
+
+ if (size < 5 || size > 8)
+ return -EINVAL;
+
+ if (strncmp(buf, "-gro", 4))
+ return -EINVAL;
+
+ sscanf(buf, "-gro %d", &gro_timer_interval);
+
+ if (gro_timer_interval > 0) {
+ gro_dev->features |= NETIF_F_GRO;
+ gro_timer.data = (ulong)gro_dev;
+ gro_timer.expires = jiffies + gro_timer_interval;
+ mod_timer(&gro_timer, jiffies + gro_timer_interval);
+ printk("\ngro enabled with interval %d\n", gro_timer_interval);
+ }
+ else {
+ gro_dev->features &= ~NETIF_F_GRO;
+ del_timer(&gro_timer);
+
+ /* flush packet in gro_device */
+ gro_watchdog((ulong)gro_dev);
+ printk("\ngro disabled\n");
+ }
+
+ return size;
+}
+#endif /* CONFIG_INET_GRO */
+
static const struct file_operations vlandev_fops = {
.owner = THIS_MODULE,
.open = vlandev_seq_open,
.read = seq_read,
+#ifdef CONFIG_INET_GRO
+ .write = gro_write,
+#endif /* CONFIG_INET_GRO */
.llseek = seq_lseek,
.release = single_release,
};
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 3fc6972..14bf114 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_fdb.c,v 1.6 2002/01/17 00:57:07 davem Exp $
+ * $Id: br_fdb.c,v 1.5 2010-06-15 01:09:50 $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -24,6 +24,100 @@
#include <asm/atomic.h>
#include <asm/unaligned.h>
#include "br_private.h"
+#ifdef HNDCTF
+#include <linux/if.h>
+#include <linux/if_vlan.h>
+#include <typedefs.h>
+#include <osl.h>
+#include <ctf/hndctf.h>
+
+static void
+br_brc_init(ctf_brc_t *brc, unsigned char *ea, struct net_device *rxdev)
+{
+ memset(brc, 0, sizeof(ctf_brc_t));
+
+ memcpy(brc->dhost.octet, ea, ETH_ALEN);
+
+ if (rxdev->priv_flags & IFF_802_1Q_VLAN) {
+ brc->txifp = (void *)(VLAN_DEV_INFO(rxdev)->real_dev);
+ brc->vid = VLAN_DEV_INFO(rxdev)->vlan_id;
+ brc->action = ((VLAN_DEV_INFO(rxdev)->flags & 1) ?
+ CTF_ACTION_TAG : CTF_ACTION_UNTAG);
+ } else {
+ brc->txifp = (void *)rxdev;
+ brc->action = CTF_ACTION_UNTAG;
+ }
+
+#ifdef DEBUG
+ printk("mac %02x:%02x:%02x:%02x:%02x:%02x\n",
+ brc->dhost.octet[0], brc->dhost.octet[1],
+ brc->dhost.octet[2], brc->dhost.octet[3],
+ brc->dhost.octet[4], brc->dhost.octet[5]);
+ printk("vid: %d action %x\n", brc->vid, brc->action);
+ printk("txif: %s\n", ((struct net_device *)brc->txifp)->name);
+#endif
+
+ return;
+}
+
+/*
+ * Add bridge cache entry.
+ */
+void
+br_brc_add(unsigned char *ea, struct net_device *rxdev)
+{
+ ctf_brc_t brc_entry;
+
+ /* Add brc entry only if packet is received on ctf
+ * enabled interface
+ */
+ if (!ctf_isenabled(kcih, ((rxdev->priv_flags & IFF_802_1Q_VLAN) ?
+ VLAN_DEV_INFO(rxdev)->real_dev : rxdev)))
+ return;
+
+ br_brc_init(&brc_entry, ea, rxdev);
+
+#ifdef DEBUG
+ printk("%s: Adding brc entry\n", __FUNCTION__);
+#endif
+
+ /* Add the bridge cache entry */
+ if (ctf_brc_lkup(kcih, ea) == NULL)
+ ctf_brc_add(kcih, &brc_entry);
+ else
+ ctf_brc_update(kcih, &brc_entry);
+
+ return;
+}
+
+/*
+ * Update bridge cache entry.
+ */
+void
+br_brc_update(unsigned char *ea, struct net_device *rxdev)
+{
+ ctf_brc_t brc_entry;
+
+ /* Update brc entry only if packet is received on ctf
+ * enabled interface
+ */
+ if (!ctf_isenabled(kcih, ((rxdev->priv_flags & IFF_802_1Q_VLAN) ?
+ VLAN_DEV_INFO(rxdev)->real_dev : rxdev)))
+ return;
+
+ /* Initialize the new device and/or vlan info */
+ br_brc_init(&brc_entry, ea, rxdev);
+
+#ifdef DEBUG
+ printk("%s: Updating brc entry\n", __FUNCTION__);
+#endif
+
+ /* Update the bridge cache entry */
+ ctf_brc_update(kcih, &brc_entry);
+
+ return;
+}
+#endif /* HNDCTF */
static struct kmem_cache *br_fdb_cache __read_mostly;
static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
@@ -134,9 +228,23 @@ void br_fdb_cleanup(unsigned long _data)
if (f->is_static)
continue;
this_timer = f->ageing_timer + delay;
- if (time_before_eq(this_timer, jiffies))
+ if (time_before_eq(this_timer, jiffies)) {
+#ifdef HNDCTF
+ ctf_brc_t *brcp;
+
+ /* Before expiring the fdb entry check the brc
+ * live counter to make sure there are no frames
+ * on this connection for timeout period.
+ */
+ brcp = ctf_brc_lkup(kcih, f->addr.addr);
+ if ((brcp != NULL) && (brcp->live > 0)) {
+ brcp->live = 0;
+ f->ageing_timer = jiffies;
+ continue;
+ }
+#endif /* HNDCTF */
fdb_delete(f);
- else if (this_timer < next_timer)
+ } else if (this_timer < next_timer)
next_timer = this_timer;
}
}
@@ -251,8 +359,15 @@ static void fdb_rcu_free(struct rcu_head *head)
/* Set entry up for deletion with RCU */
void br_fdb_put(struct net_bridge_fdb_entry *ent)
{
- if (atomic_dec_and_test(&ent->use_count))
+ if (atomic_dec_and_test(&ent->use_count)) {
+#ifdef HNDCTF
+ /* Delete the corresponding brc entry when it expires
+ * or deleted by user.
+ */
+ ctf_brc_delete(kcih, ent->addr.addr);
+#endif /* HNDCTF */
call_rcu(&ent->rcu, fdb_rcu_free);
+ }
}
/*
@@ -330,7 +445,14 @@ static struct net_bridge_fdb_entry *fdb_create(struct hlist_head *head,
fdb->is_local = is_local;
fdb->is_static = is_local;
fdb->ageing_timer = jiffies;
+
+ /* Add bridge cache entry for non local hosts */
+#ifdef HNDCTF
+ if (!is_local && (source->state == BR_STATE_FORWARDING))
+ br_brc_add((unsigned char *)addr, source->dev);
+#endif /* HNDCTF */
}
+
return fdb;
}
@@ -394,6 +516,15 @@ void br_fdb_update(struct net_bridge *br, struct net_bridge_port *source,
source->dev->name);
} else {
/* fastpath: update of existing entry */
+#ifdef HNDCTF
+ /* Update the brc entry incase the host moved from
+ * one bridge to another or to a different port under
+ * the same bridge.
+ */
+ if (source->state == BR_STATE_FORWARDING)
+ br_brc_update((unsigned char *)addr, source->dev);
+#endif /* HNDCTF */
+
fdb->dst = source;
fdb->ageing_timer = jiffies;
}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 849deaf..b589c43 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_if.c,v 1.7 2001/12/24 00:59:55 davem Exp $
+ * $Id: br_if.c,v 1.5 2010-11-04 09:38:03 $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -25,6 +25,10 @@
#include "br_private.h"
+#ifdef HNDCTF
+#include <ctf/hndctf.h>
+#endif /* HNDCTF */
+
/*
* Determine initial path cost based on speed.
* using recommendations from 802.1d standard
@@ -217,6 +221,9 @@ static struct net_device *new_bridge_dev(const char *name)
br->ageing_time = 300 * HZ;
INIT_LIST_HEAD(&br->age_list);
+#ifdef CONFIG_INET_GSO
+ br->feature_mask |= NETIF_F_GSO;
+#endif /* CONFIG_INET_GSO */
br_stp_timer_init(br);
return dev;
@@ -286,6 +293,10 @@ int br_add_bridge(const char *name)
dev = new_bridge_dev(name);
if (!dev)
return -ENOMEM;
+
+#ifdef CONFIG_INET_GSO
+ dev->features |= NETIF_F_GSO;
+#endif /* CONFIG_INET_GSO */
rtnl_lock();
if (strchr(dev->name, '%')) {
@@ -300,6 +311,16 @@ int br_add_bridge(const char *name)
if (ret)
goto out;
+#ifdef HNDCTF
+ if ((ctf_dev_register(kcih, dev, TRUE) != BCME_OK) ||
+ (ctf_enable(kcih, dev, TRUE, NULL) != BCME_OK)) {
+ ctf_dev_unregister(kcih, dev);
+ unregister_netdevice(dev);
+ ret = -ENXIO;
+ goto out;
+ }
+#endif /* HNDCTF */
+
ret = br_sysfs_addbr(dev);
if (ret)
unregister_netdevice(dev);
@@ -328,8 +349,12 @@ int br_del_bridge(const char *name)
ret = -EBUSY;
}
- else
+ else {
+#ifdef HNDCTF
+ ctf_dev_unregister(kcih, dev);
+#endif /* HNDCTF */
del_br(netdev_priv(dev));
+ }
rtnl_unlock();
return ret;
diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c
index 33c6c4a..36520a2 100644
--- a/net/bridge/br_sysfs_br.c
+++ b/net/bridge/br_sysfs_br.c
@@ -327,6 +327,46 @@ static ssize_t store_flush(struct device *d,
}
static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush);
+#ifdef CONFIG_INET_GSO
+static ssize_t show_gso(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct net_bridge *br = to_bridge(d);
+ struct net_device *gso_dev = br->dev;
+
+ if ((br->feature_mask & NETIF_F_GSO) && (gso_dev->features & NETIF_F_GSO))
+ printk("%s: gso on\n", br->dev->name);
+ else
+ printk("%s: gso off\n", br->dev->name);
+ return len;
+}
+
+static ssize_t store_gso(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct net_bridge *br = to_bridge(d);
+ struct net_device *gso_dev = br->dev;
+
+ if (!strncmp(buf, "on", 2)) {
+ br->feature_mask |= NETIF_F_GSO;
+ gso_dev->features |= NETIF_F_GSO;
+ printk("%s: gso on\n", br->dev->name);
+ }
+ else if (!strncmp(buf, "off", 3)) {
+ br->feature_mask &= ~NETIF_F_GSO;
+ gso_dev->features &= ~NETIF_F_GSO;
+ printk("%s: gso off\n", br->dev->name);
+ }
+ else
+ printk("%s: invalid argument\n", br->dev->name);
+
+ return len;
+}
+static DEVICE_ATTR(gso, S_IRUGO | S_IWUSR, show_gso, store_gso);
+#endif /* CONFIG_INET_GSO */
+
static struct attribute *bridge_attrs[] = {
&dev_attr_forward_delay.attr,
&dev_attr_hello_time.attr,
@@ -346,6 +386,9 @@ static struct attribute *bridge_attrs[] = {
&dev_attr_gc_timer.attr,
&dev_attr_group_addr.attr,
&dev_attr_flush.attr,
+#ifdef CONFIG_INET_GSO
+ &dev_attr_gso.attr,
+#endif /* CONFIG_INET_GSO */
NULL
};
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index ea02f00..05e6ee6 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -31,12 +31,19 @@
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
+#include <linux/netfilter_ipv4/ipt_cone.h>
+
+#ifdef HNDCTF
+#include <linux/if.h>
+#include <linux/if_vlan.h>
+#include <typedefs.h>
+#include <osl.h>
+#include <ctf/hndctf.h>
+
+#define NFC_CTF_ENABLED (1 << 31)
+#endif /* HNDCTF */
-#if 0
-#define DEBUGP printk
-#else
#define DEBUGP(format, args...)
-#endif
static DEFINE_RWLOCK(nf_nat_lock);
@@ -87,6 +94,12 @@ hash_by_src(const struct nf_conntrack_tuple *tuple)
tuple->dst.protonum, 0) % nf_nat_htable_size;
}
+#ifdef HNDCTF
+extern void ip_conntrack_ipct_add(struct sk_buff *skb, u_int32_t hooknum,
+ struct nf_conn *ct, enum ip_conntrack_info ci,
+ struct nf_conntrack_tuple *manip);
+#endif /* HNDCTF */
+
/* Noone using conntrack by the time this called. */
static void nf_nat_cleanup_conntrack(struct nf_conn *conn)
{
@@ -98,6 +111,9 @@ static void nf_nat_cleanup_conntrack(struct nf_conn *conn)
write_lock_bh(&nf_nat_lock);
list_del(&nat->info.bysource);
write_unlock_bh(&nf_nat_lock);
+
+ /* Detach from cone list */
+ ipt_cone_cleanup_conntrack(nat);
}
/* Is this tuple already taken? (not by us) */
@@ -113,6 +129,7 @@ nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple,
struct nf_conntrack_tuple reply;
nf_ct_invert_tuplepr(&reply, tuple);
+
return nf_conntrack_tuple_taken(&reply, ignored_conntrack);
}
EXPORT_SYMBOL(nf_nat_used_tuple);
@@ -411,10 +428,16 @@ unsigned int nf_nat_packet(struct nf_conn *ct,
/* We are aiming to look like inverse of other direction. */
nf_ct_invert_tuplepr(&target, &ct->tuplehash[!dir].tuple);
-
+#ifdef HNDCTF
+ ip_conntrack_ipct_add(*pskb, hooknum, ct, ctinfo, &target);
+#endif /* HNDCTF */
if (!manip_pkt(target.dst.protonum, pskb, 0, &target, mtype))
return NF_DROP;
+ } else {
+#ifdef HNDCTF
+#endif /* HNDCTF */
}
+
return NF_ACCEPT;
}
EXPORT_SYMBOL_GPL(nf_nat_packet);
@@ -615,7 +638,6 @@ static int __init nf_nat_init(void)
INIT_LIST_HEAD(&bysource[i]);
}
- /* FIXME: Man, this is a hack. <SIGH> */
NF_CT_ASSERT(rcu_dereference(nf_conntrack_destroyed) == NULL);
rcu_assign_pointer(nf_conntrack_destroyed, nf_nat_cleanup_conntrack);
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 1b1797f..b51b7d6 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -26,11 +26,7 @@
#include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_core.h>
-#if 0
-#define DEBUGP printk
-#else
#define DEBUGP(format, args...)
-#endif
static int ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff,
struct nf_conntrack_tuple *tuple)
@@ -230,13 +226,12 @@ static unsigned int ipv6_conntrack_in(unsigned int hooknum,
int (*okfn)(struct sk_buff *))
{
struct sk_buff *reasm = (*pskb)->nfct_reasm;
+ unsigned int ret;
/* This packet is fragmented and has reassembled packet. */
if (reasm) {
/* Reassembled packet isn't parsed yet ? */
if (!reasm->nfct) {
- unsigned int ret;
-
ret = nf_conntrack_in(PF_INET6, hooknum, &reasm);
if (ret != NF_ACCEPT)
return ret;
@@ -247,7 +242,19 @@ static unsigned int ipv6_conntrack_in(unsigned int hooknum,
return NF_ACCEPT;
}
- return nf_conntrack_in(PF_INET6, hooknum, pskb);
+ ret = nf_conntrack_in(PF_INET6, hooknum, pskb);
+
+#if defined(HNDCTF)
+ if (ret == NF_ACCEPT) {
+ struct nf_conn *ct;
+ enum ip_conntrack_info ctinfo;
+
+ ct = nf_ct_get(*pskb, &ctinfo);
+ ip_conntrack_ipct_add(*pskb, hooknum, ct, ctinfo, NULL);
+ }
+#endif /* HNDCTF */
+
+ return ret;
}
static unsigned int ipv6_conntrack_local(unsigned int hooknum,
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 7a15e30..70cf589 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -39,11 +39,32 @@
#define NF_CONNTRACK_VERSION "0.5.0"
-#if 0
-#define DEBUGP printk
+#ifdef HNDCTF
+#include <linux/if.h>
+#include <linux/if_vlan.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+
+#ifdef CONFIG_IPV6
+#include <linux/ipv6.h>
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#define IPVERSION_IS_4(ipver) ((ipver) == 4)
#else
+#define IPVERSION_IS_4(ipver) 1
+#endif /* CONFIG_IPV6 */
+
+#include <net/ip.h>
+#include <net/route.h>
+#include <typedefs.h>
+#include <osl.h>
+#include <ctf/hndctf.h>
+
+#define NFC_CTF_ENABLED (1 << 31)
+#endif /* HNDCTF */
+
#define DEBUGP(format, args...)
-#endif
DEFINE_RWLOCK(nf_conntrack_lock);
EXPORT_SYMBOL_GPL(nf_conntrack_lock);
@@ -76,6 +97,348 @@ static unsigned int nf_conntrack_next_id;
DEFINE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat);
EXPORT_PER_CPU_SYMBOL(nf_conntrack_stat);
+#ifdef HNDCTF
+bool
+ip_conntrack_is_ipc_allowed(struct sk_buff *skb, u_int32_t hooknum)
+{
+ struct net_device *dev;
+
+ if (!CTF_ENAB(kcih))
+ return FALSE;
+
+ if (hooknum == NF_IP_PRE_ROUTING || hooknum == NF_IP_POST_ROUTING) {
+ dev = skb->dev;
+ if (dev->priv_flags & IFF_802_1Q_VLAN)
+ dev = VLAN_DEV_INFO(dev)->real_dev;
+
+ /* Add ipc entry if packet is received on ctf enabled interface
+ * and the packet is not a defrag'd one.
+ */
+ if (ctf_isenabled(kcih, dev) && (skb->len <= dev->mtu))
+ skb->nfcache |= NFC_CTF_ENABLED;
+ }
+
+ /* Add the cache entries only if the device has registered and
+ * enabled ctf.
+ */
+ if (skb->nfcache & NFC_CTF_ENABLED)
+ return TRUE;
+
+ return FALSE;
+}
+
+void
+ip_conntrack_ipct_add(struct sk_buff *skb, u_int32_t hooknum,
+ struct nf_conn *ct, enum ip_conntrack_info ci,
+ struct nf_conntrack_tuple *manip)
+{
+ ctf_ipc_t ipc_entry;
+ struct hh_cache *hh;
+ struct ethhdr *eth;
+ struct iphdr *iph;
+ struct tcphdr *tcph;
+ struct rtable *rt;
+ struct nf_conn_help *help;
+ enum ip_conntrack_dir dir;
+ uint8 ipver, protocol;
+#ifdef CONFIG_IPV6
+ struct ipv6hdr *ip6h = NULL;
+#endif /* CONFIG_IPV6 */
+
+ if ((skb == NULL) || (ct == NULL))
+ return;
+
+ /* Check CTF enabled */
+ if (!ip_conntrack_is_ipc_allowed(skb, hooknum))
+ return;
+ /* We only add cache entires for non-helper connections and at
+ * pre or post routing hooks.
+ */
+ help = nfct_help(ct);
+ if ((help && help->helper) || (ct->ctf_flags & CTF_FLAGS_EXCLUDED) ||
+ ((hooknum != NF_IP_PRE_ROUTING) && (hooknum != NF_IP_POST_ROUTING)))
+ return;
+
+ iph = ip_hdr(skb);
+ ipver = iph->version;
+
+ /* Support both IPv4 and IPv6 */
+ if (ipver == 4) {
+ tcph = ((struct tcphdr *)(((__u8 *)iph) + (iph->ihl << 2)));
+ protocol = iph->protocol;
+ }
+#ifdef CONFIG_IPV6
+ else if (ipver == 6) {
+ ip6h = (struct ipv6hdr *)iph;
+ tcph = (struct tcphdr *)ctf_ipc_lkup_l4proto(kcih, ip6h, &protocol);
+ if (tcph == NULL)
+ return;
+ }
+#endif /* CONFIG_IPV6 */
+ else
+ return;
+
+ /* Only TCP and UDP are supported */
+ if (protocol == IPPROTO_TCP) {
+ /* Add ipc entries for connections in established state only */
+ if ((ci != IP_CT_ESTABLISHED) && (ci != (IP_CT_ESTABLISHED+IP_CT_IS_REPLY)))
+ return;
+
+ if (ct->proto.tcp.state >= TCP_CONNTRACK_FIN_WAIT &&
+ ct->proto.tcp.state <= TCP_CONNTRACK_TIME_WAIT)
+ return;
+ }
+ else if (protocol != IPPROTO_UDP)
+ return;
+
+ dir = CTINFO2DIR(ci);
+ if (ct->ctf_flags & (1 << dir))
+ return;
+
+ /* Do route lookup for alias address if we are doing DNAT in this
+ * direction.
+ */
+ if (skb->dst == NULL) {
+ /* Find the destination interface */
+ if (IPVERSION_IS_4(ipver)) {
+ u_int32_t daddr;
+
+ if ((manip != NULL) && (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST))
+ daddr = manip->dst.u3.ip;
+ else
+ daddr = iph->daddr;
+ ip_route_input(skb, daddr, iph->saddr, iph->tos, skb->dev);
+ }
+#ifdef CONFIG_IPV6
+ else
+ ip6_route_input(skb);
+#endif /* CONFIG_IPV6 */
+ }
+
+ /* Ensure the packet belongs to a forwarding connection and it is
+ * destined to an unicast address.
+ */
+ rt = (struct rtable *)skb->dst;
+ if ((rt == NULL) || (
+#ifdef CONFIG_IPV6
+ !IPVERSION_IS_4(ipver) ?
+ ((rt->u.dst.input != ip6_forward) ||
+ !(ipv6_addr_type(&ip6h->daddr) & IPV6_ADDR_UNICAST)) :
+#endif /* CONFIG_IPV6 */
+ ((rt->u.dst.input != ip_forward) || (rt->rt_type != RTN_UNICAST))) ||
+ (rt->u.dst.neighbour == NULL) ||
+ ((rt->u.dst.neighbour->nud_state &
+ (NUD_PERMANENT|NUD_REACHABLE|NUD_STALE|NUD_DELAY|NUD_PROBE)) == 0))
+ return;
+
+ memset(&ipc_entry, 0, sizeof(ipc_entry));
+
+ /* Init the neighboring sender address */
+ memcpy(ipc_entry.sa.octet, eth_hdr(skb)->h_source, ETH_ALEN);
+
+ /* If the packet is received on a bridge device then save
+ * the bridge cache entry pointer in the ip cache entry.
+ * This will be referenced in the data path to update the
+ * live counter of brc entry whenever a received packet
+ * matches corresponding ipc entry matches.
+ */
+ if ((skb->dev != NULL) && ctf_isbridge(kcih, skb->dev))
+ ipc_entry.brcp = ctf_brc_lkup(kcih, eth_hdr(skb)->h_source);
+
+ hh = skb->dst->hh;
+ if (hh != NULL) {
+ eth = (struct ethhdr *)(((unsigned char *)hh->hh_data) + 2);
+ memcpy(ipc_entry.dhost.octet, eth->h_dest, ETH_ALEN);
+ memcpy(ipc_entry.shost.octet, eth->h_source, ETH_ALEN);
+ } else {
+ memcpy(ipc_entry.dhost.octet, rt->u.dst.neighbour->ha, ETH_ALEN);
+ memcpy(ipc_entry.shost.octet, skb->dst->dev->dev_addr, ETH_ALEN);
+ }
+
+ /* Add ctf ipc entry for this direction */
+ if (IPVERSION_IS_4(ipver)) {
+ ipc_entry.tuple.sip[0] = iph->saddr;
+ ipc_entry.tuple.dip[0] = iph->daddr;
+#ifdef CONFIG_IPV6
+ } else {
+ memcpy(ipc_entry.tuple.sip, &ip6h->saddr, sizeof(ipc_entry.tuple.sip));
+ memcpy(ipc_entry.tuple.dip, &ip6h->daddr, sizeof(ipc_entry.tuple.dip));
+#endif /* CONFIG_IPV6 */
+ }
+ ipc_entry.tuple.proto = protocol;
+ ipc_entry.tuple.sp = tcph->source;
+ ipc_entry.tuple.dp = tcph->dest;
+
+ ipc_entry.next = NULL;
+
+ /* For vlan interfaces fill the vlan id and the tag/untag actions */
+ if (skb->dst->dev->priv_flags & IFF_802_1Q_VLAN) {
+ ipc_entry.txif = (void *)(VLAN_DEV_INFO(skb->dst->dev)->real_dev);
+ ipc_entry.vid = VLAN_DEV_INFO(skb->dst->dev)->vlan_id;
+ ipc_entry.action = ((VLAN_DEV_INFO(skb->dst->dev)->flags & 1) ?
+ CTF_ACTION_TAG : CTF_ACTION_UNTAG);
+ } else {
+ ipc_entry.txif = skb->dst->dev;
+ ipc_entry.action = CTF_ACTION_UNTAG;
+ }
+
+ /* Update the manip ip and port */
+ if (manip != NULL) {
+ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) {
+ ipc_entry.nat.ip = manip->src.u3.ip;
+ ipc_entry.nat.port = manip->src.u.tcp.port;
+ ipc_entry.action |= CTF_ACTION_SNAT;
+ } else {
+ ipc_entry.nat.ip = manip->dst.u3.ip;
+ ipc_entry.nat.port = manip->dst.u.tcp.port;
+ ipc_entry.action |= CTF_ACTION_DNAT;
+ }
+ }
+
+ /* Do bridge cache lookup to determine outgoing interface
+ * and any vlan tagging actions if needed.
+ */
+ if (ctf_isbridge(kcih, ipc_entry.txif)) {
+ ctf_brc_t *brcp;
+
+ brcp = ctf_brc_lkup(kcih, ipc_entry.dhost.octet);
+
+ if (brcp == NULL)
+ return;
+ else {
+ ipc_entry.action |= brcp->action;
+ ipc_entry.txif = brcp->txifp;
+ ipc_entry.vid = brcp->vid;
+ }
+ }
+
+#ifdef DEBUG
+ if (IPVERSION_IS_4(ipver))
+ printk("%s: Adding ipc entry for [%d]%u.%u.%u.%u:%u - %u.%u.%u.%u:%u\n", __FUNCTION__,
+ ipc_entry.tuple.proto,
+ NIPQUAD(ipc_entry.tuple.sip[0]), ntohs(ipc_entry.tuple.sp),
+ NIPQUAD(ipc_entry.tuple.dip[0]), ntohs(ipc_entry.tuple.dp));
+#ifdef CONFIG_IPV6
+ else
+ printk("\n%s: Adding ipc entry for [%d]\n"
+ "%08x.%08x.%08x.%08x:%u => %08x.%08x.%08x.%08x:%u\n",
+ __FUNCTION__, ipc_entry.tuple.proto,
+ ntohl(ipc_entry.tuple.sip[0]), ntohl(ipc_entry.tuple.sip[1]),
+ ntohl(ipc_entry.tuple.sip[2]), ntohl(ipc_entry.tuple.sip[3]),
+ ntohs(ipc_entry.tuple.sp),
+ ntohl(ipc_entry.tuple.dip[0]), ntohl(ipc_entry.tuple.dip[1]),
+ ntohl(ipc_entry.tuple.dip[2]), ntohl(ipc_entry.tuple.dip[3]),
+ ntohs(ipc_entry.tuple.dp));
+#endif /* CONFIG_IPV6 */
+ printk("sa %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ipc_entry.shost.octet[0], ipc_entry.shost.octet[1],
+ ipc_entry.shost.octet[2], ipc_entry.shost.octet[3],
+ ipc_entry.shost.octet[4], ipc_entry.shost.octet[5]);
+ printk("da %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ipc_entry.dhost.octet[0], ipc_entry.dhost.octet[1],
+ ipc_entry.dhost.octet[2], ipc_entry.dhost.octet[3],
+ ipc_entry.dhost.octet[4], ipc_entry.dhost.octet[5]);
+ printk("[%d] vid: %d action %x\n", hooknum, ipc_entry.vid, ipc_entry.action);
+ if (manip != NULL)
+ printk("manip_ip: %u.%u.%u.%u manip_port %u\n",
+ NIPQUAD(ipc_entry.nat.ip), ntohs(ipc_entry.nat.port));
+ printk("txif: %s\n", ((struct net_device *)ipc_entry.txif)->name);
+#endif
+
+ ctf_ipc_add(kcih, &ipc_entry, !IPVERSION_IS_4(ipver));
+
+ /* Update the attributes flag to indicate a CTF conn */
+ ct->ctf_flags |= (CTF_FLAGS_CACHED | (1 << dir));
+}
+
+int
+ip_conntrack_ipct_delete(struct nf_conn *ct, int ct_timeout)
+{
+ ctf_ipc_t *ipct;
+ struct nf_conntrack_tuple *orig, *repl;
+ ctf_ipc_t orig_ipct, repl_ipct;
+ int ipaddr_sz;
+ bool v6;
+
+ if (!CTF_ENAB(kcih))
+ return (0);
+
+ orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
+
+ if ((orig->dst.protonum != IPPROTO_TCP) && (orig->dst.protonum != IPPROTO_UDP))
+ return (0);
+
+ repl = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
+
+#ifdef CONFIG_IPV6
+ v6 = (orig->src.l3num == AF_INET6);
+ ipaddr_sz = (v6) ? sizeof(struct in6_addr) : sizeof(struct in_addr);
+#else
+ v6 = FALSE;
+ ipaddr_sz = sizeof(struct in_addr);
+#endif /* CONFIG_IPV6 */
+
+ memset(&orig_ipct, 0, sizeof(orig_ipct));
+ memcpy(orig_ipct.tuple.sip, &orig->src.u3.ip, ipaddr_sz);
+ memcpy(orig_ipct.tuple.dip, &orig->dst.u3.ip, ipaddr_sz);
+ orig_ipct.tuple.proto = orig->dst.protonum;
+ orig_ipct.tuple.sp = orig->src.u.tcp.port;
+ orig_ipct.tuple.dp = orig->dst.u.tcp.port;
+
+ memset(&repl_ipct, 0, sizeof(repl_ipct));
+ memcpy(repl_ipct.tuple.sip, &repl->src.u3.ip, ipaddr_sz);
+ memcpy(repl_ipct.tuple.dip, &repl->dst.u3.ip, ipaddr_sz);
+ repl_ipct.tuple.proto = repl->dst.protonum;
+ repl_ipct.tuple.sp = repl->src.u.tcp.port;
+ repl_ipct.tuple.dp = repl->dst.u.tcp.port;
+
+ /* If the refresh counter of ipc entry is non zero, it indicates
+ * that the packet transfer is active and we should not delete
+ * the conntrack entry.
+ */
+ if (ct_timeout) {
+ ipct = ctf_ipc_lkup(kcih, &orig_ipct, v6);
+
+ /* Postpone the deletion of ct entry if there are frames
+ * flowing in this direction.
+ */
+ if ((ipct != NULL) && (ipct->live > 0)) {
+ ipct->live = 0;
+ ct->timeout.expires = jiffies + ct->expire_jiffies;
+ add_timer(&ct->timeout);
+ return (-1);
+ }
+
+ ipct = ctf_ipc_lkup(kcih, &repl_ipct, v6);
+
+ if ((ipct != NULL) && (ipct->live > 0)) {
+ ipct->live = 0;
+ ct->timeout.expires = jiffies + ct->expire_jiffies;
+ add_timer(&ct->timeout);
+ return (-1);
+ }
+ }
+
+ /* If there are no packets over this connection for timeout period
+ * delete the entries.
+ */
+ ctf_ipc_delete(kcih, &orig_ipct, v6);
+
+ ctf_ipc_delete(kcih, &repl_ipct, v6);
+
+#ifdef DEBUG
+ printk("%s: Deleting the tuple %x %x %d %d %d\n",
+ __FUNCTION__, orig->src.u3.ip, orig->dst.u3.ip, orig->dst.protonum,
+ orig->src.u.tcp.port, orig->dst.u.tcp.port);
+ printk("%s: Deleting the tuple %x %x %d %d %d\n",
+ __FUNCTION__, repl->dst.u3.ip, repl->src.u3.ip, repl->dst.protonum,
+ repl->dst.u.tcp.port, repl->src.u.tcp.port);
+#endif
+
+ return (0);
+}
+#endif /* HNDCTF */
+
/*
* This scheme offers various size of "struct nf_conn" dependent on
* features(helper, nat, ...)
@@ -206,7 +569,6 @@ out_up_mutex:
}
EXPORT_SYMBOL_GPL(nf_conntrack_register_cache);
-/* FIXME: In the current, only nf_conntrack_cleanup() can call this function. */
void nf_conntrack_unregister_cache(u_int32_t features)
{
struct kmem_cache *cachep;
@@ -272,10 +634,10 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
{
NF_CT_TUPLE_U_BLANK(inverse);
- inverse->src.l3num = orig->src.l3num;
if (l3proto->invert_tuple(inverse, orig) == 0)
return 0;
+ inverse->src.l3num = orig->src.l3num;
inverse->dst.dir = !orig->dst.dir;
inverse->dst.protonum = orig->dst.protonum;
@@ -305,6 +667,10 @@ destroy_conntrack(struct nf_conntrack *nfct)
NF_CT_ASSERT(atomic_read(&nfct->use) == 0);
NF_CT_ASSERT(!timer_pending(&ct->timeout));
+#ifdef HNDCTF
+ ip_conntrack_ipct_delete(ct, 0);
+#endif /* HNDCTF*/
+
nf_conntrack_event(IPCT_DESTROY, ct);
set_bit(IPS_DYING_BIT, &ct->status);
@@ -352,6 +718,14 @@ static void death_by_timeout(unsigned long ul_conntrack)
struct nf_conn_help *help = nfct_help(ct);
struct nf_conntrack_helper *helper;
+#ifdef HNDCTF
+ /* If negative error is returned it means the entry hasn't
+ * timed out yet.
+ */
+ if (ip_conntrack_ipct_delete(ct, jiffies >= ct->timeout.expires ? 1 : 0) != 0)
+ return;
+#endif /* HNDCTF */
+
if (help) {
rcu_read_lock();
helper = rcu_dereference(help->helper);
@@ -547,6 +921,10 @@ static int early_drop(struct list_head *chain)
if (!ct)
return dropped;
+#ifdef HNDCTF
+ ip_conntrack_ipct_delete(ct, 0);
+#endif /* HNDCTF */
+
if (del_timer(&ct->timeout)) {
death_by_timeout((unsigned long)ct);
dropped = 1;
@@ -590,7 +968,6 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig,
/* find features needed by this conntrack. */
features |= l3proto->get_features(orig);
- /* FIXME: protect helper list per RCU */
read_lock_bh(&nf_conntrack_lock);
helper = __nf_ct_helper_find(repl);
/* NAT might want to assign a helper later */
@@ -931,6 +1308,9 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
/* If not in hash table, timer will not be active yet */
if (!nf_ct_is_confirmed(ct)) {
+#ifdef HNDCTF
+ ct->expire_jiffies = extra_jiffies;
+#endif /* HNDCTF */
ct->timeout.expires = extra_jiffies;
event = IPCT_REFRESH;
} else {
@@ -941,6 +1321,9 @@ void __nf_ct_refresh_acct(struct nf_conn *ct,
avoidance (may already be dying). */
if (newtime - ct->timeout.expires >= HZ
&& del_timer(&ct->timeout)) {
+#ifdef HNDCTF
+ ct->expire_jiffies = extra_jiffies;
+#endif /* HNDCTF */
ct->timeout.expires = newtime;
add_timer(&ct->timeout);
event = IPCT_REFRESH;
@@ -1077,6 +1460,9 @@ nf_ct_iterate_cleanup(int (*iter)(struct nf_conn *i, void *data), void *data)
unsigned int bucket = 0;
while ((ct = get_next_corpse(iter, data, &bucket)) != NULL) {
+#ifdef HNDCTF
+ ip_conntrack_ipct_delete(ct, 0);
+#endif /* HNDCTF */
/* Time to push up daises... */
if (del_timer(&ct->timeout))
death_by_timeout((unsigned long)ct);
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index ccdd5d2..2652fe5 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -26,12 +26,12 @@
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_ecache.h>
-#if 0
-#define DEBUGP printk
-#define DEBUGP_VARS
-#else
#define DEBUGP(format, args...)
-#endif
+
+#ifdef HNDCTF
+#include <ctf/hndctf.h>
+extern int ip_conntrack_ipct_delete(struct nf_conn *ct, int ct_timeout);
+#endif /* HNDCTF */
/* Protects conntrack->proto.tcp */
static DEFINE_RWLOCK(tcp_lock);
@@ -50,8 +50,6 @@ static int nf_ct_tcp_loose __read_mostly = 1;
will be started. */
static int nf_ct_tcp_max_retrans __read_mostly = 3;
- /* FIXME: Examine ipfilter's timeouts and conntrack transitions more
- closely. They're more complex. --RR */
static const char *tcp_conntrack_names[] = {
"NONE",
@@ -364,13 +362,10 @@ static inline __u32 segment_seq_plus_len(__u32 seq,
unsigned int dataoff,
struct tcphdr *tcph)
{
- /* XXX Should I use payload length field in IP/IPv6 header ?
- * - YK */
return (seq + len - dataoff - tcph->doff*4
+ (tcph->syn ? 1 : 0) + (tcph->fin ? 1 : 0));
}
-/* Fixme: what about big packets? */
#define MAXACKWINCONST 66000
#define MAXACKWINDOW(sender) \
((sender)->td_maxwin > MAXACKWINCONST ? (sender)->td_maxwin \
@@ -792,7 +787,6 @@ static int tcp_error(struct sk_buff *skb,
* We skip checking packets on the outgoing path
* because the checksum is assumed to be correct.
*/
- /* FIXME: Source route IP option packets --RR */
if (nf_conntrack_checksum &&
((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
(pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) &&
@@ -933,6 +927,18 @@ static int tcp_packet(struct nf_conn *conntrack,
break;
}
+#ifdef HNDCTF
+ /* Remove the ipc entries on receipt of FIN or RST */
+ if (CTF_ENAB(kcih)) {
+ if (conntrack->ctf_flags & CTF_FLAGS_CACHED) {
+ if (th->fin || th->rst) {
+ ip_conntrack_ipct_delete(conntrack, 0);
+ }
+ goto in_window;
+ }
+ }
+#endif /* HNDCTF */
+
if (!tcp_in_window(&conntrack->proto.tcp, dir, index,
skb, dataoff, th, pf)) {
write_unlock_bh(&tcp_lock);
[-- Attachment #4: Type: text/plain, Size: 172 bytes --]
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
^ permalink raw reply related
* Re: [RFC] b44: use phylib
From: Hauke Mehrtens @ 2013-08-24 14:32 UTC (permalink / raw)
To: Joe Perches; +Cc: zambrano, netdev, Florian Fainelli
In-Reply-To: <1377299409.2816.19.camel@joe-AO722>
On 08/24/2013 01:10 AM, Joe Perches wrote:
> On Sat, 2013-08-24 at 00:56 +0200, Hauke Mehrtens wrote:
>> This splits the driver into the mac and a phy driver. On routers where
>> this driver is used we have a switch which implements a phy and can be
>> controlled by a phy driver.
>
> trivial comments only...
I will extend this.
>> diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
> []
>> +static void b44_adjust_link(struct net_device *dev)
>> +{
>> + struct b44 *bp = netdev_priv(dev);
>> + struct phy_device *phydev = bp->phydev;
>> + int status_changed = 0;
>
> bool?
Thanks, I will change this.
>> +static int b44_mii_probe(struct net_device *dev)
>> +{
> []
>> + if (IS_ERR(phydev)) {
>> + netdev_err(dev, "could not attach PHY: %s", phy_id);
>
> missing newline?
Fixed.
^ permalink raw reply
* [PATCH] USB2NET : SR9700 : One chip USB 1.1 USB2NET SR9700 Device Driver Support
From: liujunliang_ljl-9Onoh4P/yGk @ 2013-08-24 11:26 UTC (permalink / raw)
To: davem-fT/PcQaiUtIeIZ0/mPfg9Q
Cc: horms-/R6kz+dDXgpPR4JQBCEnsQ, joe-6d6DIl74uiNBDgjK7y7TUQ,
romieu-W8zweXLXuWQS+FvcfC7Uqw,
gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
netdev-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
sunhecheng-i49A8sVr+H5BDgjK7y7TUQ, liujl
From: liujl <liujunliang_ljl-9Onoh4P/yGk@public.gmane.org>
Signed-off-by: liujl <liujunliang_ljl-9Onoh4P/yGk@public.gmane.org>
---
drivers/net/usb/Kconfig | 8 +
drivers/net/usb/Makefile | 1 +
drivers/net/usb/sr9700.c | 551 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/usb/sr9700.h | 172 ++++++++++++++
4 files changed, 732 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/usb/sr9700.c
create mode 100644 drivers/net/usb/sr9700.h
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 287cc62..a94b196 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -272,6 +272,14 @@ config USB_NET_DM9601
This option adds support for Davicom DM9601 based USB 1.1
10/100 Ethernet adapters.
+config USB_NET_SR9700
+ tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices"
+ depends on USB_USBNET
+ select CRC32
+ help
+ This option adds support for CoreChip-sz SR9700 based USB 1.1
+ 10/100 Ethernet adapters.
+
config USB_NET_SMSC75XX
tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 9ab5c9d..bba87a2 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_AX88179_178A) += ax88179_178a.o
obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o
obj-$(CONFIG_USB_NET_DM9601) += dm9601.o
+obj-$(CONFIG_USB_NET_SR9700) += sr9700.o
obj-$(CONFIG_USB_NET_SMSC75XX) += smsc75xx.o
obj-$(CONFIG_USB_NET_SMSC95XX) += smsc95xx.o
obj-$(CONFIG_USB_NET_GL620A) += gl620a.o
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
new file mode 100644
index 0000000..27c86ec
--- /dev/null
+++ b/drivers/net/usb/sr9700.c
@@ -0,0 +1,551 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl-9Onoh4P/yGk@public.gmane.org>
+ *
+ * Based on dm9601.c
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/usbnet.h>
+
+#include "sr9700.h"
+
+static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+ int err;
+
+ err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG,
+ 0, reg, data, length);
+ if ((err != length) && (err >= 0))
+ err = -EINVAL;
+ return err;
+}
+
+static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+ int err;
+
+ err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+ 0, reg, data, length);
+ if ((err >= 0) && (err < length))
+ err = -EINVAL;
+ return err;
+}
+
+static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value)
+{
+ return sr_read(dev, reg, 1, value);
+}
+
+static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value)
+{
+ return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG,
+ value, reg, NULL, 0);
+}
+
+static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, void *data)
+{
+ usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+ 0, reg, data, length);
+}
+
+static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value)
+{
+ usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG,
+ value, reg, NULL, 0);
+}
+
+static int wait_phy_eeprom_ready(struct usbnet *dev, int phy)
+{
+ int i, ret;
+
+ ret = 0;
+ for (i = 0; i < SR_SHARE_TIMEOUT; i++) {
+ u8 tmp = 0;
+
+ udelay(1);
+ ret = sr_read_reg(dev, EPCR, &tmp);
+ if (ret < 0)
+ goto out;
+
+ /* ready */
+ if ((tmp & EPCR_ERRE) == 0)
+ break;
+ }
+
+ if (i >= SR_SHARE_TIMEOUT) {
+ netdev_err(dev->net, "%s write timed out!\n",
+ phy ? "phy" : "eeprom");
+ ret = -EIO;
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, __le16 *value)
+{
+ int ret;
+
+ mutex_lock(&dev->phy_mutex);
+
+ sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+ sr_write_reg(dev, EPCR, phy ? 0xc : 0x4);
+
+ ret = wait_phy_eeprom_ready(dev, phy);
+ if (ret < 0)
+ goto out;
+
+ sr_write_reg(dev, EPCR, 0x0);
+ ret = sr_read(dev, EPDR, 2, value);
+
+ netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
+ phy, reg, *value, ret);
+
+out:
+ mutex_unlock(&dev->phy_mutex);
+ return ret;
+}
+
+static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, __le16 value)
+{
+ int ret;
+
+ mutex_lock(&dev->phy_mutex);
+
+ ret = sr_write(dev, EPDR, 2, &value);
+ if (ret < 0)
+ goto out;
+
+ sr_write_reg(dev, EPAR, phy ? (reg | 0x40) : reg);
+ sr_write_reg(dev, EPCR, phy ? 0x1a : 0x12);
+
+ ret = wait_phy_eeprom_ready(dev, phy);
+ if (ret < 0)
+ goto out;
+
+ sr_write_reg(dev, EPCR, 0x0);
+
+out:
+ mutex_unlock(&dev->phy_mutex);
+ return ret;
+}
+
+static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value)
+{
+ return sr_share_read_word(dev, 0, offset, value);
+}
+
+static int sr9700_get_eeprom_len(struct net_device *dev)
+{
+ return SR_EEPROM_LEN;
+}
+
+static int sr9700_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct usbnet *dev = netdev_priv(net);
+ __le16 *ebuf = (__le16 *)data;
+ int ret = 0;
+ int i;
+
+ /* access is 16bit */
+ if ((eeprom->offset & 0x01) || (eeprom->len & 0x01))
+ return -EINVAL;
+
+ for (i = 0; i < eeprom->len / 2; i++)
+ ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, &ebuf[i]);
+
+ return ret;
+}
+
+static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
+{
+ struct usbnet *dev = netdev_priv(netdev);
+ __le16 res;
+ int rc = 0;
+
+ if (phy_id) {
+ netdev_dbg(dev->net, "Only internal phy supported\n");
+ return 0;
+ }
+
+ /* Access NSR_LINKST bit for link status instead of MII_BMSR */
+ if (loc == MII_BMSR) {
+ u8 value;
+
+ sr_read_reg(dev, NSR, &value);
+ if (value & NSR_LINKST)
+ rc = 1;
+ }
+ sr_share_read_word(dev, 1, loc, &res);
+ if (rc == 1)
+ res = le16_to_cpu(res) | BMSR_LSTATUS;
+ else
+ res = le16_to_cpu(res) & ~BMSR_LSTATUS;
+
+ netdev_dbg(dev->net, "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
+ phy_id, loc, res);
+
+ return res;
+}
+
+static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
+{
+ struct usbnet *dev = netdev_priv(netdev);
+ __le16 res = cpu_to_le16(val);
+
+ if (phy_id) {
+ netdev_dbg(dev->net, "Only internal phy supported\n");
+ return;
+ }
+
+ netdev_dbg(dev->net, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+ phy_id, loc, val);
+
+ sr_share_write_word(dev, 1, loc, res);
+}
+
+static u32 sr9700_get_link(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ u8 value = 0;
+ int rc = 0;
+
+ /* Get the Link Status directly */
+ sr_read_reg(dev, NSR, &value);
+ if (value & NSR_LINKST)
+ rc = 1;
+
+ return rc;
+}
+
+static int sr9700_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static const struct ethtool_ops sr9700_ethtool_ops = {
+ .get_drvinfo = usbnet_get_drvinfo,
+ .get_link = sr9700_get_link,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_eeprom_len = sr9700_get_eeprom_len,
+ .get_eeprom = sr9700_get_eeprom,
+ .get_settings = usbnet_get_settings,
+ .set_settings = usbnet_set_settings,
+ .nway_reset = usbnet_nway_reset,
+};
+
+static void sr9700_set_multicast(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ /* We use the 20 byte dev->data for our 8 byte filter buffer
+ * to avoid allocating memory that is tricky to free later
+ */
+ u8 *hashes = (u8 *)&dev->data;
+ /* rx_ctl setting : enable, disable_long, disable_crc */
+ u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG;
+
+ memset(hashes, 0x00, SR_MCAST_SIZE);
+ /* broadcast address */
+ hashes[SR_MCAST_SIZE - 1] |= SR_MCAST_ADDR_FLAG;
+ if (net->flags & IFF_PROMISC) {
+ rx_ctl |= RCR_PRMSC;
+ } else if (net->flags & IFF_ALLMULTI ||
+ netdev_mc_count(net) > SR_MCAST_MAX) {
+ rx_ctl |= RCR_RUNT;
+ } else if (!netdev_mc_empty(net)) {
+ struct netdev_hw_addr *ha;
+ netdev_for_each_mc_addr(ha, net) {
+ u32 crc = ether_crc(ETH_ALEN, ha->addr) >> 26;
+ hashes[crc >> 3] |= 1 << (crc & 0x7);
+ }
+ }
+
+ sr_write_async(dev, MAR, SR_MCAST_SIZE, hashes);
+ sr_write_reg_async(dev, RCR, rx_ctl);
+}
+
+static int sr9700_set_mac_address(struct net_device *net, void *p)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data)) {
+ netdev_err(net, "not setting invalid mac address %pM\n",
+ addr->sa_data);
+ return -EINVAL;
+ }
+
+ memcpy(net->dev_addr, addr->sa_data, net->addr_len);
+ sr_write_async(dev, PAR, 6, dev->net->dev_addr);
+
+ return 0;
+}
+
+static const struct net_device_ops sr9700_netdev_ops = {
+ .ndo_open = usbnet_open,
+ .ndo_stop = usbnet_stop,
+ .ndo_start_xmit = usbnet_start_xmit,
+ .ndo_tx_timeout = usbnet_tx_timeout,
+ .ndo_change_mtu = usbnet_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_do_ioctl = sr9700_ioctl,
+ .ndo_set_rx_mode = sr9700_set_multicast,
+ .ndo_set_mac_address = sr9700_set_mac_address,
+};
+
+static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ int ret;
+
+ ret = usbnet_get_endpoints(dev, intf);
+ if (ret)
+ goto out;
+
+ dev->net->netdev_ops = &sr9700_netdev_ops;
+ dev->net->ethtool_ops = &sr9700_ethtool_ops;
+ dev->net->hard_header_len += SR_TX_OVERHEAD;
+ dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
+ /* bulkin buffer is preferably not less than 3K */
+ dev->rx_urb_size = 3072;
+ dev->mii.dev = dev->net;
+ dev->mii.mdio_read = sr_mdio_read;
+ dev->mii.mdio_write = sr_mdio_write;
+ dev->mii.phy_id_mask = 0x1f;
+ dev->mii.reg_num_mask = 0x1f;
+
+ /* reset the sr9700 */
+ sr_write_reg(dev, NCR, 1);
+ udelay(20);
+
+ /* read MAC
+ * After Chip Power on, the Chip will reload the MAC from
+ * EEPROM automatically to PAR. In case there is no EEPROM externally,
+ * a default MAC address is stored in PAR for making chip work properly.
+ */
+ if (sr_read(dev, PAR, ETH_ALEN, dev->net->dev_addr) < 0) {
+ netdev_err(dev->net, "Error reading MAC address\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* power up and reset phy */
+ sr_write_reg(dev, PRR, 1);
+ /* at least 10ms, here 20ms for safe */
+ mdelay(20);
+ sr_write_reg(dev, PRR, 0);
+ /* at least 1ms, here 2ms for reading right register */
+ udelay(2 * 1000);
+
+ /* receive broadcast packets */
+ sr9700_set_multicast(dev->net);
+
+ sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+ sr_mdio_write(dev->net, dev->mii.phy_id,
+ MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+ mii_nway_restart(&dev->mii);
+
+out:
+ return ret;
+}
+
+static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ struct sk_buff *sr_skb;
+ int len;
+
+ /* skb content (packets) format :
+ * p0 p1 p2 ...... pm
+ * / \
+ * / \
+ * / \
+ * / \
+ * p0b0 p0b1 p0b2 p0b3 ...... p0b(n-4) p0b(n-3)...p0bn
+ *
+ * p0 : packet 0
+ * p0b0 : packet 0 byte 0
+ *
+ * b0: rx status
+ * b1: packet length (incl crc) low
+ * b2: packet length (incl crc) high
+ * b3..n-4: packet data
+ * bn-3..bn: ethernet packet crc
+ */
+ if (unlikely(skb->len < SR_RX_OVERHEAD)) {
+ netdev_err(dev->net, "unexpected tiny rx frame\n");
+ return 0;
+ }
+
+ /* one skb may contains multiple packets */
+ while (skb->len > SR_RX_OVERHEAD) {
+ if (skb->data[0] != 0x40)
+ return 0;
+
+ /* ignore the CRC length */
+ len = (skb->data[1] | (skb->data[2] << 8)) - 4;
+
+ if (len > ETH_FRAME_LEN)
+ return 0;
+
+ /* the last packet of current skb */
+ if (skb->len == (len + SR_RX_OVERHEAD)) {
+ skb_pull(skb, 3);
+ skb->len = len;
+ skb->tail = skb->data + len;
+ skb->truesize = len + sizeof(struct sk_buff);
+ return 2;
+ }
+
+ /* skb_clone is used for address align */
+ sr_skb = skb_clone(skb, GFP_ATOMIC);
+ if (!sr_skb)
+ return 0;
+
+ sr_skb->len = len;
+ sr_skb->data = skb->data + 3;
+ sr_skb->tail = skb->data + len;
+ sr_skb->truesize = len + sizeof(struct sk_buff);
+ usbnet_skb_return(dev, sr_skb);
+
+ skb_pull(skb, len + SR_RX_OVERHEAD);
+ };
+
+ return 0;
+}
+
+static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+ int len;
+
+ /* SR9700 can only send out one ethernet packet at once.
+ *
+ * b0 b1 b2 b3 ...... b(n-4) b(n-3)...bn
+ *
+ * b0: rx status
+ * b1: packet length (incl crc) low
+ * b2: packet length (incl crc) high
+ * b3..n-4: packet data
+ * bn-3..bn: ethernet packet crc
+ */
+
+ len = skb->len;
+
+ if (skb_headroom(skb) < SR_TX_OVERHEAD) {
+ struct sk_buff *skb2;
+
+ skb2 = skb_copy_expand(skb, SR_TX_OVERHEAD, 0, flags);
+ dev_kfree_skb_any(skb);
+ skb = skb2;
+ if (!skb)
+ return NULL;
+ }
+
+ __skb_push(skb, SR_TX_OVERHEAD);
+
+ /* usbnet adds padding if length is a multiple of packet size
+ * if so, adjust length value in header
+ */
+ if ((skb->len % dev->maxpacket) == 0)
+ len++;
+
+ skb->data[0] = len;
+ skb->data[1] = len >> 8;
+
+ return skb;
+}
+
+static void sr9700_status(struct usbnet *dev, struct urb *urb)
+{
+ int link;
+ u8 *buf;
+
+ /* format:
+ b0: net status
+ b1: tx status 1
+ b2: tx status 2
+ b3: rx status
+ b4: rx overflow
+ b5: rx count
+ b6: tx count
+ b7: gpr
+ */
+
+ if (urb->actual_length < 8)
+ return;
+
+ buf = urb->transfer_buffer;
+
+ link = !!(buf[0] & 0x40);
+ if (netif_carrier_ok(dev->net) != link) {
+ usbnet_link_change(dev, link, 1);
+ netdev_dbg(dev->net, "Link Status is: %d\n", link);
+ }
+}
+
+static int sr9700_link_reset(struct usbnet *dev)
+{
+ struct ethtool_cmd ecmd;
+
+ mii_check_media(&dev->mii, 1, 1);
+ mii_ethtool_gset(&dev->mii, &ecmd);
+
+ netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n",
+ ecmd.speed, ecmd.duplex);
+
+ return 0;
+}
+
+static const struct driver_info sr9700_driver_info = {
+ .description = "CoreChip SR9700 USB Ethernet",
+ .flags = FLAG_ETHER,
+ .bind = sr9700_bind,
+ .rx_fixup = sr9700_rx_fixup,
+ .tx_fixup = sr9700_tx_fixup,
+ .status = sr9700_status,
+ .link_reset = sr9700_link_reset,
+ .reset = sr9700_link_reset,
+};
+
+static const struct usb_device_id products[] = {
+ {
+ USB_DEVICE(0x0fe6, 0x9700), /* SR9700 device */
+ .driver_info = (unsigned long)&sr9700_driver_info,
+ },
+ {}, /* END */
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver sr9700_usb_driver = {
+ .name = "sr9700",
+ .id_table = products,
+ .probe = usbnet_probe,
+ .disconnect = usbnet_disconnect,
+ .suspend = usbnet_suspend,
+ .resume = usbnet_resume,
+ .disable_hub_initiated_lpm = 1,
+};
+
+module_usb_driver(sr9700_usb_driver);
+
+MODULE_AUTHOR("liujl <liujunliang_ljl-9Onoh4P/yGk@public.gmane.org>");
+MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h
new file mode 100644
index 0000000..f1968ae
--- /dev/null
+++ b/drivers/net/usb/sr9700.h
@@ -0,0 +1,172 @@
+/*
+ * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices
+ *
+ * Author : liujl <liujunliang_ljl-9Onoh4P/yGk@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _SR9700_H
+#define _SR9700_H
+
+/* sr9700 spec. register table on Linux platform */
+
+/* Network Control Reg */
+#define NCR 0x00
+#define NCR_RST (1 << 0)
+#define NCR_LBK (3 << 1)
+#define NCR_FDX (1 << 3)
+#define NCR_WAKEEN (1 << 6)
+/* Network Status Reg */
+#define NSR 0x01
+#define NSR_RXRDY (1 << 0)
+#define NSR_RXOV (1 << 1)
+#define NSR_TX1END (1 << 2)
+#define NSR_TX2END (1 << 3)
+#define NSR_TXFULL (1 << 4)
+#define NSR_WAKEST (1 << 5)
+#define NSR_LINKST (1 << 6)
+#define NSR_SPEED (1 << 7)
+/* Tx Control Reg */
+#define TCR 0x02
+#define TCR_CRC_DIS (1 << 1)
+#define TCR_PAD_DIS (1 << 2)
+#define TCR_LC_CARE (1 << 3)
+#define TCR_CRS_CARE (1 << 4)
+#define TCR_EXCECM (1 << 5)
+#define TCR_LF_EN (1 << 6)
+/* Tx Status Reg for Packet Index 1 */
+#define TSR1 0x03
+#define TSR1_EC (1 << 2)
+#define TSR1_COL (1 << 3)
+#define TSR1_LC (1 << 4)
+#define TSR1_NC (1 << 5)
+#define TSR1_LOC (1 << 6)
+#define TSR1_TLF (1 << 7)
+/* Tx Status Reg for Packet Index 2 */
+#define TSR2 0x04
+#define TSR2_EC (1 << 2)
+#define TSR2_COL (1 << 3)
+#define TSR2_LC (1 << 4)
+#define TSR2_NC (1 << 5)
+#define TSR2_LOC (1 << 6)
+#define TSR2_TLF (1 << 7)
+/* Rx Control Reg*/
+#define RCR 0x05
+#define RCR_RXEN (1 << 0)
+#define RCR_PRMSC (1 << 1)
+#define RCR_RUNT (1 << 2)
+#define RCR_ALL (1 << 3)
+#define RCR_DIS_CRC (1 << 4)
+#define RCR_DIS_LONG (1 << 5)
+/* Rx Status Reg */
+#define RSR 0x06
+#define RSR_AE (1 << 2)
+#define RSR_MF (1 << 6)
+#define RSR_RF (1 << 7)
+/* Rx Overflow Counter Reg */
+#define ROCR 0x07
+#define ROCR_ROC (0x7F << 0)
+#define ROCR_RXFU (1 << 7)
+/* Back Pressure Threshold Reg */
+#define BPTR 0x08
+#define BPTR_JPT (0x0F << 0)
+#define BPTR_BPHW (0x0F << 4)
+/* Flow Control Threshold Reg */
+#define FCTR 0x09
+#define FCTR_LWOT (0x0F << 0)
+#define FCTR_HWOT (0x0F << 4)
+/* rx/tx Flow Control Reg */
+#define FCR 0x0A
+#define FCR_FLCE (1 << 0)
+#define FCR_BKPA (1 << 4)
+#define FCR_TXPEN (1 << 5)
+#define FCR_TXPF (1 << 6)
+#define FCR_TXP0 (1 << 7)
+/* Eeprom & Phy Control Reg */
+#define EPCR 0x0B
+#define EPCR_ERRE (1 << 0)
+#define EPCR_ERPRW (1 << 1)
+#define EPCR_ERPRR (1 << 2)
+#define EPCR_EPOS (1 << 3)
+#define EPCR_WEP (1 << 4)
+/* Eeprom & Phy Address Reg */
+#define EPAR 0x0C
+#define EPAR_EROA (0x3F << 0)
+#define EPAR_PHY_ADR (0x03 << 6)
+/* Eeprom & Phy Data Reg */
+#define EPDR 0x0D /* 0x0D ~ 0x0E for Data Reg Low & High */
+/* Wakeup Control Reg */
+#define WCR 0x0F
+#define WCR_MAGICST (1 << 0)
+#define WCR_LINKST (1 << 2)
+#define WCR_MAGICEN (1 << 3)
+#define WCR_LINKEN (1 << 5)
+/* Physical Address Reg */
+#define PAR 0x10 /* 0x10 ~ 0x15 6 bytes for PAR */
+/* Multicast Address Reg */
+#define MAR 0x16 /* 0x16 ~ 0x1D 8 bytes for MAR */
+/* 0x1e unused */
+/* Phy Reset Reg */
+#define PRR 0x1F
+#define PRR_PHY_RST (1 << 0)
+/* Tx sdram Write Pointer Address Low */
+#define TWPAL 0x20
+/* Tx sdram Write Pointer Address High */
+#define TWPAH 0x21
+/* Tx sdram Read Pointer Address Low */
+#define TRPAL 0x22
+/* Tx sdram Read Pointer Address High */
+#define TRPAH 0x23
+/* Rx sdram Write Pointer Address Low */
+#define RWPAL 0x24
+/* Rx sdram Write Pointer Address High */
+#define RWPAH 0x25
+/* Rx sdram Read Pointer Address Low */
+#define RRPAL 0x26
+/* Rx sdram Read Pointer Address High */
+#define RRPAH 0x27
+/* Vendor ID register */
+#define VID 0x28 /* 0x28 ~ 0x29 2 bytes for VID */
+/* Product ID register */
+#define PID 0x2A /* 0x2A ~ 0x2B 2 bytes for PID */
+/* CHIP Revision register */
+#define CHIPR 0x2C
+/* 0x2D --> 0xEF unused */
+/* USB Device Address */
+#define USBDA 0xF0
+#define USBDA_USBFA (0x7F << 0)
+/* RX packet Counter Reg */
+#define RXC 0xF1
+/* Tx packet Counter & USB Status Reg */
+#define TXC_USBS 0xF2
+#define TXC_USBS_TXC0 (1 << 0)
+#define TXC_USBS_TXC1 (1 << 1)
+#define TXC_USBS_TXC2 (1 << 2)
+#define TXC_USBS_EP1RDY (1 << 5)
+#define TXC_USBS_SUSFLAG (1 << 6)
+#define TXC_USBS_RXFAULT (1 << 7)
+/* USB Control register */
+#define USBC 0xF4
+#define USBC_EP3NAK (1 << 4)
+#define USBC_EP3ACK (1 << 5)
+
+/* Register access commands and flags */
+#define SR_RD_REGS 0x00
+#define SR_WR_REGS 0x01
+#define SR_WR_REG 0x03
+#define SR_REQ_RD_REG (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+#define SR_REQ_WR_REG (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+
+/* parameters */
+#define SR_SHARE_TIMEOUT 1000
+#define SR_EEPROM_LEN 256
+#define SR_MCAST_SIZE 8
+#define SR_MCAST_ADDR_FLAG 0x80
+#define SR_MCAST_MAX 64
+#define SR_TX_OVERHEAD 2 /* 2bytes header */
+#define SR_RX_OVERHEAD 7 /* 3bytes header + 4crc tail */
+
+#endif /* _SR9700_H */
--
1.7.0.4
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [net-next v2 2/8] i40e: transmit, receive, and napi
From: Stefan Assmann @ 2013-08-24 9:31 UTC (permalink / raw)
To: David Miller
Cc: jeffrey.t.kirsher, jesse.brandeburg, netdev, gospo,
shannon.nelson, peter.p.waskiewicz.jr, e1000-devel
In-Reply-To: <20130823.110415.1251655571740007987.davem@davemloft.net>
On 23.08.2013 20:04, David Miller wrote:
> From: Stefan Assmann <sassmann@kpanic.de>
> Date: Fri, 23 Aug 2013 14:42:07 +0200
>
>> On 23.08.2013 04:15, Jeff Kirsher wrote:
>>> From: Jesse Brandeburg <jesse.brandeburg@intel.com>
>>>
>>> This patch contains the transmit, receive, and napi routines, as well
>>> as ancillary routines.
>>>
>>> This file is code that is (will be) shared between the VF and PF
>>> drivers.
>>
>> Just some small nitpicks.
>>
>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
>>> new file mode 100644
>>> index 0000000..ceafef0
>>> --- /dev/null
>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
>>
>> [...]
>>
>>> +static void i40e_receive_skb(struct i40e_ring *rx_ring,
>>> + struct sk_buff *skb, u16 vlan_tag)
>>> +{
>>> + struct i40e_vsi *vsi = rx_ring->vsi;
>>> + struct i40e_q_vector *q_vector = rx_ring->q_vector;
>>> + u64 flags = vsi->back->flags;
>>> +
>>> + if (vlan_tag & VLAN_VID_MASK)
>>> + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
>>
>> Suggesting __constant_htons instead of htons here.
>
> We don't suggest that anymore, because it's completely unnecessary
> with the way the macros are implemented.
>
Okay, good to know. I see it being used frequently in igb, ixgbe so my
assumption was it's the way to go.
Stefan
^ permalink raw reply
* Re: sendto() bug?
From: Julian Anastasov @ 2013-08-24 8:35 UTC (permalink / raw)
To: Chris Clark; +Cc: davem, netdev
In-Reply-To: <alpine.DEB.2.02.1308231257140.10771@optio.utah.ind.alcatel.com>
Hello,
On Fri, 23 Aug 2013, Chris Clark wrote:
> In the same vein as 2ad5b9e4, I'm soliciting feedback on something
> similar for raw_sendmsg():
>
> =================================================================
> diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
> index dd44e0a..454d9c1 100644
> --- a/net/ipv4/raw.c
> +++ b/net/ipv4/raw.c
> @@ -571,7 +571,9 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
> flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
> RT_SCOPE_UNIVERSE,
> inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
> - inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP,
> + inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP
> + | ((msg->msg_namelen
> + && (tos & RTO_ONLINK)) ? FLOWI_FLAG_KNOWN_NH : 0),
> daddr, saddr, 0, 0);
>
> if (!inet->hdrincl) {
> =================================================================
>
> The thought here is to apply the FLOWI_FLAG_KNOWN_NH flag when:
> (a) The dest_addr is given explicitly (msg->msg_namelen), and
> (b) The socket is in MSG_DONTROUTE mode (tos & RTO_ONLINK).
IMHO, FLOWI_FLAG_KNOWN_NH should be set only
for the inet->hdrincl case, otherwise it is set from
routing result: ip_push_pending_frames -> ip_finish_skb ->
__ip_make_skb -> ip_copy_addrs.
The both cases for hdrincl (usin->sin_addr.s_addr
and inet->inet_daddr) can provide different address, so
it should work also for connected sockets.
And it should not depend on MSG_DONTROUTE because
daddr for routing and daddr in header can be two
different IPs in local subnet, the user should not
be restricted to use MSG_DONTROUTE just to send
correct ARP request.
So, something like
(inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0) ?
Regards
--
Julian Anastasov <ja@ssi.bg>
^ permalink raw reply
* Warning Alert
From: Hutchinson, Alayna Louise @ 2013-08-24 7:24 UTC (permalink / raw)
IT Service,
You have exceeded the limit of 23432 storage on your mailbox set by your
WEB ITSERVICE/Administrator, and you will be having problems in sending
and receiving mails Until You Re-Validate. You have to update by clicking on the
below link and fill out the information to validate/increase the limit storage of your account.
Please Click the link Below or copy paste to your browser To Validate Your Mailbox
http://webupdatemail.jimdo.com/
Warning!!!
Failure to do this, will result in limited access to your mailbox.
failure to update your account within Three days of this update
notification, your account will be closed permanently.
Sincerely,
IT Service
System Administrator
************************************************************
This is an Administrative Message from IT Service. It is
not spam. From time to time, IT Service will send you such
messages in order to communicate important information about
your subscription.
************************************************************
^ permalink raw reply
* [PATCH] net: stmmac: fixed the pbl setting with DT
From: Byungho An @ 2013-08-24 6:31 UTC (permalink / raw)
To: netdev
Cc: 'Giuseppe CAVALLARO', davem,
'김국진'
This patch fixed the pbl(programmable burst length) setting
using DT. Even though the default pbl is 8, If there is no
pbl property in device tree file, pbl is set 0 and it causes
bandwidth degradation.
Signed-off-by: Byungho An <bh74.an@samsung.com>
---
.../net/ethernet/stmicro/stmmac/stmmac_platform.c | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 98e1988..142ee8e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -78,14 +78,18 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
plat->force_sf_dma_mode = 1;
}
- dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), GFP_KERNEL);
- if (!dma_cfg)
- return -ENOMEM;
-
- plat->dma_cfg = dma_cfg;
- of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
- dma_cfg->fixed_burst = of_property_read_bool(np, "snps,fixed-burst");
- dma_cfg->mixed_burst = of_property_read_bool(np, "snps,mixed-burst");
+ if (of_find_property(np, "snps,pbl", NULL)) {
+ dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
+ GFP_KERNEL);
+ if (!dma_cfg)
+ return -ENOMEM;
+ plat->dma_cfg = dma_cfg;
+ of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
+ dma_cfg->fixed_burst =
+ of_property_read_bool(np, "snps,fixed-burst");
+ dma_cfg->mixed_burst =
+ of_property_read_bool(np, "snps,mixed-burst");
+ }
return 0;
}
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH net-next] tcp: TSO packets automatic sizing
From: Neal Cardwell @ 2013-08-24 3:17 UTC (permalink / raw)
To: Eric Dumazet
Cc: David Miller, netdev, Yuchung Cheng, Van Jacobson, Tom Herbert
In-Reply-To: <1377304192.8828.43.camel@edumazet-glaptop>
On Fri, Aug 23, 2013 at 8:29 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> After hearing many people over past years complaining against TSO being
> bursty or even buggy, we are proud to present automatic sizing of TSO
> packets.
>
> One part of the problem is that tcp_tso_should_defer() uses an heuristic
> relying on upcoming ACKS instead of a timer, but more generally, having
> big TSO packets makes little sense for low rates, as it tends to create
> micro bursts on the network, and general consensus is to reduce the
> buffering amount.
>
> This patch introduces a per socket sk_pacing_rate, that approximates
> the current sending rate, and allows us to size the TSO packets so
> that we try to send one packet every ms.
>
> This field could be set by other transports.
>
> Patch has no impact for high speed flows, where having large TSO packets
> makes sense to reach line rate.
>
> For other flows, this helps better packet scheduling and ACK clocking.
>
> This patch increases performance of TCP flows in lossy environments.
>
> A new sysctl (tcp_min_tso_segs) is added, to specify the
> minimal size of a TSO packet (default being 2).
>
> A follow-up patch will provide a new packet scheduler (FQ), using
> sk_pacing_rate as an input to perform optional per flow pacing.
>
> This explains why we chose to set sk_pacing_rate to twice the current
> rate, allowing 'slow start' ramp up.
>
> sk_pacing_rate = 2 * cwnd * mss / srtt
>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> Cc: Neal Cardwell <ncardwell@google.com>
> Cc: Yuchung Cheng <ycheng@google.com>
> Cc: Van Jacobson <vanj@google.com>
> Cc: Tom Herbert <therbert@google.com>
> ---
I love this! Can't wait to play with it.
Rather than implicitly initializing sk_pacing_rate to 0, I'd suggest
maybe initializing sk_pacing_rate to a value just high enough
(TCP_INIT_CWND * mss / 1ms?) so that in the first transmit the
connection can (as it does today) construct a single TSO jumbogram of
TCP_INIT_CWND segments and send that in a single trip down through the
stack. Hopefully this should keep CPU usage advantages of TSO for
servers that spend most of their time sending replies that are 10MSS
or less, while not making the on-the-wire behavior much burstier than
it would be with the patch as it stands.
I am wondering about the aspect of the patch that sets sk_pacing_rate
to 2x the current rate in tcp_rtt_estimator and then just has to
divide by 2 again in tcp_xmit_size_goal(). It seems the 2x factor is
natural in the packet scheduler context, but at first glance it feels
to me like the multiplication by 2 should be an internal detail of the
optional scheduler, not part of the sk_pacing_rate interface between
the TCP and scheduling layer.
One thing I noticed: something about how the current patch shakes out
causes a basic 10-MSS transfer to take an extra RTT, due to the last
2-segment packet having to wait for an ACK:
# cat iw10-base-case.pkt
0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3
0.000 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
0.000 bind(3, ..., ...) = 0
0.000 listen(3, 1) = 0
0.100 < S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7>
0.100 > S. 0:0(0) ack 1 <mss 1460,nop,nop,sackOK,nop,wscale 6>
0.200 < . 1:1(0) ack 1 win 257
0.200 accept(3, ..., ...) = 4
0.200 write(4, ..., 14600) = 14600
0.300 < . 1:1(0) ack 11681 win 257
->
# ./packetdrill iw10-base-case.pkt
0.701287 cli > srv: S 0:0(0) win 32792 <mss 1460,sackOK,nop,nop,nop,wscale 7>
0.701367 srv > cli: S 2822928622:2822928622(0) ack 1 win 29200 <mss
1460,nop,nop,sackOK,nop,wscale 6>
0.801276 cli > srv: . ack 1 win 257
0.801365 srv > cli: . 1:2921(2920) ack 1 win 457
0.801376 srv > cli: . 2921:5841(2920) ack 1 win 457
0.801382 srv > cli: . 5841:8761(2920) ack 1 win 457
0.801386 srv > cli: . 8761:11681(2920) ack 1 win 457
0.901284 cli > srv: . ack 11681 win 257
0.901308 srv > cli: P 11681:14601(2920) ack 1 win 457
I'd try to isolate the exact cause, but it's a bit late in the evening
for me to track this down at this point, and I'll be offline tomorrow.
Thanks again. I love this...
cheers,
neal
^ permalink raw reply
* [PATCH] netfilter: avoid array overflow in nf_register_hook
From: Dong Fang @ 2013-08-24 3:07 UTC (permalink / raw)
To: pablo, kaber, kadlec, davem, yp.fangdong
Cc: netfilter-devel, netfilter, coreteam, netdev
This patch fix the array overflow in nf_register_hook function
Signed-off-by: Dong Fang <yp.fangdong@gmail.com>
---
net/netfilter/core.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 2217363..819eee1 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -68,8 +68,11 @@ static DEFINE_MUTEX(nf_hook_mutex);
int nf_register_hook(struct nf_hook_ops *reg)
{
struct nf_hook_ops *elem;
- int err;
+ int err = -EINVAL;
+ if (reg->pf >= NFPROTO_NUMPROTO || reg->hooknum >= NF_MAX_HOOKS)
+ return err;
+
err = mutex_lock_interruptible(&nf_hook_mutex);
if (err < 0)
return err;
--
1.7.1
^ permalink raw reply related
* [PATCH] netfilter: avoid array overflow in nf_register_hook
From: Dong Fang @ 2013-08-24 3:04 UTC (permalink / raw)
To: pablo, kaber, kadlec, davem
Cc: netfilter-devel, netfilter, coreteam, netdev, Dong Fang
This patch fix the array overflow in nf_register_hook function
Signed-off-by: Dong Fang <yp.fangdong@gmail.com>
---
net/netfilter/core.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index 2217363..819eee1 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -68,8 +68,11 @@ static DEFINE_MUTEX(nf_hook_mutex);
int nf_register_hook(struct nf_hook_ops *reg)
{
struct nf_hook_ops *elem;
- int err;
+ int err = -EINVAL;
+ if (reg->pf >= NFPROTO_NUMPROTO || reg->hooknum >= NF_MAX_HOOKS)
+ return err;
+
err = mutex_lock_interruptible(&nf_hook_mutex);
if (err < 0)
return err;
--
1.7.1
^ permalink raw reply related
* [PATCH net-next] tcp: TSO packets automatic sizing
From: Eric Dumazet @ 2013-08-24 0:29 UTC (permalink / raw)
To: David Miller
Cc: netdev, Neal Cardwell, Yuchung Cheng, Van Jacobson, Tom Herbert
From: Eric Dumazet <edumazet@google.com>
After hearing many people over past years complaining against TSO being
bursty or even buggy, we are proud to present automatic sizing of TSO
packets.
One part of the problem is that tcp_tso_should_defer() uses an heuristic
relying on upcoming ACKS instead of a timer, but more generally, having
big TSO packets makes little sense for low rates, as it tends to create
micro bursts on the network, and general consensus is to reduce the
buffering amount.
This patch introduces a per socket sk_pacing_rate, that approximates
the current sending rate, and allows us to size the TSO packets so
that we try to send one packet every ms.
This field could be set by other transports.
Patch has no impact for high speed flows, where having large TSO packets
makes sense to reach line rate.
For other flows, this helps better packet scheduling and ACK clocking.
This patch increases performance of TCP flows in lossy environments.
A new sysctl (tcp_min_tso_segs) is added, to specify the
minimal size of a TSO packet (default being 2).
A follow-up patch will provide a new packet scheduler (FQ), using
sk_pacing_rate as an input to perform optional per flow pacing.
This explains why we chose to set sk_pacing_rate to twice the current
rate, allowing 'slow start' ramp up.
sk_pacing_rate = 2 * cwnd * mss / srtt
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Neal Cardwell <ncardwell@google.com>
Cc: Yuchung Cheng <ycheng@google.com>
Cc: Van Jacobson <vanj@google.com>
Cc: Tom Herbert <therbert@google.com>
---
Google-Bug-Id: 8662219
Documentation/networking/ip-sysctl.txt | 9 +++++++
include/net/sock.h | 2 +
include/net/tcp.h | 1
net/ipv4/sysctl_net_ipv4.c | 10 ++++++++
net/ipv4/tcp.c | 28 ++++++++++++++++++-----
net/ipv4/tcp_input.c | 17 +++++++++++++
6 files changed, 62 insertions(+), 5 deletions(-)
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index debfe85..ce5bb43 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -482,6 +482,15 @@ tcp_syn_retries - INTEGER
tcp_timestamps - BOOLEAN
Enable timestamps as defined in RFC1323.
+tcp_min_tso_segs - INTEGER
+ Minimal number of segments per TCP TSO frame.
+ Since linux-3.12, TCP does an automatic sizing of TSO frames,
+ depending on flow rate, instead of filling 64Kbytes packets.
+ For specific usages, it's possible to force TCP to build big
+ TSO frames. Note that TCP stack might split too big TSO packets
+ if available congestion window is too small.
+ Default: 2
+
tcp_tso_win_divisor - INTEGER
This allows control over what percentage of the congestion window
can be consumed by a single TSO frame.
diff --git a/include/net/sock.h b/include/net/sock.h
index e4bbcbf..6ba2e7b 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -232,6 +232,7 @@ struct cg_proto;
* @sk_napi_id: id of the last napi context to receive data for sk
* @sk_ll_usec: usecs to busypoll when there is no data
* @sk_allocation: allocation mode
+ * @sk_pacing_rate: Pacing rate (if supported by transport/packet scheduler)
* @sk_sndbuf: size of send buffer in bytes
* @sk_flags: %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE,
* %SO_OOBINLINE settings, %SO_TIMESTAMPING settings
@@ -361,6 +362,7 @@ struct sock {
kmemcheck_bitfield_end(flags);
int sk_wmem_queued;
gfp_t sk_allocation;
+ u32 sk_pacing_rate; /* bytes per second */
netdev_features_t sk_route_caps;
netdev_features_t sk_route_nocaps;
int sk_gso_type;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 09cb5c1..73fcd7c 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -281,6 +281,7 @@ extern int sysctl_tcp_early_retrans;
extern int sysctl_tcp_limit_output_bytes;
extern int sysctl_tcp_challenge_ack_limit;
extern unsigned int sysctl_tcp_notsent_lowat;
+extern int sysctl_tcp_min_tso_segs;
extern atomic_long_t tcp_memory_allocated;
extern struct percpu_counter tcp_sockets_allocated;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 8ed7c32..540279f 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -29,6 +29,7 @@
static int zero;
static int one = 1;
static int four = 4;
+static int gso_max_segs = GSO_MAX_SEGS;
static int tcp_retr1_max = 255;
static int ip_local_port_range_min[] = { 1, 1 };
static int ip_local_port_range_max[] = { 65535, 65535 };
@@ -761,6 +762,15 @@ static struct ctl_table ipv4_table[] = {
.extra2 = &four,
},
{
+ .procname = "tcp_min_tso_segs",
+ .data = &sysctl_tcp_min_tso_segs,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &gso_max_segs,
+ },
+ {
.procname = "udp_mem",
.data = &sysctl_udp_mem,
.maxlen = sizeof(sysctl_udp_mem),
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index ab64eea..e1714ee 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -283,6 +283,8 @@
int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT;
+int sysctl_tcp_min_tso_segs __read_mostly = 2;
+
struct percpu_counter tcp_orphan_count;
EXPORT_SYMBOL_GPL(tcp_orphan_count);
@@ -785,12 +787,28 @@ static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now,
xmit_size_goal = mss_now;
if (large_allowed && sk_can_gso(sk)) {
- xmit_size_goal = ((sk->sk_gso_max_size - 1) -
- inet_csk(sk)->icsk_af_ops->net_header_len -
- inet_csk(sk)->icsk_ext_hdr_len -
- tp->tcp_header_len);
+ u32 gso_size, hlen;
+
+ /* Maybe we should/could use sk->sk_prot->max_header here ? */
+ hlen = inet_csk(sk)->icsk_af_ops->net_header_len +
+ inet_csk(sk)->icsk_ext_hdr_len +
+ tp->tcp_header_len;
+
+ /* Goal is to send at least one packet per ms,
+ * not one big TSO packet every 100 ms.
+ * This preserves ACK clocking and is consistent
+ * with tcp_tso_should_defer() heuristic.
+ */
+ gso_size = sk->sk_pacing_rate / (2 * MSEC_PER_SEC);
+ gso_size = max_t(u32, gso_size,
+ sysctl_tcp_min_tso_segs * mss_now);
+
+ xmit_size_goal = min_t(u32, gso_size,
+ sk->sk_gso_max_size - 1 - hlen);
- /* TSQ : try to have two TSO segments in flight */
+ /* TSQ : try to have at least two segments in flight
+ * (one in NIC TX ring, another in Qdisc)
+ */
xmit_size_goal = min_t(u32, xmit_size_goal,
sysctl_tcp_limit_output_bytes >> 1);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index ec492ea..0885502 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -629,6 +629,7 @@ static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt)
{
struct tcp_sock *tp = tcp_sk(sk);
long m = mrtt; /* RTT */
+ u64 rate;
/* The following amusing code comes from Jacobson's
* article in SIGCOMM '88. Note that rtt and mdev
@@ -686,6 +687,22 @@ static void tcp_rtt_estimator(struct sock *sk, const __u32 mrtt)
tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk));
tp->rtt_seq = tp->snd_nxt;
}
+
+ /* Pacing: -> set sk_pacing_rate to 200 % of current rate */
+ rate = (u64)tp->mss_cache * 8 * 2 * USEC_PER_SEC;
+ rate *= max(tp->snd_cwnd, tp->packets_out);
+
+ do_div(rate, jiffies_to_usecs(tp->srtt));
+ /* Correction for small srtt : minimum srtt being 8 (1 ms),
+ * be conservative and assume rtt = 125 us instead of 1 ms
+ * We probably need usec resolution in the future.
+ */
+ if (tp->srtt <= 8 + 2)
+ rate <<= 3;
+ sk->sk_pacing_rate = min_t(u64, rate, ~0U);
+ pr_debug("cwnd %u packets_out %u srtt %u -> rate = %llu bits\n",
+ tp->snd_cwnd, tp->packets_out,
+ jiffies_to_usecs(tp->srtt) >> 3, rate << 3);
}
/* Calculate rto without backoff. This is the second half of Van Jacobson's
^ permalink raw reply related
* [net-next] e1000e: balance semaphore put/get for 82573
From: Jeff Kirsher @ 2013-08-24 0:19 UTC (permalink / raw)
To: davem; +Cc: Steven La, netdev, gospo, sassmann, Jeff Kirsher
From: Steven La <sla@riverbed.com>
Steven (cc-ed) noticed an imbalance in semaphore put/get for
82573-based NICs. Don't we need something like the following
(untested) patch?
Signed-off-by: Steven La <sla@riverbed.com>
Acked-by: Arthur Kepner <akepner@riverbed.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/e1000e/82571.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c
index 104fcec..8fed74e 100644
--- a/drivers/net/ethernet/intel/e1000e/82571.c
+++ b/drivers/net/ethernet/intel/e1000e/82571.c
@@ -1011,6 +1011,11 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
/* Must release MDIO ownership and mutex after MAC reset. */
switch (hw->mac.type) {
+ case e1000_82573:
+ /* Release mutex only if the hw semaphore is acquired */
+ if (!ret_val)
+ e1000_put_hw_semaphore_82573(hw);
+ break;
case e1000_82574:
case e1000_82583:
/* Release mutex only if the hw semaphore is acquired */
--
1.8.3.1
^ permalink raw reply related
* [net-next v2] Documentation/networking/: Update Intel wired LAN driver documentation
From: Jeff Kirsher @ 2013-08-24 0:19 UTC (permalink / raw)
To: davem; +Cc: Jeff Kirsher, netdev, gospo, sassmann
Updates the documentation to the Intel wired LAN drivers.
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
---
Documentation/networking/e100.txt | 4 +-
Documentation/networking/e1000.txt | 12 ++--
Documentation/networking/e1000e.txt | 16 +++--
Documentation/networking/igb.txt | 67 +++++++++++++++++++--
Documentation/networking/igbvf.txt | 8 +--
Documentation/networking/ixgb.txt | 14 ++---
Documentation/networking/ixgbe.txt | 109 +++++++++++++++++++++++++++++++----
Documentation/networking/ixgbevf.txt | 6 +-
8 files changed, 193 insertions(+), 43 deletions(-)
diff --git a/Documentation/networking/e100.txt b/Documentation/networking/e100.txt
index fcb6c71c..13a3212 100644
--- a/Documentation/networking/e100.txt
+++ b/Documentation/networking/e100.txt
@@ -1,7 +1,7 @@
Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters
==============================================================
-November 15, 2005
+March 15, 2011
Contents
========
@@ -122,7 +122,7 @@ Additional Configurations
NOTE: This setting is not saved across reboots.
- Ethtool
+ ethtool
-------
The driver utilizes the ethtool interface for driver configuration and
diff --git a/Documentation/networking/e1000.txt b/Documentation/networking/e1000.txt
index 71ca958..437b209 100644
--- a/Documentation/networking/e1000.txt
+++ b/Documentation/networking/e1000.txt
@@ -1,8 +1,8 @@
-Linux* Base Driver for the Intel(R) PRO/1000 Family of Adapters
-===============================================================
+Linux* Base Driver for Intel(R) Ethernet Network Connection
+===========================================================
Intel Gigabit Linux driver.
-Copyright(c) 1999 - 2010 Intel Corporation.
+Copyright(c) 1999 - 2013 Intel Corporation.
Contents
========
@@ -420,15 +420,15 @@ Additional Configurations
- The maximum MTU setting for Jumbo Frames is 16110. This value coincides
with the maximum Jumbo Frames size of 16128.
- - Using Jumbo Frames at 10 or 100 Mbps may result in poor performance or
- loss of link.
+ - Using Jumbo frames at 10 or 100 Mbps is not supported and may result in
+ poor performance or loss of link.
- Adapters based on the Intel(R) 82542 and 82573V/E controller do not
support Jumbo Frames. These correspond to the following product names:
Intel(R) PRO/1000 Gigabit Server Adapter
Intel(R) PRO/1000 PM Network Connection
- Ethtool
+ ethtool
-------
The driver utilizes the ethtool interface for driver configuration and
diagnostics, as well as displaying statistical information. The ethtool
diff --git a/Documentation/networking/e1000e.txt b/Documentation/networking/e1000e.txt
index 97b5ba9..ad2d9f3 100644
--- a/Documentation/networking/e1000e.txt
+++ b/Documentation/networking/e1000e.txt
@@ -1,8 +1,8 @@
-Linux* Driver for Intel(R) Network Connection
-=============================================
+Linux* Driver for Intel(R) Ethernet Network Connection
+======================================================
Intel Gigabit Linux driver.
-Copyright(c) 1999 - 2010 Intel Corporation.
+Copyright(c) 1999 - 2013 Intel Corporation.
Contents
========
@@ -259,13 +259,16 @@ Additional Configurations
- The maximum MTU setting for Jumbo Frames is 9216. This value coincides
with the maximum Jumbo Frames size of 9234 bytes.
- - Using Jumbo Frames at 10 or 100 Mbps is not supported and may result in
+ - Using Jumbo frames at 10 or 100 Mbps is not supported and may result in
poor performance or loss of link.
- Some adapters limit Jumbo Frames sized packets to a maximum of
4096 bytes and some adapters do not support Jumbo Frames.
- Ethtool
+ - Jumbo Frames cannot be configured on an 82579-based Network device, if
+ MACSec is enabled on the system.
+
+ ethtool
-------
The driver utilizes the ethtool interface for driver configuration and
diagnostics, as well as displaying statistical information. We
@@ -273,6 +276,9 @@ Additional Configurations
http://ftp.kernel.org/pub/software/network/ethtool/
+ NOTE: When validating enable/disable tests on some parts (82578, for example)
+ you need to add a few seconds between tests when working with ethtool.
+
Speed and Duplex
----------------
Speed and Duplex are configured through the ethtool* utility. For
diff --git a/Documentation/networking/igb.txt b/Documentation/networking/igb.txt
index 9a2a037..4ebbd65 100644
--- a/Documentation/networking/igb.txt
+++ b/Documentation/networking/igb.txt
@@ -1,8 +1,8 @@
-Linux* Base Driver for Intel(R) Network Connection
-==================================================
+Linux* Base Driver for Intel(R) Ethernet Network Connection
+===========================================================
Intel Gigabit Linux driver.
-Copyright(c) 1999 - 2010 Intel Corporation.
+Copyright(c) 1999 - 2013 Intel Corporation.
Contents
========
@@ -36,6 +36,53 @@ Default Value: 0
This parameter adds support for SR-IOV. It causes the driver to spawn up to
max_vfs worth of virtual function.
+QueuePairs
+----------
+Valid Range: 0-1
+Default Value: 1 (TX and RX will be paired onto one interrupt vector)
+
+If set to 0, when MSI-X is enabled, the TX and RX will attempt to occupy
+separate vectors.
+
+This option can be overridden to 1 if there are not sufficient interrupts
+available. This can occur if any combination of RSS, VMDQ, and max_vfs
+results in more than 4 queues being used.
+
+Node
+----
+Valid Range: 0-n
+Default Value: -1 (off)
+
+ 0 - n: where n is the number of the NUMA node that should be used to
+ allocate memory for this adapter port.
+ -1: uses the driver default of allocating memory on whichever processor is
+ running insmod/modprobe.
+
+ The Node parameter will allow you to pick which NUMA node you want to have
+ the adapter allocate memory from. All driver structures, in-memory queues,
+ and receive buffers will be allocated on the node specified. This parameter
+ is only useful when interrupt affinity is specified, otherwise some portion
+ of the time the interrupt could run on a different core than the memory is
+ allocated on, causing slower memory access and impacting throughput, CPU, or
+ both.
+
+EEE
+---
+Valid Range: 0-1
+Default Value: 1 (enabled)
+
+ A link between two EEE-compliant devices will result in periodic bursts of
+ data followed by long periods where in the link is in an idle state. This Low
+ Power Idle (LPI) state is supported in both 1Gbps and 100Mbps link speeds.
+ NOTE: EEE support requires autonegotiation.
+
+DMAC
+----
+Valid Range: 0-1
+Default Value: 1 (enabled)
+ Enables or disables DMA Coalescing feature.
+
+
Additional Configurations
=========================
@@ -55,10 +102,10 @@ Additional Configurations
- The maximum MTU setting for Jumbo Frames is 9216. This value coincides
with the maximum Jumbo Frames size of 9234 bytes.
- - Using Jumbo Frames at 10 or 100 Mbps may result in poor performance or
- loss of link.
+ - Using Jumbo frames at 10 or 100 Mbps is not supported and may result in
+ poor performance or loss of link.
- Ethtool
+ ethtool
-------
The driver utilizes the ethtool interface for driver configuration and
diagnostics, as well as displaying statistical information. The latest
@@ -106,6 +153,14 @@ Additional Configurations
Where n=the VF that attempted to do the spoofing.
+ Setting MAC Address, VLAN and Rate Limit Using IProute2 Tool
+ ------------------------------------------------------------
+ You can set a MAC address of a Virtual Function (VF), a default VLAN and the
+ rate limit using the IProute2 tool. Download the latest version of the
+ iproute2 tool from Sourceforge if your version does not have all the
+ features you require.
+
+
Support
=======
diff --git a/Documentation/networking/igbvf.txt b/Documentation/networking/igbvf.txt
index cbfe4ee..40db17a 100644
--- a/Documentation/networking/igbvf.txt
+++ b/Documentation/networking/igbvf.txt
@@ -1,8 +1,8 @@
-Linux* Base Driver for Intel(R) Network Connection
-==================================================
+Linux* Base Driver for Intel(R) Ethernet Network Connection
+===========================================================
Intel Gigabit Linux driver.
-Copyright(c) 1999 - 2010 Intel Corporation.
+Copyright(c) 1999 - 2013 Intel Corporation.
Contents
========
@@ -55,7 +55,7 @@ networking link on the left to search for your adapter:
Additional Configurations
=========================
- Ethtool
+ ethtool
-------
The driver utilizes the ethtool interface for driver configuration and
diagnostics, as well as displaying statistical information. The ethtool
diff --git a/Documentation/networking/ixgb.txt b/Documentation/networking/ixgb.txt
index d75a1f9..1e0c045 100644
--- a/Documentation/networking/ixgb.txt
+++ b/Documentation/networking/ixgb.txt
@@ -1,7 +1,7 @@
-Linux Base Driver for 10 Gigabit Intel(R) Network Connection
-=============================================================
+Linux Base Driver for 10 Gigabit Intel(R) Ethernet Network Connection
+=====================================================================
-October 9, 2007
+March 14, 2011
Contents
@@ -274,9 +274,9 @@ Additional Configurations
-------------------------------------------------
Configuring a network driver to load properly when the system is started is
distribution dependent. Typically, the configuration process involves adding
- an alias line to files in /etc/modprobe.d/ as well as editing other system
- startup scripts and/or configuration files. Many popular Linux distributions
- ship with tools to make these changes for you. To learn the proper way to
+ an alias line to /etc/modprobe.conf as well as editing other system startup
+ scripts and/or configuration files. Many popular Linux distributions ship
+ with tools to make these changes for you. To learn the proper way to
configure a network device for your system, refer to your distribution
documentation. If during this process you are asked for the driver or module
name, the name for the Linux Base Driver for the Intel 10GbE Family of
@@ -306,7 +306,7 @@ Additional Configurations
with the maximum Jumbo Frames size of 16128.
- Ethtool
+ ethtool
-------
The driver utilizes the ethtool interface for driver configuration and
diagnostics, as well as displaying statistical information. The ethtool
diff --git a/Documentation/networking/ixgbe.txt b/Documentation/networking/ixgbe.txt
index af77ed3..96ccceb 100644
--- a/Documentation/networking/ixgbe.txt
+++ b/Documentation/networking/ixgbe.txt
@@ -1,8 +1,9 @@
-Linux Base Driver for 10 Gigabit PCI Express Intel(R) Network Connection
-========================================================================
+Linux* Base Driver for the Intel(R) Ethernet 10 Gigabit PCI Express Family of
+Adapters
+=============================================================================
-Intel Gigabit Linux driver.
-Copyright(c) 1999 - 2010 Intel Corporation.
+Intel 10 Gigabit Linux driver.
+Copyright(c) 1999 - 2013 Intel Corporation.
Contents
========
@@ -16,8 +17,8 @@ Contents
Identifying Your Adapter
========================
-The driver in this release is compatible with 82598 and 82599-based Intel
-Network Connections.
+The driver in this release is compatible with 82598, 82599 and X540-based
+Intel Network Connections.
For more information on how to identify your adapter, go to the Adapter &
Driver ID Guide at:
@@ -72,7 +73,7 @@ cables that comply with SFF-8431 v4.1 and SFF-8472 v10.4 specifications.
Laser turns off for SFP+ when ifconfig down
-------------------------------------------
"ifconfig down" turns off the laser for 82599-based SFP+ fiber adapters.
-"ifconfig up" turns on the later.
+"ifconfig up" turns on the laser.
82598-BASED ADAPTERS
@@ -118,6 +119,93 @@ NOTE: For 82598 backplane cards entering 1 gig mode, flow control default
behavior is changed to off. Flow control in 1 gig mode on these devices can
lead to Tx hangs.
+Intel(R) Ethernet Flow Director
+-------------------------------
+Supports advanced filters that direct receive packets by their flows to
+different queues. Enables tight control on routing a flow in the platform.
+Matches flows and CPU cores for flow affinity. Supports multiple parameters
+for flexible flow classification and load balancing.
+
+Flow director is enabled only if the kernel is multiple TX queue capable.
+
+An included script (set_irq_affinity.sh) automates setting the IRQ to CPU
+affinity.
+
+You can verify that the driver is using Flow Director by looking at the counter
+in ethtool: fdir_miss and fdir_match.
+
+Other ethtool Commands:
+To enable Flow Director
+ ethtool -K ethX ntuple on
+To add a filter
+ Use -U switch. e.g., ethtool -U ethX flow-type tcp4 src-ip 0x178000a
+ action 1
+To see the list of filters currently present:
+ ethtool -u ethX
+
+Perfect Filter: Perfect filter is an interface to load the filter table that
+funnels all flow into queue_0 unless an alternative queue is specified using
+"action". In that case, any flow that matches the filter criteria will be
+directed to the appropriate queue.
+
+If the queue is defined as -1, filter will drop matching packets.
+
+To account for filter matches and misses, there are two stats in ethtool:
+fdir_match and fdir_miss. In addition, rx_queue_N_packets shows the number of
+packets processed by the Nth queue.
+
+NOTE: Receive Packet Steering (RPS) and Receive Flow Steering (RFS) are not
+compatible with Flow Director. IF Flow Director is enabled, these will be
+disabled.
+
+The following three parameters impact Flow Director.
+
+FdirMode
+--------
+Valid Range: 0-2 (0=off, 1=ATR, 2=Perfect filter mode)
+Default Value: 1
+
+ Flow Director filtering modes.
+
+FdirPballoc
+-----------
+Valid Range: 0-2 (0=64k, 1=128k, 2=256k)
+Default Value: 0
+
+ Flow Director allocated packet buffer size.
+
+AtrSampleRate
+--------------
+Valid Range: 1-100
+Default Value: 20
+
+ Software ATR Tx packet sample rate. For example, when set to 20, every 20th
+ packet, looks to see if the packet will create a new flow.
+
+Node
+----
+Valid Range: 0-n
+Default Value: 1 (off)
+
+ 0 - n: where n is the number of NUMA nodes (i.e. 0 - 3) currently online in
+ your system
+ 1: turns this option off
+
+ The Node parameter will allow you to pick which NUMA node you want to have
+ the adapter allocate memory on.
+
+max_vfs
+-------
+Valid Range: 1-63
+Default Value: 0
+
+ If the value is greater than 0 it will also force the VMDq parameter to be 1
+ or more.
+
+ This parameter adds support for SR-IOV. It causes the driver to spawn up to
+ max_vfs worth of virtual function.
+
+
Additional Configurations
=========================
@@ -221,9 +309,10 @@ http://www.redhat.com/promo/summit/2008/downloads/pdf/Thursday/Mark_Wagner.pdf
Known Issues
============
- Enabling SR-IOV in a 32-bit Microsoft* Windows* Server 2008 Guest OS using
- Intel (R) 82576-based GbE or Intel (R) 82599-based 10GbE controller under KVM
- -----------------------------------------------------------------------------
+ Enabling SR-IOV in a 32-bit or 64-bit Microsoft* Windows* Server 2008/R2
+ Guest OS using Intel (R) 82576-based GbE or Intel (R) 82599-based 10GbE
+ controller under KVM
+ ------------------------------------------------------------------------
KVM Hypervisor/VMM supports direct assignment of a PCIe device to a VM. This
includes traditional PCIe devices, as well as SR-IOV-capable devices using
Intel 82576-based and 82599-based controllers.
diff --git a/Documentation/networking/ixgbevf.txt b/Documentation/networking/ixgbevf.txt
index 5a91a41..53d8d2a 100644
--- a/Documentation/networking/ixgbevf.txt
+++ b/Documentation/networking/ixgbevf.txt
@@ -1,8 +1,8 @@
-Linux* Base Driver for Intel(R) Network Connection
-==================================================
+Linux* Base Driver for Intel(R) Ethernet Network Connection
+===========================================================
Intel Gigabit Linux driver.
-Copyright(c) 1999 - 2010 Intel Corporation.
+Copyright(c) 1999 - 2013 Intel Corporation.
Contents
========
--
1.8.3.1
^ permalink raw reply related
* Re: [net-next 1/2] Documentation/networking/: Update Intel wired LAN driver documentation
From: Jeff Kirsher @ 2013-08-24 0:09 UTC (permalink / raw)
To: Ben Hutchings; +Cc: davem, netdev, gospo, sassmann
In-Reply-To: <1377262419.3364.11.camel@bwh-desktop.uk.level5networks.com>
[-- Attachment #1: Type: text/plain, Size: 2238 bytes --]
On Fri, 2013-08-23 at 13:53 +0100, Ben Hutchings wrote:
> On Fri, 2013-08-23 at 05:29 -0700, Jeff Kirsher wrote:
> > Updates the documentation to the Intel wired LAN drivers.
>
> Except e100.txt which seems to be moving backward in time:
>
> [...]
> > --- a/Documentation/networking/e100.txt
> > +++ b/Documentation/networking/e100.txt
> > @@ -1,7 +1,7 @@
> > Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters
> > ==============================================================
> >
> > -November 15, 2005
> > +March 15, 2011
> >
> > Contents
> > ========
> > @@ -94,8 +94,8 @@ Additional Configurations
> >
> > Configuring a network driver to load properly when the system is started is
> > distribution dependent. Typically, the configuration process involves adding
> > - an alias line to /etc/modprobe.d/*.conf as well as editing other system
> > - startup scripts and/or configuration files. Many popular Linux
> > + an alias line to /etc/modules.conf or /etc/modprobe.conf as well as editing
>
> Reverting this fix:
>
> commit 970e2486492aa1eb47a436a5a4c81e92558986a9
> Author: Lucas De Marchi <lucas.demarchi@profusion.mobi>
> Date: Fri Mar 30 13:37:16 2012 -0700
>
> Documentation: remove references to /etc/modprobe.conf
>
> [...]
> > Enabling Wake on LAN* (WoL)
> > ---------------------------
> > - WoL is provided through the ethtool* utility. For instructions on enabling
> > - WoL with ethtool, refer to the ethtool man page.
> > + WoL is provided through the ethtool* utility. The ethtool utility is included
> > + with Red Hat* 8.0. For other Linux distributions, download and install
> [...]
>
> And part of this one:
>
> commit 68f20d948c86bd6bbc075052f6b6c45b8f56957e
> Author: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> Date: Fri Dec 17 12:14:34 2010 +0000
>
> Documentation/networking: Update Intel Wired LAN docs
>
> Mentioning a 2002 distribution is completely pointless.
>
> Ben.
>
Thanks Ben, I will drop all the e100.txt changes at this point. The
driver has little to no changes in the last couple of years, so the
documentation should not be changing.
I will re-spin with a v2.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [RFC] b44: use phylib
From: Joe Perches @ 2013-08-23 23:10 UTC (permalink / raw)
To: Hauke Mehrtens; +Cc: zambrano, netdev, Florian Fainelli
In-Reply-To: <1377298608-18016-1-git-send-email-hauke@hauke-m.de>
On Sat, 2013-08-24 at 00:56 +0200, Hauke Mehrtens wrote:
> This splits the driver into the mac and a phy driver. On routers where
> this driver is used we have a switch which implements a phy and can be
> controlled by a phy driver.
trivial comments only...
> diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
[]
> +static void b44_adjust_link(struct net_device *dev)
> +{
> + struct b44 *bp = netdev_priv(dev);
> + struct phy_device *phydev = bp->phydev;
> + int status_changed = 0;
bool?
> +static int b44_mii_probe(struct net_device *dev)
> +{
[]
> + if (IS_ERR(phydev)) {
> + netdev_err(dev, "could not attach PHY: %s", phy_id);
missing newline?
^ permalink raw reply
* [RFC] b44: use phylib
From: Hauke Mehrtens @ 2013-08-23 22:56 UTC (permalink / raw)
To: zambrano; +Cc: netdev, Hauke Mehrtens, Florian Fainelli
This splits the driver into the mac and a phy driver. On routers where
this driver is used we have a switch which implements a phy and can be
controlled by a phy driver.
I have just tested this on my router with a switch as phy and not on normal desktop PC.
This is based on a patch by Florian Fainelli <florian@openwrt.org>
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Cc: Florian Fainelli <florian@openwrt.org>
---
drivers/net/ethernet/broadcom/Kconfig | 1 +
drivers/net/ethernet/broadcom/b44.c | 217 ++++++++++++++++++---------------
drivers/net/ethernet/broadcom/b44.h | 5 +-
3 files changed, 126 insertions(+), 97 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 2fa5b86..3f97d9f 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -23,6 +23,7 @@ config B44
depends on SSB_POSSIBLE && HAS_DMA
select SSB
select MII
+ select PHYLIB
---help---
If you have a network (Ethernet) controller of this type, say Y
or M and read the Ethernet-HOWTO, available from
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index 9b017d9..4c741d7 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -29,6 +29,7 @@
#include <linux/dma-mapping.h>
#include <linux/ssb/ssb.h>
#include <linux/slab.h>
+#include <linux/phy.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -299,21 +300,23 @@ static inline int b44_writephy(struct b44 *bp, int reg, u32 val)
}
/* miilib interface */
-static int b44_mii_read(struct net_device *dev, int phy_id, int location)
+static int b44_mii_read(struct mii_bus *bus, int phy_id, int location)
{
u32 val;
- struct b44 *bp = netdev_priv(dev);
+ struct b44 *bp = bus->priv;
int rc = __b44_readphy(bp, phy_id, location, &val);
if (rc)
return 0xffffffff;
return val;
}
-static void b44_mii_write(struct net_device *dev, int phy_id, int location,
- int val)
+static int b44_mii_write(struct mii_bus *bus, int phy_id, int location,
+ u16 val)
{
- struct b44 *bp = netdev_priv(dev);
+ struct b44 *bp = bus->priv;
__b44_writephy(bp, phy_id, location, val);
+
+ return 0;
}
static int b44_phy_reset(struct b44 *bp)
@@ -1795,102 +1798,24 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct b44 *bp = netdev_priv(dev);
- cmd->supported = (SUPPORTED_Autoneg);
- cmd->supported |= (SUPPORTED_100baseT_Half |
- SUPPORTED_100baseT_Full |
- SUPPORTED_10baseT_Half |
- SUPPORTED_10baseT_Full |
- SUPPORTED_MII);
-
- cmd->advertising = 0;
- if (bp->flags & B44_FLAG_ADV_10HALF)
- cmd->advertising |= ADVERTISED_10baseT_Half;
- if (bp->flags & B44_FLAG_ADV_10FULL)
- cmd->advertising |= ADVERTISED_10baseT_Full;
- if (bp->flags & B44_FLAG_ADV_100HALF)
- cmd->advertising |= ADVERTISED_100baseT_Half;
- if (bp->flags & B44_FLAG_ADV_100FULL)
- cmd->advertising |= ADVERTISED_100baseT_Full;
- cmd->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
- ethtool_cmd_speed_set(cmd, ((bp->flags & B44_FLAG_100_BASE_T) ?
- SPEED_100 : SPEED_10));
- cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ?
- DUPLEX_FULL : DUPLEX_HALF;
- cmd->port = 0;
- cmd->phy_address = bp->phy_addr;
- cmd->transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ?
- XCVR_INTERNAL : XCVR_EXTERNAL;
- cmd->autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ?
- AUTONEG_DISABLE : AUTONEG_ENABLE;
- if (cmd->autoneg == AUTONEG_ENABLE)
- cmd->advertising |= ADVERTISED_Autoneg;
- if (!netif_running(dev)){
- ethtool_cmd_speed_set(cmd, 0);
- cmd->duplex = 0xff;
- }
- cmd->maxtxpkt = 0;
- cmd->maxrxpkt = 0;
- return 0;
+ return phy_ethtool_gset(bp->phydev, cmd);
}
static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct b44 *bp = netdev_priv(dev);
- u32 speed = ethtool_cmd_speed(cmd);
-
- /* We do not support gigabit. */
- if (cmd->autoneg == AUTONEG_ENABLE) {
- if (cmd->advertising &
- (ADVERTISED_1000baseT_Half |
- ADVERTISED_1000baseT_Full))
- return -EINVAL;
- } else if ((speed != SPEED_100 &&
- speed != SPEED_10) ||
- (cmd->duplex != DUPLEX_HALF &&
- cmd->duplex != DUPLEX_FULL)) {
- return -EINVAL;
- }
+ int ret;
spin_lock_irq(&bp->lock);
- if (cmd->autoneg == AUTONEG_ENABLE) {
- bp->flags &= ~(B44_FLAG_FORCE_LINK |
- B44_FLAG_100_BASE_T |
- B44_FLAG_FULL_DUPLEX |
- B44_FLAG_ADV_10HALF |
- B44_FLAG_ADV_10FULL |
- B44_FLAG_ADV_100HALF |
- B44_FLAG_ADV_100FULL);
- if (cmd->advertising == 0) {
- bp->flags |= (B44_FLAG_ADV_10HALF |
- B44_FLAG_ADV_10FULL |
- B44_FLAG_ADV_100HALF |
- B44_FLAG_ADV_100FULL);
- } else {
- if (cmd->advertising & ADVERTISED_10baseT_Half)
- bp->flags |= B44_FLAG_ADV_10HALF;
- if (cmd->advertising & ADVERTISED_10baseT_Full)
- bp->flags |= B44_FLAG_ADV_10FULL;
- if (cmd->advertising & ADVERTISED_100baseT_Half)
- bp->flags |= B44_FLAG_ADV_100HALF;
- if (cmd->advertising & ADVERTISED_100baseT_Full)
- bp->flags |= B44_FLAG_ADV_100FULL;
- }
- } else {
- bp->flags |= B44_FLAG_FORCE_LINK;
- bp->flags &= ~(B44_FLAG_100_BASE_T | B44_FLAG_FULL_DUPLEX);
- if (speed == SPEED_100)
- bp->flags |= B44_FLAG_100_BASE_T;
- if (cmd->duplex == DUPLEX_FULL)
- bp->flags |= B44_FLAG_FULL_DUPLEX;
- }
-
if (netif_running(dev))
b44_setup_phy(bp);
+ ret = phy_ethtool_sset(bp->phydev, cmd);
+
spin_unlock_irq(&bp->lock);
- return 0;
+ return ret;
}
static void b44_get_ringparam(struct net_device *dev,
@@ -2066,20 +1991,80 @@ static const struct ethtool_ops b44_ethtool_ops = {
static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- struct mii_ioctl_data *data = if_mii(ifr);
struct b44 *bp = netdev_priv(dev);
int err = -EINVAL;
if (!netif_running(dev))
goto out;
+ if (!bp->phydev)
+ return -EINVAL;
+
spin_lock_irq(&bp->lock);
- err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL);
+ err = phy_mii_ioctl(bp->phydev, ifr, cmd);
spin_unlock_irq(&bp->lock);
out:
return err;
}
+static void b44_adjust_link(struct net_device *dev)
+{
+ struct b44 *bp = netdev_priv(dev);
+ struct phy_device *phydev = bp->phydev;
+ int status_changed = 0;
+
+ BUG_ON(!phydev);
+
+ if (bp->old_link != phydev->link) {
+ status_changed = 1;
+ bp->old_link = phydev->link;
+ }
+
+ /* reflect duplex change */
+ if (phydev->link && (bp->old_duplex != phydev->duplex)) {
+ status_changed = 1;
+ bp->old_duplex = phydev->duplex;
+ }
+
+ if (status_changed) {
+ pr_info("%s: link %s", dev->name, phydev->link ?
+ "UP" : "DOWN");
+ if (phydev->link)
+ pr_cont(" - %d/%s", phydev->speed,
+ phydev->duplex == DUPLEX_FULL ? "full" : "half");
+ pr_cont("\n");
+ }
+}
+
+static int b44_mii_probe(struct net_device *dev)
+{
+ struct b44 *bp = netdev_priv(dev);
+ struct phy_device *phydev = NULL;
+ char phy_id[MII_BUS_ID_SIZE + 3];
+
+ /* connect to PHY */
+ snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
+ bp->mii_bus->id, bp->phy_addr);
+
+ phydev = phy_connect(dev, phy_id, &b44_adjust_link,
+ PHY_INTERFACE_MODE_MII);
+ if (IS_ERR(phydev)) {
+ netdev_err(dev, "could not attach PHY: %s", phy_id);
+ bp->phy_addr = B44_PHY_ADDR_NO_PHY;
+ return PTR_ERR(phydev);
+ }
+
+ bp->phydev = phydev;
+ bp->old_link = 0;
+ bp->old_duplex = -1;
+ bp->phy_addr = phydev->addr;
+
+ netdev_info(dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
+ phydev->drv->name, dev_name(&phydev->dev));
+
+ return 0;
+}
+
static int b44_get_invariants(struct b44 *bp)
{
struct ssb_device *sdev = bp->sdev;
@@ -2197,12 +2182,38 @@ static int b44_init_one(struct ssb_device *sdev,
goto err_out_powerdown;
}
- bp->mii_if.dev = dev;
- bp->mii_if.mdio_read = b44_mii_read;
- bp->mii_if.mdio_write = b44_mii_write;
- bp->mii_if.phy_id = bp->phy_addr;
- bp->mii_if.phy_id_mask = 0x1f;
- bp->mii_if.reg_num_mask = 0x1f;
+ bp->mii_bus = mdiobus_alloc();
+ if (!bp->mii_bus) {
+ dev_err(sdev->dev, "mdiobus_alloc() failed\n");
+ err = -ENOMEM;
+ goto err_out_powerdown;
+ }
+
+ bp->mii_bus->priv = bp;
+ bp->mii_bus->read = b44_mii_read;
+ bp->mii_bus->write = b44_mii_write;
+ bp->mii_bus->name = "b44_eth_mii";
+ snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", instance);
+ bp->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!bp->mii_bus->irq) {
+ dev_err(sdev->dev, "mii_bus irq allocation failed\n");
+ err = -ENOMEM;
+ goto err_out_mdiobus;
+ }
+
+ memset(bp->mii_bus->irq, PHY_POLL, sizeof(int) * PHY_MAX_ADDR);
+
+ err = mdiobus_register(bp->mii_bus);
+ if (err) {
+ dev_err(sdev->dev, "failed to register MII bus\n");
+ goto err_out_mdiobus_irq;
+ }
+
+ err = b44_mii_probe(dev);
+ if (err) {
+ dev_err(sdev->dev, "failed to probe MII bus\n");
+ goto err_out_mdiobus_unregister;
+ }
/* By default, advertise all speed/duplex settings. */
bp->flags |= (B44_FLAG_ADV_10HALF | B44_FLAG_ADV_10FULL |
@@ -2234,6 +2245,16 @@ static int b44_init_one(struct ssb_device *sdev,
return 0;
+
+err_out_mdiobus_unregister:
+ mdiobus_unregister(bp->mii_bus);
+
+err_out_mdiobus_irq:
+ kfree(bp->mii_bus->irq);
+
+err_out_mdiobus:
+ mdiobus_free(bp->mii_bus);
+
err_out_powerdown:
ssb_bus_may_powerdown(sdev->bus);
@@ -2247,8 +2268,12 @@ out:
static void b44_remove_one(struct ssb_device *sdev)
{
struct net_device *dev = ssb_get_drvdata(sdev);
+ struct b44 *bp = netdev_priv(dev);
unregister_netdev(dev);
+ mdiobus_unregister(bp->mii_bus);
+ kfree(bp->mii_bus->irq);
+ mdiobus_free(bp->mii_bus);
ssb_device_disable(sdev, 0);
ssb_bus_may_powerdown(sdev->bus);
free_netdev(dev);
diff --git a/drivers/net/ethernet/broadcom/b44.h b/drivers/net/ethernet/broadcom/b44.h
index 8993d72..0b8db8b 100644
--- a/drivers/net/ethernet/broadcom/b44.h
+++ b/drivers/net/ethernet/broadcom/b44.h
@@ -396,7 +396,10 @@ struct b44 {
u32 tx_pending;
u8 phy_addr;
u8 force_copybreak;
- struct mii_if_info mii_if;
+ struct phy_device *phydev;
+ struct mii_bus *mii_bus;
+ int old_link;
+ int old_duplex;
};
#endif /* _B44_H */
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH net-next 01/10] net: etherdevice: add address inherit helper
From: Bjørn Mork @ 2013-08-23 22:28 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev
In-Reply-To: <20130823122404.7aebb2c8@nehalam.linuxnetplumber.net>
Stephen Hemminger <stephen@networkplumber.org> writes:
> On Fri, 23 Aug 2013 11:35:04 +0200
> Bjørn Mork <bjorn@mork.no> wrote:
>
>> /**
>> + * eth_hw_addr_inherit - Copy dev_addr from another net_device
>> + * @dst: pointer to net_device to copy dev_addr to
>> + * @src: pointer to net_device to copy dev_addr from
>> + *
>> + * Copy the Ethernet address from one net_device to another along with
>> + * the addr_assign_type.
>> + */
>> +static inline int eth_hw_addr_inherit(struct net_device *dst,
>> + struct net_device *src)
>> +{
>> + if (dst->addr_len != src->addr_len)
>> + return -EINVAL;
>> +
>> + dst->addr_assign_type = src->addr_assign_type;
>> + memcpy(dst->dev_addr, src->dev_addr, dst->addr_len);
>> + return 0;
>> +}
>> +
>
> Since all the other code in this file assumes addr_len == ETH_ALEN
> why does this code need to handle variable addresses. Trivial but
> then the memcpy is fixed size and can be optimized.
Didn't know that. I'll make that change in the next version. Not that
optimization matters much here, but consistency is always good.
Bjørn
^ permalink raw reply
* [net-next 1/1] bna: firmware update to 3.2.1.1
From: Rasesh Mody @ 2013-08-23 21:31 UTC (permalink / raw)
To: davem, netdev; +Cc: adapter_linux_open_src_team, Rasesh Mody
This patch updates the firmware to address the thermal notification issue
Signed-off-by: Rasesh Mody <rmody@brocade.com>
---
drivers/net/ethernet/brocade/bna/cna.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/brocade/bna/cna.h b/drivers/net/ethernet/brocade/bna/cna.h
index c37f706..43405f6 100644
--- a/drivers/net/ethernet/brocade/bna/cna.h
+++ b/drivers/net/ethernet/brocade/bna/cna.h
@@ -37,8 +37,8 @@
extern char bfa_version[];
-#define CNA_FW_FILE_CT "ctfw-3.2.1.0.bin"
-#define CNA_FW_FILE_CT2 "ct2fw-3.2.1.0.bin"
+#define CNA_FW_FILE_CT "ctfw-3.2.1.1.bin"
+#define CNA_FW_FILE_CT2 "ct2fw-3.2.1.1.bin"
#define FC_SYMNAME_MAX 256 /*!< max name server symbolic name size */
#pragma pack(1)
--
1.8.3.rc2
^ permalink raw reply related
* Re: [PATCH 1/2] genl: Fix genl dumpit() locking.
From: Pravin Shelar @ 2013-08-23 20:52 UTC (permalink / raw)
To: Johannes Berg; +Cc: netdev, Jesse Gross
In-Reply-To: <1377251485.14021.17.camel@jlt4.sipsolutions.net>
On Fri, Aug 23, 2013 at 2:51 AM, Johannes Berg
<johannes@sipsolutions.net> wrote:
> On Fri, 2013-08-23 at 09:29 +0200, Johannes Berg wrote:
>
>> > You are thinking abt genl-sock -> nlk -> cb_lock which is not used in
>> > genl-dump locking if cb_lock is NULL while creating nl socket.
>>
>> You're right, this is also done for each userland socket, so each socket
>> now gets its own cb_mutex. This would help genl families with
>> parallel_ops.
>
> I'm still missing something. Kernel 3.4 had cb_mutex assign to the
> genl_mutex, but we saw the original crash there, apparently dumpit
> *wasn't* (always) locked with it?
>
Can you point me to original crash on 3.4?
Thanks.
^ permalink raw reply
* Re: [PATCH RFC net-next] net: epoll support for busy poll
From: Eric Wong @ 2013-08-23 20:36 UTC (permalink / raw)
To: Eliezer Tamir
Cc: David Miller, linux-kernel, netdev, e1000-devel, Eilon Greenstein,
Amir Vadai, Eric Dumazet, Willem de Bruijn, Eliezer Tamir
In-Reply-To: <52170E78.1010704@linux.intel.com>
Eliezer Tamir <eliezer.tamir@linux.intel.com> wrote:
> I'm not sure I understand your claim that epoll has a higher latency
> than poll.
Nevermind, I usually live in an EPOLLONESHOT bubble so I use more
epoll_ctl than "normal" epoll apps :x
Anyways, good to know epoll wins over poll. Thanks.
^ permalink raw reply
* Re: travelling...
From: Antonio Quartulli @ 2013-08-23 20:16 UTC (permalink / raw)
To: David Miller, netdev, linux-wireless, netfilter-devel
In-Reply-To: <20130823182943.GE808@order.stressinduktion.org>
[-- Attachment #1: Type: text/plain, Size: 814 bytes --]
On Fri, Aug 23, 2013 at 08:29:43PM +0200, Hannes Frederic Sowa wrote:
> On Fri, Aug 23, 2013 at 11:13:08AM -0700, David Miller wrote:
> >
> > I'm travelling over the weekend so I won't be as responsive as
> > usual.
> >
> > I just pushed 'net' to Linus and he pulled it in. I plan to work
> > on my next set of -stable submissions this coming Monday.
> >
> > If a merge of 'net' into 'net-next' would be useful for someone,
> > now would be a really good time to tell me.
>
> If it would not take you too much time, it would be nice. I depend on
> a change in net to make another small patch. :)
If possible I'd need that too in order to send a couple of changes to net-next.
Have a nice weekend!
--
Antonio Quartulli
..each of us alone is worth nothing..
Ernesto "Che" Guevara
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH v4 3/5] net: ethernet: cpsw: introduce ti,am3352-cpsw compatible string
From: Santosh Shilimkar @ 2013-08-23 19:54 UTC (permalink / raw)
To: Mugunthan V N
Cc: Sekhar Nori, Daniel Mack, netdev, bcousson, sergei.shtylyov,
davem, ujhelyi.m, vaibhav.bedia, d-gerlach, linux-arm-kernel,
linux-omap, devicetree
In-Reply-To: <5217AA15.7010907@ti.com>
On Friday 23 August 2013 02:29 PM, Mugunthan V N wrote:
> On Friday 23 August 2013 11:40 PM, Santosh Shilimkar wrote:
>> On Friday 23 August 2013 01:39 PM, Sekhar Nori wrote:
>>> On 8/23/2013 10:58 PM, Santosh Shilimkar wrote:
>>>> On Friday 23 August 2013 01:24 PM, Daniel Mack wrote:
>>>>> On 23.08.2013 19:19, Santosh Shilimkar wrote:
>>>>>> On Friday 23 August 2013 01:09 PM, Sekhar Nori wrote:
>>>>>>> On 8/23/2013 10:26 PM, Santosh Shilimkar wrote:
>>>>>>>> So just stick the IP version or call it cpsw-v1... cpsw-v2 etc.
>>>>>>> If this could be handled using IP version then the right way would be to
>>>>>>> just read the IP version from hardware and use it. No need of DT property.
>>>>>>>
>>>>>> Thats fine as well but I thought the patch needed additional properties like
>>>>>> CM reg-address come from DT and hence the separate compatible. If you can
>>>>>> manage without that, thats even better.
>>>>> We can't, that's the whole point :)
>>>>>
>>>> I saw that from the patch :)
>>>>
>>>>> Well, theoretically, we could for now, but that's not a clean solution.
>>>>> Again: the problem here is that the control port is separated from the
>>>>> cpsw core, and so we have to implement something specific for the AM3352
>>>>> SoC. I know that's a violation of clean and generic driver ideas, but
>>>>> there's no way we can assume that every cpsw v2 ip block has a control
>>>>> port that is compatible to the one found on am335x chips.
>>>>>
>>>> But there is a possibility that other SOC will just use the same
>>>> control module approach. So using a revision IP is just fine. BTW,
>>> But this is misleading because it makes appear like the same compatible
>>> can be used on on another SoC like DRA7 which probably has the same
>>> version of IP but a different control module implementation, when in
>>> practice it cannot.
>>>
>>> The fact is we are doing something SoC specific in the driver and we
>>> cannot hide that behind IP versions. If really in practice there comes
>>> another SoC with the same control module definition then it can always
>>> use ti,am3352-cpsw compatible as well. The compatible name does not
>>> preclude its usage.
>>>
>> My point was the CPSW needs a feature which is implemented using
>> control module rather than within the IP itself. Its an implementation
>> detail. As such the additional feature makes sense for that IP. O.w
>> there was no need to do any monkeying with control module.
>>
>> E.g
>> MMC card detect is a basic functionality, implemented by various types
>> like control module, PMIC or MMC IP itself. As such the driver need
>> that support and all the implementation details needs to still handled
>> to make that part work.
>>
>>
>
> CPSW core as such understands only GMII/MII signals, there is an
> additional module which converts GMII/MII signals to RGMII/RMII signals
> respectively which is called as CPRGMII/CPRMII as specified in the
> AM335x TRM in Figure 14-1. Ethernet Switch Integration.
>
> So to control this sub-module, the control register is used and this has
> to be configured according to the EVM design like what mode of phy is
> connected. CPRGMII and CPRMII is no way related to CPSW core.
>
Ok then why are you polluting cpsw driver with that code which
not realted to CPSW as you said above. You are contradicting what
you said by supporting the SOC usage in the core CPSW driver.
Regards,
Santosh
^ permalink raw reply
* sendto() bug?
From: Chris Clark @ 2013-08-23 19:19 UTC (permalink / raw)
To: davem; +Cc: netdev
Hi Dave,
I've run across a problem with the sendto() system call that first
appeared with commit f8126f1d:
=================================================================
commit f8126f1d5136be1ca1a3536d43ad7a710b5620f8
Author: David S. Miller <davem@davemloft.net>
Date: Fri Jul 13 05:03:45 2012 -0700
ipv4: Adjust semantics of rt->rt_gateway.
=================================================================
The issue arises when sendto() is used on a SOCK_RAW IP socket opened
with the IP_HDRINCL option. Instead of sending the packet to the
address given explicitly in the sendto() call, the kernel ignores the
given dest_addr and ARPs locally for the destination address given in
the constructed packet's IP header. Because the IP header's
destination address is not on a local subnet, the bogus ARP never
resolves and the packet is never sent.
A subsequent commit addressed a similar problem in netfilter:
=================================================================
commit 2ad5b9e4bd314fc685086b99e90e5de3bc59e26b
Author: Eric Dumazet <eric.dumazet@gmail.com>
Date: Tue Oct 16 22:33:29 2012 +0000
netfilter: xt_TEE: don't use destination address found in header
Torsten Luettgert bisected TEE regression starting with commit
f8126f1d5136be1 (ipv4: Adjust semantics of rt->rt_gateway.)
The problem is that it tries to ARP-lookup the original destination
address of the forwarded packet, not the address of the gateway.
Fix this using FLOWI_FLAG_KNOWN_NH Julian added in commit
c92b96553a80c1 (ipv4: Add FLOWI_FLAG_KNOWN_NH), so that known
nexthop (info->gw.ip) has preference on resolving.
=================================================================
In the same vein as 2ad5b9e4, I'm soliciting feedback on something
similar for raw_sendmsg():
=================================================================
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index dd44e0a..454d9c1 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -571,7 +571,9 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos,
RT_SCOPE_UNIVERSE,
inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol,
- inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP,
+ inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP
+ | ((msg->msg_namelen
+ && (tos & RTO_ONLINK)) ? FLOWI_FLAG_KNOWN_NH : 0),
daddr, saddr, 0, 0);
if (!inet->hdrincl) {
=================================================================
The thought here is to apply the FLOWI_FLAG_KNOWN_NH flag when:
(a) The dest_addr is given explicitly (msg->msg_namelen), and
(b) The socket is in MSG_DONTROUTE mode (tos & RTO_ONLINK).
This change fixes the problem because the FLOWI_FLAG_KNOWN_NH flag
ends up (very indirectly) triggering the following code in
rt_set_nexthop() which sets rt->rt_gateway to the address specified in
the sendto() call, which ultimately causes the packet to be forwarded
to that address rather than wrongly ARPing locally for the (different,
remote) address in the IP header:
=================================================================
if (unlikely(!cached)) {
/* Routes we intend to cache in nexthop exception or
* FIB nexthop have the DST_NOCACHE bit clear.
* However, if we are unsuccessful at storing this
* route into the cache we really need to set it.
*/
rt->dst.flags |= DST_NOCACHE;
if (!rt->rt_gateway)
-> rt->rt_gateway = daddr;
=================================================================
While the diff resolves the particular problem that I encountered, I'm
soliciting feedback because I'm not sure it is necessary and
sufficient beyond my particular test case.
Thanks,
Chris
^ permalink raw reply related
* [PATCH v3 2/2] genl: Hold reference on correct module while netlink-dump.
From: Pravin B Shelar @ 2013-08-23 19:45 UTC (permalink / raw)
To: netdev; +Cc: Pravin B Shelar, Jesse Gross, Johannes Berg
netlink dump operations take module as parameter to hold
reference for entire netlink dump duration.
Currently it holds ref only on genl module which is not correct
when we use ops registered to genl from another module.
Following patch adds module pointer to genl_ops so that netlink
can hold ref count on it.
CC: Jesse Gross <jesse@nicira.com>
CC: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
---
v2-v3:
get rid of extra argument (struct module *).
v1-v2:
No need to ref count genl module.
---
include/net/genetlink.h | 20 ++++++++++++++++++--
net/netlink/genetlink.c | 20 +++++++++++---------
2 files changed, 29 insertions(+), 11 deletions(-)
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index 93024a4..8e0b6c8 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -61,6 +61,7 @@ struct genl_family {
struct list_head ops_list; /* private */
struct list_head family_list; /* private */
struct list_head mcast_groups; /* private */
+ struct module *module;
};
/**
@@ -121,9 +122,24 @@ struct genl_ops {
struct list_head ops_list;
};
-extern int genl_register_family(struct genl_family *family);
-extern int genl_register_family_with_ops(struct genl_family *family,
+extern int __genl_register_family(struct genl_family *family);
+
+static inline int genl_register_family(struct genl_family *family)
+{
+ family->module = THIS_MODULE;
+ return __genl_register_family(family);
+}
+
+extern int __genl_register_family_with_ops(struct genl_family *family,
struct genl_ops *ops, size_t n_ops);
+
+static inline int genl_register_family_with_ops(struct genl_family *family,
+ struct genl_ops *ops, size_t n_ops)
+{
+ family->module = THIS_MODULE;
+ return __genl_register_family_with_ops(family, ops, n_ops);
+}
+
extern int genl_unregister_family(struct genl_family *family);
extern int genl_register_ops(struct genl_family *, struct genl_ops *ops);
extern int genl_unregister_ops(struct genl_family *, struct genl_ops *ops);
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index f09d387..f1c81d5 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -364,7 +364,7 @@ int genl_unregister_ops(struct genl_family *family, struct genl_ops *ops)
EXPORT_SYMBOL(genl_unregister_ops);
/**
- * genl_register_family - register a generic netlink family
+ * __genl_register_family - register a generic netlink family
* @family: generic netlink family
*
* Registers the specified family after validating it first. Only one
@@ -374,7 +374,7 @@ EXPORT_SYMBOL(genl_unregister_ops);
*
* Return 0 on success or a negative error code.
*/
-int genl_register_family(struct genl_family *family)
+int __genl_register_family(struct genl_family *family)
{
int err = -EINVAL;
@@ -430,10 +430,10 @@ errout_locked:
errout:
return err;
}
-EXPORT_SYMBOL(genl_register_family);
+EXPORT_SYMBOL(__genl_register_family);
/**
- * genl_register_family_with_ops - register a generic netlink family
+ * __genl_register_family_with_ops - register a generic netlink family
* @family: generic netlink family
* @ops: operations to be registered
* @n_ops: number of elements to register
@@ -457,12 +457,12 @@ EXPORT_SYMBOL(genl_register_family);
*
* Return 0 on success or a negative error code.
*/
-int genl_register_family_with_ops(struct genl_family *family,
+int __genl_register_family_with_ops(struct genl_family *family,
struct genl_ops *ops, size_t n_ops)
{
int err, i;
- err = genl_register_family(family);
+ err = __genl_register_family(family);
if (err)
return err;
@@ -476,7 +476,7 @@ err_out:
genl_unregister_family(family);
return err;
}
-EXPORT_SYMBOL(genl_register_family_with_ops);
+EXPORT_SYMBOL(__genl_register_family_with_ops);
/**
* genl_unregister_family - unregister generic netlink family
@@ -603,22 +603,24 @@ static int genl_family_rcv_msg(struct genl_family *family,
if (!family->parallel_ops) {
struct netlink_dump_control c = {
+ .module = family->module,
.data = ops,
.dump = genl_lock_dumpit,
.done = genl_lock_done,
};
genl_unlock();
- rc = netlink_dump_start(net->genl_sock, skb, nlh, &c);
+ rc = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
genl_lock();
} else {
struct netlink_dump_control c = {
+ .module = family->module,
.dump = ops->dumpit,
.done = ops->done,
};
- rc = netlink_dump_start(net->genl_sock, skb, nlh, &c);
+ rc = __netlink_dump_start(net->genl_sock, skb, nlh, &c);
}
return rc;
--
1.7.1
^ permalink raw reply related
* [PATCH v3 1/2] genl: Fix genl dumpit() locking.
From: Pravin B Shelar @ 2013-08-23 19:44 UTC (permalink / raw)
To: netdev; +Cc: Pravin B Shelar, Jesse Gross, Johannes Berg
In case of genl-family with parallel ops off, dumpif() callback
is expected to run under genl_lock, But commit def3117493eafd9df
(genl: Allow concurrent genl callbacks.) changed this behaviour
where only first dumpit() op was called under genl-lock.
For subsequent dump, only nlk->cb_lock was taken.
Following patch fixes it by defining locked dumpit() and done()
callback which takes care of genl-locking.
CC: Jesse Gross <jesse@nicira.com>
CC: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
---
v2-v3:
coding style fix.
v1-v2:
No change.
---
net/netlink/genetlink.c | 51 ++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 46 insertions(+), 5 deletions(-)
diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c
index f85f8a2..f09d387 100644
--- a/net/netlink/genetlink.c
+++ b/net/netlink/genetlink.c
@@ -544,6 +544,30 @@ void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq,
}
EXPORT_SYMBOL(genlmsg_put);
+static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct genl_ops *ops = cb->data;
+ int rc;
+
+ genl_lock();
+ rc = ops->dumpit(skb, cb);
+ genl_unlock();
+ return rc;
+}
+
+static int genl_lock_done(struct netlink_callback *cb)
+{
+ struct genl_ops *ops = cb->data;
+ int rc = 0;
+
+ if (ops->done) {
+ genl_lock();
+ rc = ops->done(cb);
+ genl_unlock();
+ }
+ return rc;
+}
+
static int genl_family_rcv_msg(struct genl_family *family,
struct sk_buff *skb,
struct nlmsghdr *nlh)
@@ -572,15 +596,32 @@ static int genl_family_rcv_msg(struct genl_family *family,
return -EPERM;
if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) {
- struct netlink_dump_control c = {
- .dump = ops->dumpit,
- .done = ops->done,
- };
+ int rc;
if (ops->dumpit == NULL)
return -EOPNOTSUPP;
- return netlink_dump_start(net->genl_sock, skb, nlh, &c);
+ if (!family->parallel_ops) {
+ struct netlink_dump_control c = {
+ .data = ops,
+ .dump = genl_lock_dumpit,
+ .done = genl_lock_done,
+ };
+
+ genl_unlock();
+ rc = netlink_dump_start(net->genl_sock, skb, nlh, &c);
+ genl_lock();
+
+ } else {
+ struct netlink_dump_control c = {
+ .dump = ops->dumpit,
+ .done = ops->done,
+ };
+
+ rc = netlink_dump_start(net->genl_sock, skb, nlh, &c);
+ }
+
+ return rc;
}
if (ops->doit == NULL)
--
1.7.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox