1 // SPDX-License-Identifier: GPL-2.0+ 2 /* Microchip VCAP API debug file system support 3 * 4 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. 5 * 6 */ 7 8 #include "vcap_api_private.h" 9 #include "vcap_api_debugfs.h" 10 11 struct vcap_admin_debugfs_info { 12 struct vcap_control *vctrl; 13 struct vcap_admin *admin; 14 }; 15 16 struct vcap_port_debugfs_info { 17 struct vcap_control *vctrl; 18 struct net_device *ndev; 19 }; 20 21 /* Dump the keyfields value and mask values */ 22 static void vcap_debugfs_show_rule_keyfield(struct vcap_control *vctrl, 23 struct vcap_output_print *out, 24 enum vcap_key_field key, 25 const struct vcap_field *keyfield, 26 struct vcap_client_keyfield_data *data) 27 { 28 bool hex = false; 29 u8 *value, *mask; 30 int idx, bytes; 31 32 out->prf(out->dst, " %s: W%d: ", vcap_keyfield_name(vctrl, key), 33 keyfield[key].width); 34 35 switch (keyfield[key].type) { 36 case VCAP_FIELD_BIT: 37 out->prf(out->dst, "%d/%d", data->u1.value, data->u1.mask); 38 break; 39 case VCAP_FIELD_U32: 40 value = (u8 *)(&data->u32.value); 41 mask = (u8 *)(&data->u32.mask); 42 43 if (key == VCAP_KF_L3_IP4_SIP || key == VCAP_KF_L3_IP4_DIP) { 44 out->prf(out->dst, "%pI4h/%pI4h", &data->u32.value, 45 &data->u32.mask); 46 } else if (key == VCAP_KF_ETYPE || 47 key == VCAP_KF_IF_IGR_PORT_MASK) { 48 hex = true; 49 } else { 50 u32 fmsk = (1 << keyfield[key].width) - 1; 51 52 out->prf(out->dst, "%u/%u", data->u32.value & fmsk, 53 data->u32.mask & fmsk); 54 } 55 break; 56 case VCAP_FIELD_U48: 57 value = data->u48.value; 58 mask = data->u48.mask; 59 if (key == VCAP_KF_L2_SMAC || key == VCAP_KF_L2_DMAC) 60 out->prf(out->dst, "%pMR/%pMR", data->u48.value, 61 data->u48.mask); 62 else 63 hex = true; 64 break; 65 case VCAP_FIELD_U56: 66 value = data->u56.value; 67 mask = data->u56.mask; 68 hex = true; 69 break; 70 case VCAP_FIELD_U64: 71 value = data->u64.value; 72 mask = data->u64.mask; 73 hex = true; 74 break; 75 case VCAP_FIELD_U72: 76 value = data->u72.value; 77 mask = data->u72.mask; 78 hex = true; 79 break; 80 case VCAP_FIELD_U112: 81 value = data->u112.value; 82 mask = data->u112.mask; 83 hex = true; 84 break; 85 case VCAP_FIELD_U128: 86 if (key == VCAP_KF_L3_IP6_SIP || key == VCAP_KF_L3_IP6_DIP) { 87 u8 nvalue[16], nmask[16]; 88 89 vcap_netbytes_copy(nvalue, data->u128.value, 90 sizeof(nvalue)); 91 vcap_netbytes_copy(nmask, data->u128.mask, 92 sizeof(nmask)); 93 out->prf(out->dst, "%pI6/%pI6", nvalue, nmask); 94 } else { 95 hex = true; 96 } 97 break; 98 } 99 if (hex) { 100 bytes = DIV_ROUND_UP(keyfield[key].width, BITS_PER_BYTE); 101 out->prf(out->dst, "0x"); 102 for (idx = 0; idx < bytes; ++idx) 103 out->prf(out->dst, "%02x", value[bytes - idx - 1]); 104 out->prf(out->dst, "/0x"); 105 for (idx = 0; idx < bytes; ++idx) 106 out->prf(out->dst, "%02x", mask[bytes - idx - 1]); 107 } 108 out->prf(out->dst, "\n"); 109 } 110 111 static void 112 vcap_debugfs_show_rule_actionfield(struct vcap_control *vctrl, 113 struct vcap_output_print *out, 114 enum vcap_action_field action, 115 const struct vcap_field *actionfield, 116 u8 *value) 117 { 118 bool hex = false; 119 int idx, bytes; 120 u32 fmsk, val; 121 122 out->prf(out->dst, " %s: W%d: ", 123 vcap_actionfield_name(vctrl, action), 124 actionfield[action].width); 125 126 switch (actionfield[action].type) { 127 case VCAP_FIELD_BIT: 128 out->prf(out->dst, "%d", value[0]); 129 break; 130 case VCAP_FIELD_U32: 131 fmsk = (1 << actionfield[action].width) - 1; 132 val = *(u32 *)value; 133 out->prf(out->dst, "%u", val & fmsk); 134 break; 135 case VCAP_FIELD_U48: 136 case VCAP_FIELD_U56: 137 case VCAP_FIELD_U64: 138 case VCAP_FIELD_U72: 139 case VCAP_FIELD_U112: 140 case VCAP_FIELD_U128: 141 hex = true; 142 break; 143 } 144 if (hex) { 145 bytes = DIV_ROUND_UP(actionfield[action].width, BITS_PER_BYTE); 146 out->prf(out->dst, "0x"); 147 for (idx = 0; idx < bytes; ++idx) 148 out->prf(out->dst, "%02x", value[bytes - idx - 1]); 149 } 150 out->prf(out->dst, "\n"); 151 } 152 153 static int vcap_debugfs_show_rule_keyset(struct vcap_rule_internal *ri, 154 struct vcap_output_print *out) 155 { 156 struct vcap_control *vctrl = ri->vctrl; 157 struct vcap_admin *admin = ri->admin; 158 enum vcap_keyfield_set keysets[10]; 159 const struct vcap_field *keyfield; 160 enum vcap_type vt = admin->vtype; 161 struct vcap_client_keyfield *ckf; 162 struct vcap_keyset_list matches; 163 u32 *maskstream; 164 u32 *keystream; 165 int res; 166 167 keystream = admin->cache.keystream; 168 maskstream = admin->cache.maskstream; 169 matches.keysets = keysets; 170 matches.cnt = 0; 171 matches.max = ARRAY_SIZE(keysets); 172 res = vcap_find_keystream_keysets(vctrl, vt, keystream, maskstream, 173 false, 0, &matches); 174 if (res < 0) { 175 pr_err("%s:%d: could not find valid keysets: %d\n", 176 __func__, __LINE__, res); 177 return -EINVAL; 178 } 179 out->prf(out->dst, " keysets:"); 180 for (int idx = 0; idx < matches.cnt; ++idx) 181 out->prf(out->dst, " %s", 182 vcap_keyset_name(vctrl, matches.keysets[idx])); 183 out->prf(out->dst, "\n"); 184 out->prf(out->dst, " keyset_sw: %d\n", ri->keyset_sw); 185 out->prf(out->dst, " keyset_sw_regs: %d\n", ri->keyset_sw_regs); 186 187 list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) { 188 keyfield = vcap_keyfields(vctrl, admin->vtype, ri->data.keyset); 189 vcap_debugfs_show_rule_keyfield(vctrl, out, ckf->ctrl.key, 190 keyfield, &ckf->data); 191 } 192 193 return 0; 194 } 195 196 static int vcap_debugfs_show_rule_actionset(struct vcap_rule_internal *ri, 197 struct vcap_output_print *out) 198 { 199 struct vcap_control *vctrl = ri->vctrl; 200 struct vcap_admin *admin = ri->admin; 201 const struct vcap_field *actionfield; 202 struct vcap_client_actionfield *caf; 203 204 out->prf(out->dst, " actionset: %s\n", 205 vcap_actionset_name(vctrl, ri->data.actionset)); 206 out->prf(out->dst, " actionset_sw: %d\n", ri->actionset_sw); 207 out->prf(out->dst, " actionset_sw_regs: %d\n", ri->actionset_sw_regs); 208 209 list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) { 210 actionfield = vcap_actionfields(vctrl, admin->vtype, 211 ri->data.actionset); 212 vcap_debugfs_show_rule_actionfield(vctrl, out, caf->ctrl.action, 213 actionfield, 214 &caf->data.u1.value); 215 } 216 217 return 0; 218 } 219 220 static void vcap_show_admin_rule(struct vcap_control *vctrl, 221 struct vcap_admin *admin, 222 struct vcap_output_print *out, 223 struct vcap_rule_internal *ri) 224 { 225 ri->counter.value = admin->cache.counter; 226 ri->counter.sticky = admin->cache.sticky; 227 out->prf(out->dst, 228 "rule: %u, addr: [%d,%d], X%d, ctr[%d]: %d, hit: %d\n", 229 ri->data.id, ri->addr, ri->addr + ri->size - 1, ri->size, 230 ri->counter_id, ri->counter.value, ri->counter.sticky); 231 out->prf(out->dst, " chain_id: %d\n", ri->data.vcap_chain_id); 232 out->prf(out->dst, " user: %d\n", ri->data.user); 233 out->prf(out->dst, " priority: %d\n", ri->data.priority); 234 vcap_debugfs_show_rule_keyset(ri, out); 235 vcap_debugfs_show_rule_actionset(ri, out); 236 } 237 238 static void vcap_show_admin_info(struct vcap_control *vctrl, 239 struct vcap_admin *admin, 240 struct vcap_output_print *out) 241 { 242 const struct vcap_info *vcap = &vctrl->vcaps[admin->vtype]; 243 244 out->prf(out->dst, "name: %s\n", vcap->name); 245 out->prf(out->dst, "rows: %d\n", vcap->rows); 246 out->prf(out->dst, "sw_count: %d\n", vcap->sw_count); 247 out->prf(out->dst, "sw_width: %d\n", vcap->sw_width); 248 out->prf(out->dst, "sticky_width: %d\n", vcap->sticky_width); 249 out->prf(out->dst, "act_width: %d\n", vcap->act_width); 250 out->prf(out->dst, "default_cnt: %d\n", vcap->default_cnt); 251 out->prf(out->dst, "require_cnt_dis: %d\n", vcap->require_cnt_dis); 252 out->prf(out->dst, "version: %d\n", vcap->version); 253 out->prf(out->dst, "vtype: %d\n", admin->vtype); 254 out->prf(out->dst, "vinst: %d\n", admin->vinst); 255 out->prf(out->dst, "first_cid: %d\n", admin->first_cid); 256 out->prf(out->dst, "last_cid: %d\n", admin->last_cid); 257 out->prf(out->dst, "lookups: %d\n", admin->lookups); 258 out->prf(out->dst, "first_valid_addr: %d\n", admin->first_valid_addr); 259 out->prf(out->dst, "last_valid_addr: %d\n", admin->last_valid_addr); 260 out->prf(out->dst, "last_used_addr: %d\n", admin->last_used_addr); 261 } 262 263 static int vcap_show_admin(struct vcap_control *vctrl, 264 struct vcap_admin *admin, 265 struct vcap_output_print *out) 266 { 267 struct vcap_rule_internal *elem; 268 struct vcap_rule *vrule; 269 int ret = 0; 270 271 vcap_show_admin_info(vctrl, admin, out); 272 list_for_each_entry(elem, &admin->rules, list) { 273 vrule = vcap_get_rule(vctrl, elem->data.id); 274 if (IS_ERR_OR_NULL(vrule)) { 275 ret = PTR_ERR(vrule); 276 break; 277 } 278 279 out->prf(out->dst, "\n"); 280 vcap_show_admin_rule(vctrl, admin, out, to_intrule(vrule)); 281 vcap_free_rule(vrule); 282 } 283 return ret; 284 } 285 286 static int vcap_show_admin_raw(struct vcap_control *vctrl, 287 struct vcap_admin *admin, 288 struct vcap_output_print *out) 289 { 290 enum vcap_keyfield_set keysets[10]; 291 enum vcap_type vt = admin->vtype; 292 struct vcap_keyset_list kslist; 293 struct vcap_rule_internal *ri; 294 const struct vcap_set *info; 295 int addr, idx; 296 int ret; 297 298 if (list_empty(&admin->rules)) 299 return 0; 300 301 ret = vcap_api_check(vctrl); 302 if (ret) 303 return ret; 304 305 ri = list_first_entry(&admin->rules, struct vcap_rule_internal, list); 306 307 /* Go from higher to lower addresses searching for a keyset */ 308 kslist.keysets = keysets; 309 kslist.max = ARRAY_SIZE(keysets); 310 for (addr = admin->last_valid_addr; addr >= admin->first_valid_addr; 311 --addr) { 312 kslist.cnt = 0; 313 ret = vcap_addr_keysets(vctrl, ri->ndev, admin, addr, &kslist); 314 if (ret < 0) 315 continue; 316 info = vcap_keyfieldset(vctrl, vt, kslist.keysets[0]); 317 if (!info) 318 continue; 319 if (addr % info->sw_per_item) { 320 pr_info("addr: %d X%d error rule, keyset: %s\n", 321 addr, 322 info->sw_per_item, 323 vcap_keyset_name(vctrl, kslist.keysets[0])); 324 } else { 325 out->prf(out->dst, " addr: %d, X%d rule, keysets:", 326 addr, 327 info->sw_per_item); 328 for (idx = 0; idx < kslist.cnt; ++idx) 329 out->prf(out->dst, " %s", 330 vcap_keyset_name(vctrl, 331 kslist.keysets[idx])); 332 out->prf(out->dst, "\n"); 333 } 334 } 335 return 0; 336 } 337 338 /* Show the port configuration and status */ 339 static int vcap_port_debugfs_show(struct seq_file *m, void *unused) 340 { 341 struct vcap_port_debugfs_info *info = m->private; 342 struct vcap_admin *admin; 343 struct vcap_output_print out = { 344 .prf = (void *)seq_printf, 345 .dst = m, 346 }; 347 348 list_for_each_entry(admin, &info->vctrl->list, list) { 349 if (admin->vinst) 350 continue; 351 info->vctrl->ops->port_info(info->ndev, admin, &out); 352 } 353 return 0; 354 } 355 DEFINE_SHOW_ATTRIBUTE(vcap_port_debugfs); 356 357 void vcap_port_debugfs(struct device *dev, struct dentry *parent, 358 struct vcap_control *vctrl, 359 struct net_device *ndev) 360 { 361 struct vcap_port_debugfs_info *info; 362 363 info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); 364 if (!info) 365 return; 366 367 info->vctrl = vctrl; 368 info->ndev = ndev; 369 debugfs_create_file(netdev_name(ndev), 0444, parent, info, 370 &vcap_port_debugfs_fops); 371 } 372 EXPORT_SYMBOL_GPL(vcap_port_debugfs); 373 374 /* Show the full VCAP instance data (rules with all fields) */ 375 static int vcap_debugfs_show(struct seq_file *m, void *unused) 376 { 377 struct vcap_admin_debugfs_info *info = m->private; 378 struct vcap_output_print out = { 379 .prf = (void *)seq_printf, 380 .dst = m, 381 }; 382 383 return vcap_show_admin(info->vctrl, info->admin, &out); 384 } 385 DEFINE_SHOW_ATTRIBUTE(vcap_debugfs); 386 387 /* Show the raw VCAP instance data (rules with address info) */ 388 static int vcap_raw_debugfs_show(struct seq_file *m, void *unused) 389 { 390 struct vcap_admin_debugfs_info *info = m->private; 391 struct vcap_output_print out = { 392 .prf = (void *)seq_printf, 393 .dst = m, 394 }; 395 396 return vcap_show_admin_raw(info->vctrl, info->admin, &out); 397 } 398 DEFINE_SHOW_ATTRIBUTE(vcap_raw_debugfs); 399 400 struct dentry *vcap_debugfs(struct device *dev, struct dentry *parent, 401 struct vcap_control *vctrl) 402 { 403 struct vcap_admin_debugfs_info *info; 404 struct vcap_admin *admin; 405 struct dentry *dir; 406 char name[50]; 407 408 dir = debugfs_create_dir("vcaps", parent); 409 if (PTR_ERR_OR_ZERO(dir)) 410 return NULL; 411 list_for_each_entry(admin, &vctrl->list, list) { 412 sprintf(name, "raw_%s_%d", vctrl->vcaps[admin->vtype].name, 413 admin->vinst); 414 info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); 415 if (!info) 416 return NULL; 417 info->vctrl = vctrl; 418 info->admin = admin; 419 debugfs_create_file(name, 0444, dir, info, 420 &vcap_raw_debugfs_fops); 421 sprintf(name, "%s_%d", vctrl->vcaps[admin->vtype].name, 422 admin->vinst); 423 debugfs_create_file(name, 0444, dir, info, &vcap_debugfs_fops); 424 } 425 return dir; 426 } 427 EXPORT_SYMBOL_GPL(vcap_debugfs); 428 429 #ifdef CONFIG_VCAP_KUNIT_TEST 430 #include "vcap_api_debugfs_kunit.c" 431 #endif 432