162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 262306a36Sopenharmony_ci/* Copyright (C) 2019 Netronome Systems, Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/bitfield.h> 562306a36Sopenharmony_ci#include <linux/io.h> 662306a36Sopenharmony_ci#include <linux/skbuff.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "ccm.h" 962306a36Sopenharmony_ci#include "nfp_net.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* CCM messages via the mailbox. CMSGs get wrapped into simple TLVs 1262306a36Sopenharmony_ci * and copied into the mailbox. Multiple messages can be copied to 1362306a36Sopenharmony_ci * form a batch. Threads come in with CMSG formed in an skb, then 1462306a36Sopenharmony_ci * enqueue that skb onto the request queue. If threads skb is first 1562306a36Sopenharmony_ci * in queue this thread will handle the mailbox operation. It copies 1662306a36Sopenharmony_ci * up to 64 messages into the mailbox (making sure that both requests 1762306a36Sopenharmony_ci * and replies will fit. After FW is done processing the batch it 1862306a36Sopenharmony_ci * copies the data out and wakes waiting threads. 1962306a36Sopenharmony_ci * If a thread is waiting it either gets its the message completed 2062306a36Sopenharmony_ci * (response is copied into the same skb as the request, overwriting 2162306a36Sopenharmony_ci * it), or becomes the first in queue. 2262306a36Sopenharmony_ci * Completions and next-to-run are signaled via the control buffer 2362306a36Sopenharmony_ci * to limit potential cache line bounces. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define NFP_CCM_MBOX_BATCH_LIMIT 64 2762306a36Sopenharmony_ci#define NFP_CCM_TIMEOUT (NFP_NET_POLL_TIMEOUT * 1000) 2862306a36Sopenharmony_ci#define NFP_CCM_MAX_QLEN 1024 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cienum nfp_net_mbox_cmsg_state { 3162306a36Sopenharmony_ci NFP_NET_MBOX_CMSG_STATE_QUEUED, 3262306a36Sopenharmony_ci NFP_NET_MBOX_CMSG_STATE_NEXT, 3362306a36Sopenharmony_ci NFP_NET_MBOX_CMSG_STATE_BUSY, 3462306a36Sopenharmony_ci NFP_NET_MBOX_CMSG_STATE_REPLY_FOUND, 3562306a36Sopenharmony_ci NFP_NET_MBOX_CMSG_STATE_DONE, 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/** 3962306a36Sopenharmony_ci * struct nfp_ccm_mbox_cmsg_cb - CCM mailbox specific info 4062306a36Sopenharmony_ci * @state: processing state (/stage) of the message 4162306a36Sopenharmony_ci * @err: error encountered during processing if any 4262306a36Sopenharmony_ci * @max_len: max(request_len, reply_len) 4362306a36Sopenharmony_ci * @exp_reply: expected reply length (0 means don't validate) 4462306a36Sopenharmony_ci * @posted: the message was posted and nobody waits for the reply 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_cistruct nfp_ccm_mbox_cmsg_cb { 4762306a36Sopenharmony_ci enum nfp_net_mbox_cmsg_state state; 4862306a36Sopenharmony_ci int err; 4962306a36Sopenharmony_ci unsigned int max_len; 5062306a36Sopenharmony_ci unsigned int exp_reply; 5162306a36Sopenharmony_ci bool posted; 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic u32 nfp_ccm_mbox_max_msg(struct nfp_net *nn) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci return round_down(nn->tlv_caps.mbox_len, 4) - 5762306a36Sopenharmony_ci NFP_NET_CFG_MBOX_SIMPLE_VAL - /* common mbox command header */ 5862306a36Sopenharmony_ci 4 * 2; /* Msg TLV plus End TLV headers */ 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic void 6262306a36Sopenharmony_cinfp_ccm_mbox_msg_init(struct sk_buff *skb, unsigned int exp_reply, int max_len) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci cb->state = NFP_NET_MBOX_CMSG_STATE_QUEUED; 6762306a36Sopenharmony_ci cb->err = 0; 6862306a36Sopenharmony_ci cb->max_len = max_len; 6962306a36Sopenharmony_ci cb->exp_reply = exp_reply; 7062306a36Sopenharmony_ci cb->posted = false; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic int nfp_ccm_mbox_maxlen(const struct sk_buff *skb) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return cb->max_len; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic bool nfp_ccm_mbox_done(struct sk_buff *skb) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return cb->state == NFP_NET_MBOX_CMSG_STATE_DONE; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic bool nfp_ccm_mbox_in_progress(struct sk_buff *skb) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci return cb->state != NFP_NET_MBOX_CMSG_STATE_QUEUED && 9262306a36Sopenharmony_ci cb->state != NFP_NET_MBOX_CMSG_STATE_NEXT; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic void nfp_ccm_mbox_set_busy(struct sk_buff *skb) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci cb->state = NFP_NET_MBOX_CMSG_STATE_BUSY; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic bool nfp_ccm_mbox_is_posted(struct sk_buff *skb) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return cb->posted; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void nfp_ccm_mbox_mark_posted(struct sk_buff *skb) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci cb->posted = true; 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic bool nfp_ccm_mbox_is_first(struct nfp_net *nn, struct sk_buff *skb) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci return skb_queue_is_first(&nn->mbox_cmsg.queue, skb); 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic bool nfp_ccm_mbox_should_run(struct nfp_net *nn, struct sk_buff *skb) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return cb->state == NFP_NET_MBOX_CMSG_STATE_NEXT; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic void nfp_ccm_mbox_mark_next_runner(struct nfp_net *nn) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct nfp_ccm_mbox_cmsg_cb *cb; 13162306a36Sopenharmony_ci struct sk_buff *skb; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci skb = skb_peek(&nn->mbox_cmsg.queue); 13462306a36Sopenharmony_ci if (!skb) 13562306a36Sopenharmony_ci return; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci cb = (void *)skb->cb; 13862306a36Sopenharmony_ci cb->state = NFP_NET_MBOX_CMSG_STATE_NEXT; 13962306a36Sopenharmony_ci if (cb->posted) 14062306a36Sopenharmony_ci queue_work(nn->mbox_cmsg.workq, &nn->mbox_cmsg.runq_work); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void 14462306a36Sopenharmony_cinfp_ccm_mbox_write_tlv(struct nfp_net *nn, u32 off, u32 type, u32 len) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci nn_writel(nn, off, 14762306a36Sopenharmony_ci FIELD_PREP(NFP_NET_MBOX_TLV_TYPE, type) | 14862306a36Sopenharmony_ci FIELD_PREP(NFP_NET_MBOX_TLV_LEN, len)); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic void nfp_ccm_mbox_copy_in(struct nfp_net *nn, struct sk_buff *last) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci struct sk_buff *skb; 15462306a36Sopenharmony_ci int reserve, i, cnt; 15562306a36Sopenharmony_ci __be32 *data; 15662306a36Sopenharmony_ci u32 off, len; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci off = nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL; 15962306a36Sopenharmony_ci skb = __skb_peek(&nn->mbox_cmsg.queue); 16062306a36Sopenharmony_ci while (true) { 16162306a36Sopenharmony_ci nfp_ccm_mbox_write_tlv(nn, off, NFP_NET_MBOX_TLV_TYPE_MSG, 16262306a36Sopenharmony_ci skb->len); 16362306a36Sopenharmony_ci off += 4; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Write data word by word, skb->data should be aligned */ 16662306a36Sopenharmony_ci data = (__be32 *)skb->data; 16762306a36Sopenharmony_ci cnt = skb->len / 4; 16862306a36Sopenharmony_ci for (i = 0 ; i < cnt; i++) { 16962306a36Sopenharmony_ci nn_writel(nn, off, be32_to_cpu(data[i])); 17062306a36Sopenharmony_ci off += 4; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci if (skb->len & 3) { 17362306a36Sopenharmony_ci __be32 tmp = 0; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci memcpy(&tmp, &data[i], skb->len & 3); 17662306a36Sopenharmony_ci nn_writel(nn, off, be32_to_cpu(tmp)); 17762306a36Sopenharmony_ci off += 4; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* Reserve space if reply is bigger */ 18162306a36Sopenharmony_ci len = round_up(skb->len, 4); 18262306a36Sopenharmony_ci reserve = nfp_ccm_mbox_maxlen(skb) - len; 18362306a36Sopenharmony_ci if (reserve > 0) { 18462306a36Sopenharmony_ci nfp_ccm_mbox_write_tlv(nn, off, 18562306a36Sopenharmony_ci NFP_NET_MBOX_TLV_TYPE_RESV, 18662306a36Sopenharmony_ci reserve); 18762306a36Sopenharmony_ci off += 4 + reserve; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (skb == last) 19162306a36Sopenharmony_ci break; 19262306a36Sopenharmony_ci skb = skb_queue_next(&nn->mbox_cmsg.queue, skb); 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci nfp_ccm_mbox_write_tlv(nn, off, NFP_NET_MBOX_TLV_TYPE_END, 0); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic struct sk_buff * 19962306a36Sopenharmony_cinfp_ccm_mbox_find_req(struct nfp_net *nn, __be16 tag, struct sk_buff *last) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct sk_buff *skb; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci skb = __skb_peek(&nn->mbox_cmsg.queue); 20462306a36Sopenharmony_ci while (true) { 20562306a36Sopenharmony_ci if (__nfp_ccm_get_tag(skb) == tag) 20662306a36Sopenharmony_ci return skb; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (skb == last) 20962306a36Sopenharmony_ci return NULL; 21062306a36Sopenharmony_ci skb = skb_queue_next(&nn->mbox_cmsg.queue, skb); 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic void nfp_ccm_mbox_copy_out(struct nfp_net *nn, struct sk_buff *last) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci struct nfp_ccm_mbox_cmsg_cb *cb; 21762306a36Sopenharmony_ci u8 __iomem *data, *end; 21862306a36Sopenharmony_ci struct sk_buff *skb; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci data = nn->dp.ctrl_bar + nn->tlv_caps.mbox_off + 22162306a36Sopenharmony_ci NFP_NET_CFG_MBOX_SIMPLE_VAL; 22262306a36Sopenharmony_ci end = data + nn->tlv_caps.mbox_len; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci while (true) { 22562306a36Sopenharmony_ci unsigned int length, offset, type; 22662306a36Sopenharmony_ci struct nfp_ccm_hdr hdr; 22762306a36Sopenharmony_ci u32 tlv_hdr; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci tlv_hdr = readl(data); 23062306a36Sopenharmony_ci type = FIELD_GET(NFP_NET_MBOX_TLV_TYPE, tlv_hdr); 23162306a36Sopenharmony_ci length = FIELD_GET(NFP_NET_MBOX_TLV_LEN, tlv_hdr); 23262306a36Sopenharmony_ci offset = data - nn->dp.ctrl_bar; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* Advance past the header */ 23562306a36Sopenharmony_ci data += 4; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (data + length > end) { 23862306a36Sopenharmony_ci nn_dp_warn(&nn->dp, "mailbox oversized TLV type:%d offset:%u len:%u\n", 23962306a36Sopenharmony_ci type, offset, length); 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (type == NFP_NET_MBOX_TLV_TYPE_END) 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci if (type == NFP_NET_MBOX_TLV_TYPE_RESV) 24662306a36Sopenharmony_ci goto next_tlv; 24762306a36Sopenharmony_ci if (type != NFP_NET_MBOX_TLV_TYPE_MSG && 24862306a36Sopenharmony_ci type != NFP_NET_MBOX_TLV_TYPE_MSG_NOSUP) { 24962306a36Sopenharmony_ci nn_dp_warn(&nn->dp, "mailbox unknown TLV type:%d offset:%u len:%u\n", 25062306a36Sopenharmony_ci type, offset, length); 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (length < 4) { 25562306a36Sopenharmony_ci nn_dp_warn(&nn->dp, "mailbox msg too short to contain header TLV type:%d offset:%u len:%u\n", 25662306a36Sopenharmony_ci type, offset, length); 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci hdr.raw = cpu_to_be32(readl(data)); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci skb = nfp_ccm_mbox_find_req(nn, hdr.tag, last); 26362306a36Sopenharmony_ci if (!skb) { 26462306a36Sopenharmony_ci nn_dp_warn(&nn->dp, "mailbox request not found:%u\n", 26562306a36Sopenharmony_ci be16_to_cpu(hdr.tag)); 26662306a36Sopenharmony_ci break; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci cb = (void *)skb->cb; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (type == NFP_NET_MBOX_TLV_TYPE_MSG_NOSUP) { 27162306a36Sopenharmony_ci nn_dp_warn(&nn->dp, 27262306a36Sopenharmony_ci "mailbox msg not supported type:%d\n", 27362306a36Sopenharmony_ci nfp_ccm_get_type(skb)); 27462306a36Sopenharmony_ci cb->err = -EIO; 27562306a36Sopenharmony_ci goto next_tlv; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (hdr.type != __NFP_CCM_REPLY(nfp_ccm_get_type(skb))) { 27962306a36Sopenharmony_ci nn_dp_warn(&nn->dp, "mailbox msg reply wrong type:%u expected:%lu\n", 28062306a36Sopenharmony_ci hdr.type, 28162306a36Sopenharmony_ci __NFP_CCM_REPLY(nfp_ccm_get_type(skb))); 28262306a36Sopenharmony_ci cb->err = -EIO; 28362306a36Sopenharmony_ci goto next_tlv; 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci if (cb->exp_reply && length != cb->exp_reply) { 28662306a36Sopenharmony_ci nn_dp_warn(&nn->dp, "mailbox msg reply wrong size type:%u expected:%u have:%u\n", 28762306a36Sopenharmony_ci hdr.type, length, cb->exp_reply); 28862306a36Sopenharmony_ci cb->err = -EIO; 28962306a36Sopenharmony_ci goto next_tlv; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci if (length > cb->max_len) { 29262306a36Sopenharmony_ci nn_dp_warn(&nn->dp, "mailbox msg oversized reply type:%u max:%u have:%u\n", 29362306a36Sopenharmony_ci hdr.type, cb->max_len, length); 29462306a36Sopenharmony_ci cb->err = -EIO; 29562306a36Sopenharmony_ci goto next_tlv; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci if (!cb->posted) { 29962306a36Sopenharmony_ci __be32 *skb_data; 30062306a36Sopenharmony_ci int i, cnt; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (length <= skb->len) 30362306a36Sopenharmony_ci __skb_trim(skb, length); 30462306a36Sopenharmony_ci else 30562306a36Sopenharmony_ci skb_put(skb, length - skb->len); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* We overcopy here slightly, but that's okay, 30862306a36Sopenharmony_ci * the skb is large enough, and the garbage will 30962306a36Sopenharmony_ci * be ignored (beyond skb->len). 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_ci skb_data = (__be32 *)skb->data; 31262306a36Sopenharmony_ci memcpy(skb_data, &hdr, 4); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci cnt = DIV_ROUND_UP(length, 4); 31562306a36Sopenharmony_ci for (i = 1 ; i < cnt; i++) 31662306a36Sopenharmony_ci skb_data[i] = cpu_to_be32(readl(data + i * 4)); 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci cb->state = NFP_NET_MBOX_CMSG_STATE_REPLY_FOUND; 32062306a36Sopenharmony_cinext_tlv: 32162306a36Sopenharmony_ci data += round_up(length, 4); 32262306a36Sopenharmony_ci if (data + 4 > end) { 32362306a36Sopenharmony_ci nn_dp_warn(&nn->dp, 32462306a36Sopenharmony_ci "reached end of MBOX without END TLV\n"); 32562306a36Sopenharmony_ci break; 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci smp_wmb(); /* order the skb->data vs. cb->state */ 33062306a36Sopenharmony_ci spin_lock_bh(&nn->mbox_cmsg.queue.lock); 33162306a36Sopenharmony_ci do { 33262306a36Sopenharmony_ci skb = __skb_dequeue(&nn->mbox_cmsg.queue); 33362306a36Sopenharmony_ci cb = (void *)skb->cb; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (cb->state != NFP_NET_MBOX_CMSG_STATE_REPLY_FOUND) { 33662306a36Sopenharmony_ci cb->err = -ENOENT; 33762306a36Sopenharmony_ci smp_wmb(); /* order the cb->err vs. cb->state */ 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci cb->state = NFP_NET_MBOX_CMSG_STATE_DONE; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (cb->posted) { 34262306a36Sopenharmony_ci if (cb->err) 34362306a36Sopenharmony_ci nn_dp_warn(&nn->dp, 34462306a36Sopenharmony_ci "mailbox posted msg failed type:%u err:%d\n", 34562306a36Sopenharmony_ci nfp_ccm_get_type(skb), cb->err); 34662306a36Sopenharmony_ci dev_consume_skb_any(skb); 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci } while (skb != last); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci nfp_ccm_mbox_mark_next_runner(nn); 35162306a36Sopenharmony_ci spin_unlock_bh(&nn->mbox_cmsg.queue.lock); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic void 35562306a36Sopenharmony_cinfp_ccm_mbox_mark_all_err(struct nfp_net *nn, struct sk_buff *last, int err) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct nfp_ccm_mbox_cmsg_cb *cb; 35862306a36Sopenharmony_ci struct sk_buff *skb; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci spin_lock_bh(&nn->mbox_cmsg.queue.lock); 36162306a36Sopenharmony_ci do { 36262306a36Sopenharmony_ci skb = __skb_dequeue(&nn->mbox_cmsg.queue); 36362306a36Sopenharmony_ci cb = (void *)skb->cb; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci cb->err = err; 36662306a36Sopenharmony_ci smp_wmb(); /* order the cb->err vs. cb->state */ 36762306a36Sopenharmony_ci cb->state = NFP_NET_MBOX_CMSG_STATE_DONE; 36862306a36Sopenharmony_ci } while (skb != last); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci nfp_ccm_mbox_mark_next_runner(nn); 37162306a36Sopenharmony_ci spin_unlock_bh(&nn->mbox_cmsg.queue.lock); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic void nfp_ccm_mbox_run_queue_unlock(struct nfp_net *nn) 37562306a36Sopenharmony_ci __releases(&nn->mbox_cmsg.queue.lock) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci int space = nn->tlv_caps.mbox_len - NFP_NET_CFG_MBOX_SIMPLE_VAL; 37862306a36Sopenharmony_ci struct sk_buff *skb, *last; 37962306a36Sopenharmony_ci int cnt, err; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci space -= 4; /* for End TLV */ 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* First skb must fit, because it's ours and we checked it fits */ 38462306a36Sopenharmony_ci cnt = 1; 38562306a36Sopenharmony_ci last = skb = __skb_peek(&nn->mbox_cmsg.queue); 38662306a36Sopenharmony_ci space -= 4 + nfp_ccm_mbox_maxlen(skb); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci while (!skb_queue_is_last(&nn->mbox_cmsg.queue, last)) { 38962306a36Sopenharmony_ci skb = skb_queue_next(&nn->mbox_cmsg.queue, last); 39062306a36Sopenharmony_ci space -= 4 + nfp_ccm_mbox_maxlen(skb); 39162306a36Sopenharmony_ci if (space < 0) 39262306a36Sopenharmony_ci break; 39362306a36Sopenharmony_ci last = skb; 39462306a36Sopenharmony_ci nfp_ccm_mbox_set_busy(skb); 39562306a36Sopenharmony_ci cnt++; 39662306a36Sopenharmony_ci if (cnt == NFP_CCM_MBOX_BATCH_LIMIT) 39762306a36Sopenharmony_ci break; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci spin_unlock_bh(&nn->mbox_cmsg.queue.lock); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci /* Now we own all skb's marked in progress, new requests may arrive 40262306a36Sopenharmony_ci * at the end of the queue. 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci nn_ctrl_bar_lock(nn); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci nfp_ccm_mbox_copy_in(nn, last); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci err = nfp_net_mbox_reconfig(nn, NFP_NET_CFG_MBOX_CMD_TLV_CMSG); 41062306a36Sopenharmony_ci if (!err) 41162306a36Sopenharmony_ci nfp_ccm_mbox_copy_out(nn, last); 41262306a36Sopenharmony_ci else 41362306a36Sopenharmony_ci nfp_ccm_mbox_mark_all_err(nn, last, -EIO); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci nn_ctrl_bar_unlock(nn); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci wake_up_all(&nn->mbox_cmsg.wq); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic int nfp_ccm_mbox_skb_return(struct sk_buff *skb) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct nfp_ccm_mbox_cmsg_cb *cb = (void *)skb->cb; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (cb->err) 42562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 42662306a36Sopenharmony_ci return cb->err; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/* If wait timed out but the command is already in progress we have 43062306a36Sopenharmony_ci * to wait until it finishes. Runners has ownership of the skbs marked 43162306a36Sopenharmony_ci * as busy. 43262306a36Sopenharmony_ci */ 43362306a36Sopenharmony_cistatic int 43462306a36Sopenharmony_cinfp_ccm_mbox_unlink_unlock(struct nfp_net *nn, struct sk_buff *skb, 43562306a36Sopenharmony_ci enum nfp_ccm_type type) 43662306a36Sopenharmony_ci __releases(&nn->mbox_cmsg.queue.lock) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci bool was_first; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci if (nfp_ccm_mbox_in_progress(skb)) { 44162306a36Sopenharmony_ci spin_unlock_bh(&nn->mbox_cmsg.queue.lock); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci wait_event(nn->mbox_cmsg.wq, nfp_ccm_mbox_done(skb)); 44462306a36Sopenharmony_ci smp_rmb(); /* pairs with smp_wmb() after data is written */ 44562306a36Sopenharmony_ci return nfp_ccm_mbox_skb_return(skb); 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci was_first = nfp_ccm_mbox_should_run(nn, skb); 44962306a36Sopenharmony_ci __skb_unlink(skb, &nn->mbox_cmsg.queue); 45062306a36Sopenharmony_ci if (was_first) 45162306a36Sopenharmony_ci nfp_ccm_mbox_mark_next_runner(nn); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci spin_unlock_bh(&nn->mbox_cmsg.queue.lock); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (was_first) 45662306a36Sopenharmony_ci wake_up_all(&nn->mbox_cmsg.wq); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci nn_dp_warn(&nn->dp, "time out waiting for mbox response to 0x%02x\n", 45962306a36Sopenharmony_ci type); 46062306a36Sopenharmony_ci return -ETIMEDOUT; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic int 46462306a36Sopenharmony_cinfp_ccm_mbox_msg_prepare(struct nfp_net *nn, struct sk_buff *skb, 46562306a36Sopenharmony_ci enum nfp_ccm_type type, 46662306a36Sopenharmony_ci unsigned int reply_size, unsigned int max_reply_size, 46762306a36Sopenharmony_ci gfp_t flags) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci const unsigned int mbox_max = nfp_ccm_mbox_max_msg(nn); 47062306a36Sopenharmony_ci unsigned int max_len; 47162306a36Sopenharmony_ci ssize_t undersize; 47262306a36Sopenharmony_ci int err; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (unlikely(!(nn->tlv_caps.mbox_cmsg_types & BIT(type)))) { 47562306a36Sopenharmony_ci nn_dp_warn(&nn->dp, 47662306a36Sopenharmony_ci "message type %d not supported by mailbox\n", type); 47762306a36Sopenharmony_ci return -EINVAL; 47862306a36Sopenharmony_ci } 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* If the reply size is unknown assume it will take the entire 48162306a36Sopenharmony_ci * mailbox, the callers should do their best for this to never 48262306a36Sopenharmony_ci * happen. 48362306a36Sopenharmony_ci */ 48462306a36Sopenharmony_ci if (!max_reply_size) 48562306a36Sopenharmony_ci max_reply_size = mbox_max; 48662306a36Sopenharmony_ci max_reply_size = round_up(max_reply_size, 4); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* Make sure we can fit the entire reply into the skb, 48962306a36Sopenharmony_ci * and that we don't have to slow down the mbox handler 49062306a36Sopenharmony_ci * with allocations. 49162306a36Sopenharmony_ci */ 49262306a36Sopenharmony_ci undersize = max_reply_size - (skb_end_pointer(skb) - skb->data); 49362306a36Sopenharmony_ci if (undersize > 0) { 49462306a36Sopenharmony_ci err = pskb_expand_head(skb, 0, undersize, flags); 49562306a36Sopenharmony_ci if (err) { 49662306a36Sopenharmony_ci nn_dp_warn(&nn->dp, 49762306a36Sopenharmony_ci "can't allocate reply buffer for mailbox\n"); 49862306a36Sopenharmony_ci return err; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* Make sure that request and response both fit into the mailbox */ 50362306a36Sopenharmony_ci max_len = max(max_reply_size, round_up(skb->len, 4)); 50462306a36Sopenharmony_ci if (max_len > mbox_max) { 50562306a36Sopenharmony_ci nn_dp_warn(&nn->dp, 50662306a36Sopenharmony_ci "message too big for the mailbox: %u/%u vs %u\n", 50762306a36Sopenharmony_ci skb->len, max_reply_size, mbox_max); 50862306a36Sopenharmony_ci return -EMSGSIZE; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci nfp_ccm_mbox_msg_init(skb, reply_size, max_len); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci return 0; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic int 51762306a36Sopenharmony_cinfp_ccm_mbox_msg_enqueue(struct nfp_net *nn, struct sk_buff *skb, 51862306a36Sopenharmony_ci enum nfp_ccm_type type, bool critical) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct nfp_ccm_hdr *hdr; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci assert_spin_locked(&nn->mbox_cmsg.queue.lock); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (!critical && nn->mbox_cmsg.queue.qlen >= NFP_CCM_MAX_QLEN) { 52562306a36Sopenharmony_ci nn_dp_warn(&nn->dp, "mailbox request queue too long\n"); 52662306a36Sopenharmony_ci return -EBUSY; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci hdr = (void *)skb->data; 53062306a36Sopenharmony_ci hdr->ver = NFP_CCM_ABI_VERSION; 53162306a36Sopenharmony_ci hdr->type = type; 53262306a36Sopenharmony_ci hdr->tag = cpu_to_be16(nn->mbox_cmsg.tag++); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci __skb_queue_tail(&nn->mbox_cmsg.queue, skb); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return 0; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ciint __nfp_ccm_mbox_communicate(struct nfp_net *nn, struct sk_buff *skb, 54062306a36Sopenharmony_ci enum nfp_ccm_type type, 54162306a36Sopenharmony_ci unsigned int reply_size, 54262306a36Sopenharmony_ci unsigned int max_reply_size, bool critical) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci int err; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci err = nfp_ccm_mbox_msg_prepare(nn, skb, type, reply_size, 54762306a36Sopenharmony_ci max_reply_size, GFP_KERNEL); 54862306a36Sopenharmony_ci if (err) 54962306a36Sopenharmony_ci goto err_free_skb; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci spin_lock_bh(&nn->mbox_cmsg.queue.lock); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci err = nfp_ccm_mbox_msg_enqueue(nn, skb, type, critical); 55462306a36Sopenharmony_ci if (err) 55562306a36Sopenharmony_ci goto err_unlock; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* First in queue takes the mailbox lock and processes the batch */ 55862306a36Sopenharmony_ci if (!nfp_ccm_mbox_is_first(nn, skb)) { 55962306a36Sopenharmony_ci bool to; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci spin_unlock_bh(&nn->mbox_cmsg.queue.lock); 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci to = !wait_event_timeout(nn->mbox_cmsg.wq, 56462306a36Sopenharmony_ci nfp_ccm_mbox_done(skb) || 56562306a36Sopenharmony_ci nfp_ccm_mbox_should_run(nn, skb), 56662306a36Sopenharmony_ci msecs_to_jiffies(NFP_CCM_TIMEOUT)); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci /* fast path for those completed by another thread */ 56962306a36Sopenharmony_ci if (nfp_ccm_mbox_done(skb)) { 57062306a36Sopenharmony_ci smp_rmb(); /* pairs with wmb after data is written */ 57162306a36Sopenharmony_ci return nfp_ccm_mbox_skb_return(skb); 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci spin_lock_bh(&nn->mbox_cmsg.queue.lock); 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci if (!nfp_ccm_mbox_is_first(nn, skb)) { 57762306a36Sopenharmony_ci WARN_ON(!to); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci err = nfp_ccm_mbox_unlink_unlock(nn, skb, type); 58062306a36Sopenharmony_ci if (err) 58162306a36Sopenharmony_ci goto err_free_skb; 58262306a36Sopenharmony_ci return 0; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci /* run queue expects the lock held */ 58762306a36Sopenharmony_ci nfp_ccm_mbox_run_queue_unlock(nn); 58862306a36Sopenharmony_ci return nfp_ccm_mbox_skb_return(skb); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cierr_unlock: 59162306a36Sopenharmony_ci spin_unlock_bh(&nn->mbox_cmsg.queue.lock); 59262306a36Sopenharmony_cierr_free_skb: 59362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 59462306a36Sopenharmony_ci return err; 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ciint nfp_ccm_mbox_communicate(struct nfp_net *nn, struct sk_buff *skb, 59862306a36Sopenharmony_ci enum nfp_ccm_type type, 59962306a36Sopenharmony_ci unsigned int reply_size, 60062306a36Sopenharmony_ci unsigned int max_reply_size) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci return __nfp_ccm_mbox_communicate(nn, skb, type, reply_size, 60362306a36Sopenharmony_ci max_reply_size, false); 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic void nfp_ccm_mbox_post_runq_work(struct work_struct *work) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci struct sk_buff *skb; 60962306a36Sopenharmony_ci struct nfp_net *nn; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci nn = container_of(work, struct nfp_net, mbox_cmsg.runq_work); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci spin_lock_bh(&nn->mbox_cmsg.queue.lock); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci skb = __skb_peek(&nn->mbox_cmsg.queue); 61662306a36Sopenharmony_ci if (WARN_ON(!skb || !nfp_ccm_mbox_is_posted(skb) || 61762306a36Sopenharmony_ci !nfp_ccm_mbox_should_run(nn, skb))) { 61862306a36Sopenharmony_ci spin_unlock_bh(&nn->mbox_cmsg.queue.lock); 61962306a36Sopenharmony_ci return; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci nfp_ccm_mbox_run_queue_unlock(nn); 62362306a36Sopenharmony_ci} 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic void nfp_ccm_mbox_post_wait_work(struct work_struct *work) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci struct sk_buff *skb; 62862306a36Sopenharmony_ci struct nfp_net *nn; 62962306a36Sopenharmony_ci int err; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci nn = container_of(work, struct nfp_net, mbox_cmsg.wait_work); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci skb = skb_peek(&nn->mbox_cmsg.queue); 63462306a36Sopenharmony_ci if (WARN_ON(!skb || !nfp_ccm_mbox_is_posted(skb))) 63562306a36Sopenharmony_ci /* Should never happen so it's unclear what to do here.. */ 63662306a36Sopenharmony_ci goto exit_unlock_wake; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci err = nfp_net_mbox_reconfig_wait_posted(nn); 63962306a36Sopenharmony_ci if (!err) 64062306a36Sopenharmony_ci nfp_ccm_mbox_copy_out(nn, skb); 64162306a36Sopenharmony_ci else 64262306a36Sopenharmony_ci nfp_ccm_mbox_mark_all_err(nn, skb, -EIO); 64362306a36Sopenharmony_ciexit_unlock_wake: 64462306a36Sopenharmony_ci nn_ctrl_bar_unlock(nn); 64562306a36Sopenharmony_ci wake_up_all(&nn->mbox_cmsg.wq); 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ciint nfp_ccm_mbox_post(struct nfp_net *nn, struct sk_buff *skb, 64962306a36Sopenharmony_ci enum nfp_ccm_type type, unsigned int max_reply_size) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci int err; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci err = nfp_ccm_mbox_msg_prepare(nn, skb, type, 0, max_reply_size, 65462306a36Sopenharmony_ci GFP_ATOMIC); 65562306a36Sopenharmony_ci if (err) 65662306a36Sopenharmony_ci goto err_free_skb; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci nfp_ccm_mbox_mark_posted(skb); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci spin_lock_bh(&nn->mbox_cmsg.queue.lock); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci err = nfp_ccm_mbox_msg_enqueue(nn, skb, type, false); 66362306a36Sopenharmony_ci if (err) 66462306a36Sopenharmony_ci goto err_unlock; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (nfp_ccm_mbox_is_first(nn, skb)) { 66762306a36Sopenharmony_ci if (nn_ctrl_bar_trylock(nn)) { 66862306a36Sopenharmony_ci nfp_ccm_mbox_copy_in(nn, skb); 66962306a36Sopenharmony_ci nfp_net_mbox_reconfig_post(nn, 67062306a36Sopenharmony_ci NFP_NET_CFG_MBOX_CMD_TLV_CMSG); 67162306a36Sopenharmony_ci queue_work(nn->mbox_cmsg.workq, 67262306a36Sopenharmony_ci &nn->mbox_cmsg.wait_work); 67362306a36Sopenharmony_ci } else { 67462306a36Sopenharmony_ci nfp_ccm_mbox_mark_next_runner(nn); 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci spin_unlock_bh(&nn->mbox_cmsg.queue.lock); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cierr_unlock: 68362306a36Sopenharmony_ci spin_unlock_bh(&nn->mbox_cmsg.queue.lock); 68462306a36Sopenharmony_cierr_free_skb: 68562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 68662306a36Sopenharmony_ci return err; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_cistruct sk_buff * 69062306a36Sopenharmony_cinfp_ccm_mbox_msg_alloc(struct nfp_net *nn, unsigned int req_size, 69162306a36Sopenharmony_ci unsigned int reply_size, gfp_t flags) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci unsigned int max_size; 69462306a36Sopenharmony_ci struct sk_buff *skb; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci if (!reply_size) 69762306a36Sopenharmony_ci max_size = nfp_ccm_mbox_max_msg(nn); 69862306a36Sopenharmony_ci else 69962306a36Sopenharmony_ci max_size = max(req_size, reply_size); 70062306a36Sopenharmony_ci max_size = round_up(max_size, 4); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci skb = alloc_skb(max_size, flags); 70362306a36Sopenharmony_ci if (!skb) 70462306a36Sopenharmony_ci return NULL; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci skb_put(skb, req_size); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci return skb; 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_cibool nfp_ccm_mbox_fits(struct nfp_net *nn, unsigned int size) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci return nfp_ccm_mbox_max_msg(nn) >= size; 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ciint nfp_ccm_mbox_init(struct nfp_net *nn) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci return 0; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_civoid nfp_ccm_mbox_clean(struct nfp_net *nn) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci drain_workqueue(nn->mbox_cmsg.workq); 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ciint nfp_ccm_mbox_alloc(struct nfp_net *nn) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci skb_queue_head_init(&nn->mbox_cmsg.queue); 72962306a36Sopenharmony_ci init_waitqueue_head(&nn->mbox_cmsg.wq); 73062306a36Sopenharmony_ci INIT_WORK(&nn->mbox_cmsg.wait_work, nfp_ccm_mbox_post_wait_work); 73162306a36Sopenharmony_ci INIT_WORK(&nn->mbox_cmsg.runq_work, nfp_ccm_mbox_post_runq_work); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci nn->mbox_cmsg.workq = alloc_workqueue("nfp-ccm-mbox", WQ_UNBOUND, 0); 73462306a36Sopenharmony_ci if (!nn->mbox_cmsg.workq) 73562306a36Sopenharmony_ci return -ENOMEM; 73662306a36Sopenharmony_ci return 0; 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_civoid nfp_ccm_mbox_free(struct nfp_net *nn) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci destroy_workqueue(nn->mbox_cmsg.workq); 74262306a36Sopenharmony_ci WARN_ON(!skb_queue_empty(&nn->mbox_cmsg.queue)); 74362306a36Sopenharmony_ci} 744