Skip to content

Commit

Permalink
cxgb3: remove __GFP_NOFAIL usage
Browse files Browse the repository at this point in the history
Pre-allocate a skb at init time to be used for control messages to the HW
if skb allocation fails.

Tolerate failures to send messages initializing some memories at the cost of
parity error detection for these memories.
Retry sending connection id release messages if both alloc_skb(GFP_ATOMIC)
and alloc_skb(GFP_KERNEL) fail.
Do not bring the interface up if messages binding queue set to port fail to
be sent.

Signed-off-by: Divy Le Ray <divy@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Divy Le Ray authored and David S. Miller committed Jun 11, 2009
1 parent 87433bf commit 74b793e
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 7 deletions.
2 changes: 2 additions & 0 deletions drivers/net/cxgb3/adapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,8 @@ struct adapter {
struct mutex mdio_lock;
spinlock_t stats_lock;
spinlock_t work_lock;

struct sk_buff *nofail_skb;
};

static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr)
Expand Down
78 changes: 73 additions & 5 deletions drivers/net/cxgb3/cxgb3_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -433,40 +433,78 @@ static int init_tp_parity(struct adapter *adap)
for (i = 0; i < 16; i++) {
struct cpl_smt_write_req *req;

skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
skb = alloc_skb(sizeof(*req), GFP_KERNEL);
if (!skb)
skb = adap->nofail_skb;
if (!skb)
goto alloc_skb_fail;

req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
memset(req, 0, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
req->iff = i;
t3_mgmt_tx(adap, skb);
if (skb == adap->nofail_skb) {
await_mgmt_replies(adap, cnt, i + 1);
adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
if (!adap->nofail_skb)
goto alloc_skb_fail;
}
}

for (i = 0; i < 2048; i++) {
struct cpl_l2t_write_req *req;

skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
skb = alloc_skb(sizeof(*req), GFP_KERNEL);
if (!skb)
skb = adap->nofail_skb;
if (!skb)
goto alloc_skb_fail;

req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
memset(req, 0, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
req->params = htonl(V_L2T_W_IDX(i));
t3_mgmt_tx(adap, skb);
if (skb == adap->nofail_skb) {
await_mgmt_replies(adap, cnt, 16 + i + 1);
adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
if (!adap->nofail_skb)
goto alloc_skb_fail;
}
}

for (i = 0; i < 2048; i++) {
struct cpl_rte_write_req *req;

skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
skb = alloc_skb(sizeof(*req), GFP_KERNEL);
if (!skb)
skb = adap->nofail_skb;
if (!skb)
goto alloc_skb_fail;

req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req));
memset(req, 0, sizeof(*req));
req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
req->l2t_idx = htonl(V_L2T_W_IDX(i));
t3_mgmt_tx(adap, skb);
if (skb == adap->nofail_skb) {
await_mgmt_replies(adap, cnt, 16 + 2048 + i + 1);
adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
if (!adap->nofail_skb)
goto alloc_skb_fail;
}
}

skb = alloc_skb(sizeof(*greq), GFP_KERNEL | __GFP_NOFAIL);
skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
if (!skb)
skb = adap->nofail_skb;
if (!skb)
goto alloc_skb_fail;

greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq));
memset(greq, 0, sizeof(*greq));
greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
Expand All @@ -475,8 +513,17 @@ static int init_tp_parity(struct adapter *adap)
t3_mgmt_tx(adap, skb);

i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
if (skb == adap->nofail_skb) {
i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
adap->nofail_skb = alloc_skb(sizeof(*greq), GFP_KERNEL);
}

t3_tp_set_offload_mode(adap, 0);
return i;

alloc_skb_fail:
t3_tp_set_offload_mode(adap, 0);
return -ENOMEM;
}

/**
Expand Down Expand Up @@ -871,7 +918,12 @@ static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
struct mngt_pktsched_wr *req;
int ret;

skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
skb = alloc_skb(sizeof(*req), GFP_KERNEL);
if (!skb)
skb = adap->nofail_skb;
if (!skb)
return -ENOMEM;

req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
Expand All @@ -881,6 +933,12 @@ static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
req->max = hi;
req->binding = port;
ret = t3_mgmt_tx(adap, skb);
if (skb == adap->nofail_skb) {
adap->nofail_skb = alloc_skb(sizeof(struct cpl_set_tcb_field),
GFP_KERNEL);
if (!adap->nofail_skb)
ret = -ENOMEM;
}

return ret;
}
Expand Down Expand Up @@ -3020,6 +3078,14 @@ static int __devinit init_one(struct pci_dev *pdev,
goto out_disable_device;
}

adapter->nofail_skb =
alloc_skb(sizeof(struct cpl_set_tcb_field), GFP_KERNEL);
if (!adapter->nofail_skb) {
dev_err(&pdev->dev, "cannot allocate nofail buffer\n");
err = -ENOMEM;
goto out_free_adapter;
}

adapter->regs = ioremap_nocache(mmio_start, mmio_len);
if (!adapter->regs) {
dev_err(&pdev->dev, "cannot map device registers\n");
Expand Down Expand Up @@ -3176,6 +3242,8 @@ static void __devexit remove_one(struct pci_dev *pdev)
free_netdev(adapter->port[i]);

iounmap(adapter->regs);
if (adapter->nofail_skb)
kfree_skb(adapter->nofail_skb);
kfree(adapter);
pci_release_regions(pdev);
pci_disable_device(pdev);
Expand Down
27 changes: 25 additions & 2 deletions drivers/net/cxgb3/cxgb3_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -566,13 +566,31 @@ static void t3_process_tid_release_list(struct work_struct *work)
spin_unlock_bh(&td->tid_release_lock);

skb = alloc_skb(sizeof(struct cpl_tid_release),
GFP_KERNEL | __GFP_NOFAIL);
GFP_KERNEL);
if (!skb)
skb = td->nofail_skb;
if (!skb) {
spin_lock_bh(&td->tid_release_lock);
p->ctx = (void *)td->tid_release_list;
td->tid_release_list = (struct t3c_tid_entry *)p;
break;
}
mk_tid_release(skb, p - td->tid_maps.tid_tab);
cxgb3_ofld_send(tdev, skb);
p->ctx = NULL;
if (skb == td->nofail_skb)
td->nofail_skb =
alloc_skb(sizeof(struct cpl_tid_release),
GFP_KERNEL);
spin_lock_bh(&td->tid_release_lock);
}
td->release_list_incomplete = (td->tid_release_list == NULL) ? 0 : 1;
spin_unlock_bh(&td->tid_release_lock);

if (!td->nofail_skb)
td->nofail_skb =
alloc_skb(sizeof(struct cpl_tid_release),
GFP_KERNEL);
}

/* use ctx as a next pointer in the tid release list */
Expand All @@ -585,7 +603,7 @@ void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid)
p->ctx = (void *)td->tid_release_list;
p->client = NULL;
td->tid_release_list = p;
if (!p->ctx)
if (!p->ctx || td->release_list_incomplete)
schedule_work(&td->tid_release_task);
spin_unlock_bh(&td->tid_release_lock);
}
Expand Down Expand Up @@ -1274,6 +1292,9 @@ int cxgb3_offload_activate(struct adapter *adapter)
if (list_empty(&adapter_list))
register_netevent_notifier(&nb);

t->nofail_skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_KERNEL);
t->release_list_incomplete = 0;

add_adapter(adapter);
return 0;

Expand All @@ -1298,6 +1319,8 @@ void cxgb3_offload_deactivate(struct adapter *adapter)
T3C_DATA(tdev) = NULL;
t3_free_l2t(L2DATA(tdev));
L2DATA(tdev) = NULL;
if (t->nofail_skb)
kfree_skb(t->nofail_skb);
kfree(t);
}

Expand Down
3 changes: 3 additions & 0 deletions drivers/net/cxgb3/cxgb3_offload.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,9 @@ struct t3c_data {
struct t3c_tid_entry *tid_release_list;
spinlock_t tid_release_lock;
struct work_struct tid_release_task;

struct sk_buff *nofail_skb;
unsigned int release_list_incomplete;
};

/*
Expand Down

0 comments on commit 74b793e

Please sign in to comment.