* Re: Kernel panic with the b44 driver in 2.6.35-rc1
From: François Valenduc @ 2010-06-01 18:06 UTC (permalink / raw)
To: netdev
In-Reply-To: <20100601133318.GA26701@tuxdriver.com>
Le 01/06/10 15:33, John W. Linville a écrit :
> On Mon, May 31, 2010 at 09:58:43PM +0200, news.gmane.org wrote:
>
>> I have a kernel panic at startup with the b44 driver with the 2.6.35-rc1
>> kernel. I have submitted a bug report (see
>> https://bugzilla.kernel.org/show_bug.cgi?id=16074) but until know, I
>> din't get any answer yet. Does anybody knows what's happening. I have
>> tried several git-bisect run but I didn't find any conclusive result.
>> The first bad-commit was different each time and if I revert it, the
>> problem still occurs anyway.
>
> This patch is already on its way to Linus -- it should fix the problem
> you are seeing:
>
> commit da1fdb02d9200ff28b6f3a380d21930335fe5429
> Author: Christoph Fritz <chf.fritz@googlemail.com>
> Date: Fri May 28 10:45:59 2010 +0200
>
> ssb: fix NULL ptr deref when pcihost_wrapper is used
>
> Ethernet driver b44 does register ssb by it's pcihost_wrapper
> and doesn't set ssb_chipcommon. A check on this value
> introduced with commit d53cdbb94a52a920d5420ed64d986c3523a56743
> and ea2db495f92ad2cf3301623e60cb95b4062bc484 triggers:
>
> BUG: unable to handle kernel NULL pointer dereference at 00000010
> IP: [<c1266c36>] ssb_is_sprom_available+0x16/0x30
>
> Signed-off-by: Christoph Fritz <chf.fritz@googlemail.com>
> Signed-off-by: John W. Linville <linville@tuxdriver.com>
>
This patch indeed solve my problem.
Thanks for your help,
François Valenduc
^ permalink raw reply
* Re: [RFC] netfilter: WIP: Xtables idletimer target implementation
From: Luciano Coelho @ 2010-06-01 18:33 UTC (permalink / raw)
To: ext Jan Engelhardt
Cc: ext Patrick McHardy, netfilter-devel@vger.kernel.org,
netdev@vger.kernel.org, Timo Teras
In-Reply-To: <alpine.LSU.2.01.1005312143470.23758@obet.zrqbmnf.qr>
On Mon, 2010-05-31 at 21:51 +0200, ext Jan Engelhardt wrote:
> On Monday 2010-05-31 21:12, Luciano Coelho wrote:
> >
> >I considered this option, but then I didn't find a proper place where to
> >include the attribute in sysfs, since I cannot add it as part of the
> >interface (eg. /sys/class/net/wlan0/idletimer) as I was doing before.
>
> You couldn't have done that before either, because the interface name
> in ipt_ip may refer to an interface that does not exist at all times.
>
> >The other option would be to make the idletimer as part of the
> >xt_IDLETIMER module object in sysfs
> >(ie. /sys/module/xt_IDLETIMER/<user_supplied_name>), but it looks out of
> >place.
>
> I like it. It follows /proc/net/xt_{hashlimit,recent}/<user_supplied_name>.
I'm starting to like this more and more too, as my code is getting much
smaller ;)
One quick question, though. Do you have any ideas on how I can make
sure that the user doesn't supply the same name twice (ie. two rules
with the same user_supplied_name)?
The problem is that the userspace always re-adds all the existing rules
before inserting a new one and only later deletes the old rules. :\
--
Cheers,
Luca.
^ permalink raw reply
* Re: [RFC] netfilter: WIP: Xtables idletimer target implementation
From: Jan Engelhardt @ 2010-06-01 18:38 UTC (permalink / raw)
To: Luciano Coelho
Cc: ext Patrick McHardy, netfilter-devel@vger.kernel.org,
netdev@vger.kernel.org, Timo Teras
In-Reply-To: <1275417197.14585.2.camel@powerslave>
On Tuesday 2010-06-01 20:33, Luciano Coelho wrote:
>On Mon, 2010-05-31 at 21:51 +0200, ext Jan Engelhardt wrote:
>> On Monday 2010-05-31 21:12, Luciano Coelho wrote:
>> >
>> >I considered this option, but then I didn't find a proper place where to
>> >include the attribute in sysfs, since I cannot add it as part of the
>> >interface (eg. /sys/class/net/wlan0/idletimer) as I was doing before.
>>
>> You couldn't have done that before either, because the interface name
>> in ipt_ip may refer to an interface that does not exist at all times.
>>
>> >The other option would be to make the idletimer as part of the
>> >xt_IDLETIMER module object in sysfs
>> >(ie. /sys/module/xt_IDLETIMER/<user_supplied_name>), but it looks out of
>> >place.
>>
>> I like it. It follows /proc/net/xt_{hashlimit,recent}/<user_supplied_name>.
>
>I'm starting to like this more and more too, as my code is getting much
>smaller ;)
>
>One quick question, though. Do you have any ideas on how I can make
>sure that the user doesn't supply the same name twice (ie. two rules
>with the same user_supplied_name)?
What's so bad about multiple rules being able to reset the timer?
^ permalink raw reply
* [PATCH] iproute2: add VF_PORT support
From: Scott Feldman @ 2010-06-01 18:40 UTC (permalink / raw)
To: shemminger; +Cc: chrisw, netdev, arnd
From: Scott Feldman <scofeldm@cisco.com>
Add support for recently added IFLA_VF_PORTS. VF port netlink msg layout is
[IFLA_NUM_VF]
[IFLA_VF_PORTS]
[IFLA_VF_PORT]
[IFLA_PORT_*], ...
[IFLA_VF_PORT]
[IFLA_PORT_*], ...
...
[IFLA_PORT_SELF]
[IFLA_PORT_*], ...
The iproute2 cmd line for link set is now:
Usage: ip link add link DEV [ name ] NAME
[ txqueuelen PACKETS ]
[ address LLADDR ]
[ broadcast LLADDR ]
[ mtu MTU ]
type TYPE [ ARGS ]
ip link delete DEV type TYPE [ ARGS ]
ip link set DEVICE [ { up | down } ]
[ arp { on | off } ]
[ dynamic { on | off } ]
[ multicast { on | off } ]
[ allmulticast { on | off } ]
[ promisc { on | off } ]
[ trailers { on | off } ]
[ txqueuelen PACKETS ]
[ name NEWNAME ]
[ address LLADDR ]
[ broadcast LLADDR ]
[ mtu MTU ]
[ netns PID ]
[ alias NAME ]
[ port MODE { PROFILE | VSI } ]
[ vf NUM [ mac LLADDR ]
[ vlan VLANID [ qos VLAN-QOS ] ]
[ rate TXRATE ]
[ port MODE { PROFILE | VSI } ] ]
ip link show [ DEVICE ]
TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | can }
MODE := { assoc | preassoc | preassocrr | disassoc }
PROFILE := profile PROFILE
[ instance UUID ]
[ host UUID ]
VSI := vsi mgr MGRID type VTID ver VER
[ instance UUID ]
Signed-off-by: Scott Feldman <scofeldm@cisco.com>
---
ip/ipaddress.c | 115 ++++++++++++++++++++++++++++
ip/iplink.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 304 insertions(+), 38 deletions(-)
diff --git a/ip/ipaddress.c b/ip/ipaddress.c
index 3a411b1..5c3e696 100644
--- a/ip/ipaddress.c
+++ b/ip/ipaddress.c
@@ -187,6 +187,107 @@ static void print_linktype(FILE *fp, struct rtattr *tb)
}
}
+static void print_port(FILE *fp, struct rtattr *port[])
+{
+ struct ifla_port_vsi *vsi;
+#define uuid_fmt "%02X%02X%02X%02X-%02X%02X-%02X%02X-" \
+ "%02X%02X-%02X%02X%02X%02X%02X%02X"
+ unsigned char *uuid;
+ __u8 request;
+ __u16 response;
+
+ if (port[IFLA_PORT_VF])
+ fprintf(fp, "\n vf %d port",
+ *(__u32 *)RTA_DATA(port[IFLA_PORT_VF]));
+ else
+ fprintf(fp, "\n port");
+
+ if (port[IFLA_PORT_REQUEST]) {
+ request = *(__u8 *)RTA_DATA(port[IFLA_PORT_REQUEST]);
+ fprintf(fp, " %s",
+ request == PORT_REQUEST_PREASSOCIATE ? "preassoc" :
+ request == PORT_REQUEST_PREASSOCIATE_RR ? "preassocrr" :
+ request == PORT_REQUEST_ASSOCIATE ? "assoc" :
+ request == PORT_REQUEST_DISASSOCIATE ? "disassoc" :
+ "unknown request");
+ }
+
+ if (port[IFLA_PORT_PROFILE])
+ fprintf(fp, " profile \"%s\"",
+ (char *)RTA_DATA(port[IFLA_PORT_PROFILE]));
+
+ if (port[IFLA_PORT_VSI_TYPE]) {
+ vsi = RTA_DATA(port[IFLA_PORT_VSI_TYPE]);
+ fprintf(fp, " vsi mgr %d type 0x%02x%02x%02x ver %d",
+ vsi->vsi_mgr_id, vsi->vsi_type_id[0],
+ vsi->vsi_type_id[1], vsi->vsi_type_id[2],
+ vsi->vsi_type_version);
+ }
+
+ if (port[IFLA_PORT_RESPONSE]) {
+ response = *(__u16 *)RTA_DATA(port[IFLA_PORT_RESPONSE]);
+ fprintf(fp, " status: %s",
+ response == PORT_VDP_RESPONSE_SUCCESS ?
+ "SUCCESS" :
+ response == PORT_VDP_RESPONSE_INVALID_FORMAT ?
+ "INVALID FORMAT" :
+ response == PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES ?
+ "INSUFFICIENT RESOURCES" :
+ response == PORT_VDP_RESPONSE_UNUSED_VTID ?
+ "UNUSED VTID" :
+ response == PORT_VDP_RESPONSE_VTID_VIOLATION ?
+ "VTID VIOLATION" :
+ response == PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION ?
+ "VTID VERSION VIOLATION" :
+ response == PORT_VDP_RESPONSE_OUT_OF_SYNC ?
+ "OUT-OF-SYNC" :
+ response == PORT_PROFILE_RESPONSE_SUCCESS ?
+ "SUCCESS" :
+ response == PORT_PROFILE_RESPONSE_INPROGRESS ?
+ "IN-PROGRESS" :
+ response == PORT_PROFILE_RESPONSE_INVALID ?
+ "INVALID" :
+ response == PORT_PROFILE_RESPONSE_BADSTATE ?
+ "BAD STATE" :
+ response ==PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES?
+ "INSUFFICIENT RESOURCES" :
+ response == PORT_PROFILE_RESPONSE_ERROR ?
+ "ERROR" :
+ "UNKNOWN RESPONSE");
+ }
+
+ if (port[IFLA_PORT_INSTANCE_UUID]) {
+ uuid = RTA_DATA(port[IFLA_PORT_INSTANCE_UUID]);
+ fprintf(fp, "\n instance "uuid_fmt,
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15]);
+ }
+
+ if (port[IFLA_PORT_HOST_UUID]) {
+ uuid = RTA_DATA(port[IFLA_PORT_HOST_UUID]);
+ fprintf(fp, "\n host "uuid_fmt,
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15]);
+ }
+}
+
+static void print_vfport(FILE *fp, struct rtattr *vfport)
+{
+ struct rtattr *port[IFLA_PORT_MAX+1];
+
+ if (vfport->rta_type != IFLA_VF_PORT) {
+ fprintf(stderr, "BUG: rta type is %d\n", vfport->rta_type);
+ return;
+ }
+
+ parse_rtattr_nested(port, IFLA_PORT_MAX, vfport);
+ print_port(fp, port);
+}
+
static void print_vfinfo(FILE *fp, struct rtattr *vfinfo)
{
struct ifla_vf_mac *vf_mac;
@@ -421,6 +522,20 @@ int print_linkinfo(const struct sockaddr_nl *who,
print_vfinfo(fp, i);
}
+ if (do_link && tb[IFLA_PORT_SELF]) {
+ struct rtattr *port[IFLA_PORT_MAX+1];
+ parse_rtattr_nested(port, IFLA_PORT_MAX, tb[IFLA_PORT_SELF]);
+ print_port(fp, port);
+ }
+
+ if (do_link && tb[IFLA_VF_PORTS] && tb[IFLA_NUM_VF]) {
+ struct rtattr *i, *vfports = tb[IFLA_VF_PORTS];
+ int rem = RTA_PAYLOAD(vfports);
+ for (i = RTA_DATA(vfports); RTA_OK(i, rem);
+ i = RTA_NEXT(i, rem))
+ print_vfport(fp, i);
+ }
+
fprintf(fp, "\n");
fflush(fp);
return 0;
diff --git a/ip/iplink.c b/ip/iplink.c
index cb2c4f5..04f55ee 100644
--- a/ip/iplink.c
+++ b/ip/iplink.c
@@ -68,14 +68,22 @@ void iplink_usage(void)
fprintf(stderr, " [ mtu MTU ]\n");
fprintf(stderr, " [ netns PID ]\n");
fprintf(stderr, " [ alias NAME ]\n");
+ fprintf(stderr, " [ port MODE { PROFILE | VSI } ]\n");
fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n");
fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] ]\n");
- fprintf(stderr, " [ rate TXRATE ] ] \n");
+ fprintf(stderr, " [ rate TXRATE ]\n");
+ fprintf(stderr, " [ port MODE { PROFILE | VSI } ] ]\n");
fprintf(stderr, " ip link show [ DEVICE ]\n");
if (iplink_have_newlink()) {
fprintf(stderr, "\n");
fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | can }\n");
+ fprintf(stderr, "MODE := { assoc | preassoc | preassocrr | disassoc }\n");
+ fprintf(stderr, "PROFILE := profile PROFILE\n");
+ fprintf(stderr, " [ instance UUID ]\n");
+ fprintf(stderr, " [ host UUID ]\n");
+ fprintf(stderr, "VSI := vsi mgr MGRID type VTID ver VER\n");
+ fprintf(stderr, " [ instance UUID ]\n");
}
exit(-1);
}
@@ -176,55 +184,170 @@ struct iplink_req {
char buf[1024];
};
-int iplink_parse_vf(int vf, int *argcp, char ***argvp,
- struct iplink_req *req)
+void iplink_parse_port(int vf, int *argcp, char ***argvp,
+ struct iplink_req *req)
+{
+ int argc = *argcp;
+ char **argv = *argvp;
+ struct rtattr *nest, *nest_inner = NULL;
+ struct ifla_port_vsi port_vsi;
+ char *port_profile = NULL;
+ char *instance_uuid = NULL;
+ char *host_uuid = NULL;
+ unsigned char uuid[16];
+ char *uuid_fmt = "%02X%02X%02X%02X-%02X%02X-%02X%02X-"
+ "%02X%02X-%02X%02X%02X%02X%02X%02X";
+ int parsed;
+ int manager_id = -1;
+ int type_id = -1;
+ int type_id_version = -1;
+ int request = -1;
+ int vsi = 0;
+
+ if (NEXT_ARG_OK()) {
+ NEXT_ARG();
+ if (matches(*argv, "assoc") == 0)
+ request = PORT_REQUEST_ASSOCIATE;
+ else if (matches(*argv, "preassoc") == 0)
+ request = PORT_REQUEST_PREASSOCIATE;
+ else if (matches(*argv, "preassocrr") == 0)
+ request = PORT_REQUEST_PREASSOCIATE_RR;
+ else if (matches(*argv, "disassoc") == 0)
+ request = PORT_REQUEST_DISASSOCIATE;
+ }
+
+ while (NEXT_ARG_OK()) {
+ NEXT_ARG();
+ if (matches(*argv, "vsi") == 0) {
+ vsi = 1;
+ } else if (matches(*argv, "mgr") == 0) {
+ NEXT_ARG();
+ if (get_integer(&manager_id, *argv, 0))
+ invarg("Invalid \"mgr\" value\n", *argv);
+ } else if (matches(*argv, "type") == 0) {
+ NEXT_ARG();
+ if (get_integer(&type_id, *argv, 0))
+ invarg("Invalid \"type\" value\n", *argv);
+ } else if (matches(*argv, "ver") == 0) {
+ NEXT_ARG();
+ if (get_integer(&type_id_version, *argv, 0))
+ invarg("Invalid \"ver\" value\n", *argv);
+ } else if (matches(*argv, "profile") == 0) {
+ NEXT_ARG();
+ port_profile = *argv;
+ } else if (matches(*argv, "instance") == 0) {
+ NEXT_ARG();
+ instance_uuid = *argv;
+ } else if (matches(*argv, "host") == 0) {
+ NEXT_ARG();
+ host_uuid = *argv;
+ } else {
+ /* rewind arg */
+ PREV_ARG();
+ break;
+ }
+ }
+
+ if (argc == *argcp)
+ incomplete_command();
+
+ if (vf == PORT_SELF_VF) {
+ nest = addattr_nest(&req->n, sizeof(*req), IFLA_PORT_SELF);
+ } else {
+ nest = addattr_nest(&req->n, sizeof(*req), IFLA_VF_PORTS);
+ nest_inner = addattr_nest(&req->n, sizeof(*req), IFLA_VF_PORT);
+ addattr_l(&req->n, sizeof(*req), IFLA_PORT_VF,
+ (uint32_t *)&vf, sizeof(uint32_t));
+ }
+
+ if (port_profile)
+ addattr_l(&req->n, sizeof(*req), IFLA_PORT_PROFILE,
+ port_profile, strlen(port_profile));
+
+ if (instance_uuid) {
+ parsed = sscanf(instance_uuid, uuid_fmt,
+ &uuid[0], &uuid[1], &uuid[2], &uuid[3],
+ &uuid[4], &uuid[5], &uuid[6], &uuid[7],
+ &uuid[8], &uuid[9], &uuid[10], &uuid[11],
+ &uuid[12], &uuid[13], &uuid[14], &uuid[15]);
+ if (parsed != sizeof(uuid))
+ invarg("Invalid \"uuid\" value\n", instance_uuid);
+ addattr_l(&req->n, sizeof(*req), IFLA_PORT_INSTANCE_UUID,
+ uuid, sizeof(uuid));
+
+ }
+
+ if (host_uuid) {
+ parsed = sscanf(host_uuid, uuid_fmt,
+ &uuid[0], &uuid[1], &uuid[2], &uuid[3],
+ &uuid[4], &uuid[5], &uuid[6], &uuid[7],
+ &uuid[8], &uuid[9], &uuid[10], &uuid[11],
+ &uuid[12], &uuid[13], &uuid[14], &uuid[15]);
+ if (parsed != sizeof(uuid))
+ invarg("Invalid \"uuid\" value\n", host_uuid);
+ addattr_l(&req->n, sizeof(*req), IFLA_PORT_HOST_UUID,
+ uuid, sizeof(uuid));
+
+ }
+
+ if (vsi) {
+ port_vsi.vsi_mgr_id = manager_id;
+ memcpy(&port_vsi.vsi_type_id, &type_id,
+ sizeof(port_vsi.vsi_type_id));
+ port_vsi.vsi_type_version = type_id_version;
+ addattr_l(&req->n, sizeof(*req), IFLA_PORT_VSI_TYPE,
+ &port_vsi, sizeof(port_vsi));
+ }
+
+ addattr_l(&req->n, sizeof(*req), IFLA_PORT_REQUEST,
+ &request, 1);
+
+ if (nest_inner)
+ addattr_nest_end(&req->n, nest_inner);
+ addattr_nest_end(&req->n, nest);
+
+ *argcp = argc;
+ *argvp = argv;
+}
+
+void iplink_parse_vf(int vf, int *argcp, char ***argvp,
+ struct iplink_req *req)
{
int len, argc = *argcp;
char **argv = *argvp;
+ struct rtattr *vflist;
struct rtattr *vfinfo;
-
- vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
+ char *mac = NULL;
+ char *vlan = NULL;
+ char *qos = NULL;
+ char *rate = NULL;
+ struct ifla_vf_mac ivm = { .vf = vf, };
+ struct ifla_vf_vlan ivv = { .vf = vf, .qos = 0, };
+ struct ifla_vf_tx_rate ivt = { .vf = vf, };
while (NEXT_ARG_OK()) {
NEXT_ARG();
- if (matches(*argv, "mac") == 0) {
- struct ifla_vf_mac ivm;
+ if (matches(*argv, "port") == 0) {
+ iplink_parse_port(vf, &argc, &argv, req);
+ } else if (matches(*argv, "mac") == 0) {
NEXT_ARG();
- ivm.vf = vf;
- len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
- if (len < 0)
- return -1;
- addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm));
+ mac = *argv;
} else if (matches(*argv, "vlan") == 0) {
- struct ifla_vf_vlan ivv;
NEXT_ARG();
- if (get_unsigned(&ivv.vlan, *argv, 0)) {
- invarg("Invalid \"vlan\" value\n", *argv);
- }
- ivv.vf = vf;
- ivv.qos = 0;
+ vlan = *argv;
if (NEXT_ARG_OK()) {
NEXT_ARG();
if (matches(*argv, "qos") == 0) {
NEXT_ARG();
- if (get_unsigned(&ivv.qos, *argv, 0)) {
- invarg("Invalid \"qos\" value\n", *argv);
- }
+ qos = *argv;
} else {
/* rewind arg */
PREV_ARG();
}
}
- addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv, sizeof(ivv));
} else if (matches(*argv, "rate") == 0) {
- struct ifla_vf_tx_rate ivt;
NEXT_ARG();
- if (get_unsigned(&ivt.rate, *argv, 0)) {
- invarg("Invalid \"rate\" value\n", *argv);
- }
- ivt.vf = vf;
- addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
-
+ rate = *argv;
} else {
/* rewind arg */
PREV_ARG();
@@ -235,11 +358,43 @@ int iplink_parse_vf(int vf, int *argcp, char ***argvp,
if (argc == *argcp)
incomplete_command();
- addattr_nest_end(&req->n, vfinfo);
+ if (mac || vlan || rate) {
+
+ vflist = addattr_nest(&req->n, sizeof(*req), IFLA_VFINFO_LIST);
+ vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
+
+ if (mac) {
+ len = ll_addr_a2n((char *)ivm.mac, 32, mac);
+ if (len < 0)
+ invarg("Invalid \"mac\" value\n", mac);
+ addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC,
+ &ivm, sizeof(ivm));
+ }
+
+ if (vlan) {
+ if (get_unsigned(&ivv.vlan, vlan, 0))
+ invarg("Invalid \"vlan\" value\n", vlan);
+ if (qos) {
+ if (get_unsigned(&ivv.qos, qos, 0))
+ invarg("Invalid \"qos\" value\n", qos);
+ }
+ addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN,
+ &ivv, sizeof(ivv));
+ }
+
+ if (rate) {
+ if (get_unsigned(&ivt.rate, rate, 0))
+ invarg("Invalid \"rate\" value\n", rate);
+ addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE,
+ &ivt, sizeof(ivt));
+ }
+
+ addattr_nest_end(&req->n, vfinfo);
+ addattr_nest_end(&req->n, vflist);
+ }
*argcp = argc;
*argvp = argv;
- return 0;
}
@@ -349,18 +504,14 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
req->i.ifi_flags |= IFF_NOARP;
} else
return on_off("noarp");
+ } else if (strcmp(*argv, "port") == 0) {
+ iplink_parse_port(vf, &argc, &argv, req);
} else if (strcmp(*argv, "vf") == 0) {
- struct rtattr *vflist;
NEXT_ARG();
if (get_integer(&vf, *argv, 0)) {
invarg("Invalid \"vf\" value\n", *argv);
}
- vflist = addattr_nest(&req->n, sizeof(*req),
- IFLA_VFINFO_LIST);
- len = iplink_parse_vf(vf, &argc, &argv, req);
- if (len < 0)
- return -1;
- addattr_nest_end(&req->n, vflist);
+ iplink_parse_vf(vf, &argc, &argv, req);
#ifdef IFF_DYNAMIC
} else if (matches(*argv, "dynamic") == 0) {
NEXT_ARG();
^ permalink raw reply related
* Re: [v5 Patch 1/3] netpoll: add generic support for bridge and bonding devices
From: Jay Vosburgh @ 2010-06-01 18:42 UTC (permalink / raw)
To: Cong Wang
Cc: Flavio Leitner, linux-kernel, Matt Mackall, netdev, bridge,
Andy Gospodarek, Neil Horman, Jeff Moyer, Stephen Hemminger,
bonding-devel, David Miller
In-Reply-To: <4C04D98D.4020509@redhat.com>
Cong Wang <amwang@redhat.com> wrote:
>On 06/01/10 03:08, Flavio Leitner wrote:
>> On Mon, May 31, 2010 at 01:56:52PM +0800, Cong Wang wrote:
>>> Hi, Flavio,
>>>
>>> Please use the attached patch instead, try to see if it solves
>>> all your problems.
>>
>> I tried and it hangs. No backtraces this time.
>> The bond_change_active_slave() prints before NETDEV_BONDING_FAILOVER
>> notification, so I think it won't work.
>
>Ah, I thought the same.
>
>>
>> Please, correct if I'm wrong, but when a failover happens with your
>> patch applied, the netconsole would be disabled forever even with
>> another healthy slave, right?
>>
>
>Yes, this is an easy solution, because bonding has several modes,
>it is complex to make netpoll work in different modes.
If I understand correctly, the root cause of the problem with
netconsole and bonding is that bonding is, ultimately, performing
printks with a write lock held, and when netconsole recursively calls
into bonding to send the printk over the netconsole, there is a deadlock
(when the bonding xmit function attempts to acquire the same lock for
read).
You're trying to avoid the deadlock by shutting off netconsole
(permanently, it looks like) for one problem case: a failover, which
does some printks with a write lock held.
This doesn't look to me like a complete solution, there are
other cases in bonding that will do printk with write locks held. I
suspect those will also hang netconsole as things exist today, and won't
be affected by your patch below.
For example:
The sysfs functions to set the primary (bonding_store_primary)
or active (bonding_store_active_slave) options: a pr_info is called to
provide a log message of the results. These could be tested by setting
the primary or active options via sysfs, e.g.,
echo eth0 > /sys/class/net/bond0/bonding/primary
echo eth0 > /sys/class/net/bond0/bonding/active
If the kernel is defined with DEBUG, there are a few pr_debug
calls within write_locks (bond_del_vlan, for example).
If the slave's underlying device driver's ndo_vlan_rx_register
or ndo_vlan_rx_kill_vid functions call printk (and it looks like some do
for error cases, e.g., igbvf, ehea, enic), those would also presumably
deadlock (because bonding holds its write_lock when calling the ndo_
vlan functions).
It also appears that (with the patch below) some nominally
normal usage patterns will immediately disable netconsole. The one that
comes to mind is if the primary= option is set (to "eth1" for this
example), but that slave not enslaved first (the slaves are added, say,
eth0 then eth1). In that situation, when the primary slave (eth1 here)
is added, the first thing that will happen is a failover, and that will
disable netconsole.
Thoughts?
-J
>Would you like to test the following patch?
>
>Thanks much!
>
>diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
>index 5e12462..59ade92 100644
>--- a/drivers/net/bonding/bond_main.c
>+++ b/drivers/net/bonding/bond_main.c
>@@ -1109,6 +1109,14 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
> if (old_active == new_active)
> return;
>
>+ write_unlock_bh(&bond->curr_slave_lock);
>+ read_unlock(&bond->lock);
>+
>+ netdev_bonding_change(bond->dev, NETDEV_BONDING_DESLAVE);
>+
>+ read_lock(&bond->lock);
>+ write_lock_bh(&bond->curr_slave_lock);
>+
> if (new_active) {
> new_active->jiffies = jiffies;
>
---
-Jay Vosburgh, IBM Linux Technology Center, fubar@us.ibm.com
^ permalink raw reply
* Re: [RFC] netfilter: WIP: Xtables idletimer target implementation
From: Luciano Coelho @ 2010-06-01 18:41 UTC (permalink / raw)
To: ext Jan Engelhardt
Cc: ext Patrick McHardy, netfilter-devel@vger.kernel.org,
netdev@vger.kernel.org, Timo Teras
In-Reply-To: <alpine.LSU.2.01.1006012035350.15461@obet.zrqbmnf.qr>
On Tue, 2010-06-01 at 20:38 +0200, ext Jan Engelhardt wrote:
> On Tuesday 2010-06-01 20:33, Luciano Coelho wrote:
> >On Mon, 2010-05-31 at 21:51 +0200, ext Jan Engelhardt wrote:
> >> On Monday 2010-05-31 21:12, Luciano Coelho wrote:
> >> >
> >> >I considered this option, but then I didn't find a proper place where to
> >> >include the attribute in sysfs, since I cannot add it as part of the
> >> >interface (eg. /sys/class/net/wlan0/idletimer) as I was doing before.
> >>
> >> You couldn't have done that before either, because the interface name
> >> in ipt_ip may refer to an interface that does not exist at all times.
> >>
> >> >The other option would be to make the idletimer as part of the
> >> >xt_IDLETIMER module object in sysfs
> >> >(ie. /sys/module/xt_IDLETIMER/<user_supplied_name>), but it looks out of
> >> >place.
> >>
> >> I like it. It follows /proc/net/xt_{hashlimit,recent}/<user_supplied_name>.
> >
> >I'm starting to like this more and more too, as my code is getting much
> >smaller ;)
> >
> >One quick question, though. Do you have any ideas on how I can make
> >sure that the user doesn't supply the same name twice (ie. two rules
> >with the same user_supplied_name)?
>
> What's so bad about multiple rules being able to reset the timer?
Ahhmm... Nothing! Thank you, I think I'm getting code-blind :)
--
Cheers,
Luca.
^ permalink raw reply
* [net-2.6 PATCH] enic: bug fix: make the set/get netlink VF_PORT support symmetrical
From: Scott Feldman @ 2010-06-01 18:59 UTC (permalink / raw)
To: davem; +Cc: chrisw, netdev
From: Scott Feldman <scofeldm@cisco.com>
To make get/set netlink VF_PORT truly symmetrical, we need to keep track
of what items are set and only return those items on get. Previously, the
driver wasn't differentiating between a set of attr with a NULL string,
for example, and not setting the attr at all. We only want to return
the NULL string if the attr was actually set with a NULL string. Otherwise,
don't return the attr.
Signed-off-by: Scott Feldman <scofeldm@cisco.com>
---
drivers/net/enic/enic.h | 7 +
drivers/net/enic/enic_main.c | 200 ++++++++++++++++++++----------------------
2 files changed, 104 insertions(+), 103 deletions(-)
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index 85f2a2e..45e86d1 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -74,7 +74,14 @@ struct enic_msix_entry {
void *devid;
};
+#define ENIC_SET_APPLIED (1 << 0)
+#define ENIC_SET_REQUEST (1 << 1)
+#define ENIC_SET_NAME (1 << 2)
+#define ENIC_SET_INSTANCE (1 << 3)
+#define ENIC_SET_HOST (1 << 4)
+
struct enic_port_profile {
+ u32 set;
u8 request;
char name[PORT_PROFILE_MAX];
u8 instance_uuid[PORT_UUID_MAX];
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index 6586b5c..bc7d6b9 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -1029,8 +1029,7 @@ static int enic_dev_init_done(struct enic *enic, int *done, int *error)
return err;
}
-static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac,
- char *name, u8 *instance_uuid, u8 *host_uuid)
+static int enic_set_port_profile(struct enic *enic, u8 *mac)
{
struct vic_provinfo *vp;
u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
@@ -1040,97 +1039,112 @@ static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac,
"%02X%02X-%02X%02X%02X%02X%0X%02X";
int err;
- if (!name)
- return -EINVAL;
+ err = enic_vnic_dev_deinit(enic);
+ if (err)
+ return err;
- if (!is_valid_ether_addr(mac))
- return -EADDRNOTAVAIL;
+ switch (enic->pp.request) {
- vp = vic_provinfo_alloc(GFP_KERNEL, oui, VIC_PROVINFO_LINUX_TYPE);
- if (!vp)
- return -ENOMEM;
+ case PORT_REQUEST_ASSOCIATE:
- vic_provinfo_add_tlv(vp,
- VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR,
- strlen(name) + 1, name);
-
- vic_provinfo_add_tlv(vp,
- VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR,
- ETH_ALEN, mac);
-
- if (instance_uuid) {
- uuid = instance_uuid;
- sprintf(uuid_str, uuid_fmt,
- uuid[0], uuid[1], uuid[2], uuid[3],
- uuid[4], uuid[5], uuid[6], uuid[7],
- uuid[8], uuid[9], uuid[10], uuid[11],
- uuid[12], uuid[13], uuid[14], uuid[15]);
- vic_provinfo_add_tlv(vp,
- VIC_LINUX_PROV_TLV_CLIENT_UUID_STR,
- sizeof(uuid_str), uuid_str);
- }
+ if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name))
+ return -EINVAL;
- if (host_uuid) {
- uuid = host_uuid;
- sprintf(uuid_str, uuid_fmt,
- uuid[0], uuid[1], uuid[2], uuid[3],
- uuid[4], uuid[5], uuid[6], uuid[7],
- uuid[8], uuid[9], uuid[10], uuid[11],
- uuid[12], uuid[13], uuid[14], uuid[15]);
- vic_provinfo_add_tlv(vp,
- VIC_LINUX_PROV_TLV_HOST_UUID_STR,
- sizeof(uuid_str), uuid_str);
- }
+ if (!is_valid_ether_addr(mac))
+ return -EADDRNOTAVAIL;
- err = enic_vnic_dev_deinit(enic);
- if (err)
- goto err_out;
+ vp = vic_provinfo_alloc(GFP_KERNEL, oui,
+ VIC_PROVINFO_LINUX_TYPE);
+ if (!vp)
+ return -ENOMEM;
- memset(&enic->pp, 0, sizeof(enic->pp));
+ vic_provinfo_add_tlv(vp,
+ VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR,
+ strlen(enic->pp.name) + 1, enic->pp.name);
- err = enic_dev_init_prov(enic, vp);
- if (err)
- goto err_out;
+ vic_provinfo_add_tlv(vp,
+ VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR,
+ ETH_ALEN, mac);
+
+ if (enic->pp.set & ENIC_SET_INSTANCE) {
+ uuid = enic->pp.instance_uuid;
+ sprintf(uuid_str, uuid_fmt,
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15]);
+ vic_provinfo_add_tlv(vp,
+ VIC_LINUX_PROV_TLV_CLIENT_UUID_STR,
+ sizeof(uuid_str), uuid_str);
+ }
- enic->pp.request = request;
- memcpy(enic->pp.name, name, PORT_PROFILE_MAX);
- if (instance_uuid)
- memcpy(enic->pp.instance_uuid,
- instance_uuid, PORT_UUID_MAX);
- if (host_uuid)
- memcpy(enic->pp.host_uuid,
- host_uuid, PORT_UUID_MAX);
+ if (enic->pp.set & ENIC_SET_HOST) {
+ uuid = enic->pp.host_uuid;
+ sprintf(uuid_str, uuid_fmt,
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15]);
+ vic_provinfo_add_tlv(vp,
+ VIC_LINUX_PROV_TLV_HOST_UUID_STR,
+ sizeof(uuid_str), uuid_str);
+ }
-err_out:
- vic_provinfo_free(vp);
+ err = enic_dev_init_prov(enic, vp);
+ vic_provinfo_free(vp);
+ if (err)
+ return err;
+ break;
- return err;
-}
+ case PORT_REQUEST_DISASSOCIATE:
+ break;
-static int enic_unset_port_profile(struct enic *enic)
-{
- memset(&enic->pp, 0, sizeof(enic->pp));
- return enic_vnic_dev_deinit(enic);
+ default:
+ return -EINVAL;
+ }
+
+ enic->pp.set |= ENIC_SET_APPLIED;
+ return 0;
}
static int enic_set_vf_port(struct net_device *netdev, int vf,
struct nlattr *port[])
{
struct enic *enic = netdev_priv(netdev);
- char *name = NULL;
- u8 *instance_uuid = NULL;
- u8 *host_uuid = NULL;
- u8 request = PORT_REQUEST_DISASSOCIATE;
+
+ memset(&enic->pp, 0, sizeof(enic->pp));
+
+ if (port[IFLA_PORT_REQUEST]) {
+ enic->pp.set |= ENIC_SET_REQUEST;
+ enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]);
+ }
+
+ if (port[IFLA_PORT_PROFILE]) {
+ enic->pp.set |= ENIC_SET_NAME;
+ memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]),
+ PORT_PROFILE_MAX);
+ }
+
+ if (port[IFLA_PORT_INSTANCE_UUID]) {
+ enic->pp.set |= ENIC_SET_INSTANCE;
+ memcpy(enic->pp.instance_uuid,
+ nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX);
+ }
+
+ if (port[IFLA_PORT_HOST_UUID]) {
+ enic->pp.set |= ENIC_SET_HOST;
+ memcpy(enic->pp.host_uuid,
+ nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX);
+ }
/* don't support VFs, yet */
if (vf != PORT_SELF_VF)
return -EOPNOTSUPP;
- if (port[IFLA_PORT_REQUEST])
- request = nla_get_u8(port[IFLA_PORT_REQUEST]);
+ if (!(enic->pp.set & ENIC_SET_REQUEST))
+ return -EOPNOTSUPP;
- switch (request) {
- case PORT_REQUEST_ASSOCIATE:
+ if (enic->pp.request == PORT_REQUEST_ASSOCIATE) {
/* If the interface mac addr hasn't been assigned,
* assign a random mac addr before setting port-
@@ -1139,30 +1153,9 @@ static int enic_set_vf_port(struct net_device *netdev, int vf,
if (is_zero_ether_addr(netdev->dev_addr))
random_ether_addr(netdev->dev_addr);
-
- if (port[IFLA_PORT_PROFILE])
- name = nla_data(port[IFLA_PORT_PROFILE]);
-
- if (port[IFLA_PORT_INSTANCE_UUID])
- instance_uuid =
- nla_data(port[IFLA_PORT_INSTANCE_UUID]);
-
- if (port[IFLA_PORT_HOST_UUID])
- host_uuid = nla_data(port[IFLA_PORT_HOST_UUID]);
-
- return enic_set_port_profile(enic, request,
- netdev->dev_addr, name,
- instance_uuid, host_uuid);
-
- case PORT_REQUEST_DISASSOCIATE:
-
- return enic_unset_port_profile(enic);
-
- default:
- break;
}
- return -EOPNOTSUPP;
+ return enic_set_port_profile(enic, netdev->dev_addr);
}
static int enic_get_vf_port(struct net_device *netdev, int vf,
@@ -1172,14 +1165,12 @@ static int enic_get_vf_port(struct net_device *netdev, int vf,
int err, error, done;
u16 response = PORT_PROFILE_RESPONSE_SUCCESS;
- /* don't support VFs, yet */
- if (vf != PORT_SELF_VF)
- return -EOPNOTSUPP;
+ if (!(enic->pp.set & ENIC_SET_APPLIED))
+ return -ENODATA;
err = enic_dev_init_done(enic, &done, &error);
-
if (err)
- return err;
+ error = err;
switch (error) {
case ERR_SUCCESS:
@@ -1202,12 +1193,15 @@ static int enic_get_vf_port(struct net_device *netdev, int vf,
NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request);
NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response);
- NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX,
- enic->pp.name);
- NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX,
- enic->pp.instance_uuid);
- NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX,
- enic->pp.host_uuid);
+ if (enic->pp.set & ENIC_SET_NAME)
+ NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX,
+ enic->pp.name);
+ if (enic->pp.set & ENIC_SET_INSTANCE)
+ NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX,
+ enic->pp.instance_uuid);
+ if (enic->pp.set & ENIC_SET_HOST)
+ NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX,
+ enic->pp.host_uuid);
return 0;
^ permalink raw reply related
* Re: [PATCHv2] Refactor update of IPv6 flow destination address for srcrt (RH) option
From: Arnaud Ebalard @ 2010-06-01 19:17 UTC (permalink / raw)
To: David S. Miller
Cc: YOSHIFUJI Hideaki / 吉藤英明, netdev
In-Reply-To: <87wruid8rx.fsf@small.ssi.corp>
Hi,
I received a comment (privately) about the fact that the transform isn't
equivalent as its sets final_p in all cases now, and asked if it matters?
It does not: in current code, final_p is always initialized to NULL when
it is declared. I also verified it is not used by anything between the
declaration and the code I replace by the helper.
In fact, one additional thing which can be done is to remove the
initialization final_p to NULL when it is declared. The updated version
below does that.
Patch is against net-2.6. Tested on 2.6.34.
Cheers,
a+
>From 50e59bf48323777a05476e0d094f15b67194f0bd Mon Sep 17 00:00:00 2001
From: Arnaud Ebalard <arno@natisbad.org>
Date: Tue, 1 Jun 2010 19:40:54 +0200
Subject: [PATCHv2] Refactor update of IPv6 flow destination address for srcrt (RH) option
There are more than a dozen occurrences of following code in the
IPv6 stack:
if (opt && opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
ipv6_addr_copy(&final, &fl.fl6_dst);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
}
Replace those with a helper. Note that the helper overrides final_p
in all cases. This is ok as final_p was previously initialized to
NULL when declared.
Signed-off-by: Arnaud Ebalard <arno@natisbad.org>
---
include/net/ipv6.h | 13 +++++++++++++
net/dccp/ipv6.c | 30 ++++++------------------------
net/ipv6/af_inet6.c | 9 ++-------
net/ipv6/datagram.c | 18 ++++--------------
net/ipv6/inet6_connection_sock.c | 9 ++-------
net/ipv6/raw.c | 10 ++--------
net/ipv6/syncookies.c | 9 ++-------
net/ipv6/tcp_ipv6.c | 27 ++++++---------------------
net/ipv6/udp.c | 11 +++--------
9 files changed, 40 insertions(+), 96 deletions(-)
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 2600b69..9edfa1c 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -290,6 +290,19 @@ static inline void ipv6_addr_copy(struct in6_addr *a1, const struct in6_addr *a2
memcpy(a1, a2, sizeof(struct in6_addr));
}
+static inline struct in6_addr *srcrt_dst_flow_update(struct in6_addr *final,
+ struct in6_addr *fl6dst,
+ const struct ipv6_txoptions *opt)
+{
+ if (opt && opt->srcrt) {
+ const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
+ ipv6_addr_copy(final, fl6dst);
+ ipv6_addr_copy(fl6dst, rt0->addr);
+ return final;
+ }
+ return NULL;
+}
+
static inline void ipv6_addr_prefix(struct in6_addr *pfx,
const struct in6_addr *addr,
int plen)
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 0916988..38151db 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -248,7 +248,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
struct ipv6_pinfo *np = inet6_sk(sk);
struct sk_buff *skb;
struct ipv6_txoptions *opt = NULL;
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
int err = -1;
struct dst_entry *dst;
@@ -265,13 +265,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
opt = np->opt;
- if (opt != NULL && opt->srcrt != NULL) {
- const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
-
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = srcrt_dst_flow_update(&final, &fl.fl6_dst, opt);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err)
@@ -545,19 +539,13 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
goto out_overflow;
if (dst == NULL) {
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
memset(&fl, 0, sizeof(fl));
fl.proto = IPPROTO_DCCP;
ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
- if (opt != NULL && opt->srcrt != NULL) {
- const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
-
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = srcrt_dst_flow_update(&final, &fl.fl6_dst, opt);
ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
fl.oif = sk->sk_bound_dev_if;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
@@ -885,7 +873,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct dccp_sock *dp = dccp_sk(sk);
- struct in6_addr *saddr = NULL, *final_p = NULL, final;
+ struct in6_addr *saddr = NULL, *final_p, final;
struct flowi fl;
struct dst_entry *dst;
int addr_type;
@@ -988,13 +976,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
fl.fl_ip_sport = inet->inet_sport;
security_sk_classify_flow(sk, &fl);
- if (np->opt != NULL && np->opt->srcrt != NULL) {
- const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
-
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = srcrt_dst_flow_update(&final, &fl.fl6_dst, np->opt);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err)
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index e733942..9df2373 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -651,7 +651,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
if (dst == NULL) {
struct inet_sock *inet = inet_sk(sk);
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
memset(&fl, 0, sizeof(fl));
@@ -665,12 +665,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
fl.fl_ip_sport = inet->inet_sport;
security_sk_classify_flow(sk, &fl);
- if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = srcrt_dst_flow_update(&final, &fl.fl6_dst, np->opt);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err) {
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 7126846..378fd58 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -38,10 +38,11 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
- struct in6_addr *daddr, *final_p = NULL, final;
+ struct in6_addr *daddr, *final_p, final;
struct dst_entry *dst;
struct flowi fl;
struct ip6_flowlabel *flowlabel = NULL;
+ struct ipv6_txoptions *opt;
int addr_type;
int err;
@@ -155,19 +156,8 @@ ipv4_connected:
security_sk_classify_flow(sk, &fl);
- if (flowlabel) {
- if (flowlabel->opt && flowlabel->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
- } else if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ opt = flowlabel ? flowlabel->opt : np->opt;
+ final_p = srcrt_dst_flow_update(&final, &fl.fl6_dst, opt);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err)
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 0c5e3c3..14b5ec5 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -185,7 +185,7 @@ int inet6_csk_xmit(struct sk_buff *skb)
struct ipv6_pinfo *np = inet6_sk(sk);
struct flowi fl;
struct dst_entry *dst;
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
memset(&fl, 0, sizeof(fl));
fl.proto = sk->sk_protocol;
@@ -199,12 +199,7 @@ int inet6_csk_xmit(struct sk_buff *skb)
fl.fl_ip_dport = inet->inet_dport;
security_sk_classify_flow(sk, &fl);
- if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = srcrt_dst_flow_update(&final, &fl.fl6_dst, np->opt);
dst = __inet6_csk_dst_check(sk, np->dst_cookie);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 4a4dcbe..f161a54 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -725,7 +725,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
{
struct ipv6_txoptions opt_space;
struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name;
- struct in6_addr *daddr, *final_p = NULL, final;
+ struct in6_addr *daddr, *final_p, final;
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct raw6_sock *rp = raw6_sk(sk);
@@ -847,13 +847,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
ipv6_addr_copy(&fl.fl6_src, &np->saddr);
- /* merge ip6_build_xmit from ip6_output */
- if (opt && opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = srcrt_dst_flow_update(&final, &fl.fl6_dst, opt);
if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
fl.oif = np->mcast_oif;
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 34d1f06..edcaa92 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -240,17 +240,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
* me if there is a preferred way.
*/
{
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
memset(&fl, 0, sizeof(fl));
fl.proto = IPPROTO_TCP;
ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
- if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = srcrt_dst_flow_update(&final, &fl.fl6_dst, np->opt);
ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
fl.oif = sk->sk_bound_dev_if;
fl.mark = sk->sk_mark;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 2b7c3a1..212315a 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -129,7 +129,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
struct inet_connection_sock *icsk = inet_csk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct tcp_sock *tp = tcp_sk(sk);
- struct in6_addr *saddr = NULL, *final_p = NULL, final;
+ struct in6_addr *saddr = NULL, *final_p, final;
struct flowi fl;
struct dst_entry *dst;
int addr_type;
@@ -250,12 +250,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
fl.fl_ip_dport = usin->sin6_port;
fl.fl_ip_sport = inet->inet_sport;
- if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = srcrt_dst_flow_update(&final, &fl.fl6_dst, np->opt);
security_sk_classify_flow(sk, &fl);
@@ -477,7 +472,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
struct ipv6_pinfo *np = inet6_sk(sk);
struct sk_buff * skb;
struct ipv6_txoptions *opt = NULL;
- struct in6_addr * final_p = NULL, final;
+ struct in6_addr * final_p, final;
struct flowi fl;
struct dst_entry *dst;
int err = -1;
@@ -494,12 +489,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
security_req_classify_flow(req, &fl);
opt = np->opt;
- if (opt && opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = srcrt_dst_flow_update(&final, &fl.fl6_dst, opt);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err)
@@ -1392,18 +1382,13 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
goto out_overflow;
if (dst == NULL) {
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
memset(&fl, 0, sizeof(fl));
fl.proto = IPPROTO_TCP;
ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
- if (opt && opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = srcrt_dst_flow_update(&final, &fl.fl6_dst, opt);
ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
fl.oif = sk->sk_bound_dev_if;
fl.mark = sk->sk_mark;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 87be586..33aa47c 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -927,7 +927,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;
- struct in6_addr *daddr, *final_p = NULL, final;
+ struct in6_addr *daddr, *final_p, final;
struct ipv6_txoptions *opt = NULL;
struct ip6_flowlabel *flowlabel = NULL;
struct flowi fl;
@@ -1097,14 +1097,9 @@ do_udp_sendmsg:
ipv6_addr_copy(&fl.fl6_src, &np->saddr);
fl.fl_ip_sport = inet->inet_sport;
- /* merge ip6_build_xmit from ip6_output */
- if (opt && opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
+ final_p = srcrt_dst_flow_update(&final, &fl.fl6_dst, opt);
+ if (final_p)
connected = 0;
- }
if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) {
fl.oif = np->mcast_oif;
--
1.7.1
^ permalink raw reply related
* [2.6.35-rc1 regression] tg3 vpd r/w failed
From: Mikael Pettersson @ 2010-06-01 20:03 UTC (permalink / raw)
To: netdev; +Cc: Matt Carlson, linux-kernel
Booting 2.6.35-rc1 on a Sun Blade 2500 Red with builtin tg3 I get:
tg3.c:v3.110 (April 9, 2010)
PCI: Enabling device: (0000:00:03.0), cmd 2
...
tg3 0000:00:03.0: vpd r/w failed. This is likely a firmware bug on this device. Contact the card vendor for a firmware update.
tg3 0000:00:03.0: vpd r/w failed. This is likely a firmware bug on this device. Contact the card vendor for a firmware update.
tg3 0000:00:03.0: vpd r/w failed. This is likely a firmware bug on this device. Contact the card vendor for a firmware update.
tg3 0000:00:03.0: eth0: Tigon3 [partno(none) rev 1002] (PCI:66MHz:64-bit) MAC address ...
tg3 0000:00:03.0: eth0: attached PHY is 5703 (10/100/1000Base-T Ethernet) (WireSpeed[1])
tg3 0000:00:03.0: eth0: RXcsums[1] LinkChgREG[0] MIirq[0] ASF[0] TSOcap[1]
tg3 0000:00:03.0: eth0: dma_rwctrl[763f0000] dma_mask[32-bit]
...
tg3 0000:00:03.0: eth0: No firmware running
tg3 0000:00:03.0: eth0: Link is up at 100 Mbps, full duplex
tg3 0000:00:03.0: eth0: Flow control is on for TX and on for RX
The three 'vpd r/w failed' messages are new and did not occur with 2.6.34
or earlier kernels.
/Mikael
^ permalink raw reply
* [PATCH] xfrm: force a dst reference in __xfrm_route_forward()
From: Eric Dumazet @ 2010-06-01 20:04 UTC (permalink / raw)
To: David Miller; +Cc: netdev
Packets going through __xfrm_route_forward() have a not refcounted dst
entry, since we enabled a noref forwarding path.
xfrm_lookup() might incorrectly release this dst entry.
It's a bit late to make invasive changes in xfrm_lookup(), so lets force
a refcount in this path.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
net/xfrm/xfrm_policy.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index d965a2b..4bf27d9 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2153,6 +2153,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
return 0;
}
+ skb_dst_force(skb);
dst = skb_dst(skb);
res = xfrm_lookup(net, &dst, &fl, NULL, 0) == 0;
^ permalink raw reply related
* Re: [PATCHv2] Refactor update of IPv6 flow destination address for srcrt (RH) option
From: Joe Perches @ 2010-06-01 20:08 UTC (permalink / raw)
To: Arnaud Ebalard
Cc: David S. Miller,
YOSHIFUJI Hideaki / 吉藤英明, netdev
In-Reply-To: <8739x6d0ky.fsf@small.ssi.corp>
On Tue, 2010-06-01 at 21:17 +0200, Arnaud Ebalard wrote:
> I received a comment (privately) about the fact that the transform isn't
> equivalent as its sets final_p in all cases now, and asked if it matters?
>
> It does not: in current code, final_p is always initialized to NULL when
> it is declared. I also verified it is not used by anything between the
> declaration and the code I replace by the helper.
>
> In fact, one additional thing which can be done is to remove the
> initialization final_p to NULL when it is declared. The updated version
> below does that.
>
> Patch is against net-2.6. Tested on 2.6.34.
[]
> +static inline struct in6_addr *srcrt_dst_flow_update(struct in6_addr *final,
> + struct in6_addr *fl6dst,
> + const struct ipv6_txoptions *opt)
> +{
> + if (opt && opt->srcrt) {
> + const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
> + ipv6_addr_copy(final, fl6dst);
> + ipv6_addr_copy(fl6dst, rt0->addr);
> + return final;
> + }
> + return NULL;
> +}
> +
Should this be inline? Maybe it'd be better moved to exthdrs.c
Perhaps this is clearer as something like:
/**
* fl6_update_dst - update flow destination address
*
* @fl: flowlabel fl_dst to update
* @opt: struct ipv6_txoptions
* @orig: original fl_dst if modified
*
* Returns NULL if no txoptions or no srcrt, otherwise
* returns orig and initial value of fl->fl6_dst set in orig
*/
struct in6_addr *fl6_update_dst(struct ip6_flowlabel *fl,
const struct ipv6_txoptions *opt,
struct in6_addr *orig)
{
if (!opt || !opt->srcrt)
return NULL;
ipv6_addr_copy(orig, &fl->fl6_dst);
ipv6_addr_copy(&fl->fl6_dst, ((struct rt0_hdr *)opt->srcrt)->addr);
return orig;
}
^ permalink raw reply
* [PATCH] [ath5k][leds] Ability to disable leds support. If leds support enabled do not force mac802.11 leds layer selection.
From: Dmytro Milinevskyy @ 2010-04-07 18:58 UTC (permalink / raw)
To: ath5k-devel
Cc: Jiri Slaby, Nick Kossifidis, Luis R. Rodriguez, Bob Copeland,
John W. Linville, GeunSik Lim, Greg Kroah-Hartman, Lukas Turek,
Mark Hindley, Johannes Berg, Jiri Kosina, Kalle Valo, Keng-Yu Lin,
Luca Verdesca, Shahar Or, linux-wireless, netdev, linux-kernel,
Dmytro Milinevskyy
Hello!
Here is the patch to disable ath5k leds support on build stage.
However if the leds support was enabled do not force selection of 802.11 leds layer.
I've applied suggestion given by Pavel Roskin.
Best regards,
--Dima
---
drivers/net/wireless/ath/ath5k/Kconfig | 10 +++++++---
drivers/net/wireless/ath/ath5k/Makefile | 2 +-
drivers/net/wireless/ath/ath5k/ath5k.h | 16 +++++++++++-----
drivers/net/wireless/ath/ath5k/base.h | 17 ++++++++++++-----
drivers/net/wireless/ath/ath5k/gpio.c | 2 ++
drivers/net/wireless/ath/ath5k/led.c | 9 +++++++++
6 files changed, 42 insertions(+), 14 deletions(-)
diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig
index eb83b7b..6b5677e 100644
--- a/drivers/net/wireless/ath/ath5k/Kconfig
+++ b/drivers/net/wireless/ath/ath5k/Kconfig
@@ -1,9 +1,6 @@
config ATH5K
tristate "Atheros 5xxx wireless cards support"
depends on PCI && MAC80211
- select MAC80211_LEDS
- select LEDS_CLASS
- select NEW_LEDS
---help---
This module adds support for wireless adapters based on
Atheros 5xxx chipset.
@@ -18,6 +15,13 @@ config ATH5K
If you choose to build a module, it'll be called ath5k. Say M if
unsure.
+
+config ATH5K_LEDS
+ tristate "Atheros 5xxx wireless cards LEDs support"
+ depends on ATH5K
+ ---help---
+ Atheros 5xxx LED support.
+
config ATH5K_DEBUG
bool "Atheros 5xxx debugging"
depends on ATH5K
diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile
index cc09595..6d552dd 100644
--- a/drivers/net/wireless/ath/ath5k/Makefile
+++ b/drivers/net/wireless/ath/ath5k/Makefile
@@ -10,8 +10,8 @@ ath5k-y += phy.o
ath5k-y += reset.o
ath5k-y += attach.o
ath5k-y += base.o
-ath5k-y += led.o
ath5k-y += rfkill.o
ath5k-y += ani.o
ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o
+ath5k-$(CONFIG_ATH5K_LEDS) += led.o
obj-$(CONFIG_ATH5K) += ath5k.o
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 2785946..615b9ca 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -920,11 +920,6 @@ enum ath5k_power_mode {
#define AR5K_LED_ASSOC 3 /*IEEE80211_S_ASSOC*/
#define AR5K_LED_RUN 4 /*IEEE80211_S_RUN*/
-/* GPIO-controlled software LED */
-#define AR5K_SOFTLED_PIN 0
-#define AR5K_SOFTLED_ON 0
-#define AR5K_SOFTLED_OFF 1
-
/*
* Chipset capabilities -see ath5k_hw_get_capability-
* get_capability function is not yet fully implemented
@@ -1148,11 +1143,18 @@ struct ath5k_hw {
int ath5k_hw_attach(struct ath5k_softc *sc);
void ath5k_hw_detach(struct ath5k_hw *ah);
+#ifdef CONFIG_ATH5K_LEDS
/* LED functions */
int ath5k_init_leds(struct ath5k_softc *sc);
void ath5k_led_enable(struct ath5k_softc *sc);
void ath5k_led_off(struct ath5k_softc *sc);
void ath5k_unregister_leds(struct ath5k_softc *sc);
+#else
+#define ath5k_init_leds(sc) do {} while (0)
+#define ath5k_led_enable(sc) do {} while (0)
+#define ath5k_led_off(sc) do {} while (0)
+#define ath5k_unregister_leds(sc) do {} while (0)
+#endif
/* Reset Functions */
int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
@@ -1233,7 +1235,11 @@ int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
int ath5k_hw_init_desc_functions(struct ath5k_hw *ah);
/* GPIO Functions */
+#ifdef CONFIG_ATH5K_LEDS
void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state);
+#else
+#define ath5k_hw_set_ledstate(ah, state) do {} while (0)
+#endif
int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio);
int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio);
u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio);
diff --git a/drivers/net/wireless/ath/ath5k/base.h b/drivers/net/wireless/ath/ath5k/base.h
index 56221bc..e493d34 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -86,15 +86,19 @@ struct ath5k_txq {
#define ATH5K_LED_MAX_NAME_LEN 31
+#ifdef CONFIG_ATH5K_LEDS
/*
* State for LED triggers
*/
struct ath5k_led
{
- char name[ATH5K_LED_MAX_NAME_LEN + 1]; /* name of the LED in sysfs */
struct ath5k_softc *sc; /* driver state */
+#ifdef CONFIG_LEDS_CLASS
+ char name[ATH5K_LED_MAX_NAME_LEN + 1]; /* name of the LED in sysfs */
struct led_classdev led_dev; /* led classdev */
+#endif
};
+#endif
/* Rfkill */
struct ath5k_rfkill {
@@ -186,9 +190,6 @@ struct ath5k_softc {
u8 bssidmask[ETH_ALEN];
- unsigned int led_pin, /* GPIO pin for driving LED */
- led_on; /* pin setting for LED on */
-
struct tasklet_struct restq; /* reset tasklet */
unsigned int rxbufsize; /* rx size based on mtu */
@@ -196,7 +197,6 @@ struct ath5k_softc {
spinlock_t rxbuflock;
u32 *rxlink; /* link ptr in last RX desc */
struct tasklet_struct rxtq; /* rx intr tasklet */
- struct ath5k_led rx_led; /* rx led */
struct list_head txbuf; /* transmit buffer */
spinlock_t txbuflock;
@@ -204,7 +204,14 @@ struct ath5k_softc {
struct ath5k_txq txqs[AR5K_NUM_TX_QUEUES]; /* tx queues */
struct ath5k_txq *txq; /* main tx queue */
struct tasklet_struct txtq; /* tx intr tasklet */
+
+
+#ifdef CONFIG_ATH5K_LEDS
+ unsigned int led_pin, /* GPIO pin for driving LED */
+ led_on; /* pin setting for LED on */
+ struct ath5k_led rx_led; /* rx led */
struct ath5k_led tx_led; /* tx led */
+#endif
struct ath5k_rfkill rf_kill;
diff --git a/drivers/net/wireless/ath/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c
index 64a27e7..9e757b3 100644
--- a/drivers/net/wireless/ath/ath5k/gpio.c
+++ b/drivers/net/wireless/ath/ath5k/gpio.c
@@ -25,6 +25,7 @@
#include "debug.h"
#include "base.h"
+#ifdef CONFIG_ATH5K_LEDS
/*
* Set led state
*/
@@ -76,6 +77,7 @@ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
else
AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210);
}
+#endif
/*
* Set GPIO inputs
diff --git a/drivers/net/wireless/ath/ath5k/led.c b/drivers/net/wireless/ath/ath5k/led.c
index 67aa52e..df8e8d2 100644
--- a/drivers/net/wireless/ath/ath5k/led.c
+++ b/drivers/net/wireless/ath/ath5k/led.c
@@ -121,6 +121,7 @@ ath5k_led_brightness_set(struct led_classdev *led_dev,
ath5k_led_on(led->sc);
}
+#ifdef CONFIG_LEDS_CLASS
static int
ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led,
const char *name, char *trigger)
@@ -140,13 +141,16 @@ ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led,
}
return err;
}
+#endif
static void
ath5k_unregister_led(struct ath5k_led *led)
{
if (!led->sc)
return;
+#ifdef CONFIG_LEDS_CLASS
led_classdev_unregister(&led->led_dev);
+#endif
ath5k_led_off(led->sc);
led->sc = NULL;
}
@@ -177,6 +181,7 @@ int ath5k_init_leds(struct ath5k_softc *sc)
ath5k_led_enable(sc);
+#ifdef CONFIG_LEDS_CLASS
snprintf(name, sizeof(name), "ath5k-%s::rx", wiphy_name(hw->wiphy));
ret = ath5k_register_led(sc, &sc->rx_led, name,
ieee80211_get_rx_led_name(hw));
@@ -186,6 +191,10 @@ int ath5k_init_leds(struct ath5k_softc *sc)
snprintf(name, sizeof(name), "ath5k-%s::tx", wiphy_name(hw->wiphy));
ret = ath5k_register_led(sc, &sc->tx_led, name,
ieee80211_get_tx_led_name(hw));
+#else
+ sc->rx_led.sc = sc;
+ sc->tx_led.sc = sc;
+#endif
out:
return ret;
}
--
1.7.1
^ permalink raw reply related
* Re: [PATCH] [ath5k][leds] Ability to disable leds support. If leds support enabled do not force mac802.11 leds layer selection.
From: Bob Copeland @ 2010-06-01 20:34 UTC (permalink / raw)
To: Dmytro Milinevskyy
Cc: ath5k-devel, Jiri Slaby, Nick Kossifidis, Luis R. Rodriguez,
John W. Linville, GeunSik Lim, Greg Kroah-Hartman, Lukas Turek,
Mark Hindley, Johannes Berg, Jiri Kosina, Kalle Valo, Keng-Yu Lin,
Luca Verdesca, Shahar Or, linux-wireless, netdev, linux-kernel
In-Reply-To: <4c056b50.0c3fdf0a.500b.44af@mx.google.com>
On Wed, Apr 7, 2010 at 2:58 PM, Dmytro Milinevskyy
<milinevskyy@gmail.com> wrote:
> Hello!
Thanks, comments inline.
> +config ATH5K_LEDS
> + tristate "Atheros 5xxx wireless cards LEDs support"
> + depends on ATH5K
> + ---help---
> + Atheros 5xxx LED support.
> +
This can select the proper LED classes? Then you can get rid of another
ifdef check later.
> -/* GPIO-controlled software LED */
> -#define AR5K_SOFTLED_PIN 0
> -#define AR5K_SOFTLED_ON 0
> -#define AR5K_SOFTLED_OFF 1
> -
Please drop this hunk, no problem keeping it around.
> +#ifdef CONFIG_ATH5K_LEDS
> /* LED functions */
> int ath5k_init_leds(struct ath5k_softc *sc);
> void ath5k_led_enable(struct ath5k_softc *sc);
> void ath5k_led_off(struct ath5k_softc *sc);
> void ath5k_unregister_leds(struct ath5k_softc *sc);
> +#else
> +#define ath5k_init_leds(sc) do {} while (0)
> +#define ath5k_led_enable(sc) do {} while (0)
> +#define ath5k_led_off(sc) do {} while (0)
> +#define ath5k_unregister_leds(sc) do {} while (0)
> +#endif
I prefer:
#ifdef
...
#else
static inline int ath5k_init_leds(struct ath5k_softc *sc)
{
return 0;
}
...
#endif
so you get type-checking. Also this doesn't quite work in your version:
int foo = ath5k_init_leds(sc);
> +#ifdef CONFIG_ATH5K_LEDS
> /*
> * State for LED triggers
> */
> struct ath5k_led
> {
> - char name[ATH5K_LED_MAX_NAME_LEN + 1]; /* name of the LED in sysfs */
> struct ath5k_softc *sc; /* driver state */
> +#ifdef CONFIG_LEDS_CLASS
> + char name[ATH5K_LED_MAX_NAME_LEN + 1]; /* name of the LED in sysfs */
> struct led_classdev led_dev; /* led classdev */
> +#endif
> };
> +#endif
Why move name?
> /* Rfkill */
> struct ath5k_rfkill {
> @@ -186,9 +190,6 @@ struct ath5k_softc {
>
> u8 bssidmask[ETH_ALEN];
>
> - unsigned int led_pin, /* GPIO pin for driving LED */
> - led_on; /* pin setting for LED on */
> -
> struct tasklet_struct restq; /* reset tasklet */
>
> unsigned int rxbufsize; /* rx size based on mtu */
> @@ -196,7 +197,6 @@ struct ath5k_softc {
> spinlock_t rxbuflock;
> u32 *rxlink; /* link ptr in last RX desc */
> struct tasklet_struct rxtq; /* rx intr tasklet */
> - struct ath5k_led rx_led; /* rx led */
>
> struct list_head txbuf; /* transmit buffer */
> spinlock_t txbuflock;
> @@ -204,7 +204,14 @@ struct ath5k_softc {
> struct ath5k_txq txqs[AR5K_NUM_TX_QUEUES]; /* tx queues */
> struct ath5k_txq *txq; /* main tx queue */
> struct tasklet_struct txtq; /* tx intr tasklet */
> +
> +
> +#ifdef CONFIG_ATH5K_LEDS
> + unsigned int led_pin, /* GPIO pin for driving LED */
> + led_on; /* pin setting for LED on */
> + struct ath5k_led rx_led; /* rx led */
> struct ath5k_led tx_led; /* tx led */
> +#endif
You might want to do this in two stages: move the led-dependent things
together in the structure (or into a separate structure) and then only
have one #ifdef section.
Still too many ifdefs in general.
--
Bob Copeland %% www.bobcopeland.com
^ permalink raw reply
* [PATCH] IP: Increment INADDRERRORS if routing for a packet is not successful
From: Christoph Lameter @ 2010-06-01 21:13 UTC (permalink / raw)
To: netdev; +Cc: Stephen Hemminger, David Miller
Something like this would have been very helpful during recent debugging
of multicast issues. Silent discards are bad.
If the kernel perceives that something is wrong with an incoming packet then the
IP stack currently silently discards packets. This makes it difficult to diagnose
problems with the network configurations (such as a misbehaving kernel
subsystem discarding multicast packets because the reverse path filter
does not like multicast subscriptions on the second NIC with rp_filter=1).
It is also necessary to know how many inbound packets are discarded to
assess networking issues in general with a NIC.
Signed-off-by: Christoph Lameter <cl@linux-foundation.org>
Acked-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/ipv4/route.c | 3 +++
1 file changed, 3 insertions(+)
Index: linux-2.6/net/ipv4/route.c
===================================================================
--- linux-2.6.orig/net/ipv4/route.c 2010-06-01 11:46:10.000000000 -0500
+++ linux-2.6/net/ipv4/route.c 2010-06-01 11:52:55.000000000 -0500
@@ -2981,6 +2981,9 @@ static int inet_rtm_getroute(struct sk_b
rt = skb_rtable(skb);
if (err == 0 && rt->u.dst.error)
err = -rt->u.dst.error;
+ if (err)
+ IP_INC_STATS_BH(dev_net(skb->dev),
+ IPSTATS_MIB_INADDRERRORS);
} else {
struct flowi fl = {
.nl_u = {
^ permalink raw reply
* [PATCH 00/12] sfc changes for 2.6.36
From: Ben Hutchings @ 2010-06-01 21:16 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
Here's a first series of changes for 2.6.36.
The major feature here is RX buffer recycling, which improves
performance on networks with heavy multicast traffic. Other than that,
there are various bug fixes and cleanup.
Ben.
Ben Hutchings (3):
sfc: Rename struct efx_mcdi_phy_cfg to efx_mcdi_phy_data
sfc: Only count bad packets in rx_errors
sfc: Get port number from CS_PORT_NUM, not PCI function number
Steve Hodgson (9):
sfc: Reschedule any resets scheduled inside efx_pm_freeze()
sfc: Workaround flush failures on Falcon B0
sfc: Synchronise link_advertising and wanted_fc on Siena
sfc: Wait for the link to stay up before running loopback selftest
sfc: Allow DRV_GEN events to be used outside of selftests
sfc: Remove efx_rx_queue::add_lock
sfc: Support only two rx buffers per page
sfc: Recycle discarded rx buffers back onto the queue
sfc: Allow shared pages to be recycled
drivers/net/sfc/efx.c | 69 +++-----
drivers/net/sfc/efx.h | 4 +-
drivers/net/sfc/falcon.c | 8 +-
drivers/net/sfc/mcdi_phy.c | 21 ++-
drivers/net/sfc/net_driver.h | 46 +++--
drivers/net/sfc/nic.c | 55 +++++--
drivers/net/sfc/nic.h | 4 +-
drivers/net/sfc/rx.c | 393 +++++++++++++++++++----------------------
drivers/net/sfc/selftest.c | 26 ++--
drivers/net/sfc/siena.c | 4 +
drivers/net/sfc/workarounds.h | 2 +-
11 files changed, 317 insertions(+), 315 deletions(-)
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
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
* [PATCH 01/12] sfc: Rename struct efx_mcdi_phy_cfg to efx_mcdi_phy_data
From: Ben Hutchings @ 2010-06-01 21:17 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1275426967.2114.25.camel@achroite.uk.solarflarecom.com>
Most of its members are constant capabilities, not configuration. The
new name is also consistent with the name of the pointer to it in
struct efx_nic and the names of structures used by other PHY drivers.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/mcdi_phy.c | 20 ++++++++++----------
1 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c
index 6032c0e..5c23f22 100644
--- a/drivers/net/sfc/mcdi_phy.c
+++ b/drivers/net/sfc/mcdi_phy.c
@@ -20,7 +20,7 @@
#include "nic.h"
#include "selftest.h"
-struct efx_mcdi_phy_cfg {
+struct efx_mcdi_phy_data {
u32 flags;
u32 type;
u32 supported_cap;
@@ -35,7 +35,7 @@ struct efx_mcdi_phy_cfg {
};
static int
-efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_cfg *cfg)
+efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_data *cfg)
{
u8 outbuf[MC_CMD_GET_PHY_CFG_OUT_LEN];
size_t outlen;
@@ -259,7 +259,7 @@ static u32 ethtool_to_mcdi_cap(u32 cap)
static u32 efx_get_mcdi_phy_flags(struct efx_nic *efx)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
enum efx_phy_mode mode, supported;
u32 flags;
@@ -307,7 +307,7 @@ static u32 mcdi_to_ethtool_media(u32 media)
static int efx_mcdi_phy_probe(struct efx_nic *efx)
{
- struct efx_mcdi_phy_cfg *phy_data;
+ struct efx_mcdi_phy_data *phy_data;
u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
u32 caps;
int rc;
@@ -405,7 +405,7 @@ fail:
int efx_mcdi_phy_reconfigure(struct efx_nic *efx)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u32 caps = (efx->link_advertising ?
ethtool_to_mcdi_cap(efx->link_advertising) :
phy_cfg->forced_cap);
@@ -446,7 +446,7 @@ void efx_mcdi_phy_decode_link(struct efx_nic *efx,
*/
void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u32 rmtadv;
/* The link partner capabilities are only relevent if the
@@ -505,7 +505,7 @@ static void efx_mcdi_phy_remove(struct efx_nic *efx)
static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
int rc;
@@ -535,7 +535,7 @@ static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *e
static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u32 caps;
int rc;
@@ -674,7 +674,7 @@ out:
static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results,
unsigned flags)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u32 mode;
int rc;
@@ -712,7 +712,7 @@ static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results,
const char *efx_mcdi_phy_test_name(struct efx_nic *efx, unsigned int index)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) {
if (index == 0)
--
1.6.2.5
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
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 related
* [PATCH 02/12] sfc: Reschedule any resets scheduled inside efx_pm_freeze()
From: Ben Hutchings @ 2010-06-01 21:17 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1275426967.2114.25.camel@achroite.uk.solarflarecom.com>
From: Steve Hodgson <shodgson@solarflare.com>
efx_pm_freeze() sets efx->state = STATE_FINI, which means
efx_reset_work() will abort any scheduled resets.
efx_pm_thaw() should reschedule efx_reset_work() again,
since a freeze/thaw will not have reset the hardware.
This bug was spotted by inspection - there is no real world example of
this happening.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/efx.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 1564605..0319000 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1886,6 +1886,9 @@ static void efx_reset_work(struct work_struct *data)
{
struct efx_nic *efx = container_of(data, struct efx_nic, reset_work);
+ if (efx->reset_pending == RESET_TYPE_NONE)
+ return;
+
/* If we're not RUNNING then don't reset. Leave the reset_pending
* flag set so that efx_pci_probe_main will be retried */
if (efx->state != STATE_RUNNING) {
@@ -2332,6 +2335,9 @@ static int efx_pm_thaw(struct device *dev)
efx->type->resume_wol(efx);
+ /* Reschedule any quenched resets scheduled during efx_pm_freeze() */
+ queue_work(reset_workqueue, &efx->reset_work);
+
return 0;
}
--
1.6.2.5
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
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 related
* [PATCH 03/12] sfc: Workaround flush failures on Falcon B0
From: Ben Hutchings @ 2010-06-01 21:17 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1275426967.2114.25.camel@achroite.uk.solarflarecom.com>
From: Steve Hodgson <shodgson@solarflare.com>
Under certain conditions a PHY may backpressure Falcon B0
in such a way that flushes timeout. In normal circumstances
the phy poller would fix the PHY, and the flush could complete.
But efx_nic_flush_queues() is always called after efx_stop_all(),
so the poller has been stopped. Even if this weren't the case,
how long would we have to wait for the poller to fix this? And
several callers of efx_nic_flush_queues() are about to reset
the device anyway - so we don't need to do anything.
Work around this bug by scheduling a reset. Ensure that the
MAC is never rewired back into the datapath before the reset
runs (we already ignore all rx events anyway).
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/efx.c | 13 +++++++++++--
drivers/net/sfc/falcon.c | 8 +++++---
drivers/net/sfc/nic.c | 3 ---
drivers/net/sfc/workarounds.h | 2 +-
4 files changed, 17 insertions(+), 9 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 0319000..d1a1d32 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -27,6 +27,7 @@
#include "nic.h"
#include "mcdi.h"
+#include "workarounds.h"
/**************************************************************************
*
@@ -556,10 +557,18 @@ static void efx_fini_channels(struct efx_nic *efx)
BUG_ON(efx->port_enabled);
rc = efx_nic_flush_queues(efx);
- if (rc)
+ if (rc && EFX_WORKAROUND_7803(efx)) {
+ /* Schedule a reset to recover from the flush failure. The
+ * descriptor caches reference memory we're about to free,
+ * but falcon_reconfigure_mac_wrapper() won't reconnect
+ * the MACs because of the pending reset. */
+ EFX_ERR(efx, "Resetting to recover from flush failure\n");
+ efx_schedule_reset(efx, RESET_TYPE_ALL);
+ } else if (rc) {
EFX_ERR(efx, "failed to flush queues\n");
- else
+ } else {
EFX_LOG(efx, "successfully flushed all queues\n");
+ }
efx_for_each_channel(channel, efx) {
EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel);
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 655b697..8558865 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -548,7 +548,9 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
{
struct efx_link_state *link_state = &efx->link_state;
efx_oword_t reg;
- int link_speed;
+ int link_speed, isolate;
+
+ isolate = (efx->reset_pending != RESET_TYPE_NONE);
switch (link_state->speed) {
case 10000: link_speed = 3; break;
@@ -570,7 +572,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
* discarded. */
if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN,
- !link_state->up);
+ !link_state->up || isolate);
}
efx_writeo(efx, ®, FR_AB_MAC_CTRL);
@@ -584,7 +586,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
/* Unisolate the MAC -> RX */
if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
- EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, !isolate);
efx_writeo(efx, ®, FR_AZ_RX_CFG);
}
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index 5d3aaec..ec0bb80 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -1219,9 +1219,6 @@ int efx_nic_flush_queues(struct efx_nic *efx)
rx_queue->flushed = FLUSH_DONE;
}
- if (EFX_WORKAROUND_7803(efx))
- return 0;
-
return -ETIMEDOUT;
}
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index 518f7fc..782e45a 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -54,7 +54,7 @@
/* Increase filter depth to avoid RX_RESET */
#define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A
/* Flushes may never complete */
-#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_A
+#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_AB
/* Leak overlength packets rather than free */
#define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A
--
1.6.2.5
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
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 related
* [PATCH 04/12] sfc: Synchronise link_advertising and wanted_fc on Siena
From: Ben Hutchings @ 2010-06-01 21:18 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1275426967.2114.25.camel@achroite.uk.solarflarecom.com>
From: Steve Hodgson <shodgson@solarflare.com>
All of the ethtool code paths keep them in sync, but we need
to ensure they are sync'd at start of day. Matches the sft9001
driver.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/mcdi_phy.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c
index 5c23f22..86e43b1 100644
--- a/drivers/net/sfc/mcdi_phy.c
+++ b/drivers/net/sfc/mcdi_phy.c
@@ -395,6 +395,7 @@ static int efx_mcdi_phy_probe(struct efx_nic *efx)
efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
efx->wanted_fc |= EFX_FC_AUTO;
+ efx_link_set_wanted_fc(efx, efx->wanted_fc);
return 0;
--
1.6.2.5
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
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 related
* [PATCH 05/12] sfc: Wait for the link to stay up before running loopback selftest
From: Ben Hutchings @ 2010-06-01 21:18 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1275426967.2114.25.camel@achroite.uk.solarflarecom.com>
From: Steve Hodgson <shodgson@solarflare.com>
It's been observed that some phys (such as the qt2025c) can
do down-up-down-up transitions, presumably as pcs block lock
settles down.
The loopback selftest will start sending data immediately
after the link comes up. Work around this by waiting for
the link state to stay up for two consecutive polls, rather
than one.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/selftest.c | 10 +++++++---
1 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 371e86c..52ac14a 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -545,7 +545,7 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
static int efx_wait_for_link(struct efx_nic *efx)
{
struct efx_link_state *link_state = &efx->link_state;
- int count;
+ int count, link_up_count = 0;
bool link_up;
for (count = 0; count < 40; count++) {
@@ -567,8 +567,12 @@ static int efx_wait_for_link(struct efx_nic *efx)
link_up = !efx->mac_op->check_fault(efx);
mutex_unlock(&efx->mac_lock);
- if (link_up)
- return 0;
+ if (link_up) {
+ if (++link_up_count == 2)
+ return 0;
+ } else {
+ link_up_count = 0;
+ }
}
return -ETIMEDOUT;
--
1.6.2.5
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
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 related
* [PATCH 06/12] sfc: Allow DRV_GEN events to be used outside of selftests
From: Ben Hutchings @ 2010-06-01 21:19 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1275426967.2114.25.camel@achroite.uk.solarflarecom.com>
From: Steve Hodgson <shodgson@solarflare.com>
Formerly, efx_test_eventq_irq() assumed it was the only user of
driver generated events. Allow it to interoperate with other users.
We can create more than 16 channels, so align event codes with
a multiple of 256 not 16.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/net_driver.h | 4 ++--
drivers/net/sfc/nic.c | 17 ++++++++++-------
drivers/net/sfc/nic.h | 3 +--
drivers/net/sfc/selftest.c | 16 +++++-----------
4 files changed, 18 insertions(+), 22 deletions(-)
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 2e6fd89..ee0ea01 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -336,7 +336,7 @@ enum efx_rx_alloc_method {
* @eventq: Event queue buffer
* @eventq_read_ptr: Event queue read pointer
* @last_eventq_read_ptr: Last event queue read pointer value.
- * @eventq_magic: Event queue magic value for driver-generated test events
+ * @magic_count: Event queue test event count
* @irq_count: Number of IRQs since last adaptive moderation decision
* @irq_mod_score: IRQ moderation score
* @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
@@ -367,7 +367,7 @@ struct efx_channel {
struct efx_special_buffer eventq;
unsigned int eventq_read_ptr;
unsigned int last_eventq_read_ptr;
- unsigned int eventq_magic;
+ unsigned int magic_count;
unsigned int irq_count;
unsigned int irq_mod_score;
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index ec0bb80..ca9cf1a 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -79,6 +79,10 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
/* Depth of RX flush request fifo */
#define EFX_RX_FLUSH_COUNT 4
+/* Magic value for efx_generate_test_event() */
+#define EFX_CHANNEL_MAGIC(_channel) \
+ (0x00010100 + (_channel)->channel)
+
/**************************************************************************
*
* Solarstorm hardware access
@@ -993,8 +997,10 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget)
}
break;
case FSE_AZ_EV_CODE_DRV_GEN_EV:
- channel->eventq_magic = EFX_QWORD_FIELD(
- event, FSF_AZ_DRV_GEN_EV_MAGIC);
+ if (EFX_QWORD_FIELD(event, FSF_AZ_DRV_GEN_EV_MAGIC)
+ == EFX_CHANNEL_MAGIC(channel))
+ ++channel->magic_count;
+
EFX_LOG(channel->efx, "channel %d received generated "
"event "EFX_QWORD_FMT"\n", channel->channel,
EFX_QWORD_VAL(event));
@@ -1088,12 +1094,9 @@ void efx_nic_remove_eventq(struct efx_channel *channel)
}
-/* Generates a test event on the event queue. A subsequent call to
- * process_eventq() should pick up the event and place the value of
- * "magic" into channel->eventq_magic;
- */
-void efx_nic_generate_test_event(struct efx_channel *channel, unsigned int magic)
+void efx_nic_generate_test_event(struct efx_channel *channel)
{
+ unsigned int magic = EFX_CHANNEL_MAGIC(channel);
efx_qword_t test_event;
EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h
index bbc2c0c..186aab5 100644
--- a/drivers/net/sfc/nic.h
+++ b/drivers/net/sfc/nic.h
@@ -190,8 +190,7 @@ extern int efx_nic_rx_xoff_thresh, efx_nic_rx_xon_thresh;
/* Interrupts and test events */
extern int efx_nic_init_interrupt(struct efx_nic *efx);
extern void efx_nic_enable_interrupts(struct efx_nic *efx);
-extern void efx_nic_generate_test_event(struct efx_channel *channel,
- unsigned int magic);
+extern void efx_nic_generate_test_event(struct efx_channel *channel);
extern void efx_nic_generate_interrupt(struct efx_nic *efx);
extern void efx_nic_disable_interrupts(struct efx_nic *efx);
extern void efx_nic_fini_interrupt(struct efx_nic *efx);
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 52ac14a..c088740 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -161,23 +161,17 @@ static int efx_test_interrupts(struct efx_nic *efx,
static int efx_test_eventq_irq(struct efx_channel *channel,
struct efx_self_tests *tests)
{
- unsigned int magic, count;
-
- /* Channel specific code, limited to 20 bits */
- magic = (0x00010150 + channel->channel);
- EFX_LOG(channel->efx, "channel %d testing event queue with code %x\n",
- channel->channel, magic);
+ unsigned int magic_count, count;
tests->eventq_dma[channel->channel] = -1;
tests->eventq_int[channel->channel] = -1;
tests->eventq_poll[channel->channel] = -1;
- /* Reset flag and zero magic word */
+ magic_count = channel->magic_count;
channel->efx->last_irq_cpu = -1;
- channel->eventq_magic = 0;
smp_wmb();
- efx_nic_generate_test_event(channel, magic);
+ efx_nic_generate_test_event(channel);
/* Wait for arrival of interrupt */
count = 0;
@@ -187,7 +181,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
if (channel->work_pending)
efx_process_channel_now(channel);
- if (channel->eventq_magic == magic)
+ if (channel->magic_count != magic_count)
goto eventq_ok;
} while (++count < 2);
@@ -204,7 +198,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
/* Check to see if event was received even if interrupt wasn't */
efx_process_channel_now(channel);
- if (channel->eventq_magic == magic) {
+ if (channel->magic_count != magic_count) {
EFX_ERR(channel->efx, "channel %d event was generated, but "
"failed to trigger an interrupt\n", channel->channel);
tests->eventq_dma[channel->channel] = 1;
--
1.6.2.5
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
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 related
* [PATCH 07/12] sfc: Remove efx_rx_queue::add_lock
From: Ben Hutchings @ 2010-06-01 21:19 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1275426967.2114.25.camel@achroite.uk.solarflarecom.com>
From: Steve Hodgson <shodgson@solarflare.com>
Ensure that efx_fast_push_rx_descriptors() must only run
from efx_process_channel() [NAPI], or when napi_disable()
has been executed.
Reimplement the slow fill by sending an event to the
channel, so that NAPI runs, and hanging the subsequent
fast fill off the event handler. Replace the sfc_refill
workqueue and delayed work items with a timer. We do
not need to stop this timer in efx_flush_all() because
it's safe to send the event always; receiving it will
be delayed until NAPI is restarted.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/efx.c | 44 +++----------------
drivers/net/sfc/efx.h | 4 +-
drivers/net/sfc/net_driver.h | 10 +---
drivers/net/sfc/nic.c | 49 +++++++++++++++++----
drivers/net/sfc/nic.h | 1 +
drivers/net/sfc/rx.c | 95 +++++++++--------------------------------
6 files changed, 73 insertions(+), 130 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index d1a1d32..5d9ef05 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -93,13 +93,6 @@ const char *efx_reset_type_names[] = {
#define EFX_MAX_MTU (9 * 1024)
-/* RX slow fill workqueue. If memory allocation fails in the fast path,
- * a work item is pushed onto this work queue to retry the allocation later,
- * to avoid the NIC being starved of RX buffers. Since this is a per cpu
- * workqueue, there is nothing to be gained in making it per NIC
- */
-static struct workqueue_struct *refill_workqueue;
-
/* Reset workqueue. If any NIC has a hardware failure then a reset will be
* queued onto this work queue. This is not a per-nic work queue, because
* efx_reset_work() acquires the rtnl lock, so resets are naturally serialised.
@@ -516,11 +509,11 @@ static void efx_start_channel(struct efx_channel *channel)
channel->enabled = true;
smp_wmb();
- napi_enable(&channel->napi_str);
-
- /* Load up RX descriptors */
+ /* Fill the queues before enabling NAPI */
efx_for_each_channel_rx_queue(rx_queue, channel)
efx_fast_push_rx_descriptors(rx_queue);
+
+ napi_enable(&channel->napi_str);
}
/* This disables event queue processing and packet transmission.
@@ -529,8 +522,6 @@ static void efx_start_channel(struct efx_channel *channel)
*/
static void efx_stop_channel(struct efx_channel *channel)
{
- struct efx_rx_queue *rx_queue;
-
if (!channel->enabled)
return;
@@ -538,12 +529,6 @@ static void efx_stop_channel(struct efx_channel *channel)
channel->enabled = false;
napi_disable(&channel->napi_str);
-
- /* Ensure that any worker threads have exited or will be no-ops */
- efx_for_each_channel_rx_queue(rx_queue, channel) {
- spin_lock_bh(&rx_queue->add_lock);
- spin_unlock_bh(&rx_queue->add_lock);
- }
}
static void efx_fini_channels(struct efx_nic *efx)
@@ -595,9 +580,9 @@ static void efx_remove_channel(struct efx_channel *channel)
efx_remove_eventq(channel);
}
-void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay)
+void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue)
{
- queue_delayed_work(refill_workqueue, &rx_queue->work, delay);
+ mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100));
}
/**************************************************************************
@@ -1242,15 +1227,8 @@ static void efx_start_all(struct efx_nic *efx)
* since we're holding the rtnl_lock at this point. */
static void efx_flush_all(struct efx_nic *efx)
{
- struct efx_rx_queue *rx_queue;
-
/* Make sure the hardware monitor is stopped */
cancel_delayed_work_sync(&efx->monitor_work);
-
- /* Ensure that all RX slow refills are complete. */
- efx_for_each_rx_queue(rx_queue, efx)
- cancel_delayed_work_sync(&rx_queue->work);
-
/* Stop scheduled port reconfigurations */
cancel_work_sync(&efx->mac_work);
}
@@ -2064,8 +2042,8 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
rx_queue->queue = i;
rx_queue->channel = &efx->channel[0]; /* for safety */
rx_queue->buffer = NULL;
- spin_lock_init(&rx_queue->add_lock);
- INIT_DELAYED_WORK(&rx_queue->work, efx_rx_work);
+ setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill,
+ (unsigned long)rx_queue);
}
efx->type = type;
@@ -2436,11 +2414,6 @@ static int __init efx_init_module(void)
if (rc)
goto err_notifier;
- refill_workqueue = create_workqueue("sfc_refill");
- if (!refill_workqueue) {
- rc = -ENOMEM;
- goto err_refill;
- }
reset_workqueue = create_singlethread_workqueue("sfc_reset");
if (!reset_workqueue) {
rc = -ENOMEM;
@@ -2456,8 +2429,6 @@ static int __init efx_init_module(void)
err_pci:
destroy_workqueue(reset_workqueue);
err_reset:
- destroy_workqueue(refill_workqueue);
- err_refill:
unregister_netdevice_notifier(&efx_netdev_notifier);
err_notifier:
return rc;
@@ -2469,7 +2440,6 @@ static void __exit efx_exit_module(void)
pci_unregister_driver(&efx_pci_driver);
destroy_workqueue(reset_workqueue);
- destroy_workqueue(refill_workqueue);
unregister_netdevice_notifier(&efx_netdev_notifier);
}
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index ffd708c..e1e4488 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -47,12 +47,12 @@ extern void efx_init_rx_queue(struct efx_rx_queue *rx_queue);
extern void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);
extern void efx_rx_strategy(struct efx_channel *channel);
extern void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
-extern void efx_rx_work(struct work_struct *data);
+extern void efx_rx_slow_fill(unsigned long context);
extern void __efx_rx_packet(struct efx_channel *channel,
struct efx_rx_buffer *rx_buf, bool checksummed);
extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
unsigned int len, bool checksummed, bool discard);
-extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay);
+extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue);
#define EFX_RXQ_SIZE 1024
#define EFX_RXQ_MASK (EFX_RXQ_SIZE - 1)
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index ee0ea01..4539803 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -18,6 +18,7 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
+#include <linux/timer.h>
#include <linux/mdio.h>
#include <linux/list.h>
#include <linux/pci.h>
@@ -242,10 +243,6 @@ struct efx_rx_buffer {
* @added_count: Number of buffers added to the receive queue.
* @notified_count: Number of buffers given to NIC (<= @added_count).
* @removed_count: Number of buffers removed from the receive queue.
- * @add_lock: Receive queue descriptor add spin lock.
- * This lock must be held in order to add buffers to the RX
- * descriptor ring (rxd and buffer) and to update added_count (but
- * not removed_count).
* @max_fill: RX descriptor maximum fill level (<= ring size)
* @fast_fill_trigger: RX descriptor fill level that will trigger a fast fill
* (<= @max_fill)
@@ -259,7 +256,7 @@ struct efx_rx_buffer {
* overflow was observed. It should never be set.
* @alloc_page_count: RX allocation strategy counter.
* @alloc_skb_count: RX allocation strategy counter.
- * @work: Descriptor push work thread
+ * @slow_fill: Timer used to defer efx_nic_generate_fill_event().
* @buf_page: Page for next RX buffer.
* We can use a single page for multiple RX buffers. This tracks
* the remaining space in the allocation.
@@ -277,7 +274,6 @@ struct efx_rx_queue {
int added_count;
int notified_count;
int removed_count;
- spinlock_t add_lock;
unsigned int max_fill;
unsigned int fast_fill_trigger;
unsigned int fast_fill_limit;
@@ -285,7 +281,7 @@ struct efx_rx_queue {
unsigned int min_overfill;
unsigned int alloc_page_count;
unsigned int alloc_skb_count;
- struct delayed_work work;
+ struct timer_list slow_fill;
unsigned int slow_fill_count;
struct page *buf_page;
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index ca9cf1a..0ee6fd3 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -79,10 +79,14 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
/* Depth of RX flush request fifo */
#define EFX_RX_FLUSH_COUNT 4
-/* Magic value for efx_generate_test_event() */
-#define EFX_CHANNEL_MAGIC(_channel) \
+/* Generated event code for efx_generate_test_event() */
+#define EFX_CHANNEL_MAGIC_TEST(_channel) \
(0x00010100 + (_channel)->channel)
+/* Generated event code for efx_generate_fill_event() */
+#define EFX_CHANNEL_MAGIC_FILL(_channel) \
+ (0x00010200 + (_channel)->channel)
+
/**************************************************************************
*
* Solarstorm hardware access
@@ -854,6 +858,26 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
checksummed, discard);
}
+static void
+efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event)
+{
+ struct efx_nic *efx = channel->efx;
+ unsigned code;
+
+ code = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC);
+ if (code == EFX_CHANNEL_MAGIC_TEST(channel))
+ ++channel->magic_count;
+ else if (code == EFX_CHANNEL_MAGIC_FILL(channel))
+ /* The queue must be empty, so we won't receive any rx
+ * events, so efx_process_channel() won't refill the
+ * queue. Refill it here */
+ efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]);
+ else
+ EFX_LOG(efx, "channel %d received generated "
+ "event "EFX_QWORD_FMT"\n", channel->channel,
+ EFX_QWORD_VAL(*event));
+}
+
/* Global events are basically PHY events */
static void
efx_handle_global_event(struct efx_channel *channel, efx_qword_t *event)
@@ -997,13 +1021,7 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget)
}
break;
case FSE_AZ_EV_CODE_DRV_GEN_EV:
- if (EFX_QWORD_FIELD(event, FSF_AZ_DRV_GEN_EV_MAGIC)
- == EFX_CHANNEL_MAGIC(channel))
- ++channel->magic_count;
-
- EFX_LOG(channel->efx, "channel %d received generated "
- "event "EFX_QWORD_FMT"\n", channel->channel,
- EFX_QWORD_VAL(event));
+ efx_handle_generated_event(channel, &event);
break;
case FSE_AZ_EV_CODE_GLOBAL_EV:
efx_handle_global_event(channel, &event);
@@ -1096,7 +1114,18 @@ void efx_nic_remove_eventq(struct efx_channel *channel)
void efx_nic_generate_test_event(struct efx_channel *channel)
{
- unsigned int magic = EFX_CHANNEL_MAGIC(channel);
+ unsigned int magic = EFX_CHANNEL_MAGIC_TEST(channel);
+ efx_qword_t test_event;
+
+ EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
+ FSE_AZ_EV_CODE_DRV_GEN_EV,
+ FSF_AZ_DRV_GEN_EV_MAGIC, magic);
+ efx_generate_event(channel, &test_event);
+}
+
+void efx_nic_generate_fill_event(struct efx_channel *channel)
+{
+ unsigned int magic = EFX_CHANNEL_MAGIC_FILL(channel);
efx_qword_t test_event;
EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h
index 186aab5..95770e1 100644
--- a/drivers/net/sfc/nic.h
+++ b/drivers/net/sfc/nic.h
@@ -191,6 +191,7 @@ extern int efx_nic_rx_xoff_thresh, efx_nic_rx_xon_thresh;
extern int efx_nic_init_interrupt(struct efx_nic *efx);
extern void efx_nic_enable_interrupts(struct efx_nic *efx);
extern void efx_nic_generate_test_event(struct efx_channel *channel);
+extern void efx_nic_generate_fill_event(struct efx_channel *channel);
extern void efx_nic_generate_interrupt(struct efx_nic *efx);
extern void efx_nic_disable_interrupts(struct efx_nic *efx);
extern void efx_nic_fini_interrupt(struct efx_nic *efx);
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index e308818..bf1e55e 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -276,28 +276,25 @@ static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
/**
* efx_fast_push_rx_descriptors - push new RX descriptors quickly
* @rx_queue: RX descriptor queue
- * @retry: Recheck the fill level
* This will aim to fill the RX descriptor queue up to
* @rx_queue->@fast_fill_limit. If there is insufficient atomic
- * memory to do so, the caller should retry.
+ * memory to do so, a slow fill will be scheduled.
+ *
+ * The caller must provide serialisation (none is used here). In practise,
+ * this means this function must run from the NAPI handler, or be called
+ * when NAPI is disabled.
*/
-static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
- int retry)
+void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
{
struct efx_rx_buffer *rx_buf;
unsigned fill_level, index;
int i, space, rc = 0;
- /* Calculate current fill level. Do this outside the lock,
- * because most of the time we'll end up not wanting to do the
- * fill anyway.
- */
+ /* Calculate current fill level, and exit if we don't need to fill */
fill_level = (rx_queue->added_count - rx_queue->removed_count);
EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE);
-
- /* Don't fill if we don't need to */
if (fill_level >= rx_queue->fast_fill_trigger)
- return 0;
+ return;
/* Record minimum fill level */
if (unlikely(fill_level < rx_queue->min_fill)) {
@@ -305,20 +302,9 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
rx_queue->min_fill = fill_level;
}
- /* Acquire RX add lock. If this lock is contended, then a fast
- * fill must already be in progress (e.g. in the refill
- * tasklet), so we don't need to do anything
- */
- if (!spin_trylock_bh(&rx_queue->add_lock))
- return -1;
-
- retry:
- /* Recalculate current fill level now that we have the lock */
- fill_level = (rx_queue->added_count - rx_queue->removed_count);
- EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE);
space = rx_queue->fast_fill_limit - fill_level;
if (space < EFX_RX_BATCH)
- goto out_unlock;
+ return;
EFX_TRACE(rx_queue->efx, "RX queue %d fast-filling descriptor ring from"
" level %d to level %d using %s allocation\n",
@@ -330,8 +316,13 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
index = rx_queue->added_count & EFX_RXQ_MASK;
rx_buf = efx_rx_buffer(rx_queue, index);
rc = efx_init_rx_buffer(rx_queue, rx_buf);
- if (unlikely(rc))
+ if (unlikely(rc)) {
+ /* Ensure that we don't leave the rx queue
+ * empty */
+ if (rx_queue->added_count == rx_queue->removed_count)
+ efx_schedule_slow_fill(rx_queue);
goto out;
+ }
++rx_queue->added_count;
}
} while ((space -= EFX_RX_BATCH) >= EFX_RX_BATCH);
@@ -343,61 +334,16 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
out:
/* Send write pointer to card. */
efx_nic_notify_rx_desc(rx_queue);
-
- /* If the fast fill is running inside from the refill tasklet, then
- * for SMP systems it may be running on a different CPU to
- * RX event processing, which means that the fill level may now be
- * out of date. */
- if (unlikely(retry && (rc == 0)))
- goto retry;
-
- out_unlock:
- spin_unlock_bh(&rx_queue->add_lock);
-
- return rc;
}
-/**
- * efx_fast_push_rx_descriptors - push new RX descriptors quickly
- * @rx_queue: RX descriptor queue
- *
- * This will aim to fill the RX descriptor queue up to
- * @rx_queue->@fast_fill_limit. If there is insufficient memory to do so,
- * it will schedule a work item to immediately continue the fast fill
- */
-void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
-{
- int rc;
-
- rc = __efx_fast_push_rx_descriptors(rx_queue, 0);
- if (unlikely(rc)) {
- /* Schedule the work item to run immediately. The hope is
- * that work is immediately pending to free some memory
- * (e.g. an RX event or TX completion)
- */
- efx_schedule_slow_fill(rx_queue, 0);
- }
-}
-
-void efx_rx_work(struct work_struct *data)
+void efx_rx_slow_fill(unsigned long context)
{
- struct efx_rx_queue *rx_queue;
- int rc;
-
- rx_queue = container_of(data, struct efx_rx_queue, work.work);
-
- if (unlikely(!rx_queue->channel->enabled))
- return;
-
- EFX_TRACE(rx_queue->efx, "RX queue %d worker thread executing on CPU "
- "%d\n", rx_queue->queue, raw_smp_processor_id());
+ struct efx_rx_queue *rx_queue = (struct efx_rx_queue *)context;
+ struct efx_channel *channel = rx_queue->channel;
+ /* Post an event to cause NAPI to run and refill the queue */
+ efx_nic_generate_fill_event(channel);
++rx_queue->slow_fill_count;
- /* Push new RX descriptors, allowing at least 1 jiffy for
- * the kernel to free some more memory. */
- rc = __efx_fast_push_rx_descriptors(rx_queue, 1);
- if (rc)
- efx_schedule_slow_fill(rx_queue, 1);
}
static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
@@ -682,6 +628,7 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue);
+ del_timer_sync(&rx_queue->slow_fill);
efx_nic_fini_rx(rx_queue);
/* Release RX buffers NB start at index 0 not current HW ptr */
--
1.6.2.5
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
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 related
* [PATCH 09/12] sfc: Recycle discarded rx buffers back onto the queue
From: Ben Hutchings @ 2010-06-01 21:20 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1275426967.2114.25.camel@achroite.uk.solarflarecom.com>
From: Steve Hodgson <shodgson@solarflare.com>
The cut-through design of the receive path means that packets that
fail to match the appropriate MAC filter are not discarded at the MAC
but are flagged in the completion event as 'to be discarded'. On
networks with heavy multicast traffic, this can account for a
significant proportion of received packets, so it is worthwhile to
recycle the buffer immediately in this case rather than freeing it
and then reallocating it shortly after.
The only complication here is dealing with a page shared
between two receive buffers. In that case, we need to be
careful to free the dma mapping when both buffers have
been free'd by the kernel. This means that we can only
recycle such a page if both receive buffers are discarded.
Unfortunately, in an environment with 1500mtu,
rx_alloc_method=PAGE, and a mixture of discarded and
not-discarded frames hitting the same receive queue,
buffer recycling won't always be possible.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/rx.c | 90 +++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 79 insertions(+), 11 deletions(-)
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index 615a1fc..dfebd73 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -82,9 +82,10 @@ static unsigned int rx_refill_limit = 95;
* RX maximum head room required.
*
* This must be at least 1 to prevent overflow and at least 2 to allow
- * pipelined receives.
+ * pipelined receives. Then a further 1 because efx_recycle_rx_buffer()
+ * might insert two buffers.
*/
-#define EFX_RXD_HEAD_ROOM 2
+#define EFX_RXD_HEAD_ROOM 3
static inline unsigned int efx_rx_buf_offset(struct efx_rx_buffer *buf)
{
@@ -250,6 +251,70 @@ static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
efx_free_rx_buffer(rx_queue->efx, rx_buf);
}
+/* Attempt to resurrect the other receive buffer that used to share this page,
+ * which had previously been passed up to the kernel and freed. */
+static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct efx_rx_buffer *new_buf;
+ unsigned index;
+
+ /* We could have recycled the 1st half, then refilled
+ * the queue, and now recycle the 2nd half.
+ * EFX_RXD_HEAD_ROOM ensures that there is always room
+ * to reinsert two buffers (once). */
+ get_page(rx_buf->page);
+
+ index = rx_queue->added_count & EFX_RXQ_MASK;
+ new_buf = efx_rx_buffer(rx_queue, index);
+ new_buf->dma_addr = rx_buf->dma_addr - (PAGE_SIZE >> 1);
+ new_buf->skb = NULL;
+ new_buf->page = rx_buf->page;
+ new_buf->data = rx_buf->data - (PAGE_SIZE >> 1);
+ new_buf->len = rx_buf->len;
+ ++rx_queue->added_count;
+}
+
+/* Recycle the given rx buffer directly back into the rx_queue. There is
+ * always room to add this buffer, because we've just popped a buffer. */
+static void efx_recycle_rx_buffer(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct efx_nic *efx = channel->efx;
+ struct efx_rx_queue *rx_queue = &efx->rx_queue[channel->channel];
+ struct efx_rx_buffer *new_buf;
+ unsigned index;
+
+ if (rx_buf->page != NULL && efx->rx_buffer_len < (PAGE_SIZE >> 1)) {
+ if (efx_rx_buf_offset(rx_buf) & (PAGE_SIZE >> 1)) {
+ /* This is the 2nd half of a page split between two
+ * buffers, If page_count() is > 1 then the kernel
+ * is holding onto the previous buffer */
+ if (page_count(rx_buf->page) != 1) {
+ efx_fini_rx_buffer(rx_queue, rx_buf);
+ return;
+ }
+
+ efx_resurrect_rx_buffer(rx_queue, rx_buf);
+ } else {
+ /* Free the 1st buffer's reference on the page. If the
+ * 2nd buffer is also discarded, this buffer will be
+ * resurrected above */
+ put_page(rx_buf->page);
+ rx_buf->page = NULL;
+ return;
+ }
+ }
+
+ index = rx_queue->added_count & EFX_RXQ_MASK;
+ new_buf = efx_rx_buffer(rx_queue, index);
+
+ memcpy(new_buf, rx_buf, sizeof(*new_buf));
+ rx_buf->page = NULL;
+ rx_buf->skb = NULL;
+ ++rx_queue->added_count;
+}
+
/**
* efx_fast_push_rx_descriptors - push new RX descriptors quickly
* @rx_queue: RX descriptor queue
@@ -271,7 +336,7 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
fill_level = (rx_queue->added_count - rx_queue->removed_count);
EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE);
if (fill_level >= rx_queue->fast_fill_trigger)
- return;
+ goto out;
/* Record minimum fill level */
if (unlikely(fill_level < rx_queue->min_fill)) {
@@ -281,7 +346,7 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
space = rx_queue->fast_fill_limit - fill_level;
if (space < EFX_RX_BATCH)
- return;
+ goto out;
EFX_TRACE(rx_queue->efx, "RX queue %d fast-filling descriptor ring from"
" level %d to level %d using %s allocation\n",
@@ -306,8 +371,8 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
rx_queue->added_count - rx_queue->removed_count);
out:
- /* Send write pointer to card. */
- efx_nic_notify_rx_desc(rx_queue);
+ if (rx_queue->notified_count != rx_queue->added_count)
+ efx_nic_notify_rx_desc(rx_queue);
}
void efx_rx_slow_fill(unsigned long context)
@@ -418,6 +483,7 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
unsigned int len, bool checksummed, bool discard)
{
struct efx_nic *efx = rx_queue->efx;
+ struct efx_channel *channel = rx_queue->channel;
struct efx_rx_buffer *rx_buf;
bool leak_packet = false;
@@ -445,12 +511,13 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
/* Discard packet, if instructed to do so */
if (unlikely(discard)) {
if (unlikely(leak_packet))
- rx_queue->channel->n_skbuff_leaks++;
+ channel->n_skbuff_leaks++;
else
- /* We haven't called efx_unmap_rx_buffer yet,
- * so fini the entire rx_buffer here */
- efx_fini_rx_buffer(rx_queue, rx_buf);
- return;
+ efx_recycle_rx_buffer(channel, rx_buf);
+
+ /* Don't hold off the previous receive */
+ rx_buf = NULL;
+ goto out;
}
/* Release card resources - assumes all RX buffers consumed in-order
@@ -467,6 +534,7 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
* prefetched into cache.
*/
rx_buf->len = len;
+out:
if (rx_queue->channel->rx_pkt)
__efx_rx_packet(rx_queue->channel,
rx_queue->channel->rx_pkt,
--
1.6.2.5
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
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 related
* [PATCH 10/12] sfc: Allow shared pages to be recycled
From: Ben Hutchings @ 2010-06-01 21:20 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1275426967.2114.25.camel@achroite.uk.solarflarecom.com>
From: Steve Hodgson <shodgson@solarflare.com>
Insert a structure at the start of the shared page that
tracks the dma mapping refcnt. DMA into the next cache
line of the (shared) page (plus EFX_PAGE_IP_ALIGN).
When recycling a page, check the page refcnt. If the
page is otherwise unused, then resurrect the other
receive buffer that previously referenced the page.
Be careful not to overflow the receive ring, since we
can now resurrect n receive buffers in a row.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/efx.c | 3 +-
drivers/net/sfc/net_driver.h | 18 +++++++++
drivers/net/sfc/rx.c | 84 +++++++++++++++++++++---------------------
3 files changed, 62 insertions(+), 43 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 5d9ef05..aae3347 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -469,7 +469,8 @@ static void efx_init_channels(struct efx_nic *efx)
efx->rx_buffer_len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) +
EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
efx->type->rx_buffer_padding);
- efx->rx_buffer_order = get_order(efx->rx_buffer_len);
+ efx->rx_buffer_order = get_order(efx->rx_buffer_len +
+ sizeof(struct efx_rx_page_state));
/* Initialise the channels */
efx_for_each_channel(channel, efx) {
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 59c8ecc..40c0d93 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -232,6 +232,24 @@ struct efx_rx_buffer {
};
/**
+ * struct efx_rx_page_state - Page-based rx buffer state
+ *
+ * Inserted at the start of every page allocated for receive buffers.
+ * Used to facilitate sharing dma mappings between recycled rx buffers
+ * and those passed up to the kernel.
+ *
+ * @refcnt: Number of struct efx_rx_buffer's referencing this page.
+ * When refcnt falls to zero, the page is unmapped for dma
+ * @dma_addr: The dma address of this page.
+ */
+struct efx_rx_page_state {
+ unsigned refcnt;
+ dma_addr_t dma_addr;
+
+ unsigned int __pad[0] ____cacheline_aligned;
+};
+
+/**
* struct efx_rx_queue - An Efx RX queue
* @efx: The associated Efx NIC
* @queue: DMA queue number
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index dfebd73..9fb698e 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -25,6 +25,9 @@
/* Number of RX descriptors pushed at once. */
#define EFX_RX_BATCH 8
+/* Maximum size of a buffer sharing a page */
+#define EFX_RX_HALF_PAGE ((PAGE_SIZE >> 1) - sizeof(struct efx_rx_page_state))
+
/* Size of buffer allocated for skb header area. */
#define EFX_SKB_HEADERS 64u
@@ -82,10 +85,9 @@ static unsigned int rx_refill_limit = 95;
* RX maximum head room required.
*
* This must be at least 1 to prevent overflow and at least 2 to allow
- * pipelined receives. Then a further 1 because efx_recycle_rx_buffer()
- * might insert two buffers.
+ * pipelined receives.
*/
-#define EFX_RXD_HEAD_ROOM 3
+#define EFX_RXD_HEAD_ROOM 2
static inline unsigned int efx_rx_buf_offset(struct efx_rx_buffer *buf)
{
@@ -164,7 +166,8 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
struct efx_nic *efx = rx_queue->efx;
struct efx_rx_buffer *rx_buf;
struct page *page;
- char *page_addr;
+ void *page_addr;
+ struct efx_rx_page_state *state;
dma_addr_t dma_addr;
unsigned index, count;
@@ -183,22 +186,27 @@ static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
__free_pages(page, efx->rx_buffer_order);
return -EIO;
}
- EFX_BUG_ON_PARANOID(dma_addr & (PAGE_SIZE - 1));
- page_addr = page_address(page) + EFX_PAGE_IP_ALIGN;
- dma_addr += EFX_PAGE_IP_ALIGN;
+ page_addr = page_address(page);
+ state = page_addr;
+ state->refcnt = 0;
+ state->dma_addr = dma_addr;
+
+ page_addr += sizeof(struct efx_rx_page_state);
+ dma_addr += sizeof(struct efx_rx_page_state);
split:
index = rx_queue->added_count & EFX_RXQ_MASK;
rx_buf = efx_rx_buffer(rx_queue, index);
- rx_buf->dma_addr = dma_addr;
+ rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN;
rx_buf->skb = NULL;
rx_buf->page = page;
- rx_buf->data = page_addr;
+ rx_buf->data = page_addr + EFX_PAGE_IP_ALIGN;
rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
++rx_queue->added_count;
++rx_queue->alloc_page_count;
+ ++state->refcnt;
- if ((~count & 1) && (efx->rx_buffer_len < (PAGE_SIZE >> 1))) {
+ if ((~count & 1) && (efx->rx_buffer_len <= EFX_RX_HALF_PAGE)) {
/* Use the second half of the page */
get_page(page);
dma_addr += (PAGE_SIZE >> 1);
@@ -215,14 +223,14 @@ static void efx_unmap_rx_buffer(struct efx_nic *efx,
struct efx_rx_buffer *rx_buf)
{
if (rx_buf->page) {
+ struct efx_rx_page_state *state;
+
EFX_BUG_ON_PARANOID(rx_buf->skb);
- /* Unmap the buffer if there's only one buffer per page(s),
- * or this is the second half of a two buffer page. */
- if (efx->rx_buffer_order != 0 ||
- (efx_rx_buf_offset(rx_buf) & (PAGE_SIZE >> 1)) != 0) {
+ state = page_address(rx_buf->page);
+ if (--state->refcnt == 0) {
pci_unmap_page(efx->pci_dev,
- rx_buf->dma_addr & ~(PAGE_SIZE - 1),
+ state->dma_addr,
efx_rx_buf_size(efx),
PCI_DMA_FROMDEVICE);
}
@@ -256,21 +264,30 @@ static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue,
struct efx_rx_buffer *rx_buf)
{
+ struct efx_rx_page_state *state = page_address(rx_buf->page);
struct efx_rx_buffer *new_buf;
- unsigned index;
+ unsigned fill_level, index;
+
+ /* +1 because efx_rx_packet() incremented removed_count. +1 because
+ * we'd like to insert an additional descriptor whilst leaving
+ * EFX_RXD_HEAD_ROOM for the non-recycle path */
+ fill_level = (rx_queue->added_count - rx_queue->removed_count + 2);
+ if (unlikely(fill_level >= EFX_RXQ_SIZE - EFX_RXD_HEAD_ROOM)) {
+ /* We could place "state" on a list, and drain the list in
+ * efx_fast_push_rx_descriptors(). For now, this will do. */
+ return;
+ }
- /* We could have recycled the 1st half, then refilled
- * the queue, and now recycle the 2nd half.
- * EFX_RXD_HEAD_ROOM ensures that there is always room
- * to reinsert two buffers (once). */
+ ++state->refcnt;
get_page(rx_buf->page);
index = rx_queue->added_count & EFX_RXQ_MASK;
new_buf = efx_rx_buffer(rx_queue, index);
- new_buf->dma_addr = rx_buf->dma_addr - (PAGE_SIZE >> 1);
+ new_buf->dma_addr = rx_buf->dma_addr ^ (PAGE_SIZE >> 1);
new_buf->skb = NULL;
new_buf->page = rx_buf->page;
- new_buf->data = rx_buf->data - (PAGE_SIZE >> 1);
+ new_buf->data = (void *)
+ ((__force unsigned long)rx_buf->data ^ (PAGE_SIZE >> 1));
new_buf->len = rx_buf->len;
++rx_queue->added_count;
}
@@ -285,26 +302,9 @@ static void efx_recycle_rx_buffer(struct efx_channel *channel,
struct efx_rx_buffer *new_buf;
unsigned index;
- if (rx_buf->page != NULL && efx->rx_buffer_len < (PAGE_SIZE >> 1)) {
- if (efx_rx_buf_offset(rx_buf) & (PAGE_SIZE >> 1)) {
- /* This is the 2nd half of a page split between two
- * buffers, If page_count() is > 1 then the kernel
- * is holding onto the previous buffer */
- if (page_count(rx_buf->page) != 1) {
- efx_fini_rx_buffer(rx_queue, rx_buf);
- return;
- }
-
- efx_resurrect_rx_buffer(rx_queue, rx_buf);
- } else {
- /* Free the 1st buffer's reference on the page. If the
- * 2nd buffer is also discarded, this buffer will be
- * resurrected above */
- put_page(rx_buf->page);
- rx_buf->page = NULL;
- return;
- }
- }
+ if (rx_buf->page != NULL && efx->rx_buffer_len <= EFX_RX_HALF_PAGE &&
+ page_count(rx_buf->page) == 1)
+ efx_resurrect_rx_buffer(rx_queue, rx_buf);
index = rx_queue->added_count & EFX_RXQ_MASK;
new_buf = efx_rx_buffer(rx_queue, index);
--
1.6.2.5
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
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 related
* [PATCH 11/12] sfc: Only count bad packets in rx_errors
From: Ben Hutchings @ 2010-06-01 21:21 UTC (permalink / raw)
To: David Miller; +Cc: netdev, linux-net-drivers
In-Reply-To: <1275426967.2114.25.camel@achroite.uk.solarflarecom.com>
rx_errors is defined as 'bad packets received', but we are currently
including various overflow errors as well.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
---
drivers/net/sfc/efx.c | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index aae3347..26b0cc2 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -1518,11 +1518,8 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
stats->tx_window_errors = mac_stats->tx_late_collision;
stats->rx_errors = (stats->rx_length_errors +
- stats->rx_over_errors +
stats->rx_crc_errors +
stats->rx_frame_errors +
- stats->rx_fifo_errors +
- stats->rx_missed_errors +
mac_stats->rx_symbol_error);
stats->tx_errors = (stats->tx_window_errors +
mac_stats->tx_bad);
--
1.6.2.5
--
Ben Hutchings, Senior Software Engineer, Solarflare Communications
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 related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox