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