* [PATCH net-next v4 0/3] netpoll: add IPv6 support
From: Cong Wang @ 2013-01-07 7:17 UTC (permalink / raw)
To: netdev; +Cc: Cong Wang
v4: remove ndisc_parse_options(), ignore ICMP options there
make udp6_csum_init() inline so that we don't rely on IPV6=y
fix a conflict with Jiri's patchset
v3: fix CONFIG_IPV6=m case
v2: use bool for ipv6 flag
fix !CONFIG_IPV6 case
This patchset implements netpoll over IPv6.
Cong Wang (3):
netpoll: prepare for ipv6
netpoll: add IPv6 support
netconsole: add IPv6 example in doc
Documentation/networking/netconsole.txt | 7 +-
drivers/net/netconsole.c | 46 ++-
include/linux/netpoll.h | 13 +-
include/net/udp.h | 34 ++
net/core/netpoll.c | 617 ++++++++++++++++++++++---------
net/ipv6/udp.c | 34 --
6 files changed, 534 insertions(+), 217 deletions(-)
--
1.7.7.6
^ permalink raw reply
* [PATCH net-next v4 1/3] netpoll: prepare for ipv6
From: Cong Wang @ 2013-01-07 7:17 UTC (permalink / raw)
To: netdev; +Cc: David S. Miller, Cong Wang
In-Reply-To: <1357543036-15492-1-git-send-email-amwang@redhat.com>
From: Cong Wang <amwang@redhat.com>
This patch adjusts some struct and functions, to prepare
for supporting IPv6.
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
drivers/net/netconsole.c | 12 +-
include/linux/netpoll.h | 13 ++-
net/core/netpoll.c | 402 ++++++++++++++++++++++++++--------------------
3 files changed, 243 insertions(+), 184 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 6989ebe..998fa02 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -269,12 +269,14 @@ static ssize_t show_remote_port(struct netconsole_target *nt, char *buf)
static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
+ if (!nt->np.ipv6)
+ return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
}
static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
+ if (!nt->np.ipv6)
+ return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
}
static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
@@ -410,7 +412,8 @@ static ssize_t store_local_ip(struct netconsole_target *nt,
return -EINVAL;
}
- nt->np.local_ip = in_aton(buf);
+ if (!strnchr(buf, count, ':'))
+ nt->np.local_ip.ip = in_aton(buf);
return strnlen(buf, count);
}
@@ -426,7 +429,8 @@ static ssize_t store_remote_ip(struct netconsole_target *nt,
return -EINVAL;
}
- nt->np.remote_ip = in_aton(buf);
+ if (!strnchr(buf, count, ':'))
+ nt->np.remote_ip.ip = in_aton(buf);
return strnlen(buf, count);
}
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 66d5379..f54c3bb 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -12,13 +12,22 @@
#include <linux/rcupdate.h>
#include <linux/list.h>
+union inet_addr {
+ __u32 all[4];
+ __be32 ip;
+ __be32 ip6[4];
+ struct in_addr in;
+ struct in6_addr in6;
+};
+
struct netpoll {
struct net_device *dev;
char dev_name[IFNAMSIZ];
const char *name;
void (*rx_hook)(struct netpoll *, int, char *, int);
- __be32 local_ip, remote_ip;
+ union inet_addr local_ip, remote_ip;
+ bool ipv6;
u16 local_port, remote_port;
u8 remote_mac[ETH_ALEN];
@@ -33,7 +42,7 @@ struct netpoll_info {
spinlock_t rx_lock;
struct list_head rx_np; /* netpolls that registered an rx_hook */
- struct sk_buff_head arp_tx; /* list of arp requests to reply to */
+ struct sk_buff_head neigh_tx; /* list of neigh requests to reply to */
struct sk_buff_head txq;
struct delayed_work tx_work;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index d2bda8e..6bd0736 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -55,7 +55,7 @@ static atomic_t trapped;
MAX_UDP_CHUNK)
static void zap_completion_queue(void);
-static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo);
+static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo);
static unsigned int carrier_timeout = 4;
module_param(carrier_timeout, uint, 0644);
@@ -181,13 +181,13 @@ static void poll_napi(struct net_device *dev)
}
}
-static void service_arp_queue(struct netpoll_info *npi)
+static void service_neigh_queue(struct netpoll_info *npi)
{
if (npi) {
struct sk_buff *skb;
- while ((skb = skb_dequeue(&npi->arp_tx)))
- netpoll_arp_reply(skb, npi);
+ while ((skb = skb_dequeue(&npi->neigh_tx)))
+ netpoll_neigh_reply(skb, npi);
}
}
@@ -216,14 +216,14 @@ static void netpoll_poll_dev(struct net_device *dev)
bond_dev = netdev_master_upper_dev_get_rcu(dev);
bond_ni = rcu_dereference_bh(bond_dev->npinfo);
- while ((skb = skb_dequeue(&ni->arp_tx))) {
+ while ((skb = skb_dequeue(&ni->neigh_tx))) {
skb->dev = bond_dev;
- skb_queue_tail(&bond_ni->arp_tx, skb);
+ skb_queue_tail(&bond_ni->neigh_tx, skb);
}
}
}
- service_arp_queue(ni);
+ service_neigh_queue(ni);
zap_completion_queue();
}
@@ -386,7 +386,9 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
static atomic_t ip_ident;
udp_len = len + sizeof(*udph);
- ip_len = udp_len + sizeof(*iph);
+ if (!np->ipv6)
+ ip_len = udp_len + sizeof(*iph);
+
total_len = ip_len + LL_RESERVED_SPACE(np->dev);
skb = find_skb(np, total_len + np->dev->needed_tailroom,
@@ -403,34 +405,38 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
udph->source = htons(np->local_port);
udph->dest = htons(np->remote_port);
udph->len = htons(udp_len);
- udph->check = 0;
- udph->check = csum_tcpudp_magic(np->local_ip,
- np->remote_ip,
- udp_len, IPPROTO_UDP,
- csum_partial(udph, udp_len, 0));
- if (udph->check == 0)
- udph->check = CSUM_MANGLED_0;
-
- skb_push(skb, sizeof(*iph));
- skb_reset_network_header(skb);
- iph = ip_hdr(skb);
-
- /* iph->version = 4; iph->ihl = 5; */
- put_unaligned(0x45, (unsigned char *)iph);
- iph->tos = 0;
- put_unaligned(htons(ip_len), &(iph->tot_len));
- iph->id = htons(atomic_inc_return(&ip_ident));
- iph->frag_off = 0;
- iph->ttl = 64;
- iph->protocol = IPPROTO_UDP;
- iph->check = 0;
- put_unaligned(np->local_ip, &(iph->saddr));
- put_unaligned(np->remote_ip, &(iph->daddr));
- iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-
- eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
- skb_reset_mac_header(skb);
- skb->protocol = eth->h_proto = htons(ETH_P_IP);
+
+ if (!np->ipv6) {
+ udph->check = 0;
+ udph->check = csum_tcpudp_magic(np->local_ip.ip,
+ np->remote_ip.ip,
+ udp_len, IPPROTO_UDP,
+ csum_partial(udph, udp_len, 0));
+ if (udph->check == 0)
+ udph->check = CSUM_MANGLED_0;
+
+ skb_push(skb, sizeof(*iph));
+ skb_reset_network_header(skb);
+ iph = ip_hdr(skb);
+
+ /* iph->version = 4; iph->ihl = 5; */
+ put_unaligned(0x45, (unsigned char *)iph);
+ iph->tos = 0;
+ put_unaligned(htons(ip_len), &(iph->tot_len));
+ iph->id = htons(atomic_inc_return(&ip_ident));
+ iph->frag_off = 0;
+ iph->ttl = 64;
+ iph->protocol = IPPROTO_UDP;
+ iph->check = 0;
+ put_unaligned(np->local_ip.ip, &(iph->saddr));
+ put_unaligned(np->remote_ip.ip, &(iph->daddr));
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+
+ eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
+ skb_reset_mac_header(skb);
+ skb->protocol = eth->h_proto = htons(ETH_P_IP);
+ }
+
memcpy(eth->h_source, np->dev->dev_addr, ETH_ALEN);
memcpy(eth->h_dest, np->remote_mac, ETH_ALEN);
@@ -440,7 +446,7 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
}
EXPORT_SYMBOL(netpoll_send_udp);
-static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
+static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
{
struct arphdr *arp;
unsigned char *arp_ptr;
@@ -451,7 +457,7 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
struct netpoll *np, *tmp;
unsigned long flags;
int hlen, tlen;
- int hits = 0;
+ int hits = 0, proto;
if (list_empty(&npinfo->rx_np))
return;
@@ -469,94 +475,97 @@ static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
if (!hits)
return;
- /* No arp on this interface */
- if (skb->dev->flags & IFF_NOARP)
- return;
-
- if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
- return;
+ proto = ntohs(eth_hdr(skb)->h_proto);
+ if (proto == ETH_P_IP) {
+ /* No arp on this interface */
+ if (skb->dev->flags & IFF_NOARP)
+ return;
- skb_reset_network_header(skb);
- skb_reset_transport_header(skb);
- arp = arp_hdr(skb);
+ if (!pskb_may_pull(skb, arp_hdr_len(skb->dev)))
+ return;
- if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
- arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
- arp->ar_pro != htons(ETH_P_IP) ||
- arp->ar_op != htons(ARPOP_REQUEST))
- return;
+ skb_reset_network_header(skb);
+ skb_reset_transport_header(skb);
+ arp = arp_hdr(skb);
- arp_ptr = (unsigned char *)(arp+1);
- /* save the location of the src hw addr */
- sha = arp_ptr;
- arp_ptr += skb->dev->addr_len;
- memcpy(&sip, arp_ptr, 4);
- arp_ptr += 4;
- /* If we actually cared about dst hw addr,
- it would get copied here */
- arp_ptr += skb->dev->addr_len;
- memcpy(&tip, arp_ptr, 4);
-
- /* Should we ignore arp? */
- if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
- return;
+ if ((arp->ar_hrd != htons(ARPHRD_ETHER) &&
+ arp->ar_hrd != htons(ARPHRD_IEEE802)) ||
+ arp->ar_pro != htons(ETH_P_IP) ||
+ arp->ar_op != htons(ARPOP_REQUEST))
+ return;
- size = arp_hdr_len(skb->dev);
+ arp_ptr = (unsigned char *)(arp+1);
+ /* save the location of the src hw addr */
+ sha = arp_ptr;
+ arp_ptr += skb->dev->addr_len;
+ memcpy(&sip, arp_ptr, 4);
+ arp_ptr += 4;
+ /* If we actually cared about dst hw addr,
+ it would get copied here */
+ arp_ptr += skb->dev->addr_len;
+ memcpy(&tip, arp_ptr, 4);
- spin_lock_irqsave(&npinfo->rx_lock, flags);
- list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
- if (tip != np->local_ip)
- continue;
+ /* Should we ignore arp? */
+ if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
+ return;
- hlen = LL_RESERVED_SPACE(np->dev);
- tlen = np->dev->needed_tailroom;
- send_skb = find_skb(np, size + hlen + tlen, hlen);
- if (!send_skb)
- continue;
+ size = arp_hdr_len(skb->dev);
- skb_reset_network_header(send_skb);
- arp = (struct arphdr *) skb_put(send_skb, size);
- send_skb->dev = skb->dev;
- send_skb->protocol = htons(ETH_P_ARP);
+ spin_lock_irqsave(&npinfo->rx_lock, flags);
+ list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+ if (tip != np->local_ip.ip)
+ continue;
+
+ hlen = LL_RESERVED_SPACE(np->dev);
+ tlen = np->dev->needed_tailroom;
+ send_skb = find_skb(np, size + hlen + tlen, hlen);
+ if (!send_skb)
+ continue;
+
+ skb_reset_network_header(send_skb);
+ arp = (struct arphdr *) skb_put(send_skb, size);
+ send_skb->dev = skb->dev;
+ send_skb->protocol = htons(ETH_P_ARP);
+
+ /* Fill the device header for the ARP frame */
+ if (dev_hard_header(send_skb, skb->dev, ptype,
+ sha, np->dev->dev_addr,
+ send_skb->len) < 0) {
+ kfree_skb(send_skb);
+ continue;
+ }
- /* Fill the device header for the ARP frame */
- if (dev_hard_header(send_skb, skb->dev, ptype,
- sha, np->dev->dev_addr,
- send_skb->len) < 0) {
- kfree_skb(send_skb);
- continue;
+ /*
+ * Fill out the arp protocol part.
+ *
+ * we only support ethernet device type,
+ * which (according to RFC 1390) should
+ * always equal 1 (Ethernet).
+ */
+
+ arp->ar_hrd = htons(np->dev->type);
+ arp->ar_pro = htons(ETH_P_IP);
+ arp->ar_hln = np->dev->addr_len;
+ arp->ar_pln = 4;
+ arp->ar_op = htons(type);
+
+ arp_ptr = (unsigned char *)(arp + 1);
+ memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
+ arp_ptr += np->dev->addr_len;
+ memcpy(arp_ptr, &tip, 4);
+ arp_ptr += 4;
+ memcpy(arp_ptr, sha, np->dev->addr_len);
+ arp_ptr += np->dev->addr_len;
+ memcpy(arp_ptr, &sip, 4);
+
+ netpoll_send_skb(np, send_skb);
+
+ /* If there are several rx_hooks for the same address,
+ we're fine by sending a single reply */
+ break;
}
-
- /*
- * Fill out the arp protocol part.
- *
- * we only support ethernet device type,
- * which (according to RFC 1390) should
- * always equal 1 (Ethernet).
- */
-
- arp->ar_hrd = htons(np->dev->type);
- arp->ar_pro = htons(ETH_P_IP);
- arp->ar_hln = np->dev->addr_len;
- arp->ar_pln = 4;
- arp->ar_op = htons(type);
-
- arp_ptr = (unsigned char *)(arp + 1);
- memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
- arp_ptr += np->dev->addr_len;
- memcpy(arp_ptr, &tip, 4);
- arp_ptr += 4;
- memcpy(arp_ptr, sha, np->dev->addr_len);
- arp_ptr += np->dev->addr_len;
- memcpy(arp_ptr, &sip, 4);
-
- netpoll_send_skb(np, send_skb);
-
- /* If there are several rx_hooks for the same address,
- we're fine by sending a single reply */
- break;
+ spin_unlock_irqrestore(&npinfo->rx_lock, flags);
}
- spin_unlock_irqrestore(&npinfo->rx_lock, flags);
}
int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
@@ -576,7 +585,7 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
/* check if netpoll clients need ARP */
if (skb->protocol == htons(ETH_P_ARP) &&
atomic_read(&trapped)) {
- skb_queue_tail(&npinfo->arp_tx, skb);
+ skb_queue_tail(&npinfo->neigh_tx, skb);
return 1;
}
@@ -587,60 +596,61 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
}
proto = ntohs(eth_hdr(skb)->h_proto);
- if (proto != ETH_P_IP)
+ if (proto != ETH_P_IP && proto != ETH_P_IPV6)
goto out;
if (skb->pkt_type == PACKET_OTHERHOST)
goto out;
if (skb_shared(skb))
goto out;
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
- goto out;
- iph = (struct iphdr *)skb->data;
- if (iph->ihl < 5 || iph->version != 4)
- goto out;
- if (!pskb_may_pull(skb, iph->ihl*4))
- goto out;
- iph = (struct iphdr *)skb->data;
- if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
- goto out;
-
- len = ntohs(iph->tot_len);
- if (skb->len < len || len < iph->ihl*4)
- goto out;
-
- /*
- * Our transport medium may have padded the buffer out.
- * Now We trim to the true length of the frame.
- */
- if (pskb_trim_rcsum(skb, len))
- goto out;
+ if (proto == ETH_P_IP) {
+ if (!pskb_may_pull(skb, sizeof(struct iphdr)))
+ goto out;
+ iph = (struct iphdr *)skb->data;
+ if (iph->ihl < 5 || iph->version != 4)
+ goto out;
+ if (!pskb_may_pull(skb, iph->ihl*4))
+ goto out;
+ iph = (struct iphdr *)skb->data;
+ if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
+ goto out;
- iph = (struct iphdr *)skb->data;
- if (iph->protocol != IPPROTO_UDP)
- goto out;
+ len = ntohs(iph->tot_len);
+ if (skb->len < len || len < iph->ihl*4)
+ goto out;
- len -= iph->ihl*4;
- uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
- ulen = ntohs(uh->len);
+ /*
+ * Our transport medium may have padded the buffer out.
+ * Now We trim to the true length of the frame.
+ */
+ if (pskb_trim_rcsum(skb, len))
+ goto out;
- if (ulen != len)
- goto out;
- if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
- goto out;
+ iph = (struct iphdr *)skb->data;
+ if (iph->protocol != IPPROTO_UDP)
+ goto out;
- list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
- if (np->local_ip && np->local_ip != iph->daddr)
- continue;
- if (np->remote_ip && np->remote_ip != iph->saddr)
- continue;
- if (np->local_port && np->local_port != ntohs(uh->dest))
- continue;
+ len -= iph->ihl*4;
+ uh = (struct udphdr *)(((char *)iph) + iph->ihl*4);
+ ulen = ntohs(uh->len);
- np->rx_hook(np, ntohs(uh->source),
- (char *)(uh+1),
- ulen - sizeof(struct udphdr));
- hits++;
+ if (ulen != len)
+ goto out;
+ if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
+ goto out;
+ list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+ if (np->local_ip.ip && np->local_ip.ip != iph->daddr)
+ continue;
+ if (np->remote_ip.ip && np->remote_ip.ip != iph->saddr)
+ continue;
+ if (np->local_port && np->local_port != ntohs(uh->dest))
+ continue;
+
+ np->rx_hook(np, ntohs(uh->source),
+ (char *)(uh+1),
+ ulen - sizeof(struct udphdr));
+ hits++;
+ }
}
if (!hits)
@@ -661,17 +671,40 @@ out:
void netpoll_print_options(struct netpoll *np)
{
np_info(np, "local port %d\n", np->local_port);
- np_info(np, "local IP %pI4\n", &np->local_ip);
+ if (!np->ipv6)
+ np_info(np, "local IPv4 address %pI4\n", &np->local_ip.ip);
np_info(np, "interface '%s'\n", np->dev_name);
np_info(np, "remote port %d\n", np->remote_port);
- np_info(np, "remote IP %pI4\n", &np->remote_ip);
+ if (!np->ipv6)
+ np_info(np, "remote IPv4 address %pI4\n", &np->remote_ip.ip);
np_info(np, "remote ethernet address %pM\n", np->remote_mac);
}
EXPORT_SYMBOL(netpoll_print_options);
+static int netpoll_parse_ip_addr(const char *str, union inet_addr *addr)
+{
+ const char *end;
+
+ if (!strchr(str, ':') &&
+ in4_pton(str, -1, (void *)addr, -1, &end) > 0) {
+ if (!*end)
+ return 0;
+ }
+ if (in6_pton(str, -1, addr->in6.s6_addr, -1, &end) > 0) {
+#if IS_ENABLED(CONFIG_IPV6)
+ if (!*end)
+ return 1;
+#else
+ return -1;
+#endif
+ }
+ return -1;
+}
+
int netpoll_parse_options(struct netpoll *np, char *opt)
{
char *cur=opt, *delim;
+ int ipv6;
if (*cur != '@') {
if ((delim = strchr(cur, '@')) == NULL)
@@ -687,7 +720,11 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
if ((delim = strchr(cur, '/')) == NULL)
goto parse_failed;
*delim = 0;
- np->local_ip = in_aton(cur);
+ ipv6 = netpoll_parse_ip_addr(cur, &np->local_ip);
+ if (ipv6 < 0)
+ goto parse_failed;
+ else
+ np->ipv6 = (bool)ipv6;
cur = delim;
}
cur++;
@@ -719,7 +756,13 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
if ((delim = strchr(cur, '/')) == NULL)
goto parse_failed;
*delim = 0;
- np->remote_ip = in_aton(cur);
+ ipv6 = netpoll_parse_ip_addr(cur, &np->remote_ip);
+ if (ipv6 < 0)
+ goto parse_failed;
+ else if (np->ipv6 != (bool)ipv6)
+ goto parse_failed;
+ else
+ np->ipv6 = (bool)ipv6;
cur = delim + 1;
if (*cur != 0) {
@@ -767,7 +810,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
INIT_LIST_HEAD(&npinfo->rx_np);
spin_lock_init(&npinfo->rx_lock);
- skb_queue_head_init(&npinfo->arp_tx);
+ skb_queue_head_init(&npinfo->neigh_tx);
skb_queue_head_init(&npinfo->txq);
INIT_DELAYED_WORK(&npinfo->tx_work, queue_process);
@@ -859,21 +902,24 @@ int netpoll_setup(struct netpoll *np)
}
}
- if (!np->local_ip) {
- rcu_read_lock();
- in_dev = __in_dev_get_rcu(ndev);
+ if (!np->local_ip.ip) {
+ if (!np->ipv6) {
+ rcu_read_lock();
+ in_dev = __in_dev_get_rcu(ndev);
- if (!in_dev || !in_dev->ifa_list) {
+
+ if (!in_dev || !in_dev->ifa_list) {
+ rcu_read_unlock();
+ np_err(np, "no IP address for %s, aborting\n",
+ np->dev_name);
+ err = -EDESTADDRREQ;
+ goto put;
+ }
+
+ np->local_ip.ip = in_dev->ifa_list->ifa_local;
rcu_read_unlock();
- np_err(np, "no IP address for %s, aborting\n",
- np->dev_name);
- err = -EDESTADDRREQ;
- goto put;
+ np_info(np, "local IP %pI4\n", &np->local_ip.ip);
}
-
- np->local_ip = in_dev->ifa_list->ifa_local;
- rcu_read_unlock();
- np_info(np, "local IP %pI4\n", &np->local_ip);
}
/* fill up the skb queue */
@@ -906,7 +952,7 @@ static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
struct netpoll_info *npinfo =
container_of(rcu_head, struct netpoll_info, rcu);
- skb_queue_purge(&npinfo->arp_tx);
+ skb_queue_purge(&npinfo->neigh_tx);
skb_queue_purge(&npinfo->txq);
/* we can't call cancel_delayed_work_sync here, as we are in softirq */
--
1.7.7.6
^ permalink raw reply related
* [PATCH net-next v4 2/3] netpoll: add IPv6 support
From: Cong Wang @ 2013-01-07 7:17 UTC (permalink / raw)
To: netdev; +Cc: David S. Miller, Cong Wang
In-Reply-To: <1357543036-15492-1-git-send-email-amwang@redhat.com>
From: Cong Wang <amwang@redhat.com>
Currently, netpoll only supports IPv4. This patch adds IPv6
support to netpoll so that we can run netconsole over IPv6 network.
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
drivers/net/netconsole.c | 46 ++++++++-
include/net/udp.h | 34 +++++++
net/core/netpoll.c | 239 ++++++++++++++++++++++++++++++++++++++++++++--
net/ipv6/udp.c | 34 -------
4 files changed, 303 insertions(+), 50 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 998fa02..62f494b 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -269,13 +269,17 @@ static ssize_t show_remote_port(struct netconsole_target *nt, char *buf)
static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
{
- if (!nt->np.ipv6)
+ if (nt->np.ipv6)
+ return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6);
+ else
return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
}
static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
{
- if (!nt->np.ipv6)
+ if (nt->np.ipv6)
+ return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6);
+ else
return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
}
@@ -412,8 +416,23 @@ static ssize_t store_local_ip(struct netconsole_target *nt,
return -EINVAL;
}
- if (!strnchr(buf, count, ':'))
- nt->np.local_ip.ip = in_aton(buf);
+ if (strnchr(buf, count, ':')) {
+ const char *end;
+ if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) {
+ if (*end && *end != '\n') {
+ printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end);
+ return -EINVAL;
+ }
+ nt->np.ipv6 = true;
+ } else
+ return -EINVAL;
+ } else {
+ if (!nt->np.ipv6) {
+ nt->np.local_ip.ip = in_aton(buf);
+ nt->np.ipv6 = false;
+ } else
+ return -EINVAL;
+ }
return strnlen(buf, count);
}
@@ -429,8 +448,23 @@ static ssize_t store_remote_ip(struct netconsole_target *nt,
return -EINVAL;
}
- if (!strnchr(buf, count, ':'))
- nt->np.remote_ip.ip = in_aton(buf);
+ if (strnchr(buf, count, ':')) {
+ const char *end;
+ if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) {
+ if (*end && *end != '\n') {
+ printk(KERN_ERR "netconsole: invalid IPv6 address at: <%c>\n", *end);
+ return -EINVAL;
+ }
+ nt->np.ipv6 = true;
+ } else
+ return -EINVAL;
+ } else {
+ if (!nt->np.ipv6) {
+ nt->np.remote_ip.ip = in_aton(buf);
+ nt->np.ipv6 = false;
+ } else
+ return -EINVAL;
+ }
return strnlen(buf, count);
}
diff --git a/include/net/udp.h b/include/net/udp.h
index 065f379..73e712a 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -156,6 +156,40 @@ static inline __wsum udp_csum(struct sk_buff *skb)
return csum;
}
+#include <net/udplite.h>
+static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto)
+{
+ int err;
+
+ UDP_SKB_CB(skb)->partial_cov = 0;
+ UDP_SKB_CB(skb)->cscov = skb->len;
+
+ if (proto == IPPROTO_UDPLITE) {
+ err = udplite_checksum_init(skb, uh);
+ if (err)
+ return err;
+ }
+
+ if (uh->check == 0) {
+ /* RFC 2460 section 8.1 says that we SHOULD log
+ this error. Well, it is reasonable.
+ */
+ LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n");
+ return 1;
+ }
+ if (skb->ip_summed == CHECKSUM_COMPLETE &&
+ !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
+ skb->len, proto, skb->csum))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ if (!skb_csum_unnecessary(skb))
+ skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
+ &ipv6_hdr(skb)->daddr,
+ skb->len, proto, 0));
+
+ return 0;
+}
+
/* hash routines shared between UDPv4/6 and UDP-Litev4/6 */
static inline void udp_lib_hash(struct sock *sk)
{
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 6bd0736..cd9c121 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -29,6 +29,8 @@
#include <linux/if_vlan.h>
#include <net/tcp.h>
#include <net/udp.h>
+#include <net/addrconf.h>
+#include <net/ndisc.h>
#include <asm/unaligned.h>
#include <trace/events/napi.h>
@@ -384,9 +386,12 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
struct iphdr *iph;
struct ethhdr *eth;
static atomic_t ip_ident;
+ struct ipv6hdr *ip6h;
udp_len = len + sizeof(*udph);
- if (!np->ipv6)
+ if (np->ipv6)
+ ip_len = udp_len + sizeof(*ip6h);
+ else
ip_len = udp_len + sizeof(*iph);
total_len = ip_len + LL_RESERVED_SPACE(np->dev);
@@ -406,7 +411,35 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
udph->dest = htons(np->remote_port);
udph->len = htons(udp_len);
- if (!np->ipv6) {
+ if (np->ipv6) {
+ udph->check = 0;
+ udph->check = csum_ipv6_magic(&np->local_ip.in6,
+ &np->remote_ip.in6,
+ udp_len, IPPROTO_UDP,
+ csum_partial(udph, udp_len, 0));
+ if (udph->check == 0)
+ udph->check = CSUM_MANGLED_0;
+
+ skb_push(skb, sizeof(*ip6h));
+ skb_reset_network_header(skb);
+ ip6h = ipv6_hdr(skb);
+
+ /* ip6h->version = 6; ip6h->priority = 0; */
+ put_unaligned(0x60, (unsigned char *)ip6h);
+ ip6h->flow_lbl[0] = 0;
+ ip6h->flow_lbl[1] = 0;
+ ip6h->flow_lbl[2] = 0;
+
+ ip6h->payload_len = htons(sizeof(struct udphdr) + len);
+ ip6h->nexthdr = IPPROTO_UDP;
+ ip6h->hop_limit = 32;
+ ip6h->saddr = np->local_ip.in6;
+ ip6h->daddr = np->remote_ip.in6;
+
+ eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
+ skb_reset_mac_header(skb);
+ skb->protocol = eth->h_proto = htons(ETH_P_IPV6);
+ } else {
udph->check = 0;
udph->check = csum_tcpudp_magic(np->local_ip.ip,
np->remote_ip.ip,
@@ -448,9 +481,7 @@ EXPORT_SYMBOL(netpoll_send_udp);
static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
{
- struct arphdr *arp;
- unsigned char *arp_ptr;
- int size, type = ARPOP_REPLY, ptype = ETH_P_ARP;
+ int size, type = ARPOP_REPLY;
__be32 sip, tip;
unsigned char *sha;
struct sk_buff *send_skb;
@@ -477,6 +508,8 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo
proto = ntohs(eth_hdr(skb)->h_proto);
if (proto == ETH_P_IP) {
+ struct arphdr *arp;
+ unsigned char *arp_ptr;
/* No arp on this interface */
if (skb->dev->flags & IFF_NOARP)
return;
@@ -528,7 +561,7 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo
send_skb->protocol = htons(ETH_P_ARP);
/* Fill the device header for the ARP frame */
- if (dev_hard_header(send_skb, skb->dev, ptype,
+ if (dev_hard_header(send_skb, skb->dev, ETH_P_ARP,
sha, np->dev->dev_addr,
send_skb->len) < 0) {
kfree_skb(send_skb);
@@ -565,9 +598,124 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo
break;
}
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+ } else if( proto == ETH_P_IPV6) {
+#if IS_ENABLED(CONFIG_IPV6)
+ struct nd_msg *msg;
+ u8 *lladdr = NULL;
+ struct ipv6hdr *hdr;
+ struct icmp6hdr *icmp6h;
+ const struct in6_addr *saddr;
+ const struct in6_addr *daddr;
+ struct inet6_dev *in6_dev = NULL;
+ struct in6_addr *target;
+
+ in6_dev = in6_dev_get(skb->dev);
+ if (!in6_dev || !in6_dev->cnf.accept_ra)
+ return;
+
+ if (!pskb_may_pull(skb, skb->len))
+ return;
+
+ msg = (struct nd_msg *)skb_transport_header(skb);
+
+ __skb_push(skb, skb->data - skb_transport_header(skb));
+
+ if (ipv6_hdr(skb)->hop_limit != 255)
+ return;
+ if (msg->icmph.icmp6_code != 0)
+ return;
+ if (msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
+ return;
+
+ saddr = &ipv6_hdr(skb)->saddr;
+ daddr = &ipv6_hdr(skb)->daddr;
+
+ size = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
+
+ spin_lock_irqsave(&npinfo->rx_lock, flags);
+ list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+ if (memcmp(daddr, &np->local_ip, sizeof(*daddr)))
+ continue;
+
+ hlen = LL_RESERVED_SPACE(np->dev);
+ tlen = np->dev->needed_tailroom;
+ send_skb = find_skb(np, size + hlen + tlen, hlen);
+ if (!send_skb)
+ continue;
+
+ send_skb->protocol = htons(ETH_P_IPV6);
+ send_skb->dev = skb->dev;
+
+ skb_reset_network_header(send_skb);
+ skb_put(send_skb, sizeof(struct ipv6hdr));
+ hdr = ipv6_hdr(send_skb);
+
+ *(__be32*)hdr = htonl(0x60000000);
+
+ hdr->payload_len = htons(size);
+ hdr->nexthdr = IPPROTO_ICMPV6;
+ hdr->hop_limit = 255;
+ hdr->saddr = *saddr;
+ hdr->daddr = *daddr;
+
+ send_skb->transport_header = send_skb->tail;
+ skb_put(send_skb, size);
+
+ icmp6h = (struct icmp6hdr *)skb_transport_header(skb);
+ icmp6h->icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
+ icmp6h->icmp6_router = 0;
+ icmp6h->icmp6_solicited = 1;
+ target = (struct in6_addr *)skb_transport_header(send_skb) + sizeof(struct icmp6hdr);
+ *target = msg->target;
+ icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, size,
+ IPPROTO_ICMPV6,
+ csum_partial(icmp6h,
+ size, 0));
+
+ if (dev_hard_header(send_skb, skb->dev, ETH_P_IPV6,
+ lladdr, np->dev->dev_addr,
+ send_skb->len) < 0) {
+ kfree_skb(send_skb);
+ continue;
+ }
+
+ netpoll_send_skb(np, send_skb);
+
+ /* If there are several rx_hooks for the same address,
+ we're fine by sending a single reply */
+ break;
+ }
+ spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+#endif
}
}
+static bool pkt_is_ns(struct sk_buff *skb)
+{
+ struct nd_msg *msg;
+ struct ipv6hdr *hdr;
+
+ if (skb->protocol != htons(ETH_P_ARP))
+ return false;
+ if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + sizeof(struct nd_msg)))
+ return false;
+
+ msg = (struct nd_msg *)skb_transport_header(skb);
+ __skb_push(skb, skb->data - skb_transport_header(skb));
+ hdr = ipv6_hdr(skb);
+
+ if (hdr->nexthdr != IPPROTO_ICMPV6)
+ return false;
+ if (hdr->hop_limit != 255)
+ return false;
+ if (msg->icmph.icmp6_code != 0)
+ return false;
+ if (msg->icmph.icmp6_type != NDISC_NEIGHBOUR_SOLICITATION)
+ return false;
+
+ return true;
+}
+
int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
{
int proto, len, ulen;
@@ -583,8 +731,10 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
goto out;
/* check if netpoll clients need ARP */
- if (skb->protocol == htons(ETH_P_ARP) &&
- atomic_read(&trapped)) {
+ if (skb->protocol == htons(ETH_P_ARP) && atomic_read(&trapped)) {
+ skb_queue_tail(&npinfo->neigh_tx, skb);
+ return 1;
+ } else if (pkt_is_ns(skb) && atomic_read(&trapped)) {
skb_queue_tail(&npinfo->neigh_tx, skb);
return 1;
}
@@ -651,6 +801,45 @@ int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
ulen - sizeof(struct udphdr));
hits++;
}
+ } else {
+#if IS_ENABLED(CONFIG_IPV6)
+ const struct ipv6hdr *ip6h;
+
+ if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+ goto out;
+ ip6h = (struct ipv6hdr *)skb->data;
+ if (ip6h->version != 6)
+ goto out;
+ len = ntohs(ip6h->payload_len);
+ if (!len)
+ goto out;
+ if (len + sizeof(struct ipv6hdr) > skb->len)
+ goto out;
+ if (pskb_trim_rcsum(skb, len + sizeof(struct ipv6hdr)))
+ goto out;
+ ip6h = ipv6_hdr(skb);
+ if (!pskb_may_pull(skb, sizeof(struct udphdr)))
+ goto out;
+ uh = udp_hdr(skb);
+ ulen = ntohs(uh->len);
+ if (ulen != skb->len)
+ goto out;
+ if (udp6_csum_init(skb, uh, IPPROTO_UDP))
+ goto out;
+ list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
+ if (memcmp(&np->local_ip.in6, &ip6h->daddr, sizeof(struct in6_addr)) != 0)
+ continue;
+ if (memcmp(&np->remote_ip.in6, &ip6h->saddr, sizeof(struct in6_addr)) != 0)
+ continue;
+ if (np->local_port && np->local_port != ntohs(uh->dest))
+ continue;
+
+ np->rx_hook(np, ntohs(uh->source),
+ (char *)(uh+1),
+ ulen - sizeof(struct udphdr));
+ hits++;
+ }
+#endif
}
if (!hits)
@@ -671,11 +860,15 @@ out:
void netpoll_print_options(struct netpoll *np)
{
np_info(np, "local port %d\n", np->local_port);
- if (!np->ipv6)
+ if (np->ipv6)
+ np_info(np, "local IPv6 address %pI6c\n", &np->local_ip.in6);
+ else
np_info(np, "local IPv4 address %pI4\n", &np->local_ip.ip);
np_info(np, "interface '%s'\n", np->dev_name);
np_info(np, "remote port %d\n", np->remote_port);
- if (!np->ipv6)
+ if (np->ipv6)
+ np_info(np, "remote IPv6 address %pI6c\n", &np->remote_ip.in6);
+ else
np_info(np, "remote IPv4 address %pI4\n", &np->remote_ip.ip);
np_info(np, "remote ethernet address %pM\n", np->remote_mac);
}
@@ -919,6 +1112,32 @@ int netpoll_setup(struct netpoll *np)
np->local_ip.ip = in_dev->ifa_list->ifa_local;
rcu_read_unlock();
np_info(np, "local IP %pI4\n", &np->local_ip.ip);
+ } else {
+ struct inet6_dev *idev;
+
+ err = -EDESTADDRREQ;
+ rcu_read_lock();
+ idev = __in6_dev_get(ndev);
+ if (idev) {
+ struct inet6_ifaddr *ifp;
+
+ read_lock_bh(&idev->lock);
+ list_for_each_entry(ifp, &idev->addr_list, if_list) {
+ if (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)
+ continue;
+ np->local_ip.in6 = ifp->addr;
+ err = 0;
+ break;
+ }
+ read_unlock_bh(&idev->lock);
+ }
+ rcu_read_unlock();
+ if (err) {
+ np_err(np, "no IPv6 address for %s, aborting\n",
+ np->dev_name);
+ goto put;
+ } else
+ np_info(np, "local IPv6 %pI6c\n", &np->local_ip.in6);
}
}
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index dfaa29b..1afb635 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -752,40 +752,6 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
return 0;
}
-static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh,
- int proto)
-{
- int err;
-
- UDP_SKB_CB(skb)->partial_cov = 0;
- UDP_SKB_CB(skb)->cscov = skb->len;
-
- if (proto == IPPROTO_UDPLITE) {
- err = udplite_checksum_init(skb, uh);
- if (err)
- return err;
- }
-
- if (uh->check == 0) {
- /* RFC 2460 section 8.1 says that we SHOULD log
- this error. Well, it is reasonable.
- */
- LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n");
- return 1;
- }
- if (skb->ip_summed == CHECKSUM_COMPLETE &&
- !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
- skb->len, proto, skb->csum))
- skb->ip_summed = CHECKSUM_UNNECESSARY;
-
- if (!skb_csum_unnecessary(skb))
- skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
- &ipv6_hdr(skb)->daddr,
- skb->len, proto, 0));
-
- return 0;
-}
-
int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
int proto)
{
--
1.7.7.6
^ permalink raw reply related
* [PATCH net-next v4 3/3] netconsole: add IPv6 example in doc
From: Cong Wang @ 2013-01-07 7:17 UTC (permalink / raw)
To: netdev; +Cc: David S. Miller, Cong Wang
In-Reply-To: <1357543036-15492-1-git-send-email-amwang@redhat.com>
From: Cong Wang <amwang@redhat.com>
Update the netconsole document as well.
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
---
Documentation/networking/netconsole.txt | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt
index 2e9e0ae2..a5d574a 100644
--- a/Documentation/networking/netconsole.txt
+++ b/Documentation/networking/netconsole.txt
@@ -1,9 +1,10 @@
started by Ingo Molnar <mingo@redhat.com>, 2001.09.17
2.6 port and netpoll api by Matt Mackall <mpm@selenic.com>, Sep 9 2003
+IPv6 support by Cong Wang <xiyou.wangcong@gmail.com>, Jan 1 2013
Please send bug reports to Matt Mackall <mpm@selenic.com>
-and Satyam Sharma <satyam.sharma@gmail.com>
+Satyam Sharma <satyam.sharma@gmail.com>, and Cong Wang <xiyou.wangcong@gmail.com>
Introduction:
=============
@@ -41,6 +42,10 @@ Examples:
insmod netconsole netconsole=@/,@10.0.0.2/
+ or using IPv6
+
+ insmod netconsole netconsole=@/,@fd00:1:2:3::1/
+
It also supports logging to multiple remote agents by specifying
parameters for the multiple agents separated by semicolons and the
complete string enclosed in "quotes", thusly:
--
1.7.7.6
^ permalink raw reply related
* [RFC PATCH v2 net-next 0/2] Remove NETIF_F_NETNS_LOCAL from software devices.
From: Rami Rosen @ 2013-01-07 7:19 UTC (permalink / raw)
To: davem; +Cc: netdev, shemminger, ebiederm, Rami Rosen
When NETIF_F_NETNS_LOCAL feature is set in some network device,
we do not allow this device to be moved from one network namespace
to another (see dev_change_net_namespace()). Vlan device is not considered
a local device and does not have the NETIF_F_NETNS_LOCAL feature. There is no
reason that software devices like ppp and bridge will set the
NETIF_F_NETNS_LOCAL feature. This patchset removes NETIF_F_NETNS_LOCAL
from ppp and bridge devices.
* Changes from v1
Do not remove NETIF_F_NETNS_LOCAL from vxlan devices. Moving vxlan device
to a different namesapce does not move the state of the UDP socket related
to this vxlan device (Following Stephen Hemminger comment).
Rami Rosen (2):
[RFC PATCH v2 net-next 1/3] ppp: remove NETIF_F_NETNS_LOCAL from ppp
device features.
[RFC PATCH v2 net-next 2/3] bridge: remove NETIF_F_NETNS_LOCAL from
bridge device features.
drivers/net/ppp/ppp_generic.c | 1 -
net/bridge/br_device.c | 2 +-
2 files changed, 1 insertion(+), 2 deletions(-)
--
1.7.11.7
^ permalink raw reply
* [RFC PATCH v2 net-next 1/2] ppp: remove NETIF_F_NETNS_LOCAL from ppp device features.
From: Rami Rosen @ 2013-01-07 7:19 UTC (permalink / raw)
To: davem; +Cc: netdev, shemminger, ebiederm, Rami Rosen
In-Reply-To: <1357543176-15352-1-git-send-email-ramirose@gmail.com>
There is no need for NETIF_F_NETNS_LOCAL for ppp device; this patch removes it.
Signed-off-by: Rami Rosen <ramirose@gmail.com>
---
drivers/net/ppp/ppp_generic.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index 0b2706a..89b6fc5 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -1073,7 +1073,6 @@ static void ppp_setup(struct net_device *dev)
dev->tx_queue_len = 3;
dev->type = ARPHRD_PPP;
dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
- dev->features |= NETIF_F_NETNS_LOCAL;
dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
}
--
1.7.11.7
^ permalink raw reply related
* [RFC PATCH v2 net-next 2/2] bridge: remove NETIF_F_NETNS_LOCAL from bridge device features.
From: Rami Rosen @ 2013-01-07 7:19 UTC (permalink / raw)
To: davem; +Cc: netdev, shemminger, ebiederm, Rami Rosen
In-Reply-To: <1357543176-15352-1-git-send-email-ramirose@gmail.com>
There is no need for NETIF_F_NETNS_LOCAL for bridge device; this patch removes it.
Signed-off-by: Rami Rosen <ramirose@gmail.com>
---
net/bridge/br_device.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index e1bc090..0f88d21 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -344,7 +344,7 @@ void br_dev_setup(struct net_device *dev)
dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
NETIF_F_GSO_MASK | NETIF_F_HW_CSUM | NETIF_F_LLTX |
- NETIF_F_NETNS_LOCAL | NETIF_F_HW_VLAN_TX;
+ NETIF_F_HW_VLAN_TX;
dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
NETIF_F_GSO_MASK | NETIF_F_HW_CSUM |
NETIF_F_HW_VLAN_TX;
--
1.7.11.7
^ permalink raw reply related
* Re: [PATCH V2 2/2] virtio-net: reset virtqueue affinity when doing cpu hotplug
From: Jason Wang @ 2013-01-07 7:28 UTC (permalink / raw)
To: Wanlong Gao
Cc: Michael S. Tsirkin, netdev, linux-kernel, virtualization,
Eric Dumazet
In-Reply-To: <1357542900-15557-2-git-send-email-gaowanlong@cn.fujitsu.com>
On 01/07/2013 03:15 PM, Wanlong Gao wrote:
> Add a cpu notifier to virtio-net, so that we can reset the
> virtqueue affinity if the cpu hotplug happens. It improve
> the performance through enabling or disabling the virtqueue
> affinity after doing cpu hotplug.
> Adding the notifier block to virtnet_info is suggested by
> Jason, thank you.
>
> Cc: Rusty Russell <rusty@rustcorp.com.au>
> Cc: "Michael S. Tsirkin" <mst@redhat.com>
> Cc: Jason Wang <jasowang@redhat.com>
> Cc: Eric Dumazet <erdnetdev@gmail.com>
> Cc: virtualization@lists.linux-foundation.org
> Cc: netdev@vger.kernel.org
> Signed-off-by: Wanlong Gao <gaowanlong@cn.fujitsu.com>
> ---
> drivers/net/virtio_net.c | 30 ++++++++++++++++++++++++++++++
> 1 file changed, 30 insertions(+)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index b483fb5..9547b4c 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -26,6 +26,7 @@
> #include <linux/scatterlist.h>
> #include <linux/if_vlan.h>
> #include <linux/slab.h>
> +#include <linux/cpu.h>
>
> static int napi_weight = 128;
> module_param(napi_weight, int, 0444);
> @@ -123,6 +124,9 @@ struct virtnet_info {
>
> /* Does the affinity hint is set for virtqueues? */
> bool affinity_hint_set;
> +
> + /* CPU hot plug notifier */
> + struct notifier_block nb;
> };
>
> struct skb_vnet_hdr {
> @@ -1051,6 +1055,23 @@ static void virtnet_set_affinity(struct virtnet_info *vi, bool set)
> }
> }
>
> +static int virtnet_cpu_callback(struct notifier_block *nfb,
> + unsigned long action, void *hcpu)
> +{
> + struct virtnet_info *vi = container_of(nfb, struct virtnet_info, nb);
> + switch(action) {
> + case CPU_ONLINE:
> + case CPU_ONLINE_FROZEN:
> + case CPU_DEAD:
> + case CPU_DEAD_FROZEN:
> + virtnet_set_affinity(vi, true);
> + break;
> + default:
> + break;
> + }
> + return NOTIFY_OK;
> +}
> +
I think you'd better fix the .ndo_select_queue() as well (as Michael
said in your V1) since it currently uses smp processor id which may not
work very well in this case also.
Thanks
> static void virtnet_get_ringparam(struct net_device *dev,
> struct ethtool_ringparam *ring)
> {
> @@ -1509,6 +1530,13 @@ static int virtnet_probe(struct virtio_device *vdev)
> }
> }
>
> + vi->nb.notifier_call = &virtnet_cpu_callback;
> + err = register_hotcpu_notifier(&vi->nb);
> + if (err) {
> + pr_debug("virtio_net: registering cpu notifier failed\n");
> + goto free_recv_bufs;
> + }
> +
> /* Assume link up if device can't report link status,
> otherwise get link status from config. */
> if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
> @@ -1553,6 +1581,8 @@ static void virtnet_remove(struct virtio_device *vdev)
> {
> struct virtnet_info *vi = vdev->priv;
>
> + unregister_hotcpu_notifier(&vi->nb);
> +
> /* Prevent config work handler from accessing the device. */
> mutex_lock(&vi->config_lock);
> vi->config_enable = false;
^ permalink raw reply
* Re: [PATCH 1/2] usbnet: allow status interrupt URB to always be active
From: Oliver Neukum @ 2013-01-07 7:40 UTC (permalink / raw)
To: Bjørn Mork
Cc: Dan Williams, Elina Pasheva, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-usb-u79uwXL29TY76Z2rM5mHXA, Rory Filer, Phil Sutter
In-Reply-To: <87y5g7nbej.fsf-lbf33ChDnrE/G1V5fR+Y7Q@public.gmane.org>
On Saturday 05 January 2013 11:59:16 Bjørn Mork wrote:
Hi,
> You can still use a trick similar to what qmi_wwan and cdc_mbim does to
> take over the status endpoint from usbnet: By not implementing .status,
> and possibly setting dev->status to NULL in .bind, you are free to
> handle the status endpoint entirely inside the minidriver. Not sure if
> that is smart though. You would have to reimplement init_status and
> intr_complete from usbnet, and kill or resubmit the interrupt urb on
> suspend/resume/disconnect yourself.
Please no. We don't look for ways to circumvent frameworks. We alter
frameworks to act as we need them to act.
> The new usbnet flag is probably a better solution.
Indeed.
> FWIW, I agree with Oliver that always submitting the interrupt URB is
> both risky and will cause too much unnecessary USB activity for most
> usbnet devices.
Good.
Regards
Oliver
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFC PATCH] vsprintf: Add %p*D extension for 80211 SSIDs
From: Johannes Berg @ 2013-01-07 7:47 UTC (permalink / raw)
To: Joe Perches
Cc: John W. Linville, Chen Gang, stas.yakovlev, linux-wireless,
netdev
In-Reply-To: <1357534195.21481.31.camel@joe-AO722>
On Sun, 2013-01-06 at 20:49 -0800, Joe Perches wrote:
> On Sun, 2013-01-06 at 19:19 -0800, Joe Perches wrote:
> > Maybe these days this should be another vsprintf %p extension
> > like %pM when the DECLARE_MAC_BUF/print_mac uses were converted.
> >
> > (or maybe extend %ph for ssids with %*phs, length, array)
>
> Maybe like this:
> + * - 'D' For a 80211 SSID, it prints the SSID escaping any non-printable
> + characters with a leading \ and octal or [0nrt\]
Honestly, I'm not sure it's worth it. print_ssid() is used in two or
three legacy drivers only, not in any modern driver, and is unlikely to
be used in the more modern drivers due to tracing etc.
johannes
^ permalink raw reply
* Re: [PATCH V2 2/2] virtio-net: reset virtqueue affinity when doing cpu hotplug
From: Wanlong Gao @ 2013-01-07 7:48 UTC (permalink / raw)
To: Jason Wang
Cc: Michael S. Tsirkin, netdev, linux-kernel, virtualization,
Eric Dumazet
In-Reply-To: <50EA792F.1010408@redhat.com>
On 01/07/2013 03:28 PM, Jason Wang wrote:
> On 01/07/2013 03:15 PM, Wanlong Gao wrote:
>> Add a cpu notifier to virtio-net, so that we can reset the
>> virtqueue affinity if the cpu hotplug happens. It improve
>> the performance through enabling or disabling the virtqueue
>> affinity after doing cpu hotplug.
>> Adding the notifier block to virtnet_info is suggested by
>> Jason, thank you.
>>
>> Cc: Rusty Russell <rusty@rustcorp.com.au>
>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>> Cc: Jason Wang <jasowang@redhat.com>
>> Cc: Eric Dumazet <erdnetdev@gmail.com>
>> Cc: virtualization@lists.linux-foundation.org
>> Cc: netdev@vger.kernel.org
>> Signed-off-by: Wanlong Gao <gaowanlong@cn.fujitsu.com>
>> ---
>> drivers/net/virtio_net.c | 30 ++++++++++++++++++++++++++++++
>> 1 file changed, 30 insertions(+)
>>
>> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
>> index b483fb5..9547b4c 100644
>> --- a/drivers/net/virtio_net.c
>> +++ b/drivers/net/virtio_net.c
>> @@ -26,6 +26,7 @@
>> #include <linux/scatterlist.h>
>> #include <linux/if_vlan.h>
>> #include <linux/slab.h>
>> +#include <linux/cpu.h>
>>
>> static int napi_weight = 128;
>> module_param(napi_weight, int, 0444);
>> @@ -123,6 +124,9 @@ struct virtnet_info {
>>
>> /* Does the affinity hint is set for virtqueues? */
>> bool affinity_hint_set;
>> +
>> + /* CPU hot plug notifier */
>> + struct notifier_block nb;
>> };
>>
>> struct skb_vnet_hdr {
>> @@ -1051,6 +1055,23 @@ static void virtnet_set_affinity(struct virtnet_info *vi, bool set)
>> }
>> }
>>
>> +static int virtnet_cpu_callback(struct notifier_block *nfb,
>> + unsigned long action, void *hcpu)
>> +{
>> + struct virtnet_info *vi = container_of(nfb, struct virtnet_info, nb);
>> + switch(action) {
>> + case CPU_ONLINE:
>> + case CPU_ONLINE_FROZEN:
>> + case CPU_DEAD:
>> + case CPU_DEAD_FROZEN:
>> + virtnet_set_affinity(vi, true);
>> + break;
>> + default:
>> + break;
>> + }
>> + return NOTIFY_OK;
>> +}
>> +
>
> I think you'd better fix the .ndo_select_queue() as well (as Michael
> said in your V1) since it currently uses smp processor id which may not
> work very well in this case also.
The bug is we can't get the right txq if the CPU IDs are not consecutive,
right? Do you have any good idea about fixing this?
Thanks,
Wanlong Gao
>
> Thanks
>> static void virtnet_get_ringparam(struct net_device *dev,
>> struct ethtool_ringparam *ring)
>> {
>> @@ -1509,6 +1530,13 @@ static int virtnet_probe(struct virtio_device *vdev)
>> }
>> }
>>
>> + vi->nb.notifier_call = &virtnet_cpu_callback;
>> + err = register_hotcpu_notifier(&vi->nb);
>> + if (err) {
>> + pr_debug("virtio_net: registering cpu notifier failed\n");
>> + goto free_recv_bufs;
>> + }
>> +
>> /* Assume link up if device can't report link status,
>> otherwise get link status from config. */
>> if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
>> @@ -1553,6 +1581,8 @@ static void virtnet_remove(struct virtio_device *vdev)
>> {
>> struct virtnet_info *vi = vdev->priv;
>>
>> + unregister_hotcpu_notifier(&vi->nb);
>> +
>> /* Prevent config work handler from accessing the device. */
>> mutex_lock(&vi->config_lock);
>> vi->config_enable = false;
>
>
^ permalink raw reply
* Re: [PATCH V2 2/2] virtio-net: reset virtqueue affinity when doing cpu hotplug
From: Jason Wang @ 2013-01-07 7:55 UTC (permalink / raw)
To: gaowanlong
Cc: Michael S. Tsirkin, netdev, linux-kernel, virtualization,
Eric Dumazet
In-Reply-To: <50EA7DC0.20605@cn.fujitsu.com>
On 01/07/2013 03:48 PM, Wanlong Gao wrote:
> On 01/07/2013 03:28 PM, Jason Wang wrote:
>> On 01/07/2013 03:15 PM, Wanlong Gao wrote:
>>> Add a cpu notifier to virtio-net, so that we can reset the
>>> virtqueue affinity if the cpu hotplug happens. It improve
>>> the performance through enabling or disabling the virtqueue
>>> affinity after doing cpu hotplug.
>>> Adding the notifier block to virtnet_info is suggested by
>>> Jason, thank you.
>>>
>>> Cc: Rusty Russell <rusty@rustcorp.com.au>
>>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>>> Cc: Jason Wang <jasowang@redhat.com>
>>> Cc: Eric Dumazet <erdnetdev@gmail.com>
>>> Cc: virtualization@lists.linux-foundation.org
>>> Cc: netdev@vger.kernel.org
>>> Signed-off-by: Wanlong Gao <gaowanlong@cn.fujitsu.com>
>>> ---
>>> drivers/net/virtio_net.c | 30 ++++++++++++++++++++++++++++++
>>> 1 file changed, 30 insertions(+)
>>>
>>> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
>>> index b483fb5..9547b4c 100644
>>> --- a/drivers/net/virtio_net.c
>>> +++ b/drivers/net/virtio_net.c
>>> @@ -26,6 +26,7 @@
>>> #include <linux/scatterlist.h>
>>> #include <linux/if_vlan.h>
>>> #include <linux/slab.h>
>>> +#include <linux/cpu.h>
>>>
>>> static int napi_weight = 128;
>>> module_param(napi_weight, int, 0444);
>>> @@ -123,6 +124,9 @@ struct virtnet_info {
>>>
>>> /* Does the affinity hint is set for virtqueues? */
>>> bool affinity_hint_set;
>>> +
>>> + /* CPU hot plug notifier */
>>> + struct notifier_block nb;
>>> };
>>>
>>> struct skb_vnet_hdr {
>>> @@ -1051,6 +1055,23 @@ static void virtnet_set_affinity(struct virtnet_info *vi, bool set)
>>> }
>>> }
>>>
>>> +static int virtnet_cpu_callback(struct notifier_block *nfb,
>>> + unsigned long action, void *hcpu)
>>> +{
>>> + struct virtnet_info *vi = container_of(nfb, struct virtnet_info, nb);
>>> + switch(action) {
>>> + case CPU_ONLINE:
>>> + case CPU_ONLINE_FROZEN:
>>> + case CPU_DEAD:
>>> + case CPU_DEAD_FROZEN:
>>> + virtnet_set_affinity(vi, true);
>>> + break;
>>> + default:
>>> + break;
>>> + }
>>> + return NOTIFY_OK;
>>> +}
>>> +
>> I think you'd better fix the .ndo_select_queue() as well (as Michael
>> said in your V1) since it currently uses smp processor id which may not
>> work very well in this case also.
> The bug is we can't get the right txq if the CPU IDs are not consecutive,
> right? Do you have any good idea about fixing this?
>
> Thanks,
> Wanlong Gao
The point is make the virtqueue private to a specific cpu when the
number of queue pairs is equal to the number of cpus. So after you bind
the vq affinity to a specific cpu, you'd better use the reverse mapping
of this affinity to do .ndo_select_queue(). One possible idea, as
Michael suggested, is a per-cpu structure to record the preferable
virtqueue and do both .ndo_select_queue() and affinity hint setting
based on this.
>
>> Thanks
>>> static void virtnet_get_ringparam(struct net_device *dev,
>>> struct ethtool_ringparam *ring)
>>> {
>>> @@ -1509,6 +1530,13 @@ static int virtnet_probe(struct virtio_device *vdev)
>>> }
>>> }
>>>
>>> + vi->nb.notifier_call = &virtnet_cpu_callback;
>>> + err = register_hotcpu_notifier(&vi->nb);
>>> + if (err) {
>>> + pr_debug("virtio_net: registering cpu notifier failed\n");
>>> + goto free_recv_bufs;
>>> + }
>>> +
>>> /* Assume link up if device can't report link status,
>>> otherwise get link status from config. */
>>> if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
>>> @@ -1553,6 +1581,8 @@ static void virtnet_remove(struct virtio_device *vdev)
>>> {
>>> struct virtnet_info *vi = vdev->priv;
>>>
>>> + unregister_hotcpu_notifier(&vi->nb);
>>> +
>>> /* Prevent config work handler from accessing the device. */
>>> mutex_lock(&vi->config_lock);
>>> vi->config_enable = false;
>>
^ permalink raw reply
* re: bnx2x: Prepare device and initialize VF database
From: Dan Carpenter @ 2013-01-07 8:18 UTC (permalink / raw)
To: ariele; +Cc: netdev
Hello Ariel Elior,
The patch b56e9670ffa4: "bnx2x: Prepare device and initialize VF
database" from Jan 1, 2013, leads to the following warning:
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c:1346
bnx2x_pretend_func()
warn: should this be '>= E1H_FUNC_MAX'
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
1342 int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val)
1343 {
1344 u32 pretend_reg;
1345
1346 if (CHIP_IS_E1H(bp) && pretend_func_val > E1H_FUNC_MAX)
1347 return -1;
1348
This is static checker test has too many false positives so I haven't
released it. Basically, every other place that uses E1H_FUNC_MAX
assumes we start counting from zero except this one. I don't know the
code enough to say if it's a problem or intended.
regards,
dan carpenter
^ permalink raw reply
* Re: [PATCH v2 1/1 net-next] net: fec: report correct hardware stamping info to ethtool
From: Sascha Hauer @ 2013-01-07 8:34 UTC (permalink / raw)
To: Frank Li; +Cc: lznuaa, shawn.guo, richardcochran, davem, linux-arm-kernel,
netdev
In-Reply-To: <1357525507-16148-1-git-send-email-Frank.Li@freescale.com>
On Mon, Jan 07, 2013 at 10:25:07AM +0800, Frank Li wrote:
> Report correct hardware stamping capability by ethtool interface.
> The v1.0 ptp4l check it.
>
> Signed-off-by: Frank Li <Frank.Li@freescale.com>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Sascha
> ---
> Change v1->v2
> 1. s/capibilty/capability/
> 2. apply Sascha's feedback
> avoid return the return value of ethtool_op_get_ts_info()
> when bufdesc_ex == 1
>
> drivers/net/ethernet/freescale/fec.c | 31 ++++++++++++++++++++++++++++++-
> 1 files changed, 30 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c
> index a379319..1c117e5 100644
> --- a/drivers/net/ethernet/freescale/fec.c
> +++ b/drivers/net/ethernet/freescale/fec.c
> @@ -1173,12 +1173,41 @@ static void fec_enet_get_drvinfo(struct net_device *ndev,
> strcpy(info->bus_info, dev_name(&ndev->dev));
> }
>
> +static int fec_enet_get_ts_info(struct net_device *ndev,
> + struct ethtool_ts_info *info)
> +{
> + struct fec_enet_private *fep = netdev_priv(ndev);
> +
> + if (fep->bufdesc_ex) {
> +
> + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
> + SOF_TIMESTAMPING_RX_SOFTWARE |
> + SOF_TIMESTAMPING_SOFTWARE |
> + SOF_TIMESTAMPING_TX_HARDWARE |
> + SOF_TIMESTAMPING_RX_HARDWARE |
> + SOF_TIMESTAMPING_RAW_HARDWARE;
> + if (fep->ptp_clock)
> + info->phc_index = ptp_clock_index(fep->ptp_clock);
> + else
> + info->phc_index = -1;
> +
> + info->tx_types = (1 << HWTSTAMP_TX_OFF) |
> + (1 << HWTSTAMP_TX_ON);
> +
> + info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
> + (1 << HWTSTAMP_FILTER_ALL);
> + return 0;
> + } else {
> + return ethtool_op_get_ts_info(ndev, info);
> + }
> +}
> +
> static const struct ethtool_ops fec_enet_ethtool_ops = {
> .get_settings = fec_enet_get_settings,
> .set_settings = fec_enet_set_settings,
> .get_drvinfo = fec_enet_get_drvinfo,
> .get_link = ethtool_op_get_link,
> - .get_ts_info = ethtool_op_get_ts_info,
> + .get_ts_info = fec_enet_get_ts_info,
> };
>
> static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
> --
> 1.7.1
>
>
>
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
^ permalink raw reply
* Re: [PATCH V2 2/2] virtio-net: reset virtqueue affinity when doing cpu hotplug
From: Wanlong Gao @ 2013-01-07 8:46 UTC (permalink / raw)
To: Jason Wang
Cc: Michael S. Tsirkin, netdev, linux-kernel, virtualization,
Eric Dumazet
In-Reply-To: <50EA7F5D.7050907@redhat.com>
On 01/07/2013 03:55 PM, Jason Wang wrote:
> On 01/07/2013 03:48 PM, Wanlong Gao wrote:
>> On 01/07/2013 03:28 PM, Jason Wang wrote:
>>> On 01/07/2013 03:15 PM, Wanlong Gao wrote:
>>>> Add a cpu notifier to virtio-net, so that we can reset the
>>>> virtqueue affinity if the cpu hotplug happens. It improve
>>>> the performance through enabling or disabling the virtqueue
>>>> affinity after doing cpu hotplug.
>>>> Adding the notifier block to virtnet_info is suggested by
>>>> Jason, thank you.
>>>>
>>>> Cc: Rusty Russell <rusty@rustcorp.com.au>
>>>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>>>> Cc: Jason Wang <jasowang@redhat.com>
>>>> Cc: Eric Dumazet <erdnetdev@gmail.com>
>>>> Cc: virtualization@lists.linux-foundation.org
>>>> Cc: netdev@vger.kernel.org
>>>> Signed-off-by: Wanlong Gao <gaowanlong@cn.fujitsu.com>
>>>> ---
>>>> drivers/net/virtio_net.c | 30 ++++++++++++++++++++++++++++++
>>>> 1 file changed, 30 insertions(+)
>>>>
>>>> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
>>>> index b483fb5..9547b4c 100644
>>>> --- a/drivers/net/virtio_net.c
>>>> +++ b/drivers/net/virtio_net.c
>>>> @@ -26,6 +26,7 @@
>>>> #include <linux/scatterlist.h>
>>>> #include <linux/if_vlan.h>
>>>> #include <linux/slab.h>
>>>> +#include <linux/cpu.h>
>>>>
>>>> static int napi_weight = 128;
>>>> module_param(napi_weight, int, 0444);
>>>> @@ -123,6 +124,9 @@ struct virtnet_info {
>>>>
>>>> /* Does the affinity hint is set for virtqueues? */
>>>> bool affinity_hint_set;
>>>> +
>>>> + /* CPU hot plug notifier */
>>>> + struct notifier_block nb;
>>>> };
>>>>
>>>> struct skb_vnet_hdr {
>>>> @@ -1051,6 +1055,23 @@ static void virtnet_set_affinity(struct virtnet_info *vi, bool set)
>>>> }
>>>> }
>>>>
>>>> +static int virtnet_cpu_callback(struct notifier_block *nfb,
>>>> + unsigned long action, void *hcpu)
>>>> +{
>>>> + struct virtnet_info *vi = container_of(nfb, struct virtnet_info, nb);
>>>> + switch(action) {
>>>> + case CPU_ONLINE:
>>>> + case CPU_ONLINE_FROZEN:
>>>> + case CPU_DEAD:
>>>> + case CPU_DEAD_FROZEN:
>>>> + virtnet_set_affinity(vi, true);
>>>> + break;
>>>> + default:
>>>> + break;
>>>> + }
>>>> + return NOTIFY_OK;
>>>> +}
>>>> +
>>> I think you'd better fix the .ndo_select_queue() as well (as Michael
>>> said in your V1) since it currently uses smp processor id which may not
>>> work very well in this case also.
>> The bug is we can't get the right txq if the CPU IDs are not consecutive,
>> right? Do you have any good idea about fixing this?
>>
>> Thanks,
>> Wanlong Gao
>
> The point is make the virtqueue private to a specific cpu when the
> number of queue pairs is equal to the number of cpus. So after you bind
> the vq affinity to a specific cpu, you'd better use the reverse mapping
> of this affinity to do .ndo_select_queue(). One possible idea, as
> Michael suggested, is a per-cpu structure to record the preferable
> virtqueue and do both .ndo_select_queue() and affinity hint setting
> based on this.
Yeah, I think I got it now, will address it in V3. thank you. ;)
Regards,
Wanlong Gao
>>
>>> Thanks
>>>> static void virtnet_get_ringparam(struct net_device *dev,
>>>> struct ethtool_ringparam *ring)
>>>> {
>>>> @@ -1509,6 +1530,13 @@ static int virtnet_probe(struct virtio_device *vdev)
>>>> }
>>>> }
>>>>
>>>> + vi->nb.notifier_call = &virtnet_cpu_callback;
>>>> + err = register_hotcpu_notifier(&vi->nb);
>>>> + if (err) {
>>>> + pr_debug("virtio_net: registering cpu notifier failed\n");
>>>> + goto free_recv_bufs;
>>>> + }
>>>> +
>>>> /* Assume link up if device can't report link status,
>>>> otherwise get link status from config. */
>>>> if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
>>>> @@ -1553,6 +1581,8 @@ static void virtnet_remove(struct virtio_device *vdev)
>>>> {
>>>> struct virtnet_info *vi = vdev->priv;
>>>>
>>>> + unregister_hotcpu_notifier(&vi->nb);
>>>> +
>>>> /* Prevent config work handler from accessing the device. */
>>>> mutex_lock(&vi->config_lock);
>>>> vi->config_enable = false;
>>>
>
>
^ permalink raw reply
* Re: [RFC PATCH v2 net-next 1/2] ppp: remove NETIF_F_NETNS_LOCAL from ppp device features.
From: Eric W. Biederman @ 2013-01-07 9:16 UTC (permalink / raw)
To: Rami Rosen; +Cc: davem, netdev, shemminger
In-Reply-To: <1357543176-15352-2-git-send-email-ramirose@gmail.com>
Rami Rosen <ramirose@gmail.com> writes:
> There is no need for NETIF_F_NETNS_LOCAL for ppp device; this patch
> removes it.
At least pppoe_rcv_core assumes that the ppp socket and the network
devices are all in the same network namespace. So it looks like
NETIF_F_NETNS_LOCAL is needed.
Eric
> Signed-off-by: Rami Rosen <ramirose@gmail.com>
> ---
> drivers/net/ppp/ppp_generic.c | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
> index 0b2706a..89b6fc5 100644
> --- a/drivers/net/ppp/ppp_generic.c
> +++ b/drivers/net/ppp/ppp_generic.c
> @@ -1073,7 +1073,6 @@ static void ppp_setup(struct net_device *dev)
> dev->tx_queue_len = 3;
> dev->type = ARPHRD_PPP;
> dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
> - dev->features |= NETIF_F_NETNS_LOCAL;
> dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
> }
^ permalink raw reply
* Re: [RFC PATCH v2 net-next 2/2] bridge: remove NETIF_F_NETNS_LOCAL from bridge device features.
From: Eric W. Biederman @ 2013-01-07 9:20 UTC (permalink / raw)
To: Rami Rosen; +Cc: davem, netdev, shemminger
In-Reply-To: <1357543176-15352-3-git-send-email-ramirose@gmail.com>
Rami Rosen <ramirose@gmail.com> writes:
> There is no need for NETIF_F_NETNS_LOCAL for bridge device; this patch
> removes it.
At the very least add_del_if assumes are network devices are in the same
network namespace as the bridge. So removing NETIF_F_NETNS_LOCAL is not
safe.
Eric
^ permalink raw reply
* Re: [RFC PATCH v2 net-next 0/2] Remove NETIF_F_NETNS_LOCAL from software devices.
From: Eric W. Biederman @ 2013-01-07 9:25 UTC (permalink / raw)
To: Rami Rosen; +Cc: davem, netdev, shemminger
In-Reply-To: <1357543176-15352-1-git-send-email-ramirose@gmail.com>
Rami Rosen <ramirose@gmail.com> writes:
> When NETIF_F_NETNS_LOCAL feature is set in some network device,
> we do not allow this device to be moved from one network namespace
> to another (see dev_change_net_namespace()). Vlan device is not considered
> a local device and does not have the NETIF_F_NETNS_LOCAL feature. There is no
> reason that software devices like ppp and bridge will set the
> NETIF_F_NETNS_LOCAL feature. This patchset removes NETIF_F_NETNS_LOCAL
> from ppp and bridge devices.
After you saw the case for vxlan I am disappointed you respun this
patchset without asking the question: Could other devices suffer
from the same class of problem.
It didn't take me more than a few minutes of looking to see that the
bridge and the ppp network device have the same class of issue as
vxlan.
> * Changes from v1
> Do not remove NETIF_F_NETNS_LOCAL from vxlan devices. Moving vxlan device
> to a different namesapce does not move the state of the UDP socket related
> to this vxlan device (Following Stephen Hemminger comment).
>
> Rami Rosen (2):
> [RFC PATCH v2 net-next 1/3] ppp: remove NETIF_F_NETNS_LOCAL from ppp
> device features.
> [RFC PATCH v2 net-next 2/3] bridge: remove NETIF_F_NETNS_LOCAL from
> bridge device features.
>
> drivers/net/ppp/ppp_generic.c | 1 -
> net/bridge/br_device.c | 2 +-
> 2 files changed, 1 insertion(+), 2 deletions(-)
^ permalink raw reply
* [PATCH repost] net,wireless: check against default_ethtool_ops
From: Stanislaw Gruszka @ 2013-01-07 9:55 UTC (permalink / raw)
To: netdev, David S. Miller
Cc: Eric Dumazet, Ben Greear, Bjørn Mork, linux-wireless,
Ben Hutchings
Since:
commit 2c60db037034d27f8c636403355d52872da92f81
Author: Eric Dumazet <edumazet@google.com>
Date: Sun Sep 16 09:17:26 2012 +0000
net: provide a default dev->ethtool_ops
wireless core does not correctly assign ethtool_ops. In order to fix
the problem, and avoid assigning ethtool_ops on each individual cfg80211
drivers, we check against default_ethool_ops pointer instead of NULL in
wireless core.
Signed-off-by: Stanislaw Gruszka <sgruszka@redhat.com>
Acked-by: Ben Hutchings <bhutchings@solarflare.com>
Cc: stable@vger.kernel.org # 3.7+
---
This should go directly through net tree since patch include core
net specific changes.
include/linux/netdevice.h | 2 ++
net/core/dev.c | 3 ++-
net/wireless/core.c | 2 +-
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index f8eda02..c98e1c3 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -60,6 +60,8 @@ struct wireless_dev;
#define SET_ETHTOOL_OPS(netdev,ops) \
( (netdev)->ethtool_ops = (ops) )
+extern const struct ethtool_ops default_ethtool_ops;
+
/* hardware address assignment types */
#define NET_ADDR_PERM 0 /* address is permanent (default) */
#define NET_ADDR_RANDOM 1 /* address is generated randomly */
diff --git a/net/core/dev.c b/net/core/dev.c
index c0946cb..4cd2168 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6008,7 +6008,8 @@ struct netdev_queue *dev_ingress_queue_create(struct net_device *dev)
return queue;
}
-static const struct ethtool_ops default_ethtool_ops;
+const struct ethtool_ops default_ethtool_ops;
+EXPORT_SYMBOL_GPL(default_ethtool_ops);
/**
* alloc_netdev_mqs - allocate network device
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 14d9904..90915d4 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -866,7 +866,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
/* allow mac80211 to determine the timeout */
wdev->ps_timeout = -1;
- if (!dev->ethtool_ops)
+ if (dev->ethtool_ops == &default_ethtool_ops)
dev->ethtool_ops = &cfg80211_ethtool_ops;
if ((wdev->iftype == NL80211_IFTYPE_STATION ||
--
1.7.1
^ permalink raw reply related
* Re: [PATCH repost] net,wireless: check against default_ethtool_ops
From: Jiri Pirko @ 2013-01-07 10:23 UTC (permalink / raw)
To: Stanislaw Gruszka
Cc: netdev-u79uwXL29TY76Z2rM5mHXA, David S. Miller, Eric Dumazet,
Ben Greear, Bjørn Mork,
linux-wireless-u79uwXL29TY76Z2rM5mHXA, Ben Hutchings
In-Reply-To: <20130107095548.GA6931-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Mon, Jan 07, 2013 at 10:55:49AM CET, sgruszka-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org wrote:
>Since:
>
>commit 2c60db037034d27f8c636403355d52872da92f81
>Author: Eric Dumazet <edumazet-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
>Date: Sun Sep 16 09:17:26 2012 +0000
>
> net: provide a default dev->ethtool_ops
>
>wireless core does not correctly assign ethtool_ops. In order to fix
>the problem, and avoid assigning ethtool_ops on each individual cfg80211
>drivers, we check against default_ethool_ops pointer instead of NULL in
>wireless core.
>
>Signed-off-by: Stanislaw Gruszka <sgruszka-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
>Acked-by: Ben Hutchings <bhutchings-s/n/eUQHGBpZroRs9YW3xA@public.gmane.org>
>Cc: stable-u79uwXL29TY76Z2rM5mHXA@public.gmane.org # 3.7+
>---
>This should go directly through net tree since patch include core
>net specific changes.
>
> include/linux/netdevice.h | 2 ++
> net/core/dev.c | 3 ++-
> net/wireless/core.c | 2 +-
> 3 files changed, 5 insertions(+), 2 deletions(-)
>
>diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
>index f8eda02..c98e1c3 100644
>--- a/include/linux/netdevice.h
>+++ b/include/linux/netdevice.h
>@@ -60,6 +60,8 @@ struct wireless_dev;
> #define SET_ETHTOOL_OPS(netdev,ops) \
> ( (netdev)->ethtool_ops = (ops) )
>
>+extern const struct ethtool_ops default_ethtool_ops;
>+
> /* hardware address assignment types */
> #define NET_ADDR_PERM 0 /* address is permanent (default) */
> #define NET_ADDR_RANDOM 1 /* address is generated randomly */
>diff --git a/net/core/dev.c b/net/core/dev.c
>index c0946cb..4cd2168 100644
>--- a/net/core/dev.c
>+++ b/net/core/dev.c
>@@ -6008,7 +6008,8 @@ struct netdev_queue *dev_ingress_queue_create(struct net_device *dev)
> return queue;
> }
>
>-static const struct ethtool_ops default_ethtool_ops;
>+const struct ethtool_ops default_ethtool_ops;
>+EXPORT_SYMBOL_GPL(default_ethtool_ops);
I think that default_ethtool_ops should stay static. Wouldn't it be
nicer to introduce a helper like:
bool dev_has_default_ethtool_ops(struct net_device *dev)
{
return dev->ethtool_ops == &default_ethtool_ops;
}
>
> /**
> * alloc_netdev_mqs - allocate network device
>diff --git a/net/wireless/core.c b/net/wireless/core.c
>index 14d9904..90915d4 100644
>--- a/net/wireless/core.c
>+++ b/net/wireless/core.c
>@@ -866,7 +866,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
> /* allow mac80211 to determine the timeout */
> wdev->ps_timeout = -1;
>
>- if (!dev->ethtool_ops)
>+ if (dev->ethtool_ops == &default_ethtool_ops)
> dev->ethtool_ops = &cfg80211_ethtool_ops;
>
> if ((wdev->iftype == NL80211_IFTYPE_STATION ||
>--
>1.7.1
>
>--
>To unsubscribe from this list: send the line "unsubscribe netdev" in
>the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 1/2] ipv6: avoid blackhole and prohibited entries upon prefix purge [v2]
From: Nicolas Dichtel @ 2013-01-07 10:25 UTC (permalink / raw)
To: Romain KUNTZ; +Cc: netdev@vger.kernel.org, Eric Dumazet, yoshfuji, davem
In-Reply-To: <2A507F9D-3D53-475F-8FA9-9E6CFEE9C97A@ipflavors.com>
Le 05/01/2013 22:44, Romain KUNTZ a écrit :
> Mobile IPv6 provokes a kernel Oops since commit 64c6d08e (ipv6:
> del unreachable route when an addr is deleted on lo), because
> ip6_route_lookup() may also return blackhole and prohibited
> entry. However, these entries have a NULL rt6i_table argument,
> which provokes an Oops in __ip6_del_rt() when trying to lock
> rt6i_table->tb6_lock.
>
> Beside, when purging a prefix, blakhole and prohibited entries
> should not be selected because they are not what we are looking
> for.
>
> We fix this by adding two new lookup flags (RT6_LOOKUP_F_NO_BLK_HOLE
> and RT6_LOOKUP_F_NO_PROHIBIT) in order to ensure that such entries
> are skipped during lookup and that the correct entry is returned.
>
> [v2]: use 'goto out;' instead of 'goto again;' to avoid unnecessary
> oprations on rt (as suggested by Eric Dumazet).
>
> Signed-off-by: Romain Kuntz <r.kuntz@ipflavors.com>
> ---
> include/net/ip6_route.h | 2 ++
> net/ipv6/addrconf.c | 4 +++-
> net/ipv6/fib6_rules.c | 4 ++++
> 3 files changed, 9 insertions(+), 1 deletions(-)
>
> diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
> index 27d8318..3c93743 100644
> --- a/include/net/ip6_route.h
> +++ b/include/net/ip6_route.h
> @@ -30,6 +30,8 @@ struct route_info {
> #define RT6_LOOKUP_F_SRCPREF_TMP 0x00000008
> #define RT6_LOOKUP_F_SRCPREF_PUBLIC 0x00000010
> #define RT6_LOOKUP_F_SRCPREF_COA 0x00000020
> +#define RT6_LOOKUP_F_NO_BLK_HOLE 0x00000040
> +#define RT6_LOOKUP_F_NO_PROHIBIT 0x00000080
>
> /*
> * rt6_srcprefs2flags() and rt6_flags2srcprefs() translate
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index 408cac4a..1891e23 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -948,7 +948,9 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
> fl6.flowi6_oif = ifp->idev->dev->ifindex;
> fl6.daddr = prefix;
> rt = (struct rt6_info *)ip6_route_lookup(net, &fl6,
> - RT6_LOOKUP_F_IFACE);
> + RT6_LOOKUP_F_IFACE |
> + RT6_LOOKUP_F_NO_BLK_HOLE |
> + RT6_LOOKUP_F_NO_PROHIBIT);
>
> if (rt != net->ipv6.ip6_null_entry &&
Is it not simpler to test the result here (net->ipv6.ip6_blk_hole_entry and
net->ipv6.ip6_prohibit_entry) like for the null_entry?
It will also avoid adding more flags.
^ permalink raw reply
* Re: [PATCH repost] net,wireless: check against default_ethtool_ops
From: Stanislaw Gruszka @ 2013-01-07 10:44 UTC (permalink / raw)
To: Jiri Pirko
Cc: netdev, David S. Miller, Eric Dumazet, Ben Greear,
Bjørn Mork, linux-wireless, Ben Hutchings
In-Reply-To: <20130107102307.GA1587@minipsycho.orion>
On Mon, Jan 07, 2013 at 11:23:07AM +0100, Jiri Pirko wrote:
> >-static const struct ethtool_ops default_ethtool_ops;
> >+const struct ethtool_ops default_ethtool_ops;
> >+EXPORT_SYMBOL_GPL(default_ethtool_ops);
>
> I think that default_ethtool_ops should stay static. Wouldn't it be
> nicer to introduce a helper like:
>
> bool dev_has_default_ethtool_ops(struct net_device *dev)
> {
> return dev->ethtool_ops == &default_ethtool_ops;
> }
Then I still have to export this function. So with your approch, number
of exported symbols will be the same, but there will be few more lines
of code.
Stanislaw
^ permalink raw reply
* [PATCH net-next] bnx2x: Segregate SR-IOV code
From: Ariel Elior @ 2013-01-07 10:50 UTC (permalink / raw)
To: David Miller
In this patch the SR-IOV code is segregated from the main bulk of
the bnx2x code. The CONFIG_BNX2X_SRIOV define is added to Broadcom's
Kconfig, and allows the elision of the building of all the SR-IOV
support code in the driver.
The define is dependant on the kernel CONFIG_PCI_IOV configuration
define.
Signed-off-by: Ariel Elior <ariele@broadcom.com>
---
drivers/net/ethernet/broadcom/Kconfig | 9 +
drivers/net/ethernet/broadcom/bnx2x/Makefile | 3 +-
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 20 +-
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 92 +---
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 18 +-
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 729 +--------------------
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 208 ++++++-
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h | 97 +++-
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c | 618 +++++++++++++++++-
drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h | 3 +
10 files changed, 953 insertions(+), 844 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index f552673..3b3bf0d 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -121,4 +121,13 @@ config BNX2X
To compile this driver as a module, choose M here: the module
will be called bnx2x. This is recommended.
+config BNX2X_SRIOV
+ bool "Broadcom 578xx and 57712 SR-IOV support"
+ depends on BNX2X && PCI_IOV
+ default y
+ ---help---
+ This configuration parameter enables Single Root Input Output
+ Virtualization support in the 578xx and 57712 products. This
+ allows for virtual function acceleration in virtual environments.
+
endif # NET_VENDOR_BROADCOM
diff --git a/drivers/net/ethernet/broadcom/bnx2x/Makefile b/drivers/net/ethernet/broadcom/bnx2x/Makefile
index 2ef6803..116762d 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/Makefile
+++ b/drivers/net/ethernet/broadcom/bnx2x/Makefile
@@ -4,4 +4,5 @@
obj-$(CONFIG_BNX2X) += bnx2x.o
-bnx2x-objs := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o bnx2x_dcb.o bnx2x_sp.o bnx2x_vfpf.o bnx2x_sriov.o
+bnx2x-y := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o bnx2x_dcb.o bnx2x_sp.o
+bnx2x-$(CONFIG_BNX2X_SRIOV) += bnx2x_vfpf.o bnx2x_sriov.o
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index 8596917..02c93e3 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -1266,6 +1266,7 @@ struct bnx2x {
(vn) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2 : 1))
#define BP_FW_MB_IDX(bp) BP_FW_MB_IDX_VN(bp, BP_VN(bp))
+#ifdef CONFIG_BNX2X_SRIOV
/* vf pf channel mailbox contains request and response buffers */
struct bnx2x_vf_mbx_msg *vf2pf_mbox;
dma_addr_t vf2pf_mbox_mapping;
@@ -1278,6 +1279,7 @@ struct bnx2x {
dma_addr_t pf2vf_bulletin_mapping;
struct pf_vf_bulletin_content old_bulletin;
+#endif /* CONFIG_BNX2X_SRIOV */
struct net_device *dev;
struct pci_dev *pdev;
@@ -1379,8 +1381,14 @@ struct bnx2x {
#define IS_VF_FLAG (1 << 22)
#define BP_NOMCP(bp) ((bp)->flags & NO_MCP_FLAG)
+
+#ifdef CONFIG_BNX2X_SRIOV
#define IS_VF(bp) ((bp)->flags & IS_VF_FLAG)
#define IS_PF(bp) (!((bp)->flags & IS_VF_FLAG))
+#else
+#define IS_VF(bp) false
+#define IS_PF(bp) true
+#endif
#define NO_ISCSI(bp) ((bp)->flags & NO_ISCSI_FLAG)
#define NO_ISCSI_OOO(bp) ((bp)->flags & NO_ISCSI_OOO_FLAG)
@@ -2275,18 +2283,6 @@ void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id,
#define GOOD_ME_REG(me_reg) (((me_reg) & ME_REG_VF_VALID) && \
(!((me_reg) & ME_REG_VF_ERR)))
-int bnx2x_get_vf_id(struct bnx2x *bp, u32 *vf_id);
-int bnx2x_send_msg2pf(struct bnx2x *bp, u8 *done, dma_addr_t msg_mapping);
-int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count);
-int bnx2x_vfpf_release(struct bnx2x *bp);
-int bnx2x_vfpf_init(struct bnx2x *bp);
-void bnx2x_vfpf_close_vf(struct bnx2x *bp);
-int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx);
-int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx);
-int bnx2x_vfpf_set_mac(struct bnx2x *bp);
-int bnx2x_vfpf_set_mcast(struct net_device *dev);
-int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp);
-
int bnx2x_nic_load_analyze_req(struct bnx2x *bp, u32 load_code);
/* Congestion management fairness mode */
#define CMNG_FNS_NONE 0
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index f9a15cb..1437f7e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -27,7 +27,6 @@
#include "bnx2x_cmn.h"
#include "bnx2x_init.h"
#include "bnx2x_sp.h"
-#include "bnx2x_sriov.h"
/**
* bnx2x_move_fp - move content of the fastpath structure.
@@ -109,7 +108,7 @@ void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len)
(bp->common.bc_ver & 0xff),
((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver);
} else {
- strlcpy(buf, bp->acquire_resp.pfdev_info.fw_ver, buf_len);
+ bnx2x_vf_fill_fw_str(bp, buf, buf_len);
}
}
@@ -2048,7 +2047,7 @@ static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp)
* request struct
*/
if (IS_SRIOV(bp))
- vf_headroom = bp->vfdb->sriov.nr_virtfn * BNX2X_CLIENTS_PER_VF;
+ vf_headroom = bnx2x_vf_headroom(bp);
/* Request is built from stats_query_header and an array of
* stats_query_cmd_group each of which contains
@@ -3793,93 +3792,6 @@ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc)
return 0;
}
-/* New mac for VF. Consider these cases:
- * 1. VF hasn't been acquired yet - save the mac in local bulletin board and
- * supply at acquire.
- * 2. VF has already been acquired but has not yet initialized - store in local
- * bulletin board. mac will be posted on VF bulletin board after VF init. VF
- * will configure this mac when it is ready.
- * 3. VF has already initialized but has not yet setup a queue - post the new
- * mac on VF's bulletin board right now. VF will configure this mac when it
- * is ready.
- * 4. VF has already set a queue - delete any macs already configured for this
- * queue and manually config the new mac.
- * In any event, once this function has been called refuse any attempts by the
- * VF to configure any mac for itself except for this mac. In case of a race
- * where the VF fails to see the new post on its bulletin board before sending a
- * mac configuration request, the PF will simply fail the request and VF can try
- * again after consulting its bulletin board
- */
-int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
-{
- struct bnx2x *bp = netdev_priv(dev);
- int rc, q_logical_state, vfidx = queue;
- struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
- struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
-
- /* if SRIOV is disabled there is nothing to do (and somewhere, someone
- * has erred).
- */
- if (!IS_SRIOV(bp)) {
- BNX2X_ERR("bnx2x_set_vf_mac called though sriov is disabled\n");
- return -EINVAL;
- }
-
- if (!is_valid_ether_addr(mac)) {
- BNX2X_ERR("mac address invalid\n");
- return -EINVAL;
- }
-
- /* update PF's copy of the VF's bulletin. will no longer accept mac
- * configuration requests from vf unless match this mac
- */
- bulletin->valid_bitmap |= 1 << MAC_ADDR_VALID;
- memcpy(bulletin->mac, mac, ETH_ALEN);
-
- /* Post update on VF's bulletin board */
- rc = bnx2x_post_vf_bulletin(bp, vfidx);
- if (rc) {
- BNX2X_ERR("failed to update VF[%d] bulletin\n", vfidx);
- return rc;
- }
-
- /* is vf initialized and queue set up? */
- q_logical_state =
- bnx2x_get_q_logical_state(bp, &bnx2x_vfq(vf, 0, sp_obj));
- if (vf->state == VF_ENABLED &&
- q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) {
- /* configure the mac in device on this vf's queue */
- unsigned long flags = 0;
- struct bnx2x_vlan_mac_obj *mac_obj = &bnx2x_vfq(vf, 0, mac_obj);
-
- /* must lock vfpf channel to protect against vf flows */
- bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
-
- /* remove existing eth macs */
- rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_ETH_MAC, true);
- if (rc) {
- BNX2X_ERR("failed to delete eth macs\n");
- return -EINVAL;
- }
-
- /* remove existing uc list macs */
- rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_UC_LIST_MAC, true);
- if (rc) {
- BNX2X_ERR("failed to delete uc_list macs\n");
- return -EINVAL;
- }
-
- /* configure the new mac to device */
- __set_bit(RAMROD_COMP_WAIT, &flags);
- bnx2x_set_mac_one(bp, (u8 *)&bulletin->mac, mac_obj, true,
- BNX2X_ETH_MAC, &flags);
-
- bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
- }
-
- return rc;
-}
-
/* called with rtnl_lock */
int bnx2x_change_mac_addr(struct net_device *dev, void *p)
{
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
index 23a1fa9..6667ec5 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
@@ -24,6 +24,7 @@
#include "bnx2x.h"
+#include "bnx2x_sriov.h"
/* This is used as a replacement for an MCP if it's not present */
extern int load_count[2][3]; /* per-path: 0-common, 1-port0, 2-port1 */
@@ -1128,22 +1129,7 @@ static inline u8 bnx2x_fp_qzone_id(struct bnx2x_fastpath *fp)
return fp->cl_id;
}
-static inline u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
-{
- struct bnx2x *bp = fp->bp;
- u32 offset = BAR_USTRORM_INTMEM;
-
- if (IS_VF(bp))
- return PXP_VF_ADDR_USDM_QUEUES_START +
- bp->acquire_resp.resc.hw_qid[fp->index] *
- sizeof(struct ustorm_queue_zone_data);
- else if (!CHIP_IS_E1x(bp))
- offset += USTORM_RX_PRODS_E2_OFFSET(fp->cl_qzone_id);
- else
- offset += USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), fp->cl_id);
-
- return offset;
-}
+u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp);
static inline void bnx2x_init_txdata(struct bnx2x *bp,
struct bnx2x_fp_txdata *txdata, u32 cid,
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 2b6a919..5fcaee1 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -60,7 +60,6 @@
#include "bnx2x_init_ops.h"
#include "bnx2x_cmn.h"
#include "bnx2x_vfpf.h"
-#include "bnx2x_sriov.h"
#include "bnx2x_dcb.h"
#include "bnx2x_sp.h"
@@ -5269,62 +5268,6 @@ void bnx2x_drv_pulse(struct bnx2x *bp)
bp->fw_drv_pulse_wr_seq);
}
-/* crc is the first field in the bulletin board. compute the crc over the
- * entire bulletin board excluding the crc field itself
- */
-u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
- struct pf_vf_bulletin_content *bulletin)
-{
- return crc32(BULLETIN_CRC_SEED,
- ((u8 *)bulletin) + sizeof(bulletin->crc),
- BULLETIN_CONTENT_SIZE - sizeof(bulletin->crc));
-}
-
-/* Check for new posts on the bulletin board */
-enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
-{
- struct pf_vf_bulletin_content bulletin = bp->pf2vf_bulletin->content;
- int attempts;
-
- /* bulletin board hasn't changed since last sample */
- if (bp->old_bulletin.version == bulletin.version)
- return PFVF_BULLETIN_UNCHANGED;
-
- /* validate crc of new bulletin board */
- if (bp->old_bulletin.version != bp->pf2vf_bulletin->content.version) {
- /* sampling structure in mid post may result with corrupted data
- * validate crc to ensure coherency.
- */
- for (attempts = 0; attempts < BULLETIN_ATTEMPTS; attempts++) {
- bulletin = bp->pf2vf_bulletin->content;
- if (bulletin.crc == bnx2x_crc_vf_bulletin(bp,
- &bulletin))
- break;
-
- BNX2X_ERR("bad crc on bulletin board. contained %x computed %x\n",
- bulletin.crc,
- bnx2x_crc_vf_bulletin(bp, &bulletin));
- }
- if (attempts >= BULLETIN_ATTEMPTS) {
- BNX2X_ERR("pf to vf bulletin board crc was wrong %d consecutive times. Aborting\n",
- attempts);
- return PFVF_BULLETIN_CRC_ERR;
- }
- }
-
- /* the mac address in bulletin board is valid and is new */
- if (bulletin.valid_bitmap & 1 << MAC_ADDR_VALID &&
- memcmp(bulletin.mac, bp->old_bulletin.mac, ETH_ALEN)) {
- /* update new mac to net device */
- memcpy(bp->dev->dev_addr, bulletin.mac, ETH_ALEN);
- }
-
- /* copy new bulletin board to bp */
- bp->old_bulletin = bulletin;
-
- return PFVF_BULLETIN_UPDATED;
-}
-
static void bnx2x_timer(unsigned long data)
{
struct bnx2x *bp = (struct bnx2x *) data;
@@ -9525,29 +9468,14 @@ sp_rtnl_not_reset:
/* work which needs rtnl lock not-taken (as it takes the lock itself and
* can be called from other contexts as well)
*/
-
rtnl_unlock();
+ /* enable SR-IOV if applicable */
if (IS_SRIOV(bp) && test_and_clear_bit(BNX2X_SP_RTNL_ENABLE_SRIOV,
- &bp->sp_rtnl_state)) {
- int rc = 0;
-
- /* disbale sriov in case it is still enabled */
- pci_disable_sriov(bp->pdev);
- DP(BNX2X_MSG_IOV, "sriov disabled\n");
-
- /* enable sriov */
- DP(BNX2X_MSG_IOV, "vf num (%d)\n", (bp->vfdb->sriov.nr_virtfn));
- rc = pci_enable_sriov(bp->pdev, (bp->vfdb->sriov.nr_virtfn));
- if (rc)
- BNX2X_ERR("pci_enable_sriov failed with %d\n", rc);
- else
- DP(BNX2X_MSG_IOV, "sriov enabled\n");
- }
+ &bp->sp_rtnl_state))
+ bnx2x_enable_sriov(bp);
}
-/* end of nic load/unload */
-
static void bnx2x_period_task(struct work_struct *work)
{
struct bnx2x *bp = container_of(work, struct bnx2x, period_task.work);
@@ -11790,7 +11718,9 @@ static const struct net_device_ops bnx2x_netdev_ops = {
.ndo_poll_controller = poll_bnx2x,
#endif
.ndo_setup_tc = bnx2x_setup_tc,
+#ifdef CONFIG_BNX2X_SRIOV
.ndo_set_vf_mac = bnx2x_set_vf_mac,
+#endif
#ifdef NETDEV_FCOE_WWNN
.ndo_fcoe_get_wwn = bnx2x_fcoe_get_wwn,
#endif
@@ -12445,17 +12375,10 @@ static int bnx2x_init_one(struct pci_dev *pdev,
* l2 connections.
*/
if (IS_VF(bp)) {
- /* vf doorbells are embedded within the regview */
- bp->doorbells = bp->regview + PXP_VF_ADDR_DB_START;
-
- /* allocate vf2pf mailbox for vf to pf channel */
- BNX2X_PCI_ALLOC(bp->vf2pf_mbox, &bp->vf2pf_mbox_mapping,
- sizeof(struct bnx2x_vf_mbx_msg));
-
- /* allocate pf 2 vf bulletin board */
- BNX2X_PCI_ALLOC(bp->pf2vf_bulletin, &bp->pf2vf_bulletin_mapping,
- sizeof(union pf_vf_bulletin));
-
+ bnx2x_vf_map_doorbells(bp);
+ rc = bnx2x_vf_pci_alloc(bp);
+ if (rc)
+ goto init_one_exit;
} else {
doorbell_size = BNX2X_L2_MAX_CID(bp) * (1 << BNX2X_DB_SHIFT);
if (doorbell_size > pci_resource_len(pdev, 2)) {
@@ -12552,11 +12475,6 @@ static int bnx2x_init_one(struct pci_dev *pdev,
return 0;
-alloc_mem_err:
- BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
- sizeof(struct bnx2x_vf_mbx_msg));
- rc = -ENOMEM;
-
init_one_exit:
if (bp->regview)
iounmap(bp->regview);
@@ -13419,619 +13337,36 @@ struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
return cp;
}
-int bnx2x_send_msg2pf(struct bnx2x *bp, u8 *done, dma_addr_t msg_mapping)
-{
- struct cstorm_vf_zone_data __iomem *zone_data =
- REG_ADDR(bp, PXP_VF_ADDR_CSDM_GLOBAL_START);
- int tout = 600, interval = 100; /* wait for 60 seconds */
-
- if (*done) {
- BNX2X_ERR("done was non zero before message to pf was sent\n");
- WARN_ON(true);
- return -EINVAL;
- }
-
- /* Write message address */
- writel(U64_LO(msg_mapping),
- &zone_data->non_trigger.vf_pf_channel.msg_addr_lo);
- writel(U64_HI(msg_mapping),
- &zone_data->non_trigger.vf_pf_channel.msg_addr_hi);
-
- /* make sure the address is written before FW accesses it */
- wmb();
-
- /* Trigger the PF FW */
- writeb(1, &zone_data->trigger.vf_pf_channel.addr_valid);
-
- /* Wait for PF to complete */
- while ((tout >= 0) && (!*done)) {
- msleep(interval);
- tout -= 1;
-
- /* progress indicator - HV can take its own sweet time in
- * answering VFs...
- */
- DP_CONT(BNX2X_MSG_IOV, ".");
- }
-
- if (!*done) {
- BNX2X_ERR("PF response has timed out\n");
- return -EAGAIN;
- }
- DP(BNX2X_MSG_SP, "Got a response from PF\n");
- return 0;
-}
-
-int bnx2x_get_vf_id(struct bnx2x *bp, u32 *vf_id)
-{
- u32 me_reg;
- int tout = 10, interval = 100; /* Wait for 1 sec */
-
- do {
- /* pxp traps vf read of doorbells and returns me reg value */
- me_reg = readl(bp->doorbells);
- if (GOOD_ME_REG(me_reg))
- break;
-
- msleep(interval);
-
- BNX2X_ERR("Invalid ME register value: 0x%08x\n. Is pf driver up?",
- me_reg);
- } while (tout-- > 0);
-
- if (!GOOD_ME_REG(me_reg)) {
- BNX2X_ERR("Invalid ME register value: 0x%08x\n", me_reg);
- return -EINVAL;
- }
-
- BNX2X_ERR("valid ME register value: 0x%08x\n", me_reg);
-
- *vf_id = (me_reg & ME_REG_VF_NUM_MASK) >> ME_REG_VF_NUM_SHIFT;
-
- return 0;
-}
-
-int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
-{
- int rc = 0, attempts = 0;
- struct vfpf_acquire_tlv *req = &bp->vf2pf_mbox->req.acquire;
- struct pfvf_acquire_resp_tlv *resp = &bp->vf2pf_mbox->resp.acquire_resp;
- u32 vf_id;
- bool resources_acquired = false;
-
- /* clear mailbox and prep first tlv */
- bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_ACQUIRE, sizeof(*req));
-
- if (bnx2x_get_vf_id(bp, &vf_id))
- return -EAGAIN;
-
- req->vfdev_info.vf_id = vf_id;
- req->vfdev_info.vf_os = 0;
-
- req->resc_request.num_rxqs = rx_count;
- req->resc_request.num_txqs = tx_count;
- req->resc_request.num_sbs = bp->igu_sb_cnt;
- req->resc_request.num_mac_filters = VF_ACQUIRE_MAC_FILTERS;
- req->resc_request.num_mc_filters = VF_ACQUIRE_MC_FILTERS;
-
- /* pf 2 vf bulletin board address */
- req->bulletin_addr = bp->pf2vf_bulletin_mapping;
-
- /* add list termination tlv */
- bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
- sizeof(struct channel_list_end_tlv));
-
- /* output tlvs list */
- bnx2x_dp_tlv_list(bp, req);
-
- while (!resources_acquired) {
- DP(BNX2X_MSG_SP, "attempting to acquire resources\n");
-
- /* send acquire request */
- rc = bnx2x_send_msg2pf(bp,
- &resp->hdr.status,
- bp->vf2pf_mbox_mapping);
-
- /* PF timeout */
- if (rc)
- return rc;
-
- /* copy acquire response from buffer to bp */
- memcpy(&bp->acquire_resp, resp, sizeof(bp->acquire_resp));
-
- attempts++;
-
- /* test whether the PF accepted our request. If not, humble the
- * the request and try again.
- */
- if (bp->acquire_resp.hdr.status == PFVF_STATUS_SUCCESS) {
- DP(BNX2X_MSG_SP, "resources acquired\n");
- resources_acquired = true;
- } else if (bp->acquire_resp.hdr.status ==
- PFVF_STATUS_NO_RESOURCE &&
- attempts < VF_ACQUIRE_THRESH) {
- DP(BNX2X_MSG_SP,
- "PF unwilling to fulfill resource request. Try PF recommended amount\n");
-
- /* humble our request */
- req->resc_request.num_txqs =
- bp->acquire_resp.resc.num_txqs;
- req->resc_request.num_rxqs =
- bp->acquire_resp.resc.num_rxqs;
- req->resc_request.num_sbs =
- bp->acquire_resp.resc.num_sbs;
- req->resc_request.num_mac_filters =
- bp->acquire_resp.resc.num_mac_filters;
- req->resc_request.num_vlan_filters =
- bp->acquire_resp.resc.num_vlan_filters;
- req->resc_request.num_mc_filters =
- bp->acquire_resp.resc.num_mc_filters;
-
- /* Clear response buffer */
- memset(&bp->vf2pf_mbox->resp, 0,
- sizeof(union pfvf_tlvs));
- } else {
- /* PF reports error */
- BNX2X_ERR("Failed to get the requested amount of resources: %d. Breaking...\n",
- bp->acquire_resp.hdr.status);
- return -EAGAIN;
- }
- }
-
- /* get HW info */
- bp->common.chip_id |= (bp->acquire_resp.pfdev_info.chip_num & 0xffff);
- bp->link_params.chip_id = bp->common.chip_id;
- bp->db_size = bp->acquire_resp.pfdev_info.db_size;
- bp->common.int_block = INT_BLOCK_IGU;
- bp->common.chip_port_mode = CHIP_2_PORT_MODE;
- bp->igu_dsb_id = -1;
- bp->mf_ov = 0;
- bp->mf_mode = 0;
- bp->common.flash_size = 0;
- bp->flags |=
- NO_WOL_FLAG | NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG | NO_FCOE_FLAG;
- bp->igu_sb_cnt = 1;
- bp->igu_base_sb = bp->acquire_resp.resc.hw_sbs[0].hw_sb_id;
- strlcpy(bp->fw_ver, bp->acquire_resp.pfdev_info.fw_ver,
- sizeof(bp->fw_ver));
-
- if (is_valid_ether_addr(bp->acquire_resp.resc.current_mac_addr))
- memcpy(bp->dev->dev_addr,
- bp->acquire_resp.resc.current_mac_addr,
- ETH_ALEN);
-
- return 0;
-}
-
-int bnx2x_vfpf_release(struct bnx2x *bp)
-{
- struct vfpf_release_tlv *req = &bp->vf2pf_mbox->req.release;
- struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
- u32 rc = 0, vf_id;
-
- /* clear mailbox and prep first tlv */
- bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_RELEASE, sizeof(*req));
-
- if (bnx2x_get_vf_id(bp, &vf_id))
- return -EAGAIN;
-
- req->vf_id = vf_id;
-
- /* add list termination tlv */
- bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
- sizeof(struct channel_list_end_tlv));
-
- /* output tlvs list */
- bnx2x_dp_tlv_list(bp, req);
-
- /* send release request */
- rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
-
- if (rc)
- /* PF timeout */
- return rc;
- if (resp->hdr.status == PFVF_STATUS_SUCCESS) {
- /* PF released us */
- DP(BNX2X_MSG_SP, "vf released\n");
- } else {
- /* PF reports error */
- BNX2X_ERR("PF failed our release request - are we out of sync? response status: %d\n",
- resp->hdr.status);
- return -EAGAIN;
- }
-
- return 0;
-}
-
-/* Tell PF about SB addresses */
-int bnx2x_vfpf_init(struct bnx2x *bp)
-{
- struct vfpf_init_tlv *req = &bp->vf2pf_mbox->req.init;
- struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
- int rc, i;
-
- /* clear mailbox and prep first tlv */
- bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_INIT, sizeof(*req));
-
- /* status blocks */
- for_each_eth_queue(bp, i)
- req->sb_addr[i] = (dma_addr_t)bnx2x_fp(bp, i,
- status_blk_mapping);
-
- /* statistics - requests only supports single queue for now */
- req->stats_addr = bp->fw_stats_data_mapping +
- offsetof(struct bnx2x_fw_stats_data, queue_stats);
-
- /* add list termination tlv */
- bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
- sizeof(struct channel_list_end_tlv));
-
- /* output tlvs list */
- bnx2x_dp_tlv_list(bp, req);
-
- rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
- if (rc)
- return rc;
-
- if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
- BNX2X_ERR("INIT VF failed: %d. Breaking...\n",
- resp->hdr.status);
- return -EAGAIN;
- }
-
- DP(BNX2X_MSG_SP, "INIT VF Succeeded\n");
- return 0;
-}
-
-/* CLOSE VF - opposite to INIT_VF */
-void bnx2x_vfpf_close_vf(struct bnx2x *bp)
-{
- struct vfpf_close_tlv *req = &bp->vf2pf_mbox->req.close;
- struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
- int i, rc;
- u32 vf_id;
-
- /* If we haven't got a valid VF id, there is no sense to
- * continue with sending messages
- */
- if (bnx2x_get_vf_id(bp, &vf_id))
- goto free_irq;
-
- /* Close the queues */
- for_each_queue(bp, i)
- bnx2x_vfpf_teardown_queue(bp, i);
-
- /* clear mailbox and prep first tlv */
- bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_CLOSE, sizeof(*req));
-
- req->vf_id = vf_id;
-
- /* add list termination tlv */
- bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
- sizeof(struct channel_list_end_tlv));
-
- /* output tlvs list */
- bnx2x_dp_tlv_list(bp, req);
-
- rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
-
- if (rc)
- BNX2X_ERR("Sending CLOSE failed. rc was: %d\n", rc);
-
- else if (resp->hdr.status != PFVF_STATUS_SUCCESS)
- BNX2X_ERR("Sending CLOSE failed: pf response was %d\n",
- resp->hdr.status);
-
-free_irq:
- /* Disable HW interrupts, NAPI */
- bnx2x_netif_stop(bp, 0);
- /* Delete all NAPI objects */
- bnx2x_del_all_napi(bp);
-
- /* Release IRQs */
- bnx2x_free_irq(bp);
-}
-
-/* ask the pf to open a queue for the vf */
-int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx)
-{
- struct vfpf_setup_q_tlv *req = &bp->vf2pf_mbox->req.setup_q;
- struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
- struct bnx2x_fastpath *fp = &bp->fp[fp_idx];
- u16 tpa_agg_size = 0, flags = 0;
- int rc;
-
- /* clear mailbox and prep first tlv */
- bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SETUP_Q, sizeof(*req));
-
- /* select tpa mode to request */
- if (!fp->disable_tpa) {
- flags |= VFPF_QUEUE_FLG_TPA;
- flags |= VFPF_QUEUE_FLG_TPA_IPV6;
- if (fp->mode == TPA_MODE_GRO)
- flags |= VFPF_QUEUE_FLG_TPA_GRO;
- tpa_agg_size = TPA_AGG_SIZE;
- }
-
- /* calculate queue flags */
- flags |= VFPF_QUEUE_FLG_STATS;
- flags |= VFPF_QUEUE_FLG_CACHE_ALIGN;
- flags |= IS_MF_SD(bp) ? VFPF_QUEUE_FLG_OV : 0;
- flags |= VFPF_QUEUE_FLG_VLAN;
- DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
-
- /* Common */
- req->vf_qid = fp_idx;
- req->param_valid = VFPF_RXQ_VALID | VFPF_TXQ_VALID;
-
- /* Rx */
- req->rxq.rcq_addr = fp->rx_comp_mapping;
- req->rxq.rcq_np_addr = fp->rx_comp_mapping + BCM_PAGE_SIZE;
- req->rxq.rxq_addr = fp->rx_desc_mapping;
- req->rxq.sge_addr = fp->rx_sge_mapping;
- req->rxq.vf_sb = fp_idx;
- req->rxq.sb_index = HC_INDEX_ETH_RX_CQ_CONS;
- req->rxq.hc_rate = bp->rx_ticks ? 1000000/bp->rx_ticks : 0;
- req->rxq.mtu = bp->dev->mtu;
- req->rxq.buf_sz = fp->rx_buf_size;
- req->rxq.sge_buf_sz = BCM_PAGE_SIZE * PAGES_PER_SGE;
- req->rxq.tpa_agg_sz = tpa_agg_size;
- req->rxq.max_sge_pkt = SGE_PAGE_ALIGN(bp->dev->mtu) >> SGE_PAGE_SHIFT;
- req->rxq.max_sge_pkt = ((req->rxq.max_sge_pkt + PAGES_PER_SGE - 1) &
- (~(PAGES_PER_SGE-1))) >> PAGES_PER_SGE_SHIFT;
- req->rxq.flags = flags;
- req->rxq.drop_flags = 0;
- req->rxq.cache_line_log = BNX2X_RX_ALIGN_SHIFT;
- req->rxq.stat_id = -1; /* No stats at the moment */
-
- /* Tx */
- req->txq.txq_addr = fp->txdata_ptr[FIRST_TX_COS_INDEX]->tx_desc_mapping;
- req->txq.vf_sb = fp_idx;
- req->txq.sb_index = HC_INDEX_ETH_TX_CQ_CONS_COS0;
- req->txq.hc_rate = bp->tx_ticks ? 1000000/bp->tx_ticks : 0;
- req->txq.flags = flags;
- req->txq.traffic_type = LLFC_TRAFFIC_TYPE_NW;
-
- /* add list termination tlv */
- bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
- sizeof(struct channel_list_end_tlv));
-
- /* output tlvs list */
- bnx2x_dp_tlv_list(bp, req);
-
- rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
- if (rc)
- BNX2X_ERR("Sending SETUP_Q message for queue[%d] failed!\n",
- fp_idx);
-
- if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
- BNX2X_ERR("Status of SETUP_Q for queue[%d] is %d\n",
- fp_idx, resp->hdr.status);
- return -EINVAL;
- }
- return rc;
-}
-
-int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx)
+u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp)
{
- struct vfpf_q_op_tlv *req = &bp->vf2pf_mbox->req.q_op;
- struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
- int rc;
-
- /* clear mailbox and prep first tlv */
- bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_TEARDOWN_Q,
- sizeof(*req));
-
- req->vf_qid = qidx;
-
- /* add list termination tlv */
- bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
- sizeof(struct channel_list_end_tlv));
-
- /* output tlvs list */
- bnx2x_dp_tlv_list(bp, req);
-
- rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
-
- if (rc) {
- BNX2X_ERR("Sending TEARDOWN for queue %d failed: %d\n", qidx,
- rc);
- return rc;
- }
-
- /* PF failed the transaction */
- if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
- BNX2X_ERR("TEARDOWN for queue %d failed: %d\n", qidx,
- resp->hdr.status);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* request pf to add a mac for the vf */
-int bnx2x_vfpf_set_mac(struct bnx2x *bp)
-{
- struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
- struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
- int rc;
-
- /* clear mailbox and prep first tlv */
- bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
- sizeof(*req));
-
- req->flags = VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED;
- req->vf_qid = 0;
- req->n_mac_vlan_filters = 1;
- req->filters[0].flags =
- VFPF_Q_FILTER_DEST_MAC_VALID | VFPF_Q_FILTER_SET_MAC;
-
- /* sample bulletin board for new mac */
- bnx2x_sample_bulletin(bp);
-
- /* copy mac from device to request */
- memcpy(req->filters[0].mac, bp->dev->dev_addr, ETH_ALEN);
-
- /* add list termination tlv */
- bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
- sizeof(struct channel_list_end_tlv));
-
- /* output tlvs list */
- bnx2x_dp_tlv_list(bp, req);
-
- /* send message to pf */
- rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
- if (rc) {
- BNX2X_ERR("failed to send message to pf. rc was %d\n", rc);
- return rc;
- }
-
- /* failure may mean PF was configured with a new mac for us */
- while (resp->hdr.status == PFVF_STATUS_FAILURE) {
- DP(BNX2X_MSG_IOV,
- "vfpf SET MAC failed. Check bulletin board for new posts\n");
-
- /* check if bulletin board was updated */
- if (bnx2x_sample_bulletin(bp) == PFVF_BULLETIN_UPDATED) {
- /* copy mac from device to request */
- memcpy(req->filters[0].mac, bp->dev->dev_addr,
- ETH_ALEN);
-
- /* send message to pf */
- rc = bnx2x_send_msg2pf(bp, &resp->hdr.status,
- bp->vf2pf_mbox_mapping);
- } else {
- /* no new info in bulletin */
- break;
- }
- }
+ struct bnx2x *bp = fp->bp;
+ u32 offset = BAR_USTRORM_INTMEM;
- if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
- BNX2X_ERR("vfpf SET MAC failed: %d\n", resp->hdr.status);
- return -EINVAL;
- }
+ if (IS_VF(bp))
+ return bnx2x_vf_ustorm_prods_offset(bp, fp);
+ else if (!CHIP_IS_E1x(bp))
+ offset += USTORM_RX_PRODS_E2_OFFSET(fp->cl_qzone_id);
+ else
+ offset += USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), fp->cl_id);
- return 0;
+ return offset;
}
-int bnx2x_vfpf_set_mcast(struct net_device *dev)
+/* called only on E1H or E2.
+ * When pretending to be PF, the pretend value is the function number 0...7
+ * When pretending to be VF, the pretend val is the PF-num:VF-valid:ABS-VFID
+ * combination
+ */
+int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val)
{
- struct bnx2x *bp = netdev_priv(dev);
- struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
- struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
- int rc, i = 0;
- struct netdev_hw_addr *ha;
+ u32 pretend_reg;
- if (bp->state != BNX2X_STATE_OPEN) {
- DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state);
- return -EINVAL;
- }
-
- /* clear mailbox and prep first tlv */
- bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
- sizeof(*req));
-
- /* Get Rx mode requested */
- DP(NETIF_MSG_IFUP, "dev->flags = %x\n", dev->flags);
-
- netdev_for_each_mc_addr(ha, dev) {
- DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n",
- bnx2x_mc_addr(ha));
- memcpy(req->multicast[i], bnx2x_mc_addr(ha), ETH_ALEN);
- i++;
- }
-
- /* We support four PFVF_MAX_MULTICAST_PER_VF mcast
- * addresses tops
- */
- if (i >= PFVF_MAX_MULTICAST_PER_VF) {
- DP(NETIF_MSG_IFUP,
- "VF supports not more than %d multicast MAC addresses\n",
- PFVF_MAX_MULTICAST_PER_VF);
- return -EINVAL;
- }
-
- req->n_multicast = i;
- req->flags |= VFPF_SET_Q_FILTERS_MULTICAST_CHANGED;
- req->vf_qid = 0;
-
- /* add list termination tlv */
- bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
- sizeof(struct channel_list_end_tlv));
-
- /* output tlvs list */
- bnx2x_dp_tlv_list(bp, req);
-
- rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
- if (rc) {
- BNX2X_ERR("Sending a message failed: %d\n", rc);
- return rc;
- }
-
- if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
- BNX2X_ERR("Set Rx mode/multicast failed: %d\n",
- resp->hdr.status);
- return -EINVAL;
- }
+ if (CHIP_IS_E1H(bp) && pretend_func_val > E1H_FUNC_MAX)
+ return -1;
+ /* get my own pretend register */
+ pretend_reg = bnx2x_get_pretend_reg(bp);
+ REG_WR(bp, pretend_reg, pretend_func_val);
+ REG_RD(bp, pretend_reg);
return 0;
}
-
-int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp)
-{
- int mode = bp->rx_mode;
- struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
- struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
- int rc;
-
- /* clear mailbox and prep first tlv */
- bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
- sizeof(*req));
-
- DP(NETIF_MSG_IFUP, "Rx mode is %d\n", mode);
-
- switch (mode) {
- case BNX2X_RX_MODE_NONE: /* no Rx */
- req->rx_mask = VFPF_RX_MASK_ACCEPT_NONE;
- break;
- case BNX2X_RX_MODE_NORMAL:
- req->rx_mask = VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST;
- req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST;
- req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
- break;
- case BNX2X_RX_MODE_ALLMULTI:
- req->rx_mask = VFPF_RX_MASK_ACCEPT_ALL_MULTICAST;
- req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST;
- req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
- break;
- case BNX2X_RX_MODE_PROMISC:
- req->rx_mask = VFPF_RX_MASK_ACCEPT_ALL_UNICAST;
- req->rx_mask |= VFPF_RX_MASK_ACCEPT_ALL_MULTICAST;
- req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
- break;
- default:
- BNX2X_ERR("BAD rx mode (%d)\n", mode);
- return -EINVAL;
- }
-
- req->flags |= VFPF_SET_Q_FILTERS_RX_MASK_CHANGED;
- req->vf_qid = 0;
-
- /* add list termination tlv */
- bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
- sizeof(struct channel_list_end_tlv));
-
- /* output tlvs list */
- bnx2x_dp_tlv_list(bp, req);
-
- rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
- if (rc)
- BNX2X_ERR("Sending a message failed: %d\n", rc);
-
- if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
- BNX2X_ERR("Set Rx mode failed: %d\n", resp->hdr.status);
- return -EINVAL;
- }
-
- return rc;
-}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
index 71fcef0..f2f5c8e 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
@@ -20,7 +20,7 @@
#include "bnx2x.h"
#include "bnx2x_init.h"
#include "bnx2x_cmn.h"
-#include "bnx2x_sriov.h"
+#include <linux/crc32.h>
/* General service functions */
static void storm_memset_vf_to_pf(struct bnx2x *bp, u16 abs_fid,
@@ -1334,25 +1334,6 @@ int bnx2x_vfop_qdown_cmd(struct bnx2x *bp,
* for calling pretend prior to calling these routines
*/
-/* called only on E1H or E2.
- * When pretending to be PF, the pretend value is the function number 0...7
- * When pretending to be VF, the pretend val is the PF-num:VF-valid:ABS-VFID
- * combination
- */
-int bnx2x_pretend_func(struct bnx2x *bp, u16 pretend_func_val)
-{
- u32 pretend_reg;
-
- if (CHIP_IS_E1H(bp) && pretend_func_val > E1H_FUNC_MAX)
- return -1;
-
- /* get my own pretend register */
- pretend_reg = bnx2x_get_pretend_reg(bp);
- REG_WR(bp, pretend_reg, pretend_func_val);
- REG_RD(bp, pretend_reg);
- return 0;
-}
-
/* internal vf enable - until vf is enabled internally all transactions
* are blocked. this routine should always be called last with pretend.
*/
@@ -1800,7 +1781,7 @@ static void bnx2x_vf_set_bars(struct bnx2x *bp, struct bnx2x_virtf *vf)
u64 start = pci_resource_start(dev, PCI_IOV_RESOURCES + i);
u32 size = pci_resource_len(dev, PCI_IOV_RESOURCES + i);
- do_div(size, iov->total);
+ size /= iov->total;
vf->bars[n].bar = start + size * vf->abs_vfid;
vf->bars[n].size = size;
}
@@ -3031,3 +3012,188 @@ void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf,
/* record the locking op */
vf->op_current = CHANNEL_TLV_NONE;
}
+
+void bnx2x_enable_sriov(struct bnx2x *bp)
+{
+ int rc = 0;
+
+ /* disbale sriov in case it is still enabled */
+ pci_disable_sriov(bp->pdev);
+ DP(BNX2X_MSG_IOV, "sriov disabled\n");
+
+ /* enable sriov */
+ DP(BNX2X_MSG_IOV, "vf num (%d)\n", (bp->vfdb->sriov.nr_virtfn));
+ rc = pci_enable_sriov(bp->pdev, (bp->vfdb->sriov.nr_virtfn));
+ if (rc)
+ BNX2X_ERR("pci_enable_sriov failed with %d\n", rc);
+ else
+ DP(BNX2X_MSG_IOV, "sriov enabled\n");
+}
+
+/* New mac for VF. Consider these cases:
+ * 1. VF hasn't been acquired yet - save the mac in local bulletin board and
+ * supply at acquire.
+ * 2. VF has already been acquired but has not yet initialized - store in local
+ * bulletin board. mac will be posted on VF bulletin board after VF init. VF
+ * will configure this mac when it is ready.
+ * 3. VF has already initialized but has not yet setup a queue - post the new
+ * mac on VF's bulletin board right now. VF will configure this mac when it
+ * is ready.
+ * 4. VF has already set a queue - delete any macs already configured for this
+ * queue and manually config the new mac.
+ * In any event, once this function has been called refuse any attempts by the
+ * VF to configure any mac for itself except for this mac. In case of a race
+ * where the VF fails to see the new post on its bulletin board before sending a
+ * mac configuration request, the PF will simply fail the request and VF can try
+ * again after consulting its bulletin board
+ */
+int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int rc, q_logical_state, vfidx = queue;
+ struct bnx2x_virtf *vf = BP_VF(bp, vfidx);
+ struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx);
+
+ /* if SRIOV is disabled there is nothing to do (and somewhere, someone
+ * has erred).
+ */
+ if (!IS_SRIOV(bp)) {
+ BNX2X_ERR("bnx2x_set_vf_mac called though sriov is disabled\n");
+ return -EINVAL;
+ }
+
+ if (!is_valid_ether_addr(mac)) {
+ BNX2X_ERR("mac address invalid\n");
+ return -EINVAL;
+ }
+
+ /* update PF's copy of the VF's bulletin. will no longer accept mac
+ * configuration requests from vf unless match this mac
+ */
+ bulletin->valid_bitmap |= 1 << MAC_ADDR_VALID;
+ memcpy(bulletin->mac, mac, ETH_ALEN);
+
+ /* Post update on VF's bulletin board */
+ rc = bnx2x_post_vf_bulletin(bp, vfidx);
+ if (rc) {
+ BNX2X_ERR("failed to update VF[%d] bulletin\n", vfidx);
+ return rc;
+ }
+
+ /* is vf initialized and queue set up? */
+ q_logical_state =
+ bnx2x_get_q_logical_state(bp, &bnx2x_vfq(vf, 0, sp_obj));
+ if (vf->state == VF_ENABLED &&
+ q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) {
+ /* configure the mac in device on this vf's queue */
+ unsigned long flags = 0;
+ struct bnx2x_vlan_mac_obj *mac_obj = &bnx2x_vfq(vf, 0, mac_obj);
+
+ /* must lock vfpf channel to protect against vf flows */
+ bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
+
+ /* remove existing eth macs */
+ rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_ETH_MAC, true);
+ if (rc) {
+ BNX2X_ERR("failed to delete eth macs\n");
+ return -EINVAL;
+ }
+
+ /* remove existing uc list macs */
+ rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_UC_LIST_MAC, true);
+ if (rc) {
+ BNX2X_ERR("failed to delete uc_list macs\n");
+ return -EINVAL;
+ }
+
+ /* configure the new mac to device */
+ __set_bit(RAMROD_COMP_WAIT, &flags);
+ bnx2x_set_mac_one(bp, (u8 *)&bulletin->mac, mac_obj, true,
+ BNX2X_ETH_MAC, &flags);
+
+ bnx2x_unlock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC);
+ }
+
+ return rc;
+}
+
+/* crc is the first field in the bulletin board. compute the crc over the
+ * entire bulletin board excluding the crc field itself
+ */
+u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
+ struct pf_vf_bulletin_content *bulletin)
+{
+ return crc32(BULLETIN_CRC_SEED,
+ ((u8 *)bulletin) + sizeof(bulletin->crc),
+ BULLETIN_CONTENT_SIZE - sizeof(bulletin->crc));
+}
+
+/* Check for new posts on the bulletin board */
+enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
+{
+ struct pf_vf_bulletin_content bulletin = bp->pf2vf_bulletin->content;
+ int attempts;
+
+ /* bulletin board hasn't changed since last sample */
+ if (bp->old_bulletin.version == bulletin.version)
+ return PFVF_BULLETIN_UNCHANGED;
+
+ /* validate crc of new bulletin board */
+ if (bp->old_bulletin.version != bp->pf2vf_bulletin->content.version) {
+ /* sampling structure in mid post may result with corrupted data
+ * validate crc to ensure coherency.
+ */
+ for (attempts = 0; attempts < BULLETIN_ATTEMPTS; attempts++) {
+ bulletin = bp->pf2vf_bulletin->content;
+ if (bulletin.crc == bnx2x_crc_vf_bulletin(bp,
+ &bulletin))
+ break;
+ BNX2X_ERR("bad crc on bulletin board. contained %x computed %x\n",
+ bulletin.crc,
+ bnx2x_crc_vf_bulletin(bp, &bulletin));
+ }
+ if (attempts >= BULLETIN_ATTEMPTS) {
+ BNX2X_ERR("pf to vf bulletin board crc was wrong %d consecutive times. Aborting\n",
+ attempts);
+ return PFVF_BULLETIN_CRC_ERR;
+ }
+ }
+
+ /* the mac address in bulletin board is valid and is new */
+ if (bulletin.valid_bitmap & 1 << MAC_ADDR_VALID &&
+ memcmp(bulletin.mac, bp->old_bulletin.mac, ETH_ALEN)) {
+ /* update new mac to net device */
+ memcpy(bp->dev->dev_addr, bulletin.mac, ETH_ALEN);
+ }
+
+ /* copy new bulletin board to bp */
+ bp->old_bulletin = bulletin;
+
+ return PFVF_BULLETIN_UPDATED;
+}
+
+void bnx2x_vf_map_doorbells(struct bnx2x *bp)
+{
+ /* vf doorbells are embedded within the regview */
+ bp->doorbells = bp->regview + PXP_VF_ADDR_DB_START;
+}
+
+int bnx2x_vf_pci_alloc(struct bnx2x *bp)
+{
+ /* allocate vf2pf mailbox for vf to pf channel */
+ BNX2X_PCI_ALLOC(bp->vf2pf_mbox, &bp->vf2pf_mbox_mapping,
+ sizeof(struct bnx2x_vf_mbx_msg));
+
+ /* allocate pf 2 vf bulletin board */
+ BNX2X_PCI_ALLOC(bp->pf2vf_bulletin, &bp->pf2vf_bulletin_mapping,
+ sizeof(union pf_vf_bulletin));
+
+ return 0;
+
+alloc_mem_err:
+ BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
+ sizeof(struct bnx2x_vf_mbx_msg));
+ BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping,
+ sizeof(union pf_vf_bulletin));
+ return -ENOMEM;
+}
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
index aab2a05..df4ae74 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h
@@ -20,7 +20,15 @@
#define BNX2X_SRIOV_H
#include "bnx2x_vfpf.h"
-#include "bnx2x_cmn.h"
+#include "bnx2x.h"
+
+enum sample_bulletin_result {
+ PFVF_BULLETIN_UNCHANGED,
+ PFVF_BULLETIN_UPDATED,
+ PFVF_BULLETIN_CRC_ERR
+};
+
+#ifdef CONFIG_BNX2X_SRIOV
/* The bnx2x device structure holds vfdb structure described below.
* The VF array is indexed by the relative vfid.
@@ -712,12 +720,89 @@ u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp,
struct pf_vf_bulletin_content *bulletin);
int bnx2x_post_vf_bulletin(struct bnx2x *bp, int vf);
-enum sample_bulletin_result {
- PFVF_BULLETIN_UNCHANGED,
- PFVF_BULLETIN_UPDATED,
- PFVF_BULLETIN_CRC_ERR
-};
enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
+/* VF side vfpf channel functions */
+int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count);
+int bnx2x_vfpf_release(struct bnx2x *bp);
+int bnx2x_vfpf_release(struct bnx2x *bp);
+int bnx2x_vfpf_init(struct bnx2x *bp);
+void bnx2x_vfpf_close_vf(struct bnx2x *bp);
+int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx);
+int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx);
+int bnx2x_vfpf_set_mac(struct bnx2x *bp);
+int bnx2x_vfpf_set_mcast(struct net_device *dev);
+int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp);
+
+static inline void bnx2x_vf_fill_fw_str(struct bnx2x *bp, char *buf,
+ size_t buf_len)
+{
+ strlcpy(buf, bp->acquire_resp.pfdev_info.fw_ver, buf_len);
+}
+
+static inline int bnx2x_vf_ustorm_prods_offset(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp)
+{
+ return PXP_VF_ADDR_USDM_QUEUES_START +
+ bp->acquire_resp.resc.hw_qid[fp->index] *
+ sizeof(struct ustorm_queue_zone_data);
+}
+
+enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp);
+void bnx2x_vf_map_doorbells(struct bnx2x *bp);
+int bnx2x_vf_pci_alloc(struct bnx2x *bp);
+void bnx2x_enable_sriov(struct bnx2x *bp);
+static inline int bnx2x_vf_headroom(struct bnx2x *bp)
+{
+ return bp->vfdb->sriov.nr_virtfn * BNX2X_CLIENTS_PER_VF;
+}
+
+#else /* CONFIG_BNX2X_SRIOV */
+
+static inline void bnx2x_iov_set_queue_sp_obj(struct bnx2x *bp, int vf_cid,
+ struct bnx2x_queue_sp_obj **q_obj) {}
+static inline void bnx2x_iov_sp_event(struct bnx2x *bp, int vf_cid,
+ bool queue_work) {}
+static inline void bnx2x_vf_handle_flr_event(struct bnx2x *bp) {}
+static inline int bnx2x_iov_eq_sp_event(struct bnx2x *bp,
+ union event_ring_elem *elem) {return 1; }
+static inline void bnx2x_iov_sp_task(struct bnx2x *bp) {}
+static inline void bnx2x_vf_mbx(struct bnx2x *bp,
+ struct vf_pf_event_data *vfpf_event) {}
+static inline int bnx2x_iov_init_ilt(struct bnx2x *bp, u16 line) {return line; }
+static inline void bnx2x_iov_init_dq(struct bnx2x *bp) {}
+static inline int bnx2x_iov_alloc_mem(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_iov_chip_cleanup(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_iov_init_dmae(struct bnx2x *bp) {}
+static inline int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param,
+ int num_vfs_param) {return 0; }
+static inline void bnx2x_iov_remove_one(struct bnx2x *bp) {}
+static inline void bnx2x_enable_sriov(struct bnx2x *bp) {}
+static inline int bnx2x_vfpf_acquire(struct bnx2x *bp,
+ u8 tx_count, u8 rx_count) {return 0; }
+static inline int bnx2x_vfpf_release(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vfpf_init(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_vfpf_close_vf(struct bnx2x *bp) {}
+static inline int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx) {return 0; }
+static inline int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx) {return 0; }
+static inline int bnx2x_vfpf_set_mac(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vfpf_set_mcast(struct net_device *dev) {return 0; }
+static inline int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_iov_nic_init(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vf_headroom(struct bnx2x *bp) {return 0; }
+static inline void bnx2x_iov_adjust_stats_req(struct bnx2x *bp) {}
+static inline void bnx2x_vf_fill_fw_str(struct bnx2x *bp, char *buf,
+ size_t buf_len) {}
+static inline int bnx2x_vf_ustorm_prods_offset(struct bnx2x *bp,
+ struct bnx2x_fastpath *fp) {return 0; }
+static inline enum sample_bulletin_result bnx2x_sample_bulletin(struct bnx2x *bp)
+{
+ return PFVF_BULLETIN_UNCHANGED;
+}
+
+static inline int bnx2x_vf_map_doorbells(struct bnx2x *bp) {return 0; }
+static inline int bnx2x_vf_pci_alloc(struct bnx2x *bp) {return 0; }
+
+#endif /* CONFIG_BNX2X_SRIOV */
#endif /* bnx2x_sriov.h */
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
index b410b9f..850aad3 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c
@@ -18,7 +18,7 @@
*/
#include "bnx2x.h"
-#include "bnx2x_sriov.h"
+#include "bnx2x_cmn.h"
#include <linux/crc32.h>
/* place a given tlv on the tlv buffer at a given offset */
@@ -98,6 +98,622 @@ static inline int bnx2x_pfvf_status_codes(int rc)
}
}
+int bnx2x_send_msg2pf(struct bnx2x *bp, u8 *done, dma_addr_t msg_mapping)
+{
+ struct cstorm_vf_zone_data __iomem *zone_data =
+ REG_ADDR(bp, PXP_VF_ADDR_CSDM_GLOBAL_START);
+ int tout = 600, interval = 100; /* wait for 60 seconds */
+
+ if (*done) {
+ BNX2X_ERR("done was non zero before message to pf was sent\n");
+ WARN_ON(true);
+ return -EINVAL;
+ }
+
+ /* Write message address */
+ writel(U64_LO(msg_mapping),
+ &zone_data->non_trigger.vf_pf_channel.msg_addr_lo);
+ writel(U64_HI(msg_mapping),
+ &zone_data->non_trigger.vf_pf_channel.msg_addr_hi);
+
+ /* make sure the address is written before FW accesses it */
+ wmb();
+
+ /* Trigger the PF FW */
+ writeb(1, &zone_data->trigger.vf_pf_channel.addr_valid);
+
+ /* Wait for PF to complete */
+ while ((tout >= 0) && (!*done)) {
+ msleep(interval);
+ tout -= 1;
+
+ /* progress indicator - HV can take its own sweet time in
+ * answering VFs...
+ */
+ DP_CONT(BNX2X_MSG_IOV, ".");
+ }
+
+ if (!*done) {
+ BNX2X_ERR("PF response has timed out\n");
+ return -EAGAIN;
+ }
+ DP(BNX2X_MSG_SP, "Got a response from PF\n");
+ return 0;
+}
+
+int bnx2x_get_vf_id(struct bnx2x *bp, u32 *vf_id)
+{
+ u32 me_reg;
+ int tout = 10, interval = 100; /* Wait for 1 sec */
+
+ do {
+ /* pxp traps vf read of doorbells and returns me reg value */
+ me_reg = readl(bp->doorbells);
+ if (GOOD_ME_REG(me_reg))
+ break;
+
+ msleep(interval);
+
+ BNX2X_ERR("Invalid ME register value: 0x%08x\n. Is pf driver up?",
+ me_reg);
+ } while (tout-- > 0);
+
+ if (!GOOD_ME_REG(me_reg)) {
+ BNX2X_ERR("Invalid ME register value: 0x%08x\n", me_reg);
+ return -EINVAL;
+ }
+
+ BNX2X_ERR("valid ME register value: 0x%08x\n", me_reg);
+
+ *vf_id = (me_reg & ME_REG_VF_NUM_MASK) >> ME_REG_VF_NUM_SHIFT;
+
+ return 0;
+}
+
+int bnx2x_vfpf_acquire(struct bnx2x *bp, u8 tx_count, u8 rx_count)
+{
+ int rc = 0, attempts = 0;
+ struct vfpf_acquire_tlv *req = &bp->vf2pf_mbox->req.acquire;
+ struct pfvf_acquire_resp_tlv *resp = &bp->vf2pf_mbox->resp.acquire_resp;
+ u32 vf_id;
+ bool resources_acquired = false;
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_ACQUIRE, sizeof(*req));
+
+ if (bnx2x_get_vf_id(bp, &vf_id))
+ return -EAGAIN;
+
+ req->vfdev_info.vf_id = vf_id;
+ req->vfdev_info.vf_os = 0;
+
+ req->resc_request.num_rxqs = rx_count;
+ req->resc_request.num_txqs = tx_count;
+ req->resc_request.num_sbs = bp->igu_sb_cnt;
+ req->resc_request.num_mac_filters = VF_ACQUIRE_MAC_FILTERS;
+ req->resc_request.num_mc_filters = VF_ACQUIRE_MC_FILTERS;
+
+ /* pf 2 vf bulletin board address */
+ req->bulletin_addr = bp->pf2vf_bulletin_mapping;
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ while (!resources_acquired) {
+ DP(BNX2X_MSG_SP, "attempting to acquire resources\n");
+
+ /* send acquire request */
+ rc = bnx2x_send_msg2pf(bp,
+ &resp->hdr.status,
+ bp->vf2pf_mbox_mapping);
+
+ /* PF timeout */
+ if (rc)
+ return rc;
+
+ /* copy acquire response from buffer to bp */
+ memcpy(&bp->acquire_resp, resp, sizeof(bp->acquire_resp));
+
+ attempts++;
+
+ /* test whether the PF accepted our request. If not, humble the
+ * the request and try again.
+ */
+ if (bp->acquire_resp.hdr.status == PFVF_STATUS_SUCCESS) {
+ DP(BNX2X_MSG_SP, "resources acquired\n");
+ resources_acquired = true;
+ } else if (bp->acquire_resp.hdr.status ==
+ PFVF_STATUS_NO_RESOURCE &&
+ attempts < VF_ACQUIRE_THRESH) {
+ DP(BNX2X_MSG_SP,
+ "PF unwilling to fulfill resource request. Try PF recommended amount\n");
+
+ /* humble our request */
+ req->resc_request.num_txqs =
+ bp->acquire_resp.resc.num_txqs;
+ req->resc_request.num_rxqs =
+ bp->acquire_resp.resc.num_rxqs;
+ req->resc_request.num_sbs =
+ bp->acquire_resp.resc.num_sbs;
+ req->resc_request.num_mac_filters =
+ bp->acquire_resp.resc.num_mac_filters;
+ req->resc_request.num_vlan_filters =
+ bp->acquire_resp.resc.num_vlan_filters;
+ req->resc_request.num_mc_filters =
+ bp->acquire_resp.resc.num_mc_filters;
+
+ /* Clear response buffer */
+ memset(&bp->vf2pf_mbox->resp, 0,
+ sizeof(union pfvf_tlvs));
+ } else {
+ /* PF reports error */
+ BNX2X_ERR("Failed to get the requested amount of resources: %d. Breaking...\n",
+ bp->acquire_resp.hdr.status);
+ return -EAGAIN;
+ }
+ }
+
+ /* get HW info */
+ bp->common.chip_id |= (bp->acquire_resp.pfdev_info.chip_num & 0xffff);
+ bp->link_params.chip_id = bp->common.chip_id;
+ bp->db_size = bp->acquire_resp.pfdev_info.db_size;
+ bp->common.int_block = INT_BLOCK_IGU;
+ bp->common.chip_port_mode = CHIP_2_PORT_MODE;
+ bp->igu_dsb_id = -1;
+ bp->mf_ov = 0;
+ bp->mf_mode = 0;
+ bp->common.flash_size = 0;
+ bp->flags |=
+ NO_WOL_FLAG | NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG | NO_FCOE_FLAG;
+ bp->igu_sb_cnt = 1;
+ bp->igu_base_sb = bp->acquire_resp.resc.hw_sbs[0].hw_sb_id;
+ strlcpy(bp->fw_ver, bp->acquire_resp.pfdev_info.fw_ver,
+ sizeof(bp->fw_ver));
+
+ if (is_valid_ether_addr(bp->acquire_resp.resc.current_mac_addr))
+ memcpy(bp->dev->dev_addr,
+ bp->acquire_resp.resc.current_mac_addr,
+ ETH_ALEN);
+
+ return 0;
+}
+
+int bnx2x_vfpf_release(struct bnx2x *bp)
+{
+ struct vfpf_release_tlv *req = &bp->vf2pf_mbox->req.release;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ u32 rc = 0, vf_id;
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_RELEASE, sizeof(*req));
+
+ if (bnx2x_get_vf_id(bp, &vf_id))
+ return -EAGAIN;
+
+ req->vf_id = vf_id;
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ /* send release request */
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+
+ if (rc)
+ /* PF timeout */
+ return rc;
+ if (resp->hdr.status == PFVF_STATUS_SUCCESS) {
+ /* PF released us */
+ DP(BNX2X_MSG_SP, "vf released\n");
+ } else {
+ /* PF reports error */
+ BNX2X_ERR("PF failed our release request - are we out of sync? response status: %d\n",
+ resp->hdr.status);
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+/* Tell PF about SB addresses */
+int bnx2x_vfpf_init(struct bnx2x *bp)
+{
+ struct vfpf_init_tlv *req = &bp->vf2pf_mbox->req.init;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ int rc, i;
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_INIT, sizeof(*req));
+
+ /* status blocks */
+ for_each_eth_queue(bp, i)
+ req->sb_addr[i] = (dma_addr_t)bnx2x_fp(bp, i,
+ status_blk_mapping);
+
+ /* statistics - requests only supports single queue for now */
+ req->stats_addr = bp->fw_stats_data_mapping +
+ offsetof(struct bnx2x_fw_stats_data, queue_stats);
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+ if (rc)
+ return rc;
+
+ if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+ BNX2X_ERR("INIT VF failed: %d. Breaking...\n",
+ resp->hdr.status);
+ return -EAGAIN;
+ }
+
+ DP(BNX2X_MSG_SP, "INIT VF Succeeded\n");
+ return 0;
+}
+
+/* CLOSE VF - opposite to INIT_VF */
+void bnx2x_vfpf_close_vf(struct bnx2x *bp)
+{
+ struct vfpf_close_tlv *req = &bp->vf2pf_mbox->req.close;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ int i, rc;
+ u32 vf_id;
+
+ /* If we haven't got a valid VF id, there is no sense to
+ * continue with sending messages
+ */
+ if (bnx2x_get_vf_id(bp, &vf_id))
+ goto free_irq;
+
+ /* Close the queues */
+ for_each_queue(bp, i)
+ bnx2x_vfpf_teardown_queue(bp, i);
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_CLOSE, sizeof(*req));
+
+ req->vf_id = vf_id;
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+
+ if (rc)
+ BNX2X_ERR("Sending CLOSE failed. rc was: %d\n", rc);
+
+ else if (resp->hdr.status != PFVF_STATUS_SUCCESS)
+ BNX2X_ERR("Sending CLOSE failed: pf response was %d\n",
+ resp->hdr.status);
+
+free_irq:
+ /* Disable HW interrupts, NAPI */
+ bnx2x_netif_stop(bp, 0);
+ /* Delete all NAPI objects */
+ bnx2x_del_all_napi(bp);
+
+ /* Release IRQs */
+ bnx2x_free_irq(bp);
+}
+
+/* ask the pf to open a queue for the vf */
+int bnx2x_vfpf_setup_q(struct bnx2x *bp, int fp_idx)
+{
+ struct vfpf_setup_q_tlv *req = &bp->vf2pf_mbox->req.setup_q;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ struct bnx2x_fastpath *fp = &bp->fp[fp_idx];
+ u16 tpa_agg_size = 0, flags = 0;
+ int rc;
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SETUP_Q, sizeof(*req));
+
+ /* select tpa mode to request */
+ if (!fp->disable_tpa) {
+ flags |= VFPF_QUEUE_FLG_TPA;
+ flags |= VFPF_QUEUE_FLG_TPA_IPV6;
+ if (fp->mode == TPA_MODE_GRO)
+ flags |= VFPF_QUEUE_FLG_TPA_GRO;
+ tpa_agg_size = TPA_AGG_SIZE;
+ }
+
+ /* calculate queue flags */
+ flags |= VFPF_QUEUE_FLG_STATS;
+ flags |= VFPF_QUEUE_FLG_CACHE_ALIGN;
+ flags |= IS_MF_SD(bp) ? VFPF_QUEUE_FLG_OV : 0;
+ flags |= VFPF_QUEUE_FLG_VLAN;
+ DP(NETIF_MSG_IFUP, "vlan removal enabled\n");
+
+ /* Common */
+ req->vf_qid = fp_idx;
+ req->param_valid = VFPF_RXQ_VALID | VFPF_TXQ_VALID;
+
+ /* Rx */
+ req->rxq.rcq_addr = fp->rx_comp_mapping;
+ req->rxq.rcq_np_addr = fp->rx_comp_mapping + BCM_PAGE_SIZE;
+ req->rxq.rxq_addr = fp->rx_desc_mapping;
+ req->rxq.sge_addr = fp->rx_sge_mapping;
+ req->rxq.vf_sb = fp_idx;
+ req->rxq.sb_index = HC_INDEX_ETH_RX_CQ_CONS;
+ req->rxq.hc_rate = bp->rx_ticks ? 1000000/bp->rx_ticks : 0;
+ req->rxq.mtu = bp->dev->mtu;
+ req->rxq.buf_sz = fp->rx_buf_size;
+ req->rxq.sge_buf_sz = BCM_PAGE_SIZE * PAGES_PER_SGE;
+ req->rxq.tpa_agg_sz = tpa_agg_size;
+ req->rxq.max_sge_pkt = SGE_PAGE_ALIGN(bp->dev->mtu) >> SGE_PAGE_SHIFT;
+ req->rxq.max_sge_pkt = ((req->rxq.max_sge_pkt + PAGES_PER_SGE - 1) &
+ (~(PAGES_PER_SGE-1))) >> PAGES_PER_SGE_SHIFT;
+ req->rxq.flags = flags;
+ req->rxq.drop_flags = 0;
+ req->rxq.cache_line_log = BNX2X_RX_ALIGN_SHIFT;
+ req->rxq.stat_id = -1; /* No stats at the moment */
+
+ /* Tx */
+ req->txq.txq_addr = fp->txdata_ptr[FIRST_TX_COS_INDEX]->tx_desc_mapping;
+ req->txq.vf_sb = fp_idx;
+ req->txq.sb_index = HC_INDEX_ETH_TX_CQ_CONS_COS0;
+ req->txq.hc_rate = bp->tx_ticks ? 1000000/bp->tx_ticks : 0;
+ req->txq.flags = flags;
+ req->txq.traffic_type = LLFC_TRAFFIC_TYPE_NW;
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+ if (rc)
+ BNX2X_ERR("Sending SETUP_Q message for queue[%d] failed!\n",
+ fp_idx);
+
+ if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+ BNX2X_ERR("Status of SETUP_Q for queue[%d] is %d\n",
+ fp_idx, resp->hdr.status);
+ return -EINVAL;
+ }
+ return rc;
+}
+
+int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx)
+{
+ struct vfpf_q_op_tlv *req = &bp->vf2pf_mbox->req.q_op;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ int rc;
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_TEARDOWN_Q,
+ sizeof(*req));
+
+ req->vf_qid = qidx;
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+
+ if (rc) {
+ BNX2X_ERR("Sending TEARDOWN for queue %d failed: %d\n", qidx,
+ rc);
+ return rc;
+ }
+
+ /* PF failed the transaction */
+ if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+ BNX2X_ERR("TEARDOWN for queue %d failed: %d\n", qidx,
+ resp->hdr.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* request pf to add a mac for the vf */
+int bnx2x_vfpf_set_mac(struct bnx2x *bp)
+{
+ struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ int rc;
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
+ sizeof(*req));
+
+ req->flags = VFPF_SET_Q_FILTERS_MAC_VLAN_CHANGED;
+ req->vf_qid = 0;
+ req->n_mac_vlan_filters = 1;
+ req->filters[0].flags =
+ VFPF_Q_FILTER_DEST_MAC_VALID | VFPF_Q_FILTER_SET_MAC;
+
+ /* sample bulletin board for new mac */
+ bnx2x_sample_bulletin(bp);
+
+ /* copy mac from device to request */
+ memcpy(req->filters[0].mac, bp->dev->dev_addr, ETH_ALEN);
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ /* send message to pf */
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+ if (rc) {
+ BNX2X_ERR("failed to send message to pf. rc was %d\n", rc);
+ return rc;
+ }
+
+ /* failure may mean PF was configured with a new mac for us */
+ while (resp->hdr.status == PFVF_STATUS_FAILURE) {
+ DP(BNX2X_MSG_IOV,
+ "vfpf SET MAC failed. Check bulletin board for new posts\n");
+
+ /* check if bulletin board was updated */
+ if (bnx2x_sample_bulletin(bp) == PFVF_BULLETIN_UPDATED) {
+ /* copy mac from device to request */
+ memcpy(req->filters[0].mac, bp->dev->dev_addr,
+ ETH_ALEN);
+
+ /* send message to pf */
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status,
+ bp->vf2pf_mbox_mapping);
+ } else {
+ /* no new info in bulletin */
+ break;
+ }
+ }
+
+ if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+ BNX2X_ERR("vfpf SET MAC failed: %d\n", resp->hdr.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int bnx2x_vfpf_set_mcast(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ int rc, i = 0;
+ struct netdev_hw_addr *ha;
+
+ if (bp->state != BNX2X_STATE_OPEN) {
+ DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state);
+ return -EINVAL;
+ }
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
+ sizeof(*req));
+
+ /* Get Rx mode requested */
+ DP(NETIF_MSG_IFUP, "dev->flags = %x\n", dev->flags);
+
+ netdev_for_each_mc_addr(ha, dev) {
+ DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n",
+ bnx2x_mc_addr(ha));
+ memcpy(req->multicast[i], bnx2x_mc_addr(ha), ETH_ALEN);
+ i++;
+ }
+
+ /* We support four PFVF_MAX_MULTICAST_PER_VF mcast
+ * addresses tops
+ */
+ if (i >= PFVF_MAX_MULTICAST_PER_VF) {
+ DP(NETIF_MSG_IFUP,
+ "VF supports not more than %d multicast MAC addresses\n",
+ PFVF_MAX_MULTICAST_PER_VF);
+ return -EINVAL;
+ }
+
+ req->n_multicast = i;
+ req->flags |= VFPF_SET_Q_FILTERS_MULTICAST_CHANGED;
+ req->vf_qid = 0;
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+ if (rc) {
+ BNX2X_ERR("Sending a message failed: %d\n", rc);
+ return rc;
+ }
+
+ if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+ BNX2X_ERR("Set Rx mode/multicast failed: %d\n",
+ resp->hdr.status);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int bnx2x_vfpf_storm_rx_mode(struct bnx2x *bp)
+{
+ int mode = bp->rx_mode;
+ struct vfpf_set_q_filters_tlv *req = &bp->vf2pf_mbox->req.set_q_filters;
+ struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp;
+ int rc;
+
+ /* clear mailbox and prep first tlv */
+ bnx2x_vfpf_prep(bp, &req->first_tlv, CHANNEL_TLV_SET_Q_FILTERS,
+ sizeof(*req));
+
+ DP(NETIF_MSG_IFUP, "Rx mode is %d\n", mode);
+
+ switch (mode) {
+ case BNX2X_RX_MODE_NONE: /* no Rx */
+ req->rx_mask = VFPF_RX_MASK_ACCEPT_NONE;
+ break;
+ case BNX2X_RX_MODE_NORMAL:
+ req->rx_mask = VFPF_RX_MASK_ACCEPT_MATCHED_MULTICAST;
+ req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST;
+ req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
+ break;
+ case BNX2X_RX_MODE_ALLMULTI:
+ req->rx_mask = VFPF_RX_MASK_ACCEPT_ALL_MULTICAST;
+ req->rx_mask |= VFPF_RX_MASK_ACCEPT_MATCHED_UNICAST;
+ req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
+ break;
+ case BNX2X_RX_MODE_PROMISC:
+ req->rx_mask = VFPF_RX_MASK_ACCEPT_ALL_UNICAST;
+ req->rx_mask |= VFPF_RX_MASK_ACCEPT_ALL_MULTICAST;
+ req->rx_mask |= VFPF_RX_MASK_ACCEPT_BROADCAST;
+ break;
+ default:
+ BNX2X_ERR("BAD rx mode (%d)\n", mode);
+ return -EINVAL;
+ }
+
+ req->flags |= VFPF_SET_Q_FILTERS_RX_MASK_CHANGED;
+ req->vf_qid = 0;
+
+ /* add list termination tlv */
+ bnx2x_add_tlv(bp, req, req->first_tlv.tl.length, CHANNEL_TLV_LIST_END,
+ sizeof(struct channel_list_end_tlv));
+
+ /* output tlvs list */
+ bnx2x_dp_tlv_list(bp, req);
+
+ rc = bnx2x_send_msg2pf(bp, &resp->hdr.status, bp->vf2pf_mbox_mapping);
+ if (rc)
+ BNX2X_ERR("Sending a message failed: %d\n", rc);
+
+ if (resp->hdr.status != PFVF_STATUS_SUCCESS) {
+ BNX2X_ERR("Set Rx mode failed: %d\n", resp->hdr.status);
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
/* General service functions */
static void storm_memset_vf_mbx_ack(struct bnx2x *bp, u16 abs_fid)
{
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
index 9f07ada..21d2985 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h
@@ -18,6 +18,8 @@
#ifndef VF_PF_IF_H
#define VF_PF_IF_H
+#ifdef CONFIG_BNX2X_SRIOV
+
/* Common definitions for all HVs */
struct vf_pf_resc_request {
u8 num_rxqs;
@@ -353,4 +355,5 @@ enum channel_tlvs {
CHANNEL_TLV_MAX
};
+#endif /* CONFIG_BNX2X_SRIOV */
#endif /* VF_PF_IF_H */
--
1.7.9.GIT
^ permalink raw reply related
* Re: [PATCH 2/2] ipv6: fix packet corruption when Dest/RT2 options are used
From: Nicolas Dichtel @ 2013-01-07 10:49 UTC (permalink / raw)
To: Romain KUNTZ; +Cc: netdev, yoshfuji, davem, Steffen Klassert
In-Reply-To: <C7895CAA-0AF7-4EED-B9E7-9D8E4A21442B@ipflavors.com>
Le 05/01/2013 17:19, Romain KUNTZ a écrit :
> Commit 299b0767 (ipv6: Fix IPsec slowpath fragmentation problem)
Add Steffen into CC, he is the author of this patch and the IPsec
maintainer.
> has introduced a bug that provokes corrupted packets when Destination
> Options or Routing Header Type 2 are used (such as with Mobile IPv6):
> rt->rt6i_nfheader_len should be substracted to rt->dst.header_len,
> and not to exthdrlen.
>
> This patch reverts to the original and correct behavior. Successfully
> tested with and without IPsec activated for MH packets.
>
> Signed-off-by: Romain Kuntz <r.kuntz@ipflavors.com>
> ---
> net/ipv6/ip6_output.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
> index 5552d13..0c7c03d 100644
> --- a/net/ipv6/ip6_output.c
> +++ b/net/ipv6/ip6_output.c
> @@ -1213,10 +1213,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
> if (dst_allfrag(rt->dst.path))
> cork->flags |= IPCORK_ALLFRAG;
> cork->length = 0;
> - exthdrlen = (opt ? opt->opt_flen : 0) - rt->rt6i_nfheader_len;
> + exthdrlen = (opt ? opt->opt_flen : 0);
> length += exthdrlen;
> transhdrlen += exthdrlen;
> - dst_exthdrlen = rt->dst.header_len;
> + dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len;
> } else {
> rt = (struct rt6_info *)cork->dst;
> fl6 = &inet->cork.fl.u.ip6;
>
^ permalink raw reply
* Re: [PATCH repost] net,wireless: check against default_ethtool_ops
From: Jiri Pirko @ 2013-01-07 11:11 UTC (permalink / raw)
To: Stanislaw Gruszka
Cc: netdev, David S. Miller, Eric Dumazet, Ben Greear,
Bjørn Mork, linux-wireless, Ben Hutchings
In-Reply-To: <20130107104413.GB6931@redhat.com>
Mon, Jan 07, 2013 at 11:44:14AM CET, sgruszka@redhat.com wrote:
>On Mon, Jan 07, 2013 at 11:23:07AM +0100, Jiri Pirko wrote:
>> >-static const struct ethtool_ops default_ethtool_ops;
>> >+const struct ethtool_ops default_ethtool_ops;
>> >+EXPORT_SYMBOL_GPL(default_ethtool_ops);
>>
>> I think that default_ethtool_ops should stay static. Wouldn't it be
>> nicer to introduce a helper like:
>>
>> bool dev_has_default_ethtool_ops(struct net_device *dev)
>> {
>> return dev->ethtool_ops == &default_ethtool_ops;
>> }
>
>Then I still have to export this function. So with your approch, number
>of exported symbols will be the same, but there will be few more lines
>of code.
I think it's always better to add few more lines in order to prevent possible
confusion which exporting default_ethtool_ops might introduce...
>
>Stanislaw
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox