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