* [PATCH 07/13] bluetooth: Convert compare_ether_addr to ether_addr_equal
From: Joe Perches @ 2012-05-09 4:56 UTC (permalink / raw)
To: David S. Miller, linux-kernel-u79uwXL29TY76Z2rM5mHXA
Cc: Marcel Holtmann, Gustavo Padovan, Johan Hedberg,
linux-bluetooth-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <cover.1336538937.git.joe-6d6DIl74uiNBDgjK7y7TUQ@public.gmane.org>
Use the new bool function ether_addr_equal to add
some clarity and reduce the likelihood for misuse
of compare_ether_addr for sorting.
Done via cocci script:
$ cat compare_ether_addr.cocci
@@
expression a,b;
@@
- !compare_ether_addr(a, b)
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- compare_ether_addr(a, b)
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) == 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) != 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) == 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) != 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !!ether_addr_equal(a, b)
+ ether_addr_equal(a, b)
Signed-off-by: Joe Perches <joe-6d6DIl74uiNBDgjK7y7TUQ@public.gmane.org>
---
net/bluetooth/bnep/core.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index a779ec7..88884d1 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -69,7 +69,7 @@ static struct bnep_session *__bnep_get_session(u8 *dst)
BT_DBG("");
list_for_each_entry(s, &bnep_session_list, list)
- if (!compare_ether_addr(dst, s->eh.h_source))
+ if (ether_addr_equal(dst, s->eh.h_source))
return s;
return NULL;
@@ -422,10 +422,10 @@ static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
iv[il++] = (struct kvec) { &type, 1 };
len++;
- if (compress_src && !compare_ether_addr(eh->h_dest, s->eh.h_source))
+ if (compress_src && ether_addr_equal(eh->h_dest, s->eh.h_source))
type |= 0x01;
- if (compress_dst && !compare_ether_addr(eh->h_source, s->eh.h_dest))
+ if (compress_dst && ether_addr_equal(eh->h_source, s->eh.h_dest))
type |= 0x02;
if (type)
--
1.7.8.111.gad25c.dirty
^ permalink raw reply related
* [PATCH 08/13] mac80211: Convert compare_ether_addr to ether_addr_equal
From: Joe Perches @ 2012-05-09 4:56 UTC (permalink / raw)
To: David S. Miller, John W. Linville, Johannes Berg
Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <cover.1336538937.git.joe@perches.com>
Use the new bool function ether_addr_equal to add
some clarity and reduce the likelihood for misuse
of compare_ether_addr for sorting.
Done via cocci script:
$ cat compare_ether_addr.cocci
@@
expression a,b;
@@
- !compare_ether_addr(a, b)
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- compare_ether_addr(a, b)
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) == 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) != 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) == 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) != 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !!ether_addr_equal(a, b)
+ ether_addr_equal(a, b)
Signed-off-by: Joe Perches <joe@perches.com>
---
net/mac80211/cfg.c | 2 +-
net/mac80211/ibss.c | 12 ++++++------
net/mac80211/ieee80211_i.h | 2 +-
net/mac80211/iface.c | 2 +-
net/mac80211/mesh.c | 4 ++--
net/mac80211/mesh_hwmp.c | 14 +++++++-------
net/mac80211/mesh_pathtbl.c | 12 ++++++------
net/mac80211/mlme.c | 29 +++++++++++++----------------
net/mac80211/rx.c | 35 ++++++++++++++++-------------------
net/mac80211/scan.c | 2 +-
net/mac80211/sta_info.c | 8 ++++----
net/mac80211/status.c | 2 +-
net/mac80211/tx.c | 11 +++++------
13 files changed, 64 insertions(+), 71 deletions(-)
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 70b2af2..7e6781f 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -919,7 +919,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
} else
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- if (compare_ether_addr(mac, sdata->vif.addr) == 0)
+ if (ether_addr_equal(mac, sdata->vif.addr))
return -EINVAL;
if (is_multicast_ether_addr(mac))
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 61cd391..d307d3b 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -66,7 +66,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
skb_reset_tail_pointer(skb);
skb_reserve(skb, sdata->local->hw.extra_tx_headroom);
- if (compare_ether_addr(ifibss->bssid, bssid))
+ if (!ether_addr_equal(ifibss->bssid, bssid))
sta_info_flush(sdata->local, sdata);
/* if merging, indicate to driver that we leave the old IBSS */
@@ -315,7 +315,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
return NULL;
}
- if (compare_ether_addr(bssid, sdata->u.ibss.bssid)) {
+ if (!ether_addr_equal(bssid, sdata->u.ibss.bssid)) {
rcu_read_lock();
return NULL;
}
@@ -401,7 +401,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
return;
if (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
- compare_ether_addr(mgmt->bssid, sdata->u.ibss.bssid) == 0) {
+ ether_addr_equal(mgmt->bssid, sdata->u.ibss.bssid)) {
rcu_read_lock();
sta = sta_info_get(sdata, mgmt->sa);
@@ -506,7 +506,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
goto put_bss;
/* same BSSID */
- if (compare_ether_addr(cbss->bssid, sdata->u.ibss.bssid) == 0)
+ if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid))
goto put_bss;
if (rx_status->flag & RX_FLAG_MACTIME_MPDU) {
@@ -591,7 +591,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
if (ifibss->state == IEEE80211_IBSS_MLME_SEARCH)
return;
- if (compare_ether_addr(bssid, sdata->u.ibss.bssid))
+ if (!ether_addr_equal(bssid, sdata->u.ibss.bssid))
return;
sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
@@ -829,7 +829,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da))
return;
- if (compare_ether_addr(mgmt->bssid, ifibss->bssid) != 0 &&
+ if (!ether_addr_equal(mgmt->bssid, ifibss->bssid) &&
!is_broadcast_ether_addr(mgmt->bssid))
return;
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6cd89d4..fabee97 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1195,7 +1195,7 @@ static inline struct ieee80211_local *hw_to_local(
static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
{
- return compare_ether_addr(raddr, addr) == 0 ||
+ return ether_addr_equal(raddr, addr) ||
is_broadcast_ether_addr(raddr);
}
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 3e05a8b..856237c 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -127,7 +127,7 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
* The remaining checks are only performed for interfaces
* with the same MAC address.
*/
- if (compare_ether_addr(dev->dev_addr, ndev->dev_addr))
+ if (!ether_addr_equal(dev->dev_addr, ndev->dev_addr))
continue;
/*
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 598a96a..7756271 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -209,7 +209,7 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr,
kmem_cache_free(rm_cache, p);
--entries;
} else if ((seqnum == p->seqnum) &&
- (compare_ether_addr(sa, p->sa) == 0))
+ (ether_addr_equal(sa, p->sa)))
return -1;
}
@@ -639,7 +639,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
/* ignore ProbeResp to foreign address */
if (stype == IEEE80211_STYPE_PROBE_RESP &&
- compare_ether_addr(mgmt->da, sdata->vif.addr))
+ !ether_addr_equal(mgmt->da, sdata->vif.addr))
return;
baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 503016f..27e0c2f 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -422,7 +422,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
new_metric = MAX_METRIC;
exp_time = TU_TO_EXP_TIME(orig_lifetime);
- if (compare_ether_addr(orig_addr, sdata->vif.addr) == 0) {
+ if (ether_addr_equal(orig_addr, sdata->vif.addr)) {
/* This MP is the originator, we are not interested in this
* frame, except for updating transmitter's path info.
*/
@@ -472,7 +472,7 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata,
/* Update and check transmitter routing info */
ta = mgmt->sa;
- if (compare_ether_addr(orig_addr, ta) == 0)
+ if (ether_addr_equal(orig_addr, ta))
fresh_info = false;
else {
fresh_info = true;
@@ -533,7 +533,7 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata,
mhwmp_dbg("received PREQ from %pM", orig_addr);
- if (compare_ether_addr(target_addr, sdata->vif.addr) == 0) {
+ if (ether_addr_equal(target_addr, sdata->vif.addr)) {
mhwmp_dbg("PREQ is for us");
forward = false;
reply = true;
@@ -631,7 +631,7 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem));
orig_addr = PREP_IE_ORIG_ADDR(prep_elem);
- if (compare_ether_addr(orig_addr, sdata->vif.addr) == 0)
+ if (ether_addr_equal(orig_addr, sdata->vif.addr))
/* destination, no forwarding required */
return;
@@ -709,7 +709,7 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
spin_lock_bh(&mpath->state_lock);
sta = next_hop_deref_protected(mpath);
if (mpath->flags & MESH_PATH_ACTIVE &&
- compare_ether_addr(ta, sta->sta.addr) == 0 &&
+ ether_addr_equal(ta, sta->sta.addr) &&
(!(mpath->flags & MESH_PATH_SN_VALID) ||
SN_GT(target_sn, mpath->sn))) {
mpath->flags &= ~MESH_PATH_ACTIVE;
@@ -756,7 +756,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
metric = le32_to_cpu(rann->rann_metric);
/* Ignore our own RANNs */
- if (compare_ether_addr(orig_addr, sdata->vif.addr) == 0)
+ if (ether_addr_equal(orig_addr, sdata->vif.addr))
return;
mhwmp_dbg("received RANN from %pM via neighbour %pM (is_gate=%d)",
@@ -1099,7 +1099,7 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
if (time_after(jiffies,
mpath->exp_time -
msecs_to_jiffies(sdata->u.mesh.mshcfg.path_refresh_time)) &&
- !compare_ether_addr(sdata->vif.addr, hdr->addr4) &&
+ ether_addr_equal(sdata->vif.addr, hdr->addr4) &&
!(mpath->flags & MESH_PATH_RESOLVING) &&
!(mpath->flags & MESH_PATH_FIXED))
mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH);
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index baa6096..b39224d 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -348,7 +348,7 @@ static struct mesh_path *mpath_lookup(struct mesh_table *tbl, u8 *dst,
hlist_for_each_entry_rcu(node, n, bucket, list) {
mpath = node->mpath;
if (mpath->sdata == sdata &&
- compare_ether_addr(dst, mpath->dst) == 0) {
+ ether_addr_equal(dst, mpath->dst)) {
if (MPATH_EXPIRED(mpath)) {
spin_lock_bh(&mpath->state_lock);
mpath->flags &= ~MESH_PATH_ACTIVE;
@@ -517,7 +517,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
int err = 0;
u32 hash_idx;
- if (compare_ether_addr(dst, sdata->vif.addr) == 0)
+ if (ether_addr_equal(dst, sdata->vif.addr))
/* never add ourselves as neighbours */
return -ENOTSUPP;
@@ -561,7 +561,7 @@ int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata)
hlist_for_each_entry(node, n, bucket, list) {
mpath = node->mpath;
if (mpath->sdata == sdata &&
- compare_ether_addr(dst, mpath->dst) == 0)
+ ether_addr_equal(dst, mpath->dst))
goto err_exists;
}
@@ -652,7 +652,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
int err = 0;
u32 hash_idx;
- if (compare_ether_addr(dst, sdata->vif.addr) == 0)
+ if (ether_addr_equal(dst, sdata->vif.addr))
/* never add ourselves as neighbours */
return -ENOTSUPP;
@@ -690,7 +690,7 @@ int mpp_path_add(u8 *dst, u8 *mpp, struct ieee80211_sub_if_data *sdata)
hlist_for_each_entry(node, n, bucket, list) {
mpath = node->mpath;
if (mpath->sdata == sdata &&
- compare_ether_addr(dst, mpath->dst) == 0)
+ ether_addr_equal(dst, mpath->dst))
goto err_exists;
}
@@ -884,7 +884,7 @@ int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata)
hlist_for_each_entry(node, n, bucket, list) {
mpath = node->mpath;
if (mpath->sdata == sdata &&
- compare_ether_addr(addr, mpath->dst) == 0) {
+ ether_addr_equal(addr, mpath->dst)) {
__mesh_path_del(tbl, node);
goto enddel;
}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 03f93f9..b1c617f 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1776,7 +1776,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
memcpy(bssid, ifmgd->auth_data->bss->bssid, ETH_ALEN);
- if (compare_ether_addr(bssid, mgmt->bssid))
+ if (!ether_addr_equal(bssid, mgmt->bssid))
return RX_MGMT_NONE;
auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
@@ -1853,7 +1853,7 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
return RX_MGMT_NONE;
if (!ifmgd->associated ||
- compare_ether_addr(mgmt->bssid, ifmgd->associated->bssid))
+ !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
return RX_MGMT_NONE;
bssid = ifmgd->associated->bssid;
@@ -1886,7 +1886,7 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
return RX_MGMT_NONE;
if (!ifmgd->associated ||
- compare_ether_addr(mgmt->bssid, ifmgd->associated->bssid))
+ !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
return RX_MGMT_NONE;
reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
@@ -2113,7 +2113,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
if (!assoc_data)
return RX_MGMT_NONE;
- if (compare_ether_addr(assoc_data->bss->bssid, mgmt->bssid))
+ if (!ether_addr_equal(assoc_data->bss->bssid, mgmt->bssid))
return RX_MGMT_NONE;
/*
@@ -2193,8 +2193,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
bool need_ps = false;
if (sdata->u.mgd.associated &&
- compare_ether_addr(mgmt->bssid, sdata->u.mgd.associated->bssid)
- == 0) {
+ ether_addr_equal(mgmt->bssid, sdata->u.mgd.associated->bssid)) {
bss = (void *)sdata->u.mgd.associated->priv;
/* not previously set so we may need to recalc */
need_ps = !bss->dtim_period;
@@ -2249,7 +2248,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
ASSERT_MGD_MTX(ifmgd);
- if (compare_ether_addr(mgmt->da, sdata->vif.addr))
+ if (!ether_addr_equal(mgmt->da, sdata->vif.addr))
return; /* ignore ProbeResp to foreign address */
baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
@@ -2262,12 +2261,11 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
if (ifmgd->associated &&
- compare_ether_addr(mgmt->bssid, ifmgd->associated->bssid) == 0)
+ ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
ieee80211_reset_ap_probe(sdata);
if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies &&
- compare_ether_addr(mgmt->bssid, ifmgd->auth_data->bss->bssid)
- == 0) {
+ ether_addr_equal(mgmt->bssid, ifmgd->auth_data->bss->bssid)) {
/* got probe response, continue with auth */
printk(KERN_DEBUG "%s: direct probe responded\n", sdata->name);
ifmgd->auth_data->tries = 0;
@@ -2324,8 +2322,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
return;
if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon &&
- compare_ether_addr(mgmt->bssid, ifmgd->assoc_data->bss->bssid)
- == 0) {
+ ether_addr_equal(mgmt->bssid, ifmgd->assoc_data->bss->bssid)) {
ieee802_11_parse_elems(mgmt->u.beacon.variable,
len - baselen, &elems);
@@ -2340,7 +2337,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
}
if (!ifmgd->associated ||
- compare_ether_addr(mgmt->bssid, ifmgd->associated->bssid))
+ !ether_addr_equal(mgmt->bssid, ifmgd->associated->bssid))
return;
bssid = ifmgd->associated->bssid;
@@ -3166,7 +3163,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
return err;
}
} else
- WARN_ON_ONCE(compare_ether_addr(ifmgd->bssid, cbss->bssid));
+ WARN_ON_ONCE(!ether_addr_equal(ifmgd->bssid, cbss->bssid));
return 0;
}
@@ -3306,7 +3303,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
bool match;
/* keep sta info, bssid if matching */
- match = compare_ether_addr(ifmgd->bssid, req->bss->bssid) == 0;
+ match = ether_addr_equal(ifmgd->bssid, req->bss->bssid);
ieee80211_destroy_auth_data(sdata, match);
}
@@ -3466,7 +3463,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
sdata->name, req->bssid, req->reason_code);
if (ifmgd->associated &&
- compare_ether_addr(ifmgd->associated->bssid, req->bssid) == 0)
+ ether_addr_equal(ifmgd->associated->bssid, req->bssid))
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
req->reason_code, true, frame_buf);
else
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index d5ac02f..26bfd6f 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -492,12 +492,12 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
if (ieee80211_has_tods(hdr->frame_control) ||
!ieee80211_has_fromds(hdr->frame_control))
return RX_DROP_MONITOR;
- if (compare_ether_addr(hdr->addr3, dev_addr) == 0)
+ if (ether_addr_equal(hdr->addr3, dev_addr))
return RX_DROP_MONITOR;
} else {
if (!ieee80211_has_a4(hdr->frame_control))
return RX_DROP_MONITOR;
- if (compare_ether_addr(hdr->addr4, dev_addr) == 0)
+ if (ether_addr_equal(hdr->addr4, dev_addr))
return RX_DROP_MONITOR;
}
}
@@ -1275,7 +1275,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
NL80211_IFTYPE_ADHOC);
- if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0) {
+ if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid)) {
sta->last_rx = jiffies;
if (ieee80211_is_data(hdr->frame_control)) {
sta->last_rx_rate_idx = status->rate_idx;
@@ -1438,8 +1438,8 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
*/
if (((hdr->frame_control ^ f_hdr->frame_control) &
cpu_to_le16(IEEE80211_FCTL_FTYPE)) ||
- compare_ether_addr(hdr->addr1, f_hdr->addr1) != 0 ||
- compare_ether_addr(hdr->addr2, f_hdr->addr2) != 0)
+ !ether_addr_equal(hdr->addr1, f_hdr->addr1) ||
+ !ether_addr_equal(hdr->addr2, f_hdr->addr2))
continue;
if (time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
@@ -1925,7 +1925,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
mpp_path_add(proxied_addr, mpp_addr, sdata);
} else {
spin_lock_bh(&mppath->state_lock);
- if (compare_ether_addr(mppath->mpp, mpp_addr) != 0)
+ if (!ether_addr_equal(mppath->mpp, mpp_addr))
memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
spin_unlock_bh(&mppath->state_lock);
}
@@ -1934,7 +1934,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
/* Frame has reached destination. Don't forward */
if (!is_multicast_ether_addr(hdr->addr1) &&
- compare_ether_addr(sdata->vif.addr, hdr->addr3) == 0)
+ ether_addr_equal(sdata->vif.addr, hdr->addr3))
return RX_CONTINUE;
q = ieee80211_select_queue_80211(local, skb, hdr);
@@ -2122,13 +2122,13 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb;
struct ieee80211_mgmt *resp;
- if (compare_ether_addr(mgmt->da, sdata->vif.addr) != 0) {
+ if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) {
/* Not to own unicast address */
return;
}
- if (compare_ether_addr(mgmt->sa, sdata->u.mgd.bssid) != 0 ||
- compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid) != 0) {
+ if (!ether_addr_equal(mgmt->sa, sdata->u.mgd.bssid) ||
+ !ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid)) {
/* Not from the current AP or not associated yet. */
return;
}
@@ -2338,7 +2338,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
if (sdata->vif.type != NL80211_IFTYPE_STATION)
break;
- if (compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid))
+ if (!ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid))
break;
goto queue;
@@ -2772,7 +2772,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
if (!bssid && !sdata->u.mgd.use_4addr)
return 0;
if (!multicast &&
- compare_ether_addr(sdata->vif.addr, hdr->addr1) != 0) {
+ !ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
if (!(sdata->dev->flags & IFF_PROMISC) ||
sdata->u.mgd.use_4addr)
return 0;
@@ -2790,8 +2790,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
return 0;
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
} else if (!multicast &&
- compare_ether_addr(sdata->vif.addr,
- hdr->addr1) != 0) {
+ !ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
@@ -2807,8 +2806,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
break;
case NL80211_IFTYPE_MESH_POINT:
if (!multicast &&
- compare_ether_addr(sdata->vif.addr,
- hdr->addr1) != 0) {
+ !ether_addr_equal(sdata->vif.addr, hdr->addr1)) {
if (!(sdata->dev->flags & IFF_PROMISC))
return 0;
@@ -2818,8 +2816,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_AP:
if (!bssid) {
- if (compare_ether_addr(sdata->vif.addr,
- hdr->addr1))
+ if (!ether_addr_equal(sdata->vif.addr, hdr->addr1))
return 0;
} else if (!ieee80211_bssid_match(bssid,
sdata->vif.addr)) {
@@ -2841,7 +2838,7 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
case NL80211_IFTYPE_WDS:
if (bssid || !ieee80211_is_data(hdr->frame_control))
return 0;
- if (compare_ether_addr(sdata->u.wds.remote_addr, hdr->addr2))
+ if (!ether_addr_equal(sdata->u.wds.remote_addr, hdr->addr2))
return 0;
break;
default:
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 8282284..169da07 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -194,7 +194,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
presp = ieee80211_is_probe_resp(fc);
if (presp) {
/* ignore ProbeResp to foreign address */
- if (compare_ether_addr(mgmt->da, sdata->vif.addr))
+ if (!ether_addr_equal(mgmt->da, sdata->vif.addr))
return RX_DROP_MONITOR;
presp = true;
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 97a9d66..f5b1638 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -102,7 +102,7 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
lockdep_is_held(&local->sta_mtx));
while (sta) {
if (sta->sdata == sdata &&
- compare_ether_addr(sta->sta.addr, addr) == 0)
+ ether_addr_equal(sta->sta.addr, addr))
break;
sta = rcu_dereference_check(sta->hnext,
lockdep_is_held(&local->sta_mtx));
@@ -125,7 +125,7 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
while (sta) {
if ((sta->sdata == sdata ||
(sta->sdata->bss && sta->sdata->bss == sdata->bss)) &&
- compare_ether_addr(sta->sta.addr, addr) == 0)
+ ether_addr_equal(sta->sta.addr, addr))
break;
sta = rcu_dereference_check(sta->hnext,
lockdep_is_held(&local->sta_mtx));
@@ -302,7 +302,7 @@ static int sta_info_insert_check(struct sta_info *sta)
if (unlikely(!ieee80211_sdata_running(sdata)))
return -ENETDOWN;
- if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->vif.addr) == 0 ||
+ if (WARN_ON(ether_addr_equal(sta->sta.addr, sdata->vif.addr) ||
is_multicast_ether_addr(sta->sta.addr)))
return -EINVAL;
@@ -912,7 +912,7 @@ struct ieee80211_sta *ieee80211_find_sta_by_ifaddr(struct ieee80211_hw *hw,
*/
for_each_sta_info(hw_to_local(hw), addr, sta, nxt) {
if (localaddr &&
- compare_ether_addr(sta->sdata->vif.addr, localaddr) != 0)
+ !ether_addr_equal(sta->sdata->vif.addr, localaddr))
continue;
if (!sta->uploaded)
return NULL;
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 05f257a..28cfa98 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -384,7 +384,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
for_each_sta_info(local, hdr->addr1, sta, tmp) {
/* skip wrong virtual interface */
- if (compare_ether_addr(hdr->addr2, sta->sdata->vif.addr))
+ if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr))
continue;
if (info->flags & IEEE80211_TX_STATUS_EOSP)
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index d67d36f..e03abc7 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1665,7 +1665,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
skb->len >= len_rthdr + hdrlen + sizeof(rfc1042_header) + 2) {
u8 *payload = (u8 *)hdr + hdrlen;
- if (compare_ether_addr(payload, rfc1042_header) == 0)
+ if (ether_addr_equal(payload, rfc1042_header))
skb->protocol = cpu_to_be16((payload[6] << 8) |
payload[7]);
}
@@ -1698,7 +1698,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
tmp_sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
tmp_sdata->vif.type == NL80211_IFTYPE_WDS)
continue;
- if (compare_ether_addr(tmp_sdata->vif.addr, hdr->addr2) == 0) {
+ if (ether_addr_equal(tmp_sdata->vif.addr, hdr->addr2)) {
sdata = tmp_sdata;
break;
}
@@ -1815,9 +1815,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
* is being proxied by a portal (i.e. portal address
* differs from proxied address)
*/
- if (compare_ether_addr(sdata->vif.addr,
- skb->data + ETH_ALEN) == 0 &&
- !(mppath && compare_ether_addr(mppath->mpp, skb->data))) {
+ if (ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN) &&
+ !(mppath && !ether_addr_equal(mppath->mpp, skb->data))) {
hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
skb->data, skb->data + ETH_ALEN);
rcu_read_unlock();
@@ -1964,7 +1963,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) &&
!is_multicast_ether_addr(hdr.addr1) && !authorized &&
(cpu_to_be16(ethertype) != sdata->control_port_protocol ||
- compare_ether_addr(sdata->vif.addr, skb->data + ETH_ALEN)))) {
+ !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: dropped frame to %pM"
--
1.7.8.111.gad25c.dirty
^ permalink raw reply related
* [PATCH 09/13] mac80211: Convert compare_ether_addr to ether_addr_equal by hand
From: Joe Perches @ 2012-05-09 4:56 UTC (permalink / raw)
To: David S. Miller, John W. Linville, Johannes Berg
Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <cover.1336538937.git.joe@perches.com>
spatch/coccinelle isn't perfect. It doesn't understand
__aligned(x) and doesn't convert functions it can't parse.
Convert the remaining compare_ether_addr uses.
Signed-off-by: Joe Perches <joe@perches.com>
---
net/mac80211/rx.c | 4 ++--
net/mac80211/sta_info.h | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 26bfd6f..d722c40 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1714,8 +1714,8 @@ static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx, __le16 fc)
* of whether the frame was encrypted or not.
*/
if (ehdr->h_proto == rx->sdata->control_port_protocol &&
- (compare_ether_addr(ehdr->h_dest, rx->sdata->vif.addr) == 0 ||
- compare_ether_addr(ehdr->h_dest, pae_group_addr) == 0))
+ (ether_addr_equal(ehdr->h_dest, rx->sdata->vif.addr) ||
+ ether_addr_equal(ehdr->h_dest, pae_group_addr)))
return true;
if (ieee80211_802_1x_port_control(rx) ||
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index f75f5d9..e920b22 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -501,7 +501,7 @@ void for_each_sta_info_type_check(struct ieee80211_local *local,
nxt = _sta ? rcu_dereference(_sta->hnext) : NULL \
) \
/* compare address and run code only if it matches */ \
- if (compare_ether_addr(_sta->sta.addr, (_addr)) == 0)
+ if (ether_addr_equal(_sta->sta.addr, (_addr)))
/*
* Get STA info by index, BROKEN!
--
1.7.8.111.gad25c.dirty
^ permalink raw reply related
* [PATCH 10/13] netfilter: Convert compare_ether_addr to ether_addr_equal
From: Joe Perches @ 2012-05-09 4:56 UTC (permalink / raw)
To: David S. Miller, Pablo Neira Ayuso, Patrick McHardy
Cc: netfilter-devel, netfilter, coreteam, netdev, linux-kernel
In-Reply-To: <cover.1336538937.git.joe@perches.com>
Use the new bool function ether_addr_equal to add
some clarity and reduce the likelihood for misuse
of compare_ether_addr for sorting.
Done via cocci script:
$ cat compare_ether_addr.cocci
@@
expression a,b;
@@
- !compare_ether_addr(a, b)
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- compare_ether_addr(a, b)
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) == 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) != 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) == 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) != 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !!ether_addr_equal(a, b)
+ ether_addr_equal(a, b)
Signed-off-by: Joe Perches <joe@perches.com>
---
net/netfilter/ipset/ip_set_bitmap_ipmac.c | 4 ++--
net/netfilter/xt_mac.c | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
index 0bb16c4..d7eaf10 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
@@ -111,7 +111,7 @@ bitmap_ipmac_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
return -EAGAIN;
case MAC_FILLED:
return data->ether == NULL ||
- compare_ether_addr(data->ether, elem->ether) == 0;
+ ether_addr_equal(data->ether, elem->ether);
}
return 0;
}
@@ -225,7 +225,7 @@ bitmap_ipmac_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
return -EAGAIN;
case MAC_FILLED:
return (data->ether == NULL ||
- compare_ether_addr(data->ether, elem->ether) == 0) &&
+ ether_addr_equal(data->ether, elem->ether)) &&
!bitmap_expired(map, data->id);
}
return 0;
diff --git a/net/netfilter/xt_mac.c b/net/netfilter/xt_mac.c
index 8160f6b..d5b4fd4 100644
--- a/net/netfilter/xt_mac.c
+++ b/net/netfilter/xt_mac.c
@@ -36,7 +36,7 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par)
return false;
if (skb_mac_header(skb) + ETH_HLEN > skb->data)
return false;
- ret = compare_ether_addr(eth_hdr(skb)->h_source, info->srcaddr) == 0;
+ ret = ether_addr_equal(eth_hdr(skb)->h_source, info->srcaddr);
ret ^= info->invert;
return ret;
}
--
1.7.8.111.gad25c.dirty
^ permalink raw reply related
* [PATCH 11/13] wireless: Convert compare_ether_addr to ether_addr_equal
From: Joe Perches @ 2012-05-09 4:56 UTC (permalink / raw)
To: David S. Miller, Johannes Berg, John W. Linville
Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <cover.1336538937.git.joe@perches.com>
Use the new bool function ether_addr_equal to add
some clarity and reduce the likelihood for misuse
of compare_ether_addr for sorting.
I removed a conversion from scan.c/cmp_bss_core
that appears to be a sorting function.
Done via cocci script:
$ cat compare_ether_addr.cocci
@@
expression a,b;
@@
- !compare_ether_addr(a, b)
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- compare_ether_addr(a, b)
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) == 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) != 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) == 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) != 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !!ether_addr_equal(a, b)
+ ether_addr_equal(a, b)
Signed-off-by: Joe Perches <joe@perches.com>
---
net/wireless/ibss.c | 2 +-
net/wireless/mlme.c | 31 +++++++++++++++----------------
net/wireless/scan.c | 2 +-
net/wireless/util.c | 5 ++---
net/wireless/wext-sme.c | 2 +-
net/wireless/wext-spy.c | 2 +-
6 files changed, 21 insertions(+), 23 deletions(-)
diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c
index 30f20fe..d2a19b0 100644
--- a/net/wireless/ibss.c
+++ b/net/wireless/ibss.c
@@ -473,7 +473,7 @@ int cfg80211_ibss_wext_siwap(struct net_device *dev,
/* fixed already - and no change */
if (wdev->wext.ibss.bssid && bssid &&
- compare_ether_addr(bssid, wdev->wext.ibss.bssid) == 0)
+ ether_addr_equal(bssid, wdev->wext.ibss.bssid))
return 0;
wdev_lock(wdev);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 6801d96..eb90988 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -101,7 +101,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
ASSERT_WDEV_LOCK(wdev);
if (wdev->current_bss &&
- compare_ether_addr(wdev->current_bss->pub.bssid, bssid) == 0) {
+ ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
cfg80211_unhold_bss(wdev->current_bss);
cfg80211_put_bss(&wdev->current_bss->pub);
wdev->current_bss = NULL;
@@ -116,7 +116,7 @@ void __cfg80211_send_deauth(struct net_device *dev,
reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
- from_ap = compare_ether_addr(mgmt->sa, dev->dev_addr) != 0;
+ from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr);
__cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
} else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
__cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
@@ -155,7 +155,7 @@ void __cfg80211_send_disassoc(struct net_device *dev,
return;
if (wdev->current_bss &&
- compare_ether_addr(wdev->current_bss->pub.bssid, bssid) == 0) {
+ ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
cfg80211_sme_disassoc(dev, wdev->current_bss);
cfg80211_unhold_bss(wdev->current_bss);
cfg80211_put_bss(&wdev->current_bss->pub);
@@ -166,7 +166,7 @@ void __cfg80211_send_disassoc(struct net_device *dev,
reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
- from_ap = compare_ether_addr(mgmt->sa, dev->dev_addr) != 0;
+ from_ap = !ether_addr_equal(mgmt->sa, dev->dev_addr);
__cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
}
EXPORT_SYMBOL(__cfg80211_send_disassoc);
@@ -286,7 +286,7 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
return -EINVAL;
if (wdev->current_bss &&
- compare_ether_addr(bssid, wdev->current_bss->pub.bssid) == 0)
+ ether_addr_equal(bssid, wdev->current_bss->pub.bssid))
return -EALREADY;
memset(&req, 0, sizeof(req));
@@ -363,7 +363,7 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
memset(&req, 0, sizeof(req));
if (wdev->current_bss && prev_bssid &&
- compare_ether_addr(wdev->current_bss->pub.bssid, prev_bssid) == 0) {
+ ether_addr_equal(wdev->current_bss->pub.bssid, prev_bssid)) {
/*
* Trying to reassociate: Allow this to proceed and let the old
* association to be dropped when the new one is completed.
@@ -447,8 +447,7 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
if (local_state_change) {
if (wdev->current_bss &&
- compare_ether_addr(wdev->current_bss->pub.bssid, bssid)
- == 0) {
+ ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
cfg80211_unhold_bss(wdev->current_bss);
cfg80211_put_bss(&wdev->current_bss->pub);
wdev->current_bss = NULL;
@@ -497,7 +496,7 @@ static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
req.local_state_change = local_state_change;
req.ie = ie;
req.ie_len = ie_len;
- if (compare_ether_addr(wdev->current_bss->pub.bssid, bssid) == 0)
+ if (ether_addr_equal(wdev->current_bss->pub.bssid, bssid))
req.bss = &wdev->current_bss->pub;
else
return -ENOTCONN;
@@ -760,8 +759,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
break;
}
- if (compare_ether_addr(wdev->current_bss->pub.bssid,
- mgmt->bssid)) {
+ if (!ether_addr_equal(wdev->current_bss->pub.bssid,
+ mgmt->bssid)) {
err = -ENOTCONN;
break;
}
@@ -774,8 +773,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
break;
/* for station, check that DA is the AP */
- if (compare_ether_addr(wdev->current_bss->pub.bssid,
- mgmt->da)) {
+ if (!ether_addr_equal(wdev->current_bss->pub.bssid,
+ mgmt->da)) {
err = -ENOTCONN;
break;
}
@@ -783,11 +782,11 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
case NL80211_IFTYPE_AP_VLAN:
- if (compare_ether_addr(mgmt->bssid, dev->dev_addr))
+ if (!ether_addr_equal(mgmt->bssid, dev->dev_addr))
err = -EINVAL;
break;
case NL80211_IFTYPE_MESH_POINT:
- if (compare_ether_addr(mgmt->sa, mgmt->bssid)) {
+ if (!ether_addr_equal(mgmt->sa, mgmt->bssid)) {
err = -EINVAL;
break;
}
@@ -806,7 +805,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
return err;
}
- if (compare_ether_addr(mgmt->sa, dev->dev_addr) != 0)
+ if (!ether_addr_equal(mgmt->sa, dev->dev_addr))
return -EINVAL;
/* Transmit the Action frame as requested by user space */
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index 1442bb6..26d96d7 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -281,7 +281,7 @@ static bool is_bss(struct cfg80211_bss *a,
{
const u8 *ssidie;
- if (bssid && compare_ether_addr(a->bssid, bssid))
+ if (bssid && !ether_addr_equal(a->bssid, bssid))
return false;
if (!ssid)
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 6cba001..3ba366f 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -609,10 +609,9 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
payload = frame->data;
ethertype = (payload[6] << 8) | payload[7];
- if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
+ if (likely((ether_addr_equal(payload, rfc1042_header) &&
ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
- compare_ether_addr(payload,
- bridge_tunnel_header) == 0)) {
+ ether_addr_equal(payload, bridge_tunnel_header))) {
/* remove RFC1042 or Bridge-Tunnel
* encapsulation and replace EtherType */
skb_pull(frame, 6);
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
index 7c01c2f..7decbd3 100644
--- a/net/wireless/wext-sme.c
+++ b/net/wireless/wext-sme.c
@@ -276,7 +276,7 @@ int cfg80211_mgd_wext_siwap(struct net_device *dev,
/* fixed already - and no change */
if (wdev->wext.connect.bssid && bssid &&
- compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
+ ether_addr_equal(bssid, wdev->wext.connect.bssid))
goto out;
err = __cfg80211_disconnect(rdev, dev,
diff --git a/net/wireless/wext-spy.c b/net/wireless/wext-spy.c
index 5d643a5..33bef22 100644
--- a/net/wireless/wext-spy.c
+++ b/net/wireless/wext-spy.c
@@ -203,7 +203,7 @@ void wireless_spy_update(struct net_device * dev,
/* Update all records that match */
for (i = 0; i < spydata->spy_number; i++)
- if (!compare_ether_addr(address, spydata->spy_address[i])) {
+ if (ether_addr_equal(address, spydata->spy_address[i])) {
memcpy(&(spydata->spy_stat[i]), wstats,
sizeof(struct iw_quality));
match = i;
--
1.7.8.111.gad25c.dirty
^ permalink raw reply related
* [PATCH 12/13] wireless: Convert compare_ether_addr to ether_addr_equal by hand
From: Joe Perches @ 2012-05-09 4:56 UTC (permalink / raw)
To: David S. Miller, Johannes Berg, John W. Linville
Cc: linux-wireless, netdev, linux-kernel
In-Reply-To: <cover.1336538937.git.joe@perches.com>
spatch/coccinelle isn't perfect. It doesn't understand
__aligned(x) and doesn't convert functions it can't parse.
Convert the remaining compare_ether_addr uses.
Signed-off-by: Joe Perches <joe@perches.com>
---
net/wireless/util.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 3ba366f..1cd2558 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -370,7 +370,7 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
iftype != NL80211_IFTYPE_P2P_CLIENT &&
iftype != NL80211_IFTYPE_MESH_POINT) ||
(is_multicast_ether_addr(dst) &&
- !compare_ether_addr(src, addr)))
+ ether_addr_equal(src, addr)))
return -1;
if (iftype == NL80211_IFTYPE_MESH_POINT) {
struct ieee80211s_hdr *meshdr =
@@ -398,9 +398,9 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
payload = skb->data + hdrlen;
ethertype = (payload[6] << 8) | payload[7];
- if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
+ if (likely((ether_addr_equal(payload, rfc1042_header) &&
ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
- compare_ether_addr(payload, bridge_tunnel_header) == 0)) {
+ ether_addr_equal(payload, bridge_tunnel_header))) {
/* remove RFC1042 or Bridge-Tunnel encapsulation and
* replace EtherType */
skb_pull(skb, hdrlen + 6);
--
1.7.8.111.gad25c.dirty
^ permalink raw reply related
* [PATCH 13/13] dsa: Convert compare_ether_addr to ether_addr_equal
From: Joe Perches @ 2012-05-09 4:56 UTC (permalink / raw)
To: David S. Miller, linux-kernel; +Cc: netdev
In-Reply-To: <cover.1336538937.git.joe@perches.com>
Use the new bool function ether_addr_equal to add
some clarity and reduce the likelihood for misuse
of compare_ether_addr for sorting.
Done via cocci script:
$ cat compare_ether_addr.cocci
@@
expression a,b;
@@
- !compare_ether_addr(a, b)
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- compare_ether_addr(a, b)
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) == 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !ether_addr_equal(a, b) != 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) == 0
+ !ether_addr_equal(a, b)
@@
expression a,b;
@@
- ether_addr_equal(a, b) != 0
+ ether_addr_equal(a, b)
@@
expression a,b;
@@
- !!ether_addr_equal(a, b)
+ ether_addr_equal(a, b)
Signed-off-by: Joe Perches <joe@perches.com>
---
net/dsa/slave.c | 10 +++++-----
1 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 56cf9b8..e32083d 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -66,7 +66,7 @@ static int dsa_slave_open(struct net_device *dev)
if (!(master->flags & IFF_UP))
return -ENETDOWN;
- if (compare_ether_addr(dev->dev_addr, master->dev_addr)) {
+ if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) {
err = dev_uc_add(master, dev->dev_addr);
if (err < 0)
goto out;
@@ -89,7 +89,7 @@ clear_allmulti:
if (dev->flags & IFF_ALLMULTI)
dev_set_allmulti(master, -1);
del_unicast:
- if (compare_ether_addr(dev->dev_addr, master->dev_addr))
+ if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
dev_uc_del(master, dev->dev_addr);
out:
return err;
@@ -107,7 +107,7 @@ static int dsa_slave_close(struct net_device *dev)
if (dev->flags & IFF_PROMISC)
dev_set_promiscuity(master, -1);
- if (compare_ether_addr(dev->dev_addr, master->dev_addr))
+ if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
dev_uc_del(master, dev->dev_addr);
return 0;
@@ -146,13 +146,13 @@ static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
if (!(dev->flags & IFF_UP))
goto out;
- if (compare_ether_addr(addr->sa_data, master->dev_addr)) {
+ if (!ether_addr_equal(addr->sa_data, master->dev_addr)) {
err = dev_uc_add(master, addr->sa_data);
if (err < 0)
return err;
}
- if (compare_ether_addr(dev->dev_addr, master->dev_addr))
+ if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
dev_uc_del(master, dev->dev_addr);
out:
--
1.7.8.111.gad25c.dirty
^ permalink raw reply related
* Re: ipctl - new tool for efficient read/write of net related sysctl
From: Oskar Berggren @ 2012-05-09 5:22 UTC (permalink / raw)
To: Oskar Berggren, Stephen Hemminger, netdev
In-Reply-To: <20120507061422.GA21089@canuck.infradead.org>
2012/5/7 Thomas Graf <tgraf@infradead.org>:
> On Sun, May 06, 2012 at 02:46:01PM +0200, Oskar Berggren wrote:
>> 2012/5/6 Stephen Hemminger <stephen.hemminger@vyatta.com>:
>> >
>> >>
>> >> In a project of mine I need to read (and possibly set) many of the
>> >> properties
>> >> found under /proc/sys/net/ipv4/conf/. This is simple enough, except
>> >> that
>> >> when you have hundreds of interfaces, it is really slow. In my tests
>> >> it takes
>> >> about 4 seconds to read a single variable for 700 interfaces. For a
>> >> while I
>> >> worked around this using the binary sysctl() interface, but this is
>> >> deprecated.
>> >>
>> >
>> > What about exposing these as NETLINK attributes? That would be faster
>> > and you could do bulk updates.
>>
>>
>> This is my first attempt at using NETLINK, so could you please elaborate?
>> Below is the generic netlink interface I implemented so far. Any pointers
>> on how I should do this differently?
>
> What Stephen means is to use the existing message types RTM_SETLINK
> and RTM_GETLINK in the NETLINK_ROUTE family.
>
> This is already partially implemented. See the IFLA_AF_SPEC attribute
> carrying IPV4_DEVCONF_ and DEVCONF_ (IPv6). Grep for rtnl_af_register()
> and you will find the corresponding implementations.
>
> Feel free to complete these existing interfaces, such as adding write
> support to IPv6 or adding support to iproute2 which is currently
> lacking.
Cool, this seems to be exactly what I need. I'll experiment with it
when I get the time.
/Oskar
^ permalink raw reply
* [PATCH net-next] be2net: avoid disabling sriov while VFs are assigned
From: Sathya Perla @ 2012-05-09 5:41 UTC (permalink / raw)
To: netdev; +Cc: Sathya Perla
Calling pci_disable_sriov() while VFs are assigned to VMs causes
kernel panic. This patch uses PCI_DEV_FLAGS_ASSIGNED bit state of the
VF's pci_dev to avoid this. Also, the unconditional function reset cmd
issued on a PF probe can delete the VF configuration for the
previously enabled VFs. A scratchpad register is now used to issue a
function reset only when needed (i.e., in a crash dump scenario.)
Signed-off-by: Sathya Perla <sathya.perla@emulex.com>
---
drivers/net/ethernet/emulex/benet/be.h | 22 ++--
drivers/net/ethernet/emulex/benet/be_hw.h | 2 +
drivers/net/ethernet/emulex/benet/be_main.c | 199 ++++++++++++++++-----------
3 files changed, 134 insertions(+), 89 deletions(-)
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index c3ee910..ecf1a81 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -313,6 +313,11 @@ struct be_vf_cfg {
u32 tx_rate;
};
+enum vf_state {
+ ENABLED = 0,
+ ASSIGNED = 1
+};
+
#define BE_FLAGS_LINK_STATUS_INIT 1
#define BE_FLAGS_WORKER_SCHEDULED (1 << 3)
#define BE_UC_PMAC_COUNT 30
@@ -403,8 +408,9 @@ struct be_adapter {
u32 flash_status;
struct completion flash_compl;
- u32 num_vfs;
- u8 is_virtfn;
+ u32 num_vfs; /* Number of VFs provisioned by PF driver */
+ u32 dev_num_vfs; /* Number of VFs supported by HW */
+ u8 virtfn;
struct be_vf_cfg *vf_cfg;
bool be3_native;
u32 sli_family;
@@ -417,8 +423,10 @@ struct be_adapter {
u32 uc_macs; /* Count of secondary UC MAC programmed */
};
-#define be_physfn(adapter) (!adapter->is_virtfn)
+#define be_physfn(adapter) (!adapter->virtfn)
#define sriov_enabled(adapter) (adapter->num_vfs > 0)
+#define sriov_want(adapter) (adapter->dev_num_vfs && num_vfs && \
+ be_physfn(adapter))
#define for_all_vfs(adapter, vf_cfg, i) \
for (i = 0, vf_cfg = &adapter->vf_cfg[i]; i < adapter->num_vfs; \
i++, vf_cfg++)
@@ -547,14 +555,6 @@ static inline u8 is_udp_pkt(struct sk_buff *skb)
return val;
}
-static inline void be_check_sriov_fn_type(struct be_adapter *adapter)
-{
- u32 sli_intf;
-
- pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf);
- adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0;
-}
-
static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
{
u32 addr;
diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h
index 0949aa6..f38b58c 100644
--- a/drivers/net/ethernet/emulex/benet/be_hw.h
+++ b/drivers/net/ethernet/emulex/benet/be_hw.h
@@ -58,6 +58,8 @@
#define SLI_PORT_CONTROL_IP_MASK 0x08000000
+#define PCICFG_CUST_SCRATCHPAD_CSR 0x1EC
+
/********* Memory BAR register ************/
#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc
/* Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index 6d5d30b..a01f734 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -1049,6 +1049,29 @@ static int be_set_vf_tx_rate(struct net_device *netdev,
return status;
}
+static int be_find_vfs(struct be_adapter *adapter, int vf_state)
+{
+ struct pci_dev *dev, *pdev = adapter->pdev;
+ int vfs = 0, assigned_vfs = 0, pos, vf_fn;
+ u16 offset, stride;
+
+ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+ pci_read_config_word(pdev, pos + PCI_SRIOV_VF_OFFSET, &offset);
+ pci_read_config_word(pdev, pos + PCI_SRIOV_VF_STRIDE, &stride);
+
+ dev = pci_get_device(pdev->vendor, PCI_ANY_ID, NULL);
+ while (dev) {
+ vf_fn = (pdev->devfn + offset + stride * vfs) & 0xFFFF;
+ if (dev->is_virtfn && dev->devfn == vf_fn) {
+ vfs++;
+ if (dev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
+ assigned_vfs++;
+ }
+ dev = pci_get_device(pdev->vendor, PCI_ANY_ID, dev);
+ }
+ return (vf_state == ASSIGNED) ? assigned_vfs : vfs;
+}
+
static void be_eqd_update(struct be_adapter *adapter, struct be_eq_obj *eqo)
{
struct be_rx_stats *stats = rx_stats(&adapter->rx_obj[eqo->idx]);
@@ -1789,9 +1812,9 @@ static void be_tx_queues_destroy(struct be_adapter *adapter)
static int be_num_txqs_want(struct be_adapter *adapter)
{
- if (sriov_enabled(adapter) || be_is_mc(adapter) ||
- lancer_chip(adapter) || !be_physfn(adapter) ||
- adapter->generation == BE_GEN2)
+ if (sriov_want(adapter) || be_is_mc(adapter) ||
+ lancer_chip(adapter) || !be_physfn(adapter) ||
+ adapter->generation == BE_GEN2)
return 1;
else
return MAX_TX_QS;
@@ -2118,7 +2141,7 @@ static void be_msix_disable(struct be_adapter *adapter)
static uint be_num_rss_want(struct be_adapter *adapter)
{
if ((adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
- adapter->num_vfs == 0 && be_physfn(adapter) &&
+ !sriov_want(adapter) && be_physfn(adapter) &&
!be_is_mc(adapter))
return (adapter->be3_native) ? BE3_MAX_RSS_QS : BE2_MAX_RSS_QS;
else
@@ -2152,53 +2175,6 @@ done:
return;
}
-static int be_sriov_enable(struct be_adapter *adapter)
-{
- be_check_sriov_fn_type(adapter);
-
-#ifdef CONFIG_PCI_IOV
- if (be_physfn(adapter) && num_vfs) {
- int status, pos;
- u16 dev_vfs;
-
- pos = pci_find_ext_capability(adapter->pdev,
- PCI_EXT_CAP_ID_SRIOV);
- pci_read_config_word(adapter->pdev,
- pos + PCI_SRIOV_TOTAL_VF, &dev_vfs);
-
- adapter->num_vfs = min_t(u16, num_vfs, dev_vfs);
- if (adapter->num_vfs != num_vfs)
- dev_info(&adapter->pdev->dev,
- "Device supports %d VFs and not %d\n",
- adapter->num_vfs, num_vfs);
-
- status = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
- if (status)
- adapter->num_vfs = 0;
-
- if (adapter->num_vfs) {
- adapter->vf_cfg = kcalloc(num_vfs,
- sizeof(struct be_vf_cfg),
- GFP_KERNEL);
- if (!adapter->vf_cfg)
- return -ENOMEM;
- }
- }
-#endif
- return 0;
-}
-
-static void be_sriov_disable(struct be_adapter *adapter)
-{
-#ifdef CONFIG_PCI_IOV
- if (sriov_enabled(adapter)) {
- pci_disable_sriov(adapter->pdev);
- kfree(adapter->vf_cfg);
- adapter->num_vfs = 0;
- }
-#endif
-}
-
static inline int be_msix_vec_get(struct be_adapter *adapter,
struct be_eq_obj *eqo)
{
@@ -2500,6 +2476,11 @@ static void be_vf_clear(struct be_adapter *adapter)
struct be_vf_cfg *vf_cfg;
u32 vf;
+ if (be_find_vfs(adapter, ASSIGNED)) {
+ dev_warn(&adapter->pdev->dev, "VFs are assigned to VMs\n");
+ goto done;
+ }
+
for_all_vfs(adapter, vf_cfg, vf) {
if (lancer_chip(adapter))
be_cmd_set_mac_list(adapter, NULL, 0, vf + 1);
@@ -2509,6 +2490,10 @@ static void be_vf_clear(struct be_adapter *adapter)
be_cmd_if_destroy(adapter, vf_cfg->if_handle, vf + 1);
}
+ pci_disable_sriov(adapter->pdev);
+done:
+ kfree(adapter->vf_cfg);
+ adapter->num_vfs = 0;
}
static int be_clear(struct be_adapter *adapter)
@@ -2538,29 +2523,60 @@ static int be_clear(struct be_adapter *adapter)
be_cmd_fw_clean(adapter);
be_msix_disable(adapter);
- kfree(adapter->pmac_id);
+ pci_write_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, 0);
return 0;
}
-static void be_vf_setup_init(struct be_adapter *adapter)
+static int be_vf_setup_init(struct be_adapter *adapter)
{
struct be_vf_cfg *vf_cfg;
int vf;
+ adapter->vf_cfg = kcalloc(adapter->num_vfs, sizeof(*vf_cfg),
+ GFP_KERNEL);
+ if (!adapter->vf_cfg)
+ return -ENOMEM;
+
for_all_vfs(adapter, vf_cfg, vf) {
vf_cfg->if_handle = -1;
vf_cfg->pmac_id = -1;
}
+ return 0;
}
static int be_vf_setup(struct be_adapter *adapter)
{
struct be_vf_cfg *vf_cfg;
+ struct device *dev = &adapter->pdev->dev;
u32 cap_flags, en_flags, vf;
u16 def_vlan, lnk_speed;
- int status;
+ int status, enabled_vfs;
+
+ enabled_vfs = be_find_vfs(adapter, ENABLED);
+ if (enabled_vfs) {
+ dev_warn(dev, "%d VFs are already enabled\n", enabled_vfs);
+ dev_warn(dev, "Ignoring num_vfs=%d setting\n", num_vfs);
+ return 0;
+ }
- be_vf_setup_init(adapter);
+ if (num_vfs > adapter->dev_num_vfs) {
+ dev_warn(dev, "Device supports %d VFs and not %d\n",
+ adapter->dev_num_vfs, num_vfs);
+ num_vfs = adapter->dev_num_vfs;
+ }
+
+ status = pci_enable_sriov(adapter->pdev, num_vfs);
+ if (!status) {
+ adapter->num_vfs = num_vfs;
+ } else {
+ /* Platform doesn't support SRIOV though device supports it */
+ dev_warn(dev, "SRIOV enable failed\n");
+ return 0;
+ }
+
+ status = be_vf_setup_init(adapter);
+ if (status)
+ goto err;
cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
BE_IF_FLAGS_MULTICAST;
@@ -2571,9 +2587,11 @@ static int be_vf_setup(struct be_adapter *adapter)
goto err;
}
- status = be_vf_eth_addr_config(adapter);
- if (status)
- goto err;
+ if (!enabled_vfs) {
+ status = be_vf_eth_addr_config(adapter);
+ if (status)
+ goto err;
+ }
for_all_vfs(adapter, vf_cfg, vf) {
status = be_cmd_link_status_query(adapter, NULL, &lnk_speed,
@@ -2630,9 +2648,25 @@ do_none:
return status;
}
+/* Routine to query per function resource limits */
+static int be_get_config(struct be_adapter *adapter)
+{
+ int pos;
+ u16 dev_num_vfs;
+
+ pos = pci_find_ext_capability(adapter->pdev, PCI_EXT_CAP_ID_SRIOV);
+ if (pos) {
+ pci_read_config_word(adapter->pdev, pos + PCI_SRIOV_TOTAL_VF,
+ &dev_num_vfs);
+ adapter->dev_num_vfs = dev_num_vfs;
+ }
+ return 0;
+}
+
static int be_setup(struct be_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
+ struct device *dev = &adapter->pdev->dev;
u32 cap_flags, en_flags;
u32 tx_fc, rx_fc;
int status;
@@ -2640,6 +2674,8 @@ static int be_setup(struct be_adapter *adapter)
be_setup_init(adapter);
+ be_get_config(adapter);
+
be_cmd_req_native_mode(adapter);
be_msix_enable(adapter);
@@ -2718,10 +2754,11 @@ static int be_setup(struct be_adapter *adapter)
pcie_set_readrq(adapter->pdev, 4096);
- if (sriov_enabled(adapter)) {
- status = be_vf_setup(adapter);
- if (status)
- goto err;
+ if (be_physfn(adapter) && num_vfs) {
+ if (adapter->dev_num_vfs)
+ be_vf_setup(adapter);
+ else
+ dev_warn(dev, "device doesn't support SRIOV\n");
}
be_cmd_get_phy_info(adapter);
@@ -2731,6 +2768,7 @@ static int be_setup(struct be_adapter *adapter)
schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
adapter->flags |= BE_FLAGS_WORKER_SCHEDULED;
+ pci_write_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, 1);
return 0;
err:
be_clear(adapter);
@@ -3352,8 +3390,6 @@ static void __devexit be_remove(struct pci_dev *pdev)
be_ctrl_cleanup(adapter);
- be_sriov_disable(adapter);
-
pci_set_drvdata(pdev, NULL);
pci_release_regions(pdev);
pci_disable_device(pdev);
@@ -3367,7 +3403,7 @@ bool be_is_wol_supported(struct be_adapter *adapter)
!be_is_wol_excluded(adapter)) ? true : false;
}
-static int be_get_config(struct be_adapter *adapter)
+static int be_get_initial_config(struct be_adapter *adapter)
{
int status;
@@ -3410,7 +3446,7 @@ static int be_get_config(struct be_adapter *adapter)
return 0;
}
-static int be_dev_family_check(struct be_adapter *adapter)
+static int be_dev_type_check(struct be_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
u32 sli_intf = 0, if_type;
@@ -3443,6 +3479,9 @@ static int be_dev_family_check(struct be_adapter *adapter)
default:
adapter->generation = 0;
}
+
+ pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf);
+ adapter->virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0;
return 0;
}
@@ -3586,6 +3625,14 @@ reschedule:
schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
}
+static bool be_reset_required(struct be_adapter *adapter)
+{
+ u32 reg;
+
+ pci_read_config_dword(adapter->pdev, PCICFG_CUST_SCRATCHPAD_CSR, ®);
+ return reg;
+}
+
static int __devinit be_probe(struct pci_dev *pdev,
const struct pci_device_id *pdev_id)
{
@@ -3611,7 +3658,7 @@ static int __devinit be_probe(struct pci_dev *pdev,
adapter->pdev = pdev;
pci_set_drvdata(pdev, adapter);
- status = be_dev_family_check(adapter);
+ status = be_dev_type_check(adapter);
if (status)
goto free_netdev;
@@ -3629,13 +3676,9 @@ static int __devinit be_probe(struct pci_dev *pdev,
}
}
- status = be_sriov_enable(adapter);
- if (status)
- goto free_netdev;
-
status = be_ctrl_init(adapter);
if (status)
- goto disable_sriov;
+ goto free_netdev;
if (lancer_chip(adapter)) {
status = lancer_wait_ready(adapter);
@@ -3662,9 +3705,11 @@ static int __devinit be_probe(struct pci_dev *pdev,
if (status)
goto ctrl_clean;
- status = be_cmd_reset_function(adapter);
- if (status)
- goto ctrl_clean;
+ if (be_reset_required(adapter)) {
+ status = be_cmd_reset_function(adapter);
+ if (status)
+ goto ctrl_clean;
+ }
/* The INTR bit may be set in the card when probed by a kdump kernel
* after a crash.
@@ -3676,7 +3721,7 @@ static int __devinit be_probe(struct pci_dev *pdev,
if (status)
goto ctrl_clean;
- status = be_get_config(adapter);
+ status = be_get_initial_config(adapter);
if (status)
goto stats_clean;
@@ -3705,8 +3750,6 @@ stats_clean:
be_stats_cleanup(adapter);
ctrl_clean:
be_ctrl_cleanup(adapter);
-disable_sriov:
- be_sriov_disable(adapter);
free_netdev:
free_netdev(netdev);
pci_set_drvdata(pdev, NULL);
--
1.7.4
^ permalink raw reply related
* RE: [PATCH net-next 3/4] netxen: added miniDIMM support in driver.
From: Rajesh Borundia @ 2012-05-09 5:59 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Ameen Rahman, Sony Chacko, Sucheta Chakraborty
In-Reply-To: <20120508.125311.1669426371305176333.davem@davemloft.net>
> -----Original Message-----
> From: David Miller [mailto:davem@davemloft.net]
> Sent: Tuesday, May 08, 2012 10:23 PM
> To: Rajesh Borundia
> Cc: netdev; Ameen Rahman; Sony Chacko; Sucheta Chakraborty
> Subject: Re: [PATCH net-next 3/4] netxen: added miniDIMM support in
> driver.
>
> From: Rajesh Borundia <rajesh.borundia@qlogic.com>
> Date: Tue, 8 May 2012 08:01:27 -0700
>
> > +static struct bin_attribute bin_attr_dimm = {
> > + .attr = {.name = "dimm", .mode = (S_IRUGO | S_IWUSR)},
>
> How about a space next to the braces?
>
I will resend the patches with review changes.
Rajesh
^ permalink raw reply
* Re: [PATCH] net: update the usage of CHECKSUM_UNNECESSARY
From: Michael S. Tsirkin @ 2012-05-09 6:03 UTC (permalink / raw)
To: Ben Hutchings; +Cc: Yi Zou, netdev, devel, jeffrey.t.kirsher
In-Reply-To: <1336501258.2749.3.camel@bwh-desktop.uk.solarflarecom.com>
On Tue, May 08, 2012 at 07:20:58PM +0100, Ben Hutchings wrote:
> On Tue, 2012-05-08 at 20:48 +0300, Michael S. Tsirkin wrote:
> > On Mon, Mar 19, 2012 at 02:12:41PM -0700, Yi Zou wrote:
> > > As suggested by Ben, this adds the clarification on the usage of
> > > CHECKSUM_UNNECESSARY on the outgoing patch. Also add the usage
> > > description of NETIF_F_FCOE_CRC and CHECKSUM_UNNECESSARY
> > > for the kernel FCoE protocol driver.
> > >
> > > This is a follow-up to the following:
> > > http://patchwork.ozlabs.org/patch/147315/
> > >
> > > Signed-off-by: Yi Zou <yi.zou@intel.com>
> > > Cc: Ben Hutchings <bhutchings@solarflare.com>
> > > Cc: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
> > > Cc: www.Open-FCoE.org <devel@open-fcoe.org>
> > > ---
> > >
> > > include/linux/skbuff.h | 7 +++++++
> > > 1 files changed, 7 insertions(+), 0 deletions(-)
> > >
> > > diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> > > index 8dc8257..a2b9953 100644
> > > --- a/include/linux/skbuff.h
> > > +++ b/include/linux/skbuff.h
> > > @@ -94,6 +94,13 @@
> > > * about CHECKSUM_UNNECESSARY. 8)
> > > * NETIF_F_IPV6_CSUM about as dumb as the last one but does IPv6 instead.
> > > *
> > > + * UNNECESSARY: device will do per protocol specific csum. Protocol drivers
> > > + * that do not want net to perform the checksum calculation should use
> > > + * this flag in their outgoing skbs.
> > > + * NETIF_F_FCOE_CRC this indicates the device can do FCoE FC CRC
> > > + * offload. Correspondingly, the FCoE protocol driver
> > > + * stack should use CHECKSUM_UNNECESSARY.
> > > + *
> > > * Any questions? No questions, good. --ANK
> > > */
> > >
> >
> > So just to make sure I understand, you never get
> > UNNECESSARY packets on tx unless you declared NETIF_F_FCOE_CRC?
> >
> > Maybe the comment says this somehow but could not figure it out.
>
> That's what should happen now. In future CHECKSUM_UNNECESSARY could be
> used on output by other protocols which don't use TCP/IP-style
> checksums, but always dependent on the output device supporting the
> relevant offload feature.
>
> Ben.
Isn't there another case: a device passes UNNECESSARY in on rx,
and the skb is forwarded to another device?
For example it is handled this way by tun, giving a nice
performance boost for VMs, see 10a8d94a95742bb15b4e617ee9884bb4381362be
> --
> Ben Hutchings, Staff Engineer, Solarflare
> Not speaking for my employer; that's the marketing department's job.
> They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [PATCH net-next 0/2] extend sch_mqprio to distribute traffic not only by ETS TC
From: John Fastabend @ 2012-05-09 6:22 UTC (permalink / raw)
To: Amir Vadai
Cc: David S. Miller, netdev, Oren Duer, Liran Liss, Jamal Hadi Salim
In-Reply-To: <4FA92606.6070401@mellanox.com>
On 5/8/2012 6:56 AM, Amir Vadai wrote:
> On 05/08/2012 03:54 AM, John Fastabend wrote:
>> On 5/6/2012 12:05 AM, Amir Vadai wrote:
>>> This series comes to revive the discussion initiated on the thread "net:
>>> support tx_ring per UP in HW based QoS mechanism" (see
>>> http://marc.info/?t=133165957200004&r=1&w=2) with the major issue to be address
>>> is - how should sk_prio<=> TC be done, for both, tagged and untagged traffic.
>>> Following is a staged description addressing the background, problem
>>> description, current situation, suggestion for the change and implementation of
>>> it.
>>
>> OK but the mqprio qdisc is only concerned with mapping skb->priority to
>> queue sets I perhaps unfortunately called the queue sets tc's. Try not
>> to get hung up on my perhaps limiting naming of variables and functions.
> I understand that.
I figured you did. Just wanted to state it again.
>
>>
>> mqprio is used outside of 802.1Q as well in these cases a traffic class
>> is not usually even defined.
>>
>>>
[...]
>>> Implementation
>>> --------------
>>> Extended mqprio hw attribute:
>>> * Bit 1: is queue offset/count owned by HW
>>> * Bits 2-7: HW queueing type.
>>> * 0 - by ETS TC
>>> * 1 - by UP
>>>
>>> __skb_tx_hash() is now aware to the HW queuing type (pg_type): for pg_type
>>> being ETS TC, traffic is distributed as it was before - tagged and untagged
>>> packets are distributed by netdev_get_prio_tc_map. For pg_type being UP, tagged
>>> and untagged packets are distributed by UP (taken from egress map for tagged
>>> traffic, or netdev_get_prio_tc_map for untagged).
>>
>> I guess I don't see why we need this. If you keep the mqprio priority to
>> queue set mapping set to 1:1. Then modify the egress map accordingly then
>> this should work right?
>>
>> For example:
>>
>> If we want to map 8 802.1Q priority code points onto 4 traffic classes this
>> should work,
>>
>> egress map: 0:0 1:0 2:1 3:1 4:2 5:2 6:3 7:3<-- vlan layer inserts correct tag
>> mqprio up2tc: 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7<-- mqprio with unfortunate 'tc' name maps priority to queues
> But mqprio is mapping sk_priority to queue set, which is different from UP to queue set.
> The term UP which we use, is the 8021q PCP in tagged traffic, and a priority mapped by the host admin for untagged traffic.
> What you wrote, is actually, that the application will set the priority without enabling the host admin to control it.
>> dcbnl up2tc: 0:0 1:0 2:1 3:1 4:2 5:2 6:3 7:3<-- dcbx pushes up2tc mapping correctly
>
> For example, lets take an application that calls setsockopt(SO_PRIORITY, 2):
> according to egress map: 8021q PCP field in vlan tag should be set to 1 (=UP)
> according to mqprio: a tx ring belonging to UP 2 will be selected.
> according to dcbnl: traffic will have ETS attributes of TC 1
>
> Except some conceptual problems, it won't work:
> 8021q PCP field is set by HW according to the tx ring (UP=2). which
> is different from the one that the user configured in the egress_map
> (UP=1).
sorry I set it up wrong above but it _can_ be made to work as best I
can tell (for a single egress_map at least)
egress map: 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 <-- ignored
mqprio : 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 <-- map priority to up queue sets
up2tc : 0:0 1:0 2:1 3:1 4:2 5:2 6:3 7:3 <-- dcbx negotiated up2tc map
With your example application does setsockopt(SO_PRIORITY, 2):
according to egress map : insert PCP 2
according to mqprio : tx ring belonging to UP2 is selected
accroding to dcbnl : traffic will have ETS attributes of TC1
The point is either you use the skb->priority to PCP map and then a 1:1
mqprio map or you use the mqprio map directly. Agree?
One more example translating the case with these patches onto a case
without these patches as I understand them.
first with these patches mapping:
up2tc : 0:0 1:0 2:1 3:1 4:2 5:2 6:3 7:3 <-- dcbnl up2tc map
egress map: 0:0 1:0 2:1 3:1 4:2 5:2 6:3 7:3 <-- sets pcp bits
mqprio : 0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 <-- with PGROUP_UP set
equivalent mapping without PGROUP_UP set
up2tc : 0:0 1:0 2:1 3:1 4:2 5:2 6:3 7:3 <-- dcbnl negotiated up2tc map
egress map: 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0 <-- default unset egress map
mqprio : 0:0 1:0 2:1 3:1 4:2 5:2 6:3 7:3 <-- with PGROUP_UP set
Application sets skb->priority to 2, in the first case egress map
sets the PCP to 1 and mqprio maps it to queues for UP1 based on PCP bits.
In case two egress map does nothing but skb->priority is still 2 so the
mqprio maps these to queues associated with UP1 so everything works
still.
I apologize if I'm missing something here but it seems correct to me. Spell
it out for me if I am still wrong.
>
>>
>> We may need to fixup userspace tools some but I think the kernel mechanisms
>> are in place.
>>
>> BTW I did think about this while implementing the existing code and decided
>> that rather than create more if/else branches the case you are describing
>> could be handled by independently controlling the priority to queue set mappings
>> in mqprio and the egress map.
>>
>> Feel free to let me know where I went wrong or why this doesn't work on
>> your hardware. I agree though we may need to fixup lldpad and maybe even
>> 'tc' some to get this to look correct in user space and get automagically
>> setup correctly.
>>
>> Thanks,
>> .John
>
> I think I understand your stand, that mqprio mapping should be generic
> and should not be TC nor UP oriented.
>
Right. Also I want to avoid user space having to somehow "know" which
mode to put the qdisc in. Checking if the hardware is a mellanox card
does not scale.
> The problem is that our HW needs the queues to be selected by UP. ETS
> TC mapping is configured before traffic starts, and therefore ETS
> attributes are enforced by HW according to the UP, which the tx ring
> belongs to. Same thing for vlan tag in tagged traffic. 8021q PCP is
> placed by HW according to the tx ring.
OK. Can you agree though in the case where we restrict the egress_map
to be the same for all vlan's on a real_dev the existing mqprio map
_can_ work?
>
> For backward compatibility, tagged traffic should be steered to a tx
> ring by UP taken from egress map - skb_tx_hash() as it is today, can't
> do it. Even if we implement ndo_select_queue(), we will need to
> duplicate most of the code from skb_tx_hash(), because there are more
> than one tx ring per UP, and we need skb_tx_hash() to be able to select
> a ring from a range of rings belonging to a UP.
agreed implementing this in select_queue() is no good.
>
> Also, there are some configurations that can't be done by mqprio and
> egress map. For example when having two vlans with different egress
> maps.
This is a good example thanks. This currently doesn't work for hardware
that maps tx_rings to traffic classes either. So if we need/want to
solve this case then I guess we need something like your patches. Note
I think the patch you submitted should work regardless if you map
the PCP bits to UP queues or PCP bits to TC queues. We could use this
in both cases which helps my user space concerns.
>
> And in the conceptual level, I think that kernel should not accept bad
> configurations and rely on user space to protect it.
I disagree policy should be managed in user space. Also I see no reason
to create a strong coupling between egress maps and mqprio maps. I can
imagine a case where they could be used independently. DCB is just one
usage model for mqprio. Using a bit like you did seems fine though.
>
> - Amir
Assuming we want the multiple different egress map case to work I guess
we will have to do something like this. At least right now I can't think
of anything better but I'll think on it tomorrow some more.
The other thought would be to provide a qdisc hook before queue selection
to attach 'tc filters' and provide a new action to hash a skb across
queue sets.
Thanks,
John
^ permalink raw reply
* Re: [PATCH net-next 1/2] net_sched/mqprio: add support for different pgroup types
From: John Fastabend @ 2012-05-09 6:36 UTC (permalink / raw)
To: Amir Vadai; +Cc: David S. Miller, netdev, Oren Duer, Liran Liss
In-Reply-To: <1336287910-12010-2-git-send-email-amirv@mellanox.com>
On 5/6/2012 12:05 AM, Amir Vadai wrote:
> Currently, HW based QoS mechanisms use the framework and means introduced in
> commits 4f57c087d "net: implement mechanism for HW based QOS" and b8970f0bfc
> "net_sched: implement a root container qdisc sch_mqprio".
>
> The approach present in these patches is strongly orientated to the extended
> transmission selection (ETS) algorithm traffic classes (TC).
>
I would argue the strongly orientated part per our other thread [0/2]
> This patch enhances the current scheme to allow for these mechanisms to be used
> also with hardware who has queues per UP - user priority (Linux has well
> established mechanisms to set UP for both tagged and untagged traffic).
>
also per other thread I think this is only needed if you have many different
egress map configurations on vlans.
> Now, __skb_tx_hash() will direct a flow to a tx ring from a range of tx rings.
> This range is defined by the admin through the mqprio scheduler for the
> specific HW. For TC based queues, the range is by TC number and for UP based
> queues, the range is by UP.
>
> Signed-off-by: Amir Vadai <amirv@mellanox.com>
> ---
> include/linux/netdevice.h | 27 +++++++++++++++++++++++++++
> include/linux/pkt_sched.h | 3 ++-
> net/core/dev.c | 12 +++++++++---
> net/sched/sch_mqprio.c | 11 +++++++++--
> 4 files changed, 47 insertions(+), 6 deletions(-)
>
> diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
> index 7f377fb..ecdd953 100644
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -835,6 +835,9 @@ struct netdev_fcoe_hbainfo {
> * is always called from the stack with the rtnl lock held and netif tx
> * queues stopped. This allows the netdevice to perform queue management
> * safely.
> + * int (*ndo_set_pg_type)(struct net_device *dev, u8 pg_type)
> + * Called to setup 'tc' type. According to this type, traffic is
> + * distributed across tx rings. If not set, ETS TC is in use.
> *
> * Fiber Channel over Ethernet (FCoE) offload functions.
> * int (*ndo_fcoe_enable)(struct net_device *dev);
> @@ -973,6 +976,8 @@ struct net_device_ops {
> int (*ndo_get_vf_port)(struct net_device *dev,
> int vf, struct sk_buff *skb);
> int (*ndo_setup_tc)(struct net_device *dev, u8 tc);
> + int (*ndo_set_pg_type)(struct net_device *dev,
> + u8 pg_type);
expand ndo_setup_tc() to take either another parameter 'pg_type' or just
start passing in the entire tc_mqprio_opt that way we get the number of
queues as well. I would prefer passing tc_mpqrio_opt to adding more parameters.
This avoids adding another ndo op.
> #if IS_ENABLED(CONFIG_FCOE)
> int (*ndo_fcoe_enable)(struct net_device *dev);
> int (*ndo_fcoe_disable)(struct net_device *dev);
> @@ -1307,6 +1312,11 @@ struct net_device {
> /* Data Center Bridging netlink ops */
> const struct dcbnl_rtnl_ops *dcbnl_ops;
> #endif
> + enum {
> + PGROUP_TC,
> + PGROUP_UP,
> + PGROUP_MAX,
> + } pg_type:8;
> u8 num_tc;
> struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE];
> u8 prio_tc_map[TC_BITMASK + 1];
> @@ -1329,6 +1339,23 @@ struct net_device {
> #define NETDEV_ALIGN 32
>
> static inline
> +int netdev_get_pg_type(const struct net_device *dev)
> +{
> + return dev->pg_type;
> +}
> +
> +static inline
> +int netdev_set_pg_type(struct net_device *dev, u8 pg_type)
> +{
> + if (pg_type >= PGROUP_MAX)
> + return -EINVAL;
> +
> + dev->pg_type = pg_type;
> +
> + return 0;
> +}
> +
> +static inline
> int netdev_get_prio_tc_map(const struct net_device *dev, u32 prio)
> {
> return dev->prio_tc_map[prio & TC_BITMASK];
> diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
> index ffe975c..1ae7d3c 100644
> --- a/include/linux/pkt_sched.h
> +++ b/include/linux/pkt_sched.h
> @@ -596,7 +596,8 @@ struct tc_drr_stats {
> struct tc_mqprio_qopt {
> __u8 num_tc;
> __u8 prio_tc_map[TC_QOPT_BITMASK + 1];
> - __u8 hw;
> + __u8 hw; /* bit 0: hw owned, bits 1-7: hw queuing type.
> + * valid types: 0 - ETS TC, 1 - UP */
> __u16 count[TC_QOPT_MAX_QUEUE];
> __u16 offset[TC_QOPT_MAX_QUEUE];
> };
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 09024fd..72ac4bf 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -2325,9 +2325,15 @@ u16 __skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb,
> }
>
> if (dev->num_tc) {
> - u8 tc = netdev_get_prio_tc_map(dev, skb->priority);
> - qoffset = dev->tc_to_txq[tc].offset;
> - qcount = dev->tc_to_txq[tc].count;
> + u8 pgroup;
> +
> + if (dev->pg_type == PGROUP_TC || !vlan_tx_tag_present(skb))
> + pgroup = netdev_get_prio_tc_map(dev, skb->priority);
> + else
> + pgroup = (vlan_tx_tag_get(skb) >> 13);
> +
> + qoffset = dev->tc_to_txq[pgroup].offset;
> + qcount = dev->tc_to_txq[pgroup].count;
> }
>
> if (skb->sk && skb->sk->sk_hash)
> diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c
> index d1831ca..2149cbb 100644
> --- a/net/sched/sch_mqprio.c
> +++ b/net/sched/sch_mqprio.c
> @@ -134,11 +134,18 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt)
> priv->qdiscs[i] = qdisc;
> }
>
> + if (dev->netdev_ops->ndo_set_pg_type)
> + err = dev->netdev_ops->ndo_set_pg_type(dev, qopt->hw >> 1);
> + else
> + err = netdev_set_pg_type(dev, PGROUP_TC);
Software should still be allowed to set PGROUP_UP even though hardware may
not support it.
> + if (err)
> + goto err;
> +
> /* If the mqprio options indicate that hardware should own
> * the queue mapping then run ndo_setup_tc otherwise use the
> * supplied and verified mapping
> */
> - if (qopt->hw) {
> + if (qopt->hw & 1) {
> priv->hw_owned = 1;
> err = dev->netdev_ops->ndo_setup_tc(dev, qopt->num_tc);
> if (err)
^ permalink raw reply
* Re: [PATCH 3.3.0] phy:icplus:fix Auto Power Saving in ip101a_config_init.
From: Jonathan Nieder @ 2012-05-09 7:25 UTC (permalink / raw)
To: David Miller; +Cc: srinivas.kandagatla, netdev, peppe.cavallaro
In-Reply-To: <20120403.184937.744089580257691570.davem@davemloft.net>
Hi Dave,
David Miller wrote:
> From: Srinivas KANDAGATLA <srinivas.kandagatla@st.com>
>> This patch fixes Auto Power Saving configuration in ip101a_config_init
>> which was broken as there is no phy register write followed after
>> setting IP101A_APS_ON flag.
>>
>> This patch also fixes the return value of ip101a_config_init.
>>
>> Without this patch ip101a_config_init returns 2 which is not an error
>> accroding to IS_ERR and the mac driver will continue accessing 2 as
>> valid pointer to phy_dev resulting in memory fault.
>>
>> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
>
> Applied and queued up for -stable, thanks.
I'm guessing 3.2.y needs this, too, since it also includes
v3.2-rc1~129^2~247 ("net/phy: add IC+ IP101A and support APS").
Here's a quick backport made by adjusting the context line to
use IP101A_APS_ON instead of IP101A_G_APS_ON.
Please include it in some later stable update if appropriate.
Thanks,
Jonathan
-- >8 --
From: Srinivas Kandagatla <srinivas.kandagatla@st.com>
Date: Mon, 2 Apr 2012 00:02:09 +0000
[ Upstream commit b3300146aa8efc5d3937fd33f3cfdc580a3843bc ]
This patch fixes Auto Power Saving configuration in ip101a_config_init
which was broken as there is no phy register write followed after
setting IP101A_APS_ON flag.
This patch also fixes the return value of ip101a_config_init.
Without this patch ip101a_config_init returns 2 which is not an error
accroding to IS_ERR and the mac driver will continue accessing 2 as
valid pointer to phy_dev resulting in memory fault.
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
drivers/net/phy/icplus.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
index c81f136ae670..b14230016d9b 100644
--- a/drivers/net/phy/icplus.c
+++ b/drivers/net/phy/icplus.c
@@ -150,7 +150,8 @@ static int ip101a_config_init(struct phy_device *phydev)
/* Enable Auto Power Saving mode */
c = phy_read(phydev, IP10XX_SPEC_CTRL_STATUS);
c |= IP101A_APS_ON;
- return c;
+
+ return phy_write(phydev, IP10XX_SPEC_CTRL_STATUS, c);
}
static int ip175c_read_status(struct phy_device *phydev)
--
1.7.10.1
^ permalink raw reply related
* [PATCH] xfrm: make xfrm_algo.c a module
From: Jan Beulich @ 2012-05-09 7:53 UTC (permalink / raw)
To: davem, netdev; +Cc: linux-kernel
By making this a standalone config option (selected as needed),
selecting CRYPTO from here rather than from XFRM (which is boolean)
allows the core crypto code to become a module again even when XFRM=y.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
net/ipv4/Kconfig | 4 ++--
net/ipv6/Kconfig | 4 ++--
net/xfrm/Kconfig | 13 +++++++++----
net/xfrm/Makefile | 3 ++-
net/xfrm/xfrm_algo.c | 5 ++---
5 files changed, 17 insertions(+), 12 deletions(-)
--- 3.4-rc6/net/ipv4/Kconfig
+++ 3.4-rc6-xfrm-algo-module/net/ipv4/Kconfig
@@ -312,7 +312,7 @@ config SYN_COOKIES
config INET_AH
tristate "IP: AH transformation"
- select XFRM
+ select XFRM_ALGO
select CRYPTO
select CRYPTO_HMAC
select CRYPTO_MD5
@@ -324,7 +324,7 @@ config INET_AH
config INET_ESP
tristate "IP: ESP transformation"
- select XFRM
+ select XFRM_ALGO
select CRYPTO
select CRYPTO_AUTHENC
select CRYPTO_HMAC
--- 3.4-rc6/net/ipv6/Kconfig
+++ 3.4-rc6-xfrm-algo-module/net/ipv6/Kconfig
@@ -69,7 +69,7 @@ config IPV6_OPTIMISTIC_DAD
config INET6_AH
tristate "IPv6: AH transformation"
- select XFRM
+ select XFRM_ALGO
select CRYPTO
select CRYPTO_HMAC
select CRYPTO_MD5
@@ -81,7 +81,7 @@ config INET6_AH
config INET6_ESP
tristate "IPv6: ESP transformation"
- select XFRM
+ select XFRM_ALGO
select CRYPTO
select CRYPTO_AUTHENC
select CRYPTO_HMAC
--- 3.4-rc6/net/xfrm/Kconfig
+++ 3.4-rc6-xfrm-algo-module/net/xfrm/Kconfig
@@ -3,12 +3,17 @@
#
config XFRM
bool
- select CRYPTO
depends on NET
+config XFRM_ALGO
+ tristate
+ select XFRM
+ select CRYPTO
+
config XFRM_USER
tristate "Transformation user configuration interface"
- depends on INET && XFRM
+ depends on INET
+ select XFRM_ALGO
---help---
Support for Transformation(XFRM) user configuration interface
like IPsec used by native Linux tools.
@@ -48,13 +53,13 @@ config XFRM_STATISTICS
config XFRM_IPCOMP
tristate
- select XFRM
+ select XFRM_ALGO
select CRYPTO
select CRYPTO_DEFLATE
config NET_KEY
tristate "PF_KEY sockets"
- select XFRM
+ select XFRM_ALGO
---help---
PF_KEYv2 socket family, compatible to KAME ones.
They are required if you are going to use IPsec tools ported
--- 3.4-rc6/net/xfrm/Makefile
+++ 3.4-rc6-xfrm-algo-module/net/xfrm/Makefile
@@ -3,8 +3,9 @@
#
obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \
- xfrm_input.o xfrm_output.o xfrm_algo.o \
+ xfrm_input.o xfrm_output.o \
xfrm_sysctl.o xfrm_replay.o
obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o
+obj-$(CONFIG_XFRM_ALGO) += xfrm_algo.o
obj-$(CONFIG_XFRM_USER) += xfrm_user.o
obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o
--- 3.4-rc6/net/xfrm/xfrm_algo.c
+++ 3.4-rc6-xfrm-algo-module/net/xfrm/xfrm_algo.c
@@ -15,9 +15,6 @@
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include <net/xfrm.h>
-#if defined(CONFIG_INET_AH) || defined(CONFIG_INET_AH_MODULE) || defined(CONFIG_INET6_AH) || defined(CONFIG_INET6_AH_MODULE)
-#include <net/ah.h>
-#endif
#if defined(CONFIG_INET_ESP) || defined(CONFIG_INET_ESP_MODULE) || defined(CONFIG_INET6_ESP) || defined(CONFIG_INET6_ESP_MODULE)
#include <net/esp.h>
#endif
@@ -752,3 +749,5 @@ void *pskb_put(struct sk_buff *skb, stru
}
EXPORT_SYMBOL_GPL(pskb_put);
#endif
+
+MODULE_LICENSE("GPL");
^ permalink raw reply
* Re: [PATCH 0/2] Add and use vsprintf extension %pMbt for bluetooth macs
From: Andrei Emeltchenko @ 2012-05-09 9:01 UTC (permalink / raw)
To: Joe Perches
Cc: Marcel Holtmann, Gustavo F. Padovan, linux-bluetooth, netdev,
linux-kernel
In-Reply-To: <cover.1291419007.git.joe@perches.com>
Hi Joe
On Fri, Dec 03, 2010 at 06:33:02PM -0800, Joe Perches wrote:
> Using vsprintf extensions can save text and data.
> Add %pMbt for the byte reversed output for bluetooth addresses.
>
> Joe Perches (2):
> vsprintf: Add %pMbt, bluetooth mac address
> bluetooth: Use printf extension %pMbt
I think this would be the best way to solve our issues with batostr.
BTW: What is the status with this patch series? I saw that it was acked by
Gustavo but not applied for some reason.
Best regards
Andrei Emeltchenko
^ permalink raw reply
* Memory exhaust issue with only IPsec policies configured on continuous traffic
From: Agarwal Nikhil-B38457 @ 2012-05-09 9:10 UTC (permalink / raw)
To: linux-kernel@vger.kernel.org, linux-crypto@vger.kernel.org,
linux-netdev@vger.kernel.org, netdev@vger.kernel.org
Hi all,
In a typical scenario, when IPSEC policies are configured in the system but SA is not present or negotiation fails or IKE daemon is not running. The current behavior of xfrm is to send those matching packets to blackhole route. i.e. xfrm_bundle_lookup returns a bundle with null route and xfrm_lookup returns a blackhole route.
For each of these packet a dst_alloc is called in ipv4_blackhole_route. However when these skbs get free and their dst's get discarded using dst_free and the garbage collector is scheduled using cancel_delayed_work and schedule_delayed_work.
If the packets are coming continuously garbage collector may not get scheduled and large amount of memory is stuck to be freed causing the system to go into non-recoverable state.
Any ideas?
Regards
Nikhil
^ permalink raw reply
* Memory exhaust issue with only IPsec policies configured on continuous traffic
From: Agarwal Nikhil-B38457 @ 2012-05-09 9:23 UTC (permalink / raw)
To: linux-kernel@vger.kernel.org, netdev@vger.kernel.org
In-Reply-To: <F0B93D0554724543876B9A180DC988575B70E7@039-SN1MPN1-001.039d.mgd.msft.net>
Hi all,
In a typical scenario, when IPSEC policies are configured in the system but SA is not present or negotiation fails or IKE daemon is not running. The current behavior of xfrm is to send those matching packets to blackhole route. i.e. xfrm_bundle_lookup returns a bundle with null route and xfrm_lookup returns a blackhole route.
For each of these packet a dst_alloc is called in ipv4_blackhole_route. However when these skbs get free and their dst's get discarded using dst_free and the garbage collector is scheduled using cancel_delayed_work and schedule_delayed_work.
If the packets are coming continuously garbage collector may not get scheduled and large amount of memory is stuck to be freed causing the system to go into non-recoverable state.
Any ideas?
Regards
Nikhil
^ permalink raw reply
* [net-next] e1000e: Fix merge conflict (net->net-next)
From: Jeff Kirsher @ 2012-05-09 9:23 UTC (permalink / raw)
To: davem; +Cc: Jeff Kirsher, netdev, gospo, sassmann
During merge of net to net-next the changes in patch:
e1000e: Fix default interrupt throttle rate not set in NIC HW
got munged in param.c of the e1000e driver. This rectifies the
merge issues.
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
This patch is also available on my net-next tree on kernel.org if you
want to pull this patch.
---
drivers/net/ethernet/intel/e1000e/param.c | 56 ++++++-----------------------
1 files changed, 11 insertions(+), 45 deletions(-)
diff --git a/drivers/net/ethernet/intel/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c
index 42444d1..55cc156 100644
--- a/drivers/net/ethernet/intel/e1000e/param.c
+++ b/drivers/net/ethernet/intel/e1000e/param.c
@@ -344,50 +344,16 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
if (num_InterruptThrottleRate > bd) {
adapter->itr = InterruptThrottleRate[bd];
- switch (adapter->itr) {
- case 0:
- e_info("%s turned off\n", opt.name);
- break;
- case 1:
- e_info("%s set to dynamic mode\n", opt.name);
- adapter->itr_setting = adapter->itr;
- adapter->itr = 20000;
- break;
- case 3:
- e_info("%s set to dynamic conservative mode\n",
- opt.name);
- adapter->itr_setting = adapter->itr;
- adapter->itr = 20000;
- break;
- case 4:
- e_info("%s set to simplified (2000-8000 ints) mode\n",
- opt.name);
- adapter->itr_setting = 4;
- break;
- default:
- /*
- * Save the setting, because the dynamic bits
- * change itr.
- */
- if (e1000_validate_option(&adapter->itr, &opt,
- adapter) &&
- (adapter->itr == 3)) {
- /*
- * In case of invalid user value,
- * default to conservative mode.
- */
- adapter->itr_setting = adapter->itr;
- adapter->itr = 20000;
- } else {
- /*
- * Clear the lower two bits because
- * they are used as control.
- */
- adapter->itr_setting =
- adapter->itr & ~3;
- }
- break;
- }
+
+ /*
+ * Make sure a message is printed for non-special
+ * values. And in case of an invalid option, display
+ * warning, use default and go through itr/itr_setting
+ * adjustment logic below
+ */
+ if ((adapter->itr > 4) &&
+ e1000_validate_option(&adapter->itr, &opt, adapter))
+ adapter->itr = opt.def;
} else {
/*
* If no option specified, use default value and go
@@ -399,7 +365,7 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
* Make sure a message is printed for non-special
* default values
*/
- if (adapter->itr > 40)
+ if (adapter->itr > 4)
e_info("%s set to default %d\n", opt.name,
adapter->itr);
}
--
1.7.7.6
^ permalink raw reply related
* Re: IP_MULTICAST_IF getsockopt man part
From: Jiri Pirko @ 2012-05-09 9:34 UTC (permalink / raw)
To: Michael Kerrisk (man-pages)
Cc: linux-man-u79uwXL29TY76Z2rM5mHXA, netdev-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <CAKgNAkgBz_dRV97JVV1Np0YuEd0EVqoLPZkajiE_KJ2Lk20YRA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Sat, May 05, 2012 at 01:57:35PM CEST, mtk.manpages-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org wrote:
>On Fri, May 4, 2012 at 9:00 PM, Jiri Pirko <jpirko-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
>> Hi.
>>
>> <quote>
>> IP_MULTICAST_IF (since Linux 1.2)
>> Set the local device for a multicast socket.
>> Argument is an ip_mreqn or ip_mreq structure
>> similar to IP_ADD_MEMBERSHIP.
>> </quote>
>>
>> That is not true. Setsockopt recognizes only ip_mreqn and in_addr. I
>> made patch which makes it recognize ip_mreq as well. So that would be
>> probably ok.
>> http://patchwork.ozlabs.org/patch/156815/
>>
>> On the other hand, getsockopt works only with in_addr. That I think is
>> good behaviour but manpages here needs to be corrected in this way (read
>> part needs to be added here)
>
>Jirka,
>
>I'm having trouble to understand what you mean. Perhaps it would be
>simplest if you showed your proposed replacement text for the text
>quoted above.
<orig>
IP_MULTICAST_IF (since Linux 1.2)
Set the local device for a multicast socket. Argument is an ip_mreqn
or ip_mreq structure similar to IP_ADD_MEMBERSHIP.
</orig>
<new>
IP_MULTICAST_IF (since Linux 1.2)
Set or read the local device for a multicast socket.
Argument for set is an ip_mreqn or ip_mreq or addr_in structure.
Argument for read is an addr_in structure.
</new>
Jirka
>
>Thanks,
>
>Michael
>
>
>
>--
>Michael Kerrisk
>Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/
>Author of "The Linux Programming Interface"; http://man7.org/tlpi/
--
To unsubscribe from this list: send the line "unsubscribe linux-man" 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
* Re: [PATCH 7/9] net: add skb_orphan_frags to copy aside frags with destructors
From: Ian Campbell @ 2012-05-09 9:36 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: netdev@vger.kernel.org, David Miller, Eric Dumazet
In-Reply-To: <20120507102441.GA18591@redhat.com>
> > diff --git a/net/core/skbuff.c b/net/core/skbuff.c
> > index 945b807..f009abb 100644
> > --- a/net/core/skbuff.c
> > +++ b/net/core/skbuff.c
> > @@ -697,31 +697,25 @@ struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src)
> > }
> > EXPORT_SYMBOL_GPL(skb_morph);
> >
> > -/* skb_copy_ubufs - copy userspace skb frags buffers to kernel
> > - * @skb: the skb to modify
> > - * @gfp_mask: allocation priority
> > - *
> > - * This must be called on SKBTX_DEV_ZEROCOPY skb.
> > - * It will copy all frags into kernel and drop the reference
> > - * to userspace pages.
> > - *
> > - * If this function is called from an interrupt gfp_mask() must be
> > - * %GFP_ATOMIC.
> > - *
> > - * Returns 0 on success or a negative error code on failure
> > - * to allocate kernel memory to copy to.
> > +/*
> > + * If uarg != NULL copy and replace all frags.
> > + * If uarg == NULL then only copy and replace those which have a destructor
> > + * pointer.
> > */
> > -int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
> > +static int skb_copy_frags(struct sk_buff *skb, gfp_t gfp_mask,
> > + struct ubuf_info *uarg)
> > {
> > int i;
> > int num_frags = skb_shinfo(skb)->nr_frags;
> > struct page *page, *head = NULL;
> > - struct ubuf_info *uarg = skb_shinfo(skb)->destructor_arg;
> >
> > for (i = 0; i < num_frags; i++) {
> > u8 *vaddr;
> > skb_frag_t *f = &skb_shinfo(skb)->frags[i];
> >
> > + if (!uarg && !f->page.destructor)
> > + continue;
> > +
> > page = alloc_page(GFP_ATOMIC);
> > if (!page) {
> > while (head) {
> > @@ -739,11 +733,16 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
> > head = page;
> > }
> >
> > - /* skb frags release userspace buffers */
> > - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
> > + /* skb frags release buffers */
> > + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
> > + skb_frag_t *f = &skb_shinfo(skb)->frags[i];
> > + if (!uarg && !f->page.destructor)
> > + continue;
> > skb_frag_unref(skb, i);
> > + }
> >
> > - uarg->callback(uarg);
> > + if (uarg)
> > + uarg->callback(uarg);
> >
>
> So above we only linked up copied pages, but below we
> try to use the list for all frags. Looks like a bug,
> I think it needs to check destructor and uarg too.
You are absolutely correct. We need the same check in all three loops.
>
>
> > /* skb frags point to kernel buffers */
> > for (i = skb_shinfo(skb)->nr_frags; i > 0; i--) {
> > @@ -752,10 +751,41 @@ int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask)
> > head = (struct page *)head->private;
> > }
> >
> > - skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY;
> > return 0;
> > }
^ permalink raw reply
* Re: [v12 PATCH 2/3] NETFILTER module xt_hmark, new target for HASH based fwmark
From: Pablo Neira Ayuso @ 2012-05-09 10:38 UTC (permalink / raw)
To: Hans Schillstrom
Cc: kaber@trash.net, jengelh@medozas.de,
netfilter-devel@vger.kernel.org, netdev@vger.kernel.org,
hans@schillstrom.com
In-Reply-To: <201205080937.36853.hans.schillstrom@ericsson.com>
On Tue, May 08, 2012 at 09:37:35AM +0200, Hans Schillstrom wrote:
> From d5065af3988cc7561a02f30bae8342e1a89126a4 Mon Sep 17 00:00:00 2001
> From: Hans Schillstrom <hans.schillstrom@ericsson.com>
> Date: Wed, 2 May 2012 07:49:47 +0000
> Subject: netfilter: add xt_hmark target for hash-based skb
> marking
>
> The target allows you to create rules in the "raw" and "mangle" tables
> which set the skbuff mark by means of hash calculation within a given
> range. The nfmark can influence the routing method (see "Use netfilter
> MARK value as routing key") and can also be used by other subsystems to
> change their behaviour.
>
> Some examples:
>
> * Default rule handles all TCP, UDP, SCTP, ESP & AH
>
> iptables -t mangle -A PREROUTING -m state --state NEW,ESTABLISHED,RELATED \
> -j HMARK --hmark-offset 10000 --hmark-mod 10
>
> * Handle SCTP and hash dest port only and produce a nfmark between 100-119.
>
> iptables -t mangle -A PREROUTING -p SCTP -j HMARK --src-mask 0 --dst-mask 0 \
> --sp-mask 0 --offset 100 --mod 20
>
> * Fragment safe Layer 3 only, that keep a class C network flow together
>
> iptables -t mangle -A PREROUTING -j HMARK --method L3 \
> --src-mask 24 --mod 20 --offset 100
I have removed these examples. Just in case we make changes to the
user-space part. We'll have the time for this (the entire 3.5 cycle).
Some minor glitches I made on this patch:
> include/linux/netfilter/xt_HMARK.h | 48 +++++
> net/netfilter/Kconfig | 15 ++
> net/netfilter/Makefile | 1 +
> net/netfilter/xt_HMARK.c | 358 ++++++++++++++++++++++++++++++++++++
> 4 files changed, 422 insertions(+)
> create mode 100644 include/linux/netfilter/xt_HMARK.h
> create mode 100644 net/netfilter/xt_HMARK.c
>
> diff --git a/include/linux/netfilter/xt_HMARK.h b/include/linux/netfilter/xt_HMARK.h
> new file mode 100644
> index 0000000..05e43ba
> --- /dev/null
> +++ b/include/linux/netfilter/xt_HMARK.h
> @@ -0,0 +1,46 @@
> +#ifndef XT_HMARK_H_
> +#define XT_HMARK_H_
> +
> +#include <linux/types.h>
> +
> +enum {
> + XT_HMARK_NONE,
this means (1 << 0) is unused. I have removed this _NONE.
> + XT_HMARK_SADR_MASK,
> + XT_HMARK_DADR_MASK,
> + XT_HMARK_SPI_MASK,
> + XT_HMARK_SPI,
> + XT_HMARK_SPORT_MASK,
> + XT_HMARK_DPORT_MASK,
> + XT_HMARK_SPORT,
> + XT_HMARK_DPORT,
> + XT_HMARK_PROTO_MASK,
> + XT_HMARK_RND,
> + XT_HMARK_MODULUS,
> + XT_HMARK_OFFSET,
> + XT_HMARK_CT,
> + XT_HMARK_METHOD_L3,
> + XT_HMARK_METHOD_L3_4,
I have also rearrange the order of the flags:
enum {
XT_HMARK_SADDR_MASK,
XT_HMARK_DADDR_MASK,
XT_HMARK_SPI,
XT_HMARK_SPI_MASK,
XT_HMARK_SPORT,
XT_HMARK_DPORT,
XT_HMARK_SPORT_MASK,
XT_HMARK_DPORT_MASK,
XT_HMARK_PROTO_MASK,
XT_HMARK_RND,
XT_HMARK_MODULUS,
XT_HMARK_OFFSET,
XT_HMARK_CT,
XT_HMARK_METHOD_L3,
XT_HMARK_METHOD_L3_4,
};
I don't want people to ask me why we where using some strange order in
the flag definition in the future (yes, you'll have to recompile your
iptables HMARK support in your setups, sorry)
> +};
> +#define XT_HMARK_FLAG(flag) (1 << flag)
> +
> +union hmark_ports {
> + struct {
> + __u16 src;
> + __u16 dst;
> + } p16;
> + __u32 v32;
> +};
> +
> +struct xt_hmark_info {
> + union nf_inet_addr src_mask; /* Source address mask */
> + union nf_inet_addr dst_mask; /* Dest address mask */
> + union hmark_ports port_mask;
> + union hmark_ports port_set;
> + __u32 flags; /* Print out only */
> + __u16 proto_mask; /* L4 Proto mask */
> + __u32 hashrnd;
> + __u32 hmodulus; /* Modulus */
> + __u32 hoffset; /* Offset */
I've removed these comments, they provide no extra information. Still
I left the one that described hoffset, that may seem not obvious.
> +#endif /* XT_HMARK_H_ */
I have applied this, I'm going to pass it to davem.
^ permalink raw reply
* [PATCH v5] tilegx network driver: initial support
From: Chris Metcalf @ 2012-05-09 10:42 UTC (permalink / raw)
To: David Miller, arnd, linux-kernel, netdev
In-Reply-To: <20120504.024216.1730395431103337434.davem@davemloft.net>
This change adds support for the tilegx network driver based on the
GXIO IORPC support in the tilegx software stack, using the on-chip
mPIPE packet processing engine.
Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
---
This version removes some "generic" comments on network driver
infrastructure, removes runs of multiple blank lines, and eliminates
the hand-rolled ROUND_UP() macro in favor of ALIGN(). There are also
a number of additional cleanups.
drivers/net/ethernet/tile/Kconfig | 1 +
drivers/net/ethernet/tile/Makefile | 4 +-
drivers/net/ethernet/tile/tilegx.c | 1928 ++++++++++++++++++++++++++++++++++++
3 files changed, 1931 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ethernet/tile/tilegx.c
diff --git a/drivers/net/ethernet/tile/Kconfig b/drivers/net/ethernet/tile/Kconfig
index 2d9218f..9184b61 100644
--- a/drivers/net/ethernet/tile/Kconfig
+++ b/drivers/net/ethernet/tile/Kconfig
@@ -7,6 +7,7 @@ config TILE_NET
depends on TILE
default y
select CRC32
+ select TILE_GXIO_MPIPE if TILEGX
---help---
This is a standard Linux network device driver for the
on-chip Tilera Gigabit Ethernet and XAUI interfaces.
diff --git a/drivers/net/ethernet/tile/Makefile b/drivers/net/ethernet/tile/Makefile
index f634f14..0ef9eef 100644
--- a/drivers/net/ethernet/tile/Makefile
+++ b/drivers/net/ethernet/tile/Makefile
@@ -4,7 +4,7 @@
obj-$(CONFIG_TILE_NET) += tile_net.o
ifdef CONFIG_TILEGX
-tile_net-objs := tilegx.o mpipe.o iorpc_mpipe.o dma_queue.o
+tile_net-y := tilegx.o
else
-tile_net-objs := tilepro.o
+tile_net-y := tilepro.o
endif
diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c
new file mode 100644
index 0000000..1ba52a7
--- /dev/null
+++ b/drivers/net/ethernet/tile/tilegx.c
@@ -0,0 +1,1928 @@
+/*
+ * Copyright 2012 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/sched.h>
+#include <linux/kernel.h> /* printk() */
+#include <linux/slab.h> /* kmalloc() */
+#include <linux/errno.h> /* error codes */
+#include <linux/types.h> /* size_t */
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/irq.h>
+#include <linux/netdevice.h> /* struct device, and other headers */
+#include <linux/etherdevice.h> /* eth_type_trans */
+#include <linux/skbuff.h>
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/hugetlb.h>
+#include <linux/in6.h>
+#include <linux/timer.h>
+#include <linux/io.h>
+#include <linux/ctype.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+
+#include <asm/checksum.h>
+#include <asm/homecache.h>
+#include <gxio/mpipe.h>
+#include <arch/sim.h>
+
+/* Define to support GSO. */
+#undef TILE_NET_GSO
+
+/* Define to support TSO. */
+#define TILE_NET_TSO
+
+/* Use 3000 to enable the Linux Traffic Control (QoS) layer, else 0. */
+#define TILE_NET_TX_QUEUE_LEN 0
+
+/* Define to dump packets (prints out the whole packet on tx and rx). */
+#undef TILE_NET_DUMP_PACKETS
+
+/* Default transmit lockup timeout period, in jiffies. */
+#define TILE_NET_TIMEOUT (5 * HZ)
+
+/* The maximum number of distinct channels (idesc.channel is 5 bits). */
+#define TILE_NET_CHANNELS 32
+
+/* Maximum number of idescs to handle per "poll". */
+#define TILE_NET_BATCH 128
+
+/* Maximum number of packets to handle per "poll". */
+#define TILE_NET_WEIGHT 64
+
+/* Number of entries in each iqueue. */
+#define IQUEUE_ENTRIES 512
+
+/* Number of entries in each equeue. */
+#define EQUEUE_ENTRIES 2048
+
+/* Total header bytes per equeue slot. Must be big enough for 2 bytes
+ * of NET_IP_ALIGN alignment, plus 14 bytes (?) of L2 header, plus up to
+ * 60 bytes of actual TCP header. We round up to align to cache lines.
+ */
+#define HEADER_BYTES 128
+
+/* Maximum completions per cpu per device (must be a power of two).
+ * ISSUE: What is the right number here?
+ */
+#define TILE_NET_MAX_COMPS 64
+
+#define MAX_FRAGS (65536 / PAGE_SIZE + 2 + 1)
+
+MODULE_AUTHOR("Tilera Corporation");
+MODULE_LICENSE("GPL");
+
+/* A "packet fragment" (a chunk of memory). */
+struct frag {
+ void *buf;
+ size_t length;
+};
+
+/* A single completion. */
+struct tile_net_comp {
+ /* The "complete_count" when the completion will be complete. */
+ s64 when;
+ /* The buffer to be freed when the completion is complete. */
+ struct sk_buff *skb;
+};
+
+/* The completions for a given cpu and device. */
+struct tile_net_comps {
+ /* The completions. */
+ struct tile_net_comp comp_queue[TILE_NET_MAX_COMPS];
+ /* The number of completions used. */
+ unsigned long comp_next;
+ /* The number of completions freed. */
+ unsigned long comp_last;
+};
+
+/* Info for a specific cpu. */
+struct tile_net_info {
+ /* The NAPI struct. */
+ struct napi_struct napi;
+ /* Packet queue. */
+ gxio_mpipe_iqueue_t iqueue;
+ /* Our cpu. */
+ int my_cpu;
+ /* True if iqueue is valid. */
+ bool has_iqueue;
+ /* NAPI flags. */
+ bool napi_added;
+ bool napi_enabled;
+ /* Number of small sk_buffs which must still be provided. */
+ unsigned int num_needed_small_buffers;
+ /* Number of large sk_buffs which must still be provided. */
+ unsigned int num_needed_large_buffers;
+ /* A timer for handling egress completions. */
+ struct timer_list egress_timer;
+ /* True if "egress_timer" is scheduled. */
+ bool egress_timer_scheduled;
+ /* Comps for each egress channel. */
+ struct tile_net_comps *comps_for_echannel[TILE_NET_CHANNELS];
+};
+
+/* Info for egress on a particular egress channel. */
+struct tile_net_egress {
+ /* The "equeue". */
+ gxio_mpipe_equeue_t *equeue;
+ /* The headers for TSO. */
+ unsigned char *headers;
+};
+
+/* Info for a specific device. */
+struct tile_net_priv {
+ /* Our network device. */
+ struct net_device *dev;
+ /* The primary link. */
+ gxio_mpipe_link_t link;
+ /* The primary channel, if open, else -1. */
+ int channel;
+ /* The "loopify" egress link, if needed. */
+ gxio_mpipe_link_t loopify_link;
+ /* The "loopify" egress channel, if open, else -1. */
+ int loopify_channel;
+ /* The egress channel (channel or loopify_channel). */
+ int echannel;
+ /* Total stats. */
+ struct net_device_stats stats;
+};
+
+/* Egress info, indexed by "priv->echannel" (lazily created as needed). */
+static struct tile_net_egress egress_for_echannel[TILE_NET_CHANNELS];
+
+/* Devices currently associated with each channel.
+ * NOTE: The array entry can become NULL after ifconfig down, but
+ * we do not free the underlying net_device structures, so it is
+ * safe to use a pointer after reading it from this array.
+ */
+static struct net_device *tile_net_devs_for_channel[TILE_NET_CHANNELS];
+
+/* A mutex for "tile_net_devs_for_channel". */
+static DEFINE_MUTEX(tile_net_devs_for_channel_mutex);
+
+/* The per-cpu info. */
+static DEFINE_PER_CPU(struct tile_net_info, per_cpu_info);
+
+/* The "context" for all devices. */
+static gxio_mpipe_context_t context;
+
+/* The small/large "buffer stacks". */
+static int small_buffer_stack = -1;
+static int large_buffer_stack = -1;
+
+/* The buckets. */
+static int first_bucket = -1;
+static int num_buckets = 1;
+
+/* The ingress irq. */
+static int ingress_irq = -1;
+
+/* Text value of tile_net.cpus if passed as a module parameter. */
+static char *network_cpus_string;
+
+/* The actual cpus in "network_cpus". */
+static struct cpumask network_cpus_map;
+
+/* If "loopify=LINK" was specified, this is "LINK". */
+static char *loopify_link_name;
+
+/* The "tile_net.cpus" argument specifies the cpus that are dedicated
+ * to handle ingress packets.
+ *
+ * The parameter should be in the form "tile_net.cpus=m-n[,x-y]", where
+ * m, n, x, y are integer numbers that represent the cpus that can be
+ * neither a dedicated cpu nor a dataplane cpu.
+ */
+static bool network_cpus_init(void)
+{
+ char buf[1024];
+ int rc;
+
+ if (network_cpus_string == NULL)
+ return false;
+
+ rc = cpulist_parse_crop(network_cpus_string, &network_cpus_map);
+ if (rc != 0) {
+ pr_warn("tile_net.cpus=%s: malformed cpu list\n",
+ network_cpus_string);
+ return false;
+ }
+
+ /* Remove dedicated cpus. */
+ cpumask_and(&network_cpus_map, &network_cpus_map, cpu_possible_mask);
+
+ if (cpumask_empty(&network_cpus_map)) {
+ pr_warn("Ignoring empty tile_net.cpus='%s'.\n",
+ network_cpus_string);
+ return false;
+ }
+
+ cpulist_scnprintf(buf, sizeof(buf), &network_cpus_map);
+ pr_info("Linux network CPUs: %s\n", buf);
+ return true;
+}
+
+module_param_named(cpus, network_cpus_string, charp, 0444);
+MODULE_PARM_DESC(cpus, "cpulist of cores that handle network interrupts");
+
+/* The "tile_net.loopify=LINK" argument causes the named device to
+ * actually use "loop0" for ingress, and "loop1" for egress. This
+ * allows an app to sit between the actual link and linux, passing
+ * (some) packets along to linux, and forwarding (some) packets sent
+ * out by linux.
+ */
+module_param_named(loopify, loopify_link_name, charp, 0444);
+MODULE_PARM_DESC(loopify, "name the device to use loop0/1 for ingress/egress");
+
+#ifdef TILE_NET_DUMP_PACKETS
+/* Dump a packet. */
+static void dump_packet(unsigned char *data, unsigned long length, char *s)
+{
+ unsigned long i;
+ static unsigned int count;
+ char buf[128];
+
+ pr_info("Dumping %s packet of 0x%lx bytes at %p [%d]\n",
+ s, length, data, count++);
+
+ pr_info("\n");
+
+ for (i = 0; i < length; i++) {
+ if ((i & 0xf) == 0)
+ sprintf(buf, "%8.8lx:", i);
+ sprintf(buf + strlen(buf), " %02x", data[i]);
+ if ((i & 0xf) == 0xf || i == length - 1)
+ pr_info("%s\n", buf);
+ }
+
+ pr_info("\n");
+}
+#endif
+
+/* Allocate and push a buffer. */
+static bool tile_net_provide_buffer(bool small)
+{
+ int stack = small ? small_buffer_stack : large_buffer_stack;
+
+ /* Buffers must be aligned. */
+ const unsigned long align = 128;
+
+ /* Note that "dev_alloc_skb()" adds NET_SKB_PAD more bytes,
+ * and also "reserves" that many bytes.
+ */
+ int len = sizeof(struct sk_buff **) + align + (small ? 128 : 1664);
+
+ /* Allocate (or fail). */
+ struct sk_buff *skb = dev_alloc_skb(len);
+ if (skb == NULL)
+ return false;
+
+ /* Make room for a back-pointer to 'skb'. */
+ skb_reserve(skb, sizeof(struct sk_buff **));
+
+ /* Make sure we are aligned. */
+ skb_reserve(skb, -(long)skb->data & (align - 1));
+
+ /* Save a back-pointer to 'skb'. */
+ *(struct sk_buff **)(skb->data - sizeof(struct sk_buff **)) = skb;
+
+ /* Make sure "skb" and the back-pointer have been flushed. */
+ wmb();
+
+ gxio_mpipe_push_buffer(&context, stack,
+ (void *)va_to_tile_io_addr(skb->data));
+
+ return true;
+}
+
+static void tile_net_pop_all_buffers(int stack)
+{
+ void *va;
+ while ((va = gxio_mpipe_pop_buffer(&context, stack)) != NULL) {
+ struct sk_buff **skb_ptr = va - sizeof(*skb_ptr);
+ struct sk_buff *skb = *skb_ptr;
+ dev_kfree_skb_irq(skb);
+ }
+}
+
+/* Provide linux buffers to mPIPE. */
+static void tile_net_provide_needed_buffers(struct tile_net_info *info)
+{
+ while (info->num_needed_small_buffers != 0) {
+ if (!tile_net_provide_buffer(true))
+ goto oops;
+ info->num_needed_small_buffers--;
+ }
+
+ while (info->num_needed_large_buffers != 0) {
+ if (!tile_net_provide_buffer(false))
+ goto oops;
+ info->num_needed_large_buffers--;
+ }
+
+ return;
+
+oops:
+ /* Add a description to the page allocation failure dump. */
+ pr_notice("Tile %d still needs some buffers\n", info->my_cpu);
+}
+
+/* Handle a packet. Return true if "processed", false if "filtered". */
+static bool tile_net_handle_packet(struct tile_net_info *info,
+ gxio_mpipe_idesc_t *idesc)
+{
+ struct net_device *dev = tile_net_devs_for_channel[idesc->channel];
+ uint8_t l2_offset = gxio_mpipe_idesc_get_l2_offset(idesc);
+ void *va;
+ void *buf;
+ unsigned long len;
+ int filter = 0;
+
+ /* Drop packets for which no buffer was available.
+ * NOTE: This happens under heavy load.
+ */
+ if (idesc->be) {
+ gxio_mpipe_iqueue_consume(&info->iqueue, idesc);
+ if (net_ratelimit())
+ pr_info("Dropping packet (insufficient buffers).\n");
+ return false;
+ }
+
+ /* Get the raw buffer VA. */
+ va = tile_io_addr_to_va((unsigned long)gxio_mpipe_idesc_get_va(idesc));
+
+ /* Get the actual packet start/length. */
+ buf = va + l2_offset;
+ len = gxio_mpipe_idesc_get_l2_length(idesc);
+
+ /* Point "va" at the raw buffer. */
+ va -= NET_IP_ALIGN;
+
+#ifdef TILE_NET_DUMP_PACKETS
+ dump_packet(buf, len, "rx");
+#endif
+
+ if (dev != NULL) {
+ /* ISSUE: Is this needed? */
+ dev->last_rx = jiffies;
+ }
+
+ if (dev == NULL || !(dev->flags & IFF_UP)) {
+ /* Filter packets received before we're up. */
+ filter = 1;
+ } else if (!(dev->flags & IFF_PROMISC)) {
+ /* ISSUE: "eth_type_trans()" implies that "IFF_PROMISC"
+ * is set for "all silly devices", however, it appears
+ * to NOT be set for us, so this code here DOES run.
+ */
+ if (!is_multicast_ether_addr(buf)) {
+ /* Filter packets not for our address. */
+ const u8 *mine = dev->dev_addr;
+ filter = compare_ether_addr(mine, buf);
+ }
+ }
+
+ if (filter) {
+
+ /* ISSUE: Update "drop" statistics? */
+
+ gxio_mpipe_iqueue_drop(&info->iqueue, idesc);
+
+ } else {
+
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ /* Acquire the associated "skb". */
+ struct sk_buff **skb_ptr = va - sizeof(*skb_ptr);
+ struct sk_buff *skb = *skb_ptr;
+
+ /* Paranoia. */
+ if (skb->data != va) {
+ /* Panic here since there's a reasonable chance
+ * that corrupt buffers means generic memory
+ * corruption, with unpredictable system effects.
+ */
+ panic("Corrupt linux buffer! "
+ "buf=%p, skb=%p, skb->data=%p",
+ buf, skb, skb->data);
+ }
+
+ /* Skip headroom, and any custom header. */
+ skb_reserve(skb, NET_IP_ALIGN + l2_offset);
+
+ /* Encode the actual packet length. */
+ skb_put(skb, len);
+
+ /* NOTE: This call also sets "skb->dev = dev".
+ * ISSUE: The classifier provides us with "eth_type"
+ * (aka "eth->h_proto"), which is basically the value
+ * returned by "eth_type_trans()".
+ * Note that "eth_type_trans()" computes "skb->pkt_type",
+ * which would be useful for the "filter" check above,
+ * if we had a (modifiable) "skb" to work with.
+ */
+ skb->protocol = eth_type_trans(skb, dev);
+
+ /* Acknowledge "good" hardware checksums. */
+ if (idesc->cs && idesc->csum_seed_val == 0xFFFF)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ netif_receive_skb(skb);
+
+ /* Update stats. */
+ atomic_add(1, (atomic_t *)&priv->stats.rx_packets);
+ atomic_add(len, (atomic_t *)&priv->stats.rx_bytes);
+
+ /* Need a new buffer. */
+ if (idesc->size == GXIO_MPIPE_BUFFER_SIZE_128)
+ info->num_needed_small_buffers++;
+ else
+ info->num_needed_large_buffers++;
+ }
+
+ gxio_mpipe_iqueue_consume(&info->iqueue, idesc);
+
+ return !filter;
+}
+
+/* Handle some packets for the current CPU.
+ *
+ * This function handles up to TILE_NET_BATCH idescs per call.
+ *
+ * ISSUE: Since we do not provide new buffers until this function is
+ * complete, we must initially provide enough buffers for each network
+ * cpu to fill its iqueue and also its batched idescs.
+ *
+ * ISSUE: The "rotting packet" race condition occurs if a packet
+ * arrives after the queue appears to be empty, and before the
+ * hypervisor interrupt is re-enabled.
+ */
+static int tile_net_poll(struct napi_struct *napi, int budget)
+{
+ struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
+ unsigned int work = 0;
+ gxio_mpipe_idesc_t *idesc;
+ int i, n;
+
+ /* Process packets. */
+ while ((n = gxio_mpipe_iqueue_try_peek(&info->iqueue, &idesc)) > 0) {
+ for (i = 0; i < n; i++) {
+ if (i == TILE_NET_BATCH)
+ goto done;
+ if (tile_net_handle_packet(info, idesc + i)) {
+ if (++work >= budget)
+ goto done;
+ }
+ }
+ }
+
+ /* There are no packets left. */
+ napi_complete(&info->napi);
+
+ /* Re-enable hypervisor interrupts. */
+ gxio_mpipe_enable_notif_ring_interrupt(&context, info->iqueue.ring);
+
+ /* HACK: Avoid the "rotting packet" problem. */
+ if (gxio_mpipe_iqueue_try_peek(&info->iqueue, &idesc) > 0)
+ napi_schedule(&info->napi);
+
+ /* ISSUE: Handle completions? */
+
+done:
+ tile_net_provide_needed_buffers(info);
+
+ return work;
+}
+
+/* Handle an ingress interrupt on the current cpu. */
+static irqreturn_t tile_net_handle_ingress_irq(int irq, void *unused)
+{
+ struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
+ napi_schedule(&info->napi);
+ return IRQ_HANDLED;
+}
+
+/* Free some completions. This must be called with interrupts blocked. */
+static void tile_net_free_comps(gxio_mpipe_equeue_t *equeue,
+ struct tile_net_comps *comps,
+ int limit, bool force_update)
+{
+ int n = 0;
+ while (comps->comp_last < comps->comp_next) {
+ unsigned int cid = comps->comp_last % TILE_NET_MAX_COMPS;
+ struct tile_net_comp *comp = &comps->comp_queue[cid];
+ if (!gxio_mpipe_equeue_is_complete(equeue, comp->when,
+ force_update || n == 0))
+ return;
+ dev_kfree_skb_irq(comp->skb);
+ comps->comp_last++;
+ if (++n == limit)
+ return;
+ }
+}
+
+/* Make sure the egress timer is scheduled.
+ *
+ * Note that we use "schedule if not scheduled" logic instead of the more
+ * obvious "reschedule" logic, because "reschedule" is fairly expensive.
+ */
+static void tile_net_schedule_egress_timer(struct tile_net_info *info)
+{
+ if (!info->egress_timer_scheduled) {
+ mod_timer_pinned(&info->egress_timer, jiffies + 1);
+ info->egress_timer_scheduled = true;
+ }
+}
+
+/* The "function" for "info->egress_timer".
+ *
+ * This timer will reschedule itself as long as there are any pending
+ * completions expected for this tile.
+ */
+static void tile_net_handle_egress_timer(unsigned long arg)
+{
+ struct tile_net_info *info = (struct tile_net_info *)arg;
+ unsigned long irqflags;
+ bool pending = false;
+ int i;
+
+ local_irq_save(irqflags);
+
+ /* The timer is no longer scheduled. */
+ info->egress_timer_scheduled = false;
+
+ /* Free all possible comps for this tile. */
+ for (i = 0; i < TILE_NET_CHANNELS; i++) {
+ struct tile_net_egress *egress = &egress_for_echannel[i];
+ struct tile_net_comps *comps = info->comps_for_echannel[i];
+ if (comps->comp_last >= comps->comp_next)
+ continue;
+ tile_net_free_comps(egress->equeue, comps, -1, true);
+ pending = pending || (comps->comp_last < comps->comp_next);
+ }
+
+ /* Reschedule timer if needed. */
+ if (pending)
+ tile_net_schedule_egress_timer(info);
+
+ local_irq_restore(irqflags);
+}
+
+/* Prepare each CPU. */
+static void tile_net_prepare_cpu(void *unused)
+{
+ struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
+ int my_cpu = smp_processor_id();
+
+ info->has_iqueue = false;
+
+ info->my_cpu = my_cpu;
+
+ /* Initialize the egress timer. */
+ init_timer(&info->egress_timer);
+ info->egress_timer.data = (long)info;
+ info->egress_timer.function = tile_net_handle_egress_timer;
+}
+
+/* Helper function for "tile_net_update()". */
+static void tile_net_update_cpu(void *arg)
+{
+ struct net_device *dev = arg;
+ struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
+
+ if (info->has_iqueue) {
+ if (dev != NULL) {
+ if (!info->napi_added) {
+ netif_napi_add(dev, &info->napi,
+ tile_net_poll, TILE_NET_WEIGHT);
+ info->napi_added = true;
+ }
+ if (!info->napi_enabled) {
+ napi_enable(&info->napi);
+ info->napi_enabled = true;
+ }
+ enable_percpu_irq(ingress_irq, 0);
+ } else {
+ disable_percpu_irq(ingress_irq);
+ if (info->napi_enabled) {
+ napi_disable(&info->napi);
+ info->napi_enabled = false;
+ }
+ /* FIXME: Drain the iqueue. */
+ }
+ }
+}
+
+/* Helper function for tile_net_open() and tile_net_stop().
+ * Always called under tile_net_devs_for_channel_mutex.
+ */
+static int tile_net_update(struct net_device *dev)
+{
+ int channel;
+ long count = 0;
+ int cpu;
+ int rc;
+ bool saw_channel;
+ static gxio_mpipe_rules_t rules;
+
+ gxio_mpipe_rules_init(&rules, &context);
+
+ saw_channel = false;
+ for (channel = 0; channel < TILE_NET_CHANNELS; channel++) {
+ if (tile_net_devs_for_channel[channel] == NULL)
+ continue;
+ if (!saw_channel) {
+ saw_channel = true;
+ gxio_mpipe_rules_begin(&rules, first_bucket,
+ num_buckets, NULL);
+ gxio_mpipe_rules_set_headroom(&rules, NET_IP_ALIGN);
+ }
+ gxio_mpipe_rules_add_channel(&rules, channel);
+ }
+
+ /* NOTE: This can fail if there is no classifier.
+ * ISSUE: Can anything else cause it to fail?
+ */
+ rc = gxio_mpipe_rules_commit(&rules);
+ if (rc != 0) {
+ netdev_warn(dev, "gxio_mpipe_rules_commit failed: %d\n", rc);
+ return -EIO;
+ }
+
+ /* Update all cpus, sequentially (to protect "netif_napi_add()"). */
+ for_each_online_cpu(cpu)
+ smp_call_function_single(cpu, tile_net_update_cpu,
+ (saw_channel ? dev : NULL), 1);
+
+ /* HACK: Allow packets to flow in the simulator. */
+ if (count != 0)
+ sim_enable_mpipe_links(0, -1);
+
+ return 0;
+}
+
+/* The first time any tilegx network device is opened, we initialize
+ * the global mpipe state. If this step fails, we fail to open the
+ * device, but if it succeeds, we never need to do it again, and since
+ * tile_net can't be unloaded, we never undo it.
+ *
+ * Note that some resources in this path (buffer stack indices,
+ * bindings from init_buffer_stack, etc.) are hypervisor resources
+ * that are freed simply via gxio_mpipe_destroy().
+ */
+static int tile_net_init_mpipe(struct net_device *dev)
+{
+ gxio_mpipe_buffer_size_enum_t small_buf_size =
+ GXIO_MPIPE_BUFFER_SIZE_128;
+ gxio_mpipe_buffer_size_enum_t large_buf_size =
+ GXIO_MPIPE_BUFFER_SIZE_1664;
+ size_t stack_bytes;
+ pte_t pte = { 0 };
+ void *small = NULL;
+ void *large = NULL;
+ int i, num_buffers, rc;
+ int network_cpus_count, cpu;
+ int ring, group, next_ring;
+ size_t comps_size = 0;
+ size_t notif_ring_size = 0;
+
+ if (!hash_default) {
+ netdev_err(dev, "Networking requires hash_default!\n");
+ return -EIO;
+ }
+
+ rc = gxio_mpipe_init(&context, 0);
+ if (rc != 0) {
+ netdev_err(dev, "gxio_mpipe_init failed: %d\n", rc);
+ return -EIO;
+ }
+
+ network_cpus_count = cpus_weight(network_cpus_map);
+
+ num_buffers =
+ network_cpus_count * (IQUEUE_ENTRIES + TILE_NET_BATCH);
+
+ /* Compute stack bytes; we round up to 64KB and then use
+ * alloc_pages() so we get the required 64KB alignment as well.
+ */
+ stack_bytes = ALIGN(gxio_mpipe_calc_buffer_stack_bytes(num_buffers),
+ 64 * 1024);
+
+ /* Allocate two buffer stack indices. */
+ rc = gxio_mpipe_alloc_buffer_stacks(&context, 2, 0, 0);
+ if (rc < 0) {
+ netdev_err(dev, "gxio_mpipe_alloc_buffer_stacks failed: %d\n",
+ rc);
+ goto fail;
+ }
+ small_buffer_stack = rc;
+ large_buffer_stack = rc + 1;
+
+ /* Allocate the small memory stack. */
+ small = alloc_pages_exact(stack_bytes, GFP_KERNEL);
+ if (small == NULL) {
+ netdev_err(dev,
+ "Could not alloc %zd bytes for buffer stacks\n",
+ stack_bytes);
+ rc = -ENOMEM;
+ goto fail;
+ }
+ rc = gxio_mpipe_init_buffer_stack(&context, small_buffer_stack,
+ small_buf_size,
+ small, stack_bytes, 0);
+ if (rc != 0) {
+ netdev_err(dev, "gxio_mpipe_init_buffer_stack: %d\n", rc);
+ goto fail;
+ }
+
+ /* Allocate the large buffer stack. */
+ large = alloc_pages_exact(stack_bytes, GFP_KERNEL);
+ if (large == NULL) {
+ netdev_err(dev,
+ "Could not alloc %zd bytes for buffer stacks\n",
+ stack_bytes);
+ rc = -ENOMEM;
+ goto fail;
+ }
+ rc = gxio_mpipe_init_buffer_stack(&context, large_buffer_stack,
+ large_buf_size,
+ large, stack_bytes, 0);
+ if (rc != 0) {
+ netdev_err(dev, "gxio_mpipe_init_buffer_stack failed: %d\n",
+ rc);
+ goto fail;
+ }
+
+ /* Register all the client memory in mpipe TLBs. */
+ pte = pte_set_home(pte, PAGE_HOME_HASH);
+ rc = gxio_mpipe_register_client_memory(&context, small_buffer_stack,
+ pte, 0);
+ if (rc != 0) {
+ netdev_err(dev,
+ "gxio_mpipe_register_buffer_memory failed: %d\n",
+ rc);
+ goto fail;
+ }
+ rc = gxio_mpipe_register_client_memory(&context, large_buffer_stack,
+ pte, 0);
+ if (rc != 0) {
+ netdev_err(dev,
+ "gxio_mpipe_register_buffer_memory failed: %d\n",
+ rc);
+ goto fail;
+ }
+
+ /* Provide initial buffers. */
+ rc = -ENOMEM;
+ for (i = 0; i < num_buffers; i++) {
+ if (!tile_net_provide_buffer(true)) {
+ netdev_err(dev, "Cannot allocate initial sk_bufs!\n");
+ goto fail_pop;
+ }
+ }
+ for (i = 0; i < num_buffers; i++) {
+ if (!tile_net_provide_buffer(false)) {
+ netdev_err(dev, "Cannot allocate initial sk_bufs!\n");
+ goto fail_pop;
+ }
+ }
+
+ /* Allocate one NotifRing for each network cpu. */
+ rc = gxio_mpipe_alloc_notif_rings(&context, network_cpus_count,
+ 0, 0);
+ if (rc < 0) {
+ netdev_err(dev, "gxio_mpipe_alloc_notif_rings failed %d\n",
+ rc);
+ goto fail_pop;
+ }
+
+ /* Init NotifRings. */
+ ring = rc;
+ next_ring = rc;
+
+ /* ISSUE: This is more than strictly necessary. */
+ comps_size = TILE_NET_CHANNELS * sizeof(struct tile_net_comps);
+
+ notif_ring_size = IQUEUE_ENTRIES * sizeof(gxio_mpipe_idesc_t);
+
+ for_each_online_cpu(cpu) {
+
+ int order;
+ struct page *page;
+ void *addr;
+
+ struct tile_net_info *info = &per_cpu(per_cpu_info, cpu);
+
+ /* Allocate the "comps". */
+ order = get_order(comps_size);
+ page = homecache_alloc_pages(GFP_KERNEL, order, cpu);
+ if (page == NULL) {
+ netdev_err(dev,
+ "Failed to alloc %zd bytes comps memory\n",
+ comps_size);
+ rc = -ENOMEM;
+ goto fail_pop;
+ }
+
+ addr = pfn_to_kaddr(page_to_pfn(page));
+ memset(addr, 0, comps_size);
+ for (i = 0; i < TILE_NET_CHANNELS; i++)
+ info->comps_for_echannel[i] =
+ addr + i * sizeof(struct tile_net_comps);
+
+ /* Only network cpus can receive packets. */
+ if (!cpu_isset(cpu, network_cpus_map))
+ continue;
+
+ /* Allocate the actual idescs array. */
+ order = get_order(notif_ring_size);
+ page = homecache_alloc_pages(GFP_KERNEL, order, cpu);
+ if (page == NULL) {
+ netdev_err(dev,
+ "Failed to alloc %zd bytes iqueue memory\n",
+ notif_ring_size);
+ rc = -ENOMEM;
+ goto fail_pop;
+ }
+ addr = pfn_to_kaddr(page_to_pfn(page));
+ rc = gxio_mpipe_iqueue_init(&info->iqueue, &context, next_ring,
+ addr, notif_ring_size, 0);
+ if (rc != 0) {
+ netdev_err(dev,
+ "gxio_mpipe_iqueue_init failed: %d\n", rc);
+ goto fail_pop;
+ }
+
+ info->has_iqueue = true;
+
+ next_ring++;
+ }
+
+ /* Allocate one NotifGroup. */
+ rc = gxio_mpipe_alloc_notif_groups(&context, 1, 0, 0);
+ if (rc < 0) {
+ netdev_err(dev, "gxio_mpipe_alloc_notif_groups failed: %d\n",
+ rc);
+ goto fail_pop;
+ }
+ group = rc;
+
+ if (network_cpus_count > 4)
+ num_buckets = 256;
+ else if (network_cpus_count > 1)
+ num_buckets = 16;
+
+ /* Allocate some buckets. */
+ rc = gxio_mpipe_alloc_buckets(&context, num_buckets, 0, 0);
+ if (rc < 0) {
+ netdev_err(dev, "gxio_mpipe_alloc_buckets failed: %d\n", rc);
+ goto fail_pop;
+ }
+ first_bucket = rc;
+
+ /* Init group and buckets. */
+ rc = gxio_mpipe_init_notif_group_and_buckets(
+ &context, group, ring, network_cpus_count,
+ first_bucket, num_buckets,
+ GXIO_MPIPE_BUCKET_STICKY_FLOW_LOCALITY);
+
+ if (rc != 0) {
+ netdev_err(
+ dev,
+ "gxio_mpipe_init_notif_group_and_buckets failed: %d\n",
+ rc);
+ goto fail_pop;
+ }
+
+ /* Create an irq and register it. Note that "ingress_irq" being
+ * initialized is how we know not to call this function again.
+ */
+ rc = create_irq();
+ if (rc < 0) {
+ netdev_err(dev, "create_irq failed: %d\n", rc);
+ goto fail_pop;
+
+ }
+ ingress_irq = rc;
+ tile_irq_activate(ingress_irq, TILE_IRQ_PERCPU);
+ rc = request_irq(ingress_irq, tile_net_handle_ingress_irq,
+ 0, NULL, NULL);
+ if (rc != 0) {
+ netdev_err(dev, "request_irq failed: %d\n", rc);
+ destroy_irq(ingress_irq);
+ ingress_irq = -1;
+ goto fail_pop;
+ }
+
+ for_each_online_cpu(cpu) {
+ struct tile_net_info *info = &per_cpu(per_cpu_info, cpu);
+ if (info->has_iqueue) {
+ gxio_mpipe_request_notif_ring_interrupt(
+ &context, cpu_x(cpu), cpu_y(cpu),
+ 1, ingress_irq, info->iqueue.ring);
+ }
+ }
+
+ return 0;
+
+fail_pop:
+ /* Do cleanups that require the mpipe context first. */
+ tile_net_pop_all_buffers(small_buffer_stack);
+ tile_net_pop_all_buffers(large_buffer_stack);
+
+fail:
+ /* Destroy mpipe context so the hardware no longer owns any memory. */
+ gxio_mpipe_destroy(&context);
+
+ for_each_online_cpu(cpu) {
+ struct tile_net_info *info = &per_cpu(per_cpu_info, cpu);
+ free_pages((unsigned long)(info->comps_for_echannel[0]),
+ get_order(comps_size));
+ info->comps_for_echannel[0] = NULL;
+ free_pages((unsigned long)(info->iqueue.idescs),
+ get_order(notif_ring_size));
+ info->iqueue.idescs = NULL;
+ }
+
+ if (small)
+ free_pages_exact(small, stack_bytes);
+ if (large)
+ free_pages_exact(large, stack_bytes);
+
+ large_buffer_stack = -1;
+ small_buffer_stack = -1;
+ first_bucket = -1;
+
+ return rc;
+}
+
+/* Create persistent egress info for a given egress channel.
+ *
+ * Note that this may be shared between, say, "gbe0" and "xgbe0".
+ *
+ * ISSUE: Defer header allocation until TSO is actually needed?
+ */
+static int tile_net_init_egress(struct net_device *dev, int echannel)
+{
+ size_t headers_order;
+ struct page *headers_page;
+ unsigned char *headers;
+
+ size_t edescs_size;
+ int edescs_order;
+ struct page *edescs_page;
+ gxio_mpipe_edesc_t *edescs;
+
+ int equeue_order;
+ struct page *equeue_page;
+ gxio_mpipe_equeue_t *equeue;
+ int edma;
+
+ int rc = -ENOMEM;
+
+ /* Only initialize once. */
+ if (egress_for_echannel[echannel].equeue != NULL)
+ return 0;
+
+ /* Allocate memory for the "headers". */
+ headers_order = get_order(EQUEUE_ENTRIES * HEADER_BYTES);
+ headers_page = alloc_pages(GFP_KERNEL, headers_order);
+ if (headers_page == NULL) {
+ netdev_warn(dev,
+ "Could not alloc %zd bytes for TSO headers.\n",
+ PAGE_SIZE << headers_order);
+ goto fail;
+ }
+ headers = pfn_to_kaddr(page_to_pfn(headers_page));
+
+ /* Allocate memory for the "edescs". */
+ edescs_size = EQUEUE_ENTRIES * sizeof(*edescs);
+ edescs_order = get_order(edescs_size);
+ edescs_page = alloc_pages(GFP_KERNEL, edescs_order);
+ if (edescs_page == NULL) {
+ netdev_warn(dev,
+ "Could not alloc %zd bytes for eDMA ring.\n",
+ edescs_size);
+ goto fail_headers;
+ }
+ edescs = pfn_to_kaddr(page_to_pfn(edescs_page));
+
+ /* Allocate memory for the "equeue". */
+ equeue_order = get_order(sizeof(*equeue));
+ equeue_page = alloc_pages(GFP_KERNEL, equeue_order);
+ if (equeue_page == NULL) {
+ netdev_warn(dev,
+ "Could not alloc %zd bytes for equeue info.\n",
+ PAGE_SIZE << equeue_order);
+ goto fail_edescs;
+ }
+ equeue = pfn_to_kaddr(page_to_pfn(equeue_page));
+
+ /* Allocate an edma ring. Note that in practice this can't
+ * fail, which is good, because we will leak an edma ring if so.
+ */
+ rc = gxio_mpipe_alloc_edma_rings(&context, 1, 0, 0);
+ if (rc < 0) {
+ netdev_warn(dev, "gxio_mpipe_alloc_edma_rings failed: %d\n",
+ rc);
+ goto fail_equeue;
+ }
+ edma = rc;
+
+ /* Initialize the equeue. */
+ rc = gxio_mpipe_equeue_init(equeue, &context, edma, echannel,
+ edescs, edescs_size, 0);
+ if (rc != 0) {
+ netdev_err(dev, "gxio_mpipe_equeue_init failed: %d\n", rc);
+ goto fail_equeue;
+ }
+
+ /* Done. */
+ egress_for_echannel[echannel].equeue = equeue;
+ egress_for_echannel[echannel].headers = headers;
+ return 0;
+
+fail_equeue:
+ __free_pages(equeue_page, equeue_order);
+
+fail_edescs:
+ __free_pages(edescs_page, edescs_order);
+
+fail_headers:
+ __free_pages(headers_page, headers_order);
+
+fail:
+ return rc;
+}
+
+/* Return channel number for a newly-opened link. */
+static int tile_net_link_open(struct net_device *dev, gxio_mpipe_link_t *link,
+ const char *link_name)
+{
+ int rc = gxio_mpipe_link_open(link, &context, link_name, 0);
+ if (rc < 0) {
+ netdev_err(dev, "Failed to open '%s'\n", link_name);
+ return rc;
+ }
+ rc = gxio_mpipe_link_channel(link);
+ if (rc < 0 || rc >= TILE_NET_CHANNELS) {
+ netdev_err(dev, "gxio_mpipe_link_channel bad value: %d\n", rc);
+ gxio_mpipe_link_close(link);
+ return -EINVAL;
+ }
+ return rc;
+}
+
+/* Help the kernel activate the given network interface. */
+static int tile_net_open(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+ int rc;
+
+ mutex_lock(&tile_net_devs_for_channel_mutex);
+
+ /* Do one-time initialization the first time any device is opened. */
+ if (ingress_irq < 0) {
+ rc = tile_net_init_mpipe(dev);
+ if (rc != 0)
+ goto fail;
+ }
+
+ /* Determine if this is the "loopify" device. */
+ if (unlikely((loopify_link_name != NULL) &&
+ !strcmp(dev->name, loopify_link_name))) {
+ rc = tile_net_link_open(dev, &priv->link, "loop0");
+ if (rc < 0)
+ goto fail;
+ priv->channel = rc;
+ rc = tile_net_link_open(dev, &priv->loopify_link, "loop1");
+ if (rc < 0)
+ goto fail;
+ priv->loopify_channel = rc;
+ priv->echannel = rc;
+ } else {
+ rc = tile_net_link_open(dev, &priv->link, dev->name);
+ if (rc < 0)
+ goto fail;
+ priv->channel = rc;
+ priv->echannel = rc;
+ }
+
+ /* Initialize egress info (if needed). Once ever, per echannel. */
+ rc = tile_net_init_egress(dev, priv->echannel);
+ if (rc != 0)
+ goto fail;
+
+ tile_net_devs_for_channel[priv->channel] = dev;
+
+ rc = tile_net_update(dev);
+ if (rc != 0)
+ goto fail;
+
+ mutex_unlock(&tile_net_devs_for_channel_mutex);
+
+ /* Start our transmit queue. */
+ netif_start_queue(dev);
+
+ netif_carrier_on(dev);
+
+ return 0;
+
+fail:
+ if (priv->loopify_channel >= 0) {
+ if (gxio_mpipe_link_close(&priv->loopify_link) != 0)
+ netdev_warn(dev, "Failed to close loopify link!\n");
+ priv->loopify_channel = -1;
+ }
+ if (priv->channel >= 0) {
+ if (gxio_mpipe_link_close(&priv->link) != 0)
+ netdev_warn(dev, "Failed to close link!\n");
+ priv->channel = -1;
+ }
+
+ priv->echannel = -1;
+
+ tile_net_devs_for_channel[priv->channel] = NULL;
+
+ mutex_unlock(&tile_net_devs_for_channel_mutex);
+
+ /* Don't return raw gxio error codes to generic Linux. */
+ return (rc > -512) ? rc : -EIO;
+}
+
+/* Help the kernel deactivate the given network interface. */
+static int tile_net_stop(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ /* Stop our transmit queue. */
+ netif_stop_queue(dev);
+
+ mutex_lock(&tile_net_devs_for_channel_mutex);
+
+ tile_net_devs_for_channel[priv->channel] = NULL;
+
+ (void)tile_net_update(dev);
+
+ if (priv->loopify_channel >= 0) {
+ if (gxio_mpipe_link_close(&priv->loopify_link) != 0)
+ netdev_warn(dev, "Failed to close loopify link!\n");
+ priv->loopify_channel = -1;
+ }
+
+ if (priv->channel >= 0) {
+ if (gxio_mpipe_link_close(&priv->link) != 0)
+ netdev_warn(dev, "Failed to close link!\n");
+ priv->channel = -1;
+ }
+
+ priv->echannel = -1;
+
+ mutex_unlock(&tile_net_devs_for_channel_mutex);
+
+ return 0;
+}
+
+/* Determine the VA for a fragment. */
+static inline void *tile_net_frag_buf(skb_frag_t *f)
+{
+ unsigned long pfn = page_to_pfn(skb_frag_page(f));
+ return pfn_to_kaddr(pfn) + f->page_offset;
+}
+
+/* Used for paranoia to make sure we handle no ill-formed packets. */
+#define TSO_DROP_IF(cond) \
+ do { if (WARN_ON(cond)) return NETDEV_TX_OK; } while (0)
+
+
+/* This function takes "skb", consisting of a header template and a
+ * (presumably) huge payload, and egresses it as one or more segments
+ * (aka packets), each consisting of a (possibly modified) copy of the
+ * header plus a piece of the payload, via "tcp segmentation offload".
+ *
+ * Usually, "data" will contain the header template, of size "sh_len",
+ * and "sh->frags" will contain "skb->data_len" bytes of payload, and
+ * there will be "sh->gso_segs" segments.
+ *
+ * Sometimes, if "sendfile()" requires copying, we will be called with
+ * "data" containing the header and payload, with "frags" being empty.
+ *
+ * Sometimes, for example when using NFS over TCP, a single segment can
+ * span 3 fragments. This requires special care below.
+ *
+ * See "emulate_large_send_offload()" for some reference code, which
+ * does not handle checksumming.
+ */
+static int tile_net_tx_tso(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
+
+ struct tile_net_egress *egress = &egress_for_echannel[priv->echannel];
+ gxio_mpipe_equeue_t *equeue = egress->equeue;
+
+ struct tile_net_comps *comps =
+ info->comps_for_echannel[priv->echannel];
+
+ unsigned int len = skb->len;
+ unsigned char *data = skb->data;
+
+ /* The ip header follows the ethernet header. */
+ struct iphdr *ih = ip_hdr(skb);
+ unsigned int ih_len = ih->ihl * 4;
+
+ /* Note that "nh == iph", by definition. */
+ unsigned char *nh = skb_network_header(skb);
+ unsigned int eh_len = nh - data;
+
+ /* The tcp header follows the ip header. */
+ struct tcphdr *th = (struct tcphdr *)(nh + ih_len);
+ unsigned int th_len = th->doff * 4;
+
+ /* The total number of header bytes. */
+ unsigned int sh_len = eh_len + ih_len + th_len;
+
+ /* Help compute "jh->check". */
+ unsigned int isum_hack =
+ ((0xFFFF - ih->check) +
+ (0xFFFF - ih->tot_len) +
+ (0xFFFF - ih->id));
+
+ /* Help compute "uh->check". */
+ unsigned int tsum_hack = th->check + (0xFFFF ^ htons(len));
+
+ struct skb_shared_info *sh = skb_shinfo(skb);
+
+ /* The maximum payload size. */
+ unsigned int gso_size = sh->gso_size;
+
+ /* The size of the initial segments (including header). */
+ unsigned int mtu = sh_len + gso_size;
+
+ /* The size of the final segment (including header). */
+ unsigned int mtu2 = len - ((sh->gso_segs - 1) * gso_size);
+
+ /* Track tx stats. */
+ unsigned int tx_packets = 0;
+ unsigned int tx_bytes = 0;
+
+ /* Which segment are we on. */
+ unsigned int segment;
+
+ /* Get the initial ip "id". */
+ u16 id = ntohs(ih->id);
+
+ /* Get the initial tcp "seq". */
+ u32 seq = ntohl(th->seq);
+
+ /* The id of the current fragment (or -1). */
+ long f_id;
+
+ /* The size of the current fragment (or -1). */
+ long f_size;
+
+ /* The bytes used from the current fragment (or -1). */
+ long f_used;
+
+ /* The size of the current piece of payload. */
+ long n;
+
+ /* Prepare checksum info. */
+ unsigned int csum_start = skb_checksum_start_offset(skb);
+
+ /* The header/payload edesc's. */
+ gxio_mpipe_edesc_t edesc_head = { { 0 } };
+ gxio_mpipe_edesc_t edesc_body = { { 0 } };
+
+ /* Total number of edescs needed. */
+ unsigned int num_edescs = 0;
+
+ unsigned long irqflags;
+
+ /* First reserved egress slot. */
+ s64 slot;
+
+ int cid;
+
+ /* Empty packets (etc) would cause trouble below. */
+ TSO_DROP_IF(skb->data_len == 0);
+ TSO_DROP_IF(sh->nr_frags == 0);
+ TSO_DROP_IF(sh->gso_segs == 0);
+
+ /* We assume the frags contain the entire payload. */
+ TSO_DROP_IF(skb_headlen(skb) != sh_len);
+ TSO_DROP_IF(len != sh_len + skb->data_len);
+
+ /* Implicitly verify "gso_segs" and "gso_size". */
+ TSO_DROP_IF(mtu2 > mtu);
+
+ /* We only have HEADER_BYTES for each header. */
+ TSO_DROP_IF(NET_IP_ALIGN + sh_len > HEADER_BYTES);
+
+ /* Paranoia. */
+ TSO_DROP_IF(skb->protocol != htons(ETH_P_IP));
+ TSO_DROP_IF(ih->protocol != IPPROTO_TCP);
+ TSO_DROP_IF(skb->ip_summed != CHECKSUM_PARTIAL);
+ TSO_DROP_IF(csum_start != eh_len + ih_len);
+
+ /* NOTE: ".hwb = 0", so ".size" is unused.
+ * NOTE: ".stack_idx" determines the TLB.
+ */
+
+ /* Prepare to egress the headers. */
+ edesc_head.csum = 1;
+ edesc_head.csum_start = csum_start;
+ edesc_head.csum_dest = csum_start + skb->csum_offset;
+ edesc_head.xfer_size = sh_len;
+ edesc_head.stack_idx = large_buffer_stack;
+
+ /* Prepare to egress the body. */
+ edesc_body.stack_idx = large_buffer_stack;
+
+ /* Reset. */
+ f_id = -1;
+ f_size = -1;
+ f_used = -1;
+
+ /* Determine how many edesc's are needed. */
+ for (segment = 0; segment < sh->gso_segs; segment++) {
+
+ /* Detect the final segment. */
+ bool final = (segment == sh->gso_segs - 1);
+
+ /* The segment size (including header). */
+ unsigned int s_len = final ? mtu2 : mtu;
+
+ /* The size of the payload. */
+ unsigned int p_len = s_len - sh_len;
+
+ /* The bytes used from the payload. */
+ unsigned int p_used = 0;
+
+ /* One edesc for the header. */
+ num_edescs++;
+
+ /* One edesc for each piece of the payload. */
+ while (p_used < p_len) {
+
+ /* Advance as needed. */
+ while (f_used >= f_size) {
+ f_id++;
+ f_size = sh->frags[f_id].size;
+ f_used = 0;
+ }
+
+ /* Use bytes from the current fragment. */
+ n = p_len - p_used;
+ if (n > f_size - f_used)
+ n = f_size - f_used;
+ f_used += n;
+ p_used += n;
+
+ num_edescs++;
+ }
+ }
+
+ /* Verify all fragments consumed. */
+ TSO_DROP_IF(f_id + 1 != sh->nr_frags);
+ TSO_DROP_IF(f_used != f_size);
+
+ local_irq_save(irqflags);
+
+ /* Reserve slots, or return NETDEV_TX_BUSY if "full". */
+ slot = gxio_mpipe_equeue_try_reserve(equeue, num_edescs);
+ if (slot < 0) {
+ local_irq_restore(irqflags);
+ /* ISSUE: "Virtual device xxx asks to queue packet". */
+ return NETDEV_TX_BUSY;
+ }
+
+ /* Reset. */
+ f_id = -1;
+ f_size = -1;
+ f_used = -1;
+
+ /* Prepare all the headers. */
+ for (segment = 0; segment < sh->gso_segs; segment++) {
+
+ /* Detect the final segment. */
+ bool final = (segment == sh->gso_segs - 1);
+
+ /* The segment size (including header). */
+ unsigned int s_len = final ? mtu2 : mtu;
+
+ /* The size of the payload. */
+ unsigned int p_len = s_len - sh_len;
+
+ /* The bytes used from the payload. */
+ unsigned int p_used = 0;
+
+ /* Access the header memory for this segment. */
+ unsigned int bn = slot % EQUEUE_ENTRIES;
+ unsigned char *buf =
+ egress->headers + bn * HEADER_BYTES + NET_IP_ALIGN;
+
+ /* The soon-to-be copied "ip" header. */
+ struct iphdr *jh = (struct iphdr *)(buf + eh_len);
+
+ /* The soon-to-be copied "tcp" header. */
+ struct tcphdr *uh = (struct tcphdr *)(buf + eh_len + ih_len);
+
+ unsigned int jsum;
+
+ /* Copy the header. */
+ memcpy(buf, data, sh_len);
+
+ /* The packet size, not including ethernet header. */
+ jh->tot_len = htons(s_len - eh_len);
+
+ /* Update the ip "id". */
+ jh->id = htons(id);
+
+ /* Compute the "ip checksum". */
+ jsum = isum_hack + htons(s_len - eh_len) + htons(id);
+ jh->check = csum_long(jsum) ^ 0xffff;
+
+ /* Update the tcp "seq". */
+ uh->seq = htonl(seq);
+
+ /* Update some flags. */
+ if (!final) {
+ uh->fin = 0;
+ uh->psh = 0;
+ }
+
+ /* Compute the tcp pseudo-header checksum. */
+ uh->check = csum_long(tsum_hack + htons(s_len));
+
+ /* Skip past the header. */
+ slot++;
+
+ /* Skip past the payload. */
+ while (p_used < p_len) {
+
+ /* Advance as needed. */
+ while (f_used >= f_size) {
+ f_id++;
+ f_size = sh->frags[f_id].size;
+ f_used = 0;
+ }
+
+ /* Use bytes from the current fragment. */
+ n = p_len - p_used;
+ if (n > f_size - f_used)
+ n = f_size - f_used;
+ f_used += n;
+ p_used += n;
+
+ slot++;
+ }
+
+ id++;
+ seq += p_len;
+ }
+
+ /* Reset "slot". */
+ slot -= num_edescs;
+
+ /* Flush the headers. */
+ wmb();
+
+ /* Reset. */
+ f_id = -1;
+ f_size = -1;
+ f_used = -1;
+
+ /* Egress all the edescs. */
+ for (segment = 0; segment < sh->gso_segs; segment++) {
+
+ /* Detect the final segment. */
+ bool final = (segment == sh->gso_segs - 1);
+
+ /* The segment size (including header). */
+ unsigned int s_len = final ? mtu2 : mtu;
+
+ /* The size of the payload. */
+ unsigned int p_len = s_len - sh_len;
+
+ /* The bytes used from the payload. */
+ unsigned int p_used = 0;
+
+ /* Access the header memory for this segment. */
+ unsigned int bn = slot % EQUEUE_ENTRIES;
+ unsigned char *buf =
+ egress->headers + bn * HEADER_BYTES + NET_IP_ALIGN;
+
+ void *va;
+
+ /* Egress the header. */
+ edesc_head.va = va_to_tile_io_addr(buf);
+ gxio_mpipe_equeue_put_at(equeue, edesc_head, slot);
+ slot++;
+
+ /* Egress the payload. */
+ while (p_used < p_len) {
+
+ /* Advance as needed. */
+ while (f_used >= f_size) {
+ f_id++;
+ f_size = sh->frags[f_id].size;
+ f_used = 0;
+ }
+
+ va = tile_net_frag_buf(&sh->frags[f_id]) + f_used;
+
+ /* Use bytes from the current fragment. */
+ n = p_len - p_used;
+ if (n > f_size - f_used)
+ n = f_size - f_used;
+ f_used += n;
+ p_used += n;
+
+ /* Egress a piece of the payload. */
+ edesc_body.va = va_to_tile_io_addr(va);
+ edesc_body.xfer_size = n;
+ edesc_body.bound = !(p_used < p_len);
+ gxio_mpipe_equeue_put_at(equeue, edesc_body, slot);
+ slot++;
+ }
+
+ tx_packets++;
+ tx_bytes += s_len;
+ }
+
+ /* Wait for a free completion entry.
+ * ISSUE: Is this the best logic?
+ * ISSUE: Can this cause undesirable "blocking"?
+ */
+ while (comps->comp_next - comps->comp_last >= TILE_NET_MAX_COMPS - 1)
+ tile_net_free_comps(equeue, comps, 32, false);
+
+ /* Update the completions array. */
+ cid = comps->comp_next % TILE_NET_MAX_COMPS;
+ comps->comp_queue[cid].when = slot;
+ comps->comp_queue[cid].skb = skb;
+ comps->comp_next++;
+
+ /* Update stats. */
+ atomic_add(tx_packets, (atomic_t *)&priv->stats.tx_packets);
+ atomic_add(tx_bytes, (atomic_t *)&priv->stats.tx_bytes);
+
+ local_irq_restore(irqflags);
+
+ /* Make sure the egress timer is scheduled. */
+ tile_net_schedule_egress_timer(info);
+
+ return NETDEV_TX_OK;
+}
+
+/* Analyze the body and frags for a transmit request. */
+static unsigned int tile_net_tx_frags(struct frag *frags,
+ struct sk_buff *skb,
+ void *b_data, unsigned int b_len)
+{
+ unsigned int i, n = 0;
+
+ struct skb_shared_info *sh = skb_shinfo(skb);
+
+ if (b_len != 0) {
+ frags[n].buf = b_data;
+ frags[n++].length = b_len;
+ }
+
+ for (i = 0; i < sh->nr_frags; i++) {
+ skb_frag_t *f = &sh->frags[i];
+ frags[n].buf = tile_net_frag_buf(f);
+ frags[n++].length = skb_frag_size(f);
+ }
+
+ return n;
+}
+
+/* Help the kernel transmit a packet. */
+static int tile_net_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+
+ struct tile_net_info *info = &__get_cpu_var(per_cpu_info);
+
+ struct tile_net_egress *egress = &egress_for_echannel[priv->echannel];
+ gxio_mpipe_equeue_t *equeue = egress->equeue;
+
+ struct tile_net_comps *comps =
+ info->comps_for_echannel[priv->echannel];
+
+ struct skb_shared_info *sh = skb_shinfo(skb);
+
+ unsigned int len = skb->len;
+ unsigned char *data = skb->data;
+
+ unsigned int num_frags;
+ struct frag frags[MAX_FRAGS];
+ gxio_mpipe_edesc_t edescs[MAX_FRAGS];
+
+ unsigned int i;
+
+ int cid;
+
+ s64 slot;
+
+ unsigned long irqflags;
+
+ /* Save the timestamp. */
+ dev->trans_start = jiffies;
+
+#ifdef TILE_NET_DUMP_PACKETS
+ /* ISSUE: Does not dump the "frags". */
+ dump_packet(data, skb_headlen(skb), "tx");
+#endif
+
+ if (sh->gso_size != 0)
+ return tile_net_tx_tso(skb, dev);
+
+ /* NOTE: This is usually 2, sometimes 3, for big writes. */
+ num_frags = tile_net_tx_frags(frags, skb, data, skb_headlen(skb));
+
+ /* Prepare the edescs. */
+ for (i = 0; i < num_frags; i++) {
+
+ /* NOTE: ".hwb = 0", so ".size" is unused.
+ * NOTE: ".stack_idx" determines the TLB.
+ */
+
+ gxio_mpipe_edesc_t edesc = { { 0 } };
+
+ /* Prepare the basic command. */
+ edesc.bound = (i == num_frags - 1);
+ edesc.xfer_size = frags[i].length;
+ edesc.va = va_to_tile_io_addr(frags[i].buf);
+ edesc.stack_idx = large_buffer_stack;
+
+ edescs[i] = edesc;
+ }
+
+ /* Add checksum info if needed. */
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ unsigned int csum_start = skb->csum_start - skb_headroom(skb);
+ edescs[0].csum = 1;
+ edescs[0].csum_start = csum_start;
+ edescs[0].csum_dest = csum_start + skb->csum_offset;
+ }
+
+ local_irq_save(irqflags);
+
+ /* Reserve slots, or return NETDEV_TX_BUSY if "full". */
+ slot = gxio_mpipe_equeue_try_reserve(equeue, num_frags);
+ if (slot < 0) {
+ local_irq_restore(irqflags);
+ /* ISSUE: "Virtual device xxx asks to queue packet". */
+ return NETDEV_TX_BUSY;
+ }
+
+ for (i = 0; i < num_frags; i++)
+ gxio_mpipe_equeue_put_at(equeue, edescs[i], slot + i);
+
+ /* Wait for a free completion entry.
+ * ISSUE: Is this the best logic?
+ * ISSUE: Can this cause undesirable "blocking"?
+ */
+ while (comps->comp_next - comps->comp_last >= TILE_NET_MAX_COMPS - 1)
+ tile_net_free_comps(equeue, comps, 32, false);
+
+ /* Update the completions array. */
+ cid = comps->comp_next % TILE_NET_MAX_COMPS;
+ comps->comp_queue[cid].when = slot + num_frags;
+ comps->comp_queue[cid].skb = skb;
+ comps->comp_next++;
+
+ /* HACK: Track "expanded" size for short packets (e.g. 42 < 60). */
+ atomic_add(1, (atomic_t *)&priv->stats.tx_packets);
+ atomic_add((len >= ETH_ZLEN) ? len : ETH_ZLEN,
+ (atomic_t *)&priv->stats.tx_bytes);
+
+ local_irq_restore(irqflags);
+
+ /* Make sure the egress timer is scheduled. */
+ tile_net_schedule_egress_timer(info);
+
+ return NETDEV_TX_OK;
+}
+
+/* Deal with a transmit timeout. */
+static void tile_net_tx_timeout(struct net_device *dev)
+{
+ /* ISSUE: This doesn't seem useful for us. */
+ netif_wake_queue(dev);
+}
+
+/* Ioctl commands. */
+static int tile_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ return -EOPNOTSUPP;
+}
+
+/* Get system network statistics for device. */
+static struct net_device_stats *tile_net_get_stats(struct net_device *dev)
+{
+ struct tile_net_priv *priv = netdev_priv(dev);
+ return &priv->stats;
+}
+
+/* Change the MTU. */
+static int tile_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+ /* Check ranges. */
+ if ((new_mtu < 68) || (new_mtu > 1500))
+ return -EINVAL;
+
+ /* Accept the value. */
+ dev->mtu = new_mtu;
+
+ return 0;
+}
+
+/* Change the Ethernet address of the NIC.
+ *
+ * The hypervisor driver does not support changing MAC address. However,
+ * the hardware does not do anything with the MAC address, so the address
+ * which gets used on outgoing packets, and which is accepted on incoming
+ * packets, is completely up to us.
+ *
+ * Returns 0 on success, negative on failure.
+ */
+static int tile_net_set_mac_address(struct net_device *dev, void *p)
+{
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ return 0;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/* Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void tile_net_netpoll(struct net_device *dev)
+{
+ disable_percpu_irq(ingress_irq);
+ tile_net_handle_ingress_irq(ingress_irq, NULL);
+ enable_percpu_irq(ingress_irq, 0);
+}
+#endif
+
+static const struct net_device_ops tile_net_ops = {
+ .ndo_open = tile_net_open,
+ .ndo_stop = tile_net_stop,
+ .ndo_start_xmit = tile_net_tx,
+ .ndo_do_ioctl = tile_net_ioctl,
+ .ndo_get_stats = tile_net_get_stats,
+ .ndo_change_mtu = tile_net_change_mtu,
+ .ndo_tx_timeout = tile_net_tx_timeout,
+ .ndo_set_mac_address = tile_net_set_mac_address,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = tile_net_netpoll,
+#endif
+};
+
+/* The setup function.
+ *
+ * This uses ether_setup() to assign various fields in dev, including
+ * setting IFF_BROADCAST and IFF_MULTICAST, then sets some extra fields.
+ */
+static void tile_net_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+
+ dev->netdev_ops = &tile_net_ops;
+ dev->watchdog_timeo = TILE_NET_TIMEOUT;
+
+ /* We want lockless xmit. */
+ dev->features |= NETIF_F_LLTX;
+
+ /* We support hardware tx checksums. */
+ dev->features |= NETIF_F_HW_CSUM;
+
+ /* We support scatter/gather. */
+ dev->features |= NETIF_F_SG;
+
+#ifdef TILE_NET_GSO
+ /* We support GSO. */
+ dev->features |= NETIF_F_GSO;
+#endif
+
+#ifdef TILE_NET_TSO
+ /* We support TSO. */
+ dev->features |= NETIF_F_TSO;
+#endif
+
+ dev->tx_queue_len = TILE_NET_TX_QUEUE_LEN;
+
+ dev->mtu = 1500;
+}
+
+/* Allocate the device structure, register the device, and obtain the
+ * MAC address from the hypervisor.
+ */
+static void tile_net_dev_init(const char *name, const uint8_t *mac)
+{
+ int ret;
+ int i;
+ int nz_addr = 0;
+ struct net_device *dev;
+ struct tile_net_priv *priv;
+
+ /* HACK: Ignore "loop" links. */
+ if (strncmp(name, "loop", 4) == 0)
+ return;
+
+ /* Allocate the device structure. This allocates "priv", calls
+ * tile_net_setup(), and saves "name". Normally, "name" is a
+ * template, instantiated by register_netdev(), but not for us.
+ */
+ dev = alloc_netdev(sizeof(*priv), name, tile_net_setup);
+ if (!dev) {
+ pr_err("alloc_netdev(%s) failed\n", name);
+ return;
+ }
+
+ priv = netdev_priv(dev);
+
+ /* Initialize "priv". */
+
+ memset(priv, 0, sizeof(*priv));
+
+ priv->dev = dev;
+
+ priv->channel = -1;
+ priv->loopify_channel = -1;
+ priv->echannel = -1;
+
+ /* Register the network device. */
+ ret = register_netdev(dev);
+ if (ret) {
+ netdev_err(dev, "register_netdev failed %d\n", ret);
+ free_netdev(dev);
+ return;
+ }
+
+ /* Get the MAC address and set it in the device struct; this must
+ * be done before the device is opened. If the MAC is all zeroes,
+ * we use a random address, since we're probably on the simulator.
+ */
+ for (i = 0; i < 6; i++)
+ nz_addr |= mac[i];
+
+ if (nz_addr) {
+ memcpy(dev->dev_addr, mac, 6);
+ dev->addr_len = 6;
+ } else {
+ random_ether_addr(dev->dev_addr);
+ }
+}
+
+/* Module initialization. */
+static int __init tile_net_init_module(void)
+{
+ int i;
+ char name[GXIO_MPIPE_LINK_NAME_LEN];
+ uint8_t mac[6];
+
+ pr_info("Tilera Network Driver\n");
+
+ mutex_init(&tile_net_devs_for_channel_mutex);
+
+ /* Initialize each CPU. */
+ on_each_cpu(tile_net_prepare_cpu, NULL, 1);
+
+ /* Find out what devices we have, and initialize them. */
+ for (i = 0; gxio_mpipe_link_enumerate_mac(i, name, mac) >= 0; i++)
+ tile_net_dev_init(name, mac);
+
+ if (!network_cpus_init())
+ network_cpus_map = *cpu_online_mask;
+
+ return 0;
+}
+
+module_init(tile_net_init_module);
--
1.6.5.2
^ permalink raw reply related
* Re: [PATCH] net: skb_set_dev do not unconditionally drop ref to dst
From: Frank Blaschka @ 2012-05-09 10:48 UTC (permalink / raw)
To: David Miller; +Cc: netdev, arnd, linux-s390, eric.dumazet
In-Reply-To: <20120503.022837.2021054007853235758.davem@davemloft.net>
On Thu, May 03, 2012 at 02:28:37AM -0400, David Miller wrote:
> From: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Wed, 02 May 2012 08:59:21 +0200
>
> > If Arnd doesnt care to even reply, we can just revert his buggy
> > patch, instead of trying to understand and fix all issues.
>
> Agreed, it's the best sounding solution by far.
Hi Dave,
looks like discussion is done and everybody is ok with reverting
Arnds patch. Can you revert commit 8a83a00b0735190384a348156837918271034144 ?
Thx
Fran ?
Thx
Frank
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* RE: [PATCH] pch_gbe: Adding read memory barriers
From: David Laight @ 2012-05-09 10:47 UTC (permalink / raw)
To: Erwan Velu, netdev, linux-kernel; +Cc: tshimizu818
In-Reply-To: <4FA822C4.60809@gmail.com>
> Under a strong incoming packet stream and/or high cpu usage,
> the pch_gbe driver reports "Receive CRC Error" and discards packet.
>
> It occurred on an Intel ATOM E620T while running a
> 300mbit/sec multicast
> network stream leading to a ~100% cpu usage.
>
> Adding rmb() calls before considering the network card's status solve
> this issue.
>
> Getting it into stable would be perfect as it solves
> reliability issues.
>
> Signed-off-by: Erwan Velu <erwan.velu@zodiacaerospace.com>
> ---
> .../net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | 3 +++
> 1 files changed, 3 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
> b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
> index 8035e5f..ace3654 100644
> --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
> +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
> @@ -1413,6 +1413,7 @@ static irqreturn_t pch_gbe_intr(int
> irq, void *data)
> pch_gbe_mac_set_pause_packet(hw);
> }
> }
> + smp_rmb(); /* prevent any other reads before*/
Under the assumption that your memory references are uncached,
you only need to stop gcc reordering the object code,
Rather than actually adding one of the 'fence' instructions.
So you should only need: asm volatile(:::"memory")
NFI which define generates that, the defines in the copy of
sysdep.h I just looked at always include one of the fences.
David
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox