* [PATCH v3 net-next 7/8] net/ncsi: No error report on DP response to non-existing package
From: Gavin Shan @ 2017-04-18 6:51 UTC (permalink / raw)
To: netdev; +Cc: joe, kubakici, davem, Gavin Shan
In-Reply-To: <1492498295-14385-1-git-send-email-gwshan@linux.vnet.ibm.com>
The issue was found from /sys/kernel/debug/ncsi/eth0/stats. The
first step in NCSI package/channel enumeration is deselect all
packages by sending DP (Deselect Package) commands. The remote
NIC replies with response while the corresponding package isn't
populated yet and it is treated as an error wrongly.
# cat /sys/kernel/debug/ncsi/eth0/stats
:
RSP OK TIMEOUT ERROR
=======================================
CIS 3 0 0
SP 3 0 0
DP 2 0 1
This fixes the issue by ignoring the error in DP response handler,
when the corresponding package isn't existing. With this applied,
no error reported from DP response packets.
# cat /sys/kernel/debug/ncsi/eth0/stats
:
RSP OK TIMEOUT ERROR
=======================================
CIS 3 0 0
SP 3 0 0
DP 3 0 0
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
net/ncsi/ncsi-rsp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index 24154fc..092f2d8 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -118,7 +118,7 @@ static int ncsi_rsp_handler_dp(struct ncsi_request *nr)
ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
&np, NULL);
if (!np)
- return -ENODEV;
+ return 0;
/* Change state of all channels attached to the package */
NCSI_FOR_EACH_CHANNEL(np, nc) {
--
2.7.4
^ permalink raw reply related
* [PATCH v3 net-next 8/8] net/ncsi: Fix length of GVI response packet
From: Gavin Shan @ 2017-04-18 6:51 UTC (permalink / raw)
To: netdev; +Cc: joe, kubakici, davem, Gavin Shan
In-Reply-To: <1492498295-14385-1-git-send-email-gwshan@linux.vnet.ibm.com>
The length of GVI (GetVersionInfo) response packet should be 40 instead
of 36. This issue was found from /sys/kernel/debug/ncsi/eth0/stats.
# cat /sys/kernel/debug/ncsi/eth0/stats
:
RSP OK TIMEOUT ERROR
=======================================
GVI 0 0 2
With this applied, no error reported on GVI response packets:
# cat /sys/kernel/debug/ncsi/eth0/stats
:
RSP OK TIMEOUT ERROR
=======================================
GVI 2 0 0
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
net/ncsi/ncsi-rsp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index 092f2d8..804ccca 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -951,7 +951,7 @@ static struct ncsi_rsp_handler {
{ NCSI_PKT_RSP_EGMF, 4, ncsi_rsp_handler_egmf },
{ NCSI_PKT_RSP_DGMF, 4, ncsi_rsp_handler_dgmf },
{ NCSI_PKT_RSP_SNFC, 4, ncsi_rsp_handler_snfc },
- { NCSI_PKT_RSP_GVI, 36, ncsi_rsp_handler_gvi },
+ { NCSI_PKT_RSP_GVI, 40, ncsi_rsp_handler_gvi },
{ NCSI_PKT_RSP_GC, 32, ncsi_rsp_handler_gc },
{ NCSI_PKT_RSP_GP, -1, ncsi_rsp_handler_gp },
{ NCSI_PKT_RSP_GCPS, 172, ncsi_rsp_handler_gcps },
--
2.7.4
^ permalink raw reply related
* [PATCH v3 net-next 5/8] net/ncsi: Dump NCSI packet statistics
From: Gavin Shan @ 2017-04-18 6:51 UTC (permalink / raw)
To: netdev; +Cc: joe, kubakici, davem, Gavin Shan
In-Reply-To: <1492498295-14385-1-git-send-email-gwshan@linux.vnet.ibm.com>
This creates /sys/kernel/debug/ncsi/<eth0>/stats to dump the NCSI
packets sent and received over all packages and channels. It's useful
to diagnose NCSI problems, especially when NCSI packages and channels
aren't probed properly. The statistics can be gained from debugfs file
as below:
# cat /sys/kernel/debug/ncsi/eth0/stats
CMD OK TIMEOUT ERROR
=======================================
CIS 32 29 0
SP 10 7 0
DP 17 14 0
EC 1 0 0
ECNT 1 0 0
AE 1 0 0
GLS 11 0 0
SMA 1 0 0
EBF 1 0 0
GVI 2 0 0
GC 2 0 0
RSP OK TIMEOUT ERROR
=======================================
CIS 3 0 0
SP 3 0 0
DP 2 0 1
EC 1 0 0
ECNT 1 0 0
AE 1 0 0
GLS 11 0 0
SMA 1 0 0
EBF 1 0 0
GVI 0 0 2
GC 2 0 0
AEN OK TIMEOUT ERROR
=======================================
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
net/ncsi/internal.h | 17 ++++
net/ncsi/ncsi-aen.c | 13 ++-
net/ncsi/ncsi-cmd.c | 12 ++-
net/ncsi/ncsi-debug.c | 252 +++++++++++++++++++++++++++++++++++++++++++++++++
net/ncsi/ncsi-manage.c | 4 +
net/ncsi/ncsi-rsp.c | 11 ++-
6 files changed, 306 insertions(+), 3 deletions(-)
diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index e9ede4f..c0b50a9 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -282,7 +282,17 @@ struct ncsi_dev_priv {
struct work_struct work; /* For channel management */
struct packet_type ptype; /* NCSI packet Rx handler */
struct list_head node; /* Form NCSI device list */
+#define NCSI_PKT_STAT_OK 0
+#define NCSI_PKT_STAT_TIMEOUT 1
+#define NCSI_PKT_STAT_ERROR 2
+#define NCSI_PKT_STAT_MAX 3
#ifdef CONFIG_NET_NCSI_DEBUG
+ struct {
+ struct dentry *dentry;
+ unsigned long cmd[128][NCSI_PKT_STAT_MAX];
+ unsigned long rsp[128][NCSI_PKT_STAT_MAX];
+ unsigned long aen[256][NCSI_PKT_STAT_MAX];
+ } stats;
struct dentry *dentry; /* Procfs directory */
#endif
};
@@ -349,6 +359,8 @@ int ncsi_aen_handler(struct ncsi_dev_priv *ndp, struct sk_buff *skb);
/* Debugging functionality */
#ifdef CONFIG_NET_NCSI_DEBUG
int ncsi_dev_init_debug(struct ncsi_dev_priv *ndp);
+void ncsi_dev_update_stats(struct ncsi_dev_priv *ndp,
+ int type, int subtype, int errno);
void ncsi_dev_release_debug(struct ncsi_dev_priv *ndp);
int ncsi_package_init_debug(struct ncsi_package *np);
void ncsi_package_release_debug(struct ncsi_package *np);
@@ -360,6 +372,11 @@ static inline int ncsi_dev_init_debug(struct ncsi_dev_priv *ndp)
return -ENOTTY;
}
+static inline void ncsi_dev_update_stats(struct ncsi_dev_priv *ndp,
+ int type, int subtype, int errno)
+{
+}
+
static inline void ncsi_dev_release_debug(struct ncsi_dev_priv *ndp)
{
}
diff --git a/net/ncsi/ncsi-aen.c b/net/ncsi/ncsi-aen.c
index 6898e72..72bac7c 100644
--- a/net/ncsi/ncsi-aen.c
+++ b/net/ncsi/ncsi-aen.c
@@ -206,16 +206,27 @@ int ncsi_aen_handler(struct ncsi_dev_priv *ndp, struct sk_buff *skb)
}
if (!nah) {
+ ncsi_dev_update_stats(ndp, NCSI_PKT_AEN,
+ h->type, NCSI_PKT_STAT_ERROR);
netdev_warn(ndp->ndev.dev, "Invalid AEN (0x%x) received\n",
h->type);
return -ENOENT;
}
ret = ncsi_validate_aen_pkt(h, nah->payload);
- if (ret)
+ if (ret) {
+ ncsi_dev_update_stats(ndp, NCSI_PKT_AEN,
+ h->type, NCSI_PKT_STAT_ERROR);
goto out;
+ }
ret = nah->handler(ndp, h);
+ if (ret)
+ ncsi_dev_update_stats(ndp, NCSI_PKT_AEN,
+ h->type, NCSI_PKT_STAT_ERROR);
+ else
+ ncsi_dev_update_stats(ndp, NCSI_PKT_AEN,
+ h->type, NCSI_PKT_STAT_OK);
out:
consume_skb(skb);
return ret;
diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c
index db7083b..9a8dac2 100644
--- a/net/ncsi/ncsi-cmd.c
+++ b/net/ncsi/ncsi-cmd.c
@@ -323,6 +323,8 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
}
if (!nch) {
+ ncsi_dev_update_stats(nca->ndp, nca->type,
+ 0, NCSI_PKT_STAT_ERROR);
netdev_err(nca->ndp->ndev.dev,
"Cannot send packet with type 0x%02x\n", nca->type);
return -ENOENT;
@@ -331,13 +333,18 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
/* Get packet payload length and allocate the request */
nca->payload = nch->payload;
nr = ncsi_alloc_command(nca);
- if (!nr)
+ if (!nr) {
+ ncsi_dev_update_stats(nca->ndp, nca->type,
+ 0, NCSI_PKT_STAT_ERROR);
return -ENOMEM;
+ }
/* Prepare the packet */
nca->id = nr->id;
ret = nch->handler(nr->cmd, nca);
if (ret) {
+ ncsi_dev_update_stats(nca->ndp, nca->type,
+ 0, NCSI_PKT_STAT_ERROR);
ncsi_free_request(nr);
return ret;
}
@@ -359,9 +366,12 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
skb_get(nr->cmd);
ret = dev_queue_xmit(nr->cmd);
if (ret < 0) {
+ ncsi_dev_update_stats(nca->ndp, nca->type,
+ 0, NCSI_PKT_STAT_ERROR);
ncsi_free_request(nr);
return ret;
}
+ ncsi_dev_update_stats(nca->ndp, nca->type, 0, NCSI_PKT_STAT_OK);
return 0;
}
diff --git a/net/ncsi/ncsi-debug.c b/net/ncsi/ncsi-debug.c
index f38483d..b6df895 100644
--- a/net/ncsi/ncsi-debug.c
+++ b/net/ncsi/ncsi-debug.c
@@ -23,6 +23,235 @@
#include "ncsi-pkt.h"
static struct dentry *ncsi_dentry;
+static const struct ncsi_pkt_handler {
+ unsigned char type;
+ const char *name;
+} ncsi_pkt_handlers[] = {
+ { NCSI_PKT_CMD_CIS, "CIS" },
+ { NCSI_PKT_CMD_SP, "SP" },
+ { NCSI_PKT_CMD_DP, "DP" },
+ { NCSI_PKT_CMD_EC, "EC" },
+ { NCSI_PKT_CMD_DC, "DC" },
+ { NCSI_PKT_CMD_RC, "RC" },
+ { NCSI_PKT_CMD_ECNT, "ECNT" },
+ { NCSI_PKT_CMD_DCNT, "DCNT" },
+ { NCSI_PKT_CMD_AE, "AE" },
+ { NCSI_PKT_CMD_SL, "SL" },
+ { NCSI_PKT_CMD_GLS, "GLS" },
+ { NCSI_PKT_CMD_SVF, "SVF" },
+ { NCSI_PKT_CMD_EV, "EV" },
+ { NCSI_PKT_CMD_DV, "DV" },
+ { NCSI_PKT_CMD_SMA, "SMA" },
+ { NCSI_PKT_CMD_EBF, "EBF" },
+ { NCSI_PKT_CMD_DBF, "DBF" },
+ { NCSI_PKT_CMD_EGMF, "EGMF" },
+ { NCSI_PKT_CMD_DGMF, "DGMF" },
+ { NCSI_PKT_CMD_SNFC, "SNFC" },
+ { NCSI_PKT_CMD_GVI, "GVI" },
+ { NCSI_PKT_CMD_GC, "GC" },
+ { NCSI_PKT_CMD_GP, "GP" },
+ { NCSI_PKT_CMD_GCPS, "GCPS" },
+ { NCSI_PKT_CMD_GNS, "GNS" },
+ { NCSI_PKT_CMD_GNPTS, "GNPTS" },
+ { NCSI_PKT_CMD_GPS, "GPS" },
+ { NCSI_PKT_CMD_OEM, "OEM" },
+ { NCSI_PKT_CMD_PLDM, "PLDM" },
+ { NCSI_PKT_CMD_GPUUID, "GPUUID" },
+};
+
+static bool ncsi_dev_stats_index(struct ncsi_dev_priv *ndp, loff_t pos,
+ unsigned long *type, unsigned long *index,
+ unsigned long *entries)
+{
+ const unsigned long ranges[3][2] = {
+ { 1,
+ ARRAY_SIZE(ndp->stats.cmd) - 1 },
+ { ranges[0][1] + 2,
+ ranges[1][0] + ARRAY_SIZE(ndp->stats.rsp) - 1 },
+ { ranges[1][1] + 2,
+ ranges[2][0] + ARRAY_SIZE(ndp->stats.aen) - 1 }
+ };
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ if (pos == (ranges[i][0] - 1)) {
+ *index = i;
+ *entries = 0;
+ return true;
+ }
+
+ if (pos >= ranges[i][0] && pos <= ranges[i][1]) {
+ *type = i;
+ *index = (pos - ranges[i][0]);
+ *entries = NCSI_PKT_STAT_MAX;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void *ncsi_dev_stats_data(struct ncsi_dev_priv *ndp, loff_t pos)
+{
+ unsigned long type, index, entries;
+ bool valid;
+
+ valid = ncsi_dev_stats_index(ndp, pos, &type, &index, &entries);
+ if (!valid)
+ return NULL;
+
+ /* The bits in return value are assigned as below:
+ *
+ * Bit[7:0]: Number of ulong entries
+ * Bit[23:8]: Offset to that specific data entry
+ * Bit[30:24]: Type of packet statistics
+ * Bit[31]: 0x1 as valid flag.
+ */
+ if (!entries)
+ index += ((unsigned long)SEQ_START_TOKEN);
+ else
+ index = (1 << 31) | (type << 24) | (index << 8) | entries;
+
+ return (void *)index;
+}
+
+static void *ncsi_dev_stats_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ struct ncsi_dev_priv *ndp = seq->private;
+ void *data;
+
+ data = ncsi_dev_stats_data(ndp, *pos);
+ ++(*pos);
+
+ return data;
+}
+
+static void *ncsi_dev_stats_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct ncsi_dev_priv *ndp = seq->private;
+ void *data;
+
+ data = ncsi_dev_stats_data(ndp, *pos);
+ ++(*pos);
+ return data;
+}
+
+static void ncsi_dev_stats_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+static const char *ncsi_pkt_type_name(unsigned int type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ncsi_pkt_handlers); i++) {
+ if (ncsi_pkt_handlers[i].type == type)
+ return ncsi_pkt_handlers[i].name;
+ }
+
+ return "N/A";
+}
+
+static const char *ncsi_dev_stats_pkt_name(unsigned long type,
+ unsigned long index)
+{
+ switch (type) {
+ case 0: /* Command */
+ case 1: /* Response */
+ return ncsi_pkt_type_name(index);
+ case 2: /* AEN */
+ switch (index) {
+ case NCSI_PKT_AEN_LSC:
+ return "LSC";
+ case NCSI_PKT_AEN_CR:
+ return "CR";
+ case NCSI_PKT_AEN_HNCDSC:
+ return "HNCDSC";
+ default:
+ return "N/A";
+ }
+ }
+
+ return "N/A";
+}
+
+static int ncsi_dev_stats_seq_show(struct seq_file *seq, void *v)
+{
+ struct ncsi_dev_priv *ndp = seq->private;
+ unsigned long type, index, entries, *data;
+ const char *name;
+
+ if (v >= SEQ_START_TOKEN && v <= (SEQ_START_TOKEN + 2)) {
+ static const char * const header[] = { "CMD", "RSP", "AEN" };
+
+ seq_puts(seq, "\n");
+ seq_printf(seq, "%-12s %-8s %-8s %-8s\n",
+ header[v - SEQ_START_TOKEN],
+ "OK", "TIMEOUT", "ERROR");
+ seq_puts(seq, "=======================================\n");
+ return 0;
+ }
+
+ index = (unsigned long)v;
+ type = (index >> 24) & 0x7F;
+ entries = (index & 0xFF);
+ index = ((index >> 8) & 0xFFFF);
+ name = ncsi_dev_stats_pkt_name(type, index);
+ if (WARN_ON_ONCE(entries != NCSI_PKT_STAT_MAX))
+ return 0;
+
+ switch (type) {
+ case 0: /* Command */
+ data = &ndp->stats.cmd[0][0];
+ break;
+ case 1: /* Response */
+ data = &ndp->stats.rsp[0][0];
+ break;
+ case 2: /* AEN */
+ data = &ndp->stats.aen[0][0];
+ break;
+ default:
+ pr_warn("%s: Unsupported type %ld\n", __func__, type);
+ return 0;
+ }
+
+ data += (index * NCSI_PKT_STAT_MAX);
+ if (*data || *(data + 1) || *(data + 2)) {
+ seq_printf(seq, "%-12s %-8ld %-8ld %-8ld\n",
+ name, *data, *(data + 1), *(data + 2));
+ }
+
+ return 0;
+}
+
+static const struct seq_operations ncsi_dev_stats_seq_ops = {
+ .start = ncsi_dev_stats_seq_start,
+ .next = ncsi_dev_stats_seq_next,
+ .stop = ncsi_dev_stats_seq_stop,
+ .show = ncsi_dev_stats_seq_show,
+};
+
+static int ncsi_dev_stats_seq_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *sf;
+ int ret;
+
+ ret = seq_open(file, &ncsi_dev_stats_seq_ops);
+ if (!ret) {
+ sf = file->private_data;
+ sf->private = inode->i_private;
+ }
+
+ return ret;
+}
+
+static const struct file_operations ncsi_dev_stats_fops = {
+ .owner = THIS_MODULE,
+ .open = ncsi_dev_stats_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
int ncsi_dev_init_debug(struct ncsi_dev_priv *ndp)
{
@@ -45,11 +274,34 @@ int ncsi_dev_init_debug(struct ncsi_dev_priv *ndp)
return -ENOMEM;
}
+ ndp->stats.dentry = debugfs_create_file("stats", 0400, ndp->dentry,
+ ndp, &ncsi_dev_stats_fops);
+ if (!ndp->stats.dentry) {
+ pr_debug("Failed to create debugfs file 'ncsi/%s/stats'\n",
+ netdev_name(ndp->ndev.dev));
+ return -ENOMEM;
+ }
+
return 0;
}
+void ncsi_dev_update_stats(struct ncsi_dev_priv *ndp,
+ int type, int subtype, int errno)
+{
+ if (errno >= NCSI_PKT_STAT_MAX)
+ return;
+
+ if (type == NCSI_PKT_AEN)
+ ndp->stats.aen[subtype][errno]++;
+ else if (type >= 0x80)
+ ndp->stats.rsp[type - 0x80][errno]++;
+ else
+ ndp->stats.cmd[type][errno]++;
+}
+
void ncsi_dev_release_debug(struct ncsi_dev_priv *ndp)
{
+ debugfs_remove(ndp->stats.dentry);
debugfs_remove(ndp->dentry);
}
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index 84f1405..be7d907 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -530,6 +530,7 @@ static void ncsi_request_timeout(unsigned long data)
struct ncsi_request *nr = (struct ncsi_request *)data;
struct ncsi_dev_priv *ndp = nr->ndp;
unsigned long flags;
+ struct ncsi_pkt_hdr *hdr;
/* If the request already had associated response,
* let the response handler to release it.
@@ -542,6 +543,9 @@ static void ncsi_request_timeout(unsigned long data)
}
spin_unlock_irqrestore(&ndp->lock, flags);
+ hdr = (struct ncsi_pkt_hdr *)skb_network_header(nr->cmd);
+ ncsi_dev_update_stats(ndp, hdr->type, 0, NCSI_PKT_STAT_TIMEOUT);
+
/* Release the request */
ncsi_free_request(nr);
}
diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index 087db77..a164eb1 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -998,6 +998,7 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
}
if (!nrh) {
+ ncsi_dev_update_stats(ndp, hdr->type, 0, NCSI_PKT_STAT_ERROR);
netdev_err(nd->dev, "Received unrecognized packet (0x%x)\n",
hdr->type);
return -ENOENT;
@@ -1007,12 +1008,14 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
spin_lock_irqsave(&ndp->lock, flags);
nr = &ndp->requests[hdr->id];
if (!nr->used) {
+ ncsi_dev_update_stats(ndp, hdr->type, 0, NCSI_PKT_STAT_TIMEOUT);
spin_unlock_irqrestore(&ndp->lock, flags);
return -ENODEV;
}
nr->rsp = skb;
if (!nr->enabled) {
+ ncsi_dev_update_stats(ndp, hdr->type, 0, NCSI_PKT_STAT_TIMEOUT);
spin_unlock_irqrestore(&ndp->lock, flags);
ret = -ENOENT;
goto out;
@@ -1024,11 +1027,17 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
if (payload < 0)
payload = ntohs(hdr->length);
ret = ncsi_validate_rsp_pkt(nr, payload);
- if (ret)
+ if (ret) {
+ ncsi_dev_update_stats(ndp, hdr->type, 0, NCSI_PKT_STAT_ERROR);
goto out;
+ }
/* Process the packet */
ret = nrh->handler(nr);
+ if (ret)
+ ncsi_dev_update_stats(ndp, hdr->type, 0, NCSI_PKT_STAT_ERROR);
+ else
+ ncsi_dev_update_stats(ndp, hdr->type, 0, NCSI_PKT_STAT_OK);
out:
ncsi_free_request(nr);
return ret;
--
2.7.4
^ permalink raw reply related
* [PATCH v3 net-next 6/8] net/ncsi: Support NCSI packet generation
From: Gavin Shan @ 2017-04-18 6:51 UTC (permalink / raw)
To: netdev; +Cc: joe, kubakici, davem, Gavin Shan
In-Reply-To: <1492498295-14385-1-git-send-email-gwshan@linux.vnet.ibm.com>
This introduces /sys/kernel/debug/ncsi/eth0/pkt. The debugfs entry
can accept parameters to produce NCSI command packet. The received
NCSI response packet is dumped on read. Below is an example to send
CIS command and dump its response.
# echo CIS,0,0 > /sys/kernel/debug/ncsi/eth0/pkt
# cat /sys/kernel/debug/ncsi/eth0/pkt
NCSI response [CIS] packet received
00 01 dd 80 00 0004 0000 0000
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
net/ncsi/internal.h | 43 +++
net/ncsi/ncsi-cmd.c | 1 +
net/ncsi/ncsi-debug.c | 697 ++++++++++++++++++++++++++++++++++++++++++++++---
net/ncsi/ncsi-manage.c | 2 +
net/ncsi/ncsi-rsp.c | 9 +
5 files changed, 722 insertions(+), 30 deletions(-)
diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index c0b50a9..67d987b 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -221,6 +221,9 @@ struct ncsi_request {
bool used; /* Request that has been assigned */
unsigned int flags; /* NCSI request property */
#define NCSI_REQ_FLAG_EVENT_DRIVEN 1
+#ifdef CONFIG_NET_NCSI_DEBUG
+#define NCSI_REQ_FLAG_DEBUG 2
+#endif
struct ncsi_dev_priv *ndp; /* Associated NCSI device */
struct sk_buff *cmd; /* Associated NCSI command packet */
struct sk_buff *rsp; /* Associated NCSI response packet */
@@ -293,6 +296,14 @@ struct ncsi_dev_priv {
unsigned long rsp[128][NCSI_PKT_STAT_MAX];
unsigned long aen[256][NCSI_PKT_STAT_MAX];
} stats;
+ struct {
+ struct dentry *dentry;
+ unsigned int req;
+#define NCSI_PKT_REQ_FREE 0
+#define NCSI_PKT_REQ_BUSY 0xFFFFFFFF
+ int errno;
+ struct sk_buff *rsp;
+ } pkt;
struct dentry *dentry; /* Procfs directory */
#endif
};
@@ -361,6 +372,22 @@ int ncsi_aen_handler(struct ncsi_dev_priv *ndp, struct sk_buff *skb);
int ncsi_dev_init_debug(struct ncsi_dev_priv *ndp);
void ncsi_dev_update_stats(struct ncsi_dev_priv *ndp,
int type, int subtype, int errno);
+
+static inline bool ncsi_dev_is_debug_pkt(struct ncsi_dev_priv *ndp,
+ struct ncsi_request *nr)
+{
+ return ((nr->flags & NCSI_REQ_FLAG_DEBUG) && ndp->pkt.req == nr->id);
+}
+
+static inline void ncsi_dev_set_debug_pkt(struct ncsi_dev_priv *ndp,
+ struct ncsi_request *nr)
+{
+ if (nr->flags & NCSI_REQ_FLAG_DEBUG)
+ ndp->pkt.req = nr->id;
+}
+
+void ncsi_dev_reset_debug_pkt(struct ncsi_dev_priv *ndp,
+ struct sk_buff *skb, int errno);
void ncsi_dev_release_debug(struct ncsi_dev_priv *ndp);
int ncsi_package_init_debug(struct ncsi_package *np);
void ncsi_package_release_debug(struct ncsi_package *np);
@@ -377,6 +404,22 @@ static inline void ncsi_dev_update_stats(struct ncsi_dev_priv *ndp,
{
}
+static inline bool ncsi_dev_is_debug_pkt(struct ncsi_dev_priv *ndp,
+ struct ncsi_request *nr)
+{
+ return false;
+}
+
+static inline void ncsi_dev_set_debug_pkt(struct ncsi_dev_priv *ndp,
+ struct ncsi_request *nr)
+{
+}
+
+static inline void ncsi_dev_reset_debug_pkt(struct ncsi_dev_priv *ndp,
+ struct sk_buff *skb, int errno)
+{
+}
+
static inline void ncsi_dev_release_debug(struct ncsi_dev_priv *ndp)
{
}
diff --git a/net/ncsi/ncsi-cmd.c b/net/ncsi/ncsi-cmd.c
index 9a8dac2..baf82b3 100644
--- a/net/ncsi/ncsi-cmd.c
+++ b/net/ncsi/ncsi-cmd.c
@@ -361,6 +361,7 @@ int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
*/
nr->enabled = true;
mod_timer(&nr->timer, jiffies + 1 * HZ);
+ ncsi_dev_set_debug_pkt(nca->ndp, nr);
/* Send NCSI packet */
skb_get(nr->cmd);
diff --git a/net/ncsi/ncsi-debug.c b/net/ncsi/ncsi-debug.c
index b6df895..4f2b72c 100644
--- a/net/ncsi/ncsi-debug.c
+++ b/net/ncsi/ncsi-debug.c
@@ -23,40 +23,651 @@
#include "ncsi-pkt.h"
static struct dentry *ncsi_dentry;
+
+static const char *ncsi_pkt_type_name(unsigned int type);
+
+static int ncsi_pkt_input_default(struct ncsi_dev_priv *ndp,
+ struct ncsi_cmd_arg *nca, char *buf)
+{
+ return 0;
+}
+
+static int ncsi_pkt_input_params(char *buf, int *outval, int count)
+{
+ int num, i;
+
+ for (i = 0; i < count; i++, outval++) {
+ if (sscanf(buf, "%x%n", outval, &num) != 1)
+ return -EINVAL;
+
+ if (buf[num] == ',')
+ buf += (count + 1);
+ else
+ buf += count;
+ }
+
+ return 0;
+}
+
+static int ncsi_pkt_input_sp(struct ncsi_dev_priv *ndp,
+ struct ncsi_cmd_arg *nca, char *buf)
+{
+ int param, ret;
+
+ /* The hardware arbitration will be configured according
+ * to the NCSI's capability if it's not specified.
+ */
+ ret = ncsi_pkt_input_params(buf, ¶m, 1);
+ if (!ret && param != 0 && param != 1)
+ return -EINVAL;
+ else if (ret)
+ param = (ndp->flags & NCSI_DEV_HWA) ? 1 : 0;
+
+ nca->bytes[0] = param;
+
+ return 0;
+}
+
+static int ncsi_pkt_input_dc(struct ncsi_dev_priv *ndp,
+ struct ncsi_cmd_arg *nca, char *buf)
+{
+ int param, ret;
+
+ /* Allow link down will be disallowed if it's not specified */
+ ret = ncsi_pkt_input_params(buf, ¶m, 1);
+ if (!ret && param != 0 && param != 1)
+ return -EINVAL;
+ else if (ret)
+ param = 0;
+
+ nca->bytes[0] = param;
+
+ return 0;
+}
+
+static int ncsi_pkt_input_ae(struct ncsi_dev_priv *ndp,
+ struct ncsi_cmd_arg *nca, char *buf)
+{
+ int param[2], ret;
+
+ /* MC ID and AE mode are mandatory */
+ ret = ncsi_pkt_input_params(buf, param, 2);
+ if (ret)
+ return -EINVAL;
+
+ nca->bytes[0] = param[0];
+ nca->dwords[1] = param[1];
+
+ return 0;
+}
+
+static int ncsi_pkt_input_sl(struct ncsi_dev_priv *ndp,
+ struct ncsi_cmd_arg *nca, char *buf)
+{
+ int param[2], ret;
+
+ /* Link mode and OEM mode are mandatory */
+ ret = ncsi_pkt_input_params(buf, param, 2);
+ if (ret)
+ return -EINVAL;
+
+ nca->dwords[0] = param[0];
+ nca->dwords[1] = param[1];
+
+ return 0;
+}
+
+static int ncsi_pkt_input_svf(struct ncsi_dev_priv *ndp,
+ struct ncsi_cmd_arg *nca, char *buf)
+{
+ int param[3], ret;
+
+ /* VLAN ID, table index and enable */
+ ret = ncsi_pkt_input_params(buf, param, 3);
+ if (ret)
+ return -EINVAL;
+
+ if (param[2] != 0 && param[2] != 1)
+ return -EINVAL;
+
+ nca->words[0] = param[0];
+ nca->bytes[2] = param[1];
+ nca->bytes[3] = param[2];
+
+ return 0;
+}
+
+static int ncsi_pkt_input_ev(struct ncsi_dev_priv *ndp,
+ struct ncsi_cmd_arg *nca, char *buf)
+{
+ int param, ret;
+
+ /* VLAN filter mode */
+ ret = ncsi_pkt_input_params(buf, ¶m, 1);
+ if (ret)
+ return -EINVAL;
+
+ nca->bytes[0] = param;
+
+ return 0;
+}
+
+static int ncsi_pkt_input_sma(struct ncsi_dev_priv *ndp,
+ struct ncsi_cmd_arg *nca, char *buf)
+{
+ int param[8], ret;
+
+ /* MAC address, MAC table index, Address type and operation */
+ ret = ncsi_pkt_input_params(buf, param, 8);
+ if (ret)
+ return -EINVAL;
+
+ if (param[7] & ~0x9)
+ return -EINVAL;
+
+ nca->bytes[0] = param[0];
+ nca->bytes[1] = param[1];
+ nca->bytes[2] = param[2];
+ nca->bytes[3] = param[3];
+ nca->bytes[4] = param[4];
+ nca->bytes[5] = param[5];
+
+ nca->bytes[6] = param[6];
+ nca->bytes[7] = param[7];
+
+ return 0;
+}
+
+static int ncsi_pkt_input_ebf(struct ncsi_dev_priv *ndp,
+ struct ncsi_cmd_arg *nca, char *buf)
+{
+ int param, ret;
+
+ /* Broadcast filter mode */
+ ret = ncsi_pkt_input_params(buf, ¶m, 1);
+ if (ret)
+ return -EINVAL;
+
+ nca->dwords[0] = param;
+
+ return 0;
+}
+
+static int ncsi_pkt_input_egmf(struct ncsi_dev_priv *ndp,
+ struct ncsi_cmd_arg *nca, char *buf)
+{
+ int param, ret;
+
+ /* Global multicast filter mode */
+ ret = ncsi_pkt_input_params(buf, ¶m, 1);
+ if (ret)
+ return -EINVAL;
+
+ nca->dwords[0] = param;
+
+ return 0;
+}
+
+static int ncsi_pkt_input_snfc(struct ncsi_dev_priv *ndp,
+ struct ncsi_cmd_arg *nca, char *buf)
+{
+ int param, ret;
+
+ /* NCSI flow control mode */
+ ret = ncsi_pkt_input_params(buf, ¶m, 1);
+ if (ret)
+ return -EINVAL;
+
+ nca->bytes[0] = param;
+
+ return 0;
+}
+
+static void ncsi_pkt_output_header(struct ncsi_dev_priv *ndp,
+ struct seq_file *seq,
+ struct ncsi_rsp_pkt_hdr *h)
+{
+ seq_printf(seq, "NCSI response [%s] packet received\n\n",
+ ncsi_pkt_type_name(h->common.type - 0x80));
+ seq_printf(seq, "%02x %02x %02x %02x %02x %04x %04x %04x\n",
+ h->common.mc_id, h->common.revision, h->common.id,
+ h->common.type, h->common.channel, ntohs(h->common.length),
+ ntohs(h->code), ntohs(h->reason));
+}
+
+static int ncsi_pkt_output_default(struct ncsi_dev_priv *ndp,
+ struct seq_file *seq,
+ struct sk_buff *skb)
+{
+ struct ncsi_rsp_pkt_hdr *hdr;
+
+ hdr = (struct ncsi_rsp_pkt_hdr *)skb_network_header(skb);
+ ncsi_pkt_output_header(ndp, seq, hdr);
+
+ return 0;
+}
+
+static int ncsi_pkt_output_gls(struct ncsi_dev_priv *ndp,
+ struct seq_file *seq, struct sk_buff *skb)
+{
+ struct ncsi_rsp_gls_pkt *gls;
+
+ ncsi_pkt_output_default(ndp, seq, skb);
+
+ gls = (struct ncsi_rsp_gls_pkt *)skb_network_header(skb);
+ seq_printf(seq, "Status: %08x Other: %08x OEM: %08x\n",
+ ntohl(gls->status), ntohl(gls->other),
+ ntohl(gls->oem_status));
+
+ return 0;
+}
+
+static int ncsi_pkt_output_gvi(struct ncsi_dev_priv *ndp,
+ struct seq_file *seq, struct sk_buff *skb)
+{
+ struct ncsi_rsp_gvi_pkt *gvi;
+
+ ncsi_pkt_output_default(ndp, seq, skb);
+
+ gvi = (struct ncsi_rsp_gvi_pkt *)skb_network_header(skb);
+ seq_printf(seq, "NCSI Version: %08x Alpha2: %02x\n",
+ ntohl(gvi->ncsi_version), gvi->alpha2);
+ seq_printf(seq, "Firmware: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x Version: %08x\n",
+ gvi->fw_name[0], gvi->fw_name[1], gvi->fw_name[2],
+ gvi->fw_name[3], gvi->fw_name[4], gvi->fw_name[5],
+ gvi->fw_name[6], gvi->fw_name[7], gvi->fw_name[8],
+ gvi->fw_name[9], gvi->fw_name[10], gvi->fw_name[11],
+ ntohl(gvi->fw_version));
+ seq_printf(seq, "PCI: %04x %04x %04x %04x Manufacture ID: %08x\n",
+ ntohs(gvi->pci_ids[0]), ntohs(gvi->pci_ids[1]),
+ ntohs(gvi->pci_ids[2]), ntohs(gvi->pci_ids[3]),
+ ntohl(gvi->mf_id));
+
+ return 0;
+}
+
+static int ncsi_pkt_output_gc(struct ncsi_dev_priv *ndp,
+ struct seq_file *seq, struct sk_buff *skb)
+{
+ struct ncsi_rsp_gc_pkt *gc;
+
+ ncsi_pkt_output_default(ndp, seq, skb);
+
+ gc = (struct ncsi_rsp_gc_pkt *)skb_network_header(skb);
+ seq_printf(seq, "Cap: %08x BC: %08x MC: %08x Buf: %08x AEN: %08x\n",
+ ntohl(gc->cap), ntohl(gc->bc_cap), ntohl(gc->mc_cap),
+ ntohl(gc->buf_cap), ntohl(gc->aen_cap));
+ seq_printf(seq, "VLAN: %02x Mixed: %02x MC: %02x UC: %02x\n",
+ gc->vlan_cnt, gc->mixed_cnt, gc->mc_cnt, gc->uc_cnt);
+ seq_printf(seq, "VLAN Mode: %02x Channels: %02x\n",
+ gc->vlan_mode, gc->channel_cnt);
+
+ return 0;
+}
+
+static int ncsi_pkt_output_gp(struct ncsi_dev_priv *ndp,
+ struct seq_file *seq, struct sk_buff *skb)
+{
+ struct ncsi_rsp_gp_pkt *gp;
+
+ ncsi_pkt_output_default(ndp, seq, skb);
+
+ gp = (struct ncsi_rsp_gp_pkt *)skb_network_header(skb);
+ seq_printf(seq, "MAC: %02x %02x VLAN: %02x %04x\n",
+ gp->mac_cnt, gp->mac_enable, gp->vlan_cnt,
+ ntohs(gp->vlan_enable));
+ seq_printf(seq, "Link: %08x BC: %08x Valid: %08x\n",
+ ntohl(gp->link_mode), ntohl(gp->bc_mode),
+ ntohl(gp->valid_modes));
+ seq_printf(seq, "VLAN: %02x FC: %02x AEN: %08x\n",
+ gp->vlan_mode, gp->fc_mode, ntohl(gp->aen_mode));
+ seq_printf(seq, "MAC: %02x %02x %02x %02x %02x %02x VLAN: %04x\n",
+ gp->mac[5], gp->mac[4], gp->mac[3], gp->mac[2],
+ gp->mac[1], gp->mac[0], ntohs(gp->vlan));
+
+ return 0;
+}
+
+static int ncsi_pkt_output_gcps(struct ncsi_dev_priv *ndp,
+ struct seq_file *seq, struct sk_buff *skb)
+{
+ struct ncsi_rsp_gcps_pkt *gcps;
+
+ ncsi_pkt_output_default(ndp, seq, skb);
+
+ gcps = (struct ncsi_rsp_gcps_pkt *)skb_network_header(skb);
+ seq_printf(seq, "cnt_hi: %08x cnt_lo: %08x rx_bytes: %08x\n",
+ ntohl(gcps->cnt_hi), ntohl(gcps->cnt_lo),
+ ntohl(gcps->rx_bytes));
+ seq_printf(seq, "tx_bytes: %08x rx_uc_pkts: %08x rx_mc_pkts: %08x\n",
+ ntohl(gcps->tx_bytes), ntohl(gcps->rx_uc_pkts),
+ ntohl(gcps->rx_mc_pkts));
+ seq_printf(seq, "rx_bc_pkts: %08x tx_uc_pkts: %08x tx_mc_pkts: %08x\n",
+ ntohl(gcps->rx_bc_pkts), ntohl(gcps->tx_uc_pkts),
+ ntohl(gcps->tx_mc_pkts));
+ seq_printf(seq, "tx_bc_pkts: %08x fcs_err: %08x align_err: %08x\n",
+ ntohl(gcps->tx_bc_pkts), ntohl(gcps->fcs_err),
+ ntohl(gcps->align_err));
+ seq_printf(seq, "false_carrier: %08x runt_pkts: %08x jabber_pkts: %08x\n",
+ ntohl(gcps->false_carrier), ntohl(gcps->runt_pkts),
+ ntohl(gcps->jabber_pkts));
+ seq_printf(seq, "rx_pause_xon: %08x rx_pause_xoff: %08x tx_pause_xon: %08x",
+ ntohl(gcps->rx_pause_xon), ntohl(gcps->rx_pause_xoff),
+ ntohl(gcps->tx_pause_xon));
+ seq_printf(seq, "tx_pause_xoff: %08x tx_s_collision: %08x tx_m_collision: %08x\n",
+ ntohl(gcps->tx_pause_xoff), ntohl(gcps->tx_s_collision),
+ ntohl(gcps->tx_m_collision));
+ seq_printf(seq, "l_collision: %08x e_collision: %08x rx_ctl_frames: %08x\n",
+ ntohl(gcps->l_collision), ntohl(gcps->e_collision),
+ ntohl(gcps->rx_ctl_frames));
+ seq_printf(seq, "rx_64_frames: %08x rx_127_frames: %08x rx_255_frames: %08x\n",
+ ntohl(gcps->rx_64_frames), ntohl(gcps->rx_127_frames),
+ ntohl(gcps->rx_255_frames));
+ seq_printf(seq, "rx_511_frames: %08x rx_1023_frames: %08x rx_1522_frames: %08x\n",
+ ntohl(gcps->rx_511_frames), ntohl(gcps->rx_1023_frames),
+ ntohl(gcps->rx_1522_frames));
+ seq_printf(seq, "rx_9022_frames: %08x tx_64_frames: %08x tx_127_frames: %08x\n",
+ ntohl(gcps->rx_9022_frames), ntohl(gcps->tx_64_frames),
+ ntohl(gcps->tx_127_frames));
+ seq_printf(seq, "tx_255_frames: %08x tx_511_frames: %08x tx_1023_frames: %08x\n",
+ ntohl(gcps->tx_255_frames), ntohl(gcps->tx_511_frames),
+ ntohl(gcps->tx_1023_frames));
+ seq_printf(seq, "tx_1522_frames: %08x tx_9022_frames: %08x rx_valid_bytes: %08x\n",
+ ntohl(gcps->tx_1522_frames), ntohl(gcps->tx_9022_frames),
+ ntohl(gcps->rx_valid_bytes));
+ seq_printf(seq, "rx_runt_pkts: %08x rx_jabber_pkts: %08x\n",
+ ntohl(gcps->rx_runt_pkts), ntohl(gcps->rx_jabber_pkts));
+
+ return 0;
+}
+
+static int ncsi_pkt_output_gns(struct ncsi_dev_priv *ndp,
+ struct seq_file *seq, struct sk_buff *skb)
+{
+ struct ncsi_rsp_gns_pkt *gns;
+
+ ncsi_pkt_output_default(ndp, seq, skb);
+
+ gns = (struct ncsi_rsp_gns_pkt *)skb_network_header(skb);
+ seq_printf(seq, "rx_cmds: %08x dropped_cmds: %08x cmd_type_errs: %08x\n",
+ ntohl(gns->rx_cmds), ntohl(gns->dropped_cmds),
+ ntohl(gns->cmd_type_errs));
+ seq_printf(seq, "cmd_csum_errs: %08x rx_pkts: %08x tx_pkts: %08x\n",
+ ntohl(gns->cmd_csum_errs), ntohl(gns->rx_pkts),
+ ntohl(gns->tx_pkts));
+ seq_printf(seq, "tx_aen_pkts: %08x\n",
+ ntohl(gns->tx_aen_pkts));
+
+ return 0;
+}
+
+static int ncsi_pkt_output_gnpts(struct ncsi_dev_priv *ndp,
+ struct seq_file *seq, struct sk_buff *skb)
+{
+ struct ncsi_rsp_gnpts_pkt *gnpts;
+
+ ncsi_pkt_output_default(ndp, seq, skb);
+
+ gnpts = (struct ncsi_rsp_gnpts_pkt *)skb_network_header(skb);
+ seq_printf(seq, "tx_pkts: %08x tx_dropped: %08x tx_channel_err: %08x\n",
+ ntohl(gnpts->tx_pkts), ntohl(gnpts->tx_dropped),
+ ntohl(gnpts->tx_channel_err));
+ seq_printf(seq, "tx_us_err: %08x rx_pkts: %08x rx_dropped: %08x\n",
+ ntohl(gnpts->tx_us_err), ntohl(gnpts->rx_pkts),
+ ntohl(gnpts->rx_dropped));
+ seq_printf(seq, "rx_channel_err: %08x rx_us_err: %08x rx_os_err: %08x\n",
+ ntohl(gnpts->rx_channel_err), ntohl(gnpts->rx_us_err),
+ ntohl(gnpts->rx_os_err));
+
+ return 0;
+}
+
+static int ncsi_pkt_output_gps(struct ncsi_dev_priv *ndp,
+ struct seq_file *seq, struct sk_buff *skb)
+{
+ struct ncsi_rsp_gps_pkt *gps;
+
+ ncsi_pkt_output_default(ndp, seq, skb);
+
+ gps = (struct ncsi_rsp_gps_pkt *)skb_network_header(skb);
+ seq_printf(seq, "Status: %08x\n", ntohl(gps->status));
+
+ return 0;
+}
+
+static int ncsi_pkt_output_gpuuid(struct ncsi_dev_priv *ndp,
+ struct seq_file *seq, struct sk_buff *skb)
+{
+ struct ncsi_rsp_gpuuid_pkt *gpuuid;
+
+ ncsi_pkt_output_default(ndp, seq, skb);
+
+ gpuuid = (struct ncsi_rsp_gpuuid_pkt *)skb_network_header(skb);
+ seq_printf(seq, "UUID: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ gpuuid->uuid[15], gpuuid->uuid[14], gpuuid->uuid[13],
+ gpuuid->uuid[12], gpuuid->uuid[11], gpuuid->uuid[10],
+ gpuuid->uuid[9], gpuuid->uuid[8]);
+ seq_printf(seq, " %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ gpuuid->uuid[7], gpuuid->uuid[6], gpuuid->uuid[5],
+ gpuuid->uuid[4], gpuuid->uuid[3], gpuuid->uuid[2],
+ gpuuid->uuid[1], gpuuid->uuid[0]);
+
+ return 0;
+}
+
static const struct ncsi_pkt_handler {
unsigned char type;
const char *name;
+ int (*input)(struct ncsi_dev_priv *ndp,
+ struct ncsi_cmd_arg *nca, char *buf);
+ int (*output)(struct ncsi_dev_priv *ndp,
+ struct seq_file *seq, struct sk_buff *skb);
} ncsi_pkt_handlers[] = {
- { NCSI_PKT_CMD_CIS, "CIS" },
- { NCSI_PKT_CMD_SP, "SP" },
- { NCSI_PKT_CMD_DP, "DP" },
- { NCSI_PKT_CMD_EC, "EC" },
- { NCSI_PKT_CMD_DC, "DC" },
- { NCSI_PKT_CMD_RC, "RC" },
- { NCSI_PKT_CMD_ECNT, "ECNT" },
- { NCSI_PKT_CMD_DCNT, "DCNT" },
- { NCSI_PKT_CMD_AE, "AE" },
- { NCSI_PKT_CMD_SL, "SL" },
- { NCSI_PKT_CMD_GLS, "GLS" },
- { NCSI_PKT_CMD_SVF, "SVF" },
- { NCSI_PKT_CMD_EV, "EV" },
- { NCSI_PKT_CMD_DV, "DV" },
- { NCSI_PKT_CMD_SMA, "SMA" },
- { NCSI_PKT_CMD_EBF, "EBF" },
- { NCSI_PKT_CMD_DBF, "DBF" },
- { NCSI_PKT_CMD_EGMF, "EGMF" },
- { NCSI_PKT_CMD_DGMF, "DGMF" },
- { NCSI_PKT_CMD_SNFC, "SNFC" },
- { NCSI_PKT_CMD_GVI, "GVI" },
- { NCSI_PKT_CMD_GC, "GC" },
- { NCSI_PKT_CMD_GP, "GP" },
- { NCSI_PKT_CMD_GCPS, "GCPS" },
- { NCSI_PKT_CMD_GNS, "GNS" },
- { NCSI_PKT_CMD_GNPTS, "GNPTS" },
- { NCSI_PKT_CMD_GPS, "GPS" },
- { NCSI_PKT_CMD_OEM, "OEM" },
- { NCSI_PKT_CMD_PLDM, "PLDM" },
- { NCSI_PKT_CMD_GPUUID, "GPUUID" },
+ { NCSI_PKT_CMD_CIS, "CIS",
+ ncsi_pkt_input_default, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_SP, "SP",
+ ncsi_pkt_input_sp, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_DP, "DP",
+ ncsi_pkt_input_default, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_EC, "EC",
+ ncsi_pkt_input_default, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_DC, "DC",
+ ncsi_pkt_input_dc, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_RC, "RC",
+ ncsi_pkt_input_default, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_ECNT, "ECNT",
+ ncsi_pkt_input_default, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_DCNT, "DCNT",
+ ncsi_pkt_input_default, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_AE, "AE",
+ ncsi_pkt_input_ae, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_SL, "SL",
+ ncsi_pkt_input_sl, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_GLS, "GLS",
+ ncsi_pkt_input_default, ncsi_pkt_output_gls },
+ { NCSI_PKT_CMD_SVF, "SVF",
+ ncsi_pkt_input_svf, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_EV, "EV",
+ ncsi_pkt_input_ev, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_DV, "DV",
+ ncsi_pkt_input_default, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_SMA, "SMA",
+ ncsi_pkt_input_sma, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_EBF, "EBF",
+ ncsi_pkt_input_ebf, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_DBF, "DBF",
+ ncsi_pkt_input_default, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_EGMF, "EGMF",
+ ncsi_pkt_input_egmf, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_DGMF, "DGMF",
+ ncsi_pkt_input_default, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_SNFC, "SNFC",
+ ncsi_pkt_input_snfc, ncsi_pkt_output_default },
+ { NCSI_PKT_CMD_GVI, "GVI",
+ ncsi_pkt_input_default, ncsi_pkt_output_gvi },
+ { NCSI_PKT_CMD_GC, "GC",
+ ncsi_pkt_input_default, ncsi_pkt_output_gc },
+ { NCSI_PKT_CMD_GP, "GP",
+ ncsi_pkt_input_default, ncsi_pkt_output_gp },
+ { NCSI_PKT_CMD_GCPS, "GCPS",
+ ncsi_pkt_input_default, ncsi_pkt_output_gcps },
+ { NCSI_PKT_CMD_GNS, "GNS",
+ ncsi_pkt_input_default, ncsi_pkt_output_gns },
+ { NCSI_PKT_CMD_GNPTS, "GNPTS",
+ ncsi_pkt_input_default, ncsi_pkt_output_gnpts },
+ { NCSI_PKT_CMD_GPS, "GPS",
+ ncsi_pkt_input_default, ncsi_pkt_output_gps },
+ { NCSI_PKT_CMD_OEM, "OEM",
+ NULL, NULL },
+ { NCSI_PKT_CMD_PLDM, "PLDM",
+ NULL, NULL },
+ { NCSI_PKT_CMD_GPUUID, "GPUUID",
+ ncsi_pkt_input_default, ncsi_pkt_output_gpuuid },
+};
+
+static int ncsi_dev_pkt_seq_show(struct seq_file *seq, void *v)
+{
+ struct ncsi_dev_priv *ndp = seq->private;
+ const struct ncsi_pkt_handler *h = NULL;
+ struct ncsi_pkt_hdr *hdr;
+ struct sk_buff *skb;
+ int i, errno;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ndp->lock, flags);
+ errno = ndp->pkt.errno;
+ skb = ndp->pkt.rsp;
+ ndp->pkt.rsp = NULL;
+ spin_unlock_irqrestore(&ndp->lock, flags);
+ ncsi_dev_reset_debug_pkt(ndp, NULL, 0);
+
+ if (errno) {
+ WARN_ON(skb);
+ seq_printf(seq, "Error %d receiving response packet\n", errno);
+ return 0;
+ } else if (!skb) {
+ seq_puts(seq, "No available response packet\n");
+ return 0;
+ }
+
+ hdr = (struct ncsi_pkt_hdr *)skb_network_header(skb);
+ for (i = 0; i < ARRAY_SIZE(ncsi_pkt_handlers); i++) {
+ if (ncsi_pkt_handlers[i].type == (hdr->type - 0x80)) {
+ h = &ncsi_pkt_handlers[i];
+ break;
+ }
+ }
+
+ if (!h || !h->output) {
+ consume_skb(skb);
+ return 0;
+ }
+
+ h->output(ndp, seq, skb);
+ return 0;
+}
+
+static int ncsi_dev_pkt_seq_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ncsi_dev_pkt_seq_show, inode->i_private);
+}
+
+static ssize_t ncsi_dev_pkt_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *pos)
+{
+ struct seq_file *seq = file->private_data;
+ struct ncsi_dev_priv *ndp = seq->private;
+ struct ncsi_cmd_arg nca;
+ char buf[64], name[64], *pbuf;
+ const struct ncsi_pkt_handler *h;
+ int num, package, channel, i, ret;
+ unsigned long flags;
+
+ if (count >= sizeof(buf))
+ return -EINVAL;
+
+ /* Copy the buffer from user space. Currently we have 64 bytes as
+ * the length limitation. It should be enough as there are no bunch
+ * of parameters to be specified when sending NCSI command packet.
+ */
+ memset(buf, 0, sizeof(buf));
+ if (copy_from_user(buf, buffer, count))
+ return -EFAULT;
+
+ /* Extract the specified command */
+ memset(name, 0, sizeof(name));
+ pbuf = strchr(buf, ',');
+ if (!pbuf)
+ return -EINVAL;
+ memcpy(name, buf, pbuf - buf);
+ pbuf++;
+
+ /* Extract mandatory parameters: package and channel ID */
+ memset(&nca, 0, sizeof(struct ncsi_cmd_arg));
+ if (sscanf(pbuf, "%x,%x%n", &package, &channel, &num) != 2)
+ return -EINVAL;
+ if (package < 0 || package >= 8 ||
+ channel < 0 || channel > NCSI_RESERVED_CHANNEL)
+ return -EINVAL;
+
+ nca.package = package;
+ nca.channel = channel;
+ if (pbuf[num] == ',')
+ pbuf += (count + 1);
+ else
+ pbuf += count;
+
+ /* Search for handler */
+ h = NULL;
+ for (i = 0; i < ARRAY_SIZE(ncsi_pkt_handlers); i++) {
+ if (!strcmp(ncsi_pkt_handlers[i].name, name)) {
+ h = &ncsi_pkt_handlers[i];
+ nca.type = h->type;
+ break;
+ }
+ }
+
+ if (!h || !h->input)
+ return -ERANGE;
+
+ /* Sort out additional parameters */
+ nca.ndp = ndp;
+ nca.req_flags = NCSI_REQ_FLAG_DEBUG;
+ ret = h->input(ndp, &nca, pbuf);
+ if (ret)
+ return ret;
+
+ /* This interface works in serialized fashion, meaning new command
+ * cannot be sent until previous one has been finalized.
+ */
+ spin_lock_irqsave(&ndp->lock, flags);
+ if (ndp->pkt.req != NCSI_PKT_REQ_FREE) {
+ spin_unlock_irqrestore(&ndp->lock, flags);
+ return -EBUSY;
+ }
+
+ ndp->pkt.req = NCSI_PKT_REQ_BUSY;
+ spin_unlock_irqrestore(&ndp->lock, flags);
+
+ ret = ncsi_xmit_cmd(&nca);
+ if (ret) {
+ spin_lock_irqsave(&ndp->lock, flags);
+ ndp->pkt.req = NCSI_PKT_REQ_FREE;
+ spin_unlock_irqrestore(&ndp->lock, flags);
+ return ret;
+ }
+
+ return count;
+}
+
+static const struct file_operations ncsi_dev_pkt_fops = {
+ .owner = THIS_MODULE,
+ .open = ncsi_dev_pkt_seq_open,
+ .read = seq_read,
+ .write = ncsi_dev_pkt_seq_write,
+ .llseek = seq_lseek,
+ .release = seq_release,
};
static bool ncsi_dev_stats_index(struct ncsi_dev_priv *ndp, loff_t pos,
@@ -282,6 +893,14 @@ int ncsi_dev_init_debug(struct ncsi_dev_priv *ndp)
return -ENOMEM;
}
+ ndp->pkt.dentry = debugfs_create_file("pkt", 0600, ndp->dentry,
+ ndp, &ncsi_dev_pkt_fops);
+ if (!ndp->pkt.dentry) {
+ pr_debug("Failed to create debugfs file 'ncsi/%s/pkt'\n",
+ netdev_name(ndp->ndev.dev));
+ return -ENOMEM;
+ }
+
return 0;
}
@@ -299,8 +918,26 @@ void ncsi_dev_update_stats(struct ncsi_dev_priv *ndp,
ndp->stats.cmd[type][errno]++;
}
+void ncsi_dev_reset_debug_pkt(struct ncsi_dev_priv *ndp,
+ struct sk_buff *skb, int errno)
+{
+ unsigned long flags;
+ struct sk_buff *old;
+
+ spin_lock_irqsave(&ndp->lock, flags);
+ ndp->pkt.req = NCSI_PKT_REQ_FREE;
+ ndp->pkt.errno = errno;
+
+ old = ndp->pkt.rsp;
+ ndp->pkt.rsp = skb;
+ spin_unlock_irqrestore(&ndp->lock, flags);
+
+ consume_skb(old);
+}
+
void ncsi_dev_release_debug(struct ncsi_dev_priv *ndp)
{
+ debugfs_remove(ndp->pkt.dentry);
debugfs_remove(ndp->stats.dentry);
debugfs_remove(ndp->dentry);
}
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index be7d907..84c3d8e 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -545,6 +545,8 @@ static void ncsi_request_timeout(unsigned long data)
hdr = (struct ncsi_pkt_hdr *)skb_network_header(nr->cmd);
ncsi_dev_update_stats(ndp, hdr->type, 0, NCSI_PKT_STAT_TIMEOUT);
+ if (ncsi_dev_is_debug_pkt(ndp, nr))
+ ncsi_dev_reset_debug_pkt(ndp, NULL, -ETIMEDOUT);
/* Release the request */
ncsi_free_request(nr);
diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index a164eb1..24154fc 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -1029,10 +1029,19 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
ret = ncsi_validate_rsp_pkt(nr, payload);
if (ret) {
ncsi_dev_update_stats(ndp, hdr->type, 0, NCSI_PKT_STAT_ERROR);
+ if (ncsi_dev_is_debug_pkt(ndp, nr))
+ ncsi_dev_reset_debug_pkt(ndp, NULL, -EINVAL);
goto out;
}
/* Process the packet */
+ if (ncsi_dev_is_debug_pkt(ndp, nr)) {
+ ncsi_dev_update_stats(ndp, hdr->type, 0, NCSI_PKT_STAT_OK);
+ ncsi_dev_reset_debug_pkt(ndp, nr->rsp, 0);
+ nr->rsp = NULL;
+ goto out;
+ }
+
ret = nrh->handler(nr);
if (ret)
ncsi_dev_update_stats(ndp, hdr->type, 0, NCSI_PKT_STAT_ERROR);
--
2.7.4
^ permalink raw reply related
* [PATCH v3 net-next 0/8] net/ncsi: Add debugging functionality
From: Gavin Shan @ 2017-04-18 6:51 UTC (permalink / raw)
To: netdev; +Cc: joe, kubakici, davem, Gavin Shan
This series supports NCSI debugging infrastructure by adding several
debugfs files. It was inspired by the reported issues: No available
package and channel are probed successfully. Obviously, we don't
have a debugging infrastructure for NCSI stack yet.
The first 3 patches, fixing some issues, aren't relevant to the
subject. I included them because I expect they can be merged beofre
the code for debugging infrastructure. PATCH[4,5,6/8] adds debugfs
directories and files to support the debugging infrastructure for
several purposes: presenting the NCSI topology; statistics on sent
and received NCSI packets; generate NCSI command packet manually.
PATCH[7,8/8] fixes two issues found from the debugging functionality.
Changelog
=========
v3:
* Use pr_debug() instead of pr_warn() upon failure to create
debugfs directory or file (Joe Perches)
* Use relative debugfs path/file names in debug messages in
ncsi-debug.c (Joe Perches)
* Use const specifier for @ncsi_pkt_handlers and @ranges (Joe Perches)
* Eliminate CONFIG_NET_NCSI_DEBUG ifdef's in *.c (Jakub Kicinski)
v2:
* Use debugfs instead of procfs (Joe Perches)
Gavin Shan (8):
net/ncsi: Disable HWA mode when no channels are found
net/ncsi: Properly track channel monitor timer state
net/ncsi: Enforce failover on link monitor timeout
net/ncsi: Add debugging infrastructurre
net/ncsi: Dump NCSI packet statistics
net/ncsi: Support NCSI packet generation
net/ncsi: No error report on DP response to non-existing package
net/ncsi: Fix length of GVI response packet
net/ncsi/Kconfig | 9 +
net/ncsi/Makefile | 1 +
net/ncsi/internal.h | 105 ++++++
net/ncsi/ncsi-aen.c | 13 +-
net/ncsi/ncsi-cmd.c | 13 +-
net/ncsi/ncsi-debug.c | 992 +++++++++++++++++++++++++++++++++++++++++++++++++
net/ncsi/ncsi-manage.c | 58 ++-
net/ncsi/ncsi-rsp.c | 24 +-
8 files changed, 1203 insertions(+), 12 deletions(-)
create mode 100644 net/ncsi/ncsi-debug.c
--
2.7.4
^ permalink raw reply
* [PATCH v3 net-next 1/8] net/ncsi: Disable HWA mode when no channels are found
From: Gavin Shan @ 2017-04-18 6:51 UTC (permalink / raw)
To: netdev; +Cc: joe, kubakici, davem, Gavin Shan
In-Reply-To: <1492498295-14385-1-git-send-email-gwshan@linux.vnet.ibm.com>
When there are no NCSI channels probed, HWA (Hardware Arbitration)
mode is enabled. It's not correct because HWA depends on the fact:
NCSI channels exist and all of them support HWA mode. This disables
HWA when no channels are probed.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
net/ncsi/ncsi-manage.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index a3bd5fa..5073e15 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -839,12 +839,15 @@ static bool ncsi_check_hwa(struct ncsi_dev_priv *ndp)
struct ncsi_package *np;
struct ncsi_channel *nc;
unsigned int cap;
+ bool has_channel = false;
/* The hardware arbitration is disabled if any one channel
* doesn't support explicitly.
*/
NCSI_FOR_EACH_PACKAGE(ndp, np) {
NCSI_FOR_EACH_CHANNEL(np, nc) {
+ has_channel = true;
+
cap = nc->caps[NCSI_CAP_GENERIC].cap;
if (!(cap & NCSI_CAP_GENERIC_HWA) ||
(cap & NCSI_CAP_GENERIC_HWA_MASK) !=
@@ -855,8 +858,13 @@ static bool ncsi_check_hwa(struct ncsi_dev_priv *ndp)
}
}
- ndp->flags |= NCSI_DEV_HWA;
- return true;
+ if (has_channel) {
+ ndp->flags |= NCSI_DEV_HWA;
+ return true;
+ }
+
+ ndp->flags &= ~NCSI_DEV_HWA;
+ return false;
}
static int ncsi_enable_hwa(struct ncsi_dev_priv *ndp)
--
2.7.4
^ permalink raw reply related
* [PATCH v3 net-next 3/8] net/ncsi: Enforce failover on link monitor timeout
From: Gavin Shan @ 2017-04-18 6:51 UTC (permalink / raw)
To: netdev; +Cc: joe, kubakici, davem, Gavin Shan
In-Reply-To: <1492498295-14385-1-git-send-email-gwshan@linux.vnet.ibm.com>
The NCSI channel has been configured to provide service if its link
monitor timer is enabled, regardless of its state (inactive or active).
So the timeout event on the link monitor indicates the out-of-service
on that channel, for which a failover is needed.
This sets NCSI_DEV_RESHUFFLE flag to enforce failover on link monitor
timeout, regardless the channel's original state (inactive or active).
Also, the link is put into "down" state to give the failing channel
lowest priority when selecting for the active channel. The state of
failing channel should be set to active in order for deinitialization
and failover to be done.
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
net/ncsi/ncsi-manage.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index c71a3a5..13ad1f26 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -170,6 +170,7 @@ static void ncsi_channel_monitor(unsigned long data)
struct ncsi_channel *nc = (struct ncsi_channel *)data;
struct ncsi_package *np = nc->package;
struct ncsi_dev_priv *ndp = np->ndp;
+ struct ncsi_channel_mode *ncm;
struct ncsi_cmd_arg nca;
bool enabled, chained;
unsigned int monitor_state;
@@ -214,20 +215,21 @@ static void ncsi_channel_monitor(unsigned long data)
case NCSI_CHANNEL_MONITOR_WAIT ... NCSI_CHANNEL_MONITOR_WAIT_MAX:
break;
default:
- if (!(ndp->flags & NCSI_DEV_HWA) &&
- state == NCSI_CHANNEL_ACTIVE) {
+ if (!(ndp->flags & NCSI_DEV_HWA)) {
ncsi_report_link(ndp, true);
ndp->flags |= NCSI_DEV_RESHUFFLE;
}
+ ncm = &nc->modes[NCSI_MODE_LINK];
spin_lock_irqsave(&nc->lock, flags);
nc->state = NCSI_CHANNEL_INVISIBLE;
+ ncm->data[2] &= ~0x1;
spin_unlock_irqrestore(&nc->lock, flags);
ncsi_stop_channel_monitor(nc);
spin_lock_irqsave(&ndp->lock, flags);
- nc->state = NCSI_CHANNEL_INACTIVE;
+ nc->state = NCSI_CHANNEL_ACTIVE;
list_add_tail_rcu(&nc->link, &ndp->channel_queue);
spin_unlock_irqrestore(&ndp->lock, flags);
ncsi_process_next_channel(ndp);
--
2.7.4
^ permalink raw reply related
* [PATCH v3 net-next 2/8] net/ncsi: Properly track channel monitor timer state
From: Gavin Shan @ 2017-04-18 6:51 UTC (permalink / raw)
To: netdev; +Cc: joe, kubakici, davem, Gavin Shan
In-Reply-To: <1492498295-14385-1-git-send-email-gwshan@linux.vnet.ibm.com>
The field @monitor.enabled in the NCSI channel descriptor is used
to track the state of channel monitor timer. It indicates the timer's
state (pending or not). We could not start the timer again in its
handler. In that case, We missed to update @monitor.enabled to false.
It leads to below warning printed by WARN_ON_ONCE() when the monitor
is restarted afterwards.
------------[ cut here ]------------
WARNING: CPU: 0 PID: 411 at /var/lib/jenkins/workspace/openbmc-build \
/distro/ubuntu/target/palmetto/openbmc/build/tmp/work-shared/palmetto \
net/ncsi/ncsi-manage.c:240 ncsi_start_channel_monitor+0x44/0x7c
CPU: 0 PID: 411 Comm: kworker/0:3 Not tainted \
4.7.10-f26558191540830589fe03932d05577957670b8d #1
Hardware name: ASpeed SoC
Workqueue: events ncsi_dev_work
[<c0106cbc>] (unwind_backtrace) from [<c0104f04>] (show_stack+0x10/0x14)
[<c0104f04>] (show_stack) from [<c010eef8>] (__warn+0xc4/0xf0)
[<c010eef8>] (__warn) from [<c010f018>] (warn_slowpath_null+0x1c/0x24)
[<c010f018>] (warn_slowpath_null) from [<c03e1d10>] (ncsi_start_channel_monitor+0x44/0x7c)
[<c03e1d10>] (ncsi_start_channel_monitor) from [<c03e29c4>] (ncsi_configure_channel+0x27c/0x2dc)
[<c03e29c4>] (ncsi_configure_channel) from [<c03e31d0>] (ncsi_dev_work+0x39c/0x3e8)
[<c03e31d0>] (ncsi_dev_work) from [<c0120288>] (process_one_work+0x1b8/0x2fc)
[<c0120288>] (process_one_work) from [<c01206bc>] (worker_thread+0x2c0/0x3f8)
[<c01206bc>] (worker_thread) from [<c0124b10>] (kthread+0xd0/0xe8)
[<c0124b10>] (kthread) from [<c0102250>] (ret_from_fork+0x14/0x24)
---[ end trace 110cccf2b038c44d ]---
This fixes the issue by updating @monitor.enabled to false if needed.
Reported-by: Sridevi Ramesh <sridevra@in.ibm.com>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
net/ncsi/ncsi-manage.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index 5073e15..c71a3a5 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -183,11 +183,16 @@ static void ncsi_channel_monitor(unsigned long data)
monitor_state = nc->monitor.state;
spin_unlock_irqrestore(&nc->lock, flags);
- if (!enabled || chained)
+ if (!enabled || chained) {
+ ncsi_stop_channel_monitor(nc);
return;
+ }
+
if (state != NCSI_CHANNEL_INACTIVE &&
- state != NCSI_CHANNEL_ACTIVE)
+ state != NCSI_CHANNEL_ACTIVE) {
+ ncsi_stop_channel_monitor(nc);
return;
+ }
switch (monitor_state) {
case NCSI_CHANNEL_MONITOR_START:
@@ -199,6 +204,7 @@ static void ncsi_channel_monitor(unsigned long data)
nca.req_flags = 0;
ret = ncsi_xmit_cmd(&nca);
if (ret) {
+ ncsi_stop_channel_monitor(nc);
netdev_err(ndp->ndev.dev, "Error %d sending GLS\n",
ret);
return;
@@ -218,6 +224,8 @@ static void ncsi_channel_monitor(unsigned long data)
nc->state = NCSI_CHANNEL_INVISIBLE;
spin_unlock_irqrestore(&nc->lock, flags);
+ ncsi_stop_channel_monitor(nc);
+
spin_lock_irqsave(&ndp->lock, flags);
nc->state = NCSI_CHANNEL_INACTIVE;
list_add_tail_rcu(&nc->link, &ndp->channel_queue);
@@ -257,6 +265,10 @@ void ncsi_stop_channel_monitor(struct ncsi_channel *nc)
nc->monitor.enabled = false;
spin_unlock_irqrestore(&nc->lock, flags);
+ /* The timer isn't in pending state if we're deleting the timer
+ * in its handler. del_timer_sync() can detect it and just does
+ * nothing.
+ */
del_timer_sync(&nc->monitor.timer);
}
--
2.7.4
^ permalink raw reply related
* [PATCH v3 net-next 4/8] net/ncsi: Add debugging infrastructurre
From: Gavin Shan @ 2017-04-18 6:51 UTC (permalink / raw)
To: netdev; +Cc: joe, kubakici, davem, Gavin Shan
In-Reply-To: <1492498295-14385-1-git-send-email-gwshan@linux.vnet.ibm.com>
This creates debugfs directories as NCSI debugging infrastructure.
With the patch applied, We will see below debugfs directories. Every
NCSI package and channel has one corresponding directory. Other than
presenting the NCSI topology, No real function has been achieved
through these debugfs directories so far.
/sys/kernel/debug/ncsi/eth0
/sys/kernel/debug/ncsi/eth0/p0
/sys/kernel/debug/ncsi/eth0/p0/c0
/sys/kernel/debug/ncsi/eth0/p0/c1
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
net/ncsi/Kconfig | 9 +++++
net/ncsi/Makefile | 1 +
net/ncsi/internal.h | 45 +++++++++++++++++++++
net/ncsi/ncsi-debug.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++
net/ncsi/ncsi-manage.c | 16 ++++++++
5 files changed, 174 insertions(+)
create mode 100644 net/ncsi/ncsi-debug.c
diff --git a/net/ncsi/Kconfig b/net/ncsi/Kconfig
index 08a8a60..baa42501 100644
--- a/net/ncsi/Kconfig
+++ b/net/ncsi/Kconfig
@@ -10,3 +10,12 @@ config NET_NCSI
support. Enable this only if your system connects to a network
device via NCSI and the ethernet driver you're using supports
the protocol explicitly.
+
+config NET_NCSI_DEBUG
+ bool "Enable NCSI debugging"
+ depends on NET_NCSI && DEBUG_FS
+ default n
+ ---help---
+ This enables the interfaces (e.g. debugfs) for NCSI debugging purpose.
+
+ If unsure, say Y.
diff --git a/net/ncsi/Makefile b/net/ncsi/Makefile
index dd12b56..2897fa0 100644
--- a/net/ncsi/Makefile
+++ b/net/ncsi/Makefile
@@ -2,3 +2,4 @@
# Makefile for NCSI API
#
obj-$(CONFIG_NET_NCSI) += ncsi-cmd.o ncsi-rsp.o ncsi-aen.o ncsi-manage.o
+obj-$(CONFIG_NET_NCSI_DEBUG) += ncsi-debug.o
diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index 1308a56..e9ede4f 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -198,6 +198,9 @@ struct ncsi_channel {
} monitor;
struct list_head node;
struct list_head link;
+#ifdef CONFIG_NET_NCSI_DEBUG
+ struct dentry *dentry; /* Debugfs directory */
+#endif
};
struct ncsi_package {
@@ -208,6 +211,9 @@ struct ncsi_package {
unsigned int channel_num; /* Number of channels */
struct list_head channels; /* List of chanels */
struct list_head node; /* Form list of packages */
+#ifdef CONFIG_NET_NCSI_DEBUG
+ struct dentry *dentry; /* Debugfs directory */
+#endif
};
struct ncsi_request {
@@ -276,6 +282,9 @@ struct ncsi_dev_priv {
struct work_struct work; /* For channel management */
struct packet_type ptype; /* NCSI packet Rx handler */
struct list_head node; /* Form NCSI device list */
+#ifdef CONFIG_NET_NCSI_DEBUG
+ struct dentry *dentry; /* Procfs directory */
+#endif
};
struct ncsi_cmd_arg {
@@ -337,4 +346,40 @@ int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev);
int ncsi_aen_handler(struct ncsi_dev_priv *ndp, struct sk_buff *skb);
+/* Debugging functionality */
+#ifdef CONFIG_NET_NCSI_DEBUG
+int ncsi_dev_init_debug(struct ncsi_dev_priv *ndp);
+void ncsi_dev_release_debug(struct ncsi_dev_priv *ndp);
+int ncsi_package_init_debug(struct ncsi_package *np);
+void ncsi_package_release_debug(struct ncsi_package *np);
+int ncsi_channel_init_debug(struct ncsi_channel *nc);
+void ncsi_channel_release_debug(struct ncsi_channel *nc);
+#else
+static inline int ncsi_dev_init_debug(struct ncsi_dev_priv *ndp)
+{
+ return -ENOTTY;
+}
+
+static inline void ncsi_dev_release_debug(struct ncsi_dev_priv *ndp)
+{
+}
+
+static inline int ncsi_package_init_debug(struct ncsi_package *np)
+{
+ return -ENOTTY;
+}
+
+static inline void ncsi_package_release_debug(struct ncsi_package *np)
+{
+}
+
+static inline int ncsi_channel_init_debug(struct ncsi_channel *nc)
+{
+ return -ENOTTY;
+}
+
+static inline void ncsi_channel_release_debug(struct ncsi_channel *nc)
+{
+}
+#endif /* CONFIG_NET_NCSI_DEBUG */
#endif /* __NCSI_INTERNAL_H__ */
diff --git a/net/ncsi/ncsi-debug.c b/net/ncsi/ncsi-debug.c
new file mode 100644
index 0000000..f38483d
--- /dev/null
+++ b/net/ncsi/ncsi-debug.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright Gavin Shan, IBM Corporation 2017.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/atomic.h>
+#include <linux/netdevice.h>
+#include <linux/debugfs.h>
+#include <linux/skbuff.h>
+
+#include <net/ncsi.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+
+#include "internal.h"
+#include "ncsi-pkt.h"
+
+static struct dentry *ncsi_dentry;
+
+int ncsi_dev_init_debug(struct ncsi_dev_priv *ndp)
+{
+ if (WARN_ON_ONCE(ndp->dentry))
+ return 0;
+
+ if (!ncsi_dentry) {
+ ncsi_dentry = debugfs_create_dir("ncsi", NULL);
+ if (!ncsi_dentry) {
+ pr_debug("Failed to create debugfs directory 'ncsi'\n");
+ return -ENOMEM;
+ }
+ }
+
+ ndp->dentry = debugfs_create_dir(netdev_name(ndp->ndev.dev),
+ ncsi_dentry);
+ if (!ndp->dentry) {
+ pr_debug("Failed to create debugfs directory 'ncsi/%s'\n",
+ netdev_name(ndp->ndev.dev));
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void ncsi_dev_release_debug(struct ncsi_dev_priv *ndp)
+{
+ debugfs_remove(ndp->dentry);
+}
+
+int ncsi_package_init_debug(struct ncsi_package *np)
+{
+ struct ncsi_dev_priv *ndp = np->ndp;
+ char name[4];
+
+ if (!ndp->dentry)
+ return -ENOENT;
+
+ sprintf(name, "p%d", np->id);
+ np->dentry = debugfs_create_dir(name, ndp->dentry);
+ if (!np->dentry) {
+ pr_debug("Failed to create debugfs directory ncsi/%s/%s\n",
+ netdev_name(ndp->ndev.dev), name);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void ncsi_package_release_debug(struct ncsi_package *np)
+{
+ debugfs_remove(np->dentry);
+}
+
+int ncsi_channel_init_debug(struct ncsi_channel *nc)
+{
+ struct ncsi_package *np = nc->package;
+ struct ncsi_dev_priv *ndp = np->ndp;
+ char name[3];
+
+ if (!np->dentry)
+ return -ENOENT;
+
+ sprintf(name, "c%d", nc->id);
+ nc->dentry = debugfs_create_dir(name, np->dentry);
+ if (!nc->dentry) {
+ pr_debug("Failed to create debugfs directory ncsi/%s/p%d/c%d\n",
+ netdev_name(ndp->ndev.dev), np->id, nc->id);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void ncsi_channel_release_debug(struct ncsi_channel *nc)
+{
+ debugfs_remove(nc->dentry);
+}
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index 13ad1f26..84f1405 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -322,6 +322,8 @@ struct ncsi_channel *ncsi_add_channel(struct ncsi_package *np, unsigned char id)
np->channel_num++;
spin_unlock_irqrestore(&np->lock, flags);
+ ncsi_channel_init_debug(nc);
+
return nc;
}
@@ -332,6 +334,8 @@ static void ncsi_remove_channel(struct ncsi_channel *nc)
unsigned long flags;
int i;
+ ncsi_channel_release_debug(nc);
+
/* Release filters */
spin_lock_irqsave(&nc->lock, flags);
for (i = 0; i < NCSI_FILTER_MAX; i++) {
@@ -396,6 +400,8 @@ struct ncsi_package *ncsi_add_package(struct ncsi_dev_priv *ndp,
ndp->package_num++;
spin_unlock_irqrestore(&ndp->lock, flags);
+ ncsi_package_init_debug(np);
+
return np;
}
@@ -409,6 +415,8 @@ void ncsi_remove_package(struct ncsi_package *np)
list_for_each_entry_safe(nc, tmp, &np->channels, node)
ncsi_remove_channel(nc);
+ ncsi_package_release_debug(np);
+
/* Remove and free package */
spin_lock_irqsave(&ndp->lock, flags);
list_del_rcu(&np->node);
@@ -1280,6 +1288,13 @@ int ncsi_start_dev(struct ncsi_dev *nd)
return -ENOTTY;
if (!(ndp->flags & NCSI_DEV_PROBED)) {
+ /* The debugging functionality should have been initialized
+ * when registerring the NCSI device. As the network device
+ * name isn't available that time, we have to delay the work
+ * to here.
+ */
+ ncsi_dev_init_debug(ndp);
+
nd->state = ncsi_dev_state_probe;
schedule_work(&ndp->work);
return 0;
@@ -1329,6 +1344,7 @@ void ncsi_unregister_dev(struct ncsi_dev *nd)
struct ncsi_package *np, *tmp;
unsigned long flags;
+ ncsi_dev_release_debug(ndp);
dev_remove_pack(&ndp->ptype);
list_for_each_entry_safe(np, tmp, &ndp->packages, node)
--
2.7.4
^ permalink raw reply related
* Re: [PATCH 05/22] drm/i915: Make use of the new sg_map helper function
From: Daniel Vetter @ 2017-04-18 6:44 UTC (permalink / raw)
To: Logan Gunthorpe
Cc: Steve Wise, linux-nvme, Stephen Bates, target-devel, Sumit Semwal,
devel, rds-devel, Sagi Grimberg, linux-scsi, Matthew Wilcox,
linux-rdma, Christoph Hellwig, fcoe-devel, Ross Zwisler,
open-iscsi, linux-media, Ming Lin, intel-gfx, sparmaintainer,
linux-raid, dri-devel, Dan Williams, megaraidlinux.pdl,
Jens Axboe, linaro-mm-sig, Martin K. Petersen, Greg
In-Reply-To: <1492121135-4437-6-git-send-email-logang@deltatee.com>
On Thu, Apr 13, 2017 at 04:05:18PM -0600, Logan Gunthorpe wrote:
> This is a single straightforward conversion from kmap to sg_map.
>
> Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Probably makes sense to merge through some other tree, but please be aware
of the considerable churn rate in i915 (i.e. make sure your tree is in
linux-next before you send a pull request for this). Plane B would be to
get the prep patch in first and then merge the i915 conversion one kernel
release later.
-Daniel
> ---
> drivers/gpu/drm/i915/i915_gem.c | 27 ++++++++++++++++-----------
> 1 file changed, 16 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 67b1fc5..1b1b91a 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -2188,6 +2188,15 @@ static void __i915_gem_object_reset_page_iter(struct drm_i915_gem_object *obj)
> radix_tree_delete(&obj->mm.get_page.radix, iter.index);
> }
>
> +static void i915_gem_object_unmap(const struct drm_i915_gem_object *obj,
> + void *ptr)
> +{
> + if (is_vmalloc_addr(ptr))
> + vunmap(ptr);
> + else
> + sg_unmap(obj->mm.pages->sgl, ptr, SG_KMAP);
> +}
> +
> void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj,
> enum i915_mm_subclass subclass)
> {
> @@ -2215,10 +2224,7 @@ void __i915_gem_object_put_pages(struct drm_i915_gem_object *obj,
> void *ptr;
>
> ptr = ptr_mask_bits(obj->mm.mapping);
> - if (is_vmalloc_addr(ptr))
> - vunmap(ptr);
> - else
> - kunmap(kmap_to_page(ptr));
> + i915_gem_object_unmap(obj, ptr);
>
> obj->mm.mapping = NULL;
> }
> @@ -2475,8 +2481,11 @@ static void *i915_gem_object_map(const struct drm_i915_gem_object *obj,
> void *addr;
>
> /* A single page can always be kmapped */
> - if (n_pages == 1 && type == I915_MAP_WB)
> - return kmap(sg_page(sgt->sgl));
> + if (n_pages == 1 && type == I915_MAP_WB) {
> + addr = sg_map(sgt->sgl, SG_KMAP);
> + if (IS_ERR(addr))
> + return NULL;
> + }
>
> if (n_pages > ARRAY_SIZE(stack_pages)) {
> /* Too big for stack -- allocate temporary array instead */
> @@ -2543,11 +2552,7 @@ void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj,
> goto err_unpin;
> }
>
> - if (is_vmalloc_addr(ptr))
> - vunmap(ptr);
> - else
> - kunmap(kmap_to_page(ptr));
> -
> + i915_gem_object_unmap(obj, ptr);
> ptr = obj->mm.mapping = NULL;
> }
>
> --
> 2.1.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* [PATCH] net/mlx4: suppress 'may be used uninitialized' warning
From: Greg Thelen @ 2017-04-18 6:21 UTC (permalink / raw)
To: Or Gerlitz, Jack Morgenstein, Matan Barak
Cc: Ido Shamay, Yishai Hadas, Amir Vadai, Roland Dreier,
David S. Miller, netdev-u79uwXL29TY76Z2rM5mHXA,
linux-rdma-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Greg Thelen
gcc 4.8.4 complains that mlx4_SW2HW_MPT_wrapper() uses an uninitialized
'mpt' variable:
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c: In function 'mlx4_SW2HW_MPT_wrapper':
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c:2802:12: warning: 'mpt' may be used uninitialized in this function [-Wmaybe-uninitialized]
mpt->mtt = mtt;
I think this warning is a false complaint. mpt is only used when
mr_res_start_move_to() return zero, and in all such cases it initializes
mpt. But apparently gcc cannot see that.
Initialize mpt to avoid the warning.
Signed-off-by: Greg Thelen <gthelen-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
---
drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index d8d5d161b8c7..4aa29ee93013 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -2749,7 +2749,7 @@ int mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave,
int err;
int index = vhcr->in_modifier;
struct res_mtt *mtt;
- struct res_mpt *mpt;
+ struct res_mpt *mpt = NULL;
int mtt_base = mr_get_mtt_addr(inbox->buf) / dev->caps.mtt_entry_sz;
int phys;
int id;
--
2.12.2.762.g0e3151a226-goog
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [PATCH RFC] sparc64: eBPF JIT
From: Alexei Starovoitov @ 2017-04-18 5:44 UTC (permalink / raw)
To: David Miller; +Cc: sparclinux, netdev, ast, daniel
In-Reply-To: <20170417.181245.1402412750148031248.davem@davemloft.net>
On Mon, Apr 17, 2017 at 06:12:45PM -0700, David Miller wrote:
> >
> >> + if (insn->src_reg == BPF_REG_FP || insn->dst_reg == BPF_REG_FP) {
> >> + ctx->saw_frame_pointer = true;
> >> + if (BPF_CLASS(code) == BPF_ALU ||
> >> + BPF_CLASS(code) == BPF_ALU64) {
> >> + pr_err_once("ALU op on FP not supported by JIT\n");
> >> + return -EINVAL;
> >
> > That should be fine. The verifier checks for that:
> > /* check whether register used as dest operand can be written to */
> > if (regno == BPF_REG_FP) {
> > verbose("frame pointer is read only\n");
> > return -EACCES;
> > }
>
> I need to trap it as a source as well, because if that is allowed then
> I have to add special handling to every ALU operation we allow.
>
> The reason is that the sparc64 stack is biased by 2047 bytes. So
> I have to adjust every FP relative reference to include that 2047
> bias.
>
> Can LLVM and CLANG emit arithmetic operations with FP as source?
The way llvm generates stack access is:
rX = r10
rX += imm
and that's the only thing verifier recognizes as valid ptr_to_stack.
Like rX -= imm will not be recognized as proper stack offset,
since llvm never does it.
I guess that counts as ALU on FP ?
Looks like we don't have such tests in test_bpf.ko. Hmm.
Pretty much all compiled C code should have such stack access.
The easiest test is tools/testing/selftests/bpf/test_progs
> >> + /* dst = imm64 */
> >> + case BPF_LD | BPF_IMM | BPF_DW:
> >> + {
> >> + const struct bpf_insn insn1 = insn[1];
> >> + u64 imm64;
> >> +
> >> + if (insn1.code != 0 || insn1.src_reg != 0 ||
> >> + insn1.dst_reg != 0 || insn1.off != 0) {
> >> + /* Note: verifier in BPF core must catch invalid
> >> + * instructions.
> >> + */
> >> + pr_err_once("Invalid BPF_LD_IMM64 instruction\n");
> >> + return -EINVAL;
> >
> > verifier should catch that too, but extra check doesn't hurt.
>
> I just copied from anoter JIT, I can remove it.
That check was added to x64 JIT, because JIT patches were submitted
before eBPF was known to user space. There was no verifier at that time.
So JIT had do some checking, just for sanity.
It's probably ok to remove it now... or leave it as-is as historical artifact.
^ permalink raw reply
* Re: [PATCH RFC] ptr_ring: add ptr_ring_unconsume
From: Jason Wang @ 2017-04-18 3:07 UTC (permalink / raw)
To: Michael S. Tsirkin, linux-kernel; +Cc: netdev
In-Reply-To: <1492384496-22644-1-git-send-email-mst@redhat.com>
On 2017年04月17日 07:19, Michael S. Tsirkin wrote:
> Applications that consume a batch of entries in one go
> can benefit from ability to return some of them back
> into the ring.
>
> Add an API for that - assuming there's space. If there's no space
> naturally we can't do this and have to drop entries, but this implies
> ring is full so we'd likely drop some anyway.
>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> ---
>
> Jason, in my mind the biggest issue with your batching patchset is the
> backet drops on disconnect. This API will help avoid that in the common
> case.
Ok, I will rebase the series on top of this. (Though I don't think we
care the packet loss).
>
> I would still prefer that we understand what's going on,
I try to reply in another thread, does it make sense?
> and I would
> like to know what's the smallest batch size that's still helpful,
Yes, I've replied in another thread, the result is:
no batching 1.88Mpps
RX_BATCH=1 1.93Mpps
RX_BATCH=4 2.11Mpps
RX_BATCH=16 2.14Mpps
RX_BATCH=64 2.25Mpps
RX_BATCH=256 2.18Mpps
> but
> I'm not going to block the patch on these grounds assuming packet drops
> are fixed.
Thanks a lot.
>
> Lightly tested - this is on top of consumer batching patches.
>
> Thanks!
>
> include/linux/ptr_ring.h | 57 ++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 57 insertions(+)
>
> diff --git a/include/linux/ptr_ring.h b/include/linux/ptr_ring.h
> index 783e7f5..5fbeab4 100644
> --- a/include/linux/ptr_ring.h
> +++ b/include/linux/ptr_ring.h
> @@ -457,6 +457,63 @@ static inline int ptr_ring_init(struct ptr_ring *r, int size, gfp_t gfp)
> return 0;
> }
>
> +/*
> + * Return entries into ring. Destroy entries that don't fit.
> + *
> + * Note: this is expected to be a rare slow path operation.
> + *
> + * Note: producer lock is nested within consumer lock, so if you
> + * resize you must make sure all uses nest correctly.
> + * In particular if you consume ring in interrupt or BH context, you must
> + * disable interrupts/BH when doing so.
> + */
> +static inline void ptr_ring_unconsume(struct ptr_ring *r, void **batch, int n,
> + void (*destroy)(void *))
> +{
> + unsigned long flags;
> + int head;
> +
> + spin_lock_irqsave(&(r)->consumer_lock, flags);
> + spin_lock(&(r)->producer_lock);
> +
> + if (!r->size)
> + goto done;
> +
> + /*
> + * Clean out buffered entries (for simplicity). This way following code
> + * can test entries for NULL and if not assume they are valid.
> + */
> + head = r->consumer_head - 1;
> + while (likely(head >= r->consumer_tail))
> + r->queue[head--] = NULL;
> + r->consumer_tail = r->consumer_head;
> +
> + /*
> + * Go over entries in batch, start moving head back and copy entries.
> + * Stop when we run into previously unconsumed entries.
> + */
> + while (n--) {
> + head = r->consumer_head - 1;
> + if (head < 0)
> + head = r->size - 1;
> + if (r->queue[head]) {
> + /* This batch entry will have to be destroyed. */
> + ++n;
> + goto done;
> + }
> + r->queue[head] = batch[n];
> + r->consumer_tail = r->consumer_head = head;
> + }
> +
> +done:
> + /* Destroy all entries left in the batch. */
> + while (n--) {
> + destroy(batch[n]);
> + }
> + spin_unlock(&(r)->producer_lock);
> + spin_unlock_irqrestore(&(r)->consumer_lock, flags);
> +}
> +
> static inline void **__ptr_ring_swap_queue(struct ptr_ring *r, void **queue,
> int size, gfp_t gfp,
> void (*destroy)(void *))
^ permalink raw reply
* linux-next: build failure after merge of the block tree
From: Stephen Rothwell @ 2017-04-18 3:02 UTC (permalink / raw)
To: Jens Axboe, David Miller, Networking
Cc: Linux-Next Mailing List, Linux Kernel Mailing List, Josef Bacik,
Johannes Berg
Hi all,
After merging the block tree, today's linux-next build (powerpc
ppc64_defconfig) failed like this:
drivers/block/nbd.c: In function 'nbd_genl_connect':
drivers/block/nbd.c:1662:10: error: too few arguments to function 'nla_parse_nested'
ret = nla_parse_nested(socks, NBD_SOCK_MAX, attr,
^
In file included from include/net/rtnetlink.h:5:0,
from include/net/sch_generic.h:12,
from include/linux/filter.h:20,
from include/net/sock.h:64,
from drivers/block/nbd.c:32:
include/net/netlink.h:754:19: note: declared here
static inline int nla_parse_nested(struct nlattr *tb[], int maxtype,
^
drivers/block/nbd.c: In function 'nbd_genl_reconfigure':
drivers/block/nbd.c:1818:10: error: too few arguments to function 'nla_parse_nested'
ret = nla_parse_nested(socks, NBD_SOCK_MAX, attr,
^
In file included from include/net/rtnetlink.h:5:0,
from include/net/sch_generic.h:12,
from include/linux/filter.h:20,
from include/net/sock.h:64,
from drivers/block/nbd.c:32:
include/net/netlink.h:754:19: note: declared here
static inline int nla_parse_nested(struct nlattr *tb[], int maxtype,
^
Caused by commits
e46c7287b1c2 ("nbd: add a basic netlink interface")
b7aa3d39385d ("nbd: add a reconfigure netlink command")
interacting with commit
fceb6435e852 ("netlink: pass extended ACK struct to parsing functions")
from the net-next tree.
I have applied the following merge fix patch:
From: Stephen Rothwell <sfr@canb.auug.org.au>
Date: Tue, 18 Apr 2017 12:59:05 +1000
Subject: [PATCH] nbd: fix up for nla_parse_nested() API change
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
drivers/block/nbd.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index b78f23ce2395..5049d19f3940 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -1660,7 +1660,7 @@ static int nbd_genl_connect(struct sk_buff *skb, struct genl_info *info)
goto out;
}
ret = nla_parse_nested(socks, NBD_SOCK_MAX, attr,
- nbd_sock_policy);
+ nbd_sock_policy, NULL);
if (ret != 0) {
printk(KERN_ERR "nbd: error processing sock list\n");
ret = -EINVAL;
@@ -1816,7 +1816,7 @@ static int nbd_genl_reconfigure(struct sk_buff *skb, struct genl_info *info)
goto out;
}
ret = nla_parse_nested(socks, NBD_SOCK_MAX, attr,
- nbd_sock_policy);
+ nbd_sock_policy, NULL);
if (ret != 0) {
printk(KERN_ERR "nbd: error processing sock list\n");
ret = -EINVAL;
--
2.11.0
--
Cheers,
Stephen Rothwell
^ permalink raw reply related
* Re: [PATCH RFC (resend) net-next 0/6] virtio-net: Add support for virtio-net header extensions
From: Jason Wang @ 2017-04-18 3:01 UTC (permalink / raw)
To: Vladislav Yasevich, netdev
Cc: virtualization, virtio-dev, mst, maxime.coquelin,
Vladislav Yasevich
In-Reply-To: <1492274298-17362-1-git-send-email-vyasevic@redhat.com>
On 2017年04月16日 00:38, Vladislav Yasevich wrote:
> Curreclty virtion net header is fixed size and adding things to it is rather
> difficult to do. This series attempt to add the infrastructure as well as some
> extensions that try to resolve some deficiencies we currently have.
>
> First, vnet header only has space for 16 flags. This may not be enough
> in the future. The extensions will provide space for 32 possbile extension
> flags and 32 possible extensions. These flags will be carried in the
> first pseudo extension header, the presense of which will be determined by
> the flag in the virtio net header.
>
> The extensions themselves will immidiately follow the extension header itself.
> They will be added to the packet in the same order as they appear in the
> extension flags. No padding is placed between the extensions and any
> extensions negotiated, but not used need by a given packet will convert to
> trailing padding.
Do we need a explicit padding (e.g an extension) which could be
controlled by each side?
>
> For example:
> | vnet mrg hdr | ext hdr | ext 1 | ext 2 | ext 5 | .. pad .. | packet data |
Just some rough thoughts:
- Is this better to use TLV instead of bitmap here? One advantage of TLV
is that the length is not limited by the length of bitmap.
- For 1.1, do we really want something like vnet header? AFAIK, it was
not used by modern NICs, is this better to pack all meta-data into
descriptor itself? This may need a some changes in tun/macvtap, but
looks more PCIE friendly.
Thanks
>
> Extensions proposed in this series are:
> - IPv6 fragment id extension
> * Currently, the guest generated fragment id is discarded and the host
> generates an IPv6 fragment id if the packet has to be fragmented. The
> code attempts to add time based perturbation to id generation to make
> it harder to guess the next fragment id to be used. However, doing this
> on the host may result is less perturbation (due to differnet timing)
> and might make id guessing easier. Ideally, the ids generated by the
> guest should be used. One could also argue that we a "violating" the
> IPv6 protocol in the if the _strict_ interpretation of the spec.
>
> - VLAN header acceleration
> * Currently virtio doesn't not do vlan header acceleration and instead
> uses software tagging. One of the first things that the host will do is
> strip the vlan header out. When passing the packet the a guest the
> vlan header is re-inserted in to the packet. We can skip all that work
> if we can pass the vlan data in accelearted format. Then the host will
> not do any extra work. However, so far, this yeilded a very small
> perf bump (only ~1%). I am still looking into this.
>
> - UDP tunnel offload
> * Similar to vlan acceleration, with this extension we can pass additional
> data to host for support GSO with udp tunnel and possible other
> encapsulations. This yeilds a significant perfromance improvement
> (still testing remote checksum code).
>
> An addition extension that is unfinished (due to still testing for any
> side-effects) is checksum passthrough to support drivers that set
> CHECKSUM_COMPLETE. This would eliminate the need for guests to compute
> the software checksum.
>
> This series only takes care of virtio net. I have addition patches for the
> host side (vhost and tap/macvtap as well as qemu), but wanted to get feedback
> on the general approach first.
>
> Vladislav Yasevich (6):
> virtio-net: Remove the use the padded vnet_header structure
> virtio-net: make header length handling uniform
> virtio_net: Add basic skeleton for handling vnet header extensions.
> virtio-net: Add support for IPv6 fragment id vnet header extension.
> virtio-net: Add support for vlan acceleration vnet header extension.
> virtio-net: Add support for UDP tunnel offload and extension.
>
> drivers/net/virtio_net.c | 132 +++++++++++++++++++++++++++++++++-------
> include/linux/skbuff.h | 5 ++
> include/linux/virtio_net.h | 91 ++++++++++++++++++++++++++-
> include/uapi/linux/virtio_net.h | 38 ++++++++++++
> 4 files changed, 242 insertions(+), 24 deletions(-)
>
^ permalink raw reply
* Re: [PATCH RFC (resend) net-next 5/6] virtio-net: Add support for vlan acceleration vnet header extension.
From: Jason Wang @ 2017-04-18 2:54 UTC (permalink / raw)
To: Vladislav Yasevich, netdev
Cc: virtualization, virtio-dev, mst, maxime.coquelin,
Vladislav Yasevich
In-Reply-To: <1492274298-17362-6-git-send-email-vyasevic@redhat.com>
On 2017年04月16日 00:38, Vladislav Yasevich wrote:
> This extension allows us to pass vlan ID and vlan protocol data to the
> host hypervisor as part of the vnet header and lets us take advantage
> of HW accelerated vlan tagging in the host. It requires support in the
> host to negotiate the feature. When the extension is enabled, the
> virtio device will enabled HW accelerated vlan features.
>
> Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
> ---
> drivers/net/virtio_net.c | 17 ++++++++++++++++-
> include/linux/virtio_net.h | 17 +++++++++++++++++
> include/uapi/linux/virtio_net.h | 7 +++++++
> 3 files changed, 40 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 18eb0dd..696ef4a 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -182,6 +182,7 @@ struct virtio_net_hdr_max {
> struct virtio_net_hdr_mrg_rxbuf hdr;
> struct virtio_net_ext_hdr ext_hdr;
> struct virtio_net_ext_ip6frag ip6f_ext;
> + struct virtio_net_ext_vlan vlan_ext;
> };
>
> static inline u8 padded_vnet_hdr(struct virtnet_info *vi)
> @@ -2276,6 +2277,11 @@ static void virtnet_init_extensions(struct virtio_device *vdev)
> vi->hdr_len += sizeof(u32);
> vi->ext_mask |= VIRTIO_NET_EXT_F_IP6FRAG;
> }
> +
> + if (virtio_has_feature(vdev, VIRTIO_NET_F_VLAN_OFFLOAD)) {
> + vi->hdr_len += sizeof(struct virtio_net_ext_vlan);
> + vi->ext_mask |= VIRTIO_NET_EXT_F_VLAN;
> + }
> }
>
> #define MIN_MTU ETH_MIN_MTU
> @@ -2352,6 +2358,14 @@ static int virtnet_probe(struct virtio_device *vdev)
> if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
> dev->features |= NETIF_F_RXCSUM;
>
> + if (virtio_has_feature(vdev, VIRTIO_NET_F_VLAN_OFFLOAD)) {
> + dev->features |= NETIF_F_HW_VLAN_CTAG_TX |
> + NETIF_F_HW_VLAN_CTAG_RX |
> + NETIF_F_HW_VLAN_STAG_TX |
> + NETIF_F_HW_VLAN_STAG_RX;
> + }
> +
> +
> dev->vlan_features = dev->features;
>
> /* MTU range: 68 - 65535 */
> @@ -2395,7 +2409,8 @@ static int virtnet_probe(struct virtio_device *vdev)
> if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
> vi->mergeable_rx_bufs = true;
>
> - if (virtio_has_feature(vdev, VIRTIO_NET_F_IP6_FRAGID))
> + if (virtio_has_feature(vdev, VIRTIO_NET_F_IP6_FRAGID) ||
> + virtio_has_feature(vdev, VIRTIO_NET_F_VLAN_OFFLOAD))
> vi->hdr_ext = true;
>
> if (vi->hdr_ext)
> diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
> index 3b259dc..e790191 100644
> --- a/include/linux/virtio_net.h
> +++ b/include/linux/virtio_net.h
> @@ -113,6 +113,14 @@ static inline int virtio_net_ext_to_skb(struct sk_buff *skb,
> ptr += sizeof(struct virtio_net_ext_ip6frag);
> }
>
> + if (ext->flags & VIRTIO_NET_EXT_F_VLAN) {
> + struct virtio_net_ext_vlan *vhdr =
> + (struct virtio_net_ext_vlan *)ptr;
> +
> + __vlan_hwaccel_put_tag(skb, vhdr->vlan_proto, vhdr->vlan_tci);
> + ptr += sizeof(struct virtio_net_ext_vlan);
> + }
> +
> return 0;
> }
>
> @@ -130,6 +138,15 @@ static inline int virtio_net_ext_from_skb(const struct sk_buff *skb,
> ext->flags |= VIRTIO_NET_EXT_F_IP6FRAG;
Looks like you need advance ptr here?
> }
>
> + if (ext_mask & VIRTIO_NET_EXT_F_VLAN && skb_vlan_tag_present(skb)) {
> + struct virtio_net_ext_vlan *vhdr =
> + (struct virtio_net_ext_vlan *)ptr;
> +
> + vlan_get_tag(skb, &vhdr->vlan_tci);
> + vhdr->vlan_proto = skb->vlan_proto;
> + ext->flags |= VIRTIO_NET_EXT_F_VLAN;
And here?
Thanks
> + }
> +
> return 0;
> }
> #endif /* _LINUX_VIRTIO_NET_H */
> diff --git a/include/uapi/linux/virtio_net.h b/include/uapi/linux/virtio_net.h
> index eac8d94..6125de7 100644
> --- a/include/uapi/linux/virtio_net.h
> +++ b/include/uapi/linux/virtio_net.h
> @@ -57,6 +57,7 @@
> * Steering */
> #define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */
> #define VIRTIO_NET_F_IP6_FRAGID 24 /* Host supports VLAN accleration */
> +#define VIRTIO_NET_F_VLAN_OFFLOAD 25 /* Host supports VLAN accleration */
>
> #ifndef VIRTIO_NET_NO_LEGACY
> #define VIRTIO_NET_F_GSO 6 /* Host handles pkts w/ any GSO type */
> @@ -111,6 +112,7 @@ struct virtio_net_hdr_v1 {
> */
> struct virtio_net_ext_hdr {
> #define VIRTIO_NET_EXT_F_IP6FRAG (1<<0)
> +#define VIRTIO_NET_EXT_F_VLAN (1<<1)
> __u32 flags;
> __u8 extensions[];
> };
> @@ -120,6 +122,11 @@ struct virtio_net_ext_ip6frag {
> __be32 frag_id;
> };
>
> +struct virtio_net_ext_vlan {
> + __be16 vlan_tci;
> + __be16 vlan_proto;
> +};
> +
> #ifndef VIRTIO_NET_NO_LEGACY
> /* This header comes first in the scatter-gather list.
> * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, it must
^ permalink raw reply
* Re: [PATCH RFC (resend) net-next 3/6] virtio_net: Add basic skeleton for handling vnet header extensions.
From: Jason Wang @ 2017-04-18 2:52 UTC (permalink / raw)
To: Vladislav Yasevich, netdev
Cc: virtualization, virtio-dev, mst, maxime.coquelin,
Vladislav Yasevich
In-Reply-To: <1492274298-17362-4-git-send-email-vyasevic@redhat.com>
On 2017年04月16日 00:38, Vladislav Yasevich wrote:
> This is the basic sceleton which will be fleshed out by individiual
> extensions.
>
> Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
> ---
> drivers/net/virtio_net.c | 21 +++++++++++++++++++++
> include/linux/virtio_net.h | 12 ++++++++++++
> include/uapi/linux/virtio_net.h | 11 +++++++++++
> 3 files changed, 44 insertions(+)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 5ad6ee6..08e2709 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -145,6 +145,10 @@ struct virtnet_info {
> /* Packet virtio header size */
> u8 hdr_len;
>
> + /* Header extensions were negotiated */
> + bool hdr_ext;
> + u32 ext_mask;
> +
> /* Active statistics */
> struct virtnet_stats __percpu *stats;
>
> @@ -174,6 +178,11 @@ struct virtnet_info {
> u32 speed;
> };
>
> +struct virtio_net_hdr_max {
> + struct virtio_net_hdr_mrg_rxbuf hdr;
> + struct virtio_net_ext_hdr ext_hdr;
> +};
> +
> static inline u8 padded_vnet_hdr(struct virtnet_info *vi)
> {
> u8 hdr_len = vi->hdr_len;
> @@ -214,6 +223,7 @@ static int rxq2vq(int rxq)
>
> static inline struct virtio_net_hdr_mrg_rxbuf *skb_vnet_hdr(struct sk_buff *skb)
> {
> + BUILD_BUG_ON(sizeof(struct virtio_net_hdr_max) > sizeof(skb->cb));
> return (struct virtio_net_hdr_mrg_rxbuf *)skb->cb;
> }
>
> @@ -767,6 +777,12 @@ static int receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
> goto frame_err;
> }
>
> + if (vi->hdr_ext &&
> + virtio_net_ext_to_skb(skb,
> + (struct virtio_net_ext_hdr *)(hdr + 1))) {
> + goto frame_err;
> + }
> +
> skb->protocol = eth_type_trans(skb, dev);
> pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
> ntohs(skb->protocol), skb->len, skb->pkt_type);
> @@ -1106,6 +1122,11 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
> if (vi->mergeable_rx_bufs)
> hdr->num_buffers = 0;
>
> + if (vi->hdr_ext &&
> + virtio_net_ext_from_skb(skb, (struct virtio_net_ext_hdr *)(hdr + 1),
> + vi->ext_mask))
> + BUG();
> +
> sg_init_table(sq->sg, skb_shinfo(skb)->nr_frags + (can_push ? 1 : 2));
> if (can_push) {
> __skb_push(skb, hdr_len);
> diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
> index 5209b5e..eaa524f 100644
> --- a/include/linux/virtio_net.h
> +++ b/include/linux/virtio_net.h
> @@ -100,4 +100,16 @@ static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb,
> return 0;
> }
>
> +static inline int virtio_net_ext_to_skb(struct sk_buff *skb,
> + struct virtio_net_ext_hdr *ext)
> +{
> + return 0;
> +}
> +
> +static inline int virtio_net_ext_from_skb(const struct sk_buff *skb,
> + struct virtio_net_ext_hdr *ext,
> + __u32 ext_mask)
> +{
> + return 0;
> +}
> #endif /* _LINUX_VIRTIO_NET_H */
> diff --git a/include/uapi/linux/virtio_net.h b/include/uapi/linux/virtio_net.h
> index fc353b5..0039b72 100644
> --- a/include/uapi/linux/virtio_net.h
> +++ b/include/uapi/linux/virtio_net.h
> @@ -88,6 +88,7 @@ struct virtio_net_config {
> struct virtio_net_hdr_v1 {
> #define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 /* Use csum_start, csum_offset */
> #define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */
> +#define VIRTIO_NET_HDR_F_VNET_EXT 4 /* Vnet extensions present */
> __u8 flags;
> #define VIRTIO_NET_HDR_GSO_NONE 0 /* Not a GSO frame */
> #define VIRTIO_NET_HDR_GSO_TCPV4 1 /* GSO frame, IPv4 TCP (TSO) */
> @@ -102,6 +103,16 @@ struct virtio_net_hdr_v1 {
> __virtio16 num_buffers; /* Number of merged rx buffers */
> };
>
> +/* If IRTIO_NET_HDR_F_VNET_EXT flags is set, this header immediately
> + * follows the virtio_net_hdr. The flags in this header will indicate
> + * which extension will follow. The extnsion data will immidiately follow
s/extnsion/extension/
> + * this header.
> + */
> +struct virtio_net_ext_hdr {
> + __u32 flags;
> + __u8 extensions[];
> +};
> +
> #ifndef VIRTIO_NET_NO_LEGACY
> /* This header comes first in the scatter-gather list.
> * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, it must
^ permalink raw reply
* (unknown),
From: scotte @ 2017-04-18 1:56 UTC (permalink / raw)
To: netdev
[-- Attachment #1: EMAIL_5628834284372_netdev.zip --]
[-- Type: application/zip, Size: 1226 bytes --]
^ permalink raw reply
* RE: [Intel-wired-lan] [PATCH] net: igbvf: Use net_device_stats from struct net_device
From: Brown, Aaron F @ 2017-04-18 1:36 UTC (permalink / raw)
To: Tobias Klauser, Kirsher, Jeffrey T
Cc: netdev@vger.kernel.org, intel-wired-lan@lists.osuosl.org
In-Reply-To: <20170406064522.13096-1-tklauser@distanz.ch>
> From: Intel-wired-lan [mailto:intel-wired-lan-bounces@lists.osuosl.org] On
> Behalf Of Tobias Klauser
> Sent: Wednesday, April 5, 2017 11:45 PM
> To: Kirsher, Jeffrey T <jeffrey.t.kirsher@intel.com>
> Cc: netdev@vger.kernel.org; intel-wired-lan@lists.osuosl.org
> Subject: [Intel-wired-lan] [PATCH] net: igbvf: Use net_device_stats from
> struct net_device
>
> Instead of using a private copy of struct net_device_stats in
> struct igbvf_adapter, use stats from struct net_device. Also remove the
> now unnecessary .ndo_get_stats function.
>
> Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
> ---
> drivers/net/ethernet/intel/igbvf/igbvf.h | 1 -
> drivers/net/ethernet/intel/igbvf/netdev.c | 26 +++++---------------------
> 2 files changed, 5 insertions(+), 22 deletions(-)
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
^ permalink raw reply
* Re: [PATCH RFC] sparc64: eBPF JIT
From: David Miller @ 2017-04-18 1:12 UTC (permalink / raw)
To: alexei.starovoitov; +Cc: sparclinux, netdev, ast, daniel
In-Reply-To: <20170417232740.GB96258@ast-mbp.thefacebook.com>
From: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Date: Mon, 17 Apr 2017 16:27:42 -0700
> On Sun, Apr 16, 2017 at 11:38:25PM -0400, David Miller wrote:
>> +static void build_prologue(struct jit_ctx *ctx)
>> +{
>> + s32 stack_needed = 176;
>> +
>> + if (ctx->saw_frame_pointer)
>> + stack_needed += MAX_BPF_STACK;
>> +
>> + /* save %sp, -176, %sp */
>> + emit(SAVE | IMMED | RS1(SP) | S13(-stack_needed) | RD(SP), ctx);
>> +
>> + if (ctx->saw_ld_abs_ind) {
>> + load_skb_regs(ctx, bpf2sparc[BPF_REG_1]);
>> + } else {
>> + emit_nop(ctx);
>> + emit_nop(ctx);
>> + emit_nop(ctx);
>> + emit_nop(ctx);
>
> why 4 nops? to keep prologue size constant w/ and w/o caching ?
> does it help somehow? I'm assuming that's prep for next step
> of tail_call.
I need to make some adjustments to how the branch offsets are done
if the prologue is variable size. Simply an implementation issue,
which I intend to fix, nothing more.
>
>> + if (insn->src_reg == BPF_REG_FP || insn->dst_reg == BPF_REG_FP) {
>> + ctx->saw_frame_pointer = true;
>> + if (BPF_CLASS(code) == BPF_ALU ||
>> + BPF_CLASS(code) == BPF_ALU64) {
>> + pr_err_once("ALU op on FP not supported by JIT\n");
>> + return -EINVAL;
>
> That should be fine. The verifier checks for that:
> /* check whether register used as dest operand can be written to */
> if (regno == BPF_REG_FP) {
> verbose("frame pointer is read only\n");
> return -EACCES;
> }
I need to trap it as a source as well, because if that is allowed then
I have to add special handling to every ALU operation we allow.
The reason is that the sparc64 stack is biased by 2047 bytes. So
I have to adjust every FP relative reference to include that 2047
bias.
Can LLVM and CLANG emit arithmetic operations with FP as source?
>> + /* dst = imm64 */
>> + case BPF_LD | BPF_IMM | BPF_DW:
>> + {
>> + const struct bpf_insn insn1 = insn[1];
>> + u64 imm64;
>> +
>> + if (insn1.code != 0 || insn1.src_reg != 0 ||
>> + insn1.dst_reg != 0 || insn1.off != 0) {
>> + /* Note: verifier in BPF core must catch invalid
>> + * instructions.
>> + */
>> + pr_err_once("Invalid BPF_LD_IMM64 instruction\n");
>> + return -EINVAL;
>
> verifier should catch that too, but extra check doesn't hurt.
I just copied from anoter JIT, I can remove it.
> all looks great to me.
Thanks for reviewing.
>
^ permalink raw reply
* Re: [PATCH net-next v2] net: ipv6: Fix UDP early demux lookup with udp_l3mdev_accept=0
From: Subash Abhinov Kasiviswanathan @ 2017-04-18 1:07 UTC (permalink / raw)
To: YUAN Linyu; +Cc: dsa, davem, netdev, rshearma, eric.dumazet, Eric Dumazet
In-Reply-To: <8729016553E3654398EA69218DA29EEF15B8090F@cnshjmbx02>
>> + break;
> I think break here should remove ?
Hi Yuan
This is similar to __udp4_lib_demux_lookup where we need to check if the
first
socket is an exact match or break since chains maybe long.
^ permalink raw reply
* [PATCH net-next] ravb: Fix ravb_ptp_interrupt clear interrupt all status
From: Simon Horman @ 2017-04-18 0:55 UTC (permalink / raw)
To: David Miller, Sergei Shtylyov; +Cc: Magnus Damm, netdev, linux-renesas-soc
From: Tsutomu Izawa <tsutomu.izawa.xk@renesas.com>
This patch fixes ravb_ptp_interrupt clears GIS register of all interrupts
status. It corrects to clear PTCF bit or PTMF bit.
Also it fixes returned value to IRQ_HANDLED or IRQ_NONE.
Signed-off-by: Tsutomu Izawa <tsutomu.izawa.xk@renesas.com>
Signed-off-by: Kazuya Mizuguchi <kazuya.mizuguchi.ks@renesas.com>
Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
---
drivers/net/ethernet/renesas/ravb.h | 4 ++--
drivers/net/ethernet/renesas/ravb_main.c | 12 ++++--------
drivers/net/ethernet/renesas/ravb_ptp.c | 15 ++++++++++++---
3 files changed, 18 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h
index 0525bd696d5d..fbfdefa659ce 100644
--- a/drivers/net/ethernet/renesas/ravb.h
+++ b/drivers/net/ethernet/renesas/ravb.h
@@ -1,6 +1,6 @@
/* Renesas Ethernet AVB device driver
*
- * Copyright (C) 2014-2015 Renesas Electronics Corporation
+ * Copyright (C) 2014-2017 Renesas Electronics Corporation
* Copyright (C) 2015 Renesas Solutions Corp.
* Copyright (C) 2015-2016 Cogent Embedded, Inc. <source@cogentembedded.com>
*
@@ -1054,7 +1054,7 @@ void ravb_modify(struct net_device *ndev, enum ravb_reg reg, u32 clear,
u32 set);
int ravb_wait(struct net_device *ndev, enum ravb_reg reg, u32 mask, u32 value);
-void ravb_ptp_interrupt(struct net_device *ndev);
+irqreturn_t ravb_ptp_interrupt(struct net_device *ndev);
void ravb_ptp_init(struct net_device *ndev, struct platform_device *pdev);
void ravb_ptp_stop(struct net_device *ndev);
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index 8cfc4a54f2dc..747686386513 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -820,10 +820,8 @@ static irqreturn_t ravb_interrupt(int irq, void *dev_id)
}
/* gPTP interrupt status summary */
- if (iss & ISS_CGIS) {
- ravb_ptp_interrupt(ndev);
- result = IRQ_HANDLED;
- }
+ if (iss & ISS_CGIS)
+ result = ravb_ptp_interrupt(ndev);
mmiowb();
spin_unlock(&priv->lock);
@@ -853,10 +851,8 @@ static irqreturn_t ravb_multi_interrupt(int irq, void *dev_id)
}
/* gPTP interrupt status summary */
- if (iss & ISS_CGIS) {
- ravb_ptp_interrupt(ndev);
- result = IRQ_HANDLED;
- }
+ if (iss & ISS_CGIS)
+ result = ravb_ptp_interrupt(ndev);
mmiowb();
spin_unlock(&priv->lock);
diff --git a/drivers/net/ethernet/renesas/ravb_ptp.c b/drivers/net/ethernet/renesas/ravb_ptp.c
index eede70ec37f8..403cf85631ba 100644
--- a/drivers/net/ethernet/renesas/ravb_ptp.c
+++ b/drivers/net/ethernet/renesas/ravb_ptp.c
@@ -1,6 +1,6 @@
/* PTP 1588 clock using the Renesas Ethernet AVB
*
- * Copyright (C) 2013-2015 Renesas Electronics Corporation
+ * Copyright (C) 2013-2017 Renesas Electronics Corporation
* Copyright (C) 2015 Renesas Solutions Corp.
* Copyright (C) 2015-2016 Cogent Embedded, Inc. <source@cogentembedded.com>
*
@@ -296,10 +296,11 @@ static const struct ptp_clock_info ravb_ptp_info = {
};
/* Caller must hold the lock */
-void ravb_ptp_interrupt(struct net_device *ndev)
+irqreturn_t ravb_ptp_interrupt(struct net_device *ndev)
{
struct ravb_private *priv = netdev_priv(ndev);
u32 gis = ravb_read(ndev, GIS);
+ irqreturn_t result = IRQ_NONE;
gis &= ravb_read(ndev, GIC);
if (gis & GIS_PTCF) {
@@ -309,6 +310,9 @@ void ravb_ptp_interrupt(struct net_device *ndev)
event.index = 0;
event.timestamp = ravb_read(ndev, GCPT);
ptp_clock_event(priv->ptp.clock, &event);
+
+ result = IRQ_HANDLED;
+ gis &= ~GIS_PTCF;
}
if (gis & GIS_PTMF) {
struct ravb_ptp_perout *perout = priv->ptp.perout;
@@ -317,9 +321,14 @@ void ravb_ptp_interrupt(struct net_device *ndev)
perout->target += perout->period;
ravb_ptp_update_compare(priv, perout->target);
}
+
+ result = IRQ_HANDLED;
+ gis &= ~GIS_PTMF;
}
- ravb_write(ndev, ~gis, GIS);
+ ravb_write(ndev, gis, GIS);
+
+ return result;
}
void ravb_ptp_init(struct net_device *ndev, struct platform_device *pdev)
--
2.7.0.rc3.207.g0ac5344
^ permalink raw reply related
* Corrupted SKB
From: Michael Ma @ 2017-04-18 0:39 UTC (permalink / raw)
To: Linux Kernel Network Developers
Hi -
We've implemented a "glue" qdisc similar to mqprio which can associate
one qdisc to multiple txqs as the root qdisc. Reference count of the
child qdiscs have been adjusted properly in this case so that it
represents the number of txqs it has been attached to. However when
sending packets we saw the skb from dequeue_skb() corrupted with the
following call stack:
[exception RIP: netif_skb_features+51]
RIP: ffffffff815292b3 RSP: ffff8817f6987940 RFLAGS: 00010246
#9 [ffff8817f6987968] validate_xmit_skb at ffffffff815294aa
#10 [ffff8817f69879a0] validate_xmit_skb at ffffffff8152a0d9
#11 [ffff8817f69879b0] __qdisc_run at ffffffff8154a193
#12 [ffff8817f6987a00] dev_queue_xmit at ffffffff81529e03
It looks like the skb has already been released since its dev pointer
field is invalid.
Any clue on how this can be investigated further? My current thought
is to add some instrumentation to the place where skb is released and
analyze whether there is any race condition happening there. However
by looking through the existing code I think the case where one root
qdisc is associated with multiple txqs already exists (when mqprio is
not used) so not sure why it won't work when we group txqs and assign
each group a root qdisc. Any insight on this issue would be much
appreciated!
Thanks,
Michael
^ permalink raw reply
* Re: linux-next: manual merge of the net-next tree with the net tree
From: Daniel Borkmann @ 2017-04-18 0:39 UTC (permalink / raw)
To: Stephen Rothwell, David Miller, Networking
Cc: Linux-Next Mailing List, Linux Kernel Mailing List,
Alexei Starovoitov
In-Reply-To: <20170418101835.745d2576@canb.auug.org.au>
On 04/18/2017 02:18 AM, Stephen Rothwell wrote:
> Hi all,
>
> Today's linux-next merge of the net-next tree got a conflict in:
>
> kernel/bpf/syscall.c
>
> between commits:
>
> 6b1bb01bcc5b ("bpf: fix cb access in socket filter programs on tail calls")
> c2002f983767 ("bpf: fix checking xdp_adjust_head on tail calls")
>
> from the net tree and commit:
>
> e245c5c6a565 ("bpf: move fixup_bpf_calls() function")
> 79741b3bdec0 ("bpf: refactor fixup_bpf_calls()")
>
> from the net-next tree.
>
> I fixed it up (the latter moved and changed teh code modified by the
> former - I added the following fix up patch) and can carry the fix as
> necessary. This is now fixed as far as linux-next is concerned, but any
> non trivial conflicts should be mentioned to your upstream maintainer
> when your tree is submitted for merging. You may also want to consider
> cooperating with the maintainer of the conflicting tree to minimise any
> particularly complex conflicts.
>
> From: Stephen Rothwell <sfr@canb.auug.org.au>
> Date: Tue, 18 Apr 2017 10:16:03 +1000
> Subject: [PATCH] bpf: merge fix for move of fixup_bpf_calls()
>
> Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
> ---
> kernel/bpf/verifier.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 62e1e447ded9..5939b4c81fe1 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -3349,6 +3349,14 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
> if (insn->imm == BPF_FUNC_xdp_adjust_head)
> prog->xdp_adjust_head = 1;
> if (insn->imm == BPF_FUNC_tail_call) {
> + /* If we tail call into other programs, we
> + * cannot make any assumptions since they
> + * can be replaced dynamically during runtime
> + * in the program array.
> + */
> + prog->cb_access = 1;
> + prog->xdp_adjust_head = 1;
> +
> /* mark bpf_tail_call as different opcode to avoid
> * conditional branch in the interpeter for every normal
> * call and to prevent accidental JITing by JIT compiler
>
Looks good, thanks.
^ permalink raw reply
* Re: [PATCH v2 net-next 5/8] net/ncsi: Dump NCSI packet statistics
From: Gavin Shan @ 2017-04-18 0:22 UTC (permalink / raw)
To: Joe Perches; +Cc: Gavin Shan, netdev, davem
In-Reply-To: <1492137045.28586.26.camel@perches.com>
On Thu, Apr 13, 2017 at 07:30:45PM -0700, Joe Perches wrote:
>On Thu, 2017-04-13 at 17:48 +1000, Gavin Shan wrote:
>> This creates /sys/kernel/debug/ncsi/<eth0>/stats to dump the NCSI
>> packets sent and received over all packages and channels. It's useful
>> to diagnose NCSI problems, especially when NCSI packages and channels
>> aren't probed properly. The statistics can be gained from debugfs file
>> as below:
>>
>> # cat /sys/kernel/debug/ncsi/eth0/stats
>>
>> CMD OK TIMEOUT ERROR
>> =======================================
>> CIS 32 29 0
>> SP 10 7 0
>> DP 17 14 0
>> EC 1 0 0
>> ECNT 1 0 0
>> AE 1 0 0
>> GLS 11 0 0
>> SMA 1 0 0
>> EBF 1 0 0
>> GVI 2 0 0
>> GC 2 0 0
>
>more trivia:
>
>> diff --git a/net/ncsi/ncsi-debug.c b/net/ncsi/ncsi-debug.c
>[]
>> @@ -23,6 +23,235 @@
>> #include "ncsi-pkt.h"
>>
>> static struct dentry *ncsi_dentry;
>> +static struct ncsi_pkt_handler {
>> + unsigned char type;
>> + const char *name;
>> +} ncsi_pkt_handlers[] = {
>> + { NCSI_PKT_CMD_CIS, "CIS" },
>> + { NCSI_PKT_CMD_SP, "SP" },
>> + { NCSI_PKT_CMD_DP, "DP" },
>> + { NCSI_PKT_CMD_EC, "EC" },
>> + { NCSI_PKT_CMD_DC, "DC" },
>> + { NCSI_PKT_CMD_RC, "RC" },
>> + { NCSI_PKT_CMD_ECNT, "ECNT" },
>> + { NCSI_PKT_CMD_DCNT, "DCNT" },
>> + { NCSI_PKT_CMD_AE, "AE" },
>> + { NCSI_PKT_CMD_SL, "SL" },
>> + { NCSI_PKT_CMD_GLS, "GLS" },
>> + { NCSI_PKT_CMD_SVF, "SVF" },
>> + { NCSI_PKT_CMD_EV, "EV" },
>> + { NCSI_PKT_CMD_DV, "DV" },
>> + { NCSI_PKT_CMD_SMA, "SMA" },
>> + { NCSI_PKT_CMD_EBF, "EBF" },
>> + { NCSI_PKT_CMD_DBF, "DBF" },
>> + { NCSI_PKT_CMD_EGMF, "EGMF" },
>> + { NCSI_PKT_CMD_DGMF, "DGMF" },
>> + { NCSI_PKT_CMD_SNFC, "SNFC" },
>> + { NCSI_PKT_CMD_GVI, "GVI" },
>> + { NCSI_PKT_CMD_GC, "GC" },
>> + { NCSI_PKT_CMD_GP, "GP" },
>> + { NCSI_PKT_CMD_GCPS, "GCPS" },
>> + { NCSI_PKT_CMD_GNS, "GNS" },
>> + { NCSI_PKT_CMD_GNPTS, "GNPTS" },
>> + { NCSI_PKT_CMD_GPS, "GPS" },
>> + { NCSI_PKT_CMD_OEM, "OEM" },
>> + { NCSI_PKT_CMD_PLDM, "PLDM" },
>> + { NCSI_PKT_CMD_GPUUID, "GPUUID" },
>
>I don't know how common these are and how
>intelligible these acronyms are to knowledgeable
>developer/users, but maybe it'd be better to
>spell out what these are instead of having to
>look up what the acronyms stand for
>
> CIS - Clear Initial State
> SP - Select Package
> etc...
>
>Maybe copy the descriptions from the ncsi-pkt.h file
>
Joe, good question. As these decriptive strings are part of
the output from ncsi/eth0/stats and input to ncsi/eth0/pkt,
I intended to keep them short enough. Also, this debugging
interface would service developers who knows NCSI protocol
and perhaps know the meanings of these acronyms.
Thanks,
Gavin
>#define NCSI_PKT_CMD_CIS 0x00 /* Clear Initial State */
>#define NCSI_PKT_CMD_SP 0x01 /* Select Package */
>#define NCSI_PKT_CMD_DP 0x02 /* Deselect Package */
>#define NCSI_PKT_CMD_EC 0x03 /* Enable Channel */
>#define NCSI_PKT_CMD_DC 0x04 /* Disable Channel */
>#define NCSI_PKT_CMD_RC 0x05 /* Reset Channel */
>#define NCSI_PKT_CMD_ECNT 0x06 /* Enable Channel Network Tx */
>#define NCSI_PKT_CMD_DCNT 0x07 /* Disable Channel Network Tx */
>#define NCSI_PKT_CMD_AE 0x08 /* AEN Enable */
>#define NCSI_PKT_CMD_SL 0x09 /* Set Link */
>#define NCSI_PKT_CMD_GLS 0x0a /* Get Link */
>#define NCSI_PKT_CMD_SVF 0x0b /* Set VLAN Filter */
>#define NCSI_PKT_CMD_EV 0x0c /* Enable VLAN */
>#define NCSI_PKT_CMD_DV 0x0d /* Disable VLAN */
>#define NCSI_PKT_CMD_SMA 0x0e /* Set MAC address */
>#define NCSI_PKT_CMD_EBF 0x10 /* Enable Broadcast Filter */
>#define NCSI_PKT_CMD_DBF 0x11 /* Disable Broadcast Filter */
>#define NCSI_PKT_CMD_EGMF 0x12 /* Enable Global Multicast Filter */
>#define NCSI_PKT_CMD_DGMF 0x13 /* Disable Global Multicast Filter */
>#define NCSI_PKT_CMD_SNFC 0x14 /* Set NCSI Flow Control */
>#define NCSI_PKT_CMD_GVI 0x15 /* Get Version ID */
>#define NCSI_PKT_CMD_GC 0x16 /* Get Capabilities */
>#define NCSI_PKT_CMD_GP 0x17 /* Get Parameters */
>#define NCSI_PKT_CMD_GCPS 0x18 /* Get Controller Packet Statistics */
>#define NCSI_PKT_CMD_GNS 0x19 /* Get NCSI Statistics */
>#define NCSI_PKT_CMD_GNPTS 0x1a /* Get NCSI Pass-throu Statistics */
>#define NCSI_PKT_CMD_GPS 0x1b /* Get package status */
>#define NCSI_PKT_CMD_OEM 0x50 /* OEM */
>#define NCSI_PKT_CMD_PLDM 0x51 /* PLDM request over NCSI over RBT */
>#define NCSI_PKT_CMD_GPUUID 0x52 /* Get package UUID */
>
^ 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