1 // SPDX-License-Identifier: GPL-2.0 2 /* Marvell Octeon EP (EndPoint) Ethernet Driver 3 * 4 * Copyright (C) 2020 Marvell. 5 * 6 */ 7 #include <linux/types.h> 8 #include <linux/errno.h> 9 #include <linux/string.h> 10 #include <linux/mutex.h> 11 #include <linux/jiffies.h> 12 #include <linux/sched.h> 13 #include <linux/sched/signal.h> 14 #include <linux/io.h> 15 #include <linux/pci.h> 16 #include <linux/etherdevice.h> 17 18 #include "octep_ctrl_mbox.h" 19 #include "octep_config.h" 20 #include "octep_main.h" 21 22 /* Timeout in msecs for message response */ 23 #define OCTEP_CTRL_MBOX_MSG_TIMEOUT_MS 100 24 /* Time in msecs to wait for message response */ 25 #define OCTEP_CTRL_MBOX_MSG_WAIT_MS 10 26 27 /* Size of mbox info in bytes */ 28 #define OCTEP_CTRL_MBOX_INFO_SZ 256 29 /* Size of mbox host to fw queue info in bytes */ 30 #define OCTEP_CTRL_MBOX_H2FQ_INFO_SZ 16 31 /* Size of mbox fw to host queue info in bytes */ 32 #define OCTEP_CTRL_MBOX_F2HQ_INFO_SZ 16 33 34 #define OCTEP_CTRL_MBOX_TOTAL_INFO_SZ (OCTEP_CTRL_MBOX_INFO_SZ + \ 35 OCTEP_CTRL_MBOX_H2FQ_INFO_SZ + \ 36 OCTEP_CTRL_MBOX_F2HQ_INFO_SZ) 37 38 #define OCTEP_CTRL_MBOX_INFO_MAGIC_NUM(m) (m) 39 #define OCTEP_CTRL_MBOX_INFO_BARMEM_SZ(m) ((m) + 8) 40 #define OCTEP_CTRL_MBOX_INFO_HOST_VERSION(m) ((m) + 16) 41 #define OCTEP_CTRL_MBOX_INFO_HOST_STATUS(m) ((m) + 24) 42 #define OCTEP_CTRL_MBOX_INFO_FW_VERSION(m) ((m) + 136) 43 #define OCTEP_CTRL_MBOX_INFO_FW_STATUS(m) ((m) + 144) 44 45 #define OCTEP_CTRL_MBOX_H2FQ_INFO(m) ((m) + OCTEP_CTRL_MBOX_INFO_SZ) 46 #define OCTEP_CTRL_MBOX_H2FQ_PROD(m) (OCTEP_CTRL_MBOX_H2FQ_INFO(m)) 47 #define OCTEP_CTRL_MBOX_H2FQ_CONS(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO(m)) + 4) 48 #define OCTEP_CTRL_MBOX_H2FQ_SZ(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO(m)) + 8) 49 50 #define OCTEP_CTRL_MBOX_F2HQ_INFO(m) ((m) + \ 51 OCTEP_CTRL_MBOX_INFO_SZ + \ 52 OCTEP_CTRL_MBOX_H2FQ_INFO_SZ) 53 #define OCTEP_CTRL_MBOX_F2HQ_PROD(m) (OCTEP_CTRL_MBOX_F2HQ_INFO(m)) 54 #define OCTEP_CTRL_MBOX_F2HQ_CONS(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO(m)) + 4) 55 #define OCTEP_CTRL_MBOX_F2HQ_SZ(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO(m)) + 8) 56 57 static const u32 mbox_hdr_sz = sizeof(union octep_ctrl_mbox_msg_hdr); 58 59 static u32 octep_ctrl_mbox_circq_inc(u32 index, u32 inc, u32 sz) 60 { 61 return (index + inc) % sz; 62 } 63 64 static u32 octep_ctrl_mbox_circq_space(u32 pi, u32 ci, u32 sz) 65 { 66 return sz - (abs(pi - ci) % sz); 67 } 68 69 static u32 octep_ctrl_mbox_circq_depth(u32 pi, u32 ci, u32 sz) 70 { 71 return (abs(pi - ci) % sz); 72 } 73 74 int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox) 75 { 76 u64 magic_num, status, fw_versions; 77 78 if (!mbox) 79 return -EINVAL; 80 81 if (!mbox->barmem) { 82 pr_info("octep_ctrl_mbox : Invalid barmem %p\n", mbox->barmem); 83 return -EINVAL; 84 } 85 86 magic_num = readq(OCTEP_CTRL_MBOX_INFO_MAGIC_NUM(mbox->barmem)); 87 if (magic_num != OCTEP_CTRL_MBOX_MAGIC_NUMBER) { 88 pr_info("octep_ctrl_mbox : Invalid magic number %llx\n", magic_num); 89 return -EINVAL; 90 } 91 92 status = readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)); 93 if (status != OCTEP_CTRL_MBOX_STATUS_READY) { 94 pr_info("octep_ctrl_mbox : Firmware is not ready.\n"); 95 return -EINVAL; 96 } 97 98 fw_versions = readq(OCTEP_CTRL_MBOX_INFO_FW_VERSION(mbox->barmem)); 99 mbox->min_fw_version = ((fw_versions & 0xffffffff00000000ull) >> 32); 100 mbox->max_fw_version = (fw_versions & 0xffffffff); 101 mbox->barmem_sz = readl(OCTEP_CTRL_MBOX_INFO_BARMEM_SZ(mbox->barmem)); 102 103 writeq(OCTEP_CTRL_MBOX_STATUS_INIT, 104 OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem)); 105 106 mutex_init(&mbox->h2fq_lock); 107 mutex_init(&mbox->f2hq_lock); 108 109 mbox->h2fq.sz = readl(OCTEP_CTRL_MBOX_H2FQ_SZ(mbox->barmem)); 110 mbox->h2fq.hw_prod = OCTEP_CTRL_MBOX_H2FQ_PROD(mbox->barmem); 111 mbox->h2fq.hw_cons = OCTEP_CTRL_MBOX_H2FQ_CONS(mbox->barmem); 112 mbox->h2fq.hw_q = mbox->barmem + OCTEP_CTRL_MBOX_TOTAL_INFO_SZ; 113 114 mbox->f2hq.sz = readl(OCTEP_CTRL_MBOX_F2HQ_SZ(mbox->barmem)); 115 mbox->f2hq.hw_prod = OCTEP_CTRL_MBOX_F2HQ_PROD(mbox->barmem); 116 mbox->f2hq.hw_cons = OCTEP_CTRL_MBOX_F2HQ_CONS(mbox->barmem); 117 mbox->f2hq.hw_q = mbox->barmem + 118 OCTEP_CTRL_MBOX_TOTAL_INFO_SZ + 119 mbox->h2fq.sz; 120 121 writeq(mbox->version, OCTEP_CTRL_MBOX_INFO_HOST_VERSION(mbox->barmem)); 122 /* ensure ready state is seen after everything is initialized */ 123 wmb(); 124 writeq(OCTEP_CTRL_MBOX_STATUS_READY, 125 OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem)); 126 127 pr_info("Octep ctrl mbox : Init successful.\n"); 128 129 return 0; 130 } 131 132 static void 133 octep_write_mbox_data(struct octep_ctrl_mbox_q *q, u32 *pi, u32 ci, void *buf, u32 w_sz) 134 { 135 u8 __iomem *qbuf; 136 u32 cp_sz; 137 138 /* Assumption: Caller has ensured enough write space */ 139 qbuf = (q->hw_q + *pi); 140 if (*pi < ci) { 141 /* copy entire w_sz */ 142 memcpy_toio(qbuf, buf, w_sz); 143 *pi = octep_ctrl_mbox_circq_inc(*pi, w_sz, q->sz); 144 } else { 145 /* copy up to end of queue */ 146 cp_sz = min((q->sz - *pi), w_sz); 147 memcpy_toio(qbuf, buf, cp_sz); 148 w_sz -= cp_sz; 149 *pi = octep_ctrl_mbox_circq_inc(*pi, cp_sz, q->sz); 150 if (w_sz) { 151 /* roll over and copy remaining w_sz */ 152 buf += cp_sz; 153 qbuf = (q->hw_q + *pi); 154 memcpy_toio(qbuf, buf, w_sz); 155 *pi = octep_ctrl_mbox_circq_inc(*pi, w_sz, q->sz); 156 } 157 } 158 } 159 160 int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg) 161 { 162 struct octep_ctrl_mbox_msg_buf *sg; 163 struct octep_ctrl_mbox_q *q; 164 u32 pi, ci, buf_sz, w_sz; 165 int s; 166 167 if (!mbox || !msg) 168 return -EINVAL; 169 170 if (readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)) != OCTEP_CTRL_MBOX_STATUS_READY) 171 return -EIO; 172 173 mutex_lock(&mbox->h2fq_lock); 174 q = &mbox->h2fq; 175 pi = readl(q->hw_prod); 176 ci = readl(q->hw_cons); 177 178 if (octep_ctrl_mbox_circq_space(pi, ci, q->sz) < (msg->hdr.s.sz + mbox_hdr_sz)) { 179 mutex_unlock(&mbox->h2fq_lock); 180 return -EAGAIN; 181 } 182 183 octep_write_mbox_data(q, &pi, ci, (void *)&msg->hdr, mbox_hdr_sz); 184 buf_sz = msg->hdr.s.sz; 185 for (s = 0; ((s < msg->sg_num) && (buf_sz > 0)); s++) { 186 sg = &msg->sg_list[s]; 187 w_sz = (sg->sz <= buf_sz) ? sg->sz : buf_sz; 188 octep_write_mbox_data(q, &pi, ci, sg->msg, w_sz); 189 buf_sz -= w_sz; 190 } 191 writel(pi, q->hw_prod); 192 mutex_unlock(&mbox->h2fq_lock); 193 194 return 0; 195 } 196 197 static void 198 octep_read_mbox_data(struct octep_ctrl_mbox_q *q, u32 pi, u32 *ci, void *buf, u32 r_sz) 199 { 200 u8 __iomem *qbuf; 201 u32 cp_sz; 202 203 /* Assumption: Caller has ensured enough read space */ 204 qbuf = (q->hw_q + *ci); 205 if (*ci < pi) { 206 /* copy entire r_sz */ 207 memcpy_fromio(buf, qbuf, r_sz); 208 *ci = octep_ctrl_mbox_circq_inc(*ci, r_sz, q->sz); 209 } else { 210 /* copy up to end of queue */ 211 cp_sz = min((q->sz - *ci), r_sz); 212 memcpy_fromio(buf, qbuf, cp_sz); 213 r_sz -= cp_sz; 214 *ci = octep_ctrl_mbox_circq_inc(*ci, cp_sz, q->sz); 215 if (r_sz) { 216 /* roll over and copy remaining r_sz */ 217 buf += cp_sz; 218 qbuf = (q->hw_q + *ci); 219 memcpy_fromio(buf, qbuf, r_sz); 220 *ci = octep_ctrl_mbox_circq_inc(*ci, r_sz, q->sz); 221 } 222 } 223 } 224 225 int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg) 226 { 227 struct octep_ctrl_mbox_msg_buf *sg; 228 u32 pi, ci, r_sz, buf_sz, q_depth; 229 struct octep_ctrl_mbox_q *q; 230 int s; 231 232 if (readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS(mbox->barmem)) != OCTEP_CTRL_MBOX_STATUS_READY) 233 return -EIO; 234 235 mutex_lock(&mbox->f2hq_lock); 236 q = &mbox->f2hq; 237 pi = readl(q->hw_prod); 238 ci = readl(q->hw_cons); 239 240 q_depth = octep_ctrl_mbox_circq_depth(pi, ci, q->sz); 241 if (q_depth < mbox_hdr_sz) { 242 mutex_unlock(&mbox->f2hq_lock); 243 return -EAGAIN; 244 } 245 246 octep_read_mbox_data(q, pi, &ci, (void *)&msg->hdr, mbox_hdr_sz); 247 buf_sz = msg->hdr.s.sz; 248 for (s = 0; ((s < msg->sg_num) && (buf_sz > 0)); s++) { 249 sg = &msg->sg_list[s]; 250 r_sz = (sg->sz <= buf_sz) ? sg->sz : buf_sz; 251 octep_read_mbox_data(q, pi, &ci, sg->msg, r_sz); 252 buf_sz -= r_sz; 253 } 254 writel(ci, q->hw_cons); 255 mutex_unlock(&mbox->f2hq_lock); 256 257 return 0; 258 } 259 260 int octep_ctrl_mbox_uninit(struct octep_ctrl_mbox *mbox) 261 { 262 if (!mbox) 263 return -EINVAL; 264 if (!mbox->barmem) 265 return -EINVAL; 266 267 writeq(0, OCTEP_CTRL_MBOX_INFO_HOST_VERSION(mbox->barmem)); 268 writeq(OCTEP_CTRL_MBOX_STATUS_INVALID, 269 OCTEP_CTRL_MBOX_INFO_HOST_STATUS(mbox->barmem)); 270 /* ensure uninit state is written before uninitialization */ 271 wmb(); 272 273 mutex_destroy(&mbox->h2fq_lock); 274 mutex_destroy(&mbox->f2hq_lock); 275 276 pr_info("Octep ctrl mbox : Uninit successful.\n"); 277 278 return 0; 279 } 280