0001
0002
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
0026
0027
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
0109
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
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 }