You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
RDMA/cxgb4: Fix bug for active and passive LE hash collision path
Retries active opens for INUSE errors. Logs any active ofld_connect_wr error replies. Sends ofld_connect_wr on same ctrlq. It needs to go on the same control txq as regular CPL active/passive messages. Retries on active open replies with EADDRINUSE. Uses active open fw wr only if active filter region is set. Adds stat for ofld_connect_wr failures. This patch also adds debugfs file to show endpoints. Signed-off-by: Vipul Pandya <vipul@chelsio.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
This commit is contained in:
committed by
Roland Dreier
parent
1cab775c3e
commit
793dad94e7
File diff suppressed because it is too large
Load Diff
@@ -280,6 +280,10 @@ static int stats_show(struct seq_file *seq, void *v)
|
||||
db_state_str[dev->db_state],
|
||||
dev->rdev.stats.db_state_transitions);
|
||||
seq_printf(seq, "TCAM_FULL: %10llu\n", dev->rdev.stats.tcam_full);
|
||||
seq_printf(seq, "ACT_OFLD_CONN_FAILS: %10llu\n",
|
||||
dev->rdev.stats.act_ofld_conn_fails);
|
||||
seq_printf(seq, "PAS_OFLD_CONN_FAILS: %10llu\n",
|
||||
dev->rdev.stats.pas_ofld_conn_fails);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -310,6 +314,9 @@ static ssize_t stats_clear(struct file *file, const char __user *buf,
|
||||
dev->rdev.stats.db_empty = 0;
|
||||
dev->rdev.stats.db_drop = 0;
|
||||
dev->rdev.stats.db_state_transitions = 0;
|
||||
dev->rdev.stats.tcam_full = 0;
|
||||
dev->rdev.stats.act_ofld_conn_fails = 0;
|
||||
dev->rdev.stats.pas_ofld_conn_fails = 0;
|
||||
mutex_unlock(&dev->rdev.stats.lock);
|
||||
return count;
|
||||
}
|
||||
@@ -323,6 +330,113 @@ static const struct file_operations stats_debugfs_fops = {
|
||||
.write = stats_clear,
|
||||
};
|
||||
|
||||
static int dump_ep(int id, void *p, void *data)
|
||||
{
|
||||
struct c4iw_ep *ep = p;
|
||||
struct c4iw_debugfs_data *epd = data;
|
||||
int space;
|
||||
int cc;
|
||||
|
||||
space = epd->bufsize - epd->pos - 1;
|
||||
if (space == 0)
|
||||
return 1;
|
||||
|
||||
cc = snprintf(epd->buf + epd->pos, space,
|
||||
"ep %p cm_id %p qp %p state %d flags 0x%lx history 0x%lx "
|
||||
"hwtid %d atid %d %pI4:%d <-> %pI4:%d\n",
|
||||
ep, ep->com.cm_id, ep->com.qp, (int)ep->com.state,
|
||||
ep->com.flags, ep->com.history, ep->hwtid, ep->atid,
|
||||
&ep->com.local_addr.sin_addr.s_addr,
|
||||
ntohs(ep->com.local_addr.sin_port),
|
||||
&ep->com.remote_addr.sin_addr.s_addr,
|
||||
ntohs(ep->com.remote_addr.sin_port));
|
||||
if (cc < space)
|
||||
epd->pos += cc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dump_listen_ep(int id, void *p, void *data)
|
||||
{
|
||||
struct c4iw_listen_ep *ep = p;
|
||||
struct c4iw_debugfs_data *epd = data;
|
||||
int space;
|
||||
int cc;
|
||||
|
||||
space = epd->bufsize - epd->pos - 1;
|
||||
if (space == 0)
|
||||
return 1;
|
||||
|
||||
cc = snprintf(epd->buf + epd->pos, space,
|
||||
"ep %p cm_id %p state %d flags 0x%lx stid %d backlog %d "
|
||||
"%pI4:%d\n", ep, ep->com.cm_id, (int)ep->com.state,
|
||||
ep->com.flags, ep->stid, ep->backlog,
|
||||
&ep->com.local_addr.sin_addr.s_addr,
|
||||
ntohs(ep->com.local_addr.sin_port));
|
||||
if (cc < space)
|
||||
epd->pos += cc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ep_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct c4iw_debugfs_data *epd = file->private_data;
|
||||
if (!epd) {
|
||||
pr_info("%s null qpd?\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
vfree(epd->buf);
|
||||
kfree(epd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ep_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct c4iw_debugfs_data *epd;
|
||||
int ret = 0;
|
||||
int count = 1;
|
||||
|
||||
epd = kmalloc(sizeof(*epd), GFP_KERNEL);
|
||||
if (!epd) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
epd->devp = inode->i_private;
|
||||
epd->pos = 0;
|
||||
|
||||
spin_lock_irq(&epd->devp->lock);
|
||||
idr_for_each(&epd->devp->hwtid_idr, count_idrs, &count);
|
||||
idr_for_each(&epd->devp->atid_idr, count_idrs, &count);
|
||||
idr_for_each(&epd->devp->stid_idr, count_idrs, &count);
|
||||
spin_unlock_irq(&epd->devp->lock);
|
||||
|
||||
epd->bufsize = count * 160;
|
||||
epd->buf = vmalloc(epd->bufsize);
|
||||
if (!epd->buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err1;
|
||||
}
|
||||
|
||||
spin_lock_irq(&epd->devp->lock);
|
||||
idr_for_each(&epd->devp->hwtid_idr, dump_ep, epd);
|
||||
idr_for_each(&epd->devp->atid_idr, dump_ep, epd);
|
||||
idr_for_each(&epd->devp->stid_idr, dump_listen_ep, epd);
|
||||
spin_unlock_irq(&epd->devp->lock);
|
||||
|
||||
file->private_data = epd;
|
||||
goto out;
|
||||
err1:
|
||||
kfree(epd);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations ep_debugfs_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ep_open,
|
||||
.release = ep_release,
|
||||
.read = debugfs_read,
|
||||
};
|
||||
|
||||
static int setup_debugfs(struct c4iw_dev *devp)
|
||||
{
|
||||
struct dentry *de;
|
||||
@@ -345,6 +459,11 @@ static int setup_debugfs(struct c4iw_dev *devp)
|
||||
if (de && de->d_inode)
|
||||
de->d_inode->i_size = 4096;
|
||||
|
||||
de = debugfs_create_file("eps", S_IWUSR, devp->debugfs_root,
|
||||
(void *)devp, &ep_debugfs_fops);
|
||||
if (de && de->d_inode)
|
||||
de->d_inode->i_size = 4096;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -476,6 +595,9 @@ static void c4iw_dealloc(struct uld_ctx *ctx)
|
||||
idr_destroy(&ctx->dev->cqidr);
|
||||
idr_destroy(&ctx->dev->qpidr);
|
||||
idr_destroy(&ctx->dev->mmidr);
|
||||
idr_destroy(&ctx->dev->hwtid_idr);
|
||||
idr_destroy(&ctx->dev->stid_idr);
|
||||
idr_destroy(&ctx->dev->atid_idr);
|
||||
iounmap(ctx->dev->rdev.oc_mw_kva);
|
||||
ib_dealloc_device(&ctx->dev->ibdev);
|
||||
ctx->dev = NULL;
|
||||
@@ -533,6 +655,9 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop)
|
||||
idr_init(&devp->cqidr);
|
||||
idr_init(&devp->qpidr);
|
||||
idr_init(&devp->mmidr);
|
||||
idr_init(&devp->hwtid_idr);
|
||||
idr_init(&devp->stid_idr);
|
||||
idr_init(&devp->atid_idr);
|
||||
spin_lock_init(&devp->lock);
|
||||
mutex_init(&devp->rdev.stats.lock);
|
||||
mutex_init(&devp->db_mutex);
|
||||
|
||||
@@ -131,6 +131,8 @@ struct c4iw_stats {
|
||||
u64 db_drop;
|
||||
u64 db_state_transitions;
|
||||
u64 tcam_full;
|
||||
u64 act_ofld_conn_fails;
|
||||
u64 pas_ofld_conn_fails;
|
||||
};
|
||||
|
||||
struct c4iw_rdev {
|
||||
@@ -224,6 +226,9 @@ struct c4iw_dev {
|
||||
struct dentry *debugfs_root;
|
||||
enum db_state db_state;
|
||||
int qpcnt;
|
||||
struct idr hwtid_idr;
|
||||
struct idr atid_idr;
|
||||
struct idr stid_idr;
|
||||
};
|
||||
|
||||
static inline struct c4iw_dev *to_c4iw_dev(struct ib_device *ibdev)
|
||||
@@ -713,6 +718,31 @@ enum c4iw_ep_flags {
|
||||
CLOSE_SENT = 3,
|
||||
};
|
||||
|
||||
enum c4iw_ep_history {
|
||||
ACT_OPEN_REQ = 0,
|
||||
ACT_OFLD_CONN = 1,
|
||||
ACT_OPEN_RPL = 2,
|
||||
ACT_ESTAB = 3,
|
||||
PASS_ACCEPT_REQ = 4,
|
||||
PASS_ESTAB = 5,
|
||||
ABORT_UPCALL = 6,
|
||||
ESTAB_UPCALL = 7,
|
||||
CLOSE_UPCALL = 8,
|
||||
ULP_ACCEPT = 9,
|
||||
ULP_REJECT = 10,
|
||||
TIMEDOUT = 11,
|
||||
PEER_ABORT = 12,
|
||||
PEER_CLOSE = 13,
|
||||
CONNREQ_UPCALL = 14,
|
||||
ABORT_CONN = 15,
|
||||
DISCONN_UPCALL = 16,
|
||||
EP_DISC_CLOSE = 17,
|
||||
EP_DISC_ABORT = 18,
|
||||
CONN_RPL_UPCALL = 19,
|
||||
ACT_RETRY_NOMEM = 20,
|
||||
ACT_RETRY_INUSE = 21
|
||||
};
|
||||
|
||||
struct c4iw_ep_common {
|
||||
struct iw_cm_id *cm_id;
|
||||
struct c4iw_qp *qp;
|
||||
@@ -724,6 +754,7 @@ struct c4iw_ep_common {
|
||||
struct sockaddr_in remote_addr;
|
||||
struct c4iw_wr_wait wr_wait;
|
||||
unsigned long flags;
|
||||
unsigned long history;
|
||||
};
|
||||
|
||||
struct c4iw_listen_ep {
|
||||
@@ -761,6 +792,7 @@ struct c4iw_ep {
|
||||
u8 tos;
|
||||
u8 retry_with_mpa_v1;
|
||||
u8 tried_with_mpa_v1;
|
||||
unsigned int retry_count;
|
||||
};
|
||||
|
||||
static inline struct c4iw_ep *to_ep(struct iw_cm_id *cm_id)
|
||||
|
||||
@@ -530,6 +530,7 @@ struct adapter {
|
||||
struct net_device *port[MAX_NPORTS];
|
||||
u8 chan_map[NCHAN]; /* channel -> port map */
|
||||
|
||||
u32 filter_mode;
|
||||
unsigned int l2t_start;
|
||||
unsigned int l2t_end;
|
||||
struct l2t_data *l2t;
|
||||
|
||||
@@ -2670,7 +2670,8 @@ static int tid_init(struct tid_info *t)
|
||||
* Returns <0 on error and one of the %NET_XMIT_* values on success.
|
||||
*/
|
||||
int cxgb4_create_server(const struct net_device *dev, unsigned int stid,
|
||||
__be32 sip, __be16 sport, unsigned int queue)
|
||||
__be32 sip, __be16 sport, __be16 vlan,
|
||||
unsigned int queue)
|
||||
{
|
||||
unsigned int chan;
|
||||
struct sk_buff *skb;
|
||||
@@ -3043,7 +3044,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
|
||||
lli.ucq_density = 1 << QUEUESPERPAGEPF0_GET(
|
||||
t4_read_reg(adap, SGE_INGRESS_QUEUES_PER_PAGE_PF) >>
|
||||
(adap->fn * 4));
|
||||
lli.filt_mode = tp_vlan_pri_map;
|
||||
lli.filt_mode = adap->filter_mode;
|
||||
/* MODQ_REQ_MAP sets queues 0-3 to chan 0-3 */
|
||||
for (i = 0; i < NCHAN; i++)
|
||||
lli.tx_modq[i] = i;
|
||||
@@ -3307,7 +3308,8 @@ static int delete_filter(struct adapter *adapter, unsigned int fidx)
|
||||
}
|
||||
|
||||
int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid,
|
||||
__be32 sip, __be16 sport, unsigned int queue)
|
||||
__be32 sip, __be16 sport, __be16 vlan,
|
||||
unsigned int queue, unsigned char port, unsigned char mask)
|
||||
{
|
||||
int ret;
|
||||
struct filter_entry *f;
|
||||
@@ -3339,11 +3341,16 @@ int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid,
|
||||
f->fs.val.lport = cpu_to_be16(sport);
|
||||
f->fs.mask.lport = ~0;
|
||||
val = (u8 *)&sip;
|
||||
if ((val[0] | val[1] | val[2] | val[3]) != 0)
|
||||
if ((val[0] | val[1] | val[2] | val[3]) != 0) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
f->fs.val.lip[i] = val[i];
|
||||
f->fs.mask.lip[i] = ~0;
|
||||
}
|
||||
if (adap->filter_mode & F_PORT) {
|
||||
f->fs.val.iport = port;
|
||||
f->fs.mask.iport = mask;
|
||||
}
|
||||
}
|
||||
|
||||
f->fs.dirsteer = 1;
|
||||
f->fs.iq = queue;
|
||||
@@ -4450,6 +4457,10 @@ static int adap_init0(struct adapter *adap)
|
||||
for (j = 0; j < NCHAN; j++)
|
||||
adap->params.tp.tx_modq[j] = j;
|
||||
|
||||
t4_read_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA,
|
||||
&adap->filter_mode, 1,
|
||||
TP_VLAN_PRI_MAP);
|
||||
|
||||
adap->flags |= FW_OK;
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <linux/cache.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/inetdevice.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
/* CPL message priority levels */
|
||||
@@ -151,9 +152,12 @@ void cxgb4_remove_tid(struct tid_info *t, unsigned int qid, unsigned int tid);
|
||||
struct in6_addr;
|
||||
|
||||
int cxgb4_create_server(const struct net_device *dev, unsigned int stid,
|
||||
__be32 sip, __be16 sport, unsigned int queue);
|
||||
__be32 sip, __be16 sport, __be16 vlan,
|
||||
unsigned int queue);
|
||||
int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid,
|
||||
__be32 sip, __be16 sport, unsigned int queue);
|
||||
__be32 sip, __be16 sport, __be16 vlan,
|
||||
unsigned int queue,
|
||||
unsigned char port, unsigned char mask);
|
||||
int cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid,
|
||||
unsigned int queue, bool ipv6);
|
||||
static inline void set_wr_txq(struct sk_buff *skb, int prio, int queue)
|
||||
|
||||
@@ -1098,5 +1098,7 @@
|
||||
#define A_TP_TX_SCHED_PCMD 0x25
|
||||
|
||||
#define S_PORT 1
|
||||
#define V_PORT(x) ((x) << S_PORT)
|
||||
#define F_PORT V_PORT(1U)
|
||||
|
||||
#endif /* __T4_REGS_H */
|
||||
|
||||
Reference in New Issue
Block a user