Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2016 Hisilicon Limited.
0003  *
0004  * This software is available to you under a choice of one of two
0005  * licenses.  You may choose to be licensed under the terms of the GNU
0006  * General Public License (GPL) Version 2, available from the file
0007  * COPYING in the main directory of this source tree, or the
0008  * OpenIB.org BSD license below:
0009  *
0010  *     Redistribution and use in source and binary forms, with or
0011  *     without modification, are permitted provided that the following
0012  *     conditions are met:
0013  *
0014  *      - Redistributions of source code must retain the above
0015  *        copyright notice, this list of conditions and the following
0016  *        disclaimer.
0017  *
0018  *      - Redistributions in binary form must reproduce the above
0019  *        copyright notice, this list of conditions and the following
0020  *        disclaimer in the documentation and/or other materials
0021  *        provided with the distribution.
0022  *
0023  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0024  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0025  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0026  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0027  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0028  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0029  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0030  * SOFTWARE.
0031  */
0032 
0033 #include <linux/dmapool.h>
0034 #include "hns_roce_common.h"
0035 #include "hns_roce_device.h"
0036 #include "hns_roce_cmd.h"
0037 
0038 #define CMD_POLL_TOKEN 0xffff
0039 #define CMD_MAX_NUM 32
0040 
0041 static int hns_roce_cmd_mbox_post_hw(struct hns_roce_dev *hr_dev,
0042                      struct hns_roce_mbox_msg *mbox_msg)
0043 {
0044     return hr_dev->hw->post_mbox(hr_dev, mbox_msg);
0045 }
0046 
0047 /* this should be called with "poll_sem" */
0048 static int __hns_roce_cmd_mbox_poll(struct hns_roce_dev *hr_dev,
0049                     struct hns_roce_mbox_msg *mbox_msg)
0050 {
0051     int ret;
0052 
0053     ret = hns_roce_cmd_mbox_post_hw(hr_dev, mbox_msg);
0054     if (ret) {
0055         dev_err_ratelimited(hr_dev->dev,
0056                     "failed to post mailbox 0x%x in poll mode, ret = %d.\n",
0057                     mbox_msg->cmd, ret);
0058         return ret;
0059     }
0060 
0061     return hr_dev->hw->poll_mbox_done(hr_dev);
0062 }
0063 
0064 static int hns_roce_cmd_mbox_poll(struct hns_roce_dev *hr_dev,
0065                   struct hns_roce_mbox_msg *mbox_msg)
0066 {
0067     int ret;
0068 
0069     down(&hr_dev->cmd.poll_sem);
0070     ret = __hns_roce_cmd_mbox_poll(hr_dev, mbox_msg);
0071     up(&hr_dev->cmd.poll_sem);
0072 
0073     return ret;
0074 }
0075 
0076 void hns_roce_cmd_event(struct hns_roce_dev *hr_dev, u16 token, u8 status,
0077             u64 out_param)
0078 {
0079     struct hns_roce_cmd_context *context =
0080         &hr_dev->cmd.context[token % hr_dev->cmd.max_cmds];
0081 
0082     if (unlikely(token != context->token)) {
0083         dev_err_ratelimited(hr_dev->dev,
0084                     "[cmd] invalid ae token 0x%x, context token is 0x%x.\n",
0085                     token, context->token);
0086         return;
0087     }
0088 
0089     context->result = (status == HNS_ROCE_CMD_SUCCESS) ? 0 : (-EIO);
0090     context->out_param = out_param;
0091     complete(&context->done);
0092 }
0093 
0094 static int __hns_roce_cmd_mbox_wait(struct hns_roce_dev *hr_dev,
0095                     struct hns_roce_mbox_msg *mbox_msg)
0096 {
0097     struct hns_roce_cmdq *cmd = &hr_dev->cmd;
0098     struct hns_roce_cmd_context *context;
0099     struct device *dev = hr_dev->dev;
0100     int ret;
0101 
0102     spin_lock(&cmd->context_lock);
0103 
0104     do {
0105         context = &cmd->context[cmd->free_head];
0106         cmd->free_head = context->next;
0107     } while (context->busy);
0108 
0109     context->busy = 1;
0110     context->token += cmd->max_cmds;
0111 
0112     spin_unlock(&cmd->context_lock);
0113 
0114     reinit_completion(&context->done);
0115 
0116     mbox_msg->token = context->token;
0117     ret = hns_roce_cmd_mbox_post_hw(hr_dev, mbox_msg);
0118     if (ret) {
0119         dev_err_ratelimited(dev,
0120                     "failed to post mailbox 0x%x in event mode, ret = %d.\n",
0121                     mbox_msg->cmd, ret);
0122         goto out;
0123     }
0124 
0125     if (!wait_for_completion_timeout(&context->done,
0126                 msecs_to_jiffies(HNS_ROCE_CMD_TIMEOUT_MSECS))) {
0127         dev_err_ratelimited(dev, "[cmd] token 0x%x mailbox 0x%x timeout.\n",
0128                     context->token, mbox_msg->cmd);
0129         ret = -EBUSY;
0130         goto out;
0131     }
0132 
0133     ret = context->result;
0134     if (ret)
0135         dev_err_ratelimited(dev, "[cmd] token 0x%x mailbox 0x%x error %d.\n",
0136                     context->token, mbox_msg->cmd, ret);
0137 
0138 out:
0139     context->busy = 0;
0140     return ret;
0141 }
0142 
0143 static int hns_roce_cmd_mbox_wait(struct hns_roce_dev *hr_dev,
0144                   struct hns_roce_mbox_msg *mbox_msg)
0145 {
0146     int ret;
0147 
0148     down(&hr_dev->cmd.event_sem);
0149     ret = __hns_roce_cmd_mbox_wait(hr_dev, mbox_msg);
0150     up(&hr_dev->cmd.event_sem);
0151 
0152     return ret;
0153 }
0154 
0155 int hns_roce_cmd_mbox(struct hns_roce_dev *hr_dev, u64 in_param, u64 out_param,
0156               u8 cmd, unsigned long tag)
0157 {
0158     struct hns_roce_mbox_msg mbox_msg = {};
0159     bool is_busy;
0160 
0161     if (hr_dev->hw->chk_mbox_avail)
0162         if (!hr_dev->hw->chk_mbox_avail(hr_dev, &is_busy))
0163             return is_busy ? -EBUSY : 0;
0164 
0165     mbox_msg.in_param = in_param;
0166     mbox_msg.out_param = out_param;
0167     mbox_msg.cmd = cmd;
0168     mbox_msg.tag = tag;
0169 
0170     if (hr_dev->cmd.use_events) {
0171         mbox_msg.event_en = 1;
0172 
0173         return hns_roce_cmd_mbox_wait(hr_dev, &mbox_msg);
0174     } else {
0175         mbox_msg.event_en = 0;
0176         mbox_msg.token = CMD_POLL_TOKEN;
0177 
0178         return hns_roce_cmd_mbox_poll(hr_dev, &mbox_msg);
0179     }
0180 }
0181 
0182 int hns_roce_cmd_init(struct hns_roce_dev *hr_dev)
0183 {
0184     sema_init(&hr_dev->cmd.poll_sem, 1);
0185     hr_dev->cmd.use_events = 0;
0186     hr_dev->cmd.max_cmds = CMD_MAX_NUM;
0187     hr_dev->cmd.pool = dma_pool_create("hns_roce_cmd", hr_dev->dev,
0188                        HNS_ROCE_MAILBOX_SIZE,
0189                        HNS_ROCE_MAILBOX_SIZE, 0);
0190     if (!hr_dev->cmd.pool)
0191         return -ENOMEM;
0192 
0193     return 0;
0194 }
0195 
0196 void hns_roce_cmd_cleanup(struct hns_roce_dev *hr_dev)
0197 {
0198     dma_pool_destroy(hr_dev->cmd.pool);
0199 }
0200 
0201 int hns_roce_cmd_use_events(struct hns_roce_dev *hr_dev)
0202 {
0203     struct hns_roce_cmdq *hr_cmd = &hr_dev->cmd;
0204     int i;
0205 
0206     hr_cmd->context =
0207         kcalloc(hr_cmd->max_cmds, sizeof(*hr_cmd->context), GFP_KERNEL);
0208     if (!hr_cmd->context) {
0209         hr_dev->cmd_mod = 0;
0210         return -ENOMEM;
0211     }
0212 
0213     for (i = 0; i < hr_cmd->max_cmds; ++i) {
0214         hr_cmd->context[i].token = i;
0215         hr_cmd->context[i].next = i + 1;
0216         init_completion(&hr_cmd->context[i].done);
0217     }
0218     hr_cmd->context[hr_cmd->max_cmds - 1].next = 0;
0219     hr_cmd->free_head = 0;
0220 
0221     sema_init(&hr_cmd->event_sem, hr_cmd->max_cmds);
0222     spin_lock_init(&hr_cmd->context_lock);
0223 
0224     hr_cmd->use_events = 1;
0225 
0226     return 0;
0227 }
0228 
0229 void hns_roce_cmd_use_polling(struct hns_roce_dev *hr_dev)
0230 {
0231     struct hns_roce_cmdq *hr_cmd = &hr_dev->cmd;
0232 
0233     kfree(hr_cmd->context);
0234     hr_cmd->use_events = 0;
0235 }
0236 
0237 struct hns_roce_cmd_mailbox *
0238 hns_roce_alloc_cmd_mailbox(struct hns_roce_dev *hr_dev)
0239 {
0240     struct hns_roce_cmd_mailbox *mailbox;
0241 
0242     mailbox = kmalloc(sizeof(*mailbox), GFP_KERNEL);
0243     if (!mailbox)
0244         return ERR_PTR(-ENOMEM);
0245 
0246     mailbox->buf =
0247         dma_pool_alloc(hr_dev->cmd.pool, GFP_KERNEL, &mailbox->dma);
0248     if (!mailbox->buf) {
0249         kfree(mailbox);
0250         return ERR_PTR(-ENOMEM);
0251     }
0252 
0253     return mailbox;
0254 }
0255 
0256 void hns_roce_free_cmd_mailbox(struct hns_roce_dev *hr_dev,
0257                    struct hns_roce_cmd_mailbox *mailbox)
0258 {
0259     if (!mailbox)
0260         return;
0261 
0262     dma_pool_free(hr_dev->cmd.pool, mailbox->buf, mailbox->dma);
0263     kfree(mailbox);
0264 }
0265 
0266 int hns_roce_create_hw_ctx(struct hns_roce_dev *dev,
0267                struct hns_roce_cmd_mailbox *mailbox,
0268                u8 cmd, unsigned long idx)
0269 {
0270     return hns_roce_cmd_mbox(dev, mailbox->dma, 0, cmd, idx);
0271 }
0272 
0273 int hns_roce_destroy_hw_ctx(struct hns_roce_dev *dev, u8 cmd, unsigned long idx)
0274 {
0275     return hns_roce_cmd_mbox(dev, 0, 0, cmd, idx);
0276 }