0001
0002
0003
0004 #include <linux/delay.h>
0005 #include <linux/device.h>
0006 #include <linux/io.h>
0007 #include <linux/mm.h>
0008
0009 #include "shm_channel.h"
0010
0011 #define PAGE_FRAME_L48_WIDTH_BYTES 6
0012 #define PAGE_FRAME_L48_WIDTH_BITS (PAGE_FRAME_L48_WIDTH_BYTES * 8)
0013 #define PAGE_FRAME_L48_MASK 0x0000FFFFFFFFFFFF
0014 #define PAGE_FRAME_H4_WIDTH_BITS 4
0015 #define VECTOR_MASK 0xFFFF
0016 #define SHMEM_VF_RESET_STATE ((u32)-1)
0017
0018 #define SMC_MSG_TYPE_ESTABLISH_HWC 1
0019 #define SMC_MSG_TYPE_ESTABLISH_HWC_VERSION 0
0020
0021 #define SMC_MSG_TYPE_DESTROY_HWC 2
0022 #define SMC_MSG_TYPE_DESTROY_HWC_VERSION 0
0023
0024 #define SMC_MSG_DIRECTION_REQUEST 0
0025 #define SMC_MSG_DIRECTION_RESPONSE 1
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 union smc_proto_hdr {
0045 u32 as_uint32;
0046
0047 struct {
0048 u8 msg_type : 3;
0049 u8 msg_version : 3;
0050 u8 reserved_1 : 1;
0051 u8 direction : 1;
0052
0053 u8 status;
0054
0055 u8 reserved_2;
0056
0057 u8 reset_vf : 1;
0058 u8 reserved_3 : 6;
0059 u8 owner_is_pf : 1;
0060 };
0061 };
0062
0063 #define SMC_APERTURE_BITS 256
0064 #define SMC_BASIC_UNIT (sizeof(u32))
0065 #define SMC_APERTURE_DWORDS (SMC_APERTURE_BITS / (SMC_BASIC_UNIT * 8))
0066 #define SMC_LAST_DWORD (SMC_APERTURE_DWORDS - 1)
0067
0068 static int mana_smc_poll_register(void __iomem *base, bool reset)
0069 {
0070 void __iomem *ptr = base + SMC_LAST_DWORD * SMC_BASIC_UNIT;
0071 u32 last_dword;
0072 int i;
0073
0074
0075
0076
0077
0078 for (i = 0; i < 20 * 1000; i++) {
0079 last_dword = readl(ptr);
0080
0081
0082 if (reset && last_dword == SHMEM_VF_RESET_STATE)
0083 return 0;
0084
0085
0086 if (!(last_dword & BIT(31)))
0087 return 0;
0088
0089 usleep_range(1000, 2000);
0090 }
0091
0092 return -ETIMEDOUT;
0093 }
0094
0095 static int mana_smc_read_response(struct shm_channel *sc, u32 msg_type,
0096 u32 msg_version, bool reset_vf)
0097 {
0098 void __iomem *base = sc->base;
0099 union smc_proto_hdr hdr;
0100 int err;
0101
0102
0103 err = mana_smc_poll_register(base, reset_vf);
0104 if (err)
0105 return err;
0106
0107 hdr.as_uint32 = readl(base + SMC_LAST_DWORD * SMC_BASIC_UNIT);
0108
0109 if (reset_vf && hdr.as_uint32 == SHMEM_VF_RESET_STATE)
0110 return 0;
0111
0112
0113 if (hdr.msg_type != msg_type || hdr.msg_version > msg_version ||
0114 hdr.direction != SMC_MSG_DIRECTION_RESPONSE) {
0115 dev_err(sc->dev, "Wrong SMC response 0x%x, type=%d, ver=%d\n",
0116 hdr.as_uint32, msg_type, msg_version);
0117 return -EPROTO;
0118 }
0119
0120
0121 if (hdr.status != 0) {
0122 dev_err(sc->dev, "SMC operation failed: 0x%x\n", hdr.status);
0123 return -EPROTO;
0124 }
0125
0126 return 0;
0127 }
0128
0129 void mana_smc_init(struct shm_channel *sc, struct device *dev,
0130 void __iomem *base)
0131 {
0132 sc->dev = dev;
0133 sc->base = base;
0134 }
0135
0136 int mana_smc_setup_hwc(struct shm_channel *sc, bool reset_vf, u64 eq_addr,
0137 u64 cq_addr, u64 rq_addr, u64 sq_addr,
0138 u32 eq_msix_index)
0139 {
0140 union smc_proto_hdr *hdr;
0141 u16 all_addr_h4bits = 0;
0142 u16 frame_addr_seq = 0;
0143 u64 frame_addr = 0;
0144 u8 shm_buf[32];
0145 u64 *shmem;
0146 u32 *dword;
0147 u8 *ptr;
0148 int err;
0149 int i;
0150
0151
0152 err = mana_smc_poll_register(sc->base, false);
0153 if (err) {
0154 dev_err(sc->dev, "Timeout when setting up HWC: %d\n", err);
0155 return err;
0156 }
0157
0158 if (!PAGE_ALIGNED(eq_addr) || !PAGE_ALIGNED(cq_addr) ||
0159 !PAGE_ALIGNED(rq_addr) || !PAGE_ALIGNED(sq_addr))
0160 return -EINVAL;
0161
0162 if ((eq_msix_index & VECTOR_MASK) != eq_msix_index)
0163 return -EINVAL;
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181 memset(shm_buf, 0, sizeof(shm_buf));
0182 ptr = shm_buf;
0183
0184
0185 shmem = (u64 *)ptr;
0186 frame_addr = PHYS_PFN(eq_addr);
0187 *shmem = frame_addr & PAGE_FRAME_L48_MASK;
0188 all_addr_h4bits |= (frame_addr >> PAGE_FRAME_L48_WIDTH_BITS) <<
0189 (frame_addr_seq++ * PAGE_FRAME_H4_WIDTH_BITS);
0190 ptr += PAGE_FRAME_L48_WIDTH_BYTES;
0191
0192
0193 shmem = (u64 *)ptr;
0194 frame_addr = PHYS_PFN(cq_addr);
0195 *shmem = frame_addr & PAGE_FRAME_L48_MASK;
0196 all_addr_h4bits |= (frame_addr >> PAGE_FRAME_L48_WIDTH_BITS) <<
0197 (frame_addr_seq++ * PAGE_FRAME_H4_WIDTH_BITS);
0198 ptr += PAGE_FRAME_L48_WIDTH_BYTES;
0199
0200
0201 shmem = (u64 *)ptr;
0202 frame_addr = PHYS_PFN(rq_addr);
0203 *shmem = frame_addr & PAGE_FRAME_L48_MASK;
0204 all_addr_h4bits |= (frame_addr >> PAGE_FRAME_L48_WIDTH_BITS) <<
0205 (frame_addr_seq++ * PAGE_FRAME_H4_WIDTH_BITS);
0206 ptr += PAGE_FRAME_L48_WIDTH_BYTES;
0207
0208
0209 shmem = (u64 *)ptr;
0210 frame_addr = PHYS_PFN(sq_addr);
0211 *shmem = frame_addr & PAGE_FRAME_L48_MASK;
0212 all_addr_h4bits |= (frame_addr >> PAGE_FRAME_L48_WIDTH_BITS) <<
0213 (frame_addr_seq++ * PAGE_FRAME_H4_WIDTH_BITS);
0214 ptr += PAGE_FRAME_L48_WIDTH_BYTES;
0215
0216
0217 *((u16 *)ptr) = all_addr_h4bits;
0218 ptr += sizeof(u16);
0219
0220
0221 *((u16 *)ptr) = (u16)eq_msix_index;
0222 ptr += sizeof(u16);
0223
0224
0225 *((u32 *)ptr) = 0;
0226
0227 hdr = (union smc_proto_hdr *)ptr;
0228 hdr->msg_type = SMC_MSG_TYPE_ESTABLISH_HWC;
0229 hdr->msg_version = SMC_MSG_TYPE_ESTABLISH_HWC_VERSION;
0230 hdr->direction = SMC_MSG_DIRECTION_REQUEST;
0231 hdr->reset_vf = reset_vf;
0232
0233
0234
0235
0236 dword = (u32 *)shm_buf;
0237 for (i = 0; i < SMC_APERTURE_DWORDS; i++)
0238 writel(*dword++, sc->base + i * SMC_BASIC_UNIT);
0239
0240
0241
0242
0243
0244 err = mana_smc_read_response(sc, SMC_MSG_TYPE_ESTABLISH_HWC,
0245 SMC_MSG_TYPE_ESTABLISH_HWC_VERSION,
0246 reset_vf);
0247 if (err) {
0248 dev_err(sc->dev, "Error when setting up HWC: %d\n", err);
0249 return err;
0250 }
0251
0252 return 0;
0253 }
0254
0255 int mana_smc_teardown_hwc(struct shm_channel *sc, bool reset_vf)
0256 {
0257 union smc_proto_hdr hdr = {};
0258 int err;
0259
0260
0261 err = mana_smc_poll_register(sc->base, false);
0262 if (err) {
0263 dev_err(sc->dev, "Timeout when tearing down HWC\n");
0264 return err;
0265 }
0266
0267
0268 hdr.msg_type = SMC_MSG_TYPE_DESTROY_HWC;
0269 hdr.msg_version = SMC_MSG_TYPE_DESTROY_HWC_VERSION;
0270 hdr.direction = SMC_MSG_DIRECTION_REQUEST;
0271 hdr.reset_vf = reset_vf;
0272
0273
0274
0275
0276 writel(hdr.as_uint32, sc->base + SMC_LAST_DWORD * SMC_BASIC_UNIT);
0277
0278
0279
0280
0281
0282 err = mana_smc_read_response(sc, SMC_MSG_TYPE_DESTROY_HWC,
0283 SMC_MSG_TYPE_DESTROY_HWC_VERSION,
0284 reset_vf);
0285 if (err) {
0286 dev_err(sc->dev, "Error when tearing down HWC: %d\n", err);
0287 return err;
0288 }
0289
0290 return 0;
0291 }