Skip to content

Commit

Permalink
cxgb3 - Fix low memory conditions
Browse files Browse the repository at this point in the history
Reuse the incoming skb when a clientless abort req is recieved.

The release of RDMA connections HW resources might be deferred in
low memory situations.
Ensure that no further activity is passed up to the RDMA driver
for these connections.

Signed-off-by: Divy Le Ray <divy@chelsio.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
  • Loading branch information
Divy Le Ray authored and Jeff Garzik committed Apr 19, 2007
1 parent 895e1fc commit 606fcd0
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 19 deletions.
5 changes: 4 additions & 1 deletion drivers/net/cxgb3/cxgb3_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ static inline union listen_entry *stid2entry(const struct tid_info *t,
static inline struct t3c_tid_entry *lookup_tid(const struct tid_info *t,
unsigned int tid)
{
return tid < t->ntids ? &(t->tid_tab[tid]) : NULL;
struct t3c_tid_entry *t3c_tid = tid < t->ntids ?
&(t->tid_tab[tid]) : NULL;

return (t3c_tid && t3c_tid->client) ? t3c_tid : NULL;
}

/*
Expand Down
69 changes: 51 additions & 18 deletions drivers/net/cxgb3/cxgb3_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid)

spin_lock_bh(&td->tid_release_lock);
p->ctx = (void *)td->tid_release_list;
p->client = NULL;
td->tid_release_list = p;
if (!p->ctx)
schedule_work(&td->tid_release_task);
Expand Down Expand Up @@ -623,7 +624,8 @@ static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb)
struct t3c_tid_entry *t3c_tid;

t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
if (t3c_tid->ctx && t3c_tid->client && t3c_tid->client->handlers &&
if (t3c_tid && t3c_tid->ctx && t3c_tid->client &&
t3c_tid->client->handlers &&
t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) {
return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb,
t3c_tid->
Expand All @@ -642,7 +644,7 @@ static int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb)
struct t3c_tid_entry *t3c_tid;

t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
if (t3c_tid->ctx && t3c_tid->client->handlers &&
if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
t3c_tid->client->handlers[p->opcode]) {
return t3c_tid->client->handlers[p->opcode] (dev, skb,
t3c_tid->ctx);
Expand All @@ -660,7 +662,7 @@ static int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb)
struct t3c_tid_entry *t3c_tid;

t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
if (t3c_tid->ctx && t3c_tid->client->handlers &&
if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
t3c_tid->client->handlers[p->opcode]) {
return t3c_tid->client->handlers[p->opcode]
(dev, skb, t3c_tid->ctx);
Expand Down Expand Up @@ -689,37 +691,68 @@ static int do_cr(struct t3cdev *dev, struct sk_buff *skb)
}
}

/*
* Returns an sk_buff for a reply CPL message of size len. If the input
* sk_buff has no other users it is trimmed and reused, otherwise a new buffer
* is allocated. The input skb must be of size at least len. Note that this
* operation does not destroy the original skb data even if it decides to reuse
* the buffer.
*/
static struct sk_buff *cxgb3_get_cpl_reply_skb(struct sk_buff *skb, size_t len,
int gfp)
{
if (likely(!skb_cloned(skb))) {
BUG_ON(skb->len < len);
__skb_trim(skb, len);
skb_get(skb);
} else {
skb = alloc_skb(len, gfp);
if (skb)
__skb_put(skb, len);
}
return skb;
}

static int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb)
{
union opcode_tid *p = cplhdr(skb);
unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
struct t3c_tid_entry *t3c_tid;

t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
if (t3c_tid->ctx && t3c_tid->client->handlers &&
if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
t3c_tid->client->handlers[p->opcode]) {
return t3c_tid->client->handlers[p->opcode]
(dev, skb, t3c_tid->ctx);
} else {
struct cpl_abort_req_rss *req = cplhdr(skb);
struct cpl_abort_rpl *rpl;
struct sk_buff *reply_skb;
unsigned int tid = GET_TID(req);
u8 cmd = req->status;

if (req->status == CPL_ERR_RTX_NEG_ADVICE ||
req->status == CPL_ERR_PERSIST_NEG_ADVICE)
goto out;

struct sk_buff *skb =
alloc_skb(sizeof(struct cpl_abort_rpl), GFP_ATOMIC);
if (!skb) {
reply_skb = cxgb3_get_cpl_reply_skb(skb,
sizeof(struct
cpl_abort_rpl),
GFP_ATOMIC);

if (!reply_skb) {
printk("do_abort_req_rss: couldn't get skb!\n");
goto out;
}
skb->priority = CPL_PRIORITY_DATA;
__skb_put(skb, sizeof(struct cpl_abort_rpl));
rpl = cplhdr(skb);
reply_skb->priority = CPL_PRIORITY_DATA;
__skb_put(reply_skb, sizeof(struct cpl_abort_rpl));
rpl = cplhdr(reply_skb);
rpl->wr.wr_hi =
htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL));
rpl->wr.wr_lo = htonl(V_WR_TID(GET_TID(req)));
OPCODE_TID(rpl) =
htonl(MK_OPCODE_TID(CPL_ABORT_RPL, GET_TID(req)));
rpl->cmd = req->status;
cxgb3_ofld_send(dev, skb);
rpl->wr.wr_lo = htonl(V_WR_TID(tid));
OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, tid));
rpl->cmd = cmd;
cxgb3_ofld_send(dev, reply_skb);
out:
return CPL_RET_BUF_DONE;
}
Expand All @@ -732,7 +765,7 @@ static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb)
struct t3c_tid_entry *t3c_tid;

t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
if (t3c_tid->ctx && t3c_tid->client->handlers &&
if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) {
return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
(dev, skb, t3c_tid->ctx);
Expand Down Expand Up @@ -762,7 +795,7 @@ static int do_term(struct t3cdev *dev, struct sk_buff *skb)
struct t3c_tid_entry *t3c_tid;

t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
if (t3c_tid->ctx && t3c_tid->client->handlers &&
if (t3c_tid && t3c_tid->ctx && t3c_tid->client->handlers &&
t3c_tid->client->handlers[opcode]) {
return t3c_tid->client->handlers[opcode] (dev, skb,
t3c_tid->ctx);
Expand Down Expand Up @@ -961,7 +994,7 @@ void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
for (tid = 0; tid < ti->ntids; tid++) {
te = lookup_tid(ti, tid);
BUG_ON(!te);
if (te->ctx && te->client && te->client->redirect) {
if (te && te->ctx && te->client && te->client->redirect) {
update_tcb = te->client->redirect(te->ctx, old, new, e);
if (update_tcb) {
l2t_hold(L2DATA(tdev), e);
Expand Down

0 comments on commit 606fcd0

Please sign in to comment.