1718cf2ccSPedro F. Giffuni /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
4fb93f5c4SNavdeep Parhar * Copyright (c) 2009-2013 Chelsio, Inc. All rights reserved.
5fb93f5c4SNavdeep Parhar *
6fb93f5c4SNavdeep Parhar * This software is available to you under a choice of one of two
7fb93f5c4SNavdeep Parhar * licenses. You may choose to be licensed under the terms of the GNU
8fb93f5c4SNavdeep Parhar * General Public License (GPL) Version 2, available from the file
9fb93f5c4SNavdeep Parhar * COPYING in the main directory of this source tree, or the
10fb93f5c4SNavdeep Parhar * OpenIB.org BSD license below:
11fb93f5c4SNavdeep Parhar *
12fb93f5c4SNavdeep Parhar * Redistribution and use in source and binary forms, with or
13fb93f5c4SNavdeep Parhar * without modification, are permitted provided that the following
14fb93f5c4SNavdeep Parhar * conditions are met:
15fb93f5c4SNavdeep Parhar *
16fb93f5c4SNavdeep Parhar * - Redistributions of source code must retain the above
17fb93f5c4SNavdeep Parhar * copyright notice, this list of conditions and the following
18fb93f5c4SNavdeep Parhar * disclaimer.
19fb93f5c4SNavdeep Parhar *
20fb93f5c4SNavdeep Parhar * - Redistributions in binary form must reproduce the above
21fb93f5c4SNavdeep Parhar * copyright notice, this list of conditions and the following
22fb93f5c4SNavdeep Parhar * disclaimer in the documentation and/or other materials
23fb93f5c4SNavdeep Parhar * provided with the distribution.
24fb93f5c4SNavdeep Parhar *
25fb93f5c4SNavdeep Parhar * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26fb93f5c4SNavdeep Parhar * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27fb93f5c4SNavdeep Parhar * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28fb93f5c4SNavdeep Parhar * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29fb93f5c4SNavdeep Parhar * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30fb93f5c4SNavdeep Parhar * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31fb93f5c4SNavdeep Parhar * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32fb93f5c4SNavdeep Parhar * SOFTWARE.
33fb93f5c4SNavdeep Parhar */
34fb93f5c4SNavdeep Parhar #include <sys/cdefs.h>
35fb93f5c4SNavdeep Parhar #include "opt_inet.h"
36fb93f5c4SNavdeep Parhar
37fb93f5c4SNavdeep Parhar #ifdef TCP_OFFLOAD
38fb93f5c4SNavdeep Parhar #include <linux/slab.h>
39fb93f5c4SNavdeep Parhar
40fb93f5c4SNavdeep Parhar #include "iw_cxgbe.h"
41fb93f5c4SNavdeep Parhar
print_tpte(struct adapter * sc,const u32 stag,const struct fw_ri_tpte * tpte)427adf138bSNavdeep Parhar static void print_tpte(struct adapter *sc, const u32 stag,
437adf138bSNavdeep Parhar const struct fw_ri_tpte *tpte)
447adf138bSNavdeep Parhar {
457adf138bSNavdeep Parhar const __be64 *p = (const void *)tpte;
467adf138bSNavdeep Parhar
477adf138bSNavdeep Parhar CH_ERR(sc, "stag idx 0x%x valid %d key 0x%x state %d pdid %d "
487adf138bSNavdeep Parhar "perm 0x%x ps %d len 0x%016llx va 0x%016llx\n",
497adf138bSNavdeep Parhar stag & 0xffffff00,
507adf138bSNavdeep Parhar G_FW_RI_TPTE_VALID(ntohl(tpte->valid_to_pdid)),
517adf138bSNavdeep Parhar G_FW_RI_TPTE_STAGKEY(ntohl(tpte->valid_to_pdid)),
527adf138bSNavdeep Parhar G_FW_RI_TPTE_STAGSTATE(ntohl(tpte->valid_to_pdid)),
537adf138bSNavdeep Parhar G_FW_RI_TPTE_PDID(ntohl(tpte->valid_to_pdid)),
547adf138bSNavdeep Parhar G_FW_RI_TPTE_PERM(ntohl(tpte->locread_to_qpid)),
557adf138bSNavdeep Parhar G_FW_RI_TPTE_PS(ntohl(tpte->locread_to_qpid)),
567adf138bSNavdeep Parhar (long long)(((u64)ntohl(tpte->len_hi) << 32) | ntohl(tpte->len_lo)),
577adf138bSNavdeep Parhar (long long)(((u64)ntohl(tpte->va_hi) << 32) | ntohl(tpte->va_lo_fbo)));
587adf138bSNavdeep Parhar CH_ERR(sc, "stag idx 0x%x: %016llx %016llx %016llx %016llx\n",
597adf138bSNavdeep Parhar stag & 0xffffff00,
607adf138bSNavdeep Parhar (long long)be64_to_cpu(p[0]), (long long)be64_to_cpu(p[1]),
617adf138bSNavdeep Parhar (long long)be64_to_cpu(p[2]), (long long)be64_to_cpu(p[3]));
627adf138bSNavdeep Parhar }
637adf138bSNavdeep Parhar
t4_dump_stag(struct adapter * sc,const u32 stag)647adf138bSNavdeep Parhar void t4_dump_stag(struct adapter *sc, const u32 stag)
657adf138bSNavdeep Parhar {
667adf138bSNavdeep Parhar struct fw_ri_tpte tpte __aligned(sizeof(__be64)) = {0};
677adf138bSNavdeep Parhar const u32 offset = sc->vres.stag.start + ((stag >> 8) * 32);
687adf138bSNavdeep Parhar
697adf138bSNavdeep Parhar if (offset > sc->vres.stag.start + sc->vres.stag.size - 32) {
707adf138bSNavdeep Parhar CH_ERR(sc, "stag 0x%x is invalid for current configuration.\n",
717adf138bSNavdeep Parhar stag);
727adf138bSNavdeep Parhar return;
737adf138bSNavdeep Parhar }
747adf138bSNavdeep Parhar read_via_memwin(sc, 0, offset, (u32 *)&tpte, 32);
757adf138bSNavdeep Parhar print_tpte(sc, stag, &tpte);
767adf138bSNavdeep Parhar }
777adf138bSNavdeep Parhar
t4_dump_all_stag(struct adapter * sc)787adf138bSNavdeep Parhar void t4_dump_all_stag(struct adapter *sc)
797adf138bSNavdeep Parhar {
807adf138bSNavdeep Parhar struct fw_ri_tpte tpte __aligned(sizeof(__be64)) = {0};
817adf138bSNavdeep Parhar const u32 first = sc->vres.stag.start;
827adf138bSNavdeep Parhar const u32 last = first + sc->vres.stag.size - 32;
837adf138bSNavdeep Parhar u32 offset, i;
847adf138bSNavdeep Parhar
857adf138bSNavdeep Parhar for (i = 0, offset = first; offset <= last; i++, offset += 32) {
867adf138bSNavdeep Parhar tpte.valid_to_pdid = 0;
877adf138bSNavdeep Parhar read_via_memwin(sc, 0, offset, (u32 *)&tpte, 4);
887adf138bSNavdeep Parhar if (tpte.valid_to_pdid != 0) {
897adf138bSNavdeep Parhar read_via_memwin(sc, 0, offset, (u32 *)&tpte, 32);
907adf138bSNavdeep Parhar print_tpte(sc, i << 8, &tpte);
917adf138bSNavdeep Parhar }
927adf138bSNavdeep Parhar }
937adf138bSNavdeep Parhar }
947adf138bSNavdeep Parhar
dump_err_cqe(struct c4iw_dev * dev,struct t4_cqe * err_cqe)957adf138bSNavdeep Parhar static void dump_err_cqe(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
967adf138bSNavdeep Parhar {
977adf138bSNavdeep Parhar struct adapter *sc = dev->rdev.adap;
987adf138bSNavdeep Parhar __be64 *p = (void *)err_cqe;
997adf138bSNavdeep Parhar
1007adf138bSNavdeep Parhar CH_ERR(sc, "AE qpid 0x%x opcode %d status 0x%x "
1017adf138bSNavdeep Parhar "type %d wrid.hi 0x%x wrid.lo 0x%x\n",
1027adf138bSNavdeep Parhar CQE_QPID(err_cqe), CQE_OPCODE(err_cqe),
1037adf138bSNavdeep Parhar CQE_STATUS(err_cqe), CQE_TYPE(err_cqe),
1047adf138bSNavdeep Parhar CQE_WRID_HI(err_cqe), CQE_WRID_LOW(err_cqe));
1057adf138bSNavdeep Parhar CH_ERR(sc, "%016llx %016llx %016llx %016llx\n",
1067adf138bSNavdeep Parhar (long long)be64_to_cpu(p[0]), (long long)be64_to_cpu(p[1]),
1077adf138bSNavdeep Parhar (long long)be64_to_cpu(p[2]), (long long)be64_to_cpu(p[3]));
1087adf138bSNavdeep Parhar
1097adf138bSNavdeep Parhar /*
1107adf138bSNavdeep Parhar * Ingress WRITE and READ_RESP errors provide
1117adf138bSNavdeep Parhar * the offending stag, so parse and log it.
1127adf138bSNavdeep Parhar */
1137adf138bSNavdeep Parhar if (RQ_TYPE(err_cqe) && (CQE_OPCODE(err_cqe) == FW_RI_RDMA_WRITE ||
1147adf138bSNavdeep Parhar CQE_OPCODE(err_cqe) == FW_RI_READ_RESP))
1157adf138bSNavdeep Parhar t4_dump_stag(sc, CQE_WRID_STAG(err_cqe));
1167adf138bSNavdeep Parhar }
1177adf138bSNavdeep Parhar
post_qp_event(struct c4iw_dev * dev,struct c4iw_cq * chp,struct c4iw_qp * qhp,struct t4_cqe * err_cqe,enum ib_event_type ib_event)118fb93f5c4SNavdeep Parhar static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp,
119fb93f5c4SNavdeep Parhar struct c4iw_qp *qhp,
120fb93f5c4SNavdeep Parhar struct t4_cqe *err_cqe,
121fb93f5c4SNavdeep Parhar enum ib_event_type ib_event)
122fb93f5c4SNavdeep Parhar {
123fb93f5c4SNavdeep Parhar struct ib_event event;
124fb93f5c4SNavdeep Parhar struct c4iw_qp_attributes attrs;
125fb93f5c4SNavdeep Parhar unsigned long flag;
126fb93f5c4SNavdeep Parhar
127fb93f5c4SNavdeep Parhar if ((qhp->attr.state == C4IW_QP_STATE_ERROR) ||
128fb93f5c4SNavdeep Parhar (qhp->attr.state == C4IW_QP_STATE_TERMINATE)) {
129fb93f5c4SNavdeep Parhar CTR4(KTR_IW_CXGBE, "%s AE received after RTS - "
130fb93f5c4SNavdeep Parhar "qp state %d qpid 0x%x status 0x%x", __func__,
131fb93f5c4SNavdeep Parhar qhp->attr.state, qhp->wq.sq.qid, CQE_STATUS(err_cqe));
132fb93f5c4SNavdeep Parhar return;
133fb93f5c4SNavdeep Parhar }
134fb93f5c4SNavdeep Parhar
1357adf138bSNavdeep Parhar dump_err_cqe(dev, err_cqe);
136fb93f5c4SNavdeep Parhar
137fb93f5c4SNavdeep Parhar if (qhp->attr.state == C4IW_QP_STATE_RTS) {
138fb93f5c4SNavdeep Parhar attrs.next_state = C4IW_QP_STATE_TERMINATE;
139fb93f5c4SNavdeep Parhar c4iw_modify_qp(qhp->rhp, qhp, C4IW_QP_ATTR_NEXT_STATE,
140fb93f5c4SNavdeep Parhar &attrs, 0);
141fb93f5c4SNavdeep Parhar }
142fb93f5c4SNavdeep Parhar
143fb93f5c4SNavdeep Parhar event.event = ib_event;
144fb93f5c4SNavdeep Parhar event.device = chp->ibcq.device;
145fb93f5c4SNavdeep Parhar if (ib_event == IB_EVENT_CQ_ERR)
146fb93f5c4SNavdeep Parhar event.element.cq = &chp->ibcq;
147fb93f5c4SNavdeep Parhar else
148fb93f5c4SNavdeep Parhar event.element.qp = &qhp->ibqp;
149fb93f5c4SNavdeep Parhar if (qhp->ibqp.event_handler)
150fb93f5c4SNavdeep Parhar (*qhp->ibqp.event_handler)(&event, qhp->ibqp.qp_context);
151fb93f5c4SNavdeep Parhar
152fb93f5c4SNavdeep Parhar spin_lock_irqsave(&chp->comp_handler_lock, flag);
153fb93f5c4SNavdeep Parhar (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
154fb93f5c4SNavdeep Parhar spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
155fb93f5c4SNavdeep Parhar }
156fb93f5c4SNavdeep Parhar
c4iw_ev_dispatch(struct c4iw_dev * dev,struct t4_cqe * err_cqe)157fb93f5c4SNavdeep Parhar void c4iw_ev_dispatch(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
158fb93f5c4SNavdeep Parhar {
159fb93f5c4SNavdeep Parhar struct c4iw_cq *chp;
160fb93f5c4SNavdeep Parhar struct c4iw_qp *qhp;
161fb93f5c4SNavdeep Parhar u32 cqid;
162fb93f5c4SNavdeep Parhar
163fb93f5c4SNavdeep Parhar spin_lock_irq(&dev->lock);
164fb93f5c4SNavdeep Parhar qhp = get_qhp(dev, CQE_QPID(err_cqe));
165fb93f5c4SNavdeep Parhar if (!qhp) {
166fb93f5c4SNavdeep Parhar printf("BAD AE qpid 0x%x opcode %d "
167fb93f5c4SNavdeep Parhar "status 0x%x type %d wrid.hi 0x%x wrid.lo 0x%x\n",
168fb93f5c4SNavdeep Parhar CQE_QPID(err_cqe),
169fb93f5c4SNavdeep Parhar CQE_OPCODE(err_cqe), CQE_STATUS(err_cqe),
170fb93f5c4SNavdeep Parhar CQE_TYPE(err_cqe), CQE_WRID_HI(err_cqe),
171fb93f5c4SNavdeep Parhar CQE_WRID_LOW(err_cqe));
172fb93f5c4SNavdeep Parhar spin_unlock_irq(&dev->lock);
173fb93f5c4SNavdeep Parhar goto out;
174fb93f5c4SNavdeep Parhar }
175fb93f5c4SNavdeep Parhar
176fb93f5c4SNavdeep Parhar if (SQ_TYPE(err_cqe))
177fb93f5c4SNavdeep Parhar cqid = qhp->attr.scq;
178fb93f5c4SNavdeep Parhar else
179fb93f5c4SNavdeep Parhar cqid = qhp->attr.rcq;
180fb93f5c4SNavdeep Parhar chp = get_chp(dev, cqid);
181fb93f5c4SNavdeep Parhar if (!chp) {
182fb93f5c4SNavdeep Parhar printf("BAD AE cqid 0x%x qpid 0x%x opcode %d "
183fb93f5c4SNavdeep Parhar "status 0x%x type %d wrid.hi 0x%x wrid.lo 0x%x\n",
184fb93f5c4SNavdeep Parhar cqid, CQE_QPID(err_cqe),
185fb93f5c4SNavdeep Parhar CQE_OPCODE(err_cqe), CQE_STATUS(err_cqe),
186fb93f5c4SNavdeep Parhar CQE_TYPE(err_cqe), CQE_WRID_HI(err_cqe),
187fb93f5c4SNavdeep Parhar CQE_WRID_LOW(err_cqe));
188fb93f5c4SNavdeep Parhar spin_unlock_irq(&dev->lock);
189fb93f5c4SNavdeep Parhar goto out;
190fb93f5c4SNavdeep Parhar }
191fb93f5c4SNavdeep Parhar
192fb93f5c4SNavdeep Parhar c4iw_qp_add_ref(&qhp->ibqp);
193fb93f5c4SNavdeep Parhar atomic_inc(&chp->refcnt);
194fb93f5c4SNavdeep Parhar spin_unlock_irq(&dev->lock);
195fb93f5c4SNavdeep Parhar
196fb93f5c4SNavdeep Parhar /* Bad incoming write */
197fb93f5c4SNavdeep Parhar if (RQ_TYPE(err_cqe) &&
198fb93f5c4SNavdeep Parhar (CQE_OPCODE(err_cqe) == FW_RI_RDMA_WRITE)) {
199fb93f5c4SNavdeep Parhar post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_REQ_ERR);
200fb93f5c4SNavdeep Parhar goto done;
201fb93f5c4SNavdeep Parhar }
202fb93f5c4SNavdeep Parhar
203fb93f5c4SNavdeep Parhar switch (CQE_STATUS(err_cqe)) {
204fb93f5c4SNavdeep Parhar
205fb93f5c4SNavdeep Parhar /* Completion Events */
206fb93f5c4SNavdeep Parhar case T4_ERR_SUCCESS:
207fb93f5c4SNavdeep Parhar printf(KERN_ERR MOD "AE with status 0!\n");
208fb93f5c4SNavdeep Parhar break;
209fb93f5c4SNavdeep Parhar
210fb93f5c4SNavdeep Parhar case T4_ERR_STAG:
211fb93f5c4SNavdeep Parhar case T4_ERR_PDID:
212fb93f5c4SNavdeep Parhar case T4_ERR_QPID:
213fb93f5c4SNavdeep Parhar case T4_ERR_ACCESS:
214fb93f5c4SNavdeep Parhar case T4_ERR_WRAP:
215fb93f5c4SNavdeep Parhar case T4_ERR_BOUND:
216fb93f5c4SNavdeep Parhar case T4_ERR_INVALIDATE_SHARED_MR:
217fb93f5c4SNavdeep Parhar case T4_ERR_INVALIDATE_MR_WITH_MW_BOUND:
218fb93f5c4SNavdeep Parhar post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_ACCESS_ERR);
219fb93f5c4SNavdeep Parhar break;
220fb93f5c4SNavdeep Parhar
221fb93f5c4SNavdeep Parhar /* Device Fatal Errors */
222fb93f5c4SNavdeep Parhar case T4_ERR_ECC:
223fb93f5c4SNavdeep Parhar case T4_ERR_ECC_PSTAG:
224fb93f5c4SNavdeep Parhar case T4_ERR_INTERNAL_ERR:
225fb93f5c4SNavdeep Parhar post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_DEVICE_FATAL);
226fb93f5c4SNavdeep Parhar break;
227fb93f5c4SNavdeep Parhar
228fb93f5c4SNavdeep Parhar /* QP Fatal Errors */
229fb93f5c4SNavdeep Parhar case T4_ERR_OUT_OF_RQE:
230fb93f5c4SNavdeep Parhar case T4_ERR_PBL_ADDR_BOUND:
231fb93f5c4SNavdeep Parhar case T4_ERR_CRC:
232fb93f5c4SNavdeep Parhar case T4_ERR_MARKER:
233fb93f5c4SNavdeep Parhar case T4_ERR_PDU_LEN_ERR:
234fb93f5c4SNavdeep Parhar case T4_ERR_DDP_VERSION:
235fb93f5c4SNavdeep Parhar case T4_ERR_RDMA_VERSION:
236fb93f5c4SNavdeep Parhar case T4_ERR_OPCODE:
237fb93f5c4SNavdeep Parhar case T4_ERR_DDP_QUEUE_NUM:
238fb93f5c4SNavdeep Parhar case T4_ERR_MSN:
239fb93f5c4SNavdeep Parhar case T4_ERR_TBIT:
240fb93f5c4SNavdeep Parhar case T4_ERR_MO:
241fb93f5c4SNavdeep Parhar case T4_ERR_MSN_GAP:
242fb93f5c4SNavdeep Parhar case T4_ERR_MSN_RANGE:
243fb93f5c4SNavdeep Parhar case T4_ERR_RQE_ADDR_BOUND:
244fb93f5c4SNavdeep Parhar case T4_ERR_IRD_OVERFLOW:
245fb93f5c4SNavdeep Parhar post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_FATAL);
246fb93f5c4SNavdeep Parhar break;
247fb93f5c4SNavdeep Parhar
248fb93f5c4SNavdeep Parhar default:
249fb93f5c4SNavdeep Parhar printf("Unknown T4 status 0x%x QPID 0x%x\n",
250fb93f5c4SNavdeep Parhar CQE_STATUS(err_cqe), qhp->wq.sq.qid);
251fb93f5c4SNavdeep Parhar post_qp_event(dev, chp, qhp, err_cqe, IB_EVENT_QP_FATAL);
252fb93f5c4SNavdeep Parhar break;
253fb93f5c4SNavdeep Parhar }
254fb93f5c4SNavdeep Parhar done:
255fb93f5c4SNavdeep Parhar if (atomic_dec_and_test(&chp->refcnt))
256fb93f5c4SNavdeep Parhar wake_up(&chp->wait);
257fb93f5c4SNavdeep Parhar c4iw_qp_rem_ref(&qhp->ibqp);
258fb93f5c4SNavdeep Parhar out:
259fb93f5c4SNavdeep Parhar return;
260fb93f5c4SNavdeep Parhar }
261fb93f5c4SNavdeep Parhar
c4iw_ev_handler(struct sge_iq * iq,const struct rsp_ctrl * rc)262fb93f5c4SNavdeep Parhar int c4iw_ev_handler(struct sge_iq *iq, const struct rsp_ctrl *rc)
263fb93f5c4SNavdeep Parhar {
264fb93f5c4SNavdeep Parhar struct c4iw_dev *dev = iq->adapter->iwarp_softc;
265fb93f5c4SNavdeep Parhar u32 qid = be32_to_cpu(rc->pldbuflen_qid);
266fb93f5c4SNavdeep Parhar struct c4iw_cq *chp;
267fb93f5c4SNavdeep Parhar unsigned long flag;
268fb93f5c4SNavdeep Parhar
269e6b775f4SNavdeep Parhar spin_lock_irqsave(&dev->lock, flag);
270fb93f5c4SNavdeep Parhar chp = get_chp(dev, qid);
271fb93f5c4SNavdeep Parhar if (chp) {
272e6b775f4SNavdeep Parhar atomic_inc(&chp->refcnt);
273e6b775f4SNavdeep Parhar spin_unlock_irqrestore(&dev->lock, flag);
274e6b775f4SNavdeep Parhar
275fb93f5c4SNavdeep Parhar spin_lock_irqsave(&chp->comp_handler_lock, flag);
276fb93f5c4SNavdeep Parhar (*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
277fb93f5c4SNavdeep Parhar spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
278e6b775f4SNavdeep Parhar if (atomic_dec_and_test(&chp->refcnt))
279e6b775f4SNavdeep Parhar wake_up(&chp->wait);
280e6b775f4SNavdeep Parhar } else {
281fb93f5c4SNavdeep Parhar CTR2(KTR_IW_CXGBE, "%s unknown cqid 0x%x", __func__, qid);
282e6b775f4SNavdeep Parhar spin_unlock_irqrestore(&dev->lock, flag);
283e6b775f4SNavdeep Parhar }
284e6b775f4SNavdeep Parhar
285fb93f5c4SNavdeep Parhar return 0;
286fb93f5c4SNavdeep Parhar }
287fb93f5c4SNavdeep Parhar #endif
288