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