744 lines · c
1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)2/* Copyright (C) 2019 Netronome Systems, Inc. */3 4#include <linux/bitfield.h>5#include <linux/io.h>6#include <linux/skbuff.h>7 8#include "ccm.h"9#include "nfp_net.h"10 11/* CCM messages via the mailbox. CMSGs get wrapped into simple TLVs12 * and copied into the mailbox. Multiple messages can be copied to13 * form a batch. Threads come in with CMSG formed in an skb, then14 * enqueue that skb onto the request queue. If threads skb is first15 * in queue this thread will handle the mailbox operation. It copies16 * up to 64 messages into the mailbox (making sure that both requests17 * and replies will fit. After FW is done processing the batch it18 * copies the data out and wakes waiting threads.19 * If a thread is waiting it either gets its the message completed20 * (response is copied into the same skb as the request, overwriting21 * it), or becomes the first in queue.22 * Completions and next-to-run are signaled via the control buffer23 * to limit potential cache line bounces.24 */25 26#define NFP_CCM_MBOX_BATCH_LIMIT 6427#define NFP_CCM_TIMEOUT (NFP_NET_POLL_TIMEOUT * 1000)28#define NFP_CCM_MAX_QLEN 102429 30enum nfp_net_mbox_cmsg_state {31 NFP_NET_MBOX_CMSG_STATE_QUEUED,32 NFP_NET_MBOX_CMSG_STATE_NEXT,33 NFP_NET_MBOX_CMSG_STATE_BUSY,34 NFP_NET_MBOX_CMSG_STATE_REPLY_FOUND,35 NFP_NET_MBOX_CMSG_STATE_DONE,36};37 38/**39 * struct nfp_ccm_mbox_cmsg_cb - CCM mailbox specific info40 * @state: processing state (/stage) of the message41 * @err: error encountered during processing if any42 * @max_len: max(request_len, reply_len)43 * @exp_reply: expected reply length (0 means don't validate)44 * @posted: the message was posted and nobody waits for the reply45 */46struct nfp_ccm_mbox_cmsg_cb {47 enum nfp_net_mbox_cmsg_state state;48 int err;49 unsigned int max_len;50 unsigned int exp_reply;51 bool posted;52};53 54static u32 nfp_ccm_mbox_max_msg(struct nfp_net *nn)55{56 return round_down(nn->tlv_caps.mbox_len, 4) -57 NFP_NET_CFG_MBOX_SIMPLE_VAL - /* common mbox command header */58 4 * 2; /* Msg TLV plus End TLV headers */59}60 61static void62nfp_ccm_mbox_msg_init(struct sk_buff *skb, unsigned int exp_reply, int max_len)63{64 struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;65 66 cb->state = NFP_NET_MBOX_CMSG_STATE_QUEUED;67 cb->err = 0;68 cb->max_len = max_len;69 cb->exp_reply = exp_reply;70 cb->posted = false;71}72 73static int nfp_ccm_mbox_maxlen(const struct sk_buff *skb)74{75 struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;76 77 return cb->max_len;78}79 80static bool nfp_ccm_mbox_done(struct sk_buff *skb)81{82 struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;83 84 return cb->state == NFP_NET_MBOX_CMSG_STATE_DONE;85}86 87static bool nfp_ccm_mbox_in_progress(struct sk_buff *skb)88{89 struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;90 91 return cb->state != NFP_NET_MBOX_CMSG_STATE_QUEUED &&92 cb->state != NFP_NET_MBOX_CMSG_STATE_NEXT;93}94 95static void nfp_ccm_mbox_set_busy(struct sk_buff *skb)96{97 struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;98 99 cb->state = NFP_NET_MBOX_CMSG_STATE_BUSY;100}101 102static bool nfp_ccm_mbox_is_posted(struct sk_buff *skb)103{104 struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;105 106 return cb->posted;107}108 109static void nfp_ccm_mbox_mark_posted(struct sk_buff *skb)110{111 struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;112 113 cb->posted = true;114}115 116static bool nfp_ccm_mbox_is_first(struct nfp_net *nn, struct sk_buff *skb)117{118 return skb_queue_is_first(&nn->mbox_cmsg.queue, skb);119}120 121static bool nfp_ccm_mbox_should_run(struct nfp_net *nn, struct sk_buff *skb)122{123 struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;124 125 return cb->state == NFP_NET_MBOX_CMSG_STATE_NEXT;126}127 128static void nfp_ccm_mbox_mark_next_runner(struct nfp_net *nn)129{130 struct nfp_ccm_mbox_cmsg_cb *cb;131 struct sk_buff *skb;132 133 skb = skb_peek(&nn->mbox_cmsg.queue);134 if (!skb)135 return;136 137 cb = (void *)skb->cb;138 cb->state = NFP_NET_MBOX_CMSG_STATE_NEXT;139 if (cb->posted)140 queue_work(nn->mbox_cmsg.workq, &nn->mbox_cmsg.runq_work);141}142 143static void144nfp_ccm_mbox_write_tlv(struct nfp_net *nn, u32 off, u32 type, u32 len)145{146 nn_writel(nn, off,147 FIELD_PREP(NFP_NET_MBOX_TLV_TYPE, type) |148 FIELD_PREP(NFP_NET_MBOX_TLV_LEN, len));149}150 151static void nfp_ccm_mbox_copy_in(struct nfp_net *nn, struct sk_buff *last)152{153 struct sk_buff *skb;154 int reserve, i, cnt;155 __be32 *data;156 u32 off, len;157 158 off = nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL;159 skb = __skb_peek(&nn->mbox_cmsg.queue);160 while (true) {161 nfp_ccm_mbox_write_tlv(nn, off, NFP_NET_MBOX_TLV_TYPE_MSG,162 skb->len);163 off += 4;164 165 /* Write data word by word, skb->data should be aligned */166 data = (__be32 *)skb->data;167 cnt = skb->len / 4;168 for (i = 0 ; i < cnt; i++) {169 nn_writel(nn, off, be32_to_cpu(data[i]));170 off += 4;171 }172 if (skb->len & 3) {173 __be32 tmp = 0;174 175 memcpy(&tmp, &data[i], skb->len & 3);176 nn_writel(nn, off, be32_to_cpu(tmp));177 off += 4;178 }179 180 /* Reserve space if reply is bigger */181 len = round_up(skb->len, 4);182 reserve = nfp_ccm_mbox_maxlen(skb) - len;183 if (reserve > 0) {184 nfp_ccm_mbox_write_tlv(nn, off,185 NFP_NET_MBOX_TLV_TYPE_RESV,186 reserve);187 off += 4 + reserve;188 }189 190 if (skb == last)191 break;192 skb = skb_queue_next(&nn->mbox_cmsg.queue, skb);193 }194 195 nfp_ccm_mbox_write_tlv(nn, off, NFP_NET_MBOX_TLV_TYPE_END, 0);196}197 198static struct sk_buff *199nfp_ccm_mbox_find_req(struct nfp_net *nn, __be16 tag, struct sk_buff *last)200{201 struct sk_buff *skb;202 203 skb = __skb_peek(&nn->mbox_cmsg.queue);204 while (true) {205 if (__nfp_ccm_get_tag(skb) == tag)206 return skb;207 208 if (skb == last)209 return NULL;210 skb = skb_queue_next(&nn->mbox_cmsg.queue, skb);211 }212}213 214static void nfp_ccm_mbox_copy_out(struct nfp_net *nn, struct sk_buff *last)215{216 struct nfp_ccm_mbox_cmsg_cb *cb;217 u8 __iomem *data, *end;218 struct sk_buff *skb;219 220 data = nn->dp.ctrl_bar + nn->tlv_caps.mbox_off +221 NFP_NET_CFG_MBOX_SIMPLE_VAL;222 end = data + nn->tlv_caps.mbox_len;223 224 while (true) {225 unsigned int length, offset, type;226 struct nfp_ccm_hdr hdr;227 u32 tlv_hdr;228 229 tlv_hdr = readl(data);230 type = FIELD_GET(NFP_NET_MBOX_TLV_TYPE, tlv_hdr);231 length = FIELD_GET(NFP_NET_MBOX_TLV_LEN, tlv_hdr);232 offset = data - nn->dp.ctrl_bar;233 234 /* Advance past the header */235 data += 4;236 237 if (data + length > end) {238 nn_dp_warn(&nn->dp, "mailbox oversized TLV type:%d offset:%u len:%u\n",239 type, offset, length);240 break;241 }242 243 if (type == NFP_NET_MBOX_TLV_TYPE_END)244 break;245 if (type == NFP_NET_MBOX_TLV_TYPE_RESV)246 goto next_tlv;247 if (type != NFP_NET_MBOX_TLV_TYPE_MSG &&248 type != NFP_NET_MBOX_TLV_TYPE_MSG_NOSUP) {249 nn_dp_warn(&nn->dp, "mailbox unknown TLV type:%d offset:%u len:%u\n",250 type, offset, length);251 break;252 }253 254 if (length < 4) {255 nn_dp_warn(&nn->dp, "mailbox msg too short to contain header TLV type:%d offset:%u len:%u\n",256 type, offset, length);257 break;258 }259 260 hdr.raw = cpu_to_be32(readl(data));261 262 skb = nfp_ccm_mbox_find_req(nn, hdr.tag, last);263 if (!skb) {264 nn_dp_warn(&nn->dp, "mailbox request not found:%u\n",265 be16_to_cpu(hdr.tag));266 break;267 }268 cb = (void *)skb->cb;269 270 if (type == NFP_NET_MBOX_TLV_TYPE_MSG_NOSUP) {271 nn_dp_warn(&nn->dp,272 "mailbox msg not supported type:%d\n",273 nfp_ccm_get_type(skb));274 cb->err = -EIO;275 goto next_tlv;276 }277 278 if (hdr.type != __NFP_CCM_REPLY(nfp_ccm_get_type(skb))) {279 nn_dp_warn(&nn->dp, "mailbox msg reply wrong type:%u expected:%lu\n",280 hdr.type,281 __NFP_CCM_REPLY(nfp_ccm_get_type(skb)));282 cb->err = -EIO;283 goto next_tlv;284 }285 if (cb->exp_reply && length != cb->exp_reply) {286 nn_dp_warn(&nn->dp, "mailbox msg reply wrong size type:%u expected:%u have:%u\n",287 hdr.type, length, cb->exp_reply);288 cb->err = -EIO;289 goto next_tlv;290 }291 if (length > cb->max_len) {292 nn_dp_warn(&nn->dp, "mailbox msg oversized reply type:%u max:%u have:%u\n",293 hdr.type, cb->max_len, length);294 cb->err = -EIO;295 goto next_tlv;296 }297 298 if (!cb->posted) {299 __be32 *skb_data;300 int i, cnt;301 302 if (length <= skb->len)303 __skb_trim(skb, length);304 else305 skb_put(skb, length - skb->len);306 307 /* We overcopy here slightly, but that's okay,308 * the skb is large enough, and the garbage will309 * be ignored (beyond skb->len).310 */311 skb_data = (__be32 *)skb->data;312 memcpy(skb_data, &hdr, 4);313 314 cnt = DIV_ROUND_UP(length, 4);315 for (i = 1 ; i < cnt; i++)316 skb_data[i] = cpu_to_be32(readl(data + i * 4));317 }318 319 cb->state = NFP_NET_MBOX_CMSG_STATE_REPLY_FOUND;320next_tlv:321 data += round_up(length, 4);322 if (data + 4 > end) {323 nn_dp_warn(&nn->dp,324 "reached end of MBOX without END TLV\n");325 break;326 }327 }328 329 smp_wmb(); /* order the skb->data vs. cb->state */330 spin_lock_bh(&nn->mbox_cmsg.queue.lock);331 do {332 skb = __skb_dequeue(&nn->mbox_cmsg.queue);333 cb = (void *)skb->cb;334 335 if (cb->state != NFP_NET_MBOX_CMSG_STATE_REPLY_FOUND) {336 cb->err = -ENOENT;337 smp_wmb(); /* order the cb->err vs. cb->state */338 }339 cb->state = NFP_NET_MBOX_CMSG_STATE_DONE;340 341 if (cb->posted) {342 if (cb->err)343 nn_dp_warn(&nn->dp,344 "mailbox posted msg failed type:%u err:%d\n",345 nfp_ccm_get_type(skb), cb->err);346 dev_consume_skb_any(skb);347 }348 } while (skb != last);349 350 nfp_ccm_mbox_mark_next_runner(nn);351 spin_unlock_bh(&nn->mbox_cmsg.queue.lock);352}353 354static void355nfp_ccm_mbox_mark_all_err(struct nfp_net *nn, struct sk_buff *last, int err)356{357 struct nfp_ccm_mbox_cmsg_cb *cb;358 struct sk_buff *skb;359 360 spin_lock_bh(&nn->mbox_cmsg.queue.lock);361 do {362 skb = __skb_dequeue(&nn->mbox_cmsg.queue);363 cb = (void *)skb->cb;364 365 cb->err = err;366 smp_wmb(); /* order the cb->err vs. cb->state */367 cb->state = NFP_NET_MBOX_CMSG_STATE_DONE;368 } while (skb != last);369 370 nfp_ccm_mbox_mark_next_runner(nn);371 spin_unlock_bh(&nn->mbox_cmsg.queue.lock);372}373 374static void nfp_ccm_mbox_run_queue_unlock(struct nfp_net *nn)375 __releases(&nn->mbox_cmsg.queue.lock)376{377 int space = nn->tlv_caps.mbox_len - NFP_NET_CFG_MBOX_SIMPLE_VAL;378 struct sk_buff *skb, *last;379 int cnt, err;380 381 space -= 4; /* for End TLV */382 383 /* First skb must fit, because it's ours and we checked it fits */384 cnt = 1;385 last = skb = __skb_peek(&nn->mbox_cmsg.queue);386 space -= 4 + nfp_ccm_mbox_maxlen(skb);387 388 while (!skb_queue_is_last(&nn->mbox_cmsg.queue, last)) {389 skb = skb_queue_next(&nn->mbox_cmsg.queue, last);390 space -= 4 + nfp_ccm_mbox_maxlen(skb);391 if (space < 0)392 break;393 last = skb;394 nfp_ccm_mbox_set_busy(skb);395 cnt++;396 if (cnt == NFP_CCM_MBOX_BATCH_LIMIT)397 break;398 }399 spin_unlock_bh(&nn->mbox_cmsg.queue.lock);400 401 /* Now we own all skb's marked in progress, new requests may arrive402 * at the end of the queue.403 */404 405 nn_ctrl_bar_lock(nn);406 407 nfp_ccm_mbox_copy_in(nn, last);408 409 err = nfp_net_mbox_reconfig(nn, NFP_NET_CFG_MBOX_CMD_TLV_CMSG);410 if (!err)411 nfp_ccm_mbox_copy_out(nn, last);412 else413 nfp_ccm_mbox_mark_all_err(nn, last, -EIO);414 415 nn_ctrl_bar_unlock(nn);416 417 wake_up_all(&nn->mbox_cmsg.wq);418}419 420static int nfp_ccm_mbox_skb_return(struct sk_buff *skb)421{422 struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb;423 424 if (cb->err)425 dev_kfree_skb_any(skb);426 return cb->err;427}428 429/* If wait timed out but the command is already in progress we have430 * to wait until it finishes. Runners has ownership of the skbs marked431 * as busy.432 */433static int434nfp_ccm_mbox_unlink_unlock(struct nfp_net *nn, struct sk_buff *skb,435 enum nfp_ccm_type type)436 __releases(&nn->mbox_cmsg.queue.lock)437{438 bool was_first;439 440 if (nfp_ccm_mbox_in_progress(skb)) {441 spin_unlock_bh(&nn->mbox_cmsg.queue.lock);442 443 wait_event(nn->mbox_cmsg.wq, nfp_ccm_mbox_done(skb));444 smp_rmb(); /* pairs with smp_wmb() after data is written */445 return nfp_ccm_mbox_skb_return(skb);446 }447 448 was_first = nfp_ccm_mbox_should_run(nn, skb);449 __skb_unlink(skb, &nn->mbox_cmsg.queue);450 if (was_first)451 nfp_ccm_mbox_mark_next_runner(nn);452 453 spin_unlock_bh(&nn->mbox_cmsg.queue.lock);454 455 if (was_first)456 wake_up_all(&nn->mbox_cmsg.wq);457 458 nn_dp_warn(&nn->dp, "time out waiting for mbox response to 0x%02x\n",459 type);460 return -ETIMEDOUT;461}462 463static int464nfp_ccm_mbox_msg_prepare(struct nfp_net *nn, struct sk_buff *skb,465 enum nfp_ccm_type type,466 unsigned int reply_size, unsigned int max_reply_size,467 gfp_t flags)468{469 const unsigned int mbox_max = nfp_ccm_mbox_max_msg(nn);470 unsigned int max_len;471 ssize_t undersize;472 int err;473 474 if (unlikely(!(nn->tlv_caps.mbox_cmsg_types & BIT(type)))) {475 nn_dp_warn(&nn->dp,476 "message type %d not supported by mailbox\n", type);477 return -EINVAL;478 }479 480 /* If the reply size is unknown assume it will take the entire481 * mailbox, the callers should do their best for this to never482 * happen.483 */484 if (!max_reply_size)485 max_reply_size = mbox_max;486 max_reply_size = round_up(max_reply_size, 4);487 488 /* Make sure we can fit the entire reply into the skb,489 * and that we don't have to slow down the mbox handler490 * with allocations.491 */492 undersize = max_reply_size - (skb_end_pointer(skb) - skb->data);493 if (undersize > 0) {494 err = pskb_expand_head(skb, 0, undersize, flags);495 if (err) {496 nn_dp_warn(&nn->dp,497 "can't allocate reply buffer for mailbox\n");498 return err;499 }500 }501 502 /* Make sure that request and response both fit into the mailbox */503 max_len = max(max_reply_size, round_up(skb->len, 4));504 if (max_len > mbox_max) {505 nn_dp_warn(&nn->dp,506 "message too big for the mailbox: %u/%u vs %u\n",507 skb->len, max_reply_size, mbox_max);508 return -EMSGSIZE;509 }510 511 nfp_ccm_mbox_msg_init(skb, reply_size, max_len);512 513 return 0;514}515 516static int517nfp_ccm_mbox_msg_enqueue(struct nfp_net *nn, struct sk_buff *skb,518 enum nfp_ccm_type type, bool critical)519{520 struct nfp_ccm_hdr *hdr;521 522 assert_spin_locked(&nn->mbox_cmsg.queue.lock);523 524 if (!critical && nn->mbox_cmsg.queue.qlen >= NFP_CCM_MAX_QLEN) {525 nn_dp_warn(&nn->dp, "mailbox request queue too long\n");526 return -EBUSY;527 }528 529 hdr = (void *)skb->data;530 hdr->ver = NFP_CCM_ABI_VERSION;531 hdr->type = type;532 hdr->tag = cpu_to_be16(nn->mbox_cmsg.tag++);533 534 __skb_queue_tail(&nn->mbox_cmsg.queue, skb);535 536 return 0;537}538 539int __nfp_ccm_mbox_communicate(struct nfp_net *nn, struct sk_buff *skb,540 enum nfp_ccm_type type,541 unsigned int reply_size,542 unsigned int max_reply_size, bool critical)543{544 int err;545 546 err = nfp_ccm_mbox_msg_prepare(nn, skb, type, reply_size,547 max_reply_size, GFP_KERNEL);548 if (err)549 goto err_free_skb;550 551 spin_lock_bh(&nn->mbox_cmsg.queue.lock);552 553 err = nfp_ccm_mbox_msg_enqueue(nn, skb, type, critical);554 if (err)555 goto err_unlock;556 557 /* First in queue takes the mailbox lock and processes the batch */558 if (!nfp_ccm_mbox_is_first(nn, skb)) {559 bool to;560 561 spin_unlock_bh(&nn->mbox_cmsg.queue.lock);562 563 to = !wait_event_timeout(nn->mbox_cmsg.wq,564 nfp_ccm_mbox_done(skb) ||565 nfp_ccm_mbox_should_run(nn, skb),566 msecs_to_jiffies(NFP_CCM_TIMEOUT));567 568 /* fast path for those completed by another thread */569 if (nfp_ccm_mbox_done(skb)) {570 smp_rmb(); /* pairs with wmb after data is written */571 return nfp_ccm_mbox_skb_return(skb);572 }573 574 spin_lock_bh(&nn->mbox_cmsg.queue.lock);575 576 if (!nfp_ccm_mbox_is_first(nn, skb)) {577 WARN_ON(!to);578 579 err = nfp_ccm_mbox_unlink_unlock(nn, skb, type);580 if (err)581 goto err_free_skb;582 return 0;583 }584 }585 586 /* run queue expects the lock held */587 nfp_ccm_mbox_run_queue_unlock(nn);588 return nfp_ccm_mbox_skb_return(skb);589 590err_unlock:591 spin_unlock_bh(&nn->mbox_cmsg.queue.lock);592err_free_skb:593 dev_kfree_skb_any(skb);594 return err;595}596 597int nfp_ccm_mbox_communicate(struct nfp_net *nn, struct sk_buff *skb,598 enum nfp_ccm_type type,599 unsigned int reply_size,600 unsigned int max_reply_size)601{602 return __nfp_ccm_mbox_communicate(nn, skb, type, reply_size,603 max_reply_size, false);604}605 606static void nfp_ccm_mbox_post_runq_work(struct work_struct *work)607{608 struct sk_buff *skb;609 struct nfp_net *nn;610 611 nn = container_of(work, struct nfp_net, mbox_cmsg.runq_work);612 613 spin_lock_bh(&nn->mbox_cmsg.queue.lock);614 615 skb = __skb_peek(&nn->mbox_cmsg.queue);616 if (WARN_ON(!skb || !nfp_ccm_mbox_is_posted(skb) ||617 !nfp_ccm_mbox_should_run(nn, skb))) {618 spin_unlock_bh(&nn->mbox_cmsg.queue.lock);619 return;620 }621 622 nfp_ccm_mbox_run_queue_unlock(nn);623}624 625static void nfp_ccm_mbox_post_wait_work(struct work_struct *work)626{627 struct sk_buff *skb;628 struct nfp_net *nn;629 int err;630 631 nn = container_of(work, struct nfp_net, mbox_cmsg.wait_work);632 633 skb = skb_peek(&nn->mbox_cmsg.queue);634 if (WARN_ON(!skb || !nfp_ccm_mbox_is_posted(skb)))635 /* Should never happen so it's unclear what to do here.. */636 goto exit_unlock_wake;637 638 err = nfp_net_mbox_reconfig_wait_posted(nn);639 if (!err)640 nfp_ccm_mbox_copy_out(nn, skb);641 else642 nfp_ccm_mbox_mark_all_err(nn, skb, -EIO);643exit_unlock_wake:644 nn_ctrl_bar_unlock(nn);645 wake_up_all(&nn->mbox_cmsg.wq);646}647 648int nfp_ccm_mbox_post(struct nfp_net *nn, struct sk_buff *skb,649 enum nfp_ccm_type type, unsigned int max_reply_size)650{651 int err;652 653 err = nfp_ccm_mbox_msg_prepare(nn, skb, type, 0, max_reply_size,654 GFP_ATOMIC);655 if (err)656 goto err_free_skb;657 658 nfp_ccm_mbox_mark_posted(skb);659 660 spin_lock_bh(&nn->mbox_cmsg.queue.lock);661 662 err = nfp_ccm_mbox_msg_enqueue(nn, skb, type, false);663 if (err)664 goto err_unlock;665 666 if (nfp_ccm_mbox_is_first(nn, skb)) {667 if (nn_ctrl_bar_trylock(nn)) {668 nfp_ccm_mbox_copy_in(nn, skb);669 nfp_net_mbox_reconfig_post(nn,670 NFP_NET_CFG_MBOX_CMD_TLV_CMSG);671 queue_work(nn->mbox_cmsg.workq,672 &nn->mbox_cmsg.wait_work);673 } else {674 nfp_ccm_mbox_mark_next_runner(nn);675 }676 }677 678 spin_unlock_bh(&nn->mbox_cmsg.queue.lock);679 680 return 0;681 682err_unlock:683 spin_unlock_bh(&nn->mbox_cmsg.queue.lock);684err_free_skb:685 dev_kfree_skb_any(skb);686 return err;687}688 689struct sk_buff *690nfp_ccm_mbox_msg_alloc(struct nfp_net *nn, unsigned int req_size,691 unsigned int reply_size, gfp_t flags)692{693 unsigned int max_size;694 struct sk_buff *skb;695 696 if (!reply_size)697 max_size = nfp_ccm_mbox_max_msg(nn);698 else699 max_size = max(req_size, reply_size);700 max_size = round_up(max_size, 4);701 702 skb = alloc_skb(max_size, flags);703 if (!skb)704 return NULL;705 706 skb_put(skb, req_size);707 708 return skb;709}710 711bool nfp_ccm_mbox_fits(struct nfp_net *nn, unsigned int size)712{713 return nfp_ccm_mbox_max_msg(nn) >= size;714}715 716int nfp_ccm_mbox_init(struct nfp_net *nn)717{718 return 0;719}720 721void nfp_ccm_mbox_clean(struct nfp_net *nn)722{723 drain_workqueue(nn->mbox_cmsg.workq);724}725 726int nfp_ccm_mbox_alloc(struct nfp_net *nn)727{728 skb_queue_head_init(&nn->mbox_cmsg.queue);729 init_waitqueue_head(&nn->mbox_cmsg.wq);730 INIT_WORK(&nn->mbox_cmsg.wait_work, nfp_ccm_mbox_post_wait_work);731 INIT_WORK(&nn->mbox_cmsg.runq_work, nfp_ccm_mbox_post_runq_work);732 733 nn->mbox_cmsg.workq = alloc_workqueue("nfp-ccm-mbox", WQ_UNBOUND, 0);734 if (!nn->mbox_cmsg.workq)735 return -ENOMEM;736 return 0;737}738 739void nfp_ccm_mbox_free(struct nfp_net *nn)740{741 destroy_workqueue(nn->mbox_cmsg.workq);742 WARN_ON(!skb_queue_empty(&nn->mbox_cmsg.queue));743}744