Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
0002 /* Copyright (C) 2016-2019 Netronome Systems, Inc. */
0003 
0004 #include <linux/bitops.h>
0005 
0006 #include "ccm.h"
0007 #include "nfp_app.h"
0008 #include "nfp_net.h"
0009 
0010 #define ccm_warn(app, msg...)   nn_dp_warn(&(app)->ctrl->dp, msg)
0011 
0012 #define NFP_CCM_TAG_ALLOC_SPAN  (U16_MAX / 4)
0013 
0014 static bool nfp_ccm_all_tags_busy(struct nfp_ccm *ccm)
0015 {
0016     u16 used_tags;
0017 
0018     used_tags = ccm->tag_alloc_next - ccm->tag_alloc_last;
0019 
0020     return used_tags > NFP_CCM_TAG_ALLOC_SPAN;
0021 }
0022 
0023 static int nfp_ccm_alloc_tag(struct nfp_ccm *ccm)
0024 {
0025     /* CCM is for FW communication which is request-reply.  To make sure
0026      * we don't reuse the message ID too early after timeout - limit the
0027      * number of requests in flight.
0028      */
0029     if (unlikely(nfp_ccm_all_tags_busy(ccm))) {
0030         ccm_warn(ccm->app, "all FW request contexts busy!\n");
0031         return -EAGAIN;
0032     }
0033 
0034     WARN_ON(__test_and_set_bit(ccm->tag_alloc_next, ccm->tag_allocator));
0035     return ccm->tag_alloc_next++;
0036 }
0037 
0038 static void nfp_ccm_free_tag(struct nfp_ccm *ccm, u16 tag)
0039 {
0040     WARN_ON(!__test_and_clear_bit(tag, ccm->tag_allocator));
0041 
0042     while (!test_bit(ccm->tag_alloc_last, ccm->tag_allocator) &&
0043            ccm->tag_alloc_last != ccm->tag_alloc_next)
0044         ccm->tag_alloc_last++;
0045 }
0046 
0047 static struct sk_buff *__nfp_ccm_reply(struct nfp_ccm *ccm, u16 tag)
0048 {
0049     unsigned int msg_tag;
0050     struct sk_buff *skb;
0051 
0052     skb_queue_walk(&ccm->replies, skb) {
0053         msg_tag = nfp_ccm_get_tag(skb);
0054         if (msg_tag == tag) {
0055             nfp_ccm_free_tag(ccm, tag);
0056             __skb_unlink(skb, &ccm->replies);
0057             return skb;
0058         }
0059     }
0060 
0061     return NULL;
0062 }
0063 
0064 static struct sk_buff *
0065 nfp_ccm_reply(struct nfp_ccm *ccm, struct nfp_app *app, u16 tag)
0066 {
0067     struct sk_buff *skb;
0068 
0069     nfp_ctrl_lock(app->ctrl);
0070     skb = __nfp_ccm_reply(ccm, tag);
0071     nfp_ctrl_unlock(app->ctrl);
0072 
0073     return skb;
0074 }
0075 
0076 static struct sk_buff *
0077 nfp_ccm_reply_drop_tag(struct nfp_ccm *ccm, struct nfp_app *app, u16 tag)
0078 {
0079     struct sk_buff *skb;
0080 
0081     nfp_ctrl_lock(app->ctrl);
0082     skb = __nfp_ccm_reply(ccm, tag);
0083     if (!skb)
0084         nfp_ccm_free_tag(ccm, tag);
0085     nfp_ctrl_unlock(app->ctrl);
0086 
0087     return skb;
0088 }
0089 
0090 static struct sk_buff *
0091 nfp_ccm_wait_reply(struct nfp_ccm *ccm, struct nfp_app *app,
0092            enum nfp_ccm_type type, int tag)
0093 {
0094     struct sk_buff *skb;
0095     int i, err;
0096 
0097     for (i = 0; i < 50; i++) {
0098         udelay(4);
0099         skb = nfp_ccm_reply(ccm, app, tag);
0100         if (skb)
0101             return skb;
0102     }
0103 
0104     err = wait_event_interruptible_timeout(ccm->wq,
0105                            skb = nfp_ccm_reply(ccm, app,
0106                                    tag),
0107                            msecs_to_jiffies(5000));
0108     /* We didn't get a response - try last time and atomically drop
0109      * the tag even if no response is matched.
0110      */
0111     if (!skb)
0112         skb = nfp_ccm_reply_drop_tag(ccm, app, tag);
0113     if (err < 0) {
0114         ccm_warn(app, "%s waiting for response to 0x%02x: %d\n",
0115              err == ERESTARTSYS ? "interrupted" : "error",
0116              type, err);
0117         return ERR_PTR(err);
0118     }
0119     if (!skb) {
0120         ccm_warn(app, "timeout waiting for response to 0x%02x\n", type);
0121         return ERR_PTR(-ETIMEDOUT);
0122     }
0123 
0124     return skb;
0125 }
0126 
0127 struct sk_buff *
0128 nfp_ccm_communicate(struct nfp_ccm *ccm, struct sk_buff *skb,
0129             enum nfp_ccm_type type, unsigned int reply_size)
0130 {
0131     struct nfp_app *app = ccm->app;
0132     struct nfp_ccm_hdr *hdr;
0133     int reply_type, tag;
0134 
0135     nfp_ctrl_lock(app->ctrl);
0136     tag = nfp_ccm_alloc_tag(ccm);
0137     if (tag < 0) {
0138         nfp_ctrl_unlock(app->ctrl);
0139         dev_kfree_skb_any(skb);
0140         return ERR_PTR(tag);
0141     }
0142 
0143     hdr = (void *)skb->data;
0144     hdr->ver = NFP_CCM_ABI_VERSION;
0145     hdr->type = type;
0146     hdr->tag = cpu_to_be16(tag);
0147 
0148     __nfp_app_ctrl_tx(app, skb);
0149 
0150     nfp_ctrl_unlock(app->ctrl);
0151 
0152     skb = nfp_ccm_wait_reply(ccm, app, type, tag);
0153     if (IS_ERR(skb))
0154         return skb;
0155 
0156     reply_type = nfp_ccm_get_type(skb);
0157     if (reply_type != __NFP_CCM_REPLY(type)) {
0158         ccm_warn(app, "cmsg drop - wrong type 0x%02x != 0x%02lx!\n",
0159              reply_type, __NFP_CCM_REPLY(type));
0160         goto err_free;
0161     }
0162     /* 0 reply_size means caller will do the validation */
0163     if (reply_size && skb->len != reply_size) {
0164         ccm_warn(app, "cmsg drop - type 0x%02x wrong size %d != %d!\n",
0165              type, skb->len, reply_size);
0166         goto err_free;
0167     }
0168 
0169     return skb;
0170 err_free:
0171     dev_kfree_skb_any(skb);
0172     return ERR_PTR(-EIO);
0173 }
0174 
0175 void nfp_ccm_rx(struct nfp_ccm *ccm, struct sk_buff *skb)
0176 {
0177     struct nfp_app *app = ccm->app;
0178     unsigned int tag;
0179 
0180     if (unlikely(skb->len < sizeof(struct nfp_ccm_hdr))) {
0181         ccm_warn(app, "cmsg drop - too short %d!\n", skb->len);
0182         goto err_free;
0183     }
0184 
0185     nfp_ctrl_lock(app->ctrl);
0186 
0187     tag = nfp_ccm_get_tag(skb);
0188     if (unlikely(!test_bit(tag, ccm->tag_allocator))) {
0189         ccm_warn(app, "cmsg drop - no one is waiting for tag %u!\n",
0190              tag);
0191         goto err_unlock;
0192     }
0193 
0194     __skb_queue_tail(&ccm->replies, skb);
0195     wake_up_interruptible_all(&ccm->wq);
0196 
0197     nfp_ctrl_unlock(app->ctrl);
0198     return;
0199 
0200 err_unlock:
0201     nfp_ctrl_unlock(app->ctrl);
0202 err_free:
0203     dev_kfree_skb_any(skb);
0204 }
0205 
0206 int nfp_ccm_init(struct nfp_ccm *ccm, struct nfp_app *app)
0207 {
0208     ccm->app = app;
0209     skb_queue_head_init(&ccm->replies);
0210     init_waitqueue_head(&ccm->wq);
0211     return 0;
0212 }
0213 
0214 void nfp_ccm_clean(struct nfp_ccm *ccm)
0215 {
0216     WARN_ON(!skb_queue_empty(&ccm->replies));
0217 }