Commit 74b793e1 authored by Divy Le Ray's avatar Divy Le Ray Committed by David S. Miller

cxgb3: remove __GFP_NOFAIL usage

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: default avatarDivy Le Ray <divy@chelsio.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 87433bfc
......@@ -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)
......
......@@ -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));
......@@ -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;
}
/**
......@@ -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;
......@@ -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;
}
......@@ -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");
......@@ -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);
......
......@@ -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 */
......@@ -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);
}
......@@ -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;
......@@ -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);
}
......
......@@ -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;
};
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment