octep_ctrl_mbox.c (7163B)
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#define OCTEP_CTRL_MBOX_INFO_MAGIC_NUM_OFFSET(m) (m) 28#define OCTEP_CTRL_MBOX_INFO_BARMEM_SZ_OFFSET(m) ((m) + 8) 29#define OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(m) ((m) + 24) 30#define OCTEP_CTRL_MBOX_INFO_FW_STATUS_OFFSET(m) ((m) + 144) 31 32#define OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m) ((m) + OCTEP_CTRL_MBOX_INFO_SZ) 33#define OCTEP_CTRL_MBOX_H2FQ_PROD_OFFSET(m) (OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) 34#define OCTEP_CTRL_MBOX_H2FQ_CONS_OFFSET(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) + 4) 35#define OCTEP_CTRL_MBOX_H2FQ_ELEM_SZ_OFFSET(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) + 8) 36#define OCTEP_CTRL_MBOX_H2FQ_ELEM_CNT_OFFSET(m) ((OCTEP_CTRL_MBOX_H2FQ_INFO_OFFSET(m)) + 12) 37 38#define OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m) ((m) + \ 39 OCTEP_CTRL_MBOX_INFO_SZ + \ 40 OCTEP_CTRL_MBOX_H2FQ_INFO_SZ) 41#define OCTEP_CTRL_MBOX_F2HQ_PROD_OFFSET(m) (OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) 42#define OCTEP_CTRL_MBOX_F2HQ_CONS_OFFSET(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 4) 43#define OCTEP_CTRL_MBOX_F2HQ_ELEM_SZ_OFFSET(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 8) 44#define OCTEP_CTRL_MBOX_F2HQ_ELEM_CNT_OFFSET(m) ((OCTEP_CTRL_MBOX_F2HQ_INFO_OFFSET(m)) + 12) 45 46#define OCTEP_CTRL_MBOX_Q_OFFSET(m, i) ((m) + \ 47 (sizeof(struct octep_ctrl_mbox_msg) * (i))) 48 49static u32 octep_ctrl_mbox_circq_inc(u32 index, u32 mask) 50{ 51 return (index + 1) & mask; 52} 53 54static u32 octep_ctrl_mbox_circq_space(u32 pi, u32 ci, u32 mask) 55{ 56 return mask - ((pi - ci) & mask); 57} 58 59static u32 octep_ctrl_mbox_circq_depth(u32 pi, u32 ci, u32 mask) 60{ 61 return ((pi - ci) & mask); 62} 63 64int octep_ctrl_mbox_init(struct octep_ctrl_mbox *mbox) 65{ 66 u64 magic_num, status; 67 68 if (!mbox) 69 return -EINVAL; 70 71 if (!mbox->barmem) { 72 pr_info("octep_ctrl_mbox : Invalid barmem %p\n", mbox->barmem); 73 return -EINVAL; 74 } 75 76 magic_num = readq(OCTEP_CTRL_MBOX_INFO_MAGIC_NUM_OFFSET(mbox->barmem)); 77 if (magic_num != OCTEP_CTRL_MBOX_MAGIC_NUMBER) { 78 pr_info("octep_ctrl_mbox : Invalid magic number %llx\n", magic_num); 79 return -EINVAL; 80 } 81 82 status = readq(OCTEP_CTRL_MBOX_INFO_FW_STATUS_OFFSET(mbox->barmem)); 83 if (status != OCTEP_CTRL_MBOX_STATUS_READY) { 84 pr_info("octep_ctrl_mbox : Firmware is not ready.\n"); 85 return -EINVAL; 86 } 87 88 mbox->barmem_sz = readl(OCTEP_CTRL_MBOX_INFO_BARMEM_SZ_OFFSET(mbox->barmem)); 89 90 writeq(OCTEP_CTRL_MBOX_STATUS_INIT, OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem)); 91 92 mbox->h2fq.elem_cnt = readl(OCTEP_CTRL_MBOX_H2FQ_ELEM_CNT_OFFSET(mbox->barmem)); 93 mbox->h2fq.elem_sz = readl(OCTEP_CTRL_MBOX_H2FQ_ELEM_SZ_OFFSET(mbox->barmem)); 94 mbox->h2fq.mask = (mbox->h2fq.elem_cnt - 1); 95 mutex_init(&mbox->h2fq_lock); 96 97 mbox->f2hq.elem_cnt = readl(OCTEP_CTRL_MBOX_F2HQ_ELEM_CNT_OFFSET(mbox->barmem)); 98 mbox->f2hq.elem_sz = readl(OCTEP_CTRL_MBOX_F2HQ_ELEM_SZ_OFFSET(mbox->barmem)); 99 mbox->f2hq.mask = (mbox->f2hq.elem_cnt - 1); 100 mutex_init(&mbox->f2hq_lock); 101 102 mbox->h2fq.hw_prod = OCTEP_CTRL_MBOX_H2FQ_PROD_OFFSET(mbox->barmem); 103 mbox->h2fq.hw_cons = OCTEP_CTRL_MBOX_H2FQ_CONS_OFFSET(mbox->barmem); 104 mbox->h2fq.hw_q = mbox->barmem + 105 OCTEP_CTRL_MBOX_INFO_SZ + 106 OCTEP_CTRL_MBOX_H2FQ_INFO_SZ + 107 OCTEP_CTRL_MBOX_F2HQ_INFO_SZ; 108 109 mbox->f2hq.hw_prod = OCTEP_CTRL_MBOX_F2HQ_PROD_OFFSET(mbox->barmem); 110 mbox->f2hq.hw_cons = OCTEP_CTRL_MBOX_F2HQ_CONS_OFFSET(mbox->barmem); 111 mbox->f2hq.hw_q = mbox->h2fq.hw_q + 112 ((mbox->h2fq.elem_sz + sizeof(union octep_ctrl_mbox_msg_hdr)) * 113 mbox->h2fq.elem_cnt); 114 115 /* ensure ready state is seen after everything is initialized */ 116 wmb(); 117 writeq(OCTEP_CTRL_MBOX_STATUS_READY, OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem)); 118 119 pr_info("Octep ctrl mbox : Init successful.\n"); 120 121 return 0; 122} 123 124int octep_ctrl_mbox_send(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg) 125{ 126 unsigned long timeout = msecs_to_jiffies(OCTEP_CTRL_MBOX_MSG_TIMEOUT_MS); 127 unsigned long period = msecs_to_jiffies(OCTEP_CTRL_MBOX_MSG_WAIT_MS); 128 struct octep_ctrl_mbox_q *q; 129 unsigned long expire; 130 u64 *mbuf, *word0; 131 u8 __iomem *qidx; 132 u16 pi, ci; 133 int i; 134 135 if (!mbox || !msg) 136 return -EINVAL; 137 138 q = &mbox->h2fq; 139 pi = readl(q->hw_prod); 140 ci = readl(q->hw_cons); 141 142 if (!octep_ctrl_mbox_circq_space(pi, ci, q->mask)) 143 return -ENOMEM; 144 145 qidx = OCTEP_CTRL_MBOX_Q_OFFSET(q->hw_q, pi); 146 mbuf = (u64 *)msg->msg; 147 word0 = &msg->hdr.word0; 148 149 mutex_lock(&mbox->h2fq_lock); 150 for (i = 1; i <= msg->hdr.sizew; i++) 151 writeq(*mbuf++, (qidx + (i * 8))); 152 153 writeq(*word0, qidx); 154 155 pi = octep_ctrl_mbox_circq_inc(pi, q->mask); 156 writel(pi, q->hw_prod); 157 mutex_unlock(&mbox->h2fq_lock); 158 159 /* don't check for notification response */ 160 if (msg->hdr.flags & OCTEP_CTRL_MBOX_MSG_HDR_FLAG_NOTIFY) 161 return 0; 162 163 expire = jiffies + timeout; 164 while (true) { 165 *word0 = readq(qidx); 166 if (msg->hdr.flags == OCTEP_CTRL_MBOX_MSG_HDR_FLAG_RESP) 167 break; 168 schedule_timeout_interruptible(period); 169 if (signal_pending(current) || time_after(jiffies, expire)) { 170 pr_info("octep_ctrl_mbox: Timed out\n"); 171 return -EBUSY; 172 } 173 } 174 mbuf = (u64 *)msg->msg; 175 for (i = 1; i <= msg->hdr.sizew; i++) 176 *mbuf++ = readq(qidx + (i * 8)); 177 178 return 0; 179} 180 181int octep_ctrl_mbox_recv(struct octep_ctrl_mbox *mbox, struct octep_ctrl_mbox_msg *msg) 182{ 183 struct octep_ctrl_mbox_q *q; 184 u32 count, pi, ci; 185 u8 __iomem *qidx; 186 u64 *mbuf; 187 int i; 188 189 if (!mbox || !msg) 190 return -EINVAL; 191 192 q = &mbox->f2hq; 193 pi = readl(q->hw_prod); 194 ci = readl(q->hw_cons); 195 count = octep_ctrl_mbox_circq_depth(pi, ci, q->mask); 196 if (!count) 197 return -EAGAIN; 198 199 qidx = OCTEP_CTRL_MBOX_Q_OFFSET(q->hw_q, ci); 200 mbuf = (u64 *)msg->msg; 201 202 mutex_lock(&mbox->f2hq_lock); 203 204 msg->hdr.word0 = readq(qidx); 205 for (i = 1; i <= msg->hdr.sizew; i++) 206 *mbuf++ = readq(qidx + (i * 8)); 207 208 ci = octep_ctrl_mbox_circq_inc(ci, q->mask); 209 writel(ci, q->hw_cons); 210 211 mutex_unlock(&mbox->f2hq_lock); 212 213 if (msg->hdr.flags != OCTEP_CTRL_MBOX_MSG_HDR_FLAG_REQ || !mbox->process_req) 214 return 0; 215 216 mbox->process_req(mbox->user_ctx, msg); 217 mbuf = (u64 *)msg->msg; 218 for (i = 1; i <= msg->hdr.sizew; i++) 219 writeq(*mbuf++, (qidx + (i * 8))); 220 221 writeq(msg->hdr.word0, qidx); 222 223 return 0; 224} 225 226int octep_ctrl_mbox_uninit(struct octep_ctrl_mbox *mbox) 227{ 228 if (!mbox) 229 return -EINVAL; 230 231 writeq(OCTEP_CTRL_MBOX_STATUS_UNINIT, 232 OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem)); 233 /* ensure uninit state is written before uninitialization */ 234 wmb(); 235 236 mutex_destroy(&mbox->h2fq_lock); 237 mutex_destroy(&mbox->f2hq_lock); 238 239 writeq(OCTEP_CTRL_MBOX_STATUS_INVALID, 240 OCTEP_CTRL_MBOX_INFO_HOST_STATUS_OFFSET(mbox->barmem)); 241 242 pr_info("Octep ctrl mbox : Uninit successful.\n"); 243 244 return 0; 245}