···1362136213631363 ep = lookup_tid(t, tid);13641364 PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);13651365- BUG_ON(!ep);13651365+ if (!ep) {13661366+ printk(KERN_WARNING MOD "Abort rpl to freed endpoint\n");13671367+ return 0;13681368+ }13661369 mutex_lock(&ep->com.mutex);13671370 switch (ep->com.state) {13681371 case ABORTING:···14111408 printk(KERN_WARNING MOD "Connection problems for atid %u\n",14121409 atid);14131410 return 0;14111411+ }14121412+14131413+ /*14141414+ * Log interesting failures.14151415+ */14161416+ switch (status) {14171417+ case CPL_ERR_CONN_RESET:14181418+ case CPL_ERR_CONN_TIMEDOUT:14191419+ break;14201420+ default:14211421+ printk(KERN_INFO MOD "Active open failure - "14221422+ "atid %u status %u errno %d %pI4:%u->%pI4:%u\n",14231423+ atid, status, status2errno(status),14241424+ &ep->com.local_addr.sin_addr.s_addr,14251425+ ntohs(ep->com.local_addr.sin_port),14261426+ &ep->com.remote_addr.sin_addr.s_addr,14271427+ ntohs(ep->com.remote_addr.sin_port));14281428+ break;14141429 }1415143014161431 connect_reply_upcall(ep, status2errno(status));···16141593 n, n->dev, 0);16151594 if (!ep->l2t)16161595 goto out;16171617- ep->mtu = dst_mtu(ep->dst);15961596+ ep->mtu = dst_mtu(dst);16181597 ep->tx_chan = cxgb4_port_chan(n->dev);16191598 ep->smac_idx = (cxgb4_port_viid(n->dev) & 0x7F) << 1;16201599 step = cdev->rdev.lldi.ntxq /···26772656 unsigned int tid = GET_TID(req);2678265726792658 ep = lookup_tid(t, tid);26592659+ if (!ep) {26602660+ printk(KERN_WARNING MOD26612661+ "Abort on non-existent endpoint, tid %d\n", tid);26622662+ kfree_skb(skb);26632663+ return 0;26642664+ }26802665 if (is_neg_adv_abort(req->status)) {26812666 PDBG("%s neg_adv_abort ep %p tid %u\n", __func__, ep,26822667 ep->hwtid);···2694266726952668 /*26962669 * Wake up any threads in rdma_init() or rdma_fini().26972697- * However, this is not needed if com state is just26982698- * MPA_REQ_SENT26992670 */27002700- if (ep->com.state != MPA_REQ_SENT)27012701- c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);26712671+ c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);27022672 sched(dev, skb);27032673 return 0;27042674}
+329-11
drivers/infiniband/hw/cxgb4/device.c
···3232#include <linux/module.h>3333#include <linux/moduleparam.h>3434#include <linux/debugfs.h>3535+#include <linux/vmalloc.h>35363637#include <rdma/ib_verbs.h>3738···4443MODULE_DESCRIPTION("Chelsio T4 RDMA Driver");4544MODULE_LICENSE("Dual BSD/GPL");4645MODULE_VERSION(DRV_VERSION);4646+4747+struct uld_ctx {4848+ struct list_head entry;4949+ struct cxgb4_lld_info lldi;5050+ struct c4iw_dev *dev;5151+};47524853static LIST_HEAD(uld_ctx_list);4954static DEFINE_MUTEX(dev_mutex);···122115 printk(KERN_INFO "%s null qpd?\n", __func__);123116 return 0;124117 }125125- kfree(qpd->buf);118118+ vfree(qpd->buf);126119 kfree(qpd);127120 return 0;128121}···146139 spin_unlock_irq(&qpd->devp->lock);147140148141 qpd->bufsize = count * 128;149149- qpd->buf = kmalloc(qpd->bufsize, GFP_KERNEL);142142+ qpd->buf = vmalloc(qpd->bufsize);150143 if (!qpd->buf) {151144 ret = -ENOMEM;152145 goto err1;···247240 .llseek = default_llseek,248241};249242243243+static char *db_state_str[] = {"NORMAL", "FLOW_CONTROL", "RECOVERY"};244244+245245+static int stats_show(struct seq_file *seq, void *v)246246+{247247+ struct c4iw_dev *dev = seq->private;248248+249249+ seq_printf(seq, " Object: %10s %10s %10s %10s\n", "Total", "Current",250250+ "Max", "Fail");251251+ seq_printf(seq, " PDID: %10llu %10llu %10llu %10llu\n",252252+ dev->rdev.stats.pd.total, dev->rdev.stats.pd.cur,253253+ dev->rdev.stats.pd.max, dev->rdev.stats.pd.fail);254254+ seq_printf(seq, " QID: %10llu %10llu %10llu %10llu\n",255255+ dev->rdev.stats.qid.total, dev->rdev.stats.qid.cur,256256+ dev->rdev.stats.qid.max, dev->rdev.stats.qid.fail);257257+ seq_printf(seq, " TPTMEM: %10llu %10llu %10llu %10llu\n",258258+ dev->rdev.stats.stag.total, dev->rdev.stats.stag.cur,259259+ dev->rdev.stats.stag.max, dev->rdev.stats.stag.fail);260260+ seq_printf(seq, " PBLMEM: %10llu %10llu %10llu %10llu\n",261261+ dev->rdev.stats.pbl.total, dev->rdev.stats.pbl.cur,262262+ dev->rdev.stats.pbl.max, dev->rdev.stats.pbl.fail);263263+ seq_printf(seq, " RQTMEM: %10llu %10llu %10llu %10llu\n",264264+ dev->rdev.stats.rqt.total, dev->rdev.stats.rqt.cur,265265+ dev->rdev.stats.rqt.max, dev->rdev.stats.rqt.fail);266266+ seq_printf(seq, " OCQPMEM: %10llu %10llu %10llu %10llu\n",267267+ dev->rdev.stats.ocqp.total, dev->rdev.stats.ocqp.cur,268268+ dev->rdev.stats.ocqp.max, dev->rdev.stats.ocqp.fail);269269+ seq_printf(seq, " DB FULL: %10llu\n", dev->rdev.stats.db_full);270270+ seq_printf(seq, " DB EMPTY: %10llu\n", dev->rdev.stats.db_empty);271271+ seq_printf(seq, " DB DROP: %10llu\n", dev->rdev.stats.db_drop);272272+ seq_printf(seq, " DB State: %s Transitions %llu\n",273273+ db_state_str[dev->db_state],274274+ dev->rdev.stats.db_state_transitions);275275+ return 0;276276+}277277+278278+static int stats_open(struct inode *inode, struct file *file)279279+{280280+ return single_open(file, stats_show, inode->i_private);281281+}282282+283283+static ssize_t stats_clear(struct file *file, const char __user *buf,284284+ size_t count, loff_t *pos)285285+{286286+ struct c4iw_dev *dev = ((struct seq_file *)file->private_data)->private;287287+288288+ mutex_lock(&dev->rdev.stats.lock);289289+ dev->rdev.stats.pd.max = 0;290290+ dev->rdev.stats.pd.fail = 0;291291+ dev->rdev.stats.qid.max = 0;292292+ dev->rdev.stats.qid.fail = 0;293293+ dev->rdev.stats.stag.max = 0;294294+ dev->rdev.stats.stag.fail = 0;295295+ dev->rdev.stats.pbl.max = 0;296296+ dev->rdev.stats.pbl.fail = 0;297297+ dev->rdev.stats.rqt.max = 0;298298+ dev->rdev.stats.rqt.fail = 0;299299+ dev->rdev.stats.ocqp.max = 0;300300+ dev->rdev.stats.ocqp.fail = 0;301301+ dev->rdev.stats.db_full = 0;302302+ dev->rdev.stats.db_empty = 0;303303+ dev->rdev.stats.db_drop = 0;304304+ dev->rdev.stats.db_state_transitions = 0;305305+ mutex_unlock(&dev->rdev.stats.lock);306306+ return count;307307+}308308+309309+static const struct file_operations stats_debugfs_fops = {310310+ .owner = THIS_MODULE,311311+ .open = stats_open,312312+ .release = single_release,313313+ .read = seq_read,314314+ .llseek = seq_lseek,315315+ .write = stats_clear,316316+};317317+250318static int setup_debugfs(struct c4iw_dev *devp)251319{252320 struct dentry *de;···338256 (void *)devp, &stag_debugfs_fops);339257 if (de && de->d_inode)340258 de->d_inode->i_size = 4096;259259+260260+ de = debugfs_create_file("stats", S_IWUSR, devp->debugfs_root,261261+ (void *)devp, &stats_debugfs_fops);262262+ if (de && de->d_inode)263263+ de->d_inode->i_size = 4096;264264+341265 return 0;342266}343267···357269 list_for_each_safe(pos, nxt, &uctx->qpids) {358270 entry = list_entry(pos, struct c4iw_qid_list, entry);359271 list_del_init(&entry->entry);360360- if (!(entry->qid & rdev->qpmask))361361- c4iw_put_resource(&rdev->resource.qid_fifo, entry->qid,362362- &rdev->resource.qid_fifo_lock);272272+ if (!(entry->qid & rdev->qpmask)) {273273+ c4iw_put_resource(&rdev->resource.qid_table,274274+ entry->qid);275275+ mutex_lock(&rdev->stats.lock);276276+ rdev->stats.qid.cur -= rdev->qpmask + 1;277277+ mutex_unlock(&rdev->stats.lock);278278+ }363279 kfree(entry);364280 }365281···424332 goto err1;425333 }426334335335+ rdev->stats.pd.total = T4_MAX_NUM_PD;336336+ rdev->stats.stag.total = rdev->lldi.vr->stag.size;337337+ rdev->stats.pbl.total = rdev->lldi.vr->pbl.size;338338+ rdev->stats.rqt.total = rdev->lldi.vr->rq.size;339339+ rdev->stats.ocqp.total = rdev->lldi.vr->ocq.size;340340+ rdev->stats.qid.total = rdev->lldi.vr->qp.size;341341+427342 err = c4iw_init_resource(rdev, c4iw_num_stags(rdev), T4_MAX_NUM_PD);428343 if (err) {429344 printk(KERN_ERR MOD "error %d initializing resources\n", err);···468369 c4iw_rqtpool_destroy(rdev);469370 c4iw_destroy_resource(&rdev->resource);470371}471471-472472-struct uld_ctx {473473- struct list_head entry;474474- struct cxgb4_lld_info lldi;475475- struct c4iw_dev *dev;476476-};477372478373static void c4iw_dealloc(struct uld_ctx *ctx)479374{···533440 idr_init(&devp->qpidr);534441 idr_init(&devp->mmidr);535442 spin_lock_init(&devp->lock);443443+ mutex_init(&devp->rdev.stats.lock);444444+ mutex_init(&devp->db_mutex);536445537446 if (c4iw_debugfs_root) {538447 devp->debugfs_root = debugfs_create_dir(···680585 return 0;681586}682587588588+static int disable_qp_db(int id, void *p, void *data)589589+{590590+ struct c4iw_qp *qp = p;591591+592592+ t4_disable_wq_db(&qp->wq);593593+ return 0;594594+}595595+596596+static void stop_queues(struct uld_ctx *ctx)597597+{598598+ spin_lock_irq(&ctx->dev->lock);599599+ if (ctx->dev->db_state == NORMAL) {600600+ ctx->dev->rdev.stats.db_state_transitions++;601601+ ctx->dev->db_state = FLOW_CONTROL;602602+ idr_for_each(&ctx->dev->qpidr, disable_qp_db, NULL);603603+ }604604+ spin_unlock_irq(&ctx->dev->lock);605605+}606606+607607+static int enable_qp_db(int id, void *p, void *data)608608+{609609+ struct c4iw_qp *qp = p;610610+611611+ t4_enable_wq_db(&qp->wq);612612+ return 0;613613+}614614+615615+static void resume_queues(struct uld_ctx *ctx)616616+{617617+ spin_lock_irq(&ctx->dev->lock);618618+ if (ctx->dev->qpcnt <= db_fc_threshold &&619619+ ctx->dev->db_state == FLOW_CONTROL) {620620+ ctx->dev->db_state = NORMAL;621621+ ctx->dev->rdev.stats.db_state_transitions++;622622+ idr_for_each(&ctx->dev->qpidr, enable_qp_db, NULL);623623+ }624624+ spin_unlock_irq(&ctx->dev->lock);625625+}626626+627627+struct qp_list {628628+ unsigned idx;629629+ struct c4iw_qp **qps;630630+};631631+632632+static int add_and_ref_qp(int id, void *p, void *data)633633+{634634+ struct qp_list *qp_listp = data;635635+ struct c4iw_qp *qp = p;636636+637637+ c4iw_qp_add_ref(&qp->ibqp);638638+ qp_listp->qps[qp_listp->idx++] = qp;639639+ return 0;640640+}641641+642642+static int count_qps(int id, void *p, void *data)643643+{644644+ unsigned *countp = data;645645+ (*countp)++;646646+ return 0;647647+}648648+649649+static void deref_qps(struct qp_list qp_list)650650+{651651+ int idx;652652+653653+ for (idx = 0; idx < qp_list.idx; idx++)654654+ c4iw_qp_rem_ref(&qp_list.qps[idx]->ibqp);655655+}656656+657657+static void recover_lost_dbs(struct uld_ctx *ctx, struct qp_list *qp_list)658658+{659659+ int idx;660660+ int ret;661661+662662+ for (idx = 0; idx < qp_list->idx; idx++) {663663+ struct c4iw_qp *qp = qp_list->qps[idx];664664+665665+ ret = cxgb4_sync_txq_pidx(qp->rhp->rdev.lldi.ports[0],666666+ qp->wq.sq.qid,667667+ t4_sq_host_wq_pidx(&qp->wq),668668+ t4_sq_wq_size(&qp->wq));669669+ if (ret) {670670+ printk(KERN_ERR MOD "%s: Fatal error - "671671+ "DB overflow recovery failed - "672672+ "error syncing SQ qid %u\n",673673+ pci_name(ctx->lldi.pdev), qp->wq.sq.qid);674674+ return;675675+ }676676+677677+ ret = cxgb4_sync_txq_pidx(qp->rhp->rdev.lldi.ports[0],678678+ qp->wq.rq.qid,679679+ t4_rq_host_wq_pidx(&qp->wq),680680+ t4_rq_wq_size(&qp->wq));681681+682682+ if (ret) {683683+ printk(KERN_ERR MOD "%s: Fatal error - "684684+ "DB overflow recovery failed - "685685+ "error syncing RQ qid %u\n",686686+ pci_name(ctx->lldi.pdev), qp->wq.rq.qid);687687+ return;688688+ }689689+690690+ /* Wait for the dbfifo to drain */691691+ while (cxgb4_dbfifo_count(qp->rhp->rdev.lldi.ports[0], 1) > 0) {692692+ set_current_state(TASK_UNINTERRUPTIBLE);693693+ schedule_timeout(usecs_to_jiffies(10));694694+ }695695+ }696696+}697697+698698+static void recover_queues(struct uld_ctx *ctx)699699+{700700+ int count = 0;701701+ struct qp_list qp_list;702702+ int ret;703703+704704+ /* lock out kernel db ringers */705705+ mutex_lock(&ctx->dev->db_mutex);706706+707707+ /* put all queues in to recovery mode */708708+ spin_lock_irq(&ctx->dev->lock);709709+ ctx->dev->db_state = RECOVERY;710710+ ctx->dev->rdev.stats.db_state_transitions++;711711+ idr_for_each(&ctx->dev->qpidr, disable_qp_db, NULL);712712+ spin_unlock_irq(&ctx->dev->lock);713713+714714+ /* slow everybody down */715715+ set_current_state(TASK_UNINTERRUPTIBLE);716716+ schedule_timeout(usecs_to_jiffies(1000));717717+718718+ /* Wait for the dbfifo to completely drain. */719719+ while (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) > 0) {720720+ set_current_state(TASK_UNINTERRUPTIBLE);721721+ schedule_timeout(usecs_to_jiffies(10));722722+ }723723+724724+ /* flush the SGE contexts */725725+ ret = cxgb4_flush_eq_cache(ctx->dev->rdev.lldi.ports[0]);726726+ if (ret) {727727+ printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n",728728+ pci_name(ctx->lldi.pdev));729729+ goto out;730730+ }731731+732732+ /* Count active queues so we can build a list of queues to recover */733733+ spin_lock_irq(&ctx->dev->lock);734734+ idr_for_each(&ctx->dev->qpidr, count_qps, &count);735735+736736+ qp_list.qps = kzalloc(count * sizeof *qp_list.qps, GFP_ATOMIC);737737+ if (!qp_list.qps) {738738+ printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n",739739+ pci_name(ctx->lldi.pdev));740740+ spin_unlock_irq(&ctx->dev->lock);741741+ goto out;742742+ }743743+ qp_list.idx = 0;744744+745745+ /* add and ref each qp so it doesn't get freed */746746+ idr_for_each(&ctx->dev->qpidr, add_and_ref_qp, &qp_list);747747+748748+ spin_unlock_irq(&ctx->dev->lock);749749+750750+ /* now traverse the list in a safe context to recover the db state*/751751+ recover_lost_dbs(ctx, &qp_list);752752+753753+ /* we're almost done! deref the qps and clean up */754754+ deref_qps(qp_list);755755+ kfree(qp_list.qps);756756+757757+ /* Wait for the dbfifo to completely drain again */758758+ while (cxgb4_dbfifo_count(ctx->dev->rdev.lldi.ports[0], 1) > 0) {759759+ set_current_state(TASK_UNINTERRUPTIBLE);760760+ schedule_timeout(usecs_to_jiffies(10));761761+ }762762+763763+ /* resume the queues */764764+ spin_lock_irq(&ctx->dev->lock);765765+ if (ctx->dev->qpcnt > db_fc_threshold)766766+ ctx->dev->db_state = FLOW_CONTROL;767767+ else {768768+ ctx->dev->db_state = NORMAL;769769+ idr_for_each(&ctx->dev->qpidr, enable_qp_db, NULL);770770+ }771771+ ctx->dev->rdev.stats.db_state_transitions++;772772+ spin_unlock_irq(&ctx->dev->lock);773773+774774+out:775775+ /* start up kernel db ringers again */776776+ mutex_unlock(&ctx->dev->db_mutex);777777+}778778+779779+static int c4iw_uld_control(void *handle, enum cxgb4_control control, ...)780780+{781781+ struct uld_ctx *ctx = handle;782782+783783+ switch (control) {784784+ case CXGB4_CONTROL_DB_FULL:785785+ stop_queues(ctx);786786+ mutex_lock(&ctx->dev->rdev.stats.lock);787787+ ctx->dev->rdev.stats.db_full++;788788+ mutex_unlock(&ctx->dev->rdev.stats.lock);789789+ break;790790+ case CXGB4_CONTROL_DB_EMPTY:791791+ resume_queues(ctx);792792+ mutex_lock(&ctx->dev->rdev.stats.lock);793793+ ctx->dev->rdev.stats.db_empty++;794794+ mutex_unlock(&ctx->dev->rdev.stats.lock);795795+ break;796796+ case CXGB4_CONTROL_DB_DROP:797797+ recover_queues(ctx);798798+ mutex_lock(&ctx->dev->rdev.stats.lock);799799+ ctx->dev->rdev.stats.db_drop++;800800+ mutex_unlock(&ctx->dev->rdev.stats.lock);801801+ break;802802+ default:803803+ printk(KERN_WARNING MOD "%s: unknown control cmd %u\n",804804+ pci_name(ctx->lldi.pdev), control);805805+ break;806806+ }807807+ return 0;808808+}809809+683810static struct cxgb4_uld_info c4iw_uld_info = {684811 .name = DRV_NAME,685812 .add = c4iw_uld_add,686813 .rx_handler = c4iw_uld_rx_handler,687814 .state_change = c4iw_uld_state_change,815815+ .control = c4iw_uld_control,688816};689817690818static int __init c4iw_init_module(void)
···11+/*22+ * Copyright (c) 2011 Chelsio Communications. All rights reserved.33+ *44+ * This software is available to you under a choice of one of two55+ * licenses. You may choose to be licensed under the terms of the GNU66+ * General Public License (GPL) Version 2, available from the file77+ * COPYING in the main directory of this source tree, or the88+ * OpenIB.org BSD license below:99+ *1010+ * Redistribution and use in source and binary forms, with or1111+ * without modification, are permitted provided that the following1212+ * conditions are met:1313+ *1414+ * - Redistributions of source code must retain the above1515+ * copyright notice, this list of conditions and the following1616+ * disclaimer.1717+ *1818+ * - Redistributions in binary form must reproduce the above1919+ * copyright notice, this list of conditions and the following2020+ * disclaimer in the documentation and/or other materials2121+ * provided with the distribution.2222+ *2323+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,2424+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF2525+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND2626+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS2727+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN2828+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN2929+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE3030+ * SOFTWARE.3131+ */3232+#include <linux/kernel.h>3333+#include <linux/random.h>3434+#include "iw_cxgb4.h"3535+3636+#define RANDOM_SKIP 163737+3838+/*3939+ * Trivial bitmap-based allocator. If the random flag is set, the4040+ * allocator is designed to:4141+ * - pseudo-randomize the id returned such that it is not trivially predictable.4242+ * - avoid reuse of recently used id (at the expense of predictability)4343+ */4444+u32 c4iw_id_alloc(struct c4iw_id_table *alloc)4545+{4646+ unsigned long flags;4747+ u32 obj;4848+4949+ spin_lock_irqsave(&alloc->lock, flags);5050+5151+ obj = find_next_zero_bit(alloc->table, alloc->max, alloc->last);5252+ if (obj >= alloc->max)5353+ obj = find_first_zero_bit(alloc->table, alloc->max);5454+5555+ if (obj < alloc->max) {5656+ if (alloc->flags & C4IW_ID_TABLE_F_RANDOM)5757+ alloc->last += random32() % RANDOM_SKIP;5858+ else5959+ alloc->last = obj + 1;6060+ if (alloc->last >= alloc->max)6161+ alloc->last = 0;6262+ set_bit(obj, alloc->table);6363+ obj += alloc->start;6464+ } else6565+ obj = -1;6666+6767+ spin_unlock_irqrestore(&alloc->lock, flags);6868+ return obj;6969+}7070+7171+void c4iw_id_free(struct c4iw_id_table *alloc, u32 obj)7272+{7373+ unsigned long flags;7474+7575+ obj -= alloc->start;7676+ BUG_ON((int)obj < 0);7777+7878+ spin_lock_irqsave(&alloc->lock, flags);7979+ clear_bit(obj, alloc->table);8080+ spin_unlock_irqrestore(&alloc->lock, flags);8181+}8282+8383+int c4iw_id_table_alloc(struct c4iw_id_table *alloc, u32 start, u32 num,8484+ u32 reserved, u32 flags)8585+{8686+ int i;8787+8888+ alloc->start = start;8989+ alloc->flags = flags;9090+ if (flags & C4IW_ID_TABLE_F_RANDOM)9191+ alloc->last = random32() % RANDOM_SKIP;9292+ else9393+ alloc->last = 0;9494+ alloc->max = num;9595+ spin_lock_init(&alloc->lock);9696+ alloc->table = kmalloc(BITS_TO_LONGS(num) * sizeof(long),9797+ GFP_KERNEL);9898+ if (!alloc->table)9999+ return -ENOMEM;100100+101101+ bitmap_zero(alloc->table, num);102102+ if (!(alloc->flags & C4IW_ID_TABLE_F_EMPTY))103103+ for (i = 0; i < reserved; ++i)104104+ set_bit(i, alloc->table);105105+106106+ return 0;107107+}108108+109109+void c4iw_id_table_free(struct c4iw_id_table *alloc)110110+{111111+ kfree(alloc->table);112112+}
···3232#ifndef __C4IW_USER_H__3333#define __C4IW_USER_H__34343535-#define C4IW_UVERBS_ABI_VERSION 13535+#define C4IW_UVERBS_ABI_VERSION 236363737/*3838 * Make sure that all structs defined in this file remain laid out so
···11+/*******************************************************************22+ * This file is part of the Emulex RoCE Device Driver for *33+ * RoCE (RDMA over Converged Ethernet) adapters. *44+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *55+ * EMULEX and SLI are trademarks of Emulex. *66+ * www.emulex.com *77+ * *88+ * This program is free software; you can redistribute it and/or *99+ * modify it under the terms of version 2 of the GNU General *1010+ * Public License as published by the Free Software Foundation. *1111+ * This program is distributed in the hope that it will be useful. *1212+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *1313+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *1414+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *1515+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *1616+ * TO BE LEGALLY INVALID. See the GNU General Public License for *1717+ * more details, a copy of which can be found in the file COPYING *1818+ * included with this package. *1919+ *2020+ * Contact Information:2121+ * linux-drivers@emulex.com2222+ *2323+ * Emulex2424+ * 3333 Susan Street2525+ * Costa Mesa, CA 926262626+ *******************************************************************/2727+2828+#ifndef __OCRDMA_H__2929+#define __OCRDMA_H__3030+3131+#include <linux/mutex.h>3232+#include <linux/list.h>3333+#include <linux/spinlock.h>3434+#include <linux/pci.h>3535+3636+#include <rdma/ib_verbs.h>3737+#include <rdma/ib_user_verbs.h>3838+3939+#include <be_roce.h>4040+#include "ocrdma_sli.h"4141+4242+#define OCRDMA_ROCE_DEV_VERSION "1.0.0"4343+#define OCRDMA_NODE_DESC "Emulex OneConnect RoCE HCA"4444+4545+#define ocrdma_err(format, arg...) printk(KERN_ERR format, ##arg)4646+4747+#define OCRDMA_MAX_AH 5124848+4949+#define OCRDMA_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME)5050+5151+struct ocrdma_dev_attr {5252+ u8 fw_ver[32];5353+ u32 vendor_id;5454+ u32 device_id;5555+ u16 max_pd;5656+ u16 max_cq;5757+ u16 max_cqe;5858+ u16 max_qp;5959+ u16 max_wqe;6060+ u16 max_rqe;6161+ u32 max_inline_data;6262+ int max_send_sge;6363+ int max_recv_sge;6464+ int max_mr;6565+ u64 max_mr_size;6666+ u32 max_num_mr_pbl;6767+ int max_fmr;6868+ int max_map_per_fmr;6969+ int max_pages_per_frmr;7070+ u16 max_ord_per_qp;7171+ u16 max_ird_per_qp;7272+7373+ int device_cap_flags;7474+ u8 cq_overflow_detect;7575+ u8 srq_supported;7676+7777+ u32 wqe_size;7878+ u32 rqe_size;7979+ u32 ird_page_size;8080+ u8 local_ca_ack_delay;8181+ u8 ird;8282+ u8 num_ird_pages;8383+};8484+8585+struct ocrdma_pbl {8686+ void *va;8787+ dma_addr_t pa;8888+};8989+9090+struct ocrdma_queue_info {9191+ void *va;9292+ dma_addr_t dma;9393+ u32 size;9494+ u16 len;9595+ u16 entry_size; /* Size of an element in the queue */9696+ u16 id; /* qid, where to ring the doorbell. */9797+ u16 head, tail;9898+ bool created;9999+ atomic_t used; /* Number of valid elements in the queue */100100+};101101+102102+struct ocrdma_eq {103103+ struct ocrdma_queue_info q;104104+ u32 vector;105105+ int cq_cnt;106106+ struct ocrdma_dev *dev;107107+ char irq_name[32];108108+};109109+110110+struct ocrdma_mq {111111+ struct ocrdma_queue_info sq;112112+ struct ocrdma_queue_info cq;113113+ bool rearm_cq;114114+};115115+116116+struct mqe_ctx {117117+ struct mutex lock; /* for serializing mailbox commands on MQ */118118+ wait_queue_head_t cmd_wait;119119+ u32 tag;120120+ u16 cqe_status;121121+ u16 ext_status;122122+ bool cmd_done;123123+};124124+125125+struct ocrdma_dev {126126+ struct ib_device ibdev;127127+ struct ocrdma_dev_attr attr;128128+129129+ struct mutex dev_lock; /* provides syncronise access to device data */130130+ spinlock_t flush_q_lock ____cacheline_aligned;131131+132132+ struct ocrdma_cq **cq_tbl;133133+ struct ocrdma_qp **qp_tbl;134134+135135+ struct ocrdma_eq meq;136136+ struct ocrdma_eq *qp_eq_tbl;137137+ int eq_cnt;138138+ u16 base_eqid;139139+ u16 max_eq;140140+141141+ union ib_gid *sgid_tbl;142142+ /* provided synchronization to sgid table for143143+ * updating gid entries triggered by notifier.144144+ */145145+ spinlock_t sgid_lock;146146+147147+ int gsi_qp_created;148148+ struct ocrdma_cq *gsi_sqcq;149149+ struct ocrdma_cq *gsi_rqcq;150150+151151+ struct {152152+ struct ocrdma_av *va;153153+ dma_addr_t pa;154154+ u32 size;155155+ u32 num_ah;156156+ /* provide synchronization for av157157+ * entry allocations.158158+ */159159+ spinlock_t lock;160160+ u32 ahid;161161+ struct ocrdma_pbl pbl;162162+ } av_tbl;163163+164164+ void *mbx_cmd;165165+ struct ocrdma_mq mq;166166+ struct mqe_ctx mqe_ctx;167167+168168+ struct be_dev_info nic_info;169169+170170+ struct list_head entry;171171+ struct rcu_head rcu;172172+ int id;173173+};174174+175175+struct ocrdma_cq {176176+ struct ib_cq ibcq;177177+ struct ocrdma_dev *dev;178178+ struct ocrdma_cqe *va;179179+ u32 phase;180180+ u32 getp; /* pointer to pending wrs to181181+ * return to stack, wrap arounds182182+ * at max_hw_cqe183183+ */184184+ u32 max_hw_cqe;185185+ bool phase_change;186186+ bool armed, solicited;187187+ bool arm_needed;188188+189189+ spinlock_t cq_lock ____cacheline_aligned; /* provide synchronization190190+ * to cq polling191191+ */192192+ /* syncronizes cq completion handler invoked from multiple context */193193+ spinlock_t comp_handler_lock ____cacheline_aligned;194194+ u16 id;195195+ u16 eqn;196196+197197+ struct ocrdma_ucontext *ucontext;198198+ dma_addr_t pa;199199+ u32 len;200200+ atomic_t use_cnt;201201+202202+ /* head of all qp's sq and rq for which cqes need to be flushed203203+ * by the software.204204+ */205205+ struct list_head sq_head, rq_head;206206+};207207+208208+struct ocrdma_pd {209209+ struct ib_pd ibpd;210210+ struct ocrdma_dev *dev;211211+ struct ocrdma_ucontext *uctx;212212+ atomic_t use_cnt;213213+ u32 id;214214+ int num_dpp_qp;215215+ u32 dpp_page;216216+ bool dpp_enabled;217217+};218218+219219+struct ocrdma_ah {220220+ struct ib_ah ibah;221221+ struct ocrdma_dev *dev;222222+ struct ocrdma_av *av;223223+ u16 sgid_index;224224+ u32 id;225225+};226226+227227+struct ocrdma_qp_hwq_info {228228+ u8 *va; /* virtual address */229229+ u32 max_sges;230230+ u32 head, tail;231231+ u32 entry_size;232232+ u32 max_cnt;233233+ u32 max_wqe_idx;234234+ u32 free_delta;235235+ u16 dbid; /* qid, where to ring the doorbell. */236236+ u32 len;237237+ dma_addr_t pa;238238+};239239+240240+struct ocrdma_srq {241241+ struct ib_srq ibsrq;242242+ struct ocrdma_dev *dev;243243+ u8 __iomem *db;244244+ /* provide synchronization to multiple context(s) posting rqe */245245+ spinlock_t q_lock ____cacheline_aligned;246246+247247+ struct ocrdma_qp_hwq_info rq;248248+ struct ocrdma_pd *pd;249249+ atomic_t use_cnt;250250+ u32 id;251251+ u64 *rqe_wr_id_tbl;252252+ u32 *idx_bit_fields;253253+ u32 bit_fields_len;254254+};255255+256256+struct ocrdma_qp {257257+ struct ib_qp ibqp;258258+ struct ocrdma_dev *dev;259259+260260+ u8 __iomem *sq_db;261261+ /* provide synchronization to multiple context(s) posting wqe, rqe */262262+ spinlock_t q_lock ____cacheline_aligned;263263+ struct ocrdma_qp_hwq_info sq;264264+ struct {265265+ uint64_t wrid;266266+ uint16_t dpp_wqe_idx;267267+ uint16_t dpp_wqe;268268+ uint8_t signaled;269269+ uint8_t rsvd[3];270270+ } *wqe_wr_id_tbl;271271+ u32 max_inline_data;272272+ struct ocrdma_cq *sq_cq;273273+ /* list maintained per CQ to flush SQ errors */274274+ struct list_head sq_entry;275275+276276+ u8 __iomem *rq_db;277277+ struct ocrdma_qp_hwq_info rq;278278+ u64 *rqe_wr_id_tbl;279279+ struct ocrdma_cq *rq_cq;280280+ struct ocrdma_srq *srq;281281+ /* list maintained per CQ to flush RQ errors */282282+ struct list_head rq_entry;283283+284284+ enum ocrdma_qp_state state; /* QP state */285285+ int cap_flags;286286+ u32 max_ord, max_ird;287287+288288+ u32 id;289289+ struct ocrdma_pd *pd;290290+291291+ enum ib_qp_type qp_type;292292+293293+ int sgid_idx;294294+ u32 qkey;295295+ bool dpp_enabled;296296+ u8 *ird_q_va;297297+};298298+299299+#define OCRDMA_GET_NUM_POSTED_SHIFT_VAL(qp) \300300+ (((qp->dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) && \301301+ (qp->id < 64)) ? 24 : 16)302302+303303+struct ocrdma_hw_mr {304304+ struct ocrdma_dev *dev;305305+ u32 lkey;306306+ u8 fr_mr;307307+ u8 remote_atomic;308308+ u8 remote_rd;309309+ u8 remote_wr;310310+ u8 local_rd;311311+ u8 local_wr;312312+ u8 mw_bind;313313+ u8 rsvd;314314+ u64 len;315315+ struct ocrdma_pbl *pbl_table;316316+ u32 num_pbls;317317+ u32 num_pbes;318318+ u32 pbl_size;319319+ u32 pbe_size;320320+ u64 fbo;321321+ u64 va;322322+};323323+324324+struct ocrdma_mr {325325+ struct ib_mr ibmr;326326+ struct ib_umem *umem;327327+ struct ocrdma_hw_mr hwmr;328328+ struct ocrdma_pd *pd;329329+};330330+331331+struct ocrdma_ucontext {332332+ struct ib_ucontext ibucontext;333333+ struct ocrdma_dev *dev;334334+335335+ struct list_head mm_head;336336+ struct mutex mm_list_lock; /* protects list entries of mm type */337337+ struct {338338+ u32 *va;339339+ dma_addr_t pa;340340+ u32 len;341341+ } ah_tbl;342342+};343343+344344+struct ocrdma_mm {345345+ struct {346346+ u64 phy_addr;347347+ unsigned long len;348348+ } key;349349+ struct list_head entry;350350+};351351+352352+static inline struct ocrdma_dev *get_ocrdma_dev(struct ib_device *ibdev)353353+{354354+ return container_of(ibdev, struct ocrdma_dev, ibdev);355355+}356356+357357+static inline struct ocrdma_ucontext *get_ocrdma_ucontext(struct ib_ucontext358358+ *ibucontext)359359+{360360+ return container_of(ibucontext, struct ocrdma_ucontext, ibucontext);361361+}362362+363363+static inline struct ocrdma_pd *get_ocrdma_pd(struct ib_pd *ibpd)364364+{365365+ return container_of(ibpd, struct ocrdma_pd, ibpd);366366+}367367+368368+static inline struct ocrdma_cq *get_ocrdma_cq(struct ib_cq *ibcq)369369+{370370+ return container_of(ibcq, struct ocrdma_cq, ibcq);371371+}372372+373373+static inline struct ocrdma_qp *get_ocrdma_qp(struct ib_qp *ibqp)374374+{375375+ return container_of(ibqp, struct ocrdma_qp, ibqp);376376+}377377+378378+static inline struct ocrdma_mr *get_ocrdma_mr(struct ib_mr *ibmr)379379+{380380+ return container_of(ibmr, struct ocrdma_mr, ibmr);381381+}382382+383383+static inline struct ocrdma_ah *get_ocrdma_ah(struct ib_ah *ibah)384384+{385385+ return container_of(ibah, struct ocrdma_ah, ibah);386386+}387387+388388+static inline struct ocrdma_srq *get_ocrdma_srq(struct ib_srq *ibsrq)389389+{390390+ return container_of(ibsrq, struct ocrdma_srq, ibsrq);391391+}392392+393393+#endif
+134
drivers/infiniband/hw/ocrdma/ocrdma_abi.h
···11+/*******************************************************************22+ * This file is part of the Emulex RoCE Device Driver for *33+ * RoCE (RDMA over Converged Ethernet) adapters. *44+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *55+ * EMULEX and SLI are trademarks of Emulex. *66+ * www.emulex.com *77+ * *88+ * This program is free software; you can redistribute it and/or *99+ * modify it under the terms of version 2 of the GNU General *1010+ * Public License as published by the Free Software Foundation. *1111+ * This program is distributed in the hope that it will be useful. *1212+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *1313+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *1414+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *1515+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *1616+ * TO BE LEGALLY INVALID. See the GNU General Public License for *1717+ * more details, a copy of which can be found in the file COPYING *1818+ * included with this package. *1919+ *2020+ * Contact Information:2121+ * linux-drivers@emulex.com2222+ *2323+ * Emulex2424+ * 3333 Susan Street2525+ * Costa Mesa, CA 926262626+ *******************************************************************/2727+2828+#ifndef __OCRDMA_ABI_H__2929+#define __OCRDMA_ABI_H__3030+3131+struct ocrdma_alloc_ucontext_resp {3232+ u32 dev_id;3333+ u32 wqe_size;3434+ u32 max_inline_data;3535+ u32 dpp_wqe_size;3636+ u64 ah_tbl_page;3737+ u32 ah_tbl_len;3838+ u32 rsvd;3939+ u8 fw_ver[32];4040+ u32 rqe_size;4141+ u64 rsvd1;4242+} __packed;4343+4444+/* user kernel communication data structures. */4545+struct ocrdma_alloc_pd_ureq {4646+ u64 rsvd1;4747+} __packed;4848+4949+struct ocrdma_alloc_pd_uresp {5050+ u32 id;5151+ u32 dpp_enabled;5252+ u32 dpp_page_addr_hi;5353+ u32 dpp_page_addr_lo;5454+ u64 rsvd1;5555+} __packed;5656+5757+struct ocrdma_create_cq_ureq {5858+ u32 dpp_cq;5959+ u32 rsvd;6060+} __packed;6161+6262+#define MAX_CQ_PAGES 86363+struct ocrdma_create_cq_uresp {6464+ u32 cq_id;6565+ u32 page_size;6666+ u32 num_pages;6767+ u32 max_hw_cqe;6868+ u64 page_addr[MAX_CQ_PAGES];6969+ u64 db_page_addr;7070+ u32 db_page_size;7171+ u32 phase_change;7272+ u64 rsvd1;7373+ u64 rsvd2;7474+} __packed;7575+7676+#define MAX_QP_PAGES 87777+#define MAX_UD_AV_PAGES 87878+7979+struct ocrdma_create_qp_ureq {8080+ u8 enable_dpp_cq;8181+ u8 rsvd;8282+ u16 dpp_cq_id;8383+ u32 rsvd1;8484+};8585+8686+struct ocrdma_create_qp_uresp {8787+ u16 qp_id;8888+ u16 sq_dbid;8989+ u16 rq_dbid;9090+ u16 resv0;9191+ u32 sq_page_size;9292+ u32 rq_page_size;9393+ u32 num_sq_pages;9494+ u32 num_rq_pages;9595+ u64 sq_page_addr[MAX_QP_PAGES];9696+ u64 rq_page_addr[MAX_QP_PAGES];9797+ u64 db_page_addr;9898+ u32 db_page_size;9999+ u32 dpp_credit;100100+ u32 dpp_offset;101101+ u32 rsvd1;102102+ u32 num_wqe_allocated;103103+ u32 num_rqe_allocated;104104+ u32 free_wqe_delta;105105+ u32 free_rqe_delta;106106+ u32 db_sq_offset;107107+ u32 db_rq_offset;108108+ u32 db_shift;109109+ u64 rsvd2;110110+ u64 rsvd3;111111+} __packed;112112+113113+struct ocrdma_create_srq_uresp {114114+ u16 rq_dbid;115115+ u16 resv0;116116+ u32 resv1;117117+118118+ u32 rq_page_size;119119+ u32 num_rq_pages;120120+121121+ u64 rq_page_addr[MAX_QP_PAGES];122122+ u64 db_page_addr;123123+124124+ u32 db_page_size;125125+ u32 num_rqe_allocated;126126+ u32 db_rq_offset;127127+ u32 db_shift;128128+129129+ u32 free_rqe_delta;130130+ u32 rsvd2;131131+ u64 rsvd3;132132+} __packed;133133+134134+#endif /* __OCRDMA_ABI_H__ */
+172
drivers/infiniband/hw/ocrdma/ocrdma_ah.c
···11+/*******************************************************************22+ * This file is part of the Emulex RoCE Device Driver for *33+ * RoCE (RDMA over Converged Ethernet) adapters. *44+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *55+ * EMULEX and SLI are trademarks of Emulex. *66+ * www.emulex.com *77+ * *88+ * This program is free software; you can redistribute it and/or *99+ * modify it under the terms of version 2 of the GNU General *1010+ * Public License as published by the Free Software Foundation. *1111+ * This program is distributed in the hope that it will be useful. *1212+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *1313+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *1414+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *1515+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *1616+ * TO BE LEGALLY INVALID. See the GNU General Public License for *1717+ * more details, a copy of which can be found in the file COPYING *1818+ * included with this package. *1919+ *2020+ * Contact Information:2121+ * linux-drivers@emulex.com2222+ *2323+ * Emulex2424+ * 3333 Susan Street2525+ * Costa Mesa, CA 926262626+ *******************************************************************/2727+2828+#include <net/neighbour.h>2929+#include <net/netevent.h>3030+3131+#include <rdma/ib_addr.h>3232+#include <rdma/ib_cache.h>3333+3434+#include "ocrdma.h"3535+#include "ocrdma_verbs.h"3636+#include "ocrdma_ah.h"3737+#include "ocrdma_hw.h"3838+3939+static inline int set_av_attr(struct ocrdma_ah *ah,4040+ struct ib_ah_attr *attr, int pdid)4141+{4242+ int status = 0;4343+ u16 vlan_tag; bool vlan_enabled = false;4444+ struct ocrdma_dev *dev = ah->dev;4545+ struct ocrdma_eth_vlan eth;4646+ struct ocrdma_grh grh;4747+ int eth_sz;4848+4949+ memset(ð, 0, sizeof(eth));5050+ memset(&grh, 0, sizeof(grh));5151+5252+ ah->sgid_index = attr->grh.sgid_index;5353+5454+ vlan_tag = rdma_get_vlan_id(&attr->grh.dgid);5555+ if (vlan_tag && (vlan_tag < 0x1000)) {5656+ eth.eth_type = cpu_to_be16(0x8100);5757+ eth.roce_eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE);5858+ vlan_tag |= (attr->sl & 7) << 13;5959+ eth.vlan_tag = cpu_to_be16(vlan_tag);6060+ eth_sz = sizeof(struct ocrdma_eth_vlan);6161+ vlan_enabled = true;6262+ } else {6363+ eth.eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE);6464+ eth_sz = sizeof(struct ocrdma_eth_basic);6565+ }6666+ memcpy(ð.smac[0], &dev->nic_info.mac_addr[0], ETH_ALEN);6767+ status = ocrdma_resolve_dgid(dev, &attr->grh.dgid, ð.dmac[0]);6868+ if (status)6969+ return status;7070+ status = ocrdma_query_gid(&dev->ibdev, 1, attr->grh.sgid_index,7171+ (union ib_gid *)&grh.sgid[0]);7272+ if (status)7373+ return status;7474+7575+ grh.tclass_flow = cpu_to_be32((6 << 28) |7676+ (attr->grh.traffic_class << 24) |7777+ attr->grh.flow_label);7878+ /* 0x1b is next header value in GRH */7979+ grh.pdid_hoplimit = cpu_to_be32((pdid << 16) |8080+ (0x1b << 8) | attr->grh.hop_limit);8181+8282+ memcpy(&grh.dgid[0], attr->grh.dgid.raw, sizeof(attr->grh.dgid.raw));8383+ memcpy(&ah->av->eth_hdr, ð, eth_sz);8484+ memcpy((u8 *)ah->av + eth_sz, &grh, sizeof(struct ocrdma_grh));8585+ if (vlan_enabled)8686+ ah->av->valid |= OCRDMA_AV_VLAN_VALID;8787+ return status;8888+}8989+9090+struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)9191+{9292+ u32 *ahid_addr;9393+ int status;9494+ struct ocrdma_ah *ah;9595+ struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);9696+ struct ocrdma_dev *dev = pd->dev;9797+9898+ if (!(attr->ah_flags & IB_AH_GRH))9999+ return ERR_PTR(-EINVAL);100100+101101+ ah = kzalloc(sizeof *ah, GFP_ATOMIC);102102+ if (!ah)103103+ return ERR_PTR(-ENOMEM);104104+ ah->dev = pd->dev;105105+106106+ status = ocrdma_alloc_av(dev, ah);107107+ if (status)108108+ goto av_err;109109+ status = set_av_attr(ah, attr, pd->id);110110+ if (status)111111+ goto av_conf_err;112112+113113+ /* if pd is for the user process, pass the ah_id to user space */114114+ if ((pd->uctx) && (pd->uctx->ah_tbl.va)) {115115+ ahid_addr = pd->uctx->ah_tbl.va + attr->dlid;116116+ *ahid_addr = ah->id;117117+ }118118+ return &ah->ibah;119119+120120+av_conf_err:121121+ ocrdma_free_av(dev, ah);122122+av_err:123123+ kfree(ah);124124+ return ERR_PTR(status);125125+}126126+127127+int ocrdma_destroy_ah(struct ib_ah *ibah)128128+{129129+ struct ocrdma_ah *ah = get_ocrdma_ah(ibah);130130+ ocrdma_free_av(ah->dev, ah);131131+ kfree(ah);132132+ return 0;133133+}134134+135135+int ocrdma_query_ah(struct ib_ah *ibah, struct ib_ah_attr *attr)136136+{137137+ struct ocrdma_ah *ah = get_ocrdma_ah(ibah);138138+ struct ocrdma_av *av = ah->av;139139+ struct ocrdma_grh *grh;140140+ attr->ah_flags |= IB_AH_GRH;141141+ if (ah->av->valid & Bit(1)) {142142+ grh = (struct ocrdma_grh *)((u8 *)ah->av +143143+ sizeof(struct ocrdma_eth_vlan));144144+ attr->sl = be16_to_cpu(av->eth_hdr.vlan_tag) >> 13;145145+ } else {146146+ grh = (struct ocrdma_grh *)((u8 *)ah->av +147147+ sizeof(struct ocrdma_eth_basic));148148+ attr->sl = 0;149149+ }150150+ memcpy(&attr->grh.dgid.raw[0], &grh->dgid[0], sizeof(grh->dgid));151151+ attr->grh.sgid_index = ah->sgid_index;152152+ attr->grh.hop_limit = be32_to_cpu(grh->pdid_hoplimit) & 0xff;153153+ attr->grh.traffic_class = be32_to_cpu(grh->tclass_flow) >> 24;154154+ attr->grh.flow_label = be32_to_cpu(grh->tclass_flow) & 0x00ffffffff;155155+ return 0;156156+}157157+158158+int ocrdma_modify_ah(struct ib_ah *ibah, struct ib_ah_attr *attr)159159+{160160+ /* modify_ah is unsupported */161161+ return -ENOSYS;162162+}163163+164164+int ocrdma_process_mad(struct ib_device *ibdev,165165+ int process_mad_flags,166166+ u8 port_num,167167+ struct ib_wc *in_wc,168168+ struct ib_grh *in_grh,169169+ struct ib_mad *in_mad, struct ib_mad *out_mad)170170+{171171+ return IB_MAD_RESULT_SUCCESS;172172+}
+42
drivers/infiniband/hw/ocrdma/ocrdma_ah.h
···11+/*******************************************************************22+ * This file is part of the Emulex RoCE Device Driver for *33+ * RoCE (RDMA over Converged Ethernet) adapters. *44+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *55+ * EMULEX and SLI are trademarks of Emulex. *66+ * www.emulex.com *77+ * *88+ * This program is free software; you can redistribute it and/or *99+ * modify it under the terms of version 2 of the GNU General *1010+ * Public License as published by the Free Software Foundation. *1111+ * This program is distributed in the hope that it will be useful. *1212+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *1313+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *1414+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *1515+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *1616+ * TO BE LEGALLY INVALID. See the GNU General Public License for *1717+ * more details, a copy of which can be found in the file COPYING *1818+ * included with this package. *1919+ *2020+ * Contact Information:2121+ * linux-drivers@emulex.com2222+ *2323+ * Emulex2424+ * 3333 Susan Street2525+ * Costa Mesa, CA 926262626+ *******************************************************************/2727+2828+#ifndef __OCRDMA_AH_H__2929+#define __OCRDMA_AH_H__3030+3131+struct ib_ah *ocrdma_create_ah(struct ib_pd *, struct ib_ah_attr *);3232+int ocrdma_destroy_ah(struct ib_ah *);3333+int ocrdma_query_ah(struct ib_ah *, struct ib_ah_attr *);3434+int ocrdma_modify_ah(struct ib_ah *, struct ib_ah_attr *);3535+3636+int ocrdma_process_mad(struct ib_device *,3737+ int process_mad_flags,3838+ u8 port_num,3939+ struct ib_wc *in_wc,4040+ struct ib_grh *in_grh,4141+ struct ib_mad *in_mad, struct ib_mad *out_mad);4242+#endif /* __OCRDMA_AH_H__ */
+2640
drivers/infiniband/hw/ocrdma/ocrdma_hw.c
···11+/*******************************************************************22+ * This file is part of the Emulex RoCE Device Driver for *33+ * RoCE (RDMA over Converged Ethernet) CNA Adapters. *44+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *55+ * EMULEX and SLI are trademarks of Emulex. *66+ * www.emulex.com *77+ * *88+ * This program is free software; you can redistribute it and/or *99+ * modify it under the terms of version 2 of the GNU General *1010+ * Public License as published by the Free Software Foundation. *1111+ * This program is distributed in the hope that it will be useful. *1212+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *1313+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *1414+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *1515+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *1616+ * TO BE LEGALLY INVALID. See the GNU General Public License for *1717+ * more details, a copy of which can be found in the file COPYING *1818+ * included with this package. *1919+ *2020+ * Contact Information:2121+ * linux-drivers@emulex.com2222+ *2323+ * Emulex2424+ * 3333 Susan Street2525+ * Costa Mesa, CA 926262626+ *******************************************************************/2727+2828+#include <linux/sched.h>2929+#include <linux/interrupt.h>3030+#include <linux/log2.h>3131+#include <linux/dma-mapping.h>3232+3333+#include <rdma/ib_verbs.h>3434+#include <rdma/ib_user_verbs.h>3535+#include <rdma/ib_addr.h>3636+3737+#include "ocrdma.h"3838+#include "ocrdma_hw.h"3939+#include "ocrdma_verbs.h"4040+#include "ocrdma_ah.h"4141+4242+enum mbx_status {4343+ OCRDMA_MBX_STATUS_FAILED = 1,4444+ OCRDMA_MBX_STATUS_ILLEGAL_FIELD = 3,4545+ OCRDMA_MBX_STATUS_OOR = 100,4646+ OCRDMA_MBX_STATUS_INVALID_PD = 101,4747+ OCRDMA_MBX_STATUS_PD_INUSE = 102,4848+ OCRDMA_MBX_STATUS_INVALID_CQ = 103,4949+ OCRDMA_MBX_STATUS_INVALID_QP = 104,5050+ OCRDMA_MBX_STATUS_INVALID_LKEY = 105,5151+ OCRDMA_MBX_STATUS_ORD_EXCEEDS = 106,5252+ OCRDMA_MBX_STATUS_IRD_EXCEEDS = 107,5353+ OCRDMA_MBX_STATUS_SENDQ_WQE_EXCEEDS = 108,5454+ OCRDMA_MBX_STATUS_RECVQ_RQE_EXCEEDS = 109,5555+ OCRDMA_MBX_STATUS_SGE_SEND_EXCEEDS = 110,5656+ OCRDMA_MBX_STATUS_SGE_WRITE_EXCEEDS = 111,5757+ OCRDMA_MBX_STATUS_SGE_RECV_EXCEEDS = 112,5858+ OCRDMA_MBX_STATUS_INVALID_STATE_CHANGE = 113,5959+ OCRDMA_MBX_STATUS_MW_BOUND = 114,6060+ OCRDMA_MBX_STATUS_INVALID_VA = 115,6161+ OCRDMA_MBX_STATUS_INVALID_LENGTH = 116,6262+ OCRDMA_MBX_STATUS_INVALID_FBO = 117,6363+ OCRDMA_MBX_STATUS_INVALID_ACC_RIGHTS = 118,6464+ OCRDMA_MBX_STATUS_INVALID_PBE_SIZE = 119,6565+ OCRDMA_MBX_STATUS_INVALID_PBL_ENTRY = 120,6666+ OCRDMA_MBX_STATUS_INVALID_PBL_SHIFT = 121,6767+ OCRDMA_MBX_STATUS_INVALID_SRQ_ID = 129,6868+ OCRDMA_MBX_STATUS_SRQ_ERROR = 133,6969+ OCRDMA_MBX_STATUS_RQE_EXCEEDS = 134,7070+ OCRDMA_MBX_STATUS_MTU_EXCEEDS = 135,7171+ OCRDMA_MBX_STATUS_MAX_QP_EXCEEDS = 136,7272+ OCRDMA_MBX_STATUS_SRQ_LIMIT_EXCEEDS = 137,7373+ OCRDMA_MBX_STATUS_SRQ_SIZE_UNDERUNS = 138,7474+ OCRDMA_MBX_STATUS_QP_BOUND = 130,7575+ OCRDMA_MBX_STATUS_INVALID_CHANGE = 139,7676+ OCRDMA_MBX_STATUS_ATOMIC_OPS_UNSUP = 140,7777+ OCRDMA_MBX_STATUS_INVALID_RNR_NAK_TIMER = 141,7878+ OCRDMA_MBX_STATUS_MW_STILL_BOUND = 142,7979+ OCRDMA_MBX_STATUS_PKEY_INDEX_INVALID = 143,8080+ OCRDMA_MBX_STATUS_PKEY_INDEX_EXCEEDS = 1448181+};8282+8383+enum additional_status {8484+ OCRDMA_MBX_ADDI_STATUS_INSUFFICIENT_RESOURCES = 228585+};8686+8787+enum cqe_status {8888+ OCRDMA_MBX_CQE_STATUS_INSUFFICIENT_PRIVILEDGES = 1,8989+ OCRDMA_MBX_CQE_STATUS_INVALID_PARAMETER = 2,9090+ OCRDMA_MBX_CQE_STATUS_INSUFFICIENT_RESOURCES = 3,9191+ OCRDMA_MBX_CQE_STATUS_QUEUE_FLUSHING = 4,9292+ OCRDMA_MBX_CQE_STATUS_DMA_FAILED = 59393+};9494+9595+static inline void *ocrdma_get_eqe(struct ocrdma_eq *eq)9696+{9797+ return (u8 *)eq->q.va + (eq->q.tail * sizeof(struct ocrdma_eqe));9898+}9999+100100+static inline void ocrdma_eq_inc_tail(struct ocrdma_eq *eq)101101+{102102+ eq->q.tail = (eq->q.tail + 1) & (OCRDMA_EQ_LEN - 1);103103+}104104+105105+static inline void *ocrdma_get_mcqe(struct ocrdma_dev *dev)106106+{107107+ struct ocrdma_mcqe *cqe = (struct ocrdma_mcqe *)108108+ ((u8 *) dev->mq.cq.va +109109+ (dev->mq.cq.tail * sizeof(struct ocrdma_mcqe)));110110+111111+ if (!(le32_to_cpu(cqe->valid_ae_cmpl_cons) & OCRDMA_MCQE_VALID_MASK))112112+ return NULL;113113+ return cqe;114114+}115115+116116+static inline void ocrdma_mcq_inc_tail(struct ocrdma_dev *dev)117117+{118118+ dev->mq.cq.tail = (dev->mq.cq.tail + 1) & (OCRDMA_MQ_CQ_LEN - 1);119119+}120120+121121+static inline struct ocrdma_mqe *ocrdma_get_mqe(struct ocrdma_dev *dev)122122+{123123+ return (struct ocrdma_mqe *)((u8 *) dev->mq.sq.va +124124+ (dev->mq.sq.head *125125+ sizeof(struct ocrdma_mqe)));126126+}127127+128128+static inline void ocrdma_mq_inc_head(struct ocrdma_dev *dev)129129+{130130+ dev->mq.sq.head = (dev->mq.sq.head + 1) & (OCRDMA_MQ_LEN - 1);131131+ atomic_inc(&dev->mq.sq.used);132132+}133133+134134+static inline void *ocrdma_get_mqe_rsp(struct ocrdma_dev *dev)135135+{136136+ return (void *)((u8 *) dev->mq.sq.va +137137+ (dev->mqe_ctx.tag * sizeof(struct ocrdma_mqe)));138138+}139139+140140+enum ib_qp_state get_ibqp_state(enum ocrdma_qp_state qps)141141+{142142+ switch (qps) {143143+ case OCRDMA_QPS_RST:144144+ return IB_QPS_RESET;145145+ case OCRDMA_QPS_INIT:146146+ return IB_QPS_INIT;147147+ case OCRDMA_QPS_RTR:148148+ return IB_QPS_RTR;149149+ case OCRDMA_QPS_RTS:150150+ return IB_QPS_RTS;151151+ case OCRDMA_QPS_SQD:152152+ case OCRDMA_QPS_SQ_DRAINING:153153+ return IB_QPS_SQD;154154+ case OCRDMA_QPS_SQE:155155+ return IB_QPS_SQE;156156+ case OCRDMA_QPS_ERR:157157+ return IB_QPS_ERR;158158+ };159159+ return IB_QPS_ERR;160160+}161161+162162+static enum ocrdma_qp_state get_ocrdma_qp_state(enum ib_qp_state qps)163163+{164164+ switch (qps) {165165+ case IB_QPS_RESET:166166+ return OCRDMA_QPS_RST;167167+ case IB_QPS_INIT:168168+ return OCRDMA_QPS_INIT;169169+ case IB_QPS_RTR:170170+ return OCRDMA_QPS_RTR;171171+ case IB_QPS_RTS:172172+ return OCRDMA_QPS_RTS;173173+ case IB_QPS_SQD:174174+ return OCRDMA_QPS_SQD;175175+ case IB_QPS_SQE:176176+ return OCRDMA_QPS_SQE;177177+ case IB_QPS_ERR:178178+ return OCRDMA_QPS_ERR;179179+ };180180+ return OCRDMA_QPS_ERR;181181+}182182+183183+static int ocrdma_get_mbx_errno(u32 status)184184+{185185+ int err_num = -EFAULT;186186+ u8 mbox_status = (status & OCRDMA_MBX_RSP_STATUS_MASK) >>187187+ OCRDMA_MBX_RSP_STATUS_SHIFT;188188+ u8 add_status = (status & OCRDMA_MBX_RSP_ASTATUS_MASK) >>189189+ OCRDMA_MBX_RSP_ASTATUS_SHIFT;190190+191191+ switch (mbox_status) {192192+ case OCRDMA_MBX_STATUS_OOR:193193+ case OCRDMA_MBX_STATUS_MAX_QP_EXCEEDS:194194+ err_num = -EAGAIN;195195+ break;196196+197197+ case OCRDMA_MBX_STATUS_INVALID_PD:198198+ case OCRDMA_MBX_STATUS_INVALID_CQ:199199+ case OCRDMA_MBX_STATUS_INVALID_SRQ_ID:200200+ case OCRDMA_MBX_STATUS_INVALID_QP:201201+ case OCRDMA_MBX_STATUS_INVALID_CHANGE:202202+ case OCRDMA_MBX_STATUS_MTU_EXCEEDS:203203+ case OCRDMA_MBX_STATUS_INVALID_RNR_NAK_TIMER:204204+ case OCRDMA_MBX_STATUS_PKEY_INDEX_INVALID:205205+ case OCRDMA_MBX_STATUS_PKEY_INDEX_EXCEEDS:206206+ case OCRDMA_MBX_STATUS_ILLEGAL_FIELD:207207+ case OCRDMA_MBX_STATUS_INVALID_PBL_ENTRY:208208+ case OCRDMA_MBX_STATUS_INVALID_LKEY:209209+ case OCRDMA_MBX_STATUS_INVALID_VA:210210+ case OCRDMA_MBX_STATUS_INVALID_LENGTH:211211+ case OCRDMA_MBX_STATUS_INVALID_FBO:212212+ case OCRDMA_MBX_STATUS_INVALID_ACC_RIGHTS:213213+ case OCRDMA_MBX_STATUS_INVALID_PBE_SIZE:214214+ case OCRDMA_MBX_STATUS_ATOMIC_OPS_UNSUP:215215+ case OCRDMA_MBX_STATUS_SRQ_ERROR:216216+ case OCRDMA_MBX_STATUS_SRQ_SIZE_UNDERUNS:217217+ err_num = -EINVAL;218218+ break;219219+220220+ case OCRDMA_MBX_STATUS_PD_INUSE:221221+ case OCRDMA_MBX_STATUS_QP_BOUND:222222+ case OCRDMA_MBX_STATUS_MW_STILL_BOUND:223223+ case OCRDMA_MBX_STATUS_MW_BOUND:224224+ err_num = -EBUSY;225225+ break;226226+227227+ case OCRDMA_MBX_STATUS_RECVQ_RQE_EXCEEDS:228228+ case OCRDMA_MBX_STATUS_SGE_RECV_EXCEEDS:229229+ case OCRDMA_MBX_STATUS_RQE_EXCEEDS:230230+ case OCRDMA_MBX_STATUS_SRQ_LIMIT_EXCEEDS:231231+ case OCRDMA_MBX_STATUS_ORD_EXCEEDS:232232+ case OCRDMA_MBX_STATUS_IRD_EXCEEDS:233233+ case OCRDMA_MBX_STATUS_SENDQ_WQE_EXCEEDS:234234+ case OCRDMA_MBX_STATUS_SGE_SEND_EXCEEDS:235235+ case OCRDMA_MBX_STATUS_SGE_WRITE_EXCEEDS:236236+ err_num = -ENOBUFS;237237+ break;238238+239239+ case OCRDMA_MBX_STATUS_FAILED:240240+ switch (add_status) {241241+ case OCRDMA_MBX_ADDI_STATUS_INSUFFICIENT_RESOURCES:242242+ err_num = -EAGAIN;243243+ break;244244+ }245245+ default:246246+ err_num = -EFAULT;247247+ }248248+ return err_num;249249+}250250+251251+static int ocrdma_get_mbx_cqe_errno(u16 cqe_status)252252+{253253+ int err_num = -EINVAL;254254+255255+ switch (cqe_status) {256256+ case OCRDMA_MBX_CQE_STATUS_INSUFFICIENT_PRIVILEDGES:257257+ err_num = -EPERM;258258+ break;259259+ case OCRDMA_MBX_CQE_STATUS_INVALID_PARAMETER:260260+ err_num = -EINVAL;261261+ break;262262+ case OCRDMA_MBX_CQE_STATUS_INSUFFICIENT_RESOURCES:263263+ case OCRDMA_MBX_CQE_STATUS_QUEUE_FLUSHING:264264+ err_num = -EAGAIN;265265+ break;266266+ case OCRDMA_MBX_CQE_STATUS_DMA_FAILED:267267+ err_num = -EIO;268268+ break;269269+ }270270+ return err_num;271271+}272272+273273+void ocrdma_ring_cq_db(struct ocrdma_dev *dev, u16 cq_id, bool armed,274274+ bool solicited, u16 cqe_popped)275275+{276276+ u32 val = cq_id & OCRDMA_DB_CQ_RING_ID_MASK;277277+278278+ val |= ((cq_id & OCRDMA_DB_CQ_RING_ID_EXT_MASK) <<279279+ OCRDMA_DB_CQ_RING_ID_EXT_MASK_SHIFT);280280+281281+ if (armed)282282+ val |= (1 << OCRDMA_DB_CQ_REARM_SHIFT);283283+ if (solicited)284284+ val |= (1 << OCRDMA_DB_CQ_SOLICIT_SHIFT);285285+ val |= (cqe_popped << OCRDMA_DB_CQ_NUM_POPPED_SHIFT);286286+ iowrite32(val, dev->nic_info.db + OCRDMA_DB_CQ_OFFSET);287287+}288288+289289+static void ocrdma_ring_mq_db(struct ocrdma_dev *dev)290290+{291291+ u32 val = 0;292292+293293+ val |= dev->mq.sq.id & OCRDMA_MQ_ID_MASK;294294+ val |= 1 << OCRDMA_MQ_NUM_MQE_SHIFT;295295+ iowrite32(val, dev->nic_info.db + OCRDMA_DB_MQ_OFFSET);296296+}297297+298298+static void ocrdma_ring_eq_db(struct ocrdma_dev *dev, u16 eq_id,299299+ bool arm, bool clear_int, u16 num_eqe)300300+{301301+ u32 val = 0;302302+303303+ val |= eq_id & OCRDMA_EQ_ID_MASK;304304+ val |= ((eq_id & OCRDMA_EQ_ID_EXT_MASK) << OCRDMA_EQ_ID_EXT_MASK_SHIFT);305305+ if (arm)306306+ val |= (1 << OCRDMA_REARM_SHIFT);307307+ if (clear_int)308308+ val |= (1 << OCRDMA_EQ_CLR_SHIFT);309309+ val |= (1 << OCRDMA_EQ_TYPE_SHIFT);310310+ val |= (num_eqe << OCRDMA_NUM_EQE_SHIFT);311311+ iowrite32(val, dev->nic_info.db + OCRDMA_DB_EQ_OFFSET);312312+}313313+314314+static void ocrdma_init_mch(struct ocrdma_mbx_hdr *cmd_hdr,315315+ u8 opcode, u8 subsys, u32 cmd_len)316316+{317317+ cmd_hdr->subsys_op = (opcode | (subsys << OCRDMA_MCH_SUBSYS_SHIFT));318318+ cmd_hdr->timeout = 20; /* seconds */319319+ cmd_hdr->cmd_len = cmd_len - sizeof(struct ocrdma_mbx_hdr);320320+}321321+322322+static void *ocrdma_init_emb_mqe(u8 opcode, u32 cmd_len)323323+{324324+ struct ocrdma_mqe *mqe;325325+326326+ mqe = kzalloc(sizeof(struct ocrdma_mqe), GFP_KERNEL);327327+ if (!mqe)328328+ return NULL;329329+ mqe->hdr.spcl_sge_cnt_emb |=330330+ (OCRDMA_MQE_EMBEDDED << OCRDMA_MQE_HDR_EMB_SHIFT) &331331+ OCRDMA_MQE_HDR_EMB_MASK;332332+ mqe->hdr.pyld_len = cmd_len - sizeof(struct ocrdma_mqe_hdr);333333+334334+ ocrdma_init_mch(&mqe->u.emb_req.mch, opcode, OCRDMA_SUBSYS_ROCE,335335+ mqe->hdr.pyld_len);336336+ return mqe;337337+}338338+339339+static void ocrdma_free_q(struct ocrdma_dev *dev, struct ocrdma_queue_info *q)340340+{341341+ dma_free_coherent(&dev->nic_info.pdev->dev, q->size, q->va, q->dma);342342+}343343+344344+static int ocrdma_alloc_q(struct ocrdma_dev *dev,345345+ struct ocrdma_queue_info *q, u16 len, u16 entry_size)346346+{347347+ memset(q, 0, sizeof(*q));348348+ q->len = len;349349+ q->entry_size = entry_size;350350+ q->size = len * entry_size;351351+ q->va = dma_alloc_coherent(&dev->nic_info.pdev->dev, q->size,352352+ &q->dma, GFP_KERNEL);353353+ if (!q->va)354354+ return -ENOMEM;355355+ memset(q->va, 0, q->size);356356+ return 0;357357+}358358+359359+static void ocrdma_build_q_pages(struct ocrdma_pa *q_pa, int cnt,360360+ dma_addr_t host_pa, int hw_page_size)361361+{362362+ int i;363363+364364+ for (i = 0; i < cnt; i++) {365365+ q_pa[i].lo = (u32) (host_pa & 0xffffffff);366366+ q_pa[i].hi = (u32) upper_32_bits(host_pa);367367+ host_pa += hw_page_size;368368+ }369369+}370370+371371+static void ocrdma_assign_eq_vect_gen2(struct ocrdma_dev *dev,372372+ struct ocrdma_eq *eq)373373+{374374+ /* assign vector and update vector id for next EQ */375375+ eq->vector = dev->nic_info.msix.start_vector;376376+ dev->nic_info.msix.start_vector += 1;377377+}378378+379379+static void ocrdma_free_eq_vect_gen2(struct ocrdma_dev *dev)380380+{381381+ /* this assumes that EQs are freed in exactly reverse order382382+ * as its allocation.383383+ */384384+ dev->nic_info.msix.start_vector -= 1;385385+}386386+387387+static int ocrdma_mbx_delete_q(struct ocrdma_dev *dev, struct ocrdma_queue_info *q,388388+ int queue_type)389389+{390390+ u8 opcode = 0;391391+ int status;392392+ struct ocrdma_delete_q_req *cmd = dev->mbx_cmd;393393+394394+ switch (queue_type) {395395+ case QTYPE_MCCQ:396396+ opcode = OCRDMA_CMD_DELETE_MQ;397397+ break;398398+ case QTYPE_CQ:399399+ opcode = OCRDMA_CMD_DELETE_CQ;400400+ break;401401+ case QTYPE_EQ:402402+ opcode = OCRDMA_CMD_DELETE_EQ;403403+ break;404404+ default:405405+ BUG();406406+ }407407+ memset(cmd, 0, sizeof(*cmd));408408+ ocrdma_init_mch(&cmd->req, opcode, OCRDMA_SUBSYS_COMMON, sizeof(*cmd));409409+ cmd->id = q->id;410410+411411+ status = be_roce_mcc_cmd(dev->nic_info.netdev,412412+ cmd, sizeof(*cmd), NULL, NULL);413413+ if (!status)414414+ q->created = false;415415+ return status;416416+}417417+418418+static int ocrdma_mbx_create_eq(struct ocrdma_dev *dev, struct ocrdma_eq *eq)419419+{420420+ int status;421421+ struct ocrdma_create_eq_req *cmd = dev->mbx_cmd;422422+ struct ocrdma_create_eq_rsp *rsp = dev->mbx_cmd;423423+424424+ memset(cmd, 0, sizeof(*cmd));425425+ ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_EQ, OCRDMA_SUBSYS_COMMON,426426+ sizeof(*cmd));427427+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY)428428+ cmd->req.rsvd_version = 0;429429+ else430430+ cmd->req.rsvd_version = 2;431431+432432+ cmd->num_pages = 4;433433+ cmd->valid = OCRDMA_CREATE_EQ_VALID;434434+ cmd->cnt = 4 << OCRDMA_CREATE_EQ_CNT_SHIFT;435435+436436+ ocrdma_build_q_pages(&cmd->pa[0], cmd->num_pages, eq->q.dma,437437+ PAGE_SIZE_4K);438438+ status = be_roce_mcc_cmd(dev->nic_info.netdev, cmd, sizeof(*cmd), NULL,439439+ NULL);440440+ if (!status) {441441+ eq->q.id = rsp->vector_eqid & 0xffff;442442+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY)443443+ ocrdma_assign_eq_vect_gen2(dev, eq);444444+ else {445445+ eq->vector = (rsp->vector_eqid >> 16) & 0xffff;446446+ dev->nic_info.msix.start_vector += 1;447447+ }448448+ eq->q.created = true;449449+ }450450+ return status;451451+}452452+453453+static int ocrdma_create_eq(struct ocrdma_dev *dev,454454+ struct ocrdma_eq *eq, u16 q_len)455455+{456456+ int status;457457+458458+ status = ocrdma_alloc_q(dev, &eq->q, OCRDMA_EQ_LEN,459459+ sizeof(struct ocrdma_eqe));460460+ if (status)461461+ return status;462462+463463+ status = ocrdma_mbx_create_eq(dev, eq);464464+ if (status)465465+ goto mbx_err;466466+ eq->dev = dev;467467+ ocrdma_ring_eq_db(dev, eq->q.id, true, true, 0);468468+469469+ return 0;470470+mbx_err:471471+ ocrdma_free_q(dev, &eq->q);472472+ return status;473473+}474474+475475+static int ocrdma_get_irq(struct ocrdma_dev *dev, struct ocrdma_eq *eq)476476+{477477+ int irq;478478+479479+ if (dev->nic_info.intr_mode == BE_INTERRUPT_MODE_INTX)480480+ irq = dev->nic_info.pdev->irq;481481+ else482482+ irq = dev->nic_info.msix.vector_list[eq->vector];483483+ return irq;484484+}485485+486486+static void _ocrdma_destroy_eq(struct ocrdma_dev *dev, struct ocrdma_eq *eq)487487+{488488+ if (eq->q.created) {489489+ ocrdma_mbx_delete_q(dev, &eq->q, QTYPE_EQ);490490+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY)491491+ ocrdma_free_eq_vect_gen2(dev);492492+ ocrdma_free_q(dev, &eq->q);493493+ }494494+}495495+496496+static void ocrdma_destroy_eq(struct ocrdma_dev *dev, struct ocrdma_eq *eq)497497+{498498+ int irq;499499+500500+ /* disarm EQ so that interrupts are not generated501501+ * during freeing and EQ delete is in progress.502502+ */503503+ ocrdma_ring_eq_db(dev, eq->q.id, false, false, 0);504504+505505+ irq = ocrdma_get_irq(dev, eq);506506+ free_irq(irq, eq);507507+ _ocrdma_destroy_eq(dev, eq);508508+}509509+510510+static void ocrdma_destroy_qp_eqs(struct ocrdma_dev *dev)511511+{512512+ int i;513513+514514+ /* deallocate the data path eqs */515515+ for (i = 0; i < dev->eq_cnt; i++)516516+ ocrdma_destroy_eq(dev, &dev->qp_eq_tbl[i]);517517+}518518+519519+static int ocrdma_mbx_mq_cq_create(struct ocrdma_dev *dev,520520+ struct ocrdma_queue_info *cq,521521+ struct ocrdma_queue_info *eq)522522+{523523+ struct ocrdma_create_cq_cmd *cmd = dev->mbx_cmd;524524+ struct ocrdma_create_cq_cmd_rsp *rsp = dev->mbx_cmd;525525+ int status;526526+527527+ memset(cmd, 0, sizeof(*cmd));528528+ ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_CQ,529529+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));530530+531531+ cmd->pgsz_pgcnt = PAGES_4K_SPANNED(cq->va, cq->size);532532+ cmd->ev_cnt_flags = OCRDMA_CREATE_CQ_DEF_FLAGS;533533+ cmd->eqn = (eq->id << OCRDMA_CREATE_CQ_EQID_SHIFT);534534+535535+ ocrdma_build_q_pages(&cmd->pa[0], cmd->pgsz_pgcnt,536536+ cq->dma, PAGE_SIZE_4K);537537+ status = be_roce_mcc_cmd(dev->nic_info.netdev,538538+ cmd, sizeof(*cmd), NULL, NULL);539539+ if (!status) {540540+ cq->id = (rsp->cq_id & OCRDMA_CREATE_CQ_RSP_CQ_ID_MASK);541541+ cq->created = true;542542+ }543543+ return status;544544+}545545+546546+static u32 ocrdma_encoded_q_len(int q_len)547547+{548548+ u32 len_encoded = fls(q_len); /* log2(len) + 1 */549549+550550+ if (len_encoded == 16)551551+ len_encoded = 0;552552+ return len_encoded;553553+}554554+555555+static int ocrdma_mbx_create_mq(struct ocrdma_dev *dev,556556+ struct ocrdma_queue_info *mq,557557+ struct ocrdma_queue_info *cq)558558+{559559+ int num_pages, status;560560+ struct ocrdma_create_mq_req *cmd = dev->mbx_cmd;561561+ struct ocrdma_create_mq_rsp *rsp = dev->mbx_cmd;562562+ struct ocrdma_pa *pa;563563+564564+ memset(cmd, 0, sizeof(*cmd));565565+ num_pages = PAGES_4K_SPANNED(mq->va, mq->size);566566+567567+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {568568+ ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_MQ,569569+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));570570+ cmd->v0.pages = num_pages;571571+ cmd->v0.async_cqid_valid = OCRDMA_CREATE_MQ_ASYNC_CQ_VALID;572572+ cmd->v0.async_cqid_valid = (cq->id << 1);573573+ cmd->v0.cqid_ringsize |= (ocrdma_encoded_q_len(mq->len) <<574574+ OCRDMA_CREATE_MQ_RING_SIZE_SHIFT);575575+ cmd->v0.cqid_ringsize |=576576+ (cq->id << OCRDMA_CREATE_MQ_V0_CQ_ID_SHIFT);577577+ cmd->v0.valid = OCRDMA_CREATE_MQ_VALID;578578+ pa = &cmd->v0.pa[0];579579+ } else {580580+ ocrdma_init_mch(&cmd->req, OCRDMA_CMD_CREATE_MQ_EXT,581581+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));582582+ cmd->req.rsvd_version = 1;583583+ cmd->v1.cqid_pages = num_pages;584584+ cmd->v1.cqid_pages |= (cq->id << OCRDMA_CREATE_MQ_CQ_ID_SHIFT);585585+ cmd->v1.async_cqid_valid = OCRDMA_CREATE_MQ_ASYNC_CQ_VALID;586586+ cmd->v1.async_event_bitmap = Bit(20);587587+ cmd->v1.async_cqid_ringsize = cq->id;588588+ cmd->v1.async_cqid_ringsize |= (ocrdma_encoded_q_len(mq->len) <<589589+ OCRDMA_CREATE_MQ_RING_SIZE_SHIFT);590590+ cmd->v1.valid = OCRDMA_CREATE_MQ_VALID;591591+ pa = &cmd->v1.pa[0];592592+ }593593+ ocrdma_build_q_pages(pa, num_pages, mq->dma, PAGE_SIZE_4K);594594+ status = be_roce_mcc_cmd(dev->nic_info.netdev,595595+ cmd, sizeof(*cmd), NULL, NULL);596596+ if (!status) {597597+ mq->id = rsp->id;598598+ mq->created = true;599599+ }600600+ return status;601601+}602602+603603+static int ocrdma_create_mq(struct ocrdma_dev *dev)604604+{605605+ int status;606606+607607+ /* Alloc completion queue for Mailbox queue */608608+ status = ocrdma_alloc_q(dev, &dev->mq.cq, OCRDMA_MQ_CQ_LEN,609609+ sizeof(struct ocrdma_mcqe));610610+ if (status)611611+ goto alloc_err;612612+613613+ status = ocrdma_mbx_mq_cq_create(dev, &dev->mq.cq, &dev->meq.q);614614+ if (status)615615+ goto mbx_cq_free;616616+617617+ memset(&dev->mqe_ctx, 0, sizeof(dev->mqe_ctx));618618+ init_waitqueue_head(&dev->mqe_ctx.cmd_wait);619619+ mutex_init(&dev->mqe_ctx.lock);620620+621621+ /* Alloc Mailbox queue */622622+ status = ocrdma_alloc_q(dev, &dev->mq.sq, OCRDMA_MQ_LEN,623623+ sizeof(struct ocrdma_mqe));624624+ if (status)625625+ goto mbx_cq_destroy;626626+ status = ocrdma_mbx_create_mq(dev, &dev->mq.sq, &dev->mq.cq);627627+ if (status)628628+ goto mbx_q_free;629629+ ocrdma_ring_cq_db(dev, dev->mq.cq.id, true, false, 0);630630+ return 0;631631+632632+mbx_q_free:633633+ ocrdma_free_q(dev, &dev->mq.sq);634634+mbx_cq_destroy:635635+ ocrdma_mbx_delete_q(dev, &dev->mq.cq, QTYPE_CQ);636636+mbx_cq_free:637637+ ocrdma_free_q(dev, &dev->mq.cq);638638+alloc_err:639639+ return status;640640+}641641+642642+static void ocrdma_destroy_mq(struct ocrdma_dev *dev)643643+{644644+ struct ocrdma_queue_info *mbxq, *cq;645645+646646+ /* mqe_ctx lock synchronizes with any other pending cmds. */647647+ mutex_lock(&dev->mqe_ctx.lock);648648+ mbxq = &dev->mq.sq;649649+ if (mbxq->created) {650650+ ocrdma_mbx_delete_q(dev, mbxq, QTYPE_MCCQ);651651+ ocrdma_free_q(dev, mbxq);652652+ }653653+ mutex_unlock(&dev->mqe_ctx.lock);654654+655655+ cq = &dev->mq.cq;656656+ if (cq->created) {657657+ ocrdma_mbx_delete_q(dev, cq, QTYPE_CQ);658658+ ocrdma_free_q(dev, cq);659659+ }660660+}661661+662662+static void ocrdma_process_qpcat_error(struct ocrdma_dev *dev,663663+ struct ocrdma_qp *qp)664664+{665665+ enum ib_qp_state new_ib_qps = IB_QPS_ERR;666666+ enum ib_qp_state old_ib_qps;667667+668668+ if (qp == NULL)669669+ BUG();670670+ ocrdma_qp_state_machine(qp, new_ib_qps, &old_ib_qps);671671+}672672+673673+static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev,674674+ struct ocrdma_ae_mcqe *cqe)675675+{676676+ struct ocrdma_qp *qp = NULL;677677+ struct ocrdma_cq *cq = NULL;678678+ struct ib_event ib_evt;679679+ int cq_event = 0;680680+ int qp_event = 1;681681+ int srq_event = 0;682682+ int dev_event = 0;683683+ int type = (cqe->valid_ae_event & OCRDMA_AE_MCQE_EVENT_TYPE_MASK) >>684684+ OCRDMA_AE_MCQE_EVENT_TYPE_SHIFT;685685+686686+ if (cqe->qpvalid_qpid & OCRDMA_AE_MCQE_QPVALID)687687+ qp = dev->qp_tbl[cqe->qpvalid_qpid & OCRDMA_AE_MCQE_QPID_MASK];688688+ if (cqe->cqvalid_cqid & OCRDMA_AE_MCQE_CQVALID)689689+ cq = dev->cq_tbl[cqe->cqvalid_cqid & OCRDMA_AE_MCQE_CQID_MASK];690690+691691+ ib_evt.device = &dev->ibdev;692692+693693+ switch (type) {694694+ case OCRDMA_CQ_ERROR:695695+ ib_evt.element.cq = &cq->ibcq;696696+ ib_evt.event = IB_EVENT_CQ_ERR;697697+ cq_event = 1;698698+ qp_event = 0;699699+ break;700700+ case OCRDMA_CQ_OVERRUN_ERROR:701701+ ib_evt.element.cq = &cq->ibcq;702702+ ib_evt.event = IB_EVENT_CQ_ERR;703703+ break;704704+ case OCRDMA_CQ_QPCAT_ERROR:705705+ ib_evt.element.qp = &qp->ibqp;706706+ ib_evt.event = IB_EVENT_QP_FATAL;707707+ ocrdma_process_qpcat_error(dev, qp);708708+ break;709709+ case OCRDMA_QP_ACCESS_ERROR:710710+ ib_evt.element.qp = &qp->ibqp;711711+ ib_evt.event = IB_EVENT_QP_ACCESS_ERR;712712+ break;713713+ case OCRDMA_QP_COMM_EST_EVENT:714714+ ib_evt.element.qp = &qp->ibqp;715715+ ib_evt.event = IB_EVENT_COMM_EST;716716+ break;717717+ case OCRDMA_SQ_DRAINED_EVENT:718718+ ib_evt.element.qp = &qp->ibqp;719719+ ib_evt.event = IB_EVENT_SQ_DRAINED;720720+ break;721721+ case OCRDMA_DEVICE_FATAL_EVENT:722722+ ib_evt.element.port_num = 1;723723+ ib_evt.event = IB_EVENT_DEVICE_FATAL;724724+ qp_event = 0;725725+ dev_event = 1;726726+ break;727727+ case OCRDMA_SRQCAT_ERROR:728728+ ib_evt.element.srq = &qp->srq->ibsrq;729729+ ib_evt.event = IB_EVENT_SRQ_ERR;730730+ srq_event = 1;731731+ qp_event = 0;732732+ break;733733+ case OCRDMA_SRQ_LIMIT_EVENT:734734+ ib_evt.element.srq = &qp->srq->ibsrq;735735+ ib_evt.event = IB_EVENT_QP_LAST_WQE_REACHED;736736+ srq_event = 1;737737+ qp_event = 0;738738+ break;739739+ case OCRDMA_QP_LAST_WQE_EVENT:740740+ ib_evt.element.qp = &qp->ibqp;741741+ ib_evt.event = IB_EVENT_QP_LAST_WQE_REACHED;742742+ break;743743+ default:744744+ cq_event = 0;745745+ qp_event = 0;746746+ srq_event = 0;747747+ dev_event = 0;748748+ ocrdma_err("%s() unknown type=0x%x\n", __func__, type);749749+ break;750750+ }751751+752752+ if (qp_event) {753753+ if (qp->ibqp.event_handler)754754+ qp->ibqp.event_handler(&ib_evt, qp->ibqp.qp_context);755755+ } else if (cq_event) {756756+ if (cq->ibcq.event_handler)757757+ cq->ibcq.event_handler(&ib_evt, cq->ibcq.cq_context);758758+ } else if (srq_event) {759759+ if (qp->srq->ibsrq.event_handler)760760+ qp->srq->ibsrq.event_handler(&ib_evt,761761+ qp->srq->ibsrq.762762+ srq_context);763763+ } else if (dev_event)764764+ ib_dispatch_event(&ib_evt);765765+766766+}767767+768768+static void ocrdma_process_acqe(struct ocrdma_dev *dev, void *ae_cqe)769769+{770770+ /* async CQE processing */771771+ struct ocrdma_ae_mcqe *cqe = ae_cqe;772772+ u32 evt_code = (cqe->valid_ae_event & OCRDMA_AE_MCQE_EVENT_CODE_MASK) >>773773+ OCRDMA_AE_MCQE_EVENT_CODE_SHIFT;774774+775775+ if (evt_code == OCRDMA_ASYNC_EVE_CODE)776776+ ocrdma_dispatch_ibevent(dev, cqe);777777+ else778778+ ocrdma_err("%s(%d) invalid evt code=0x%x\n",779779+ __func__, dev->id, evt_code);780780+}781781+782782+static void ocrdma_process_mcqe(struct ocrdma_dev *dev, struct ocrdma_mcqe *cqe)783783+{784784+ if (dev->mqe_ctx.tag == cqe->tag_lo && dev->mqe_ctx.cmd_done == false) {785785+ dev->mqe_ctx.cqe_status = (cqe->status &786786+ OCRDMA_MCQE_STATUS_MASK) >> OCRDMA_MCQE_STATUS_SHIFT;787787+ dev->mqe_ctx.ext_status =788788+ (cqe->status & OCRDMA_MCQE_ESTATUS_MASK)789789+ >> OCRDMA_MCQE_ESTATUS_SHIFT;790790+ dev->mqe_ctx.cmd_done = true;791791+ wake_up(&dev->mqe_ctx.cmd_wait);792792+ } else793793+ ocrdma_err("%s() cqe for invalid tag0x%x.expected=0x%x\n",794794+ __func__, cqe->tag_lo, dev->mqe_ctx.tag);795795+}796796+797797+static int ocrdma_mq_cq_handler(struct ocrdma_dev *dev, u16 cq_id)798798+{799799+ u16 cqe_popped = 0;800800+ struct ocrdma_mcqe *cqe;801801+802802+ while (1) {803803+ cqe = ocrdma_get_mcqe(dev);804804+ if (cqe == NULL)805805+ break;806806+ ocrdma_le32_to_cpu(cqe, sizeof(*cqe));807807+ cqe_popped += 1;808808+ if (cqe->valid_ae_cmpl_cons & OCRDMA_MCQE_AE_MASK)809809+ ocrdma_process_acqe(dev, cqe);810810+ else if (cqe->valid_ae_cmpl_cons & OCRDMA_MCQE_CMPL_MASK)811811+ ocrdma_process_mcqe(dev, cqe);812812+ else813813+ ocrdma_err("%s() cqe->compl is not set.\n", __func__);814814+ memset(cqe, 0, sizeof(struct ocrdma_mcqe));815815+ ocrdma_mcq_inc_tail(dev);816816+ }817817+ ocrdma_ring_cq_db(dev, dev->mq.cq.id, true, false, cqe_popped);818818+ return 0;819819+}820820+821821+static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,822822+ struct ocrdma_cq *cq)823823+{824824+ unsigned long flags;825825+ struct ocrdma_qp *qp;826826+ bool buddy_cq_found = false;827827+ /* Go through list of QPs in error state which are using this CQ828828+ * and invoke its callback handler to trigger CQE processing for829829+ * error/flushed CQE. It is rare to find more than few entries in830830+ * this list as most consumers stops after getting error CQE.831831+ * List is traversed only once when a matching buddy cq found for a QP.832832+ */833833+ spin_lock_irqsave(&dev->flush_q_lock, flags);834834+ list_for_each_entry(qp, &cq->sq_head, sq_entry) {835835+ if (qp->srq)836836+ continue;837837+ /* if wq and rq share the same cq, than comp_handler838838+ * is already invoked.839839+ */840840+ if (qp->sq_cq == qp->rq_cq)841841+ continue;842842+ /* if completion came on sq, rq's cq is buddy cq.843843+ * if completion came on rq, sq's cq is buddy cq.844844+ */845845+ if (qp->sq_cq == cq)846846+ cq = qp->rq_cq;847847+ else848848+ cq = qp->sq_cq;849849+ buddy_cq_found = true;850850+ break;851851+ }852852+ spin_unlock_irqrestore(&dev->flush_q_lock, flags);853853+ if (buddy_cq_found == false)854854+ return;855855+ if (cq->ibcq.comp_handler) {856856+ spin_lock_irqsave(&cq->comp_handler_lock, flags);857857+ (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);858858+ spin_unlock_irqrestore(&cq->comp_handler_lock, flags);859859+ }860860+}861861+862862+static void ocrdma_qp_cq_handler(struct ocrdma_dev *dev, u16 cq_idx)863863+{864864+ unsigned long flags;865865+ struct ocrdma_cq *cq;866866+867867+ if (cq_idx >= OCRDMA_MAX_CQ)868868+ BUG();869869+870870+ cq = dev->cq_tbl[cq_idx];871871+ if (cq == NULL) {872872+ ocrdma_err("%s%d invalid id=0x%x\n", __func__, dev->id, cq_idx);873873+ return;874874+ }875875+ spin_lock_irqsave(&cq->cq_lock, flags);876876+ cq->armed = false;877877+ cq->solicited = false;878878+ spin_unlock_irqrestore(&cq->cq_lock, flags);879879+880880+ ocrdma_ring_cq_db(dev, cq->id, false, false, 0);881881+882882+ if (cq->ibcq.comp_handler) {883883+ spin_lock_irqsave(&cq->comp_handler_lock, flags);884884+ (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);885885+ spin_unlock_irqrestore(&cq->comp_handler_lock, flags);886886+ }887887+ ocrdma_qp_buddy_cq_handler(dev, cq);888888+}889889+890890+static void ocrdma_cq_handler(struct ocrdma_dev *dev, u16 cq_id)891891+{892892+ /* process the MQ-CQE. */893893+ if (cq_id == dev->mq.cq.id)894894+ ocrdma_mq_cq_handler(dev, cq_id);895895+ else896896+ ocrdma_qp_cq_handler(dev, cq_id);897897+}898898+899899+static irqreturn_t ocrdma_irq_handler(int irq, void *handle)900900+{901901+ struct ocrdma_eq *eq = handle;902902+ struct ocrdma_dev *dev = eq->dev;903903+ struct ocrdma_eqe eqe;904904+ struct ocrdma_eqe *ptr;905905+ u16 eqe_popped = 0;906906+ u16 cq_id;907907+ while (1) {908908+ ptr = ocrdma_get_eqe(eq);909909+ eqe = *ptr;910910+ ocrdma_le32_to_cpu(&eqe, sizeof(eqe));911911+ if ((eqe.id_valid & OCRDMA_EQE_VALID_MASK) == 0)912912+ break;913913+ eqe_popped += 1;914914+ ptr->id_valid = 0;915915+ /* check whether its CQE or not. */916916+ if ((eqe.id_valid & OCRDMA_EQE_FOR_CQE_MASK) == 0) {917917+ cq_id = eqe.id_valid >> OCRDMA_EQE_RESOURCE_ID_SHIFT;918918+ ocrdma_cq_handler(dev, cq_id);919919+ }920920+ ocrdma_eq_inc_tail(eq);921921+ }922922+ ocrdma_ring_eq_db(dev, eq->q.id, true, true, eqe_popped);923923+ /* Ring EQ doorbell with num_popped to 0 to enable interrupts again. */924924+ if (dev->nic_info.intr_mode == BE_INTERRUPT_MODE_INTX)925925+ ocrdma_ring_eq_db(dev, eq->q.id, true, true, 0);926926+ return IRQ_HANDLED;927927+}928928+929929+static void ocrdma_post_mqe(struct ocrdma_dev *dev, struct ocrdma_mqe *cmd)930930+{931931+ struct ocrdma_mqe *mqe;932932+933933+ dev->mqe_ctx.tag = dev->mq.sq.head;934934+ dev->mqe_ctx.cmd_done = false;935935+ mqe = ocrdma_get_mqe(dev);936936+ cmd->hdr.tag_lo = dev->mq.sq.head;937937+ ocrdma_copy_cpu_to_le32(mqe, cmd, sizeof(*mqe));938938+ /* make sure descriptor is written before ringing doorbell */939939+ wmb();940940+ ocrdma_mq_inc_head(dev);941941+ ocrdma_ring_mq_db(dev);942942+}943943+944944+static int ocrdma_wait_mqe_cmpl(struct ocrdma_dev *dev)945945+{946946+ long status;947947+ /* 30 sec timeout */948948+ status = wait_event_timeout(dev->mqe_ctx.cmd_wait,949949+ (dev->mqe_ctx.cmd_done != false),950950+ msecs_to_jiffies(30000));951951+ if (status)952952+ return 0;953953+ else954954+ return -1;955955+}956956+957957+/* issue a mailbox command on the MQ */958958+static int ocrdma_mbx_cmd(struct ocrdma_dev *dev, struct ocrdma_mqe *mqe)959959+{960960+ int status = 0;961961+ u16 cqe_status, ext_status;962962+ struct ocrdma_mqe *rsp;963963+964964+ mutex_lock(&dev->mqe_ctx.lock);965965+ ocrdma_post_mqe(dev, mqe);966966+ status = ocrdma_wait_mqe_cmpl(dev);967967+ if (status)968968+ goto mbx_err;969969+ cqe_status = dev->mqe_ctx.cqe_status;970970+ ext_status = dev->mqe_ctx.ext_status;971971+ rsp = ocrdma_get_mqe_rsp(dev);972972+ ocrdma_copy_le32_to_cpu(mqe, rsp, (sizeof(*mqe)));973973+ if (cqe_status || ext_status) {974974+ ocrdma_err975975+ ("%s() opcode=0x%x, cqe_status=0x%x, ext_status=0x%x\n",976976+ __func__,977977+ (rsp->u.rsp.subsys_op & OCRDMA_MBX_RSP_OPCODE_MASK) >>978978+ OCRDMA_MBX_RSP_OPCODE_SHIFT, cqe_status, ext_status);979979+ status = ocrdma_get_mbx_cqe_errno(cqe_status);980980+ goto mbx_err;981981+ }982982+ if (mqe->u.rsp.status & OCRDMA_MBX_RSP_STATUS_MASK)983983+ status = ocrdma_get_mbx_errno(mqe->u.rsp.status);984984+mbx_err:985985+ mutex_unlock(&dev->mqe_ctx.lock);986986+ return status;987987+}988988+989989+static void ocrdma_get_attr(struct ocrdma_dev *dev,990990+ struct ocrdma_dev_attr *attr,991991+ struct ocrdma_mbx_query_config *rsp)992992+{993993+ int max_q_mem;994994+995995+ attr->max_pd =996996+ (rsp->max_pd_ca_ack_delay & OCRDMA_MBX_QUERY_CFG_MAX_PD_MASK) >>997997+ OCRDMA_MBX_QUERY_CFG_MAX_PD_SHIFT;998998+ attr->max_qp =999999+ (rsp->qp_srq_cq_ird_ord & OCRDMA_MBX_QUERY_CFG_MAX_QP_MASK) >>10001000+ OCRDMA_MBX_QUERY_CFG_MAX_QP_SHIFT;10011001+ attr->max_send_sge = ((rsp->max_write_send_sge &10021002+ OCRDMA_MBX_QUERY_CFG_MAX_SEND_SGE_MASK) >>10031003+ OCRDMA_MBX_QUERY_CFG_MAX_SEND_SGE_SHIFT);10041004+ attr->max_recv_sge = (rsp->max_write_send_sge &10051005+ OCRDMA_MBX_QUERY_CFG_MAX_SEND_SGE_MASK) >>10061006+ OCRDMA_MBX_QUERY_CFG_MAX_SEND_SGE_SHIFT;10071007+ attr->max_ord_per_qp = (rsp->max_ird_ord_per_qp &10081008+ OCRDMA_MBX_QUERY_CFG_MAX_ORD_PER_QP_MASK) >>10091009+ OCRDMA_MBX_QUERY_CFG_MAX_ORD_PER_QP_SHIFT;10101010+ attr->max_ird_per_qp = (rsp->max_ird_ord_per_qp &10111011+ OCRDMA_MBX_QUERY_CFG_MAX_IRD_PER_QP_MASK) >>10121012+ OCRDMA_MBX_QUERY_CFG_MAX_IRD_PER_QP_SHIFT;10131013+ attr->cq_overflow_detect = (rsp->qp_srq_cq_ird_ord &10141014+ OCRDMA_MBX_QUERY_CFG_CQ_OVERFLOW_MASK) >>10151015+ OCRDMA_MBX_QUERY_CFG_CQ_OVERFLOW_SHIFT;10161016+ attr->srq_supported = (rsp->qp_srq_cq_ird_ord &10171017+ OCRDMA_MBX_QUERY_CFG_SRQ_SUPPORTED_MASK) >>10181018+ OCRDMA_MBX_QUERY_CFG_SRQ_SUPPORTED_SHIFT;10191019+ attr->local_ca_ack_delay = (rsp->max_pd_ca_ack_delay &10201020+ OCRDMA_MBX_QUERY_CFG_CA_ACK_DELAY_MASK) >>10211021+ OCRDMA_MBX_QUERY_CFG_CA_ACK_DELAY_SHIFT;10221022+ attr->max_mr = rsp->max_mr;10231023+ attr->max_mr_size = ~0ull;10241024+ attr->max_fmr = 0;10251025+ attr->max_pages_per_frmr = rsp->max_pages_per_frmr;10261026+ attr->max_num_mr_pbl = rsp->max_num_mr_pbl;10271027+ attr->max_cqe = rsp->max_cq_cqes_per_cq &10281028+ OCRDMA_MBX_QUERY_CFG_MAX_CQES_PER_CQ_MASK;10291029+ attr->wqe_size = ((rsp->wqe_rqe_stride_max_dpp_cqs &10301030+ OCRDMA_MBX_QUERY_CFG_MAX_WQE_SIZE_MASK) >>10311031+ OCRDMA_MBX_QUERY_CFG_MAX_WQE_SIZE_OFFSET) *10321032+ OCRDMA_WQE_STRIDE;10331033+ attr->rqe_size = ((rsp->wqe_rqe_stride_max_dpp_cqs &10341034+ OCRDMA_MBX_QUERY_CFG_MAX_RQE_SIZE_MASK) >>10351035+ OCRDMA_MBX_QUERY_CFG_MAX_RQE_SIZE_OFFSET) *10361036+ OCRDMA_WQE_STRIDE;10371037+ attr->max_inline_data =10381038+ attr->wqe_size - (sizeof(struct ocrdma_hdr_wqe) +10391039+ sizeof(struct ocrdma_sge));10401040+ max_q_mem = OCRDMA_Q_PAGE_BASE_SIZE << (OCRDMA_MAX_Q_PAGE_SIZE_CNT - 1);10411041+ /* hw can queue one less then the configured size,10421042+ * so publish less by one to stack.10431043+ */10441044+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {10451045+ dev->attr.max_wqe = max_q_mem / dev->attr.wqe_size;10461046+ attr->ird = 1;10471047+ attr->ird_page_size = OCRDMA_MIN_Q_PAGE_SIZE;10481048+ attr->num_ird_pages = MAX_OCRDMA_IRD_PAGES;10491049+ } else10501050+ dev->attr.max_wqe = (max_q_mem / dev->attr.wqe_size) - 1;10511051+ dev->attr.max_rqe = (max_q_mem / dev->attr.rqe_size) - 1;10521052+}10531053+10541054+static int ocrdma_check_fw_config(struct ocrdma_dev *dev,10551055+ struct ocrdma_fw_conf_rsp *conf)10561056+{10571057+ u32 fn_mode;10581058+10591059+ fn_mode = conf->fn_mode & OCRDMA_FN_MODE_RDMA;10601060+ if (fn_mode != OCRDMA_FN_MODE_RDMA)10611061+ return -EINVAL;10621062+ dev->base_eqid = conf->base_eqid;10631063+ dev->max_eq = conf->max_eq;10641064+ dev->attr.max_cq = OCRDMA_MAX_CQ - 1;10651065+ return 0;10661066+}10671067+10681068+/* can be issued only during init time. */10691069+static int ocrdma_mbx_query_fw_ver(struct ocrdma_dev *dev)10701070+{10711071+ int status = -ENOMEM;10721072+ struct ocrdma_mqe *cmd;10731073+ struct ocrdma_fw_ver_rsp *rsp;10741074+10751075+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_GET_FW_VER, sizeof(*cmd));10761076+ if (!cmd)10771077+ return -ENOMEM;10781078+ ocrdma_init_mch((struct ocrdma_mbx_hdr *)&cmd->u.cmd[0],10791079+ OCRDMA_CMD_GET_FW_VER,10801080+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));10811081+10821082+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);10831083+ if (status)10841084+ goto mbx_err;10851085+ rsp = (struct ocrdma_fw_ver_rsp *)cmd;10861086+ memset(&dev->attr.fw_ver[0], 0, sizeof(dev->attr.fw_ver));10871087+ memcpy(&dev->attr.fw_ver[0], &rsp->running_ver[0],10881088+ sizeof(rsp->running_ver));10891089+ ocrdma_le32_to_cpu(dev->attr.fw_ver, sizeof(rsp->running_ver));10901090+mbx_err:10911091+ kfree(cmd);10921092+ return status;10931093+}10941094+10951095+/* can be issued only during init time. */10961096+static int ocrdma_mbx_query_fw_config(struct ocrdma_dev *dev)10971097+{10981098+ int status = -ENOMEM;10991099+ struct ocrdma_mqe *cmd;11001100+ struct ocrdma_fw_conf_rsp *rsp;11011101+11021102+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_GET_FW_CONFIG, sizeof(*cmd));11031103+ if (!cmd)11041104+ return -ENOMEM;11051105+ ocrdma_init_mch((struct ocrdma_mbx_hdr *)&cmd->u.cmd[0],11061106+ OCRDMA_CMD_GET_FW_CONFIG,11071107+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));11081108+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);11091109+ if (status)11101110+ goto mbx_err;11111111+ rsp = (struct ocrdma_fw_conf_rsp *)cmd;11121112+ status = ocrdma_check_fw_config(dev, rsp);11131113+mbx_err:11141114+ kfree(cmd);11151115+ return status;11161116+}11171117+11181118+static int ocrdma_mbx_query_dev(struct ocrdma_dev *dev)11191119+{11201120+ int status = -ENOMEM;11211121+ struct ocrdma_mbx_query_config *rsp;11221122+ struct ocrdma_mqe *cmd;11231123+11241124+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_QUERY_CONFIG, sizeof(*cmd));11251125+ if (!cmd)11261126+ return status;11271127+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);11281128+ if (status)11291129+ goto mbx_err;11301130+ rsp = (struct ocrdma_mbx_query_config *)cmd;11311131+ ocrdma_get_attr(dev, &dev->attr, rsp);11321132+mbx_err:11331133+ kfree(cmd);11341134+ return status;11351135+}11361136+11371137+int ocrdma_mbx_alloc_pd(struct ocrdma_dev *dev, struct ocrdma_pd *pd)11381138+{11391139+ int status = -ENOMEM;11401140+ struct ocrdma_alloc_pd *cmd;11411141+ struct ocrdma_alloc_pd_rsp *rsp;11421142+11431143+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_PD, sizeof(*cmd));11441144+ if (!cmd)11451145+ return status;11461146+ if (pd->dpp_enabled)11471147+ cmd->enable_dpp_rsvd |= OCRDMA_ALLOC_PD_ENABLE_DPP;11481148+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);11491149+ if (status)11501150+ goto mbx_err;11511151+ rsp = (struct ocrdma_alloc_pd_rsp *)cmd;11521152+ pd->id = rsp->dpp_page_pdid & OCRDMA_ALLOC_PD_RSP_PDID_MASK;11531153+ if (rsp->dpp_page_pdid & OCRDMA_ALLOC_PD_RSP_DPP) {11541154+ pd->dpp_enabled = true;11551155+ pd->dpp_page = rsp->dpp_page_pdid >>11561156+ OCRDMA_ALLOC_PD_RSP_DPP_PAGE_SHIFT;11571157+ } else {11581158+ pd->dpp_enabled = false;11591159+ pd->num_dpp_qp = 0;11601160+ }11611161+mbx_err:11621162+ kfree(cmd);11631163+ return status;11641164+}11651165+11661166+int ocrdma_mbx_dealloc_pd(struct ocrdma_dev *dev, struct ocrdma_pd *pd)11671167+{11681168+ int status = -ENOMEM;11691169+ struct ocrdma_dealloc_pd *cmd;11701170+11711171+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DEALLOC_PD, sizeof(*cmd));11721172+ if (!cmd)11731173+ return status;11741174+ cmd->id = pd->id;11751175+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);11761176+ kfree(cmd);11771177+ return status;11781178+}11791179+11801180+static int ocrdma_build_q_conf(u32 *num_entries, int entry_size,11811181+ int *num_pages, int *page_size)11821182+{11831183+ int i;11841184+ int mem_size;11851185+11861186+ *num_entries = roundup_pow_of_two(*num_entries);11871187+ mem_size = *num_entries * entry_size;11881188+ /* find the possible lowest possible multiplier */11891189+ for (i = 0; i < OCRDMA_MAX_Q_PAGE_SIZE_CNT; i++) {11901190+ if (mem_size <= (OCRDMA_Q_PAGE_BASE_SIZE << i))11911191+ break;11921192+ }11931193+ if (i >= OCRDMA_MAX_Q_PAGE_SIZE_CNT)11941194+ return -EINVAL;11951195+ mem_size = roundup(mem_size,11961196+ ((OCRDMA_Q_PAGE_BASE_SIZE << i) / OCRDMA_MAX_Q_PAGES));11971197+ *num_pages =11981198+ mem_size / ((OCRDMA_Q_PAGE_BASE_SIZE << i) / OCRDMA_MAX_Q_PAGES);11991199+ *page_size = ((OCRDMA_Q_PAGE_BASE_SIZE << i) / OCRDMA_MAX_Q_PAGES);12001200+ *num_entries = mem_size / entry_size;12011201+ return 0;12021202+}12031203+12041204+static int ocrdma_mbx_create_ah_tbl(struct ocrdma_dev *dev)12051205+{12061206+ int i ;12071207+ int status = 0;12081208+ int max_ah;12091209+ struct ocrdma_create_ah_tbl *cmd;12101210+ struct ocrdma_create_ah_tbl_rsp *rsp;12111211+ struct pci_dev *pdev = dev->nic_info.pdev;12121212+ dma_addr_t pa;12131213+ struct ocrdma_pbe *pbes;12141214+12151215+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_AH_TBL, sizeof(*cmd));12161216+ if (!cmd)12171217+ return status;12181218+12191219+ max_ah = OCRDMA_MAX_AH;12201220+ dev->av_tbl.size = sizeof(struct ocrdma_av) * max_ah;12211221+12221222+ /* number of PBEs in PBL */12231223+ cmd->ah_conf = (OCRDMA_AH_TBL_PAGES <<12241224+ OCRDMA_CREATE_AH_NUM_PAGES_SHIFT) &12251225+ OCRDMA_CREATE_AH_NUM_PAGES_MASK;12261226+12271227+ /* page size */12281228+ for (i = 0; i < OCRDMA_MAX_Q_PAGE_SIZE_CNT; i++) {12291229+ if (PAGE_SIZE == (OCRDMA_MIN_Q_PAGE_SIZE << i))12301230+ break;12311231+ }12321232+ cmd->ah_conf |= (i << OCRDMA_CREATE_AH_PAGE_SIZE_SHIFT) &12331233+ OCRDMA_CREATE_AH_PAGE_SIZE_MASK;12341234+12351235+ /* ah_entry size */12361236+ cmd->ah_conf |= (sizeof(struct ocrdma_av) <<12371237+ OCRDMA_CREATE_AH_ENTRY_SIZE_SHIFT) &12381238+ OCRDMA_CREATE_AH_ENTRY_SIZE_MASK;12391239+12401240+ dev->av_tbl.pbl.va = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,12411241+ &dev->av_tbl.pbl.pa,12421242+ GFP_KERNEL);12431243+ if (dev->av_tbl.pbl.va == NULL)12441244+ goto mem_err;12451245+12461246+ dev->av_tbl.va = dma_alloc_coherent(&pdev->dev, dev->av_tbl.size,12471247+ &pa, GFP_KERNEL);12481248+ if (dev->av_tbl.va == NULL)12491249+ goto mem_err_ah;12501250+ dev->av_tbl.pa = pa;12511251+ dev->av_tbl.num_ah = max_ah;12521252+ memset(dev->av_tbl.va, 0, dev->av_tbl.size);12531253+12541254+ pbes = (struct ocrdma_pbe *)dev->av_tbl.pbl.va;12551255+ for (i = 0; i < dev->av_tbl.size / OCRDMA_MIN_Q_PAGE_SIZE; i++) {12561256+ pbes[i].pa_lo = (u32) (pa & 0xffffffff);12571257+ pbes[i].pa_hi = (u32) upper_32_bits(pa);12581258+ pa += PAGE_SIZE;12591259+ }12601260+ cmd->tbl_addr[0].lo = (u32)(dev->av_tbl.pbl.pa & 0xFFFFFFFF);12611261+ cmd->tbl_addr[0].hi = (u32)upper_32_bits(dev->av_tbl.pbl.pa);12621262+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);12631263+ if (status)12641264+ goto mbx_err;12651265+ rsp = (struct ocrdma_create_ah_tbl_rsp *)cmd;12661266+ dev->av_tbl.ahid = rsp->ahid & 0xFFFF;12671267+ kfree(cmd);12681268+ return 0;12691269+12701270+mbx_err:12711271+ dma_free_coherent(&pdev->dev, dev->av_tbl.size, dev->av_tbl.va,12721272+ dev->av_tbl.pa);12731273+ dev->av_tbl.va = NULL;12741274+mem_err_ah:12751275+ dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->av_tbl.pbl.va,12761276+ dev->av_tbl.pbl.pa);12771277+ dev->av_tbl.pbl.va = NULL;12781278+ dev->av_tbl.size = 0;12791279+mem_err:12801280+ kfree(cmd);12811281+ return status;12821282+}12831283+12841284+static void ocrdma_mbx_delete_ah_tbl(struct ocrdma_dev *dev)12851285+{12861286+ struct ocrdma_delete_ah_tbl *cmd;12871287+ struct pci_dev *pdev = dev->nic_info.pdev;12881288+12891289+ if (dev->av_tbl.va == NULL)12901290+ return;12911291+12921292+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DELETE_AH_TBL, sizeof(*cmd));12931293+ if (!cmd)12941294+ return;12951295+ cmd->ahid = dev->av_tbl.ahid;12961296+12971297+ ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);12981298+ dma_free_coherent(&pdev->dev, dev->av_tbl.size, dev->av_tbl.va,12991299+ dev->av_tbl.pa);13001300+ dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->av_tbl.pbl.va,13011301+ dev->av_tbl.pbl.pa);13021302+ kfree(cmd);13031303+}13041304+13051305+/* Multiple CQs uses the EQ. This routine returns least used13061306+ * EQ to associate with CQ. This will distributes the interrupt13071307+ * processing and CPU load to associated EQ, vector and so to that CPU.13081308+ */13091309+static u16 ocrdma_bind_eq(struct ocrdma_dev *dev)13101310+{13111311+ int i, selected_eq = 0, cq_cnt = 0;13121312+ u16 eq_id;13131313+13141314+ mutex_lock(&dev->dev_lock);13151315+ cq_cnt = dev->qp_eq_tbl[0].cq_cnt;13161316+ eq_id = dev->qp_eq_tbl[0].q.id;13171317+ /* find the EQ which is has the least number of13181318+ * CQs associated with it.13191319+ */13201320+ for (i = 0; i < dev->eq_cnt; i++) {13211321+ if (dev->qp_eq_tbl[i].cq_cnt < cq_cnt) {13221322+ cq_cnt = dev->qp_eq_tbl[i].cq_cnt;13231323+ eq_id = dev->qp_eq_tbl[i].q.id;13241324+ selected_eq = i;13251325+ }13261326+ }13271327+ dev->qp_eq_tbl[selected_eq].cq_cnt += 1;13281328+ mutex_unlock(&dev->dev_lock);13291329+ return eq_id;13301330+}13311331+13321332+static void ocrdma_unbind_eq(struct ocrdma_dev *dev, u16 eq_id)13331333+{13341334+ int i;13351335+13361336+ mutex_lock(&dev->dev_lock);13371337+ for (i = 0; i < dev->eq_cnt; i++) {13381338+ if (dev->qp_eq_tbl[i].q.id != eq_id)13391339+ continue;13401340+ dev->qp_eq_tbl[i].cq_cnt -= 1;13411341+ break;13421342+ }13431343+ mutex_unlock(&dev->dev_lock);13441344+}13451345+13461346+int ocrdma_mbx_create_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq,13471347+ int entries, int dpp_cq)13481348+{13491349+ int status = -ENOMEM; int max_hw_cqe;13501350+ struct pci_dev *pdev = dev->nic_info.pdev;13511351+ struct ocrdma_create_cq *cmd;13521352+ struct ocrdma_create_cq_rsp *rsp;13531353+ u32 hw_pages, cqe_size, page_size, cqe_count;13541354+13551355+ if (dpp_cq)13561356+ return -EINVAL;13571357+ if (entries > dev->attr.max_cqe) {13581358+ ocrdma_err("%s(%d) max_cqe=0x%x, requester_cqe=0x%x\n",13591359+ __func__, dev->id, dev->attr.max_cqe, entries);13601360+ return -EINVAL;13611361+ }13621362+ if (dpp_cq && (dev->nic_info.dev_family != OCRDMA_GEN2_FAMILY))13631363+ return -EINVAL;13641364+13651365+ if (dpp_cq) {13661366+ cq->max_hw_cqe = 1;13671367+ max_hw_cqe = 1;13681368+ cqe_size = OCRDMA_DPP_CQE_SIZE;13691369+ hw_pages = 1;13701370+ } else {13711371+ cq->max_hw_cqe = dev->attr.max_cqe;13721372+ max_hw_cqe = dev->attr.max_cqe;13731373+ cqe_size = sizeof(struct ocrdma_cqe);13741374+ hw_pages = OCRDMA_CREATE_CQ_MAX_PAGES;13751375+ }13761376+13771377+ cq->len = roundup(max_hw_cqe * cqe_size, OCRDMA_MIN_Q_PAGE_SIZE);13781378+13791379+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_CQ, sizeof(*cmd));13801380+ if (!cmd)13811381+ return -ENOMEM;13821382+ ocrdma_init_mch(&cmd->cmd.req, OCRDMA_CMD_CREATE_CQ,13831383+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));13841384+ cq->va = dma_alloc_coherent(&pdev->dev, cq->len, &cq->pa, GFP_KERNEL);13851385+ if (!cq->va) {13861386+ status = -ENOMEM;13871387+ goto mem_err;13881388+ }13891389+ memset(cq->va, 0, cq->len);13901390+ page_size = cq->len / hw_pages;13911391+ cmd->cmd.pgsz_pgcnt = (page_size / OCRDMA_MIN_Q_PAGE_SIZE) <<13921392+ OCRDMA_CREATE_CQ_PAGE_SIZE_SHIFT;13931393+ cmd->cmd.pgsz_pgcnt |= hw_pages;13941394+ cmd->cmd.ev_cnt_flags = OCRDMA_CREATE_CQ_DEF_FLAGS;13951395+13961396+ if (dev->eq_cnt < 0)13971397+ goto eq_err;13981398+ cq->eqn = ocrdma_bind_eq(dev);13991399+ cmd->cmd.req.rsvd_version = OCRDMA_CREATE_CQ_VER2;14001400+ cqe_count = cq->len / cqe_size;14011401+ if (cqe_count > 1024)14021402+ /* Set cnt to 3 to indicate more than 1024 cq entries */14031403+ cmd->cmd.ev_cnt_flags |= (0x3 << OCRDMA_CREATE_CQ_CNT_SHIFT);14041404+ else {14051405+ u8 count = 0;14061406+ switch (cqe_count) {14071407+ case 256:14081408+ count = 0;14091409+ break;14101410+ case 512:14111411+ count = 1;14121412+ break;14131413+ case 1024:14141414+ count = 2;14151415+ break;14161416+ default:14171417+ goto mbx_err;14181418+ }14191419+ cmd->cmd.ev_cnt_flags |= (count << OCRDMA_CREATE_CQ_CNT_SHIFT);14201420+ }14211421+ /* shared eq between all the consumer cqs. */14221422+ cmd->cmd.eqn = cq->eqn;14231423+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {14241424+ if (dpp_cq)14251425+ cmd->cmd.pgsz_pgcnt |= OCRDMA_CREATE_CQ_DPP <<14261426+ OCRDMA_CREATE_CQ_TYPE_SHIFT;14271427+ cq->phase_change = false;14281428+ cmd->cmd.cqe_count = (cq->len / cqe_size);14291429+ } else {14301430+ cmd->cmd.cqe_count = (cq->len / cqe_size) - 1;14311431+ cmd->cmd.ev_cnt_flags |= OCRDMA_CREATE_CQ_FLAGS_AUTO_VALID;14321432+ cq->phase_change = true;14331433+ }14341434+14351435+ ocrdma_build_q_pages(&cmd->cmd.pa[0], hw_pages, cq->pa, page_size);14361436+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);14371437+ if (status)14381438+ goto mbx_err;14391439+14401440+ rsp = (struct ocrdma_create_cq_rsp *)cmd;14411441+ cq->id = (u16) (rsp->rsp.cq_id & OCRDMA_CREATE_CQ_RSP_CQ_ID_MASK);14421442+ kfree(cmd);14431443+ return 0;14441444+mbx_err:14451445+ ocrdma_unbind_eq(dev, cq->eqn);14461446+eq_err:14471447+ dma_free_coherent(&pdev->dev, cq->len, cq->va, cq->pa);14481448+mem_err:14491449+ kfree(cmd);14501450+ return status;14511451+}14521452+14531453+int ocrdma_mbx_destroy_cq(struct ocrdma_dev *dev, struct ocrdma_cq *cq)14541454+{14551455+ int status = -ENOMEM;14561456+ struct ocrdma_destroy_cq *cmd;14571457+14581458+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DELETE_CQ, sizeof(*cmd));14591459+ if (!cmd)14601460+ return status;14611461+ ocrdma_init_mch(&cmd->req, OCRDMA_CMD_DELETE_CQ,14621462+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));14631463+14641464+ cmd->bypass_flush_qid |=14651465+ (cq->id << OCRDMA_DESTROY_CQ_QID_SHIFT) &14661466+ OCRDMA_DESTROY_CQ_QID_MASK;14671467+14681468+ ocrdma_unbind_eq(dev, cq->eqn);14691469+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);14701470+ if (status)14711471+ goto mbx_err;14721472+ dma_free_coherent(&dev->nic_info.pdev->dev, cq->len, cq->va, cq->pa);14731473+mbx_err:14741474+ kfree(cmd);14751475+ return status;14761476+}14771477+14781478+int ocrdma_mbx_alloc_lkey(struct ocrdma_dev *dev, struct ocrdma_hw_mr *hwmr,14791479+ u32 pdid, int addr_check)14801480+{14811481+ int status = -ENOMEM;14821482+ struct ocrdma_alloc_lkey *cmd;14831483+ struct ocrdma_alloc_lkey_rsp *rsp;14841484+14851485+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_LKEY, sizeof(*cmd));14861486+ if (!cmd)14871487+ return status;14881488+ cmd->pdid = pdid;14891489+ cmd->pbl_sz_flags |= addr_check;14901490+ cmd->pbl_sz_flags |= (hwmr->fr_mr << OCRDMA_ALLOC_LKEY_FMR_SHIFT);14911491+ cmd->pbl_sz_flags |=14921492+ (hwmr->remote_wr << OCRDMA_ALLOC_LKEY_REMOTE_WR_SHIFT);14931493+ cmd->pbl_sz_flags |=14941494+ (hwmr->remote_rd << OCRDMA_ALLOC_LKEY_REMOTE_RD_SHIFT);14951495+ cmd->pbl_sz_flags |=14961496+ (hwmr->local_wr << OCRDMA_ALLOC_LKEY_LOCAL_WR_SHIFT);14971497+ cmd->pbl_sz_flags |=14981498+ (hwmr->remote_atomic << OCRDMA_ALLOC_LKEY_REMOTE_ATOMIC_SHIFT);14991499+ cmd->pbl_sz_flags |=15001500+ (hwmr->num_pbls << OCRDMA_ALLOC_LKEY_PBL_SIZE_SHIFT);15011501+15021502+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);15031503+ if (status)15041504+ goto mbx_err;15051505+ rsp = (struct ocrdma_alloc_lkey_rsp *)cmd;15061506+ hwmr->lkey = rsp->lrkey;15071507+mbx_err:15081508+ kfree(cmd);15091509+ return status;15101510+}15111511+15121512+int ocrdma_mbx_dealloc_lkey(struct ocrdma_dev *dev, int fr_mr, u32 lkey)15131513+{15141514+ int status = -ENOMEM;15151515+ struct ocrdma_dealloc_lkey *cmd;15161516+15171517+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DEALLOC_LKEY, sizeof(*cmd));15181518+ if (!cmd)15191519+ return -ENOMEM;15201520+ cmd->lkey = lkey;15211521+ cmd->rsvd_frmr = fr_mr ? 1 : 0;15221522+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);15231523+ if (status)15241524+ goto mbx_err;15251525+mbx_err:15261526+ kfree(cmd);15271527+ return status;15281528+}15291529+15301530+static int ocrdma_mbx_reg_mr(struct ocrdma_dev *dev, struct ocrdma_hw_mr *hwmr,15311531+ u32 pdid, u32 pbl_cnt, u32 pbe_size, u32 last)15321532+{15331533+ int status = -ENOMEM;15341534+ int i;15351535+ struct ocrdma_reg_nsmr *cmd;15361536+ struct ocrdma_reg_nsmr_rsp *rsp;15371537+15381538+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_REGISTER_NSMR, sizeof(*cmd));15391539+ if (!cmd)15401540+ return -ENOMEM;15411541+ cmd->num_pbl_pdid =15421542+ pdid | (hwmr->num_pbls << OCRDMA_REG_NSMR_NUM_PBL_SHIFT);15431543+15441544+ cmd->flags_hpage_pbe_sz |= (hwmr->remote_wr <<15451545+ OCRDMA_REG_NSMR_REMOTE_WR_SHIFT);15461546+ cmd->flags_hpage_pbe_sz |= (hwmr->remote_rd <<15471547+ OCRDMA_REG_NSMR_REMOTE_RD_SHIFT);15481548+ cmd->flags_hpage_pbe_sz |= (hwmr->local_wr <<15491549+ OCRDMA_REG_NSMR_LOCAL_WR_SHIFT);15501550+ cmd->flags_hpage_pbe_sz |= (hwmr->remote_atomic <<15511551+ OCRDMA_REG_NSMR_REMOTE_ATOMIC_SHIFT);15521552+ cmd->flags_hpage_pbe_sz |= (hwmr->mw_bind <<15531553+ OCRDMA_REG_NSMR_BIND_MEMWIN_SHIFT);15541554+ cmd->flags_hpage_pbe_sz |= (last << OCRDMA_REG_NSMR_LAST_SHIFT);15551555+15561556+ cmd->flags_hpage_pbe_sz |= (hwmr->pbe_size / OCRDMA_MIN_HPAGE_SIZE);15571557+ cmd->flags_hpage_pbe_sz |= (hwmr->pbl_size / OCRDMA_MIN_HPAGE_SIZE) <<15581558+ OCRDMA_REG_NSMR_HPAGE_SIZE_SHIFT;15591559+ cmd->totlen_low = hwmr->len;15601560+ cmd->totlen_high = upper_32_bits(hwmr->len);15611561+ cmd->fbo_low = (u32) (hwmr->fbo & 0xffffffff);15621562+ cmd->fbo_high = (u32) upper_32_bits(hwmr->fbo);15631563+ cmd->va_loaddr = (u32) hwmr->va;15641564+ cmd->va_hiaddr = (u32) upper_32_bits(hwmr->va);15651565+15661566+ for (i = 0; i < pbl_cnt; i++) {15671567+ cmd->pbl[i].lo = (u32) (hwmr->pbl_table[i].pa & 0xffffffff);15681568+ cmd->pbl[i].hi = upper_32_bits(hwmr->pbl_table[i].pa);15691569+ }15701570+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);15711571+ if (status)15721572+ goto mbx_err;15731573+ rsp = (struct ocrdma_reg_nsmr_rsp *)cmd;15741574+ hwmr->lkey = rsp->lrkey;15751575+mbx_err:15761576+ kfree(cmd);15771577+ return status;15781578+}15791579+15801580+static int ocrdma_mbx_reg_mr_cont(struct ocrdma_dev *dev,15811581+ struct ocrdma_hw_mr *hwmr, u32 pbl_cnt,15821582+ u32 pbl_offset, u32 last)15831583+{15841584+ int status = -ENOMEM;15851585+ int i;15861586+ struct ocrdma_reg_nsmr_cont *cmd;15871587+15881588+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_REGISTER_NSMR_CONT, sizeof(*cmd));15891589+ if (!cmd)15901590+ return -ENOMEM;15911591+ cmd->lrkey = hwmr->lkey;15921592+ cmd->num_pbl_offset = (pbl_cnt << OCRDMA_REG_NSMR_CONT_NUM_PBL_SHIFT) |15931593+ (pbl_offset & OCRDMA_REG_NSMR_CONT_PBL_SHIFT_MASK);15941594+ cmd->last = last << OCRDMA_REG_NSMR_CONT_LAST_SHIFT;15951595+15961596+ for (i = 0; i < pbl_cnt; i++) {15971597+ cmd->pbl[i].lo =15981598+ (u32) (hwmr->pbl_table[i + pbl_offset].pa & 0xffffffff);15991599+ cmd->pbl[i].hi =16001600+ upper_32_bits(hwmr->pbl_table[i + pbl_offset].pa);16011601+ }16021602+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);16031603+ if (status)16041604+ goto mbx_err;16051605+mbx_err:16061606+ kfree(cmd);16071607+ return status;16081608+}16091609+16101610+int ocrdma_reg_mr(struct ocrdma_dev *dev,16111611+ struct ocrdma_hw_mr *hwmr, u32 pdid, int acc)16121612+{16131613+ int status;16141614+ u32 last = 0;16151615+ u32 cur_pbl_cnt, pbl_offset;16161616+ u32 pending_pbl_cnt = hwmr->num_pbls;16171617+16181618+ pbl_offset = 0;16191619+ cur_pbl_cnt = min(pending_pbl_cnt, MAX_OCRDMA_NSMR_PBL);16201620+ if (cur_pbl_cnt == pending_pbl_cnt)16211621+ last = 1;16221622+16231623+ status = ocrdma_mbx_reg_mr(dev, hwmr, pdid,16241624+ cur_pbl_cnt, hwmr->pbe_size, last);16251625+ if (status) {16261626+ ocrdma_err("%s() status=%d\n", __func__, status);16271627+ return status;16281628+ }16291629+ /* if there is no more pbls to register then exit. */16301630+ if (last)16311631+ return 0;16321632+16331633+ while (!last) {16341634+ pbl_offset += cur_pbl_cnt;16351635+ pending_pbl_cnt -= cur_pbl_cnt;16361636+ cur_pbl_cnt = min(pending_pbl_cnt, MAX_OCRDMA_NSMR_PBL);16371637+ /* if we reach the end of the pbls, then need to set the last16381638+ * bit, indicating no more pbls to register for this memory key.16391639+ */16401640+ if (cur_pbl_cnt == pending_pbl_cnt)16411641+ last = 1;16421642+16431643+ status = ocrdma_mbx_reg_mr_cont(dev, hwmr, cur_pbl_cnt,16441644+ pbl_offset, last);16451645+ if (status)16461646+ break;16471647+ }16481648+ if (status)16491649+ ocrdma_err("%s() err. status=%d\n", __func__, status);16501650+16511651+ return status;16521652+}16531653+16541654+bool ocrdma_is_qp_in_sq_flushlist(struct ocrdma_cq *cq, struct ocrdma_qp *qp)16551655+{16561656+ struct ocrdma_qp *tmp;16571657+ bool found = false;16581658+ list_for_each_entry(tmp, &cq->sq_head, sq_entry) {16591659+ if (qp == tmp) {16601660+ found = true;16611661+ break;16621662+ }16631663+ }16641664+ return found;16651665+}16661666+16671667+bool ocrdma_is_qp_in_rq_flushlist(struct ocrdma_cq *cq, struct ocrdma_qp *qp)16681668+{16691669+ struct ocrdma_qp *tmp;16701670+ bool found = false;16711671+ list_for_each_entry(tmp, &cq->rq_head, rq_entry) {16721672+ if (qp == tmp) {16731673+ found = true;16741674+ break;16751675+ }16761676+ }16771677+ return found;16781678+}16791679+16801680+void ocrdma_flush_qp(struct ocrdma_qp *qp)16811681+{16821682+ bool found;16831683+ unsigned long flags;16841684+16851685+ spin_lock_irqsave(&qp->dev->flush_q_lock, flags);16861686+ found = ocrdma_is_qp_in_sq_flushlist(qp->sq_cq, qp);16871687+ if (!found)16881688+ list_add_tail(&qp->sq_entry, &qp->sq_cq->sq_head);16891689+ if (!qp->srq) {16901690+ found = ocrdma_is_qp_in_rq_flushlist(qp->rq_cq, qp);16911691+ if (!found)16921692+ list_add_tail(&qp->rq_entry, &qp->rq_cq->rq_head);16931693+ }16941694+ spin_unlock_irqrestore(&qp->dev->flush_q_lock, flags);16951695+}16961696+16971697+int ocrdma_qp_state_machine(struct ocrdma_qp *qp, enum ib_qp_state new_ib_state,16981698+ enum ib_qp_state *old_ib_state)16991699+{17001700+ unsigned long flags;17011701+ int status = 0;17021702+ enum ocrdma_qp_state new_state;17031703+ new_state = get_ocrdma_qp_state(new_ib_state);17041704+17051705+ /* sync with wqe and rqe posting */17061706+ spin_lock_irqsave(&qp->q_lock, flags);17071707+17081708+ if (old_ib_state)17091709+ *old_ib_state = get_ibqp_state(qp->state);17101710+ if (new_state == qp->state) {17111711+ spin_unlock_irqrestore(&qp->q_lock, flags);17121712+ return 1;17131713+ }17141714+17151715+ switch (qp->state) {17161716+ case OCRDMA_QPS_RST:17171717+ switch (new_state) {17181718+ case OCRDMA_QPS_RST:17191719+ case OCRDMA_QPS_INIT:17201720+ break;17211721+ default:17221722+ status = -EINVAL;17231723+ break;17241724+ };17251725+ break;17261726+ case OCRDMA_QPS_INIT:17271727+ /* qps: INIT->XXX */17281728+ switch (new_state) {17291729+ case OCRDMA_QPS_INIT:17301730+ case OCRDMA_QPS_RTR:17311731+ break;17321732+ case OCRDMA_QPS_ERR:17331733+ ocrdma_flush_qp(qp);17341734+ break;17351735+ default:17361736+ status = -EINVAL;17371737+ break;17381738+ };17391739+ break;17401740+ case OCRDMA_QPS_RTR:17411741+ /* qps: RTS->XXX */17421742+ switch (new_state) {17431743+ case OCRDMA_QPS_RTS:17441744+ break;17451745+ case OCRDMA_QPS_ERR:17461746+ ocrdma_flush_qp(qp);17471747+ break;17481748+ default:17491749+ status = -EINVAL;17501750+ break;17511751+ };17521752+ break;17531753+ case OCRDMA_QPS_RTS:17541754+ /* qps: RTS->XXX */17551755+ switch (new_state) {17561756+ case OCRDMA_QPS_SQD:17571757+ case OCRDMA_QPS_SQE:17581758+ break;17591759+ case OCRDMA_QPS_ERR:17601760+ ocrdma_flush_qp(qp);17611761+ break;17621762+ default:17631763+ status = -EINVAL;17641764+ break;17651765+ };17661766+ break;17671767+ case OCRDMA_QPS_SQD:17681768+ /* qps: SQD->XXX */17691769+ switch (new_state) {17701770+ case OCRDMA_QPS_RTS:17711771+ case OCRDMA_QPS_SQE:17721772+ case OCRDMA_QPS_ERR:17731773+ break;17741774+ default:17751775+ status = -EINVAL;17761776+ break;17771777+ };17781778+ break;17791779+ case OCRDMA_QPS_SQE:17801780+ switch (new_state) {17811781+ case OCRDMA_QPS_RTS:17821782+ case OCRDMA_QPS_ERR:17831783+ break;17841784+ default:17851785+ status = -EINVAL;17861786+ break;17871787+ };17881788+ break;17891789+ case OCRDMA_QPS_ERR:17901790+ /* qps: ERR->XXX */17911791+ switch (new_state) {17921792+ case OCRDMA_QPS_RST:17931793+ break;17941794+ default:17951795+ status = -EINVAL;17961796+ break;17971797+ };17981798+ break;17991799+ default:18001800+ status = -EINVAL;18011801+ break;18021802+ };18031803+ if (!status)18041804+ qp->state = new_state;18051805+18061806+ spin_unlock_irqrestore(&qp->q_lock, flags);18071807+ return status;18081808+}18091809+18101810+static u32 ocrdma_set_create_qp_mbx_access_flags(struct ocrdma_qp *qp)18111811+{18121812+ u32 flags = 0;18131813+ if (qp->cap_flags & OCRDMA_QP_INB_RD)18141814+ flags |= OCRDMA_CREATE_QP_REQ_INB_RDEN_MASK;18151815+ if (qp->cap_flags & OCRDMA_QP_INB_WR)18161816+ flags |= OCRDMA_CREATE_QP_REQ_INB_WREN_MASK;18171817+ if (qp->cap_flags & OCRDMA_QP_MW_BIND)18181818+ flags |= OCRDMA_CREATE_QP_REQ_BIND_MEMWIN_MASK;18191819+ if (qp->cap_flags & OCRDMA_QP_LKEY0)18201820+ flags |= OCRDMA_CREATE_QP_REQ_ZERO_LKEYEN_MASK;18211821+ if (qp->cap_flags & OCRDMA_QP_FAST_REG)18221822+ flags |= OCRDMA_CREATE_QP_REQ_FMR_EN_MASK;18231823+ return flags;18241824+}18251825+18261826+static int ocrdma_set_create_qp_sq_cmd(struct ocrdma_create_qp_req *cmd,18271827+ struct ib_qp_init_attr *attrs,18281828+ struct ocrdma_qp *qp)18291829+{18301830+ int status;18311831+ u32 len, hw_pages, hw_page_size;18321832+ dma_addr_t pa;18331833+ struct ocrdma_dev *dev = qp->dev;18341834+ struct pci_dev *pdev = dev->nic_info.pdev;18351835+ u32 max_wqe_allocated;18361836+ u32 max_sges = attrs->cap.max_send_sge;18371837+18381838+ max_wqe_allocated = attrs->cap.max_send_wr;18391839+ /* need to allocate one extra to for GEN1 family */18401840+ if (dev->nic_info.dev_family != OCRDMA_GEN2_FAMILY)18411841+ max_wqe_allocated += 1;18421842+18431843+ status = ocrdma_build_q_conf(&max_wqe_allocated,18441844+ dev->attr.wqe_size, &hw_pages, &hw_page_size);18451845+ if (status) {18461846+ ocrdma_err("%s() req. max_send_wr=0x%x\n", __func__,18471847+ max_wqe_allocated);18481848+ return -EINVAL;18491849+ }18501850+ qp->sq.max_cnt = max_wqe_allocated;18511851+ len = (hw_pages * hw_page_size);18521852+18531853+ qp->sq.va = dma_alloc_coherent(&pdev->dev, len, &pa, GFP_KERNEL);18541854+ if (!qp->sq.va)18551855+ return -EINVAL;18561856+ memset(qp->sq.va, 0, len);18571857+ qp->sq.len = len;18581858+ qp->sq.pa = pa;18591859+ qp->sq.entry_size = dev->attr.wqe_size;18601860+ ocrdma_build_q_pages(&cmd->wq_addr[0], hw_pages, pa, hw_page_size);18611861+18621862+ cmd->type_pgsz_pdn |= (ilog2(hw_page_size / OCRDMA_MIN_Q_PAGE_SIZE)18631863+ << OCRDMA_CREATE_QP_REQ_SQ_PAGE_SIZE_SHIFT);18641864+ cmd->num_wq_rq_pages |= (hw_pages <<18651865+ OCRDMA_CREATE_QP_REQ_NUM_WQ_PAGES_SHIFT) &18661866+ OCRDMA_CREATE_QP_REQ_NUM_WQ_PAGES_MASK;18671867+ cmd->max_sge_send_write |= (max_sges <<18681868+ OCRDMA_CREATE_QP_REQ_MAX_SGE_SEND_SHIFT) &18691869+ OCRDMA_CREATE_QP_REQ_MAX_SGE_SEND_MASK;18701870+ cmd->max_sge_send_write |= (max_sges <<18711871+ OCRDMA_CREATE_QP_REQ_MAX_SGE_WRITE_SHIFT) &18721872+ OCRDMA_CREATE_QP_REQ_MAX_SGE_WRITE_MASK;18731873+ cmd->max_wqe_rqe |= (ilog2(qp->sq.max_cnt) <<18741874+ OCRDMA_CREATE_QP_REQ_MAX_WQE_SHIFT) &18751875+ OCRDMA_CREATE_QP_REQ_MAX_WQE_MASK;18761876+ cmd->wqe_rqe_size |= (dev->attr.wqe_size <<18771877+ OCRDMA_CREATE_QP_REQ_WQE_SIZE_SHIFT) &18781878+ OCRDMA_CREATE_QP_REQ_WQE_SIZE_MASK;18791879+ return 0;18801880+}18811881+18821882+static int ocrdma_set_create_qp_rq_cmd(struct ocrdma_create_qp_req *cmd,18831883+ struct ib_qp_init_attr *attrs,18841884+ struct ocrdma_qp *qp)18851885+{18861886+ int status;18871887+ u32 len, hw_pages, hw_page_size;18881888+ dma_addr_t pa = 0;18891889+ struct ocrdma_dev *dev = qp->dev;18901890+ struct pci_dev *pdev = dev->nic_info.pdev;18911891+ u32 max_rqe_allocated = attrs->cap.max_recv_wr + 1;18921892+18931893+ status = ocrdma_build_q_conf(&max_rqe_allocated, dev->attr.rqe_size,18941894+ &hw_pages, &hw_page_size);18951895+ if (status) {18961896+ ocrdma_err("%s() req. max_recv_wr=0x%x\n", __func__,18971897+ attrs->cap.max_recv_wr + 1);18981898+ return status;18991899+ }19001900+ qp->rq.max_cnt = max_rqe_allocated;19011901+ len = (hw_pages * hw_page_size);19021902+19031903+ qp->rq.va = dma_alloc_coherent(&pdev->dev, len, &pa, GFP_KERNEL);19041904+ if (!qp->rq.va)19051905+ return status;19061906+ memset(qp->rq.va, 0, len);19071907+ qp->rq.pa = pa;19081908+ qp->rq.len = len;19091909+ qp->rq.entry_size = dev->attr.rqe_size;19101910+19111911+ ocrdma_build_q_pages(&cmd->rq_addr[0], hw_pages, pa, hw_page_size);19121912+ cmd->type_pgsz_pdn |= (ilog2(hw_page_size / OCRDMA_MIN_Q_PAGE_SIZE) <<19131913+ OCRDMA_CREATE_QP_REQ_RQ_PAGE_SIZE_SHIFT);19141914+ cmd->num_wq_rq_pages |=19151915+ (hw_pages << OCRDMA_CREATE_QP_REQ_NUM_RQ_PAGES_SHIFT) &19161916+ OCRDMA_CREATE_QP_REQ_NUM_RQ_PAGES_MASK;19171917+ cmd->max_sge_recv_flags |= (attrs->cap.max_recv_sge <<19181918+ OCRDMA_CREATE_QP_REQ_MAX_SGE_RECV_SHIFT) &19191919+ OCRDMA_CREATE_QP_REQ_MAX_SGE_RECV_MASK;19201920+ cmd->max_wqe_rqe |= (ilog2(qp->rq.max_cnt) <<19211921+ OCRDMA_CREATE_QP_REQ_MAX_RQE_SHIFT) &19221922+ OCRDMA_CREATE_QP_REQ_MAX_RQE_MASK;19231923+ cmd->wqe_rqe_size |= (dev->attr.rqe_size <<19241924+ OCRDMA_CREATE_QP_REQ_RQE_SIZE_SHIFT) &19251925+ OCRDMA_CREATE_QP_REQ_RQE_SIZE_MASK;19261926+ return 0;19271927+}19281928+19291929+static void ocrdma_set_create_qp_dpp_cmd(struct ocrdma_create_qp_req *cmd,19301930+ struct ocrdma_pd *pd,19311931+ struct ocrdma_qp *qp,19321932+ u8 enable_dpp_cq, u16 dpp_cq_id)19331933+{19341934+ pd->num_dpp_qp--;19351935+ qp->dpp_enabled = true;19361936+ cmd->max_sge_recv_flags |= OCRDMA_CREATE_QP_REQ_ENABLE_DPP_MASK;19371937+ if (!enable_dpp_cq)19381938+ return;19391939+ cmd->max_sge_recv_flags |= OCRDMA_CREATE_QP_REQ_ENABLE_DPP_MASK;19401940+ cmd->dpp_credits_cqid = dpp_cq_id;19411941+ cmd->dpp_credits_cqid |= OCRDMA_CREATE_QP_REQ_DPP_CREDIT_LIMIT <<19421942+ OCRDMA_CREATE_QP_REQ_DPP_CREDIT_SHIFT;19431943+}19441944+19451945+static int ocrdma_set_create_qp_ird_cmd(struct ocrdma_create_qp_req *cmd,19461946+ struct ocrdma_qp *qp)19471947+{19481948+ struct ocrdma_dev *dev = qp->dev;19491949+ struct pci_dev *pdev = dev->nic_info.pdev;19501950+ dma_addr_t pa = 0;19511951+ int ird_page_size = dev->attr.ird_page_size;19521952+ int ird_q_len = dev->attr.num_ird_pages * ird_page_size;19531953+19541954+ if (dev->attr.ird == 0)19551955+ return 0;19561956+19571957+ qp->ird_q_va = dma_alloc_coherent(&pdev->dev, ird_q_len,19581958+ &pa, GFP_KERNEL);19591959+ if (!qp->ird_q_va)19601960+ return -ENOMEM;19611961+ memset(qp->ird_q_va, 0, ird_q_len);19621962+ ocrdma_build_q_pages(&cmd->ird_addr[0], dev->attr.num_ird_pages,19631963+ pa, ird_page_size);19641964+ return 0;19651965+}19661966+19671967+static void ocrdma_get_create_qp_rsp(struct ocrdma_create_qp_rsp *rsp,19681968+ struct ocrdma_qp *qp,19691969+ struct ib_qp_init_attr *attrs,19701970+ u16 *dpp_offset, u16 *dpp_credit_lmt)19711971+{19721972+ u32 max_wqe_allocated, max_rqe_allocated;19731973+ qp->id = rsp->qp_id & OCRDMA_CREATE_QP_RSP_QP_ID_MASK;19741974+ qp->rq.dbid = rsp->sq_rq_id & OCRDMA_CREATE_QP_RSP_RQ_ID_MASK;19751975+ qp->sq.dbid = rsp->sq_rq_id >> OCRDMA_CREATE_QP_RSP_SQ_ID_SHIFT;19761976+ qp->max_ird = rsp->max_ord_ird & OCRDMA_CREATE_QP_RSP_MAX_IRD_MASK;19771977+ qp->max_ord = (rsp->max_ord_ird >> OCRDMA_CREATE_QP_RSP_MAX_ORD_SHIFT);19781978+ qp->dpp_enabled = false;19791979+ if (rsp->dpp_response & OCRDMA_CREATE_QP_RSP_DPP_ENABLED_MASK) {19801980+ qp->dpp_enabled = true;19811981+ *dpp_credit_lmt = (rsp->dpp_response &19821982+ OCRDMA_CREATE_QP_RSP_DPP_CREDITS_MASK) >>19831983+ OCRDMA_CREATE_QP_RSP_DPP_CREDITS_SHIFT;19841984+ *dpp_offset = (rsp->dpp_response &19851985+ OCRDMA_CREATE_QP_RSP_DPP_PAGE_OFFSET_MASK) >>19861986+ OCRDMA_CREATE_QP_RSP_DPP_PAGE_OFFSET_SHIFT;19871987+ }19881988+ max_wqe_allocated =19891989+ rsp->max_wqe_rqe >> OCRDMA_CREATE_QP_RSP_MAX_WQE_SHIFT;19901990+ max_wqe_allocated = 1 << max_wqe_allocated;19911991+ max_rqe_allocated = 1 << ((u16)rsp->max_wqe_rqe);19921992+19931993+ if (qp->dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {19941994+ qp->sq.free_delta = 0;19951995+ qp->rq.free_delta = 1;19961996+ } else19971997+ qp->sq.free_delta = 1;19981998+19991999+ qp->sq.max_cnt = max_wqe_allocated;20002000+ qp->sq.max_wqe_idx = max_wqe_allocated - 1;20012001+20022002+ if (!attrs->srq) {20032003+ qp->rq.max_cnt = max_rqe_allocated;20042004+ qp->rq.max_wqe_idx = max_rqe_allocated - 1;20052005+ qp->rq.free_delta = 1;20062006+ }20072007+}20082008+20092009+int ocrdma_mbx_create_qp(struct ocrdma_qp *qp, struct ib_qp_init_attr *attrs,20102010+ u8 enable_dpp_cq, u16 dpp_cq_id, u16 *dpp_offset,20112011+ u16 *dpp_credit_lmt)20122012+{20132013+ int status = -ENOMEM;20142014+ u32 flags = 0;20152015+ struct ocrdma_dev *dev = qp->dev;20162016+ struct ocrdma_pd *pd = qp->pd;20172017+ struct pci_dev *pdev = dev->nic_info.pdev;20182018+ struct ocrdma_cq *cq;20192019+ struct ocrdma_create_qp_req *cmd;20202020+ struct ocrdma_create_qp_rsp *rsp;20212021+ int qptype;20222022+20232023+ switch (attrs->qp_type) {20242024+ case IB_QPT_GSI:20252025+ qptype = OCRDMA_QPT_GSI;20262026+ break;20272027+ case IB_QPT_RC:20282028+ qptype = OCRDMA_QPT_RC;20292029+ break;20302030+ case IB_QPT_UD:20312031+ qptype = OCRDMA_QPT_UD;20322032+ break;20332033+ default:20342034+ return -EINVAL;20352035+ };20362036+20372037+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_QP, sizeof(*cmd));20382038+ if (!cmd)20392039+ return status;20402040+ cmd->type_pgsz_pdn |= (qptype << OCRDMA_CREATE_QP_REQ_QPT_SHIFT) &20412041+ OCRDMA_CREATE_QP_REQ_QPT_MASK;20422042+ status = ocrdma_set_create_qp_sq_cmd(cmd, attrs, qp);20432043+ if (status)20442044+ goto sq_err;20452045+20462046+ if (attrs->srq) {20472047+ struct ocrdma_srq *srq = get_ocrdma_srq(attrs->srq);20482048+ cmd->max_sge_recv_flags |= OCRDMA_CREATE_QP_REQ_USE_SRQ_MASK;20492049+ cmd->rq_addr[0].lo = srq->id;20502050+ qp->srq = srq;20512051+ } else {20522052+ status = ocrdma_set_create_qp_rq_cmd(cmd, attrs, qp);20532053+ if (status)20542054+ goto rq_err;20552055+ }20562056+20572057+ status = ocrdma_set_create_qp_ird_cmd(cmd, qp);20582058+ if (status)20592059+ goto mbx_err;20602060+20612061+ cmd->type_pgsz_pdn |= (pd->id << OCRDMA_CREATE_QP_REQ_PD_ID_SHIFT) &20622062+ OCRDMA_CREATE_QP_REQ_PD_ID_MASK;20632063+20642064+ flags = ocrdma_set_create_qp_mbx_access_flags(qp);20652065+20662066+ cmd->max_sge_recv_flags |= flags;20672067+ cmd->max_ord_ird |= (dev->attr.max_ord_per_qp <<20682068+ OCRDMA_CREATE_QP_REQ_MAX_ORD_SHIFT) &20692069+ OCRDMA_CREATE_QP_REQ_MAX_ORD_MASK;20702070+ cmd->max_ord_ird |= (dev->attr.max_ird_per_qp <<20712071+ OCRDMA_CREATE_QP_REQ_MAX_IRD_SHIFT) &20722072+ OCRDMA_CREATE_QP_REQ_MAX_IRD_MASK;20732073+ cq = get_ocrdma_cq(attrs->send_cq);20742074+ cmd->wq_rq_cqid |= (cq->id << OCRDMA_CREATE_QP_REQ_WQ_CQID_SHIFT) &20752075+ OCRDMA_CREATE_QP_REQ_WQ_CQID_MASK;20762076+ qp->sq_cq = cq;20772077+ cq = get_ocrdma_cq(attrs->recv_cq);20782078+ cmd->wq_rq_cqid |= (cq->id << OCRDMA_CREATE_QP_REQ_RQ_CQID_SHIFT) &20792079+ OCRDMA_CREATE_QP_REQ_RQ_CQID_MASK;20802080+ qp->rq_cq = cq;20812081+20822082+ if (pd->dpp_enabled && attrs->cap.max_inline_data && pd->num_dpp_qp &&20832083+ (attrs->cap.max_inline_data <= dev->attr.max_inline_data))20842084+ ocrdma_set_create_qp_dpp_cmd(cmd, pd, qp, enable_dpp_cq,20852085+ dpp_cq_id);20862086+20872087+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);20882088+ if (status)20892089+ goto mbx_err;20902090+ rsp = (struct ocrdma_create_qp_rsp *)cmd;20912091+ ocrdma_get_create_qp_rsp(rsp, qp, attrs, dpp_offset, dpp_credit_lmt);20922092+ qp->state = OCRDMA_QPS_RST;20932093+ kfree(cmd);20942094+ return 0;20952095+mbx_err:20962096+ if (qp->rq.va)20972097+ dma_free_coherent(&pdev->dev, qp->rq.len, qp->rq.va, qp->rq.pa);20982098+rq_err:20992099+ ocrdma_err("%s(%d) rq_err\n", __func__, dev->id);21002100+ dma_free_coherent(&pdev->dev, qp->sq.len, qp->sq.va, qp->sq.pa);21012101+sq_err:21022102+ ocrdma_err("%s(%d) sq_err\n", __func__, dev->id);21032103+ kfree(cmd);21042104+ return status;21052105+}21062106+21072107+int ocrdma_mbx_query_qp(struct ocrdma_dev *dev, struct ocrdma_qp *qp,21082108+ struct ocrdma_qp_params *param)21092109+{21102110+ int status = -ENOMEM;21112111+ struct ocrdma_query_qp *cmd;21122112+ struct ocrdma_query_qp_rsp *rsp;21132113+21142114+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_QUERY_QP, sizeof(*cmd));21152115+ if (!cmd)21162116+ return status;21172117+ cmd->qp_id = qp->id;21182118+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);21192119+ if (status)21202120+ goto mbx_err;21212121+ rsp = (struct ocrdma_query_qp_rsp *)cmd;21222122+ memcpy(param, &rsp->params, sizeof(struct ocrdma_qp_params));21232123+mbx_err:21242124+ kfree(cmd);21252125+ return status;21262126+}21272127+21282128+int ocrdma_resolve_dgid(struct ocrdma_dev *dev, union ib_gid *dgid,21292129+ u8 *mac_addr)21302130+{21312131+ struct in6_addr in6;21322132+21332133+ memcpy(&in6, dgid, sizeof in6);21342134+ if (rdma_is_multicast_addr(&in6))21352135+ rdma_get_mcast_mac(&in6, mac_addr);21362136+ else if (rdma_link_local_addr(&in6))21372137+ rdma_get_ll_mac(&in6, mac_addr);21382138+ else {21392139+ ocrdma_err("%s() fail to resolve mac_addr.\n", __func__);21402140+ return -EINVAL;21412141+ }21422142+ return 0;21432143+}21442144+21452145+static void ocrdma_set_av_params(struct ocrdma_qp *qp,21462146+ struct ocrdma_modify_qp *cmd,21472147+ struct ib_qp_attr *attrs)21482148+{21492149+ struct ib_ah_attr *ah_attr = &attrs->ah_attr;21502150+ union ib_gid sgid;21512151+ u32 vlan_id;21522152+ u8 mac_addr[6];21532153+ if ((ah_attr->ah_flags & IB_AH_GRH) == 0)21542154+ return;21552155+ cmd->params.tclass_sq_psn |=21562156+ (ah_attr->grh.traffic_class << OCRDMA_QP_PARAMS_TCLASS_SHIFT);21572157+ cmd->params.rnt_rc_sl_fl |=21582158+ (ah_attr->grh.flow_label & OCRDMA_QP_PARAMS_FLOW_LABEL_MASK);21592159+ cmd->params.hop_lmt_rq_psn |=21602160+ (ah_attr->grh.hop_limit << OCRDMA_QP_PARAMS_HOP_LMT_SHIFT);21612161+ cmd->flags |= OCRDMA_QP_PARA_FLOW_LBL_VALID;21622162+ memcpy(&cmd->params.dgid[0], &ah_attr->grh.dgid.raw[0],21632163+ sizeof(cmd->params.dgid));21642164+ ocrdma_query_gid(&qp->dev->ibdev, 1,21652165+ ah_attr->grh.sgid_index, &sgid);21662166+ qp->sgid_idx = ah_attr->grh.sgid_index;21672167+ memcpy(&cmd->params.sgid[0], &sgid.raw[0], sizeof(cmd->params.sgid));21682168+ ocrdma_resolve_dgid(qp->dev, &ah_attr->grh.dgid, &mac_addr[0]);21692169+ cmd->params.dmac_b0_to_b3 = mac_addr[0] | (mac_addr[1] << 8) |21702170+ (mac_addr[2] << 16) | (mac_addr[3] << 24);21712171+ /* convert them to LE format. */21722172+ ocrdma_cpu_to_le32(&cmd->params.dgid[0], sizeof(cmd->params.dgid));21732173+ ocrdma_cpu_to_le32(&cmd->params.sgid[0], sizeof(cmd->params.sgid));21742174+ cmd->params.vlan_dmac_b4_to_b5 = mac_addr[4] | (mac_addr[5] << 8);21752175+ vlan_id = rdma_get_vlan_id(&sgid);21762176+ if (vlan_id && (vlan_id < 0x1000)) {21772177+ cmd->params.vlan_dmac_b4_to_b5 |=21782178+ vlan_id << OCRDMA_QP_PARAMS_VLAN_SHIFT;21792179+ cmd->flags |= OCRDMA_QP_PARA_VLAN_EN_VALID;21802180+ }21812181+}21822182+21832183+static int ocrdma_set_qp_params(struct ocrdma_qp *qp,21842184+ struct ocrdma_modify_qp *cmd,21852185+ struct ib_qp_attr *attrs, int attr_mask,21862186+ enum ib_qp_state old_qps)21872187+{21882188+ int status = 0;21892189+ struct net_device *netdev = qp->dev->nic_info.netdev;21902190+ int eth_mtu = iboe_get_mtu(netdev->mtu);21912191+21922192+ if (attr_mask & IB_QP_PKEY_INDEX) {21932193+ cmd->params.path_mtu_pkey_indx |= (attrs->pkey_index &21942194+ OCRDMA_QP_PARAMS_PKEY_INDEX_MASK);21952195+ cmd->flags |= OCRDMA_QP_PARA_PKEY_VALID;21962196+ }21972197+ if (attr_mask & IB_QP_QKEY) {21982198+ qp->qkey = attrs->qkey;21992199+ cmd->params.qkey = attrs->qkey;22002200+ cmd->flags |= OCRDMA_QP_PARA_QKEY_VALID;22012201+ }22022202+ if (attr_mask & IB_QP_AV)22032203+ ocrdma_set_av_params(qp, cmd, attrs);22042204+ else if (qp->qp_type == IB_QPT_GSI || qp->qp_type == IB_QPT_UD) {22052205+ /* set the default mac address for UD, GSI QPs */22062206+ cmd->params.dmac_b0_to_b3 = qp->dev->nic_info.mac_addr[0] |22072207+ (qp->dev->nic_info.mac_addr[1] << 8) |22082208+ (qp->dev->nic_info.mac_addr[2] << 16) |22092209+ (qp->dev->nic_info.mac_addr[3] << 24);22102210+ cmd->params.vlan_dmac_b4_to_b5 = qp->dev->nic_info.mac_addr[4] |22112211+ (qp->dev->nic_info.mac_addr[5] << 8);22122212+ }22132213+ if ((attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) &&22142214+ attrs->en_sqd_async_notify) {22152215+ cmd->params.max_sge_recv_flags |=22162216+ OCRDMA_QP_PARAMS_FLAGS_SQD_ASYNC;22172217+ cmd->flags |= OCRDMA_QP_PARA_DST_QPN_VALID;22182218+ }22192219+ if (attr_mask & IB_QP_DEST_QPN) {22202220+ cmd->params.ack_to_rnr_rtc_dest_qpn |= (attrs->dest_qp_num &22212221+ OCRDMA_QP_PARAMS_DEST_QPN_MASK);22222222+ cmd->flags |= OCRDMA_QP_PARA_DST_QPN_VALID;22232223+ }22242224+ if (attr_mask & IB_QP_PATH_MTU) {22252225+ if (ib_mtu_enum_to_int(eth_mtu) <22262226+ ib_mtu_enum_to_int(attrs->path_mtu)) {22272227+ status = -EINVAL;22282228+ goto pmtu_err;22292229+ }22302230+ cmd->params.path_mtu_pkey_indx |=22312231+ (ib_mtu_enum_to_int(attrs->path_mtu) <<22322232+ OCRDMA_QP_PARAMS_PATH_MTU_SHIFT) &22332233+ OCRDMA_QP_PARAMS_PATH_MTU_MASK;22342234+ cmd->flags |= OCRDMA_QP_PARA_PMTU_VALID;22352235+ }22362236+ if (attr_mask & IB_QP_TIMEOUT) {22372237+ cmd->params.ack_to_rnr_rtc_dest_qpn |= attrs->timeout <<22382238+ OCRDMA_QP_PARAMS_ACK_TIMEOUT_SHIFT;22392239+ cmd->flags |= OCRDMA_QP_PARA_ACK_TO_VALID;22402240+ }22412241+ if (attr_mask & IB_QP_RETRY_CNT) {22422242+ cmd->params.rnt_rc_sl_fl |= (attrs->retry_cnt <<22432243+ OCRDMA_QP_PARAMS_RETRY_CNT_SHIFT) &22442244+ OCRDMA_QP_PARAMS_RETRY_CNT_MASK;22452245+ cmd->flags |= OCRDMA_QP_PARA_RETRY_CNT_VALID;22462246+ }22472247+ if (attr_mask & IB_QP_MIN_RNR_TIMER) {22482248+ cmd->params.rnt_rc_sl_fl |= (attrs->min_rnr_timer <<22492249+ OCRDMA_QP_PARAMS_RNR_NAK_TIMER_SHIFT) &22502250+ OCRDMA_QP_PARAMS_RNR_NAK_TIMER_MASK;22512251+ cmd->flags |= OCRDMA_QP_PARA_RNT_VALID;22522252+ }22532253+ if (attr_mask & IB_QP_RNR_RETRY) {22542254+ cmd->params.ack_to_rnr_rtc_dest_qpn |= (attrs->rnr_retry <<22552255+ OCRDMA_QP_PARAMS_RNR_RETRY_CNT_SHIFT)22562256+ & OCRDMA_QP_PARAMS_RNR_RETRY_CNT_MASK;22572257+ cmd->flags |= OCRDMA_QP_PARA_RRC_VALID;22582258+ }22592259+ if (attr_mask & IB_QP_SQ_PSN) {22602260+ cmd->params.tclass_sq_psn |= (attrs->sq_psn & 0x00ffffff);22612261+ cmd->flags |= OCRDMA_QP_PARA_SQPSN_VALID;22622262+ }22632263+ if (attr_mask & IB_QP_RQ_PSN) {22642264+ cmd->params.hop_lmt_rq_psn |= (attrs->rq_psn & 0x00ffffff);22652265+ cmd->flags |= OCRDMA_QP_PARA_RQPSN_VALID;22662266+ }22672267+ if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {22682268+ if (attrs->max_rd_atomic > qp->dev->attr.max_ord_per_qp) {22692269+ status = -EINVAL;22702270+ goto pmtu_err;22712271+ }22722272+ qp->max_ord = attrs->max_rd_atomic;22732273+ cmd->flags |= OCRDMA_QP_PARA_MAX_ORD_VALID;22742274+ }22752275+ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {22762276+ if (attrs->max_dest_rd_atomic > qp->dev->attr.max_ird_per_qp) {22772277+ status = -EINVAL;22782278+ goto pmtu_err;22792279+ }22802280+ qp->max_ird = attrs->max_dest_rd_atomic;22812281+ cmd->flags |= OCRDMA_QP_PARA_MAX_IRD_VALID;22822282+ }22832283+ cmd->params.max_ord_ird = (qp->max_ord <<22842284+ OCRDMA_QP_PARAMS_MAX_ORD_SHIFT) |22852285+ (qp->max_ird & OCRDMA_QP_PARAMS_MAX_IRD_MASK);22862286+pmtu_err:22872287+ return status;22882288+}22892289+22902290+int ocrdma_mbx_modify_qp(struct ocrdma_dev *dev, struct ocrdma_qp *qp,22912291+ struct ib_qp_attr *attrs, int attr_mask,22922292+ enum ib_qp_state old_qps)22932293+{22942294+ int status = -ENOMEM;22952295+ struct ocrdma_modify_qp *cmd;22962296+22972297+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_MODIFY_QP, sizeof(*cmd));22982298+ if (!cmd)22992299+ return status;23002300+23012301+ cmd->params.id = qp->id;23022302+ cmd->flags = 0;23032303+ if (attr_mask & IB_QP_STATE) {23042304+ cmd->params.max_sge_recv_flags |=23052305+ (get_ocrdma_qp_state(attrs->qp_state) <<23062306+ OCRDMA_QP_PARAMS_STATE_SHIFT) &23072307+ OCRDMA_QP_PARAMS_STATE_MASK;23082308+ cmd->flags |= OCRDMA_QP_PARA_QPS_VALID;23092309+ } else23102310+ cmd->params.max_sge_recv_flags |=23112311+ (qp->state << OCRDMA_QP_PARAMS_STATE_SHIFT) &23122312+ OCRDMA_QP_PARAMS_STATE_MASK;23132313+ status = ocrdma_set_qp_params(qp, cmd, attrs, attr_mask, old_qps);23142314+ if (status)23152315+ goto mbx_err;23162316+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);23172317+ if (status)23182318+ goto mbx_err;23192319+23202320+mbx_err:23212321+ kfree(cmd);23222322+ return status;23232323+}23242324+23252325+int ocrdma_mbx_destroy_qp(struct ocrdma_dev *dev, struct ocrdma_qp *qp)23262326+{23272327+ int status = -ENOMEM;23282328+ struct ocrdma_destroy_qp *cmd;23292329+ struct pci_dev *pdev = dev->nic_info.pdev;23302330+23312331+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DELETE_QP, sizeof(*cmd));23322332+ if (!cmd)23332333+ return status;23342334+ cmd->qp_id = qp->id;23352335+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);23362336+ if (status)23372337+ goto mbx_err;23382338+23392339+mbx_err:23402340+ kfree(cmd);23412341+ if (qp->sq.va)23422342+ dma_free_coherent(&pdev->dev, qp->sq.len, qp->sq.va, qp->sq.pa);23432343+ if (!qp->srq && qp->rq.va)23442344+ dma_free_coherent(&pdev->dev, qp->rq.len, qp->rq.va, qp->rq.pa);23452345+ if (qp->dpp_enabled)23462346+ qp->pd->num_dpp_qp++;23472347+ return status;23482348+}23492349+23502350+int ocrdma_mbx_create_srq(struct ocrdma_srq *srq,23512351+ struct ib_srq_init_attr *srq_attr,23522352+ struct ocrdma_pd *pd)23532353+{23542354+ int status = -ENOMEM;23552355+ int hw_pages, hw_page_size;23562356+ int len;23572357+ struct ocrdma_create_srq_rsp *rsp;23582358+ struct ocrdma_create_srq *cmd;23592359+ dma_addr_t pa;23602360+ struct ocrdma_dev *dev = srq->dev;23612361+ struct pci_dev *pdev = dev->nic_info.pdev;23622362+ u32 max_rqe_allocated;23632363+23642364+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_SRQ, sizeof(*cmd));23652365+ if (!cmd)23662366+ return status;23672367+23682368+ cmd->pgsz_pdid = pd->id & OCRDMA_CREATE_SRQ_PD_ID_MASK;23692369+ max_rqe_allocated = srq_attr->attr.max_wr + 1;23702370+ status = ocrdma_build_q_conf(&max_rqe_allocated,23712371+ dev->attr.rqe_size,23722372+ &hw_pages, &hw_page_size);23732373+ if (status) {23742374+ ocrdma_err("%s() req. max_wr=0x%x\n", __func__,23752375+ srq_attr->attr.max_wr);23762376+ status = -EINVAL;23772377+ goto ret;23782378+ }23792379+ len = hw_pages * hw_page_size;23802380+ srq->rq.va = dma_alloc_coherent(&pdev->dev, len, &pa, GFP_KERNEL);23812381+ if (!srq->rq.va) {23822382+ status = -ENOMEM;23832383+ goto ret;23842384+ }23852385+ ocrdma_build_q_pages(&cmd->rq_addr[0], hw_pages, pa, hw_page_size);23862386+23872387+ srq->rq.entry_size = dev->attr.rqe_size;23882388+ srq->rq.pa = pa;23892389+ srq->rq.len = len;23902390+ srq->rq.max_cnt = max_rqe_allocated;23912391+23922392+ cmd->max_sge_rqe = ilog2(max_rqe_allocated);23932393+ cmd->max_sge_rqe |= srq_attr->attr.max_sge <<23942394+ OCRDMA_CREATE_SRQ_MAX_SGE_RECV_SHIFT;23952395+23962396+ cmd->pgsz_pdid |= (ilog2(hw_page_size / OCRDMA_MIN_Q_PAGE_SIZE)23972397+ << OCRDMA_CREATE_SRQ_PG_SZ_SHIFT);23982398+ cmd->pages_rqe_sz |= (dev->attr.rqe_size23992399+ << OCRDMA_CREATE_SRQ_RQE_SIZE_SHIFT)24002400+ & OCRDMA_CREATE_SRQ_RQE_SIZE_MASK;24012401+ cmd->pages_rqe_sz |= hw_pages << OCRDMA_CREATE_SRQ_NUM_RQ_PAGES_SHIFT;24022402+24032403+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);24042404+ if (status)24052405+ goto mbx_err;24062406+ rsp = (struct ocrdma_create_srq_rsp *)cmd;24072407+ srq->id = rsp->id;24082408+ srq->rq.dbid = rsp->id;24092409+ max_rqe_allocated = ((rsp->max_sge_rqe_allocated &24102410+ OCRDMA_CREATE_SRQ_RSP_MAX_RQE_ALLOCATED_MASK) >>24112411+ OCRDMA_CREATE_SRQ_RSP_MAX_RQE_ALLOCATED_SHIFT);24122412+ max_rqe_allocated = (1 << max_rqe_allocated);24132413+ srq->rq.max_cnt = max_rqe_allocated;24142414+ srq->rq.max_wqe_idx = max_rqe_allocated - 1;24152415+ srq->rq.max_sges = (rsp->max_sge_rqe_allocated &24162416+ OCRDMA_CREATE_SRQ_RSP_MAX_SGE_RECV_ALLOCATED_MASK) >>24172417+ OCRDMA_CREATE_SRQ_RSP_MAX_SGE_RECV_ALLOCATED_SHIFT;24182418+ goto ret;24192419+mbx_err:24202420+ dma_free_coherent(&pdev->dev, srq->rq.len, srq->rq.va, pa);24212421+ret:24222422+ kfree(cmd);24232423+ return status;24242424+}24252425+24262426+int ocrdma_mbx_modify_srq(struct ocrdma_srq *srq, struct ib_srq_attr *srq_attr)24272427+{24282428+ int status = -ENOMEM;24292429+ struct ocrdma_modify_srq *cmd;24302430+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_SRQ, sizeof(*cmd));24312431+ if (!cmd)24322432+ return status;24332433+ cmd->id = srq->id;24342434+ cmd->limit_max_rqe |= srq_attr->srq_limit <<24352435+ OCRDMA_MODIFY_SRQ_LIMIT_SHIFT;24362436+ status = ocrdma_mbx_cmd(srq->dev, (struct ocrdma_mqe *)cmd);24372437+ kfree(cmd);24382438+ return status;24392439+}24402440+24412441+int ocrdma_mbx_query_srq(struct ocrdma_srq *srq, struct ib_srq_attr *srq_attr)24422442+{24432443+ int status = -ENOMEM;24442444+ struct ocrdma_query_srq *cmd;24452445+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_CREATE_SRQ, sizeof(*cmd));24462446+ if (!cmd)24472447+ return status;24482448+ cmd->id = srq->rq.dbid;24492449+ status = ocrdma_mbx_cmd(srq->dev, (struct ocrdma_mqe *)cmd);24502450+ if (status == 0) {24512451+ struct ocrdma_query_srq_rsp *rsp =24522452+ (struct ocrdma_query_srq_rsp *)cmd;24532453+ srq_attr->max_sge =24542454+ rsp->srq_lmt_max_sge &24552455+ OCRDMA_QUERY_SRQ_RSP_MAX_SGE_RECV_MASK;24562456+ srq_attr->max_wr =24572457+ rsp->max_rqe_pdid >> OCRDMA_QUERY_SRQ_RSP_MAX_RQE_SHIFT;24582458+ srq_attr->srq_limit = rsp->srq_lmt_max_sge >>24592459+ OCRDMA_QUERY_SRQ_RSP_SRQ_LIMIT_SHIFT;24602460+ }24612461+ kfree(cmd);24622462+ return status;24632463+}24642464+24652465+int ocrdma_mbx_destroy_srq(struct ocrdma_dev *dev, struct ocrdma_srq *srq)24662466+{24672467+ int status = -ENOMEM;24682468+ struct ocrdma_destroy_srq *cmd;24692469+ struct pci_dev *pdev = dev->nic_info.pdev;24702470+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DELETE_SRQ, sizeof(*cmd));24712471+ if (!cmd)24722472+ return status;24732473+ cmd->id = srq->id;24742474+ status = ocrdma_mbx_cmd(srq->dev, (struct ocrdma_mqe *)cmd);24752475+ if (srq->rq.va)24762476+ dma_free_coherent(&pdev->dev, srq->rq.len,24772477+ srq->rq.va, srq->rq.pa);24782478+ kfree(cmd);24792479+ return status;24802480+}24812481+24822482+int ocrdma_alloc_av(struct ocrdma_dev *dev, struct ocrdma_ah *ah)24832483+{24842484+ int i;24852485+ int status = -EINVAL;24862486+ struct ocrdma_av *av;24872487+ unsigned long flags;24882488+24892489+ av = dev->av_tbl.va;24902490+ spin_lock_irqsave(&dev->av_tbl.lock, flags);24912491+ for (i = 0; i < dev->av_tbl.num_ah; i++) {24922492+ if (av->valid == 0) {24932493+ av->valid = OCRDMA_AV_VALID;24942494+ ah->av = av;24952495+ ah->id = i;24962496+ status = 0;24972497+ break;24982498+ }24992499+ av++;25002500+ }25012501+ if (i == dev->av_tbl.num_ah)25022502+ status = -EAGAIN;25032503+ spin_unlock_irqrestore(&dev->av_tbl.lock, flags);25042504+ return status;25052505+}25062506+25072507+int ocrdma_free_av(struct ocrdma_dev *dev, struct ocrdma_ah *ah)25082508+{25092509+ unsigned long flags;25102510+ spin_lock_irqsave(&dev->av_tbl.lock, flags);25112511+ ah->av->valid = 0;25122512+ spin_unlock_irqrestore(&dev->av_tbl.lock, flags);25132513+ return 0;25142514+}25152515+25162516+static int ocrdma_create_mq_eq(struct ocrdma_dev *dev)25172517+{25182518+ int status;25192519+ int irq;25202520+ unsigned long flags = 0;25212521+ int num_eq = 0;25222522+25232523+ if (dev->nic_info.intr_mode == BE_INTERRUPT_MODE_INTX)25242524+ flags = IRQF_SHARED;25252525+ else {25262526+ num_eq = dev->nic_info.msix.num_vectors -25272527+ dev->nic_info.msix.start_vector;25282528+ /* minimum two vectors/eq are required for rdma to work.25292529+ * one for control path and one for data path.25302530+ */25312531+ if (num_eq < 2)25322532+ return -EBUSY;25332533+ }25342534+25352535+ status = ocrdma_create_eq(dev, &dev->meq, OCRDMA_EQ_LEN);25362536+ if (status)25372537+ return status;25382538+ sprintf(dev->meq.irq_name, "ocrdma_mq%d", dev->id);25392539+ irq = ocrdma_get_irq(dev, &dev->meq);25402540+ status = request_irq(irq, ocrdma_irq_handler, flags, dev->meq.irq_name,25412541+ &dev->meq);25422542+ if (status)25432543+ _ocrdma_destroy_eq(dev, &dev->meq);25442544+ return status;25452545+}25462546+25472547+static int ocrdma_create_qp_eqs(struct ocrdma_dev *dev)25482548+{25492549+ int num_eq, i, status = 0;25502550+ int irq;25512551+ unsigned long flags = 0;25522552+25532553+ num_eq = dev->nic_info.msix.num_vectors -25542554+ dev->nic_info.msix.start_vector;25552555+ if (dev->nic_info.intr_mode == BE_INTERRUPT_MODE_INTX) {25562556+ num_eq = 1;25572557+ flags = IRQF_SHARED;25582558+ } else25592559+ num_eq = min_t(u32, num_eq, num_online_cpus());25602560+ dev->qp_eq_tbl = kzalloc(sizeof(struct ocrdma_eq) * num_eq, GFP_KERNEL);25612561+ if (!dev->qp_eq_tbl)25622562+ return -ENOMEM;25632563+25642564+ for (i = 0; i < num_eq; i++) {25652565+ status = ocrdma_create_eq(dev, &dev->qp_eq_tbl[i],25662566+ OCRDMA_EQ_LEN);25672567+ if (status) {25682568+ status = -EINVAL;25692569+ break;25702570+ }25712571+ sprintf(dev->qp_eq_tbl[i].irq_name, "ocrdma_qp%d-%d",25722572+ dev->id, i);25732573+ irq = ocrdma_get_irq(dev, &dev->qp_eq_tbl[i]);25742574+ status = request_irq(irq, ocrdma_irq_handler, flags,25752575+ dev->qp_eq_tbl[i].irq_name,25762576+ &dev->qp_eq_tbl[i]);25772577+ if (status) {25782578+ _ocrdma_destroy_eq(dev, &dev->qp_eq_tbl[i]);25792579+ status = -EINVAL;25802580+ break;25812581+ }25822582+ dev->eq_cnt += 1;25832583+ }25842584+ /* one eq is sufficient for data path to work */25852585+ if (dev->eq_cnt >= 1)25862586+ return 0;25872587+ if (status)25882588+ ocrdma_destroy_qp_eqs(dev);25892589+ return status;25902590+}25912591+25922592+int ocrdma_init_hw(struct ocrdma_dev *dev)25932593+{25942594+ int status;25952595+ /* set up control path eq */25962596+ status = ocrdma_create_mq_eq(dev);25972597+ if (status)25982598+ return status;25992599+ /* set up data path eq */26002600+ status = ocrdma_create_qp_eqs(dev);26012601+ if (status)26022602+ goto qpeq_err;26032603+ status = ocrdma_create_mq(dev);26042604+ if (status)26052605+ goto mq_err;26062606+ status = ocrdma_mbx_query_fw_config(dev);26072607+ if (status)26082608+ goto conf_err;26092609+ status = ocrdma_mbx_query_dev(dev);26102610+ if (status)26112611+ goto conf_err;26122612+ status = ocrdma_mbx_query_fw_ver(dev);26132613+ if (status)26142614+ goto conf_err;26152615+ status = ocrdma_mbx_create_ah_tbl(dev);26162616+ if (status)26172617+ goto conf_err;26182618+ return 0;26192619+26202620+conf_err:26212621+ ocrdma_destroy_mq(dev);26222622+mq_err:26232623+ ocrdma_destroy_qp_eqs(dev);26242624+qpeq_err:26252625+ ocrdma_destroy_eq(dev, &dev->meq);26262626+ ocrdma_err("%s() status=%d\n", __func__, status);26272627+ return status;26282628+}26292629+26302630+void ocrdma_cleanup_hw(struct ocrdma_dev *dev)26312631+{26322632+ ocrdma_mbx_delete_ah_tbl(dev);26332633+26342634+ /* cleanup the data path eqs */26352635+ ocrdma_destroy_qp_eqs(dev);26362636+26372637+ /* cleanup the control path */26382638+ ocrdma_destroy_mq(dev);26392639+ ocrdma_destroy_eq(dev, &dev->meq);26402640+}
+132
drivers/infiniband/hw/ocrdma/ocrdma_hw.h
···11+/*******************************************************************22+ * This file is part of the Emulex RoCE Device Driver for *33+ * RoCE (RDMA over Converged Ethernet) CNA Adapters. *44+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *55+ * EMULEX and SLI are trademarks of Emulex. *66+ * www.emulex.com *77+ * *88+ * This program is free software; you can redistribute it and/or *99+ * modify it under the terms of version 2 of the GNU General *1010+ * Public License as published by the Free Software Foundation. *1111+ * This program is distributed in the hope that it will be useful. *1212+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *1313+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *1414+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *1515+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *1616+ * TO BE LEGALLY INVALID. See the GNU General Public License for *1717+ * more details, a copy of which can be found in the file COPYING *1818+ * included with this package. *1919+ *2020+ * Contact Information:2121+ * linux-drivers@emulex.com2222+ *2323+ * Emulex2424+ * 3333 Susan Street2525+ * Costa Mesa, CA 926262626+ *******************************************************************/2727+2828+#ifndef __OCRDMA_HW_H__2929+#define __OCRDMA_HW_H__3030+3131+#include "ocrdma_sli.h"3232+3333+static inline void ocrdma_cpu_to_le32(void *dst, u32 len)3434+{3535+#ifdef __BIG_ENDIAN3636+ int i = 0;3737+ u32 *src_ptr = dst;3838+ u32 *dst_ptr = dst;3939+ for (; i < (len / 4); i++)4040+ *(dst_ptr + i) = cpu_to_le32p(src_ptr + i);4141+#endif4242+}4343+4444+static inline void ocrdma_le32_to_cpu(void *dst, u32 len)4545+{4646+#ifdef __BIG_ENDIAN4747+ int i = 0;4848+ u32 *src_ptr = dst;4949+ u32 *dst_ptr = dst;5050+ for (; i < (len / sizeof(u32)); i++)5151+ *(dst_ptr + i) = le32_to_cpu(*(src_ptr + i));5252+#endif5353+}5454+5555+static inline void ocrdma_copy_cpu_to_le32(void *dst, void *src, u32 len)5656+{5757+#ifdef __BIG_ENDIAN5858+ int i = 0;5959+ u32 *src_ptr = src;6060+ u32 *dst_ptr = dst;6161+ for (; i < (len / sizeof(u32)); i++)6262+ *(dst_ptr + i) = cpu_to_le32p(src_ptr + i);6363+#else6464+ memcpy(dst, src, len);6565+#endif6666+}6767+6868+static inline void ocrdma_copy_le32_to_cpu(void *dst, void *src, u32 len)6969+{7070+#ifdef __BIG_ENDIAN7171+ int i = 0;7272+ u32 *src_ptr = src;7373+ u32 *dst_ptr = dst;7474+ for (; i < len / sizeof(u32); i++)7575+ *(dst_ptr + i) = le32_to_cpu(*(src_ptr + i));7676+#else7777+ memcpy(dst, src, len);7878+#endif7979+}8080+8181+int ocrdma_init_hw(struct ocrdma_dev *);8282+void ocrdma_cleanup_hw(struct ocrdma_dev *);8383+8484+enum ib_qp_state get_ibqp_state(enum ocrdma_qp_state qps);8585+void ocrdma_ring_cq_db(struct ocrdma_dev *, u16 cq_id, bool armed,8686+ bool solicited, u16 cqe_popped);8787+8888+/* verbs specific mailbox commands */8989+int ocrdma_query_config(struct ocrdma_dev *,9090+ struct ocrdma_mbx_query_config *config);9191+int ocrdma_resolve_dgid(struct ocrdma_dev *, union ib_gid *dgid, u8 *mac_addr);9292+9393+int ocrdma_mbx_alloc_pd(struct ocrdma_dev *, struct ocrdma_pd *);9494+int ocrdma_mbx_dealloc_pd(struct ocrdma_dev *, struct ocrdma_pd *);9595+9696+int ocrdma_mbx_alloc_lkey(struct ocrdma_dev *, struct ocrdma_hw_mr *hwmr,9797+ u32 pd_id, int addr_check);9898+int ocrdma_mbx_dealloc_lkey(struct ocrdma_dev *, int fmr, u32 lkey);9999+100100+int ocrdma_reg_mr(struct ocrdma_dev *, struct ocrdma_hw_mr *hwmr,101101+ u32 pd_id, int acc);102102+int ocrdma_mbx_create_cq(struct ocrdma_dev *, struct ocrdma_cq *,103103+ int entries, int dpp_cq);104104+int ocrdma_mbx_destroy_cq(struct ocrdma_dev *, struct ocrdma_cq *);105105+106106+int ocrdma_mbx_create_qp(struct ocrdma_qp *, struct ib_qp_init_attr *attrs,107107+ u8 enable_dpp_cq, u16 dpp_cq_id, u16 *dpp_offset,108108+ u16 *dpp_credit_lmt);109109+int ocrdma_mbx_modify_qp(struct ocrdma_dev *, struct ocrdma_qp *,110110+ struct ib_qp_attr *attrs, int attr_mask,111111+ enum ib_qp_state old_qps);112112+int ocrdma_mbx_query_qp(struct ocrdma_dev *, struct ocrdma_qp *,113113+ struct ocrdma_qp_params *param);114114+int ocrdma_mbx_destroy_qp(struct ocrdma_dev *, struct ocrdma_qp *);115115+116116+int ocrdma_mbx_create_srq(struct ocrdma_srq *,117117+ struct ib_srq_init_attr *,118118+ struct ocrdma_pd *);119119+int ocrdma_mbx_modify_srq(struct ocrdma_srq *, struct ib_srq_attr *);120120+int ocrdma_mbx_query_srq(struct ocrdma_srq *, struct ib_srq_attr *);121121+int ocrdma_mbx_destroy_srq(struct ocrdma_dev *, struct ocrdma_srq *);122122+123123+int ocrdma_alloc_av(struct ocrdma_dev *, struct ocrdma_ah *);124124+int ocrdma_free_av(struct ocrdma_dev *, struct ocrdma_ah *);125125+126126+int ocrdma_qp_state_machine(struct ocrdma_qp *, enum ib_qp_state new_state,127127+ enum ib_qp_state *old_ib_state);128128+bool ocrdma_is_qp_in_sq_flushlist(struct ocrdma_cq *, struct ocrdma_qp *);129129+bool ocrdma_is_qp_in_rq_flushlist(struct ocrdma_cq *, struct ocrdma_qp *);130130+void ocrdma_flush_qp(struct ocrdma_qp *);131131+132132+#endif /* __OCRDMA_HW_H__ */
+577
drivers/infiniband/hw/ocrdma/ocrdma_main.c
···11+/*******************************************************************22+ * This file is part of the Emulex RoCE Device Driver for *33+ * RoCE (RDMA over Converged Ethernet) adapters. *44+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *55+ * EMULEX and SLI are trademarks of Emulex. *66+ * www.emulex.com *77+ * *88+ * This program is free software; you can redistribute it and/or *99+ * modify it under the terms of version 2 of the GNU General *1010+ * Public License as published by the Free Software Foundation. *1111+ * This program is distributed in the hope that it will be useful. *1212+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *1313+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *1414+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *1515+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *1616+ * TO BE LEGALLY INVALID. See the GNU General Public License for *1717+ * more details, a copy of which can be found in the file COPYING *1818+ * included with this package. *1919+ *2020+ * Contact Information:2121+ * linux-drivers@emulex.com2222+ *2323+ * Emulex2424+ * 3333 Susan Street2525+ * Costa Mesa, CA 926262626+ *******************************************************************/2727+2828+#include <linux/module.h>2929+#include <linux/version.h>3030+#include <linux/idr.h>3131+#include <rdma/ib_verbs.h>3232+#include <rdma/ib_user_verbs.h>3333+#include <rdma/ib_addr.h>3434+3535+#include <linux/netdevice.h>3636+#include <net/addrconf.h>3737+3838+#include "ocrdma.h"3939+#include "ocrdma_verbs.h"4040+#include "ocrdma_ah.h"4141+#include "be_roce.h"4242+#include "ocrdma_hw.h"4343+4444+MODULE_VERSION(OCRDMA_ROCE_DEV_VERSION);4545+MODULE_DESCRIPTION("Emulex RoCE HCA Driver");4646+MODULE_AUTHOR("Emulex Corporation");4747+MODULE_LICENSE("GPL");4848+4949+static LIST_HEAD(ocrdma_dev_list);5050+static DEFINE_SPINLOCK(ocrdma_devlist_lock);5151+static DEFINE_IDR(ocrdma_dev_id);5252+5353+static union ib_gid ocrdma_zero_sgid;5454+5555+static int ocrdma_get_instance(void)5656+{5757+ int instance = 0;5858+5959+ /* Assign an unused number */6060+ if (!idr_pre_get(&ocrdma_dev_id, GFP_KERNEL))6161+ return -1;6262+ if (idr_get_new(&ocrdma_dev_id, NULL, &instance))6363+ return -1;6464+ return instance;6565+}6666+6767+void ocrdma_get_guid(struct ocrdma_dev *dev, u8 *guid)6868+{6969+ u8 mac_addr[6];7070+7171+ memcpy(&mac_addr[0], &dev->nic_info.mac_addr[0], ETH_ALEN);7272+ guid[0] = mac_addr[0] ^ 2;7373+ guid[1] = mac_addr[1];7474+ guid[2] = mac_addr[2];7575+ guid[3] = 0xff;7676+ guid[4] = 0xfe;7777+ guid[5] = mac_addr[3];7878+ guid[6] = mac_addr[4];7979+ guid[7] = mac_addr[5];8080+}8181+8282+static void ocrdma_build_sgid_mac(union ib_gid *sgid, unsigned char *mac_addr,8383+ bool is_vlan, u16 vlan_id)8484+{8585+ sgid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);8686+ sgid->raw[8] = mac_addr[0] ^ 2;8787+ sgid->raw[9] = mac_addr[1];8888+ sgid->raw[10] = mac_addr[2];8989+ if (is_vlan) {9090+ sgid->raw[11] = vlan_id >> 8;9191+ sgid->raw[12] = vlan_id & 0xff;9292+ } else {9393+ sgid->raw[11] = 0xff;9494+ sgid->raw[12] = 0xfe;9595+ }9696+ sgid->raw[13] = mac_addr[3];9797+ sgid->raw[14] = mac_addr[4];9898+ sgid->raw[15] = mac_addr[5];9999+}100100+101101+static void ocrdma_add_sgid(struct ocrdma_dev *dev, unsigned char *mac_addr,102102+ bool is_vlan, u16 vlan_id)103103+{104104+ int i;105105+ bool found = false;106106+ union ib_gid new_sgid;107107+ int free_idx = OCRDMA_MAX_SGID;108108+ unsigned long flags;109109+110110+ memset(&ocrdma_zero_sgid, 0, sizeof(union ib_gid));111111+112112+ ocrdma_build_sgid_mac(&new_sgid, mac_addr, is_vlan, vlan_id);113113+114114+ spin_lock_irqsave(&dev->sgid_lock, flags);115115+ for (i = 0; i < OCRDMA_MAX_SGID; i++) {116116+ if (!memcmp(&dev->sgid_tbl[i], &ocrdma_zero_sgid,117117+ sizeof(union ib_gid))) {118118+ /* found free entry */119119+ if (!found) {120120+ free_idx = i;121121+ found = true;122122+ break;123123+ }124124+ } else if (!memcmp(&dev->sgid_tbl[i], &new_sgid,125125+ sizeof(union ib_gid))) {126126+ /* entry already present, no addition is required. */127127+ spin_unlock_irqrestore(&dev->sgid_lock, flags);128128+ return;129129+ }130130+ }131131+ /* if entry doesn't exist and if table has some space, add entry */132132+ if (found)133133+ memcpy(&dev->sgid_tbl[free_idx], &new_sgid,134134+ sizeof(union ib_gid));135135+ spin_unlock_irqrestore(&dev->sgid_lock, flags);136136+}137137+138138+static bool ocrdma_del_sgid(struct ocrdma_dev *dev, unsigned char *mac_addr,139139+ bool is_vlan, u16 vlan_id)140140+{141141+ int found = false;142142+ int i;143143+ union ib_gid sgid;144144+ unsigned long flags;145145+146146+ ocrdma_build_sgid_mac(&sgid, mac_addr, is_vlan, vlan_id);147147+148148+ spin_lock_irqsave(&dev->sgid_lock, flags);149149+ /* first is default sgid, which cannot be deleted. */150150+ for (i = 1; i < OCRDMA_MAX_SGID; i++) {151151+ if (!memcmp(&dev->sgid_tbl[i], &sgid, sizeof(union ib_gid))) {152152+ /* found matching entry */153153+ memset(&dev->sgid_tbl[i], 0, sizeof(union ib_gid));154154+ found = true;155155+ break;156156+ }157157+ }158158+ spin_unlock_irqrestore(&dev->sgid_lock, flags);159159+ return found;160160+}161161+162162+static void ocrdma_add_default_sgid(struct ocrdma_dev *dev)163163+{164164+ /* GID Index 0 - Invariant manufacturer-assigned EUI-64 */165165+ union ib_gid *sgid = &dev->sgid_tbl[0];166166+167167+ sgid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);168168+ ocrdma_get_guid(dev, &sgid->raw[8]);169169+}170170+171171+static int ocrdma_build_sgid_tbl(struct ocrdma_dev *dev)172172+{173173+ struct net_device *netdev, *tmp;174174+ u16 vlan_id;175175+ bool is_vlan;176176+177177+ netdev = dev->nic_info.netdev;178178+179179+ ocrdma_add_default_sgid(dev);180180+181181+ rcu_read_lock();182182+ for_each_netdev_rcu(&init_net, tmp) {183183+ if (netdev == tmp || vlan_dev_real_dev(tmp) == netdev) {184184+ if (!netif_running(tmp) || !netif_oper_up(tmp))185185+ continue;186186+ if (netdev != tmp) {187187+ vlan_id = vlan_dev_vlan_id(tmp);188188+ is_vlan = true;189189+ } else {190190+ is_vlan = false;191191+ vlan_id = 0;192192+ tmp = netdev;193193+ }194194+ ocrdma_add_sgid(dev, tmp->dev_addr, is_vlan, vlan_id);195195+ }196196+ }197197+ rcu_read_unlock();198198+ return 0;199199+}200200+201201+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)202202+203203+static int ocrdma_inet6addr_event(struct notifier_block *notifier,204204+ unsigned long event, void *ptr)205205+{206206+ struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;207207+ struct net_device *event_netdev = ifa->idev->dev;208208+ struct net_device *netdev = NULL;209209+ struct ib_event gid_event;210210+ struct ocrdma_dev *dev;211211+ bool found = false;212212+ bool is_vlan = false;213213+ u16 vid = 0;214214+215215+ netdev = vlan_dev_real_dev(event_netdev);216216+ if (netdev != event_netdev) {217217+ is_vlan = true;218218+ vid = vlan_dev_vlan_id(event_netdev);219219+ }220220+ rcu_read_lock();221221+ list_for_each_entry_rcu(dev, &ocrdma_dev_list, entry) {222222+ if (dev->nic_info.netdev == netdev) {223223+ found = true;224224+ break;225225+ }226226+ }227227+ rcu_read_unlock();228228+229229+ if (!found)230230+ return NOTIFY_DONE;231231+ if (!rdma_link_local_addr((struct in6_addr *)&ifa->addr))232232+ return NOTIFY_DONE;233233+234234+ mutex_lock(&dev->dev_lock);235235+ switch (event) {236236+ case NETDEV_UP:237237+ ocrdma_add_sgid(dev, netdev->dev_addr, is_vlan, vid);238238+ break;239239+ case NETDEV_DOWN:240240+ found = ocrdma_del_sgid(dev, netdev->dev_addr, is_vlan, vid);241241+ if (found) {242242+ /* found the matching entry, notify243243+ * the consumers about it244244+ */245245+ gid_event.device = &dev->ibdev;246246+ gid_event.element.port_num = 1;247247+ gid_event.event = IB_EVENT_GID_CHANGE;248248+ ib_dispatch_event(&gid_event);249249+ }250250+ break;251251+ default:252252+ break;253253+ }254254+ mutex_unlock(&dev->dev_lock);255255+ return NOTIFY_OK;256256+}257257+258258+static struct notifier_block ocrdma_inet6addr_notifier = {259259+ .notifier_call = ocrdma_inet6addr_event260260+};261261+262262+#endif /* IPV6 */263263+264264+static enum rdma_link_layer ocrdma_link_layer(struct ib_device *device,265265+ u8 port_num)266266+{267267+ return IB_LINK_LAYER_ETHERNET;268268+}269269+270270+static int ocrdma_register_device(struct ocrdma_dev *dev)271271+{272272+ strlcpy(dev->ibdev.name, "ocrdma%d", IB_DEVICE_NAME_MAX);273273+ ocrdma_get_guid(dev, (u8 *)&dev->ibdev.node_guid);274274+ memcpy(dev->ibdev.node_desc, OCRDMA_NODE_DESC,275275+ sizeof(OCRDMA_NODE_DESC));276276+ dev->ibdev.owner = THIS_MODULE;277277+ dev->ibdev.uverbs_cmd_mask =278278+ OCRDMA_UVERBS(GET_CONTEXT) |279279+ OCRDMA_UVERBS(QUERY_DEVICE) |280280+ OCRDMA_UVERBS(QUERY_PORT) |281281+ OCRDMA_UVERBS(ALLOC_PD) |282282+ OCRDMA_UVERBS(DEALLOC_PD) |283283+ OCRDMA_UVERBS(REG_MR) |284284+ OCRDMA_UVERBS(DEREG_MR) |285285+ OCRDMA_UVERBS(CREATE_COMP_CHANNEL) |286286+ OCRDMA_UVERBS(CREATE_CQ) |287287+ OCRDMA_UVERBS(RESIZE_CQ) |288288+ OCRDMA_UVERBS(DESTROY_CQ) |289289+ OCRDMA_UVERBS(REQ_NOTIFY_CQ) |290290+ OCRDMA_UVERBS(CREATE_QP) |291291+ OCRDMA_UVERBS(MODIFY_QP) |292292+ OCRDMA_UVERBS(QUERY_QP) |293293+ OCRDMA_UVERBS(DESTROY_QP) |294294+ OCRDMA_UVERBS(POLL_CQ) |295295+ OCRDMA_UVERBS(POST_SEND) |296296+ OCRDMA_UVERBS(POST_RECV);297297+298298+ dev->ibdev.uverbs_cmd_mask |=299299+ OCRDMA_UVERBS(CREATE_AH) |300300+ OCRDMA_UVERBS(MODIFY_AH) |301301+ OCRDMA_UVERBS(QUERY_AH) |302302+ OCRDMA_UVERBS(DESTROY_AH);303303+304304+ dev->ibdev.node_type = RDMA_NODE_IB_CA;305305+ dev->ibdev.phys_port_cnt = 1;306306+ dev->ibdev.num_comp_vectors = 1;307307+308308+ /* mandatory verbs. */309309+ dev->ibdev.query_device = ocrdma_query_device;310310+ dev->ibdev.query_port = ocrdma_query_port;311311+ dev->ibdev.modify_port = ocrdma_modify_port;312312+ dev->ibdev.query_gid = ocrdma_query_gid;313313+ dev->ibdev.get_link_layer = ocrdma_link_layer;314314+ dev->ibdev.alloc_pd = ocrdma_alloc_pd;315315+ dev->ibdev.dealloc_pd = ocrdma_dealloc_pd;316316+317317+ dev->ibdev.create_cq = ocrdma_create_cq;318318+ dev->ibdev.destroy_cq = ocrdma_destroy_cq;319319+ dev->ibdev.resize_cq = ocrdma_resize_cq;320320+321321+ dev->ibdev.create_qp = ocrdma_create_qp;322322+ dev->ibdev.modify_qp = ocrdma_modify_qp;323323+ dev->ibdev.query_qp = ocrdma_query_qp;324324+ dev->ibdev.destroy_qp = ocrdma_destroy_qp;325325+326326+ dev->ibdev.query_pkey = ocrdma_query_pkey;327327+ dev->ibdev.create_ah = ocrdma_create_ah;328328+ dev->ibdev.destroy_ah = ocrdma_destroy_ah;329329+ dev->ibdev.query_ah = ocrdma_query_ah;330330+ dev->ibdev.modify_ah = ocrdma_modify_ah;331331+332332+ dev->ibdev.poll_cq = ocrdma_poll_cq;333333+ dev->ibdev.post_send = ocrdma_post_send;334334+ dev->ibdev.post_recv = ocrdma_post_recv;335335+ dev->ibdev.req_notify_cq = ocrdma_arm_cq;336336+337337+ dev->ibdev.get_dma_mr = ocrdma_get_dma_mr;338338+ dev->ibdev.dereg_mr = ocrdma_dereg_mr;339339+ dev->ibdev.reg_user_mr = ocrdma_reg_user_mr;340340+341341+ /* mandatory to support user space verbs consumer. */342342+ dev->ibdev.alloc_ucontext = ocrdma_alloc_ucontext;343343+ dev->ibdev.dealloc_ucontext = ocrdma_dealloc_ucontext;344344+ dev->ibdev.mmap = ocrdma_mmap;345345+ dev->ibdev.dma_device = &dev->nic_info.pdev->dev;346346+347347+ dev->ibdev.process_mad = ocrdma_process_mad;348348+349349+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {350350+ dev->ibdev.uverbs_cmd_mask |=351351+ OCRDMA_UVERBS(CREATE_SRQ) |352352+ OCRDMA_UVERBS(MODIFY_SRQ) |353353+ OCRDMA_UVERBS(QUERY_SRQ) |354354+ OCRDMA_UVERBS(DESTROY_SRQ) |355355+ OCRDMA_UVERBS(POST_SRQ_RECV);356356+357357+ dev->ibdev.create_srq = ocrdma_create_srq;358358+ dev->ibdev.modify_srq = ocrdma_modify_srq;359359+ dev->ibdev.query_srq = ocrdma_query_srq;360360+ dev->ibdev.destroy_srq = ocrdma_destroy_srq;361361+ dev->ibdev.post_srq_recv = ocrdma_post_srq_recv;362362+ }363363+ return ib_register_device(&dev->ibdev, NULL);364364+}365365+366366+static int ocrdma_alloc_resources(struct ocrdma_dev *dev)367367+{368368+ mutex_init(&dev->dev_lock);369369+ dev->sgid_tbl = kzalloc(sizeof(union ib_gid) *370370+ OCRDMA_MAX_SGID, GFP_KERNEL);371371+ if (!dev->sgid_tbl)372372+ goto alloc_err;373373+ spin_lock_init(&dev->sgid_lock);374374+375375+ dev->cq_tbl = kzalloc(sizeof(struct ocrdma_cq *) *376376+ OCRDMA_MAX_CQ, GFP_KERNEL);377377+ if (!dev->cq_tbl)378378+ goto alloc_err;379379+380380+ if (dev->attr.max_qp) {381381+ dev->qp_tbl = kzalloc(sizeof(struct ocrdma_qp *) *382382+ OCRDMA_MAX_QP, GFP_KERNEL);383383+ if (!dev->qp_tbl)384384+ goto alloc_err;385385+ }386386+ spin_lock_init(&dev->av_tbl.lock);387387+ spin_lock_init(&dev->flush_q_lock);388388+ return 0;389389+alloc_err:390390+ ocrdma_err("%s(%d) error.\n", __func__, dev->id);391391+ return -ENOMEM;392392+}393393+394394+static void ocrdma_free_resources(struct ocrdma_dev *dev)395395+{396396+ kfree(dev->qp_tbl);397397+ kfree(dev->cq_tbl);398398+ kfree(dev->sgid_tbl);399399+}400400+401401+static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)402402+{403403+ int status = 0;404404+ struct ocrdma_dev *dev;405405+406406+ dev = (struct ocrdma_dev *)ib_alloc_device(sizeof(struct ocrdma_dev));407407+ if (!dev) {408408+ ocrdma_err("Unable to allocate ib device\n");409409+ return NULL;410410+ }411411+ dev->mbx_cmd = kzalloc(sizeof(struct ocrdma_mqe_emb_cmd), GFP_KERNEL);412412+ if (!dev->mbx_cmd)413413+ goto idr_err;414414+415415+ memcpy(&dev->nic_info, dev_info, sizeof(*dev_info));416416+ dev->id = ocrdma_get_instance();417417+ if (dev->id < 0)418418+ goto idr_err;419419+420420+ status = ocrdma_init_hw(dev);421421+ if (status)422422+ goto init_err;423423+424424+ status = ocrdma_alloc_resources(dev);425425+ if (status)426426+ goto alloc_err;427427+428428+ status = ocrdma_build_sgid_tbl(dev);429429+ if (status)430430+ goto alloc_err;431431+432432+ status = ocrdma_register_device(dev);433433+ if (status)434434+ goto alloc_err;435435+436436+ spin_lock(&ocrdma_devlist_lock);437437+ list_add_tail_rcu(&dev->entry, &ocrdma_dev_list);438438+ spin_unlock(&ocrdma_devlist_lock);439439+ return dev;440440+441441+alloc_err:442442+ ocrdma_free_resources(dev);443443+ ocrdma_cleanup_hw(dev);444444+init_err:445445+ idr_remove(&ocrdma_dev_id, dev->id);446446+idr_err:447447+ kfree(dev->mbx_cmd);448448+ ib_dealloc_device(&dev->ibdev);449449+ ocrdma_err("%s() leaving. ret=%d\n", __func__, status);450450+ return NULL;451451+}452452+453453+static void ocrdma_remove_free(struct rcu_head *rcu)454454+{455455+ struct ocrdma_dev *dev = container_of(rcu, struct ocrdma_dev, rcu);456456+457457+ ocrdma_free_resources(dev);458458+ ocrdma_cleanup_hw(dev);459459+460460+ idr_remove(&ocrdma_dev_id, dev->id);461461+ kfree(dev->mbx_cmd);462462+ ib_dealloc_device(&dev->ibdev);463463+}464464+465465+static void ocrdma_remove(struct ocrdma_dev *dev)466466+{467467+ /* first unregister with stack to stop all the active traffic468468+ * of the registered clients.469469+ */470470+ ib_unregister_device(&dev->ibdev);471471+472472+ spin_lock(&ocrdma_devlist_lock);473473+ list_del_rcu(&dev->entry);474474+ spin_unlock(&ocrdma_devlist_lock);475475+ call_rcu(&dev->rcu, ocrdma_remove_free);476476+}477477+478478+static int ocrdma_open(struct ocrdma_dev *dev)479479+{480480+ struct ib_event port_event;481481+482482+ port_event.event = IB_EVENT_PORT_ACTIVE;483483+ port_event.element.port_num = 1;484484+ port_event.device = &dev->ibdev;485485+ ib_dispatch_event(&port_event);486486+ return 0;487487+}488488+489489+static int ocrdma_close(struct ocrdma_dev *dev)490490+{491491+ int i;492492+ struct ocrdma_qp *qp, **cur_qp;493493+ struct ib_event err_event;494494+ struct ib_qp_attr attrs;495495+ int attr_mask = IB_QP_STATE;496496+497497+ attrs.qp_state = IB_QPS_ERR;498498+ mutex_lock(&dev->dev_lock);499499+ if (dev->qp_tbl) {500500+ cur_qp = dev->qp_tbl;501501+ for (i = 0; i < OCRDMA_MAX_QP; i++) {502502+ qp = cur_qp[i];503503+ if (qp) {504504+ /* change the QP state to ERROR */505505+ _ocrdma_modify_qp(&qp->ibqp, &attrs, attr_mask);506506+507507+ err_event.event = IB_EVENT_QP_FATAL;508508+ err_event.element.qp = &qp->ibqp;509509+ err_event.device = &dev->ibdev;510510+ ib_dispatch_event(&err_event);511511+ }512512+ }513513+ }514514+ mutex_unlock(&dev->dev_lock);515515+516516+ err_event.event = IB_EVENT_PORT_ERR;517517+ err_event.element.port_num = 1;518518+ err_event.device = &dev->ibdev;519519+ ib_dispatch_event(&err_event);520520+ return 0;521521+}522522+523523+/* event handling via NIC driver ensures that all the NIC specific524524+ * initialization done before RoCE driver notifies525525+ * event to stack.526526+ */527527+static void ocrdma_event_handler(struct ocrdma_dev *dev, u32 event)528528+{529529+ switch (event) {530530+ case BE_DEV_UP:531531+ ocrdma_open(dev);532532+ break;533533+ case BE_DEV_DOWN:534534+ ocrdma_close(dev);535535+ break;536536+ };537537+}538538+539539+static struct ocrdma_driver ocrdma_drv = {540540+ .name = "ocrdma_driver",541541+ .add = ocrdma_add,542542+ .remove = ocrdma_remove,543543+ .state_change_handler = ocrdma_event_handler,544544+};545545+546546+static void ocrdma_unregister_inet6addr_notifier(void)547547+{548548+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)549549+ unregister_inet6addr_notifier(&ocrdma_inet6addr_notifier);550550+#endif551551+}552552+553553+static int __init ocrdma_init_module(void)554554+{555555+ int status;556556+557557+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)558558+ status = register_inet6addr_notifier(&ocrdma_inet6addr_notifier);559559+ if (status)560560+ return status;561561+#endif562562+563563+ status = be_roce_register_driver(&ocrdma_drv);564564+ if (status)565565+ ocrdma_unregister_inet6addr_notifier();566566+567567+ return status;568568+}569569+570570+static void __exit ocrdma_exit_module(void)571571+{572572+ be_roce_unregister_driver(&ocrdma_drv);573573+ ocrdma_unregister_inet6addr_notifier();574574+}575575+576576+module_init(ocrdma_init_module);577577+module_exit(ocrdma_exit_module);
···11+/*******************************************************************22+ * This file is part of the Emulex RoCE Device Driver for *33+ * RoCE (RDMA over Converged Ethernet) adapters. *44+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *55+ * EMULEX and SLI are trademarks of Emulex. *66+ * www.emulex.com *77+ * *88+ * This program is free software; you can redistribute it and/or *99+ * modify it under the terms of version 2 of the GNU General *1010+ * Public License as published by the Free Software Foundation. *1111+ * This program is distributed in the hope that it will be useful. *1212+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *1313+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *1414+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *1515+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *1616+ * TO BE LEGALLY INVALID. See the GNU General Public License for *1717+ * more details, a copy of which can be found in the file COPYING *1818+ * included with this package. *1919+ *2020+ * Contact Information:2121+ * linux-drivers@emulex.com2222+ *2323+ * Emulex2424+ * 3333 Susan Street2525+ * Costa Mesa, CA 926262626+ *******************************************************************/2727+2828+#include <linux/dma-mapping.h>2929+#include <rdma/ib_verbs.h>3030+#include <rdma/ib_user_verbs.h>3131+#include <rdma/iw_cm.h>3232+#include <rdma/ib_umem.h>3333+#include <rdma/ib_addr.h>3434+3535+#include "ocrdma.h"3636+#include "ocrdma_hw.h"3737+#include "ocrdma_verbs.h"3838+#include "ocrdma_abi.h"3939+4040+int ocrdma_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)4141+{4242+ if (index > 1)4343+ return -EINVAL;4444+4545+ *pkey = 0xffff;4646+ return 0;4747+}4848+4949+int ocrdma_query_gid(struct ib_device *ibdev, u8 port,5050+ int index, union ib_gid *sgid)5151+{5252+ struct ocrdma_dev *dev;5353+5454+ dev = get_ocrdma_dev(ibdev);5555+ memset(sgid, 0, sizeof(*sgid));5656+ if (index > OCRDMA_MAX_SGID)5757+ return -EINVAL;5858+5959+ memcpy(sgid, &dev->sgid_tbl[index], sizeof(*sgid));6060+6161+ return 0;6262+}6363+6464+int ocrdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr)6565+{6666+ struct ocrdma_dev *dev = get_ocrdma_dev(ibdev);6767+6868+ memset(attr, 0, sizeof *attr);6969+ memcpy(&attr->fw_ver, &dev->attr.fw_ver[0],7070+ min(sizeof(dev->attr.fw_ver), sizeof(attr->fw_ver)));7171+ ocrdma_get_guid(dev, (u8 *)&attr->sys_image_guid);7272+ attr->max_mr_size = ~0ull;7373+ attr->page_size_cap = 0xffff000;7474+ attr->vendor_id = dev->nic_info.pdev->vendor;7575+ attr->vendor_part_id = dev->nic_info.pdev->device;7676+ attr->hw_ver = 0;7777+ attr->max_qp = dev->attr.max_qp;7878+ attr->max_ah = dev->attr.max_qp;7979+ attr->max_qp_wr = dev->attr.max_wqe;8080+8181+ attr->device_cap_flags = IB_DEVICE_CURR_QP_STATE_MOD |8282+ IB_DEVICE_RC_RNR_NAK_GEN |8383+ IB_DEVICE_SHUTDOWN_PORT |8484+ IB_DEVICE_SYS_IMAGE_GUID |8585+ IB_DEVICE_LOCAL_DMA_LKEY;8686+ attr->max_sge = dev->attr.max_send_sge;8787+ attr->max_sge_rd = dev->attr.max_send_sge;8888+ attr->max_cq = dev->attr.max_cq;8989+ attr->max_cqe = dev->attr.max_cqe;9090+ attr->max_mr = dev->attr.max_mr;9191+ attr->max_mw = 0;9292+ attr->max_pd = dev->attr.max_pd;9393+ attr->atomic_cap = 0;9494+ attr->max_fmr = 0;9595+ attr->max_map_per_fmr = 0;9696+ attr->max_qp_rd_atom =9797+ min(dev->attr.max_ord_per_qp, dev->attr.max_ird_per_qp);9898+ attr->max_qp_init_rd_atom = dev->attr.max_ord_per_qp;9999+ attr->max_srq = (dev->attr.max_qp - 1);100100+ attr->max_srq_sge = attr->max_sge;101101+ attr->max_srq_wr = dev->attr.max_rqe;102102+ attr->local_ca_ack_delay = dev->attr.local_ca_ack_delay;103103+ attr->max_fast_reg_page_list_len = 0;104104+ attr->max_pkeys = 1;105105+ return 0;106106+}107107+108108+int ocrdma_query_port(struct ib_device *ibdev,109109+ u8 port, struct ib_port_attr *props)110110+{111111+ enum ib_port_state port_state;112112+ struct ocrdma_dev *dev;113113+ struct net_device *netdev;114114+115115+ dev = get_ocrdma_dev(ibdev);116116+ if (port > 1) {117117+ ocrdma_err("%s(%d) invalid_port=0x%x\n", __func__,118118+ dev->id, port);119119+ return -EINVAL;120120+ }121121+ netdev = dev->nic_info.netdev;122122+ if (netif_running(netdev) && netif_oper_up(netdev)) {123123+ port_state = IB_PORT_ACTIVE;124124+ props->phys_state = 5;125125+ } else {126126+ port_state = IB_PORT_DOWN;127127+ props->phys_state = 3;128128+ }129129+ props->max_mtu = IB_MTU_4096;130130+ props->active_mtu = iboe_get_mtu(netdev->mtu);131131+ props->lid = 0;132132+ props->lmc = 0;133133+ props->sm_lid = 0;134134+ props->sm_sl = 0;135135+ props->state = port_state;136136+ props->port_cap_flags =137137+ IB_PORT_CM_SUP |138138+ IB_PORT_REINIT_SUP |139139+ IB_PORT_DEVICE_MGMT_SUP | IB_PORT_VENDOR_CLASS_SUP;140140+ props->gid_tbl_len = OCRDMA_MAX_SGID;141141+ props->pkey_tbl_len = 1;142142+ props->bad_pkey_cntr = 0;143143+ props->qkey_viol_cntr = 0;144144+ props->active_width = IB_WIDTH_1X;145145+ props->active_speed = 4;146146+ props->max_msg_sz = 0x80000000;147147+ props->max_vl_num = 4;148148+ return 0;149149+}150150+151151+int ocrdma_modify_port(struct ib_device *ibdev, u8 port, int mask,152152+ struct ib_port_modify *props)153153+{154154+ struct ocrdma_dev *dev;155155+156156+ dev = get_ocrdma_dev(ibdev);157157+ if (port > 1) {158158+ ocrdma_err("%s(%d) invalid_port=0x%x\n", __func__,159159+ dev->id, port);160160+ return -EINVAL;161161+ }162162+ return 0;163163+}164164+165165+static int ocrdma_add_mmap(struct ocrdma_ucontext *uctx, u64 phy_addr,166166+ unsigned long len)167167+{168168+ struct ocrdma_mm *mm;169169+170170+ mm = kzalloc(sizeof(*mm), GFP_KERNEL);171171+ if (mm == NULL)172172+ return -ENOMEM;173173+ mm->key.phy_addr = phy_addr;174174+ mm->key.len = len;175175+ INIT_LIST_HEAD(&mm->entry);176176+177177+ mutex_lock(&uctx->mm_list_lock);178178+ list_add_tail(&mm->entry, &uctx->mm_head);179179+ mutex_unlock(&uctx->mm_list_lock);180180+ return 0;181181+}182182+183183+static void ocrdma_del_mmap(struct ocrdma_ucontext *uctx, u64 phy_addr,184184+ unsigned long len)185185+{186186+ struct ocrdma_mm *mm, *tmp;187187+188188+ mutex_lock(&uctx->mm_list_lock);189189+ list_for_each_entry_safe(mm, tmp, &uctx->mm_head, entry) {190190+ if (len != mm->key.len || phy_addr != mm->key.phy_addr)191191+ continue;192192+193193+ list_del(&mm->entry);194194+ kfree(mm);195195+ break;196196+ }197197+ mutex_unlock(&uctx->mm_list_lock);198198+}199199+200200+static bool ocrdma_search_mmap(struct ocrdma_ucontext *uctx, u64 phy_addr,201201+ unsigned long len)202202+{203203+ bool found = false;204204+ struct ocrdma_mm *mm;205205+206206+ mutex_lock(&uctx->mm_list_lock);207207+ list_for_each_entry(mm, &uctx->mm_head, entry) {208208+ if (len != mm->key.len || phy_addr != mm->key.phy_addr)209209+ continue;210210+211211+ found = true;212212+ break;213213+ }214214+ mutex_unlock(&uctx->mm_list_lock);215215+ return found;216216+}217217+218218+struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *ibdev,219219+ struct ib_udata *udata)220220+{221221+ int status;222222+ struct ocrdma_ucontext *ctx;223223+ struct ocrdma_alloc_ucontext_resp resp;224224+ struct ocrdma_dev *dev = get_ocrdma_dev(ibdev);225225+ struct pci_dev *pdev = dev->nic_info.pdev;226226+ u32 map_len = roundup(sizeof(u32) * 2048, PAGE_SIZE);227227+228228+ if (!udata)229229+ return ERR_PTR(-EFAULT);230230+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);231231+ if (!ctx)232232+ return ERR_PTR(-ENOMEM);233233+ ctx->dev = dev;234234+ INIT_LIST_HEAD(&ctx->mm_head);235235+ mutex_init(&ctx->mm_list_lock);236236+237237+ ctx->ah_tbl.va = dma_alloc_coherent(&pdev->dev, map_len,238238+ &ctx->ah_tbl.pa, GFP_KERNEL);239239+ if (!ctx->ah_tbl.va) {240240+ kfree(ctx);241241+ return ERR_PTR(-ENOMEM);242242+ }243243+ memset(ctx->ah_tbl.va, 0, map_len);244244+ ctx->ah_tbl.len = map_len;245245+246246+ resp.ah_tbl_len = ctx->ah_tbl.len;247247+ resp.ah_tbl_page = ctx->ah_tbl.pa;248248+249249+ status = ocrdma_add_mmap(ctx, resp.ah_tbl_page, resp.ah_tbl_len);250250+ if (status)251251+ goto map_err;252252+ resp.dev_id = dev->id;253253+ resp.max_inline_data = dev->attr.max_inline_data;254254+ resp.wqe_size = dev->attr.wqe_size;255255+ resp.rqe_size = dev->attr.rqe_size;256256+ resp.dpp_wqe_size = dev->attr.wqe_size;257257+ resp.rsvd = 0;258258+259259+ memcpy(resp.fw_ver, dev->attr.fw_ver, sizeof(resp.fw_ver));260260+ status = ib_copy_to_udata(udata, &resp, sizeof(resp));261261+ if (status)262262+ goto cpy_err;263263+ return &ctx->ibucontext;264264+265265+cpy_err:266266+ ocrdma_del_mmap(ctx, ctx->ah_tbl.pa, ctx->ah_tbl.len);267267+map_err:268268+ dma_free_coherent(&pdev->dev, ctx->ah_tbl.len, ctx->ah_tbl.va,269269+ ctx->ah_tbl.pa);270270+ kfree(ctx);271271+ return ERR_PTR(status);272272+}273273+274274+int ocrdma_dealloc_ucontext(struct ib_ucontext *ibctx)275275+{276276+ struct ocrdma_mm *mm, *tmp;277277+ struct ocrdma_ucontext *uctx = get_ocrdma_ucontext(ibctx);278278+ struct pci_dev *pdev = uctx->dev->nic_info.pdev;279279+280280+ ocrdma_del_mmap(uctx, uctx->ah_tbl.pa, uctx->ah_tbl.len);281281+ dma_free_coherent(&pdev->dev, uctx->ah_tbl.len, uctx->ah_tbl.va,282282+ uctx->ah_tbl.pa);283283+284284+ list_for_each_entry_safe(mm, tmp, &uctx->mm_head, entry) {285285+ list_del(&mm->entry);286286+ kfree(mm);287287+ }288288+ kfree(uctx);289289+ return 0;290290+}291291+292292+int ocrdma_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)293293+{294294+ struct ocrdma_ucontext *ucontext = get_ocrdma_ucontext(context);295295+ struct ocrdma_dev *dev = ucontext->dev;296296+ unsigned long vm_page = vma->vm_pgoff << PAGE_SHIFT;297297+ u64 unmapped_db = (u64) dev->nic_info.unmapped_db;298298+ unsigned long len = (vma->vm_end - vma->vm_start);299299+ int status = 0;300300+ bool found;301301+302302+ if (vma->vm_start & (PAGE_SIZE - 1))303303+ return -EINVAL;304304+ found = ocrdma_search_mmap(ucontext, vma->vm_pgoff << PAGE_SHIFT, len);305305+ if (!found)306306+ return -EINVAL;307307+308308+ if ((vm_page >= unmapped_db) && (vm_page <= (unmapped_db +309309+ dev->nic_info.db_total_size)) &&310310+ (len <= dev->nic_info.db_page_size)) {311311+ /* doorbell mapping */312312+ status = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,313313+ len, vma->vm_page_prot);314314+ } else if (dev->nic_info.dpp_unmapped_len &&315315+ (vm_page >= (u64) dev->nic_info.dpp_unmapped_addr) &&316316+ (vm_page <= (u64) (dev->nic_info.dpp_unmapped_addr +317317+ dev->nic_info.dpp_unmapped_len)) &&318318+ (len <= dev->nic_info.dpp_unmapped_len)) {319319+ /* dpp area mapping */320320+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);321321+ status = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,322322+ len, vma->vm_page_prot);323323+ } else {324324+ /* queue memory mapping */325325+ status = remap_pfn_range(vma, vma->vm_start,326326+ vma->vm_pgoff, len, vma->vm_page_prot);327327+ }328328+ return status;329329+}330330+331331+static int ocrdma_copy_pd_uresp(struct ocrdma_pd *pd,332332+ struct ib_ucontext *ib_ctx,333333+ struct ib_udata *udata)334334+{335335+ int status;336336+ u64 db_page_addr;337337+ u64 dpp_page_addr = 0;338338+ u32 db_page_size;339339+ struct ocrdma_alloc_pd_uresp rsp;340340+ struct ocrdma_ucontext *uctx = get_ocrdma_ucontext(ib_ctx);341341+342342+ rsp.id = pd->id;343343+ rsp.dpp_enabled = pd->dpp_enabled;344344+ db_page_addr = pd->dev->nic_info.unmapped_db +345345+ (pd->id * pd->dev->nic_info.db_page_size);346346+ db_page_size = pd->dev->nic_info.db_page_size;347347+348348+ status = ocrdma_add_mmap(uctx, db_page_addr, db_page_size);349349+ if (status)350350+ return status;351351+352352+ if (pd->dpp_enabled) {353353+ dpp_page_addr = pd->dev->nic_info.dpp_unmapped_addr +354354+ (pd->id * OCRDMA_DPP_PAGE_SIZE);355355+ status = ocrdma_add_mmap(uctx, dpp_page_addr,356356+ OCRDMA_DPP_PAGE_SIZE);357357+ if (status)358358+ goto dpp_map_err;359359+ rsp.dpp_page_addr_hi = upper_32_bits(dpp_page_addr);360360+ rsp.dpp_page_addr_lo = dpp_page_addr;361361+ }362362+363363+ status = ib_copy_to_udata(udata, &rsp, sizeof(rsp));364364+ if (status)365365+ goto ucopy_err;366366+367367+ pd->uctx = uctx;368368+ return 0;369369+370370+ucopy_err:371371+ if (pd->dpp_enabled)372372+ ocrdma_del_mmap(pd->uctx, dpp_page_addr, OCRDMA_DPP_PAGE_SIZE);373373+dpp_map_err:374374+ ocrdma_del_mmap(pd->uctx, db_page_addr, db_page_size);375375+ return status;376376+}377377+378378+struct ib_pd *ocrdma_alloc_pd(struct ib_device *ibdev,379379+ struct ib_ucontext *context,380380+ struct ib_udata *udata)381381+{382382+ struct ocrdma_dev *dev = get_ocrdma_dev(ibdev);383383+ struct ocrdma_pd *pd;384384+ int status;385385+386386+ pd = kzalloc(sizeof(*pd), GFP_KERNEL);387387+ if (!pd)388388+ return ERR_PTR(-ENOMEM);389389+ pd->dev = dev;390390+ if (udata && context) {391391+ pd->dpp_enabled = (dev->nic_info.dev_family ==392392+ OCRDMA_GEN2_FAMILY) ? true : false;393393+ pd->num_dpp_qp =394394+ pd->dpp_enabled ? OCRDMA_PD_MAX_DPP_ENABLED_QP : 0;395395+ }396396+ status = ocrdma_mbx_alloc_pd(dev, pd);397397+ if (status) {398398+ kfree(pd);399399+ return ERR_PTR(status);400400+ }401401+ atomic_set(&pd->use_cnt, 0);402402+403403+ if (udata && context) {404404+ status = ocrdma_copy_pd_uresp(pd, context, udata);405405+ if (status)406406+ goto err;407407+ }408408+ return &pd->ibpd;409409+410410+err:411411+ ocrdma_dealloc_pd(&pd->ibpd);412412+ return ERR_PTR(status);413413+}414414+415415+int ocrdma_dealloc_pd(struct ib_pd *ibpd)416416+{417417+ struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);418418+ struct ocrdma_dev *dev = pd->dev;419419+ int status;420420+ u64 usr_db;421421+422422+ if (atomic_read(&pd->use_cnt)) {423423+ ocrdma_err("%s(%d) pd=0x%x is in use.\n",424424+ __func__, dev->id, pd->id);425425+ status = -EFAULT;426426+ goto dealloc_err;427427+ }428428+ status = ocrdma_mbx_dealloc_pd(dev, pd);429429+ if (pd->uctx) {430430+ u64 dpp_db = dev->nic_info.dpp_unmapped_addr +431431+ (pd->id * OCRDMA_DPP_PAGE_SIZE);432432+ if (pd->dpp_enabled)433433+ ocrdma_del_mmap(pd->uctx, dpp_db, OCRDMA_DPP_PAGE_SIZE);434434+ usr_db = dev->nic_info.unmapped_db +435435+ (pd->id * dev->nic_info.db_page_size);436436+ ocrdma_del_mmap(pd->uctx, usr_db, dev->nic_info.db_page_size);437437+ }438438+ kfree(pd);439439+dealloc_err:440440+ return status;441441+}442442+443443+static struct ocrdma_mr *ocrdma_alloc_lkey(struct ib_pd *ibpd,444444+ int acc, u32 num_pbls,445445+ u32 addr_check)446446+{447447+ int status;448448+ struct ocrdma_mr *mr;449449+ struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);450450+ struct ocrdma_dev *dev = pd->dev;451451+452452+ if (acc & IB_ACCESS_REMOTE_WRITE && !(acc & IB_ACCESS_LOCAL_WRITE)) {453453+ ocrdma_err("%s(%d) leaving err, invalid access rights\n",454454+ __func__, dev->id);455455+ return ERR_PTR(-EINVAL);456456+ }457457+458458+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);459459+ if (!mr)460460+ return ERR_PTR(-ENOMEM);461461+ mr->hwmr.dev = dev;462462+ mr->hwmr.fr_mr = 0;463463+ mr->hwmr.local_rd = 1;464464+ mr->hwmr.remote_rd = (acc & IB_ACCESS_REMOTE_READ) ? 1 : 0;465465+ mr->hwmr.remote_wr = (acc & IB_ACCESS_REMOTE_WRITE) ? 1 : 0;466466+ mr->hwmr.local_wr = (acc & IB_ACCESS_LOCAL_WRITE) ? 1 : 0;467467+ mr->hwmr.mw_bind = (acc & IB_ACCESS_MW_BIND) ? 1 : 0;468468+ mr->hwmr.remote_atomic = (acc & IB_ACCESS_REMOTE_ATOMIC) ? 1 : 0;469469+ mr->hwmr.num_pbls = num_pbls;470470+471471+ status = ocrdma_mbx_alloc_lkey(dev, &mr->hwmr, pd->id, addr_check);472472+ if (status) {473473+ kfree(mr);474474+ return ERR_PTR(-ENOMEM);475475+ }476476+ mr->pd = pd;477477+ atomic_inc(&pd->use_cnt);478478+ mr->ibmr.lkey = mr->hwmr.lkey;479479+ if (mr->hwmr.remote_wr || mr->hwmr.remote_rd)480480+ mr->ibmr.rkey = mr->hwmr.lkey;481481+ return mr;482482+}483483+484484+struct ib_mr *ocrdma_get_dma_mr(struct ib_pd *ibpd, int acc)485485+{486486+ struct ocrdma_mr *mr;487487+488488+ mr = ocrdma_alloc_lkey(ibpd, acc, 0, OCRDMA_ADDR_CHECK_DISABLE);489489+ if (IS_ERR(mr))490490+ return ERR_CAST(mr);491491+492492+ return &mr->ibmr;493493+}494494+495495+static void ocrdma_free_mr_pbl_tbl(struct ocrdma_dev *dev,496496+ struct ocrdma_hw_mr *mr)497497+{498498+ struct pci_dev *pdev = dev->nic_info.pdev;499499+ int i = 0;500500+501501+ if (mr->pbl_table) {502502+ for (i = 0; i < mr->num_pbls; i++) {503503+ if (!mr->pbl_table[i].va)504504+ continue;505505+ dma_free_coherent(&pdev->dev, mr->pbl_size,506506+ mr->pbl_table[i].va,507507+ mr->pbl_table[i].pa);508508+ }509509+ kfree(mr->pbl_table);510510+ mr->pbl_table = NULL;511511+ }512512+}513513+514514+static int ocrdma_get_pbl_info(struct ocrdma_mr *mr, u32 num_pbes)515515+{516516+ u32 num_pbls = 0;517517+ u32 idx = 0;518518+ int status = 0;519519+ u32 pbl_size;520520+521521+ do {522522+ pbl_size = OCRDMA_MIN_HPAGE_SIZE * (1 << idx);523523+ if (pbl_size > MAX_OCRDMA_PBL_SIZE) {524524+ status = -EFAULT;525525+ break;526526+ }527527+ num_pbls = roundup(num_pbes, (pbl_size / sizeof(u64)));528528+ num_pbls = num_pbls / (pbl_size / sizeof(u64));529529+ idx++;530530+ } while (num_pbls >= mr->hwmr.dev->attr.max_num_mr_pbl);531531+532532+ mr->hwmr.num_pbes = num_pbes;533533+ mr->hwmr.num_pbls = num_pbls;534534+ mr->hwmr.pbl_size = pbl_size;535535+ return status;536536+}537537+538538+static int ocrdma_build_pbl_tbl(struct ocrdma_dev *dev, struct ocrdma_hw_mr *mr)539539+{540540+ int status = 0;541541+ int i;542542+ u32 dma_len = mr->pbl_size;543543+ struct pci_dev *pdev = dev->nic_info.pdev;544544+ void *va;545545+ dma_addr_t pa;546546+547547+ mr->pbl_table = kzalloc(sizeof(struct ocrdma_pbl) *548548+ mr->num_pbls, GFP_KERNEL);549549+550550+ if (!mr->pbl_table)551551+ return -ENOMEM;552552+553553+ for (i = 0; i < mr->num_pbls; i++) {554554+ va = dma_alloc_coherent(&pdev->dev, dma_len, &pa, GFP_KERNEL);555555+ if (!va) {556556+ ocrdma_free_mr_pbl_tbl(dev, mr);557557+ status = -ENOMEM;558558+ break;559559+ }560560+ memset(va, 0, dma_len);561561+ mr->pbl_table[i].va = va;562562+ mr->pbl_table[i].pa = pa;563563+ }564564+ return status;565565+}566566+567567+static void build_user_pbes(struct ocrdma_dev *dev, struct ocrdma_mr *mr,568568+ u32 num_pbes)569569+{570570+ struct ocrdma_pbe *pbe;571571+ struct ib_umem_chunk *chunk;572572+ struct ocrdma_pbl *pbl_tbl = mr->hwmr.pbl_table;573573+ struct ib_umem *umem = mr->umem;574574+ int i, shift, pg_cnt, pages, pbe_cnt, total_num_pbes = 0;575575+576576+ if (!mr->hwmr.num_pbes)577577+ return;578578+579579+ pbe = (struct ocrdma_pbe *)pbl_tbl->va;580580+ pbe_cnt = 0;581581+582582+ shift = ilog2(umem->page_size);583583+584584+ list_for_each_entry(chunk, &umem->chunk_list, list) {585585+ /* get all the dma regions from the chunk. */586586+ for (i = 0; i < chunk->nmap; i++) {587587+ pages = sg_dma_len(&chunk->page_list[i]) >> shift;588588+ for (pg_cnt = 0; pg_cnt < pages; pg_cnt++) {589589+ /* store the page address in pbe */590590+ pbe->pa_lo =591591+ cpu_to_le32(sg_dma_address592592+ (&chunk->page_list[i]) +593593+ (umem->page_size * pg_cnt));594594+ pbe->pa_hi =595595+ cpu_to_le32(upper_32_bits596596+ ((sg_dma_address597597+ (&chunk->page_list[i]) +598598+ umem->page_size * pg_cnt)));599599+ pbe_cnt += 1;600600+ total_num_pbes += 1;601601+ pbe++;602602+603603+ /* if done building pbes, issue the mbx cmd. */604604+ if (total_num_pbes == num_pbes)605605+ return;606606+607607+ /* if the given pbl is full storing the pbes,608608+ * move to next pbl.609609+ */610610+ if (pbe_cnt ==611611+ (mr->hwmr.pbl_size / sizeof(u64))) {612612+ pbl_tbl++;613613+ pbe = (struct ocrdma_pbe *)pbl_tbl->va;614614+ pbe_cnt = 0;615615+ }616616+ }617617+ }618618+ }619619+}620620+621621+struct ib_mr *ocrdma_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 len,622622+ u64 usr_addr, int acc, struct ib_udata *udata)623623+{624624+ int status = -ENOMEM;625625+ struct ocrdma_dev *dev;626626+ struct ocrdma_mr *mr;627627+ struct ocrdma_pd *pd;628628+ u32 num_pbes;629629+630630+ pd = get_ocrdma_pd(ibpd);631631+ dev = pd->dev;632632+633633+ if (acc & IB_ACCESS_REMOTE_WRITE && !(acc & IB_ACCESS_LOCAL_WRITE))634634+ return ERR_PTR(-EINVAL);635635+636636+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);637637+ if (!mr)638638+ return ERR_PTR(status);639639+ mr->hwmr.dev = dev;640640+ mr->umem = ib_umem_get(ibpd->uobject->context, start, len, acc, 0);641641+ if (IS_ERR(mr->umem)) {642642+ status = -EFAULT;643643+ goto umem_err;644644+ }645645+ num_pbes = ib_umem_page_count(mr->umem);646646+ status = ocrdma_get_pbl_info(mr, num_pbes);647647+ if (status)648648+ goto umem_err;649649+650650+ mr->hwmr.pbe_size = mr->umem->page_size;651651+ mr->hwmr.fbo = mr->umem->offset;652652+ mr->hwmr.va = usr_addr;653653+ mr->hwmr.len = len;654654+ mr->hwmr.remote_wr = (acc & IB_ACCESS_REMOTE_WRITE) ? 1 : 0;655655+ mr->hwmr.remote_rd = (acc & IB_ACCESS_REMOTE_READ) ? 1 : 0;656656+ mr->hwmr.local_wr = (acc & IB_ACCESS_LOCAL_WRITE) ? 1 : 0;657657+ mr->hwmr.local_rd = 1;658658+ mr->hwmr.remote_atomic = (acc & IB_ACCESS_REMOTE_ATOMIC) ? 1 : 0;659659+ status = ocrdma_build_pbl_tbl(dev, &mr->hwmr);660660+ if (status)661661+ goto umem_err;662662+ build_user_pbes(dev, mr, num_pbes);663663+ status = ocrdma_reg_mr(dev, &mr->hwmr, pd->id, acc);664664+ if (status)665665+ goto mbx_err;666666+ mr->pd = pd;667667+ atomic_inc(&pd->use_cnt);668668+ mr->ibmr.lkey = mr->hwmr.lkey;669669+ if (mr->hwmr.remote_wr || mr->hwmr.remote_rd)670670+ mr->ibmr.rkey = mr->hwmr.lkey;671671+672672+ return &mr->ibmr;673673+674674+mbx_err:675675+ ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);676676+umem_err:677677+ kfree(mr);678678+ return ERR_PTR(status);679679+}680680+681681+int ocrdma_dereg_mr(struct ib_mr *ib_mr)682682+{683683+ struct ocrdma_mr *mr = get_ocrdma_mr(ib_mr);684684+ struct ocrdma_dev *dev = mr->hwmr.dev;685685+ int status;686686+687687+ status = ocrdma_mbx_dealloc_lkey(dev, mr->hwmr.fr_mr, mr->hwmr.lkey);688688+689689+ if (mr->hwmr.fr_mr == 0)690690+ ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);691691+692692+ atomic_dec(&mr->pd->use_cnt);693693+ /* it could be user registered memory. */694694+ if (mr->umem)695695+ ib_umem_release(mr->umem);696696+ kfree(mr);697697+ return status;698698+}699699+700700+static int ocrdma_copy_cq_uresp(struct ocrdma_cq *cq, struct ib_udata *udata,701701+ struct ib_ucontext *ib_ctx)702702+{703703+ int status;704704+ struct ocrdma_ucontext *uctx;705705+ struct ocrdma_create_cq_uresp uresp;706706+707707+ uresp.cq_id = cq->id;708708+ uresp.page_size = cq->len;709709+ uresp.num_pages = 1;710710+ uresp.max_hw_cqe = cq->max_hw_cqe;711711+ uresp.page_addr[0] = cq->pa;712712+ uresp.db_page_addr = cq->dev->nic_info.unmapped_db;713713+ uresp.db_page_size = cq->dev->nic_info.db_page_size;714714+ uresp.phase_change = cq->phase_change ? 1 : 0;715715+ status = ib_copy_to_udata(udata, &uresp, sizeof(uresp));716716+ if (status) {717717+ ocrdma_err("%s(%d) copy error cqid=0x%x.\n",718718+ __func__, cq->dev->id, cq->id);719719+ goto err;720720+ }721721+ uctx = get_ocrdma_ucontext(ib_ctx);722722+ status = ocrdma_add_mmap(uctx, uresp.db_page_addr, uresp.db_page_size);723723+ if (status)724724+ goto err;725725+ status = ocrdma_add_mmap(uctx, uresp.page_addr[0], uresp.page_size);726726+ if (status) {727727+ ocrdma_del_mmap(uctx, uresp.db_page_addr, uresp.db_page_size);728728+ goto err;729729+ }730730+ cq->ucontext = uctx;731731+err:732732+ return status;733733+}734734+735735+struct ib_cq *ocrdma_create_cq(struct ib_device *ibdev, int entries, int vector,736736+ struct ib_ucontext *ib_ctx,737737+ struct ib_udata *udata)738738+{739739+ struct ocrdma_cq *cq;740740+ struct ocrdma_dev *dev = get_ocrdma_dev(ibdev);741741+ int status;742742+ struct ocrdma_create_cq_ureq ureq;743743+744744+ if (udata) {745745+ if (ib_copy_from_udata(&ureq, udata, sizeof(ureq)))746746+ return ERR_PTR(-EFAULT);747747+ } else748748+ ureq.dpp_cq = 0;749749+ cq = kzalloc(sizeof(*cq), GFP_KERNEL);750750+ if (!cq)751751+ return ERR_PTR(-ENOMEM);752752+753753+ spin_lock_init(&cq->cq_lock);754754+ spin_lock_init(&cq->comp_handler_lock);755755+ atomic_set(&cq->use_cnt, 0);756756+ INIT_LIST_HEAD(&cq->sq_head);757757+ INIT_LIST_HEAD(&cq->rq_head);758758+ cq->dev = dev;759759+760760+ status = ocrdma_mbx_create_cq(dev, cq, entries, ureq.dpp_cq);761761+ if (status) {762762+ kfree(cq);763763+ return ERR_PTR(status);764764+ }765765+ if (ib_ctx) {766766+ status = ocrdma_copy_cq_uresp(cq, udata, ib_ctx);767767+ if (status)768768+ goto ctx_err;769769+ }770770+ cq->phase = OCRDMA_CQE_VALID;771771+ cq->arm_needed = true;772772+ dev->cq_tbl[cq->id] = cq;773773+774774+ return &cq->ibcq;775775+776776+ctx_err:777777+ ocrdma_mbx_destroy_cq(dev, cq);778778+ kfree(cq);779779+ return ERR_PTR(status);780780+}781781+782782+int ocrdma_resize_cq(struct ib_cq *ibcq, int new_cnt,783783+ struct ib_udata *udata)784784+{785785+ int status = 0;786786+ struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);787787+788788+ if (new_cnt < 1 || new_cnt > cq->max_hw_cqe) {789789+ status = -EINVAL;790790+ return status;791791+ }792792+ ibcq->cqe = new_cnt;793793+ return status;794794+}795795+796796+int ocrdma_destroy_cq(struct ib_cq *ibcq)797797+{798798+ int status;799799+ struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);800800+ struct ocrdma_dev *dev = cq->dev;801801+802802+ if (atomic_read(&cq->use_cnt))803803+ return -EINVAL;804804+805805+ status = ocrdma_mbx_destroy_cq(dev, cq);806806+807807+ if (cq->ucontext) {808808+ ocrdma_del_mmap(cq->ucontext, (u64) cq->pa, cq->len);809809+ ocrdma_del_mmap(cq->ucontext, dev->nic_info.unmapped_db,810810+ dev->nic_info.db_page_size);811811+ }812812+ dev->cq_tbl[cq->id] = NULL;813813+814814+ kfree(cq);815815+ return status;816816+}817817+818818+static int ocrdma_add_qpn_map(struct ocrdma_dev *dev, struct ocrdma_qp *qp)819819+{820820+ int status = -EINVAL;821821+822822+ if (qp->id < OCRDMA_MAX_QP && dev->qp_tbl[qp->id] == NULL) {823823+ dev->qp_tbl[qp->id] = qp;824824+ status = 0;825825+ }826826+ return status;827827+}828828+829829+static void ocrdma_del_qpn_map(struct ocrdma_dev *dev, struct ocrdma_qp *qp)830830+{831831+ dev->qp_tbl[qp->id] = NULL;832832+}833833+834834+static int ocrdma_check_qp_params(struct ib_pd *ibpd, struct ocrdma_dev *dev,835835+ struct ib_qp_init_attr *attrs)836836+{837837+ if (attrs->qp_type != IB_QPT_GSI &&838838+ attrs->qp_type != IB_QPT_RC &&839839+ attrs->qp_type != IB_QPT_UD) {840840+ ocrdma_err("%s(%d) unsupported qp type=0x%x requested\n",841841+ __func__, dev->id, attrs->qp_type);842842+ return -EINVAL;843843+ }844844+ if (attrs->cap.max_send_wr > dev->attr.max_wqe) {845845+ ocrdma_err("%s(%d) unsupported send_wr=0x%x requested\n",846846+ __func__, dev->id, attrs->cap.max_send_wr);847847+ ocrdma_err("%s(%d) supported send_wr=0x%x\n",848848+ __func__, dev->id, dev->attr.max_wqe);849849+ return -EINVAL;850850+ }851851+ if (!attrs->srq && (attrs->cap.max_recv_wr > dev->attr.max_rqe)) {852852+ ocrdma_err("%s(%d) unsupported recv_wr=0x%x requested\n",853853+ __func__, dev->id, attrs->cap.max_recv_wr);854854+ ocrdma_err("%s(%d) supported recv_wr=0x%x\n",855855+ __func__, dev->id, dev->attr.max_rqe);856856+ return -EINVAL;857857+ }858858+ if (attrs->cap.max_inline_data > dev->attr.max_inline_data) {859859+ ocrdma_err("%s(%d) unsupported inline data size=0x%x"860860+ " requested\n", __func__, dev->id,861861+ attrs->cap.max_inline_data);862862+ ocrdma_err("%s(%d) supported inline data size=0x%x\n",863863+ __func__, dev->id, dev->attr.max_inline_data);864864+ return -EINVAL;865865+ }866866+ if (attrs->cap.max_send_sge > dev->attr.max_send_sge) {867867+ ocrdma_err("%s(%d) unsupported send_sge=0x%x requested\n",868868+ __func__, dev->id, attrs->cap.max_send_sge);869869+ ocrdma_err("%s(%d) supported send_sge=0x%x\n",870870+ __func__, dev->id, dev->attr.max_send_sge);871871+ return -EINVAL;872872+ }873873+ if (attrs->cap.max_recv_sge > dev->attr.max_recv_sge) {874874+ ocrdma_err("%s(%d) unsupported recv_sge=0x%x requested\n",875875+ __func__, dev->id, attrs->cap.max_recv_sge);876876+ ocrdma_err("%s(%d) supported recv_sge=0x%x\n",877877+ __func__, dev->id, dev->attr.max_recv_sge);878878+ return -EINVAL;879879+ }880880+ /* unprivileged user space cannot create special QP */881881+ if (ibpd->uobject && attrs->qp_type == IB_QPT_GSI) {882882+ ocrdma_err883883+ ("%s(%d) Userspace can't create special QPs of type=0x%x\n",884884+ __func__, dev->id, attrs->qp_type);885885+ return -EINVAL;886886+ }887887+ /* allow creating only one GSI type of QP */888888+ if (attrs->qp_type == IB_QPT_GSI && dev->gsi_qp_created) {889889+ ocrdma_err("%s(%d) GSI special QPs already created.\n",890890+ __func__, dev->id);891891+ return -EINVAL;892892+ }893893+ /* verify consumer QPs are not trying to use GSI QP's CQ */894894+ if ((attrs->qp_type != IB_QPT_GSI) && (dev->gsi_qp_created)) {895895+ if ((dev->gsi_sqcq == get_ocrdma_cq(attrs->send_cq)) ||896896+ (dev->gsi_sqcq == get_ocrdma_cq(attrs->send_cq))) {897897+ ocrdma_err("%s(%d) Consumer QP cannot use GSI CQs.\n",898898+ __func__, dev->id);899899+ return -EINVAL;900900+ }901901+ }902902+ return 0;903903+}904904+905905+static int ocrdma_copy_qp_uresp(struct ocrdma_qp *qp,906906+ struct ib_udata *udata, int dpp_offset,907907+ int dpp_credit_lmt, int srq)908908+{909909+ int status = 0;910910+ u64 usr_db;911911+ struct ocrdma_create_qp_uresp uresp;912912+ struct ocrdma_dev *dev = qp->dev;913913+ struct ocrdma_pd *pd = qp->pd;914914+915915+ memset(&uresp, 0, sizeof(uresp));916916+ usr_db = dev->nic_info.unmapped_db +917917+ (pd->id * dev->nic_info.db_page_size);918918+ uresp.qp_id = qp->id;919919+ uresp.sq_dbid = qp->sq.dbid;920920+ uresp.num_sq_pages = 1;921921+ uresp.sq_page_size = qp->sq.len;922922+ uresp.sq_page_addr[0] = qp->sq.pa;923923+ uresp.num_wqe_allocated = qp->sq.max_cnt;924924+ if (!srq) {925925+ uresp.rq_dbid = qp->rq.dbid;926926+ uresp.num_rq_pages = 1;927927+ uresp.rq_page_size = qp->rq.len;928928+ uresp.rq_page_addr[0] = qp->rq.pa;929929+ uresp.num_rqe_allocated = qp->rq.max_cnt;930930+ }931931+ uresp.db_page_addr = usr_db;932932+ uresp.db_page_size = dev->nic_info.db_page_size;933933+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {934934+ uresp.db_sq_offset = OCRDMA_DB_GEN2_SQ_OFFSET;935935+ uresp.db_rq_offset = ((qp->id & 0xFFFF) < 128) ?936936+ OCRDMA_DB_GEN2_RQ1_OFFSET : OCRDMA_DB_GEN2_RQ2_OFFSET;937937+ uresp.db_shift = (qp->id < 128) ? 24 : 16;938938+ } else {939939+ uresp.db_sq_offset = OCRDMA_DB_SQ_OFFSET;940940+ uresp.db_rq_offset = OCRDMA_DB_RQ_OFFSET;941941+ uresp.db_shift = 16;942942+ }943943+ uresp.free_wqe_delta = qp->sq.free_delta;944944+ uresp.free_rqe_delta = qp->rq.free_delta;945945+946946+ if (qp->dpp_enabled) {947947+ uresp.dpp_credit = dpp_credit_lmt;948948+ uresp.dpp_offset = dpp_offset;949949+ }950950+ status = ib_copy_to_udata(udata, &uresp, sizeof(uresp));951951+ if (status) {952952+ ocrdma_err("%s(%d) user copy error.\n", __func__, dev->id);953953+ goto err;954954+ }955955+ status = ocrdma_add_mmap(pd->uctx, uresp.sq_page_addr[0],956956+ uresp.sq_page_size);957957+ if (status)958958+ goto err;959959+960960+ if (!srq) {961961+ status = ocrdma_add_mmap(pd->uctx, uresp.rq_page_addr[0],962962+ uresp.rq_page_size);963963+ if (status)964964+ goto rq_map_err;965965+ }966966+ return status;967967+rq_map_err:968968+ ocrdma_del_mmap(pd->uctx, uresp.sq_page_addr[0], uresp.sq_page_size);969969+err:970970+ return status;971971+}972972+973973+static void ocrdma_set_qp_db(struct ocrdma_dev *dev, struct ocrdma_qp *qp,974974+ struct ocrdma_pd *pd)975975+{976976+ if (dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {977977+ qp->sq_db = dev->nic_info.db +978978+ (pd->id * dev->nic_info.db_page_size) +979979+ OCRDMA_DB_GEN2_SQ_OFFSET;980980+ qp->rq_db = dev->nic_info.db +981981+ (pd->id * dev->nic_info.db_page_size) +982982+ ((qp->id < 128) ?983983+ OCRDMA_DB_GEN2_RQ1_OFFSET : OCRDMA_DB_GEN2_RQ2_OFFSET);984984+ } else {985985+ qp->sq_db = dev->nic_info.db +986986+ (pd->id * dev->nic_info.db_page_size) +987987+ OCRDMA_DB_SQ_OFFSET;988988+ qp->rq_db = dev->nic_info.db +989989+ (pd->id * dev->nic_info.db_page_size) +990990+ OCRDMA_DB_RQ_OFFSET;991991+ }992992+}993993+994994+static int ocrdma_alloc_wr_id_tbl(struct ocrdma_qp *qp)995995+{996996+ qp->wqe_wr_id_tbl =997997+ kzalloc(sizeof(*(qp->wqe_wr_id_tbl)) * qp->sq.max_cnt,998998+ GFP_KERNEL);999999+ if (qp->wqe_wr_id_tbl == NULL)10001000+ return -ENOMEM;10011001+ qp->rqe_wr_id_tbl =10021002+ kzalloc(sizeof(u64) * qp->rq.max_cnt, GFP_KERNEL);10031003+ if (qp->rqe_wr_id_tbl == NULL)10041004+ return -ENOMEM;10051005+10061006+ return 0;10071007+}10081008+10091009+static void ocrdma_set_qp_init_params(struct ocrdma_qp *qp,10101010+ struct ocrdma_pd *pd,10111011+ struct ib_qp_init_attr *attrs)10121012+{10131013+ qp->pd = pd;10141014+ spin_lock_init(&qp->q_lock);10151015+ INIT_LIST_HEAD(&qp->sq_entry);10161016+ INIT_LIST_HEAD(&qp->rq_entry);10171017+10181018+ qp->qp_type = attrs->qp_type;10191019+ qp->cap_flags = OCRDMA_QP_INB_RD | OCRDMA_QP_INB_WR;10201020+ qp->max_inline_data = attrs->cap.max_inline_data;10211021+ qp->sq.max_sges = attrs->cap.max_send_sge;10221022+ qp->rq.max_sges = attrs->cap.max_recv_sge;10231023+ qp->state = OCRDMA_QPS_RST;10241024+}10251025+10261026+static void ocrdma_set_qp_use_cnt(struct ocrdma_qp *qp, struct ocrdma_pd *pd)10271027+{10281028+ atomic_inc(&pd->use_cnt);10291029+ atomic_inc(&qp->sq_cq->use_cnt);10301030+ atomic_inc(&qp->rq_cq->use_cnt);10311031+ if (qp->srq)10321032+ atomic_inc(&qp->srq->use_cnt);10331033+ qp->ibqp.qp_num = qp->id;10341034+}10351035+10361036+static void ocrdma_store_gsi_qp_cq(struct ocrdma_dev *dev,10371037+ struct ib_qp_init_attr *attrs)10381038+{10391039+ if (attrs->qp_type == IB_QPT_GSI) {10401040+ dev->gsi_qp_created = 1;10411041+ dev->gsi_sqcq = get_ocrdma_cq(attrs->send_cq);10421042+ dev->gsi_rqcq = get_ocrdma_cq(attrs->recv_cq);10431043+ }10441044+}10451045+10461046+struct ib_qp *ocrdma_create_qp(struct ib_pd *ibpd,10471047+ struct ib_qp_init_attr *attrs,10481048+ struct ib_udata *udata)10491049+{10501050+ int status;10511051+ struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);10521052+ struct ocrdma_qp *qp;10531053+ struct ocrdma_dev *dev = pd->dev;10541054+ struct ocrdma_create_qp_ureq ureq;10551055+ u16 dpp_credit_lmt, dpp_offset;10561056+10571057+ status = ocrdma_check_qp_params(ibpd, dev, attrs);10581058+ if (status)10591059+ goto gen_err;10601060+10611061+ memset(&ureq, 0, sizeof(ureq));10621062+ if (udata) {10631063+ if (ib_copy_from_udata(&ureq, udata, sizeof(ureq)))10641064+ return ERR_PTR(-EFAULT);10651065+ }10661066+ qp = kzalloc(sizeof(*qp), GFP_KERNEL);10671067+ if (!qp) {10681068+ status = -ENOMEM;10691069+ goto gen_err;10701070+ }10711071+ qp->dev = dev;10721072+ ocrdma_set_qp_init_params(qp, pd, attrs);10731073+10741074+ mutex_lock(&dev->dev_lock);10751075+ status = ocrdma_mbx_create_qp(qp, attrs, ureq.enable_dpp_cq,10761076+ ureq.dpp_cq_id,10771077+ &dpp_offset, &dpp_credit_lmt);10781078+ if (status)10791079+ goto mbx_err;10801080+10811081+ /* user space QP's wr_id table are managed in library */10821082+ if (udata == NULL) {10831083+ qp->cap_flags |= (OCRDMA_QP_MW_BIND | OCRDMA_QP_LKEY0 |10841084+ OCRDMA_QP_FAST_REG);10851085+ status = ocrdma_alloc_wr_id_tbl(qp);10861086+ if (status)10871087+ goto map_err;10881088+ }10891089+10901090+ status = ocrdma_add_qpn_map(dev, qp);10911091+ if (status)10921092+ goto map_err;10931093+ ocrdma_set_qp_db(dev, qp, pd);10941094+ if (udata) {10951095+ status = ocrdma_copy_qp_uresp(qp, udata, dpp_offset,10961096+ dpp_credit_lmt,10971097+ (attrs->srq != NULL));10981098+ if (status)10991099+ goto cpy_err;11001100+ }11011101+ ocrdma_store_gsi_qp_cq(dev, attrs);11021102+ ocrdma_set_qp_use_cnt(qp, pd);11031103+ mutex_unlock(&dev->dev_lock);11041104+ return &qp->ibqp;11051105+11061106+cpy_err:11071107+ ocrdma_del_qpn_map(dev, qp);11081108+map_err:11091109+ ocrdma_mbx_destroy_qp(dev, qp);11101110+mbx_err:11111111+ mutex_unlock(&dev->dev_lock);11121112+ kfree(qp->wqe_wr_id_tbl);11131113+ kfree(qp->rqe_wr_id_tbl);11141114+ kfree(qp);11151115+ ocrdma_err("%s(%d) error=%d\n", __func__, dev->id, status);11161116+gen_err:11171117+ return ERR_PTR(status);11181118+}11191119+11201120+int _ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,11211121+ int attr_mask)11221122+{11231123+ int status = 0;11241124+ struct ocrdma_qp *qp;11251125+ struct ocrdma_dev *dev;11261126+ enum ib_qp_state old_qps;11271127+11281128+ qp = get_ocrdma_qp(ibqp);11291129+ dev = qp->dev;11301130+ if (attr_mask & IB_QP_STATE)11311131+ status = ocrdma_qp_state_machine(qp, attr->qp_state, &old_qps);11321132+ /* if new and previous states are same hw doesn't need to11331133+ * know about it.11341134+ */11351135+ if (status < 0)11361136+ return status;11371137+ status = ocrdma_mbx_modify_qp(dev, qp, attr, attr_mask, old_qps);11381138+ return status;11391139+}11401140+11411141+int ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,11421142+ int attr_mask, struct ib_udata *udata)11431143+{11441144+ unsigned long flags;11451145+ int status = -EINVAL;11461146+ struct ocrdma_qp *qp;11471147+ struct ocrdma_dev *dev;11481148+ enum ib_qp_state old_qps, new_qps;11491149+11501150+ qp = get_ocrdma_qp(ibqp);11511151+ dev = qp->dev;11521152+11531153+ /* syncronize with multiple context trying to change, retrive qps */11541154+ mutex_lock(&dev->dev_lock);11551155+ /* syncronize with wqe, rqe posting and cqe processing contexts */11561156+ spin_lock_irqsave(&qp->q_lock, flags);11571157+ old_qps = get_ibqp_state(qp->state);11581158+ if (attr_mask & IB_QP_STATE)11591159+ new_qps = attr->qp_state;11601160+ else11611161+ new_qps = old_qps;11621162+ spin_unlock_irqrestore(&qp->q_lock, flags);11631163+11641164+ if (!ib_modify_qp_is_ok(old_qps, new_qps, ibqp->qp_type, attr_mask)) {11651165+ ocrdma_err("%s(%d) invalid attribute mask=0x%x specified for "11661166+ "qpn=0x%x of type=0x%x old_qps=0x%x, new_qps=0x%x\n",11671167+ __func__, dev->id, attr_mask, qp->id, ibqp->qp_type,11681168+ old_qps, new_qps);11691169+ goto param_err;11701170+ }11711171+11721172+ status = _ocrdma_modify_qp(ibqp, attr, attr_mask);11731173+ if (status > 0)11741174+ status = 0;11751175+param_err:11761176+ mutex_unlock(&dev->dev_lock);11771177+ return status;11781178+}11791179+11801180+static enum ib_mtu ocrdma_mtu_int_to_enum(u16 mtu)11811181+{11821182+ switch (mtu) {11831183+ case 256:11841184+ return IB_MTU_256;11851185+ case 512:11861186+ return IB_MTU_512;11871187+ case 1024:11881188+ return IB_MTU_1024;11891189+ case 2048:11901190+ return IB_MTU_2048;11911191+ case 4096:11921192+ return IB_MTU_4096;11931193+ default:11941194+ return IB_MTU_1024;11951195+ }11961196+}11971197+11981198+static int ocrdma_to_ib_qp_acc_flags(int qp_cap_flags)11991199+{12001200+ int ib_qp_acc_flags = 0;12011201+12021202+ if (qp_cap_flags & OCRDMA_QP_INB_WR)12031203+ ib_qp_acc_flags |= IB_ACCESS_REMOTE_WRITE;12041204+ if (qp_cap_flags & OCRDMA_QP_INB_RD)12051205+ ib_qp_acc_flags |= IB_ACCESS_LOCAL_WRITE;12061206+ return ib_qp_acc_flags;12071207+}12081208+12091209+int ocrdma_query_qp(struct ib_qp *ibqp,12101210+ struct ib_qp_attr *qp_attr,12111211+ int attr_mask, struct ib_qp_init_attr *qp_init_attr)12121212+{12131213+ int status;12141214+ u32 qp_state;12151215+ struct ocrdma_qp_params params;12161216+ struct ocrdma_qp *qp = get_ocrdma_qp(ibqp);12171217+ struct ocrdma_dev *dev = qp->dev;12181218+12191219+ memset(¶ms, 0, sizeof(params));12201220+ mutex_lock(&dev->dev_lock);12211221+ status = ocrdma_mbx_query_qp(dev, qp, ¶ms);12221222+ mutex_unlock(&dev->dev_lock);12231223+ if (status)12241224+ goto mbx_err;12251225+ qp_attr->qp_state = get_ibqp_state(IB_QPS_INIT);12261226+ qp_attr->cur_qp_state = get_ibqp_state(IB_QPS_INIT);12271227+ qp_attr->path_mtu =12281228+ ocrdma_mtu_int_to_enum(params.path_mtu_pkey_indx &12291229+ OCRDMA_QP_PARAMS_PATH_MTU_MASK) >>12301230+ OCRDMA_QP_PARAMS_PATH_MTU_SHIFT;12311231+ qp_attr->path_mig_state = IB_MIG_MIGRATED;12321232+ qp_attr->rq_psn = params.hop_lmt_rq_psn & OCRDMA_QP_PARAMS_RQ_PSN_MASK;12331233+ qp_attr->sq_psn = params.tclass_sq_psn & OCRDMA_QP_PARAMS_SQ_PSN_MASK;12341234+ qp_attr->dest_qp_num =12351235+ params.ack_to_rnr_rtc_dest_qpn & OCRDMA_QP_PARAMS_DEST_QPN_MASK;12361236+12371237+ qp_attr->qp_access_flags = ocrdma_to_ib_qp_acc_flags(qp->cap_flags);12381238+ qp_attr->cap.max_send_wr = qp->sq.max_cnt - 1;12391239+ qp_attr->cap.max_recv_wr = qp->rq.max_cnt - 1;12401240+ qp_attr->cap.max_send_sge = qp->sq.max_sges;12411241+ qp_attr->cap.max_recv_sge = qp->rq.max_sges;12421242+ qp_attr->cap.max_inline_data = dev->attr.max_inline_data;12431243+ qp_init_attr->cap = qp_attr->cap;12441244+ memcpy(&qp_attr->ah_attr.grh.dgid, ¶ms.dgid[0],12451245+ sizeof(params.dgid));12461246+ qp_attr->ah_attr.grh.flow_label = params.rnt_rc_sl_fl &12471247+ OCRDMA_QP_PARAMS_FLOW_LABEL_MASK;12481248+ qp_attr->ah_attr.grh.sgid_index = qp->sgid_idx;12491249+ qp_attr->ah_attr.grh.hop_limit = (params.hop_lmt_rq_psn &12501250+ OCRDMA_QP_PARAMS_HOP_LMT_MASK) >>12511251+ OCRDMA_QP_PARAMS_HOP_LMT_SHIFT;12521252+ qp_attr->ah_attr.grh.traffic_class = (params.tclass_sq_psn &12531253+ OCRDMA_QP_PARAMS_SQ_PSN_MASK) >>12541254+ OCRDMA_QP_PARAMS_TCLASS_SHIFT;12551255+12561256+ qp_attr->ah_attr.ah_flags = IB_AH_GRH;12571257+ qp_attr->ah_attr.port_num = 1;12581258+ qp_attr->ah_attr.sl = (params.rnt_rc_sl_fl &12591259+ OCRDMA_QP_PARAMS_SL_MASK) >>12601260+ OCRDMA_QP_PARAMS_SL_SHIFT;12611261+ qp_attr->timeout = (params.ack_to_rnr_rtc_dest_qpn &12621262+ OCRDMA_QP_PARAMS_ACK_TIMEOUT_MASK) >>12631263+ OCRDMA_QP_PARAMS_ACK_TIMEOUT_SHIFT;12641264+ qp_attr->rnr_retry = (params.ack_to_rnr_rtc_dest_qpn &12651265+ OCRDMA_QP_PARAMS_RNR_RETRY_CNT_MASK) >>12661266+ OCRDMA_QP_PARAMS_RNR_RETRY_CNT_SHIFT;12671267+ qp_attr->retry_cnt =12681268+ (params.rnt_rc_sl_fl & OCRDMA_QP_PARAMS_RETRY_CNT_MASK) >>12691269+ OCRDMA_QP_PARAMS_RETRY_CNT_SHIFT;12701270+ qp_attr->min_rnr_timer = 0;12711271+ qp_attr->pkey_index = 0;12721272+ qp_attr->port_num = 1;12731273+ qp_attr->ah_attr.src_path_bits = 0;12741274+ qp_attr->ah_attr.static_rate = 0;12751275+ qp_attr->alt_pkey_index = 0;12761276+ qp_attr->alt_port_num = 0;12771277+ qp_attr->alt_timeout = 0;12781278+ memset(&qp_attr->alt_ah_attr, 0, sizeof(qp_attr->alt_ah_attr));12791279+ qp_state = (params.max_sge_recv_flags & OCRDMA_QP_PARAMS_STATE_MASK) >>12801280+ OCRDMA_QP_PARAMS_STATE_SHIFT;12811281+ qp_attr->sq_draining = (qp_state == OCRDMA_QPS_SQ_DRAINING) ? 1 : 0;12821282+ qp_attr->max_dest_rd_atomic =12831283+ params.max_ord_ird >> OCRDMA_QP_PARAMS_MAX_ORD_SHIFT;12841284+ qp_attr->max_rd_atomic =12851285+ params.max_ord_ird & OCRDMA_QP_PARAMS_MAX_IRD_MASK;12861286+ qp_attr->en_sqd_async_notify = (params.max_sge_recv_flags &12871287+ OCRDMA_QP_PARAMS_FLAGS_SQD_ASYNC) ? 1 : 0;12881288+mbx_err:12891289+ return status;12901290+}12911291+12921292+static void ocrdma_srq_toggle_bit(struct ocrdma_srq *srq, int idx)12931293+{12941294+ int i = idx / 32;12951295+ unsigned int mask = (1 << (idx % 32));12961296+12971297+ if (srq->idx_bit_fields[i] & mask)12981298+ srq->idx_bit_fields[i] &= ~mask;12991299+ else13001300+ srq->idx_bit_fields[i] |= mask;13011301+}13021302+13031303+static int ocrdma_hwq_free_cnt(struct ocrdma_qp_hwq_info *q)13041304+{13051305+ int free_cnt;13061306+ if (q->head >= q->tail)13071307+ free_cnt = (q->max_cnt - q->head) + q->tail;13081308+ else13091309+ free_cnt = q->tail - q->head;13101310+ if (q->free_delta)13111311+ free_cnt -= q->free_delta;13121312+ return free_cnt;13131313+}13141314+13151315+static int is_hw_sq_empty(struct ocrdma_qp *qp)13161316+{13171317+ return (qp->sq.tail == qp->sq.head &&13181318+ ocrdma_hwq_free_cnt(&qp->sq) ? 1 : 0);13191319+}13201320+13211321+static int is_hw_rq_empty(struct ocrdma_qp *qp)13221322+{13231323+ return (qp->rq.tail == qp->rq.head) ? 1 : 0;13241324+}13251325+13261326+static void *ocrdma_hwq_head(struct ocrdma_qp_hwq_info *q)13271327+{13281328+ return q->va + (q->head * q->entry_size);13291329+}13301330+13311331+static void *ocrdma_hwq_head_from_idx(struct ocrdma_qp_hwq_info *q,13321332+ u32 idx)13331333+{13341334+ return q->va + (idx * q->entry_size);13351335+}13361336+13371337+static void ocrdma_hwq_inc_head(struct ocrdma_qp_hwq_info *q)13381338+{13391339+ q->head = (q->head + 1) & q->max_wqe_idx;13401340+}13411341+13421342+static void ocrdma_hwq_inc_tail(struct ocrdma_qp_hwq_info *q)13431343+{13441344+ q->tail = (q->tail + 1) & q->max_wqe_idx;13451345+}13461346+13471347+/* discard the cqe for a given QP */13481348+static void ocrdma_discard_cqes(struct ocrdma_qp *qp, struct ocrdma_cq *cq)13491349+{13501350+ unsigned long cq_flags;13511351+ unsigned long flags;13521352+ int discard_cnt = 0;13531353+ u32 cur_getp, stop_getp;13541354+ struct ocrdma_cqe *cqe;13551355+ u32 qpn = 0;13561356+13571357+ spin_lock_irqsave(&cq->cq_lock, cq_flags);13581358+13591359+ /* traverse through the CQEs in the hw CQ,13601360+ * find the matching CQE for a given qp,13611361+ * mark the matching one discarded by clearing qpn.13621362+ * ring the doorbell in the poll_cq() as13631363+ * we don't complete out of order cqe.13641364+ */13651365+13661366+ cur_getp = cq->getp;13671367+ /* find upto when do we reap the cq. */13681368+ stop_getp = cur_getp;13691369+ do {13701370+ if (is_hw_sq_empty(qp) && (!qp->srq && is_hw_rq_empty(qp)))13711371+ break;13721372+13731373+ cqe = cq->va + cur_getp;13741374+ /* if (a) done reaping whole hw cq, or13751375+ * (b) qp_xq becomes empty.13761376+ * then exit13771377+ */13781378+ qpn = cqe->cmn.qpn & OCRDMA_CQE_QPN_MASK;13791379+ /* if previously discarded cqe found, skip that too. */13801380+ /* check for matching qp */13811381+ if (qpn == 0 || qpn != qp->id)13821382+ goto skip_cqe;13831383+13841384+ /* mark cqe discarded so that it is not picked up later13851385+ * in the poll_cq().13861386+ */13871387+ discard_cnt += 1;13881388+ cqe->cmn.qpn = 0;13891389+ if (is_cqe_for_sq(cqe))13901390+ ocrdma_hwq_inc_tail(&qp->sq);13911391+ else {13921392+ if (qp->srq) {13931393+ spin_lock_irqsave(&qp->srq->q_lock, flags);13941394+ ocrdma_hwq_inc_tail(&qp->srq->rq);13951395+ ocrdma_srq_toggle_bit(qp->srq, cur_getp);13961396+ spin_unlock_irqrestore(&qp->srq->q_lock, flags);13971397+13981398+ } else13991399+ ocrdma_hwq_inc_tail(&qp->rq);14001400+ }14011401+skip_cqe:14021402+ cur_getp = (cur_getp + 1) % cq->max_hw_cqe;14031403+ } while (cur_getp != stop_getp);14041404+ spin_unlock_irqrestore(&cq->cq_lock, cq_flags);14051405+}14061406+14071407+static void ocrdma_del_flush_qp(struct ocrdma_qp *qp)14081408+{14091409+ int found = false;14101410+ unsigned long flags;14111411+ struct ocrdma_dev *dev = qp->dev;14121412+ /* sync with any active CQ poll */14131413+14141414+ spin_lock_irqsave(&dev->flush_q_lock, flags);14151415+ found = ocrdma_is_qp_in_sq_flushlist(qp->sq_cq, qp);14161416+ if (found)14171417+ list_del(&qp->sq_entry);14181418+ if (!qp->srq) {14191419+ found = ocrdma_is_qp_in_rq_flushlist(qp->rq_cq, qp);14201420+ if (found)14211421+ list_del(&qp->rq_entry);14221422+ }14231423+ spin_unlock_irqrestore(&dev->flush_q_lock, flags);14241424+}14251425+14261426+int ocrdma_destroy_qp(struct ib_qp *ibqp)14271427+{14281428+ int status;14291429+ struct ocrdma_pd *pd;14301430+ struct ocrdma_qp *qp;14311431+ struct ocrdma_dev *dev;14321432+ struct ib_qp_attr attrs;14331433+ int attr_mask = IB_QP_STATE;14341434+ unsigned long flags;14351435+14361436+ qp = get_ocrdma_qp(ibqp);14371437+ dev = qp->dev;14381438+14391439+ attrs.qp_state = IB_QPS_ERR;14401440+ pd = qp->pd;14411441+14421442+ /* change the QP state to ERROR */14431443+ _ocrdma_modify_qp(ibqp, &attrs, attr_mask);14441444+14451445+ /* ensure that CQEs for newly created QP (whose id may be same with14461446+ * one which just getting destroyed are same), dont get14471447+ * discarded until the old CQEs are discarded.14481448+ */14491449+ mutex_lock(&dev->dev_lock);14501450+ status = ocrdma_mbx_destroy_qp(dev, qp);14511451+14521452+ /*14531453+ * acquire CQ lock while destroy is in progress, in order to14541454+ * protect against proessing in-flight CQEs for this QP.14551455+ */14561456+ spin_lock_irqsave(&qp->sq_cq->cq_lock, flags);14571457+ if (qp->rq_cq && (qp->rq_cq != qp->sq_cq))14581458+ spin_lock(&qp->rq_cq->cq_lock);14591459+14601460+ ocrdma_del_qpn_map(dev, qp);14611461+14621462+ if (qp->rq_cq && (qp->rq_cq != qp->sq_cq))14631463+ spin_unlock(&qp->rq_cq->cq_lock);14641464+ spin_unlock_irqrestore(&qp->sq_cq->cq_lock, flags);14651465+14661466+ if (!pd->uctx) {14671467+ ocrdma_discard_cqes(qp, qp->sq_cq);14681468+ ocrdma_discard_cqes(qp, qp->rq_cq);14691469+ }14701470+ mutex_unlock(&dev->dev_lock);14711471+14721472+ if (pd->uctx) {14731473+ ocrdma_del_mmap(pd->uctx, (u64) qp->sq.pa, qp->sq.len);14741474+ if (!qp->srq)14751475+ ocrdma_del_mmap(pd->uctx, (u64) qp->rq.pa, qp->rq.len);14761476+ }14771477+14781478+ ocrdma_del_flush_qp(qp);14791479+14801480+ atomic_dec(&qp->pd->use_cnt);14811481+ atomic_dec(&qp->sq_cq->use_cnt);14821482+ atomic_dec(&qp->rq_cq->use_cnt);14831483+ if (qp->srq)14841484+ atomic_dec(&qp->srq->use_cnt);14851485+ kfree(qp->wqe_wr_id_tbl);14861486+ kfree(qp->rqe_wr_id_tbl);14871487+ kfree(qp);14881488+ return status;14891489+}14901490+14911491+static int ocrdma_copy_srq_uresp(struct ocrdma_srq *srq, struct ib_udata *udata)14921492+{14931493+ int status;14941494+ struct ocrdma_create_srq_uresp uresp;14951495+14961496+ uresp.rq_dbid = srq->rq.dbid;14971497+ uresp.num_rq_pages = 1;14981498+ uresp.rq_page_addr[0] = srq->rq.pa;14991499+ uresp.rq_page_size = srq->rq.len;15001500+ uresp.db_page_addr = srq->dev->nic_info.unmapped_db +15011501+ (srq->pd->id * srq->dev->nic_info.db_page_size);15021502+ uresp.db_page_size = srq->dev->nic_info.db_page_size;15031503+ uresp.num_rqe_allocated = srq->rq.max_cnt;15041504+ uresp.free_rqe_delta = 1;15051505+ if (srq->dev->nic_info.dev_family == OCRDMA_GEN2_FAMILY) {15061506+ uresp.db_rq_offset = OCRDMA_DB_GEN2_RQ1_OFFSET;15071507+ uresp.db_shift = 24;15081508+ } else {15091509+ uresp.db_rq_offset = OCRDMA_DB_RQ_OFFSET;15101510+ uresp.db_shift = 16;15111511+ }15121512+15131513+ status = ib_copy_to_udata(udata, &uresp, sizeof(uresp));15141514+ if (status)15151515+ return status;15161516+ status = ocrdma_add_mmap(srq->pd->uctx, uresp.rq_page_addr[0],15171517+ uresp.rq_page_size);15181518+ if (status)15191519+ return status;15201520+ return status;15211521+}15221522+15231523+struct ib_srq *ocrdma_create_srq(struct ib_pd *ibpd,15241524+ struct ib_srq_init_attr *init_attr,15251525+ struct ib_udata *udata)15261526+{15271527+ int status = -ENOMEM;15281528+ struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);15291529+ struct ocrdma_dev *dev = pd->dev;15301530+ struct ocrdma_srq *srq;15311531+15321532+ if (init_attr->attr.max_sge > dev->attr.max_recv_sge)15331533+ return ERR_PTR(-EINVAL);15341534+ if (init_attr->attr.max_wr > dev->attr.max_rqe)15351535+ return ERR_PTR(-EINVAL);15361536+15371537+ srq = kzalloc(sizeof(*srq), GFP_KERNEL);15381538+ if (!srq)15391539+ return ERR_PTR(status);15401540+15411541+ spin_lock_init(&srq->q_lock);15421542+ srq->dev = dev;15431543+ srq->pd = pd;15441544+ srq->db = dev->nic_info.db + (pd->id * dev->nic_info.db_page_size);15451545+ status = ocrdma_mbx_create_srq(srq, init_attr, pd);15461546+ if (status)15471547+ goto err;15481548+15491549+ if (udata == NULL) {15501550+ srq->rqe_wr_id_tbl = kzalloc(sizeof(u64) * srq->rq.max_cnt,15511551+ GFP_KERNEL);15521552+ if (srq->rqe_wr_id_tbl == NULL)15531553+ goto arm_err;15541554+15551555+ srq->bit_fields_len = (srq->rq.max_cnt / 32) +15561556+ (srq->rq.max_cnt % 32 ? 1 : 0);15571557+ srq->idx_bit_fields =15581558+ kmalloc(srq->bit_fields_len * sizeof(u32), GFP_KERNEL);15591559+ if (srq->idx_bit_fields == NULL)15601560+ goto arm_err;15611561+ memset(srq->idx_bit_fields, 0xff,15621562+ srq->bit_fields_len * sizeof(u32));15631563+ }15641564+15651565+ if (init_attr->attr.srq_limit) {15661566+ status = ocrdma_mbx_modify_srq(srq, &init_attr->attr);15671567+ if (status)15681568+ goto arm_err;15691569+ }15701570+15711571+ atomic_set(&srq->use_cnt, 0);15721572+ if (udata) {15731573+ status = ocrdma_copy_srq_uresp(srq, udata);15741574+ if (status)15751575+ goto arm_err;15761576+ }15771577+15781578+ atomic_inc(&pd->use_cnt);15791579+ return &srq->ibsrq;15801580+15811581+arm_err:15821582+ ocrdma_mbx_destroy_srq(dev, srq);15831583+err:15841584+ kfree(srq->rqe_wr_id_tbl);15851585+ kfree(srq->idx_bit_fields);15861586+ kfree(srq);15871587+ return ERR_PTR(status);15881588+}15891589+15901590+int ocrdma_modify_srq(struct ib_srq *ibsrq,15911591+ struct ib_srq_attr *srq_attr,15921592+ enum ib_srq_attr_mask srq_attr_mask,15931593+ struct ib_udata *udata)15941594+{15951595+ int status = 0;15961596+ struct ocrdma_srq *srq;15971597+15981598+ srq = get_ocrdma_srq(ibsrq);15991599+ if (srq_attr_mask & IB_SRQ_MAX_WR)16001600+ status = -EINVAL;16011601+ else16021602+ status = ocrdma_mbx_modify_srq(srq, srq_attr);16031603+ return status;16041604+}16051605+16061606+int ocrdma_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)16071607+{16081608+ int status;16091609+ struct ocrdma_srq *srq;16101610+16111611+ srq = get_ocrdma_srq(ibsrq);16121612+ status = ocrdma_mbx_query_srq(srq, srq_attr);16131613+ return status;16141614+}16151615+16161616+int ocrdma_destroy_srq(struct ib_srq *ibsrq)16171617+{16181618+ int status;16191619+ struct ocrdma_srq *srq;16201620+ struct ocrdma_dev *dev;16211621+16221622+ srq = get_ocrdma_srq(ibsrq);16231623+ dev = srq->dev;16241624+ if (atomic_read(&srq->use_cnt)) {16251625+ ocrdma_err("%s(%d) err, srq=0x%x in use\n",16261626+ __func__, dev->id, srq->id);16271627+ return -EAGAIN;16281628+ }16291629+16301630+ status = ocrdma_mbx_destroy_srq(dev, srq);16311631+16321632+ if (srq->pd->uctx)16331633+ ocrdma_del_mmap(srq->pd->uctx, (u64) srq->rq.pa, srq->rq.len);16341634+16351635+ atomic_dec(&srq->pd->use_cnt);16361636+ kfree(srq->idx_bit_fields);16371637+ kfree(srq->rqe_wr_id_tbl);16381638+ kfree(srq);16391639+ return status;16401640+}16411641+16421642+/* unprivileged verbs and their support functions. */16431643+static void ocrdma_build_ud_hdr(struct ocrdma_qp *qp,16441644+ struct ocrdma_hdr_wqe *hdr,16451645+ struct ib_send_wr *wr)16461646+{16471647+ struct ocrdma_ewqe_ud_hdr *ud_hdr =16481648+ (struct ocrdma_ewqe_ud_hdr *)(hdr + 1);16491649+ struct ocrdma_ah *ah = get_ocrdma_ah(wr->wr.ud.ah);16501650+16511651+ ud_hdr->rsvd_dest_qpn = wr->wr.ud.remote_qpn;16521652+ if (qp->qp_type == IB_QPT_GSI)16531653+ ud_hdr->qkey = qp->qkey;16541654+ else16551655+ ud_hdr->qkey = wr->wr.ud.remote_qkey;16561656+ ud_hdr->rsvd_ahid = ah->id;16571657+}16581658+16591659+static void ocrdma_build_sges(struct ocrdma_hdr_wqe *hdr,16601660+ struct ocrdma_sge *sge, int num_sge,16611661+ struct ib_sge *sg_list)16621662+{16631663+ int i;16641664+16651665+ for (i = 0; i < num_sge; i++) {16661666+ sge[i].lrkey = sg_list[i].lkey;16671667+ sge[i].addr_lo = sg_list[i].addr;16681668+ sge[i].addr_hi = upper_32_bits(sg_list[i].addr);16691669+ sge[i].len = sg_list[i].length;16701670+ hdr->total_len += sg_list[i].length;16711671+ }16721672+ if (num_sge == 0)16731673+ memset(sge, 0, sizeof(*sge));16741674+}16751675+16761676+static int ocrdma_build_inline_sges(struct ocrdma_qp *qp,16771677+ struct ocrdma_hdr_wqe *hdr,16781678+ struct ocrdma_sge *sge,16791679+ struct ib_send_wr *wr, u32 wqe_size)16801680+{16811681+ if (wr->send_flags & IB_SEND_INLINE) {16821682+ if (wr->sg_list[0].length > qp->max_inline_data) {16831683+ ocrdma_err("%s() supported_len=0x%x,"16841684+ " unspported len req=0x%x\n", __func__,16851685+ qp->max_inline_data, wr->sg_list[0].length);16861686+ return -EINVAL;16871687+ }16881688+ memcpy(sge,16891689+ (void *)(unsigned long)wr->sg_list[0].addr,16901690+ wr->sg_list[0].length);16911691+ hdr->total_len = wr->sg_list[0].length;16921692+ wqe_size += roundup(hdr->total_len, OCRDMA_WQE_ALIGN_BYTES);16931693+ hdr->cw |= (OCRDMA_TYPE_INLINE << OCRDMA_WQE_TYPE_SHIFT);16941694+ } else {16951695+ ocrdma_build_sges(hdr, sge, wr->num_sge, wr->sg_list);16961696+ if (wr->num_sge)16971697+ wqe_size += (wr->num_sge * sizeof(struct ocrdma_sge));16981698+ else16991699+ wqe_size += sizeof(struct ocrdma_sge);17001700+ hdr->cw |= (OCRDMA_TYPE_LKEY << OCRDMA_WQE_TYPE_SHIFT);17011701+ }17021702+ hdr->cw |= ((wqe_size / OCRDMA_WQE_STRIDE) << OCRDMA_WQE_SIZE_SHIFT);17031703+ return 0;17041704+}17051705+17061706+static int ocrdma_build_send(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,17071707+ struct ib_send_wr *wr)17081708+{17091709+ int status;17101710+ struct ocrdma_sge *sge;17111711+ u32 wqe_size = sizeof(*hdr);17121712+17131713+ if (qp->qp_type == IB_QPT_UD || qp->qp_type == IB_QPT_GSI) {17141714+ ocrdma_build_ud_hdr(qp, hdr, wr);17151715+ sge = (struct ocrdma_sge *)(hdr + 2);17161716+ wqe_size += sizeof(struct ocrdma_ewqe_ud_hdr);17171717+ } else17181718+ sge = (struct ocrdma_sge *)(hdr + 1);17191719+17201720+ status = ocrdma_build_inline_sges(qp, hdr, sge, wr, wqe_size);17211721+ return status;17221722+}17231723+17241724+static int ocrdma_build_write(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,17251725+ struct ib_send_wr *wr)17261726+{17271727+ int status;17281728+ struct ocrdma_sge *ext_rw = (struct ocrdma_sge *)(hdr + 1);17291729+ struct ocrdma_sge *sge = ext_rw + 1;17301730+ u32 wqe_size = sizeof(*hdr) + sizeof(*ext_rw);17311731+17321732+ status = ocrdma_build_inline_sges(qp, hdr, sge, wr, wqe_size);17331733+ if (status)17341734+ return status;17351735+ ext_rw->addr_lo = wr->wr.rdma.remote_addr;17361736+ ext_rw->addr_hi = upper_32_bits(wr->wr.rdma.remote_addr);17371737+ ext_rw->lrkey = wr->wr.rdma.rkey;17381738+ ext_rw->len = hdr->total_len;17391739+ return 0;17401740+}17411741+17421742+static void ocrdma_build_read(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,17431743+ struct ib_send_wr *wr)17441744+{17451745+ struct ocrdma_sge *ext_rw = (struct ocrdma_sge *)(hdr + 1);17461746+ struct ocrdma_sge *sge = ext_rw + 1;17471747+ u32 wqe_size = ((wr->num_sge + 1) * sizeof(struct ocrdma_sge)) +17481748+ sizeof(struct ocrdma_hdr_wqe);17491749+17501750+ ocrdma_build_sges(hdr, sge, wr->num_sge, wr->sg_list);17511751+ hdr->cw |= ((wqe_size / OCRDMA_WQE_STRIDE) << OCRDMA_WQE_SIZE_SHIFT);17521752+ hdr->cw |= (OCRDMA_READ << OCRDMA_WQE_OPCODE_SHIFT);17531753+ hdr->cw |= (OCRDMA_TYPE_LKEY << OCRDMA_WQE_TYPE_SHIFT);17541754+17551755+ ext_rw->addr_lo = wr->wr.rdma.remote_addr;17561756+ ext_rw->addr_hi = upper_32_bits(wr->wr.rdma.remote_addr);17571757+ ext_rw->lrkey = wr->wr.rdma.rkey;17581758+ ext_rw->len = hdr->total_len;17591759+}17601760+17611761+static void ocrdma_ring_sq_db(struct ocrdma_qp *qp)17621762+{17631763+ u32 val = qp->sq.dbid | (1 << 16);17641764+17651765+ iowrite32(val, qp->sq_db);17661766+}17671767+17681768+int ocrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,17691769+ struct ib_send_wr **bad_wr)17701770+{17711771+ int status = 0;17721772+ struct ocrdma_qp *qp = get_ocrdma_qp(ibqp);17731773+ struct ocrdma_hdr_wqe *hdr;17741774+ unsigned long flags;17751775+17761776+ spin_lock_irqsave(&qp->q_lock, flags);17771777+ if (qp->state != OCRDMA_QPS_RTS && qp->state != OCRDMA_QPS_SQD) {17781778+ spin_unlock_irqrestore(&qp->q_lock, flags);17791779+ return -EINVAL;17801780+ }17811781+17821782+ while (wr) {17831783+ if (ocrdma_hwq_free_cnt(&qp->sq) == 0 ||17841784+ wr->num_sge > qp->sq.max_sges) {17851785+ status = -ENOMEM;17861786+ break;17871787+ }17881788+ hdr = ocrdma_hwq_head(&qp->sq);17891789+ hdr->cw = 0;17901790+ if (wr->send_flags & IB_SEND_SIGNALED)17911791+ hdr->cw |= (OCRDMA_FLAG_SIG << OCRDMA_WQE_FLAGS_SHIFT);17921792+ if (wr->send_flags & IB_SEND_FENCE)17931793+ hdr->cw |=17941794+ (OCRDMA_FLAG_FENCE_L << OCRDMA_WQE_FLAGS_SHIFT);17951795+ if (wr->send_flags & IB_SEND_SOLICITED)17961796+ hdr->cw |=17971797+ (OCRDMA_FLAG_SOLICIT << OCRDMA_WQE_FLAGS_SHIFT);17981798+ hdr->total_len = 0;17991799+ switch (wr->opcode) {18001800+ case IB_WR_SEND_WITH_IMM:18011801+ hdr->cw |= (OCRDMA_FLAG_IMM << OCRDMA_WQE_FLAGS_SHIFT);18021802+ hdr->immdt = ntohl(wr->ex.imm_data);18031803+ case IB_WR_SEND:18041804+ hdr->cw |= (OCRDMA_SEND << OCRDMA_WQE_OPCODE_SHIFT);18051805+ ocrdma_build_send(qp, hdr, wr);18061806+ break;18071807+ case IB_WR_SEND_WITH_INV:18081808+ hdr->cw |= (OCRDMA_FLAG_INV << OCRDMA_WQE_FLAGS_SHIFT);18091809+ hdr->cw |= (OCRDMA_SEND << OCRDMA_WQE_OPCODE_SHIFT);18101810+ hdr->lkey = wr->ex.invalidate_rkey;18111811+ status = ocrdma_build_send(qp, hdr, wr);18121812+ break;18131813+ case IB_WR_RDMA_WRITE_WITH_IMM:18141814+ hdr->cw |= (OCRDMA_FLAG_IMM << OCRDMA_WQE_FLAGS_SHIFT);18151815+ hdr->immdt = ntohl(wr->ex.imm_data);18161816+ case IB_WR_RDMA_WRITE:18171817+ hdr->cw |= (OCRDMA_WRITE << OCRDMA_WQE_OPCODE_SHIFT);18181818+ status = ocrdma_build_write(qp, hdr, wr);18191819+ break;18201820+ case IB_WR_RDMA_READ_WITH_INV:18211821+ hdr->cw |= (OCRDMA_FLAG_INV << OCRDMA_WQE_FLAGS_SHIFT);18221822+ case IB_WR_RDMA_READ:18231823+ ocrdma_build_read(qp, hdr, wr);18241824+ break;18251825+ case IB_WR_LOCAL_INV:18261826+ hdr->cw |=18271827+ (OCRDMA_LKEY_INV << OCRDMA_WQE_OPCODE_SHIFT);18281828+ hdr->cw |= (sizeof(struct ocrdma_hdr_wqe) /18291829+ OCRDMA_WQE_STRIDE) << OCRDMA_WQE_SIZE_SHIFT;18301830+ hdr->lkey = wr->ex.invalidate_rkey;18311831+ break;18321832+ default:18331833+ status = -EINVAL;18341834+ break;18351835+ }18361836+ if (status) {18371837+ *bad_wr = wr;18381838+ break;18391839+ }18401840+ if (wr->send_flags & IB_SEND_SIGNALED)18411841+ qp->wqe_wr_id_tbl[qp->sq.head].signaled = 1;18421842+ else18431843+ qp->wqe_wr_id_tbl[qp->sq.head].signaled = 0;18441844+ qp->wqe_wr_id_tbl[qp->sq.head].wrid = wr->wr_id;18451845+ ocrdma_cpu_to_le32(hdr, ((hdr->cw >> OCRDMA_WQE_SIZE_SHIFT) &18461846+ OCRDMA_WQE_SIZE_MASK) * OCRDMA_WQE_STRIDE);18471847+ /* make sure wqe is written before adapter can access it */18481848+ wmb();18491849+ /* inform hw to start processing it */18501850+ ocrdma_ring_sq_db(qp);18511851+18521852+ /* update pointer, counter for next wr */18531853+ ocrdma_hwq_inc_head(&qp->sq);18541854+ wr = wr->next;18551855+ }18561856+ spin_unlock_irqrestore(&qp->q_lock, flags);18571857+ return status;18581858+}18591859+18601860+static void ocrdma_ring_rq_db(struct ocrdma_qp *qp)18611861+{18621862+ u32 val = qp->rq.dbid | (1 << OCRDMA_GET_NUM_POSTED_SHIFT_VAL(qp));18631863+18641864+ iowrite32(val, qp->rq_db);18651865+}18661866+18671867+static void ocrdma_build_rqe(struct ocrdma_hdr_wqe *rqe, struct ib_recv_wr *wr,18681868+ u16 tag)18691869+{18701870+ u32 wqe_size = 0;18711871+ struct ocrdma_sge *sge;18721872+ if (wr->num_sge)18731873+ wqe_size = (wr->num_sge * sizeof(*sge)) + sizeof(*rqe);18741874+ else18751875+ wqe_size = sizeof(*sge) + sizeof(*rqe);18761876+18771877+ rqe->cw = ((wqe_size / OCRDMA_WQE_STRIDE) <<18781878+ OCRDMA_WQE_SIZE_SHIFT);18791879+ rqe->cw |= (OCRDMA_FLAG_SIG << OCRDMA_WQE_FLAGS_SHIFT);18801880+ rqe->cw |= (OCRDMA_TYPE_LKEY << OCRDMA_WQE_TYPE_SHIFT);18811881+ rqe->total_len = 0;18821882+ rqe->rsvd_tag = tag;18831883+ sge = (struct ocrdma_sge *)(rqe + 1);18841884+ ocrdma_build_sges(rqe, sge, wr->num_sge, wr->sg_list);18851885+ ocrdma_cpu_to_le32(rqe, wqe_size);18861886+}18871887+18881888+int ocrdma_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,18891889+ struct ib_recv_wr **bad_wr)18901890+{18911891+ int status = 0;18921892+ unsigned long flags;18931893+ struct ocrdma_qp *qp = get_ocrdma_qp(ibqp);18941894+ struct ocrdma_hdr_wqe *rqe;18951895+18961896+ spin_lock_irqsave(&qp->q_lock, flags);18971897+ if (qp->state == OCRDMA_QPS_RST || qp->state == OCRDMA_QPS_ERR) {18981898+ spin_unlock_irqrestore(&qp->q_lock, flags);18991899+ *bad_wr = wr;19001900+ return -EINVAL;19011901+ }19021902+ while (wr) {19031903+ if (ocrdma_hwq_free_cnt(&qp->rq) == 0 ||19041904+ wr->num_sge > qp->rq.max_sges) {19051905+ *bad_wr = wr;19061906+ status = -ENOMEM;19071907+ break;19081908+ }19091909+ rqe = ocrdma_hwq_head(&qp->rq);19101910+ ocrdma_build_rqe(rqe, wr, 0);19111911+19121912+ qp->rqe_wr_id_tbl[qp->rq.head] = wr->wr_id;19131913+ /* make sure rqe is written before adapter can access it */19141914+ wmb();19151915+19161916+ /* inform hw to start processing it */19171917+ ocrdma_ring_rq_db(qp);19181918+19191919+ /* update pointer, counter for next wr */19201920+ ocrdma_hwq_inc_head(&qp->rq);19211921+ wr = wr->next;19221922+ }19231923+ spin_unlock_irqrestore(&qp->q_lock, flags);19241924+ return status;19251925+}19261926+19271927+/* cqe for srq's rqe can potentially arrive out of order.19281928+ * index gives the entry in the shadow table where to store19291929+ * the wr_id. tag/index is returned in cqe to reference back19301930+ * for a given rqe.19311931+ */19321932+static int ocrdma_srq_get_idx(struct ocrdma_srq *srq)19331933+{19341934+ int row = 0;19351935+ int indx = 0;19361936+19371937+ for (row = 0; row < srq->bit_fields_len; row++) {19381938+ if (srq->idx_bit_fields[row]) {19391939+ indx = ffs(srq->idx_bit_fields[row]);19401940+ indx = (row * 32) + (indx - 1);19411941+ if (indx >= srq->rq.max_cnt)19421942+ BUG();19431943+ ocrdma_srq_toggle_bit(srq, indx);19441944+ break;19451945+ }19461946+ }19471947+19481948+ if (row == srq->bit_fields_len)19491949+ BUG();19501950+ return indx;19511951+}19521952+19531953+static void ocrdma_ring_srq_db(struct ocrdma_srq *srq)19541954+{19551955+ u32 val = srq->rq.dbid | (1 << 16);19561956+19571957+ iowrite32(val, srq->db + OCRDMA_DB_GEN2_SRQ_OFFSET);19581958+}19591959+19601960+int ocrdma_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,19611961+ struct ib_recv_wr **bad_wr)19621962+{19631963+ int status = 0;19641964+ unsigned long flags;19651965+ struct ocrdma_srq *srq;19661966+ struct ocrdma_hdr_wqe *rqe;19671967+ u16 tag;19681968+19691969+ srq = get_ocrdma_srq(ibsrq);19701970+19711971+ spin_lock_irqsave(&srq->q_lock, flags);19721972+ while (wr) {19731973+ if (ocrdma_hwq_free_cnt(&srq->rq) == 0 ||19741974+ wr->num_sge > srq->rq.max_sges) {19751975+ status = -ENOMEM;19761976+ *bad_wr = wr;19771977+ break;19781978+ }19791979+ tag = ocrdma_srq_get_idx(srq);19801980+ rqe = ocrdma_hwq_head(&srq->rq);19811981+ ocrdma_build_rqe(rqe, wr, tag);19821982+19831983+ srq->rqe_wr_id_tbl[tag] = wr->wr_id;19841984+ /* make sure rqe is written before adapter can perform DMA */19851985+ wmb();19861986+ /* inform hw to start processing it */19871987+ ocrdma_ring_srq_db(srq);19881988+ /* update pointer, counter for next wr */19891989+ ocrdma_hwq_inc_head(&srq->rq);19901990+ wr = wr->next;19911991+ }19921992+ spin_unlock_irqrestore(&srq->q_lock, flags);19931993+ return status;19941994+}19951995+19961996+static enum ib_wc_status ocrdma_to_ibwc_err(u16 status)19971997+{19981998+ enum ib_wc_status ibwc_status = IB_WC_GENERAL_ERR;19991999+20002000+ switch (status) {20012001+ case OCRDMA_CQE_GENERAL_ERR:20022002+ ibwc_status = IB_WC_GENERAL_ERR;20032003+ break;20042004+ case OCRDMA_CQE_LOC_LEN_ERR:20052005+ ibwc_status = IB_WC_LOC_LEN_ERR;20062006+ break;20072007+ case OCRDMA_CQE_LOC_QP_OP_ERR:20082008+ ibwc_status = IB_WC_LOC_QP_OP_ERR;20092009+ break;20102010+ case OCRDMA_CQE_LOC_EEC_OP_ERR:20112011+ ibwc_status = IB_WC_LOC_EEC_OP_ERR;20122012+ break;20132013+ case OCRDMA_CQE_LOC_PROT_ERR:20142014+ ibwc_status = IB_WC_LOC_PROT_ERR;20152015+ break;20162016+ case OCRDMA_CQE_WR_FLUSH_ERR:20172017+ ibwc_status = IB_WC_WR_FLUSH_ERR;20182018+ break;20192019+ case OCRDMA_CQE_MW_BIND_ERR:20202020+ ibwc_status = IB_WC_MW_BIND_ERR;20212021+ break;20222022+ case OCRDMA_CQE_BAD_RESP_ERR:20232023+ ibwc_status = IB_WC_BAD_RESP_ERR;20242024+ break;20252025+ case OCRDMA_CQE_LOC_ACCESS_ERR:20262026+ ibwc_status = IB_WC_LOC_ACCESS_ERR;20272027+ break;20282028+ case OCRDMA_CQE_REM_INV_REQ_ERR:20292029+ ibwc_status = IB_WC_REM_INV_REQ_ERR;20302030+ break;20312031+ case OCRDMA_CQE_REM_ACCESS_ERR:20322032+ ibwc_status = IB_WC_REM_ACCESS_ERR;20332033+ break;20342034+ case OCRDMA_CQE_REM_OP_ERR:20352035+ ibwc_status = IB_WC_REM_OP_ERR;20362036+ break;20372037+ case OCRDMA_CQE_RETRY_EXC_ERR:20382038+ ibwc_status = IB_WC_RETRY_EXC_ERR;20392039+ break;20402040+ case OCRDMA_CQE_RNR_RETRY_EXC_ERR:20412041+ ibwc_status = IB_WC_RNR_RETRY_EXC_ERR;20422042+ break;20432043+ case OCRDMA_CQE_LOC_RDD_VIOL_ERR:20442044+ ibwc_status = IB_WC_LOC_RDD_VIOL_ERR;20452045+ break;20462046+ case OCRDMA_CQE_REM_INV_RD_REQ_ERR:20472047+ ibwc_status = IB_WC_REM_INV_RD_REQ_ERR;20482048+ break;20492049+ case OCRDMA_CQE_REM_ABORT_ERR:20502050+ ibwc_status = IB_WC_REM_ABORT_ERR;20512051+ break;20522052+ case OCRDMA_CQE_INV_EECN_ERR:20532053+ ibwc_status = IB_WC_INV_EECN_ERR;20542054+ break;20552055+ case OCRDMA_CQE_INV_EEC_STATE_ERR:20562056+ ibwc_status = IB_WC_INV_EEC_STATE_ERR;20572057+ break;20582058+ case OCRDMA_CQE_FATAL_ERR:20592059+ ibwc_status = IB_WC_FATAL_ERR;20602060+ break;20612061+ case OCRDMA_CQE_RESP_TIMEOUT_ERR:20622062+ ibwc_status = IB_WC_RESP_TIMEOUT_ERR;20632063+ break;20642064+ default:20652065+ ibwc_status = IB_WC_GENERAL_ERR;20662066+ break;20672067+ };20682068+ return ibwc_status;20692069+}20702070+20712071+static void ocrdma_update_wc(struct ocrdma_qp *qp, struct ib_wc *ibwc,20722072+ u32 wqe_idx)20732073+{20742074+ struct ocrdma_hdr_wqe *hdr;20752075+ struct ocrdma_sge *rw;20762076+ int opcode;20772077+20782078+ hdr = ocrdma_hwq_head_from_idx(&qp->sq, wqe_idx);20792079+20802080+ ibwc->wr_id = qp->wqe_wr_id_tbl[wqe_idx].wrid;20812081+ /* Undo the hdr->cw swap */20822082+ opcode = le32_to_cpu(hdr->cw) & OCRDMA_WQE_OPCODE_MASK;20832083+ switch (opcode) {20842084+ case OCRDMA_WRITE:20852085+ ibwc->opcode = IB_WC_RDMA_WRITE;20862086+ break;20872087+ case OCRDMA_READ:20882088+ rw = (struct ocrdma_sge *)(hdr + 1);20892089+ ibwc->opcode = IB_WC_RDMA_READ;20902090+ ibwc->byte_len = rw->len;20912091+ break;20922092+ case OCRDMA_SEND:20932093+ ibwc->opcode = IB_WC_SEND;20942094+ break;20952095+ case OCRDMA_LKEY_INV:20962096+ ibwc->opcode = IB_WC_LOCAL_INV;20972097+ break;20982098+ default:20992099+ ibwc->status = IB_WC_GENERAL_ERR;21002100+ ocrdma_err("%s() invalid opcode received = 0x%x\n",21012101+ __func__, hdr->cw & OCRDMA_WQE_OPCODE_MASK);21022102+ break;21032103+ };21042104+}21052105+21062106+static void ocrdma_set_cqe_status_flushed(struct ocrdma_qp *qp,21072107+ struct ocrdma_cqe *cqe)21082108+{21092109+ if (is_cqe_for_sq(cqe)) {21102110+ cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu(21112111+ cqe->flags_status_srcqpn) &21122112+ ~OCRDMA_CQE_STATUS_MASK);21132113+ cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu(21142114+ cqe->flags_status_srcqpn) |21152115+ (OCRDMA_CQE_WR_FLUSH_ERR <<21162116+ OCRDMA_CQE_STATUS_SHIFT));21172117+ } else {21182118+ if (qp->qp_type == IB_QPT_UD || qp->qp_type == IB_QPT_GSI) {21192119+ cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu(21202120+ cqe->flags_status_srcqpn) &21212121+ ~OCRDMA_CQE_UD_STATUS_MASK);21222122+ cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu(21232123+ cqe->flags_status_srcqpn) |21242124+ (OCRDMA_CQE_WR_FLUSH_ERR <<21252125+ OCRDMA_CQE_UD_STATUS_SHIFT));21262126+ } else {21272127+ cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu(21282128+ cqe->flags_status_srcqpn) &21292129+ ~OCRDMA_CQE_STATUS_MASK);21302130+ cqe->flags_status_srcqpn = cpu_to_le32(le32_to_cpu(21312131+ cqe->flags_status_srcqpn) |21322132+ (OCRDMA_CQE_WR_FLUSH_ERR <<21332133+ OCRDMA_CQE_STATUS_SHIFT));21342134+ }21352135+ }21362136+}21372137+21382138+static bool ocrdma_update_err_cqe(struct ib_wc *ibwc, struct ocrdma_cqe *cqe,21392139+ struct ocrdma_qp *qp, int status)21402140+{21412141+ bool expand = false;21422142+21432143+ ibwc->byte_len = 0;21442144+ ibwc->qp = &qp->ibqp;21452145+ ibwc->status = ocrdma_to_ibwc_err(status);21462146+21472147+ ocrdma_flush_qp(qp);21482148+ ocrdma_qp_state_machine(qp, IB_QPS_ERR, NULL);21492149+21502150+ /* if wqe/rqe pending for which cqe needs to be returned,21512151+ * trigger inflating it.21522152+ */21532153+ if (!is_hw_rq_empty(qp) || !is_hw_sq_empty(qp)) {21542154+ expand = true;21552155+ ocrdma_set_cqe_status_flushed(qp, cqe);21562156+ }21572157+ return expand;21582158+}21592159+21602160+static int ocrdma_update_err_rcqe(struct ib_wc *ibwc, struct ocrdma_cqe *cqe,21612161+ struct ocrdma_qp *qp, int status)21622162+{21632163+ ibwc->opcode = IB_WC_RECV;21642164+ ibwc->wr_id = qp->rqe_wr_id_tbl[qp->rq.tail];21652165+ ocrdma_hwq_inc_tail(&qp->rq);21662166+21672167+ return ocrdma_update_err_cqe(ibwc, cqe, qp, status);21682168+}21692169+21702170+static int ocrdma_update_err_scqe(struct ib_wc *ibwc, struct ocrdma_cqe *cqe,21712171+ struct ocrdma_qp *qp, int status)21722172+{21732173+ ocrdma_update_wc(qp, ibwc, qp->sq.tail);21742174+ ocrdma_hwq_inc_tail(&qp->sq);21752175+21762176+ return ocrdma_update_err_cqe(ibwc, cqe, qp, status);21772177+}21782178+21792179+21802180+static bool ocrdma_poll_err_scqe(struct ocrdma_qp *qp,21812181+ struct ocrdma_cqe *cqe, struct ib_wc *ibwc,21822182+ bool *polled, bool *stop)21832183+{21842184+ bool expand;21852185+ int status = (le32_to_cpu(cqe->flags_status_srcqpn) &21862186+ OCRDMA_CQE_STATUS_MASK) >> OCRDMA_CQE_STATUS_SHIFT;21872187+21882188+ /* when hw sq is empty, but rq is not empty, so we continue21892189+ * to keep the cqe in order to get the cq event again.21902190+ */21912191+ if (is_hw_sq_empty(qp) && !is_hw_rq_empty(qp)) {21922192+ /* when cq for rq and sq is same, it is safe to return21932193+ * flush cqe for RQEs.21942194+ */21952195+ if (!qp->srq && (qp->sq_cq == qp->rq_cq)) {21962196+ *polled = true;21972197+ status = OCRDMA_CQE_WR_FLUSH_ERR;21982198+ expand = ocrdma_update_err_rcqe(ibwc, cqe, qp, status);21992199+ } else {22002200+ /* stop processing further cqe as this cqe is used for22012201+ * triggering cq event on buddy cq of RQ.22022202+ * When QP is destroyed, this cqe will be removed22032203+ * from the cq's hardware q.22042204+ */22052205+ *polled = false;22062206+ *stop = true;22072207+ expand = false;22082208+ }22092209+ } else {22102210+ *polled = true;22112211+ expand = ocrdma_update_err_scqe(ibwc, cqe, qp, status);22122212+ }22132213+ return expand;22142214+}22152215+22162216+static bool ocrdma_poll_success_scqe(struct ocrdma_qp *qp,22172217+ struct ocrdma_cqe *cqe,22182218+ struct ib_wc *ibwc, bool *polled)22192219+{22202220+ bool expand = false;22212221+ int tail = qp->sq.tail;22222222+ u32 wqe_idx;22232223+22242224+ if (!qp->wqe_wr_id_tbl[tail].signaled) {22252225+ expand = true; /* CQE cannot be consumed yet */22262226+ *polled = false; /* WC cannot be consumed yet */22272227+ } else {22282228+ ibwc->status = IB_WC_SUCCESS;22292229+ ibwc->wc_flags = 0;22302230+ ibwc->qp = &qp->ibqp;22312231+ ocrdma_update_wc(qp, ibwc, tail);22322232+ *polled = true;22332233+ wqe_idx = le32_to_cpu(cqe->wq.wqeidx) & OCRDMA_CQE_WQEIDX_MASK;22342234+ if (tail != wqe_idx)22352235+ expand = true; /* Coalesced CQE can't be consumed yet */22362236+ }22372237+ ocrdma_hwq_inc_tail(&qp->sq);22382238+ return expand;22392239+}22402240+22412241+static bool ocrdma_poll_scqe(struct ocrdma_qp *qp, struct ocrdma_cqe *cqe,22422242+ struct ib_wc *ibwc, bool *polled, bool *stop)22432243+{22442244+ int status;22452245+ bool expand;22462246+22472247+ status = (le32_to_cpu(cqe->flags_status_srcqpn) &22482248+ OCRDMA_CQE_STATUS_MASK) >> OCRDMA_CQE_STATUS_SHIFT;22492249+22502250+ if (status == OCRDMA_CQE_SUCCESS)22512251+ expand = ocrdma_poll_success_scqe(qp, cqe, ibwc, polled);22522252+ else22532253+ expand = ocrdma_poll_err_scqe(qp, cqe, ibwc, polled, stop);22542254+ return expand;22552255+}22562256+22572257+static int ocrdma_update_ud_rcqe(struct ib_wc *ibwc, struct ocrdma_cqe *cqe)22582258+{22592259+ int status;22602260+22612261+ status = (le32_to_cpu(cqe->flags_status_srcqpn) &22622262+ OCRDMA_CQE_UD_STATUS_MASK) >> OCRDMA_CQE_UD_STATUS_SHIFT;22632263+ ibwc->src_qp = le32_to_cpu(cqe->flags_status_srcqpn) &22642264+ OCRDMA_CQE_SRCQP_MASK;22652265+ ibwc->pkey_index = le32_to_cpu(cqe->ud.rxlen_pkey) &22662266+ OCRDMA_CQE_PKEY_MASK;22672267+ ibwc->wc_flags = IB_WC_GRH;22682268+ ibwc->byte_len = (le32_to_cpu(cqe->ud.rxlen_pkey) >>22692269+ OCRDMA_CQE_UD_XFER_LEN_SHIFT);22702270+ return status;22712271+}22722272+22732273+static void ocrdma_update_free_srq_cqe(struct ib_wc *ibwc,22742274+ struct ocrdma_cqe *cqe,22752275+ struct ocrdma_qp *qp)22762276+{22772277+ unsigned long flags;22782278+ struct ocrdma_srq *srq;22792279+ u32 wqe_idx;22802280+22812281+ srq = get_ocrdma_srq(qp->ibqp.srq);22822282+ wqe_idx = le32_to_cpu(cqe->rq.buftag_qpn) >> OCRDMA_CQE_BUFTAG_SHIFT;22832283+ ibwc->wr_id = srq->rqe_wr_id_tbl[wqe_idx];22842284+ spin_lock_irqsave(&srq->q_lock, flags);22852285+ ocrdma_srq_toggle_bit(srq, wqe_idx);22862286+ spin_unlock_irqrestore(&srq->q_lock, flags);22872287+ ocrdma_hwq_inc_tail(&srq->rq);22882288+}22892289+22902290+static bool ocrdma_poll_err_rcqe(struct ocrdma_qp *qp, struct ocrdma_cqe *cqe,22912291+ struct ib_wc *ibwc, bool *polled, bool *stop,22922292+ int status)22932293+{22942294+ bool expand;22952295+22962296+ /* when hw_rq is empty, but wq is not empty, so continue22972297+ * to keep the cqe to get the cq event again.22982298+ */22992299+ if (is_hw_rq_empty(qp) && !is_hw_sq_empty(qp)) {23002300+ if (!qp->srq && (qp->sq_cq == qp->rq_cq)) {23012301+ *polled = true;23022302+ status = OCRDMA_CQE_WR_FLUSH_ERR;23032303+ expand = ocrdma_update_err_scqe(ibwc, cqe, qp, status);23042304+ } else {23052305+ *polled = false;23062306+ *stop = true;23072307+ expand = false;23082308+ }23092309+ } else23102310+ expand = ocrdma_update_err_rcqe(ibwc, cqe, qp, status);23112311+ return expand;23122312+}23132313+23142314+static void ocrdma_poll_success_rcqe(struct ocrdma_qp *qp,23152315+ struct ocrdma_cqe *cqe, struct ib_wc *ibwc)23162316+{23172317+ ibwc->opcode = IB_WC_RECV;23182318+ ibwc->qp = &qp->ibqp;23192319+ ibwc->status = IB_WC_SUCCESS;23202320+23212321+ if (qp->qp_type == IB_QPT_UD || qp->qp_type == IB_QPT_GSI)23222322+ ocrdma_update_ud_rcqe(ibwc, cqe);23232323+ else23242324+ ibwc->byte_len = le32_to_cpu(cqe->rq.rxlen);23252325+23262326+ if (is_cqe_imm(cqe)) {23272327+ ibwc->ex.imm_data = htonl(le32_to_cpu(cqe->rq.lkey_immdt));23282328+ ibwc->wc_flags |= IB_WC_WITH_IMM;23292329+ } else if (is_cqe_wr_imm(cqe)) {23302330+ ibwc->opcode = IB_WC_RECV_RDMA_WITH_IMM;23312331+ ibwc->ex.imm_data = htonl(le32_to_cpu(cqe->rq.lkey_immdt));23322332+ ibwc->wc_flags |= IB_WC_WITH_IMM;23332333+ } else if (is_cqe_invalidated(cqe)) {23342334+ ibwc->ex.invalidate_rkey = le32_to_cpu(cqe->rq.lkey_immdt);23352335+ ibwc->wc_flags |= IB_WC_WITH_INVALIDATE;23362336+ }23372337+ if (qp->ibqp.srq)23382338+ ocrdma_update_free_srq_cqe(ibwc, cqe, qp);23392339+ else {23402340+ ibwc->wr_id = qp->rqe_wr_id_tbl[qp->rq.tail];23412341+ ocrdma_hwq_inc_tail(&qp->rq);23422342+ }23432343+}23442344+23452345+static bool ocrdma_poll_rcqe(struct ocrdma_qp *qp, struct ocrdma_cqe *cqe,23462346+ struct ib_wc *ibwc, bool *polled, bool *stop)23472347+{23482348+ int status;23492349+ bool expand = false;23502350+23512351+ ibwc->wc_flags = 0;23522352+ if (qp->qp_type == IB_QPT_UD || qp->qp_type == IB_QPT_GSI)23532353+ status = (le32_to_cpu(cqe->flags_status_srcqpn) &23542354+ OCRDMA_CQE_UD_STATUS_MASK) >>23552355+ OCRDMA_CQE_UD_STATUS_SHIFT;23562356+ else23572357+ status = (le32_to_cpu(cqe->flags_status_srcqpn) &23582358+ OCRDMA_CQE_STATUS_MASK) >> OCRDMA_CQE_STATUS_SHIFT;23592359+23602360+ if (status == OCRDMA_CQE_SUCCESS) {23612361+ *polled = true;23622362+ ocrdma_poll_success_rcqe(qp, cqe, ibwc);23632363+ } else {23642364+ expand = ocrdma_poll_err_rcqe(qp, cqe, ibwc, polled, stop,23652365+ status);23662366+ }23672367+ return expand;23682368+}23692369+23702370+static void ocrdma_change_cq_phase(struct ocrdma_cq *cq, struct ocrdma_cqe *cqe,23712371+ u16 cur_getp)23722372+{23732373+ if (cq->phase_change) {23742374+ if (cur_getp == 0)23752375+ cq->phase = (~cq->phase & OCRDMA_CQE_VALID);23762376+ } else23772377+ /* clear valid bit */23782378+ cqe->flags_status_srcqpn = 0;23792379+}23802380+23812381+static int ocrdma_poll_hwcq(struct ocrdma_cq *cq, int num_entries,23822382+ struct ib_wc *ibwc)23832383+{23842384+ u16 qpn = 0;23852385+ int i = 0;23862386+ bool expand = false;23872387+ int polled_hw_cqes = 0;23882388+ struct ocrdma_qp *qp = NULL;23892389+ struct ocrdma_dev *dev = cq->dev;23902390+ struct ocrdma_cqe *cqe;23912391+ u16 cur_getp; bool polled = false; bool stop = false;23922392+23932393+ cur_getp = cq->getp;23942394+ while (num_entries) {23952395+ cqe = cq->va + cur_getp;23962396+ /* check whether valid cqe or not */23972397+ if (!is_cqe_valid(cq, cqe))23982398+ break;23992399+ qpn = (le32_to_cpu(cqe->cmn.qpn) & OCRDMA_CQE_QPN_MASK);24002400+ /* ignore discarded cqe */24012401+ if (qpn == 0)24022402+ goto skip_cqe;24032403+ qp = dev->qp_tbl[qpn];24042404+ BUG_ON(qp == NULL);24052405+24062406+ if (is_cqe_for_sq(cqe)) {24072407+ expand = ocrdma_poll_scqe(qp, cqe, ibwc, &polled,24082408+ &stop);24092409+ } else {24102410+ expand = ocrdma_poll_rcqe(qp, cqe, ibwc, &polled,24112411+ &stop);24122412+ }24132413+ if (expand)24142414+ goto expand_cqe;24152415+ if (stop)24162416+ goto stop_cqe;24172417+ /* clear qpn to avoid duplicate processing by discard_cqe() */24182418+ cqe->cmn.qpn = 0;24192419+skip_cqe:24202420+ polled_hw_cqes += 1;24212421+ cur_getp = (cur_getp + 1) % cq->max_hw_cqe;24222422+ ocrdma_change_cq_phase(cq, cqe, cur_getp);24232423+expand_cqe:24242424+ if (polled) {24252425+ num_entries -= 1;24262426+ i += 1;24272427+ ibwc = ibwc + 1;24282428+ polled = false;24292429+ }24302430+ }24312431+stop_cqe:24322432+ cq->getp = cur_getp;24332433+ if (polled_hw_cqes || expand || stop) {24342434+ ocrdma_ring_cq_db(dev, cq->id, cq->armed, cq->solicited,24352435+ polled_hw_cqes);24362436+ }24372437+ return i;24382438+}24392439+24402440+/* insert error cqe if the QP's SQ or RQ's CQ matches the CQ under poll. */24412441+static int ocrdma_add_err_cqe(struct ocrdma_cq *cq, int num_entries,24422442+ struct ocrdma_qp *qp, struct ib_wc *ibwc)24432443+{24442444+ int err_cqes = 0;24452445+24462446+ while (num_entries) {24472447+ if (is_hw_sq_empty(qp) && is_hw_rq_empty(qp))24482448+ break;24492449+ if (!is_hw_sq_empty(qp) && qp->sq_cq == cq) {24502450+ ocrdma_update_wc(qp, ibwc, qp->sq.tail);24512451+ ocrdma_hwq_inc_tail(&qp->sq);24522452+ } else if (!is_hw_rq_empty(qp) && qp->rq_cq == cq) {24532453+ ibwc->wr_id = qp->rqe_wr_id_tbl[qp->rq.tail];24542454+ ocrdma_hwq_inc_tail(&qp->rq);24552455+ } else24562456+ return err_cqes;24572457+ ibwc->byte_len = 0;24582458+ ibwc->status = IB_WC_WR_FLUSH_ERR;24592459+ ibwc = ibwc + 1;24602460+ err_cqes += 1;24612461+ num_entries -= 1;24622462+ }24632463+ return err_cqes;24642464+}24652465+24662466+int ocrdma_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)24672467+{24682468+ int cqes_to_poll = num_entries;24692469+ struct ocrdma_cq *cq = NULL;24702470+ unsigned long flags;24712471+ struct ocrdma_dev *dev;24722472+ int num_os_cqe = 0, err_cqes = 0;24732473+ struct ocrdma_qp *qp;24742474+24752475+ cq = get_ocrdma_cq(ibcq);24762476+ dev = cq->dev;24772477+24782478+ /* poll cqes from adapter CQ */24792479+ spin_lock_irqsave(&cq->cq_lock, flags);24802480+ num_os_cqe = ocrdma_poll_hwcq(cq, cqes_to_poll, wc);24812481+ spin_unlock_irqrestore(&cq->cq_lock, flags);24822482+ cqes_to_poll -= num_os_cqe;24832483+24842484+ if (cqes_to_poll) {24852485+ wc = wc + num_os_cqe;24862486+ /* adapter returns single error cqe when qp moves to24872487+ * error state. So insert error cqes with wc_status as24882488+ * FLUSHED for pending WQEs and RQEs of QP's SQ and RQ24892489+ * respectively which uses this CQ.24902490+ */24912491+ spin_lock_irqsave(&dev->flush_q_lock, flags);24922492+ list_for_each_entry(qp, &cq->sq_head, sq_entry) {24932493+ if (cqes_to_poll == 0)24942494+ break;24952495+ err_cqes = ocrdma_add_err_cqe(cq, cqes_to_poll, qp, wc);24962496+ cqes_to_poll -= err_cqes;24972497+ num_os_cqe += err_cqes;24982498+ wc = wc + err_cqes;24992499+ }25002500+ spin_unlock_irqrestore(&dev->flush_q_lock, flags);25012501+ }25022502+ return num_os_cqe;25032503+}25042504+25052505+int ocrdma_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags cq_flags)25062506+{25072507+ struct ocrdma_cq *cq;25082508+ unsigned long flags;25092509+ struct ocrdma_dev *dev;25102510+ u16 cq_id;25112511+ u16 cur_getp;25122512+ struct ocrdma_cqe *cqe;25132513+25142514+ cq = get_ocrdma_cq(ibcq);25152515+ cq_id = cq->id;25162516+ dev = cq->dev;25172517+25182518+ spin_lock_irqsave(&cq->cq_lock, flags);25192519+ if (cq_flags & IB_CQ_NEXT_COMP || cq_flags & IB_CQ_SOLICITED)25202520+ cq->armed = true;25212521+ if (cq_flags & IB_CQ_SOLICITED)25222522+ cq->solicited = true;25232523+25242524+ cur_getp = cq->getp;25252525+ cqe = cq->va + cur_getp;25262526+25272527+ /* check whether any valid cqe exist or not, if not then safe to25282528+ * arm. If cqe is not yet consumed, then let it get consumed and then25292529+ * we arm it to avoid false interrupts.25302530+ */25312531+ if (!is_cqe_valid(cq, cqe) || cq->arm_needed) {25322532+ cq->arm_needed = false;25332533+ ocrdma_ring_cq_db(dev, cq_id, cq->armed, cq->solicited, 0);25342534+ }25352535+ spin_unlock_irqrestore(&cq->cq_lock, flags);25362536+ return 0;25372537+}
+94
drivers/infiniband/hw/ocrdma/ocrdma_verbs.h
···11+/*******************************************************************22+ * This file is part of the Emulex RoCE Device Driver for *33+ * RoCE (RDMA over Converged Ethernet) adapters. *44+ * Copyright (C) 2008-2012 Emulex. All rights reserved. *55+ * EMULEX and SLI are trademarks of Emulex. *66+ * www.emulex.com *77+ * *88+ * This program is free software; you can redistribute it and/or *99+ * modify it under the terms of version 2 of the GNU General *1010+ * Public License as published by the Free Software Foundation. *1111+ * This program is distributed in the hope that it will be useful. *1212+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *1313+ * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *1414+ * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *1515+ * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *1616+ * TO BE LEGALLY INVALID. See the GNU General Public License for *1717+ * more details, a copy of which can be found in the file COPYING *1818+ * included with this package. *1919+ *2020+ * Contact Information:2121+ * linux-drivers@emulex.com2222+ *2323+ * Emulex2424+ * 3333 Susan Street2525+ * Costa Mesa, CA 926262626+ *******************************************************************/2727+2828+#ifndef __OCRDMA_VERBS_H__2929+#define __OCRDMA_VERBS_H__3030+3131+#include <linux/version.h>3232+int ocrdma_post_send(struct ib_qp *, struct ib_send_wr *,3333+ struct ib_send_wr **bad_wr);3434+int ocrdma_post_recv(struct ib_qp *, struct ib_recv_wr *,3535+ struct ib_recv_wr **bad_wr);3636+3737+int ocrdma_poll_cq(struct ib_cq *, int num_entries, struct ib_wc *wc);3838+int ocrdma_arm_cq(struct ib_cq *, enum ib_cq_notify_flags flags);3939+4040+int ocrdma_query_device(struct ib_device *, struct ib_device_attr *props);4141+int ocrdma_query_port(struct ib_device *, u8 port, struct ib_port_attr *props);4242+int ocrdma_modify_port(struct ib_device *, u8 port, int mask,4343+ struct ib_port_modify *props);4444+4545+void ocrdma_get_guid(struct ocrdma_dev *, u8 *guid);4646+int ocrdma_query_gid(struct ib_device *, u8 port,4747+ int index, union ib_gid *gid);4848+int ocrdma_query_pkey(struct ib_device *, u8 port, u16 index, u16 *pkey);4949+5050+struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *,5151+ struct ib_udata *);5252+int ocrdma_dealloc_ucontext(struct ib_ucontext *);5353+5454+int ocrdma_mmap(struct ib_ucontext *, struct vm_area_struct *vma);5555+5656+struct ib_pd *ocrdma_alloc_pd(struct ib_device *,5757+ struct ib_ucontext *, struct ib_udata *);5858+int ocrdma_dealloc_pd(struct ib_pd *pd);5959+6060+struct ib_cq *ocrdma_create_cq(struct ib_device *, int entries, int vector,6161+ struct ib_ucontext *, struct ib_udata *);6262+int ocrdma_resize_cq(struct ib_cq *, int cqe, struct ib_udata *);6363+int ocrdma_destroy_cq(struct ib_cq *);6464+6565+struct ib_qp *ocrdma_create_qp(struct ib_pd *,6666+ struct ib_qp_init_attr *attrs,6767+ struct ib_udata *);6868+int _ocrdma_modify_qp(struct ib_qp *, struct ib_qp_attr *attr,6969+ int attr_mask);7070+int ocrdma_modify_qp(struct ib_qp *, struct ib_qp_attr *attr,7171+ int attr_mask, struct ib_udata *udata);7272+int ocrdma_query_qp(struct ib_qp *,7373+ struct ib_qp_attr *qp_attr,7474+ int qp_attr_mask, struct ib_qp_init_attr *);7575+int ocrdma_destroy_qp(struct ib_qp *);7676+7777+struct ib_srq *ocrdma_create_srq(struct ib_pd *, struct ib_srq_init_attr *,7878+ struct ib_udata *);7979+int ocrdma_modify_srq(struct ib_srq *, struct ib_srq_attr *,8080+ enum ib_srq_attr_mask, struct ib_udata *);8181+int ocrdma_query_srq(struct ib_srq *, struct ib_srq_attr *);8282+int ocrdma_destroy_srq(struct ib_srq *);8383+int ocrdma_post_srq_recv(struct ib_srq *, struct ib_recv_wr *,8484+ struct ib_recv_wr **bad_recv_wr);8585+8686+int ocrdma_dereg_mr(struct ib_mr *);8787+struct ib_mr *ocrdma_get_dma_mr(struct ib_pd *, int acc);8888+struct ib_mr *ocrdma_reg_kernel_mr(struct ib_pd *,8989+ struct ib_phys_buf *buffer_list,9090+ int num_phys_buf, int acc, u64 *iova_start);9191+struct ib_mr *ocrdma_reg_user_mr(struct ib_pd *, u64 start, u64 length,9292+ u64 virt, int acc, struct ib_udata *);9393+9494+#endif /* __OCRDMA_VERBS_H__ */
+24-17
drivers/infiniband/hw/qib/qib.h
···530530 /* qib_lflags driver is waiting for */531531 u32 state_wanted;532532 spinlock_t lflags_lock;533533- /* number of (port-specific) interrupts for this port -- saturates... */534534- u32 int_counter;535533536534 /* ref count for each pkey */537535 atomic_t pkeyrefs[4];···541543 u64 *statusp;542544543545 /* SendDMA related entries */544544- spinlock_t sdma_lock;545545- struct qib_sdma_state sdma_state;546546- unsigned long sdma_buf_jiffies;547547- struct qib_sdma_desc *sdma_descq;548548- u64 sdma_descq_added;549549- u64 sdma_descq_removed;550550- u16 sdma_descq_cnt;551551- u16 sdma_descq_tail;552552- u16 sdma_descq_head;553553- u16 sdma_next_intr;554554- u16 sdma_reset_wait;555555- u8 sdma_generation;556556- struct tasklet_struct sdma_sw_clean_up_task;557557- struct list_head sdma_activelist;558546547547+ /* read mostly */548548+ struct qib_sdma_desc *sdma_descq;549549+ struct qib_sdma_state sdma_state;559550 dma_addr_t sdma_descq_phys;560551 volatile __le64 *sdma_head_dma; /* DMA'ed by chip */561552 dma_addr_t sdma_head_phys;553553+ u16 sdma_descq_cnt;554554+555555+ /* read/write using lock */556556+ spinlock_t sdma_lock ____cacheline_aligned_in_smp;557557+ struct list_head sdma_activelist;558558+ u64 sdma_descq_added;559559+ u64 sdma_descq_removed;560560+ u16 sdma_descq_tail;561561+ u16 sdma_descq_head;562562+ u8 sdma_generation;563563+564564+ struct tasklet_struct sdma_sw_clean_up_task565565+ ____cacheline_aligned_in_smp;562566563567 wait_queue_head_t state_wait; /* for state_wanted */564568···873873 * pio_writing.874874 */875875 spinlock_t pioavail_lock;876876-876876+ /*877877+ * index of last buffer to optimize search for next878878+ */879879+ u32 last_pio;880880+ /*881881+ * min kernel pio buffer to optimize search882882+ */883883+ u32 min_kernel_pio;877884 /*878885 * Shadow copies of registers; size indicates read access size.879886 * Most of them are readonly, but some are write-only register,
···244244 int ret = 0;245245 int delta;246246247247- ohdr = &qp->s_hdr.u.oth;247247+ ohdr = &qp->s_hdr->u.oth;248248 if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)249249- ohdr = &qp->s_hdr.u.l.oth;249249+ ohdr = &qp->s_hdr->u.l.oth;250250251251 /*252252 * The lock is needed to synchronize between the sending tasklet,
+6-6
drivers/infiniband/hw/qib/qib_ruc.c
···688688 nwords = (qp->s_cur_size + extra_bytes) >> 2;689689 lrh0 = QIB_LRH_BTH;690690 if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {691691- qp->s_hdrwords += qib_make_grh(ibp, &qp->s_hdr.u.l.grh,691691+ qp->s_hdrwords += qib_make_grh(ibp, &qp->s_hdr->u.l.grh,692692 &qp->remote_ah_attr.grh,693693 qp->s_hdrwords, nwords);694694 lrh0 = QIB_LRH_GRH;695695 }696696 lrh0 |= ibp->sl_to_vl[qp->remote_ah_attr.sl] << 12 |697697 qp->remote_ah_attr.sl << 4;698698- qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);699699- qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);700700- qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);701701- qp->s_hdr.lrh[3] = cpu_to_be16(ppd_from_ibp(ibp)->lid |698698+ qp->s_hdr->lrh[0] = cpu_to_be16(lrh0);699699+ qp->s_hdr->lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);700700+ qp->s_hdr->lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);701701+ qp->s_hdr->lrh[3] = cpu_to_be16(ppd_from_ibp(ibp)->lid |702702 qp->remote_ah_attr.src_path_bits);703703 bth0 |= qib_get_pkey(ibp, qp->s_pkey_index);704704 bth0 |= extra_bytes << 20;···758758 * If the packet cannot be sent now, return and759759 * the send tasklet will be woken up later.760760 */761761- if (qib_verbs_send(qp, &qp->s_hdr, qp->s_hdrwords,761761+ if (qib_verbs_send(qp, qp->s_hdr, qp->s_hdrwords,762762 qp->s_cur_sge, qp->s_cur_size))763763 break;764764 /* Record that s_hdr is empty. */
+5-2
drivers/infiniband/hw/qib/qib_sysfs.c
···503503 struct qib_devdata *dd = dd_from_dev(dev);504504505505 /* Return the number of user ports (contexts) available. */506506- return scnprintf(buf, PAGE_SIZE, "%u\n", dd->cfgctxts -507507- dd->first_user_ctxt);506506+ /* The calculation below deals with a special case where507507+ * cfgctxts is set to 1 on a single-port board. */508508+ return scnprintf(buf, PAGE_SIZE, "%u\n",509509+ (dd->first_user_ctxt > dd->cfgctxts) ? 0 :510510+ (dd->cfgctxts - dd->first_user_ctxt));508511}509512510513static ssize_t show_nfreectxts(struct device *device,
+17-8
drivers/infiniband/hw/qib/qib_tx.c
···295295296296 nbufs = last - first + 1; /* number in range to check */297297 if (dd->upd_pio_shadow) {298298+update_shadow:298299 /*299300 * Minor optimization. If we had no buffers on last call,300301 * start out by doing the update; continue and do scan even···305304 updated++;306305 }307306 i = first;308308-rescan:309307 /*310308 * While test_and_set_bit() is atomic, we do that and then the311309 * change_bit(), and the pair is not. See if this is the cause312310 * of the remaining armlaunch errors.313311 */314312 spin_lock_irqsave(&dd->pioavail_lock, flags);313313+ if (dd->last_pio >= first && dd->last_pio <= last)314314+ i = dd->last_pio + 1;315315+ if (!first)316316+ /* adjust to min possible */317317+ nbufs = last - dd->min_kernel_pio + 1;315318 for (j = 0; j < nbufs; j++, i++) {316319 if (i > last)317317- i = first;320320+ i = !first ? dd->min_kernel_pio : first;318321 if (__test_and_set_bit((2 * i) + 1, shadow))319322 continue;320323 /* flip generation bit */321324 __change_bit(2 * i, shadow);322325 /* remember that the buffer can be written to now */323326 __set_bit(i, dd->pio_writing);327327+ if (!first && first != last) /* first == last on VL15, avoid */328328+ dd->last_pio = i;324329 break;325330 }326331 spin_unlock_irqrestore(&dd->pioavail_lock, flags);327332328333 if (j == nbufs) {329329- if (!updated) {334334+ if (!updated)330335 /*331336 * First time through; shadow exhausted, but may be332337 * buffers available, try an update and then rescan.333338 */334334- update_send_bufs(dd);335335- updated++;336336- i = first;337337- goto rescan;338338- }339339+ goto update_shadow;339340 no_send_bufs(dd);340341 buf = NULL;341342 } else {···425422 __clear_bit(QLOGIC_IB_SENDPIOAVAIL_CHECK_SHIFT426423 + start, dd->pioavailshadow);427424 __set_bit(start, dd->pioavailkernel);425425+ if ((start >> 1) < dd->min_kernel_pio)426426+ dd->min_kernel_pio = start >> 1;428427 } else {429428 __set_bit(start + QLOGIC_IB_SENDPIOAVAIL_BUSY_SHIFT,430429 dd->pioavailshadow);431430 __clear_bit(start, dd->pioavailkernel);431431+ if ((start >> 1) > dd->min_kernel_pio)432432+ dd->min_kernel_pio = start >> 1;432433 }433434 start += 2;434435 }435436437437+ if (dd->min_kernel_pio > 0 && dd->last_pio < dd->min_kernel_pio - 1)438438+ dd->last_pio = dd->min_kernel_pio - 1;436439 spin_unlock_irqrestore(&dd->pioavail_lock, flags);437440438441 dd->f_txchk_change(dd, ostart, len, avail, rcd);
···321321322322 if (ah_attr->ah_flags & IB_AH_GRH) {323323 /* Header size in 32-bit words. */324324- qp->s_hdrwords += qib_make_grh(ibp, &qp->s_hdr.u.l.grh,324324+ qp->s_hdrwords += qib_make_grh(ibp, &qp->s_hdr->u.l.grh,325325 &ah_attr->grh,326326 qp->s_hdrwords, nwords);327327 lrh0 = QIB_LRH_GRH;328328- ohdr = &qp->s_hdr.u.l.oth;328328+ ohdr = &qp->s_hdr->u.l.oth;329329 /*330330 * Don't worry about sending to locally attached multicast331331 * QPs. It is unspecified by the spec. what happens.···333333 } else {334334 /* Header size in 32-bit words. */335335 lrh0 = QIB_LRH_BTH;336336- ohdr = &qp->s_hdr.u.oth;336336+ ohdr = &qp->s_hdr->u.oth;337337 }338338 if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) {339339 qp->s_hdrwords++;···346346 lrh0 |= 0xF000; /* Set VL (see ch. 13.5.3.1) */347347 else348348 lrh0 |= ibp->sl_to_vl[ah_attr->sl] << 12;349349- qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);350350- qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */351351- qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);349349+ qp->s_hdr->lrh[0] = cpu_to_be16(lrh0);350350+ qp->s_hdr->lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */351351+ qp->s_hdr->lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC);352352 lid = ppd->lid;353353 if (lid) {354354 lid |= ah_attr->src_path_bits & ((1 << ppd->lmc) - 1);355355- qp->s_hdr.lrh[3] = cpu_to_be16(lid);355355+ qp->s_hdr->lrh[3] = cpu_to_be16(lid);356356 } else357357- qp->s_hdr.lrh[3] = IB_LID_PERMISSIVE;357357+ qp->s_hdr->lrh[3] = IB_LID_PERMISSIVE;358358 if (wqe->wr.send_flags & IB_SEND_SOLICITED)359359 bth0 |= IB_BTH_SOLICITED;360360 bth0 |= extra_bytes << 20;
+86-67
drivers/infiniband/hw/qib/qib_verbs.h
···367367368368struct qib_rq {369369 struct qib_rwq *wq;370370- spinlock_t lock; /* protect changes in this struct */371370 u32 size; /* size of RWQE array */372371 u8 max_sge;372372+ spinlock_t lock /* protect changes in this struct */373373+ ____cacheline_aligned_in_smp;373374};374375375376struct qib_srq {···413412 */414413struct qib_qp {415414 struct ib_qp ibqp;416416- struct qib_qp *next; /* link list for QPN hash table */417417- struct qib_qp *timer_next; /* link list for qib_ib_timer() */418418- struct list_head iowait; /* link for wait PIO buf */419419- struct list_head rspwait; /* link for waititing to respond */415415+ /* read mostly fields above and below */420416 struct ib_ah_attr remote_ah_attr;421417 struct ib_ah_attr alt_ah_attr;422422- struct qib_ib_header s_hdr; /* next packet header to send */423423- atomic_t refcount;424424- wait_queue_head_t wait;425425- wait_queue_head_t wait_dma;426426- struct timer_list s_timer;427427- struct work_struct s_work;418418+ struct qib_qp *next; /* link list for QPN hash table */419419+ struct qib_swqe *s_wq; /* send work queue */428420 struct qib_mmap_info *ip;429429- struct qib_sge_state *s_cur_sge;430430- struct qib_verbs_txreq *s_tx;431431- struct qib_mregion *s_rdma_mr;432432- struct qib_sge_state s_sge; /* current send request data */433433- struct qib_ack_entry s_ack_queue[QIB_MAX_RDMA_ATOMIC + 1];434434- struct qib_sge_state s_ack_rdma_sge;421421+ struct qib_ib_header *s_hdr; /* next packet header to send */422422+ unsigned long timeout_jiffies; /* computed from timeout */423423+424424+ enum ib_mtu path_mtu;425425+ u32 remote_qpn;426426+ u32 pmtu; /* decoded from path_mtu */427427+ u32 qkey; /* QKEY for this QP (for UD or RD) */428428+ u32 s_size; /* send work queue size */429429+ u32 s_rnr_timeout; /* number of milliseconds for RNR timeout */430430+431431+ u8 state; /* QP state */432432+ u8 qp_access_flags;433433+ u8 alt_timeout; /* Alternate path timeout for this QP */434434+ u8 timeout; /* Timeout for this QP */435435+ u8 s_srate;436436+ u8 s_mig_state;437437+ u8 port_num;438438+ u8 s_pkey_index; /* PKEY index to use */439439+ u8 s_alt_pkey_index; /* Alternate path PKEY index to use */440440+ u8 r_max_rd_atomic; /* max number of RDMA read/atomic to receive */441441+ u8 s_max_rd_atomic; /* max number of RDMA read/atomic to send */442442+ u8 s_retry_cnt; /* number of times to retry */443443+ u8 s_rnr_retry_cnt;444444+ u8 r_min_rnr_timer; /* retry timeout value for RNR NAKs */445445+ u8 s_max_sge; /* size of s_wq->sg_list */446446+ u8 s_draining;447447+448448+ /* start of read/write fields */449449+450450+ atomic_t refcount ____cacheline_aligned_in_smp;451451+ wait_queue_head_t wait;452452+453453+454454+ struct qib_ack_entry s_ack_queue[QIB_MAX_RDMA_ATOMIC + 1]455455+ ____cacheline_aligned_in_smp;435456 struct qib_sge_state s_rdma_read_sge;457457+458458+ spinlock_t r_lock ____cacheline_aligned_in_smp; /* used for APM */459459+ unsigned long r_aflags;460460+ u64 r_wr_id; /* ID for current receive WQE */461461+ u32 r_ack_psn; /* PSN for next ACK or atomic ACK */462462+ u32 r_len; /* total length of r_sge */463463+ u32 r_rcv_len; /* receive data len processed */464464+ u32 r_psn; /* expected rcv packet sequence number */465465+ u32 r_msn; /* message sequence number */466466+467467+ u8 r_state; /* opcode of last packet received */468468+ u8 r_flags;469469+ u8 r_head_ack_queue; /* index into s_ack_queue[] */470470+471471+ struct list_head rspwait; /* link for waititing to respond */472472+436473 struct qib_sge_state r_sge; /* current receive data */437437- spinlock_t r_lock; /* used for APM */438438- spinlock_t s_lock;439439- atomic_t s_dma_busy;474474+ struct qib_rq r_rq; /* receive work queue */475475+476476+ spinlock_t s_lock ____cacheline_aligned_in_smp;477477+ struct qib_sge_state *s_cur_sge;440478 u32 s_flags;479479+ struct qib_verbs_txreq *s_tx;480480+ struct qib_swqe *s_wqe;481481+ struct qib_sge_state s_sge; /* current send request data */482482+ struct qib_mregion *s_rdma_mr;483483+ atomic_t s_dma_busy;441484 u32 s_cur_size; /* size of send packet in bytes */442485 u32 s_len; /* total length of s_sge */443486 u32 s_rdma_read_len; /* total length of s_rdma_read_sge */···492447 u32 s_psn; /* current packet sequence number */493448 u32 s_ack_rdma_psn; /* PSN for sending RDMA read responses */494449 u32 s_ack_psn; /* PSN for acking sends and RDMA writes */495495- u32 s_rnr_timeout; /* number of milliseconds for RNR timeout */496496- u32 r_ack_psn; /* PSN for next ACK or atomic ACK */497497- u64 r_wr_id; /* ID for current receive WQE */498498- unsigned long r_aflags;499499- u32 r_len; /* total length of r_sge */500500- u32 r_rcv_len; /* receive data len processed */501501- u32 r_psn; /* expected rcv packet sequence number */502502- u32 r_msn; /* message sequence number */503503- u16 s_hdrwords; /* size of s_hdr in 32 bit words */504504- u16 s_rdma_ack_cnt;505505- u8 state; /* QP state */506506- u8 s_state; /* opcode of last packet sent */507507- u8 s_ack_state; /* opcode of packet to ACK */508508- u8 s_nak_state; /* non-zero if NAK is pending */509509- u8 r_state; /* opcode of last packet received */510510- u8 r_nak_state; /* non-zero if NAK is pending */511511- u8 r_min_rnr_timer; /* retry timeout value for RNR NAKs */512512- u8 r_flags;513513- u8 r_max_rd_atomic; /* max number of RDMA read/atomic to receive */514514- u8 r_head_ack_queue; /* index into s_ack_queue[] */515515- u8 qp_access_flags;516516- u8 s_max_sge; /* size of s_wq->sg_list */517517- u8 s_retry_cnt; /* number of times to retry */518518- u8 s_rnr_retry_cnt;519519- u8 s_retry; /* requester retry counter */520520- u8 s_rnr_retry; /* requester RNR retry counter */521521- u8 s_pkey_index; /* PKEY index to use */522522- u8 s_alt_pkey_index; /* Alternate path PKEY index to use */523523- u8 s_max_rd_atomic; /* max number of RDMA read/atomic to send */524524- u8 s_num_rd_atomic; /* number of RDMA read/atomic pending */525525- u8 s_tail_ack_queue; /* index into s_ack_queue[] */526526- u8 s_srate;527527- u8 s_draining;528528- u8 s_mig_state;529529- u8 timeout; /* Timeout for this QP */530530- u8 alt_timeout; /* Alternate path timeout for this QP */531531- u8 port_num;532532- enum ib_mtu path_mtu;533533- u32 pmtu; /* decoded from path_mtu */534534- u32 remote_qpn;535535- u32 qkey; /* QKEY for this QP (for UD or RD) */536536- u32 s_size; /* send work queue size */537450 u32 s_head; /* new entries added here */538451 u32 s_tail; /* next entry to process */539452 u32 s_cur; /* current work queue entry */···499496 u32 s_last; /* last completed entry */500497 u32 s_ssn; /* SSN of tail entry */501498 u32 s_lsn; /* limit sequence number (credit) */502502- unsigned long timeout_jiffies; /* computed from timeout */503503- struct qib_swqe *s_wq; /* send work queue */504504- struct qib_swqe *s_wqe;505505- struct qib_rq r_rq; /* receive work queue */506506- struct qib_sge r_sg_list[0]; /* verified SGEs */499499+ u16 s_hdrwords; /* size of s_hdr in 32 bit words */500500+ u16 s_rdma_ack_cnt;501501+ u8 s_state; /* opcode of last packet sent */502502+ u8 s_ack_state; /* opcode of packet to ACK */503503+ u8 s_nak_state; /* non-zero if NAK is pending */504504+ u8 r_nak_state; /* non-zero if NAK is pending */505505+ u8 s_retry; /* requester retry counter */506506+ u8 s_rnr_retry; /* requester RNR retry counter */507507+ u8 s_num_rd_atomic; /* number of RDMA read/atomic pending */508508+ u8 s_tail_ack_queue; /* index into s_ack_queue[] */509509+510510+ struct qib_sge_state s_ack_rdma_sge;511511+ struct timer_list s_timer;512512+ struct list_head iowait; /* link for wait PIO buf */513513+514514+ struct work_struct s_work;515515+516516+ wait_queue_head_t wait_dma;517517+518518+ struct qib_sge r_sg_list[0] /* verified SGEs */519519+ ____cacheline_aligned_in_smp;507520};508521509522/*
+2-3
drivers/infiniband/ulp/iser/iscsi_iser.c
···573573574574 err = iser_connect(ib_conn, NULL, (struct sockaddr_in *)dst_addr,575575 non_blocking);576576- if (err) {577577- iscsi_destroy_endpoint(ep);576576+ if (err)578577 return ERR_PTR(err);579579- }578578+580579 return ep;581580}582581
···10561056/* The HW can come up in either of the following multi-channel modes10571057 * based on the skew/IPL.10581058 */10591059+#define RDMA_ENABLED 0x410591060#define FLEX10_MODE 0x40010601061#define VNIC_MODE 0x2000010611062#define UMC_ENABLED 0x1000000
···21032103static void be_msix_enable(struct be_adapter *adapter)21042104{21052105#define BE_MIN_MSIX_VECTORS 121062106- int i, status, num_vec;21062106+ int i, status, num_vec, num_roce_vec = 0;2107210721082108 /* If RSS queues are not used, need a vec for default RX Q */21092109 num_vec = min(be_num_rss_want(adapter), num_online_cpus());21102110+ if (be_roce_supported(adapter)) {21112111+ num_roce_vec = min_t(u32, MAX_ROCE_MSIX_VECTORS,21122112+ (num_online_cpus() + 1));21132113+ num_roce_vec = min(num_roce_vec, MAX_ROCE_EQS);21142114+ num_vec += num_roce_vec;21152115+ num_vec = min(num_vec, MAX_MSIX_VECTORS);21162116+ }21102117 num_vec = max(num_vec, BE_MIN_MSIX_VECTORS);2111211821122119 for (i = 0; i < num_vec; i++)···21302123 }21312124 return;21322125done:21332133- adapter->num_msix_vec = num_vec;21262126+ if (be_roce_supported(adapter)) {21272127+ if (num_vec > num_roce_vec) {21282128+ adapter->num_msix_vec = num_vec - num_roce_vec;21292129+ adapter->num_msix_roce_vec =21302130+ num_vec - adapter->num_msix_vec;21312131+ } else {21322132+ adapter->num_msix_vec = num_vec;21332133+ adapter->num_msix_roce_vec = 0;21342134+ }21352135+ } else21362136+ adapter->num_msix_vec = num_vec;21342137 return;21352138}21362139···22992282 struct be_eq_obj *eqo;23002283 int i;2301228422852285+ be_roce_dev_close(adapter);22862286+23022287 be_async_mcc_disable(adapter);2303228823042289 if (!lancer_chip(adapter))···24092390 if (!status)24102391 be_link_status_update(adapter, link_status);2411239223932393+ be_roce_dev_open(adapter);24122394 return 0;24132395err:24142396 be_close(adapter->netdev);···31423122 iounmap(adapter->csr);31433123 if (adapter->db)31443124 iounmap(adapter->db);31253125+ if (adapter->roce_db.base)31263126+ pci_iounmap(adapter->pdev, adapter->roce_db.base);31273127+}31283128+31293129+static int lancer_roce_map_pci_bars(struct be_adapter *adapter)31303130+{31313131+ struct pci_dev *pdev = adapter->pdev;31323132+ u8 __iomem *addr;31333133+31343134+ addr = pci_iomap(pdev, 2, 0);31353135+ if (addr == NULL)31363136+ return -ENOMEM;31373137+31383138+ adapter->roce_db.base = addr;31393139+ adapter->roce_db.io_addr = pci_resource_start(pdev, 2);31403140+ adapter->roce_db.size = 8192;31413141+ adapter->roce_db.total_size = pci_resource_len(pdev, 2);31423142+ return 0;31453143}3146314431473145static int be_map_pci_bars(struct be_adapter *adapter)···31683130 int db_reg;3169313131703132 if (lancer_chip(adapter)) {31713171- addr = ioremap_nocache(pci_resource_start(adapter->pdev, 0),31723172- pci_resource_len(adapter->pdev, 0));31733173- if (addr == NULL)31743174- return -ENOMEM;31753175- adapter->db = addr;31333133+ if (be_type_2_3(adapter)) {31343134+ addr = ioremap_nocache(31353135+ pci_resource_start(adapter->pdev, 0),31363136+ pci_resource_len(adapter->pdev, 0));31373137+ if (addr == NULL)31383138+ return -ENOMEM;31393139+ adapter->db = addr;31403140+ }31413141+ if (adapter->if_type == SLI_INTF_TYPE_3) {31423142+ if (lancer_roce_map_pci_bars(adapter))31433143+ goto pci_map_err;31443144+ }31763145 return 0;31773146 }31783147···32043159 if (addr == NULL)32053160 goto pci_map_err;32063161 adapter->db = addr;32073207-31623162+ if (adapter->sli_family == SKYHAWK_SLI_FAMILY) {31633163+ adapter->roce_db.size = 4096;31643164+ adapter->roce_db.io_addr =31653165+ pci_resource_start(adapter->pdev, db_reg);31663166+ adapter->roce_db.total_size =31673167+ pci_resource_len(adapter->pdev, db_reg);31683168+ }32083169 return 0;32093170pci_map_err:32103171 be_unmap_pci_bars(adapter);32113172 return -ENOMEM;32123173}32133213-3214317432153175static void be_ctrl_cleanup(struct be_adapter *adapter)32163176{···33223272 if (!adapter)33233273 return;3324327432753275+ be_roce_dev_remove(adapter);32763276+33253277 unregister_netdev(adapter->netdev);3326327833273279 be_clear(adapter);···34023350 break;34033351 case BE_DEVICE_ID2:34043352 case OC_DEVICE_ID2:34053405- case OC_DEVICE_ID5:34063353 adapter->generation = BE_GEN3;34073354 break;34083355 case OC_DEVICE_ID3:34093356 case OC_DEVICE_ID4:34103357 pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf);33583358+ adapter->if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >>33593359+ SLI_INTF_IF_TYPE_SHIFT;34113360 if_type = (sli_intf & SLI_INTF_IF_TYPE_MASK) >>34123361 SLI_INTF_IF_TYPE_SHIFT;34133413-34143362 if (((sli_intf & SLI_INTF_VALID_MASK) != SLI_INTF_VALID) ||34153415- if_type != 0x02) {33633363+ !be_type_2_3(adapter)) {33643364+ dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n");33653365+ return -EINVAL;33663366+ }33673367+ adapter->sli_family = ((sli_intf & SLI_INTF_FAMILY_MASK) >>33683368+ SLI_INTF_FAMILY_SHIFT);33693369+ adapter->generation = BE_GEN3;33703370+ break;33713371+ case OC_DEVICE_ID5:33723372+ pci_read_config_dword(pdev, SLI_INTF_REG_OFFSET, &sli_intf);33733373+ if ((sli_intf & SLI_INTF_VALID_MASK) != SLI_INTF_VALID) {34163374 dev_err(&pdev->dev, "SLI_INTF reg val is not valid\n");34173375 return -EINVAL;34183376 }···36813619 status = register_netdev(netdev);36823620 if (status != 0)36833621 goto unsetup;36223622+36233623+ be_roce_dev_add(adapter);3684362436853625 dev_info(&pdev->dev, "%s: %s port %d\n", netdev->name, nic_name(pdev),36863626 adapter->port_num);
+182
drivers/net/ethernet/emulex/benet/be_roce.c
···11+/*22+ * Copyright (C) 2005 - 2011 Emulex33+ * All rights reserved.44+ *55+ * This program is free software; you can redistribute it and/or66+ * modify it under the terms of the GNU General Public License version 277+ * as published by the Free Software Foundation. The full GNU General88+ * Public License is included in this distribution in the file called COPYING.99+ *1010+ * Contact Information:1111+ * linux-drivers@emulex.com1212+ *1313+ * Emulex1414+ * 3333 Susan Street1515+ * Costa Mesa, CA 926261616+ */1717+1818+#include <linux/mutex.h>1919+#include <linux/list.h>2020+#include <linux/netdevice.h>2121+#include <linux/module.h>2222+2323+#include "be.h"2424+#include "be_cmds.h"2525+2626+static struct ocrdma_driver *ocrdma_drv;2727+static LIST_HEAD(be_adapter_list);2828+static DEFINE_MUTEX(be_adapter_list_lock);2929+3030+static void _be_roce_dev_add(struct be_adapter *adapter)3131+{3232+ struct be_dev_info dev_info;3333+ int i, num_vec;3434+ struct pci_dev *pdev = adapter->pdev;3535+3636+ if (!ocrdma_drv)3737+ return;3838+ if (pdev->device == OC_DEVICE_ID5) {3939+ /* only msix is supported on these devices */4040+ if (!msix_enabled(adapter))4141+ return;4242+ /* DPP region address and length */4343+ dev_info.dpp_unmapped_addr = pci_resource_start(pdev, 2);4444+ dev_info.dpp_unmapped_len = pci_resource_len(pdev, 2);4545+ } else {4646+ dev_info.dpp_unmapped_addr = 0;4747+ dev_info.dpp_unmapped_len = 0;4848+ }4949+ dev_info.pdev = adapter->pdev;5050+ if (adapter->sli_family == SKYHAWK_SLI_FAMILY)5151+ dev_info.db = adapter->db;5252+ else5353+ dev_info.db = adapter->roce_db.base;5454+ dev_info.unmapped_db = adapter->roce_db.io_addr;5555+ dev_info.db_page_size = adapter->roce_db.size;5656+ dev_info.db_total_size = adapter->roce_db.total_size;5757+ dev_info.netdev = adapter->netdev;5858+ memcpy(dev_info.mac_addr, adapter->netdev->dev_addr, ETH_ALEN);5959+ dev_info.dev_family = adapter->sli_family;6060+ if (msix_enabled(adapter)) {6161+ /* provide all the vectors, so that EQ creation response6262+ * can decide which one to use.6363+ */6464+ num_vec = adapter->num_msix_vec + adapter->num_msix_roce_vec;6565+ dev_info.intr_mode = BE_INTERRUPT_MODE_MSIX;6666+ dev_info.msix.num_vectors = min(num_vec, MAX_ROCE_MSIX_VECTORS);6767+ /* provide start index of the vector,6868+ * so in case of linear usage,6969+ * it can use the base as starting point.7070+ */7171+ dev_info.msix.start_vector = adapter->num_evt_qs;7272+ for (i = 0; i < dev_info.msix.num_vectors; i++) {7373+ dev_info.msix.vector_list[i] =7474+ adapter->msix_entries[i].vector;7575+ }7676+ } else {7777+ dev_info.msix.num_vectors = 0;7878+ dev_info.intr_mode = BE_INTERRUPT_MODE_INTX;7979+ }8080+ adapter->ocrdma_dev = ocrdma_drv->add(&dev_info);8181+}8282+8383+void be_roce_dev_add(struct be_adapter *adapter)8484+{8585+ if (be_roce_supported(adapter)) {8686+ INIT_LIST_HEAD(&adapter->entry);8787+ mutex_lock(&be_adapter_list_lock);8888+ list_add_tail(&adapter->entry, &be_adapter_list);8989+9090+ /* invoke add() routine of roce driver only if9191+ * valid driver registered with add method and add() is not yet9292+ * invoked on a given adapter.9393+ */9494+ _be_roce_dev_add(adapter);9595+ mutex_unlock(&be_adapter_list_lock);9696+ }9797+}9898+9999+void _be_roce_dev_remove(struct be_adapter *adapter)100100+{101101+ if (ocrdma_drv && ocrdma_drv->remove && adapter->ocrdma_dev)102102+ ocrdma_drv->remove(adapter->ocrdma_dev);103103+ adapter->ocrdma_dev = NULL;104104+}105105+106106+void be_roce_dev_remove(struct be_adapter *adapter)107107+{108108+ if (be_roce_supported(adapter)) {109109+ mutex_lock(&be_adapter_list_lock);110110+ _be_roce_dev_remove(adapter);111111+ list_del(&adapter->entry);112112+ mutex_unlock(&be_adapter_list_lock);113113+ }114114+}115115+116116+void _be_roce_dev_open(struct be_adapter *adapter)117117+{118118+ if (ocrdma_drv && adapter->ocrdma_dev &&119119+ ocrdma_drv->state_change_handler)120120+ ocrdma_drv->state_change_handler(adapter->ocrdma_dev, 0);121121+}122122+123123+void be_roce_dev_open(struct be_adapter *adapter)124124+{125125+ if (be_roce_supported(adapter)) {126126+ mutex_lock(&be_adapter_list_lock);127127+ _be_roce_dev_open(adapter);128128+ mutex_unlock(&be_adapter_list_lock);129129+ }130130+}131131+132132+void _be_roce_dev_close(struct be_adapter *adapter)133133+{134134+ if (ocrdma_drv && adapter->ocrdma_dev &&135135+ ocrdma_drv->state_change_handler)136136+ ocrdma_drv->state_change_handler(adapter->ocrdma_dev, 1);137137+}138138+139139+void be_roce_dev_close(struct be_adapter *adapter)140140+{141141+ if (be_roce_supported(adapter)) {142142+ mutex_lock(&be_adapter_list_lock);143143+ _be_roce_dev_close(adapter);144144+ mutex_unlock(&be_adapter_list_lock);145145+ }146146+}147147+148148+int be_roce_register_driver(struct ocrdma_driver *drv)149149+{150150+ struct be_adapter *dev;151151+152152+ mutex_lock(&be_adapter_list_lock);153153+ if (ocrdma_drv) {154154+ mutex_unlock(&be_adapter_list_lock);155155+ return -EINVAL;156156+ }157157+ ocrdma_drv = drv;158158+ list_for_each_entry(dev, &be_adapter_list, entry) {159159+ struct net_device *netdev;160160+ _be_roce_dev_add(dev);161161+ netdev = dev->netdev;162162+ if (netif_running(netdev) && netif_oper_up(netdev))163163+ _be_roce_dev_open(dev);164164+ }165165+ mutex_unlock(&be_adapter_list_lock);166166+ return 0;167167+}168168+EXPORT_SYMBOL(be_roce_register_driver);169169+170170+void be_roce_unregister_driver(struct ocrdma_driver *drv)171171+{172172+ struct be_adapter *dev;173173+174174+ mutex_lock(&be_adapter_list_lock);175175+ list_for_each_entry(dev, &be_adapter_list, entry) {176176+ if (dev->ocrdma_dev)177177+ _be_roce_dev_remove(dev);178178+ }179179+ ocrdma_drv = NULL;180180+ mutex_unlock(&be_adapter_list_lock);181181+}182182+EXPORT_SYMBOL(be_roce_unregister_driver);
+75
drivers/net/ethernet/emulex/benet/be_roce.h
···11+/*22+ * Copyright (C) 2005 - 2011 Emulex33+ * All rights reserved.44+ *55+ * This program is free software; you can redistribute it and/or66+ * modify it under the terms of the GNU General Public License version 277+ * as published by the Free Software Foundation. The full GNU General88+ * Public License is included in this distribution in the file called COPYING.99+ *1010+ * Contact Information:1111+ * linux-drivers@emulex.com1212+ *1313+ * Emulex1414+ * 3333 Susan Street1515+ * Costa Mesa, CA 926261616+ */1717+1818+#ifndef BE_ROCE_H1919+#define BE_ROCE_H2020+2121+#include <linux/pci.h>2222+#include <linux/netdevice.h>2323+2424+struct ocrdma_dev;2525+2626+enum be_interrupt_mode {2727+ BE_INTERRUPT_MODE_MSIX = 0,2828+ BE_INTERRUPT_MODE_INTX = 1,2929+ BE_INTERRUPT_MODE_MSI = 2,3030+};3131+3232+#define MAX_ROCE_MSIX_VECTORS 163333+struct be_dev_info {3434+ u8 __iomem *db;3535+ u64 unmapped_db;3636+ u32 db_page_size;3737+ u32 db_total_size;3838+ u64 dpp_unmapped_addr;3939+ u32 dpp_unmapped_len;4040+ struct pci_dev *pdev;4141+ struct net_device *netdev;4242+ u8 mac_addr[ETH_ALEN];4343+ u32 dev_family;4444+ enum be_interrupt_mode intr_mode;4545+ struct {4646+ int num_vectors;4747+ int start_vector;4848+ u32 vector_list[MAX_ROCE_MSIX_VECTORS];4949+ } msix;5050+};5151+5252+/* ocrdma driver register's the callback functions with nic driver. */5353+struct ocrdma_driver {5454+ unsigned char name[32];5555+ struct ocrdma_dev *(*add) (struct be_dev_info *dev_info);5656+ void (*remove) (struct ocrdma_dev *);5757+ void (*state_change_handler) (struct ocrdma_dev *, u32 new_state);5858+};5959+6060+enum {6161+ BE_DEV_UP = 0,6262+ BE_DEV_DOWN = 16363+};6464+6565+/* APIs for RoCE driver to register callback handlers,6666+ * which will be invoked when device is added, removed, ifup, ifdown6767+ */6868+int be_roce_register_driver(struct ocrdma_driver *drv);6969+void be_roce_unregister_driver(struct ocrdma_driver *drv);7070+7171+/* API for RoCE driver to issue mailbox commands */7272+int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload,7373+ int wrb_payload_size, u16 *cmd_status, u16 *ext_status);7474+7575+#endif /* BE_ROCE_H */