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_rule_keyset(struct vcap_rule_internal *ri, 156 struct vcap_output_print *out) 157 { 158 struct vcap_control *vctrl = ri->vctrl; 159 struct vcap_admin *admin = ri->admin; 160 enum vcap_keyfield_set keysets[10]; 161 const struct vcap_field *keyfield; 162 enum vcap_type vt = admin->vtype; 163 struct vcap_client_keyfield *ckf; 164 struct vcap_keyset_list matches; 165 u32 *maskstream; 166 u32 *keystream; 167 int res; 168 169 keystream = admin->cache.keystream; 170 maskstream = admin->cache.maskstream; 171 matches.keysets = keysets; 172 matches.cnt = 0; 173 matches.max = ARRAY_SIZE(keysets); 174 res = vcap_find_keystream_keysets(vctrl, vt, keystream, maskstream, 175 false, 0, &matches); 176 if (res < 0) { 177 pr_err("%s:%d: could not find valid keysets: %d\n", 178 __func__, __LINE__, res); 179 return -EINVAL; 180 } 181 out->prf(out->dst, " keysets:"); 182 for (int idx = 0; idx < matches.cnt; ++idx) 183 out->prf(out->dst, " %s", 184 vcap_keyset_name(vctrl, matches.keysets[idx])); 185 out->prf(out->dst, "\n"); 186 out->prf(out->dst, " keyset_sw: %d\n", ri->keyset_sw); 187 out->prf(out->dst, " keyset_sw_regs: %d\n", ri->keyset_sw_regs); 188 189 list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) { 190 keyfield = vcap_keyfields(vctrl, admin->vtype, ri->data.keyset); 191 vcap_debugfs_show_rule_keyfield(vctrl, out, ckf->ctrl.key, 192 keyfield, &ckf->data); 193 } 194 195 return 0; 196 } 197 198 static int vcap_debugfs_show_rule_actionset(struct vcap_rule_internal *ri, 199 struct vcap_output_print *out) 200 { 201 struct vcap_control *vctrl = ri->vctrl; 202 struct vcap_admin *admin = ri->admin; 203 const struct vcap_field *actionfield; 204 struct vcap_client_actionfield *caf; 205 206 out->prf(out->dst, " actionset: %s\n", 207 vcap_actionset_name(vctrl, ri->data.actionset)); 208 out->prf(out->dst, " actionset_sw: %d\n", ri->actionset_sw); 209 out->prf(out->dst, " actionset_sw_regs: %d\n", ri->actionset_sw_regs); 210 211 list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) { 212 actionfield = vcap_actionfields(vctrl, admin->vtype, 213 ri->data.actionset); 214 vcap_debugfs_show_rule_actionfield(vctrl, out, caf->ctrl.action, 215 actionfield, 216 &caf->data.u1.value); 217 } 218 219 return 0; 220 } 221 222 static void vcap_show_admin_rule(struct vcap_control *vctrl, 223 struct vcap_admin *admin, 224 struct vcap_output_print *out, 225 struct vcap_rule_internal *ri) 226 { 227 ri->counter.value = admin->cache.counter; 228 ri->counter.sticky = admin->cache.sticky; 229 out->prf(out->dst, 230 "rule: %u, addr: [%d,%d], X%d, ctr[%d]: %d, hit: %d\n", 231 ri->data.id, ri->addr, ri->addr + ri->size - 1, ri->size, 232 ri->counter_id, ri->counter.value, ri->counter.sticky); 233 out->prf(out->dst, " chain_id: %d\n", ri->data.vcap_chain_id); 234 out->prf(out->dst, " user: %d\n", ri->data.user); 235 out->prf(out->dst, " priority: %d\n", ri->data.priority); 236 vcap_debugfs_show_rule_keyset(ri, out); 237 vcap_debugfs_show_rule_actionset(ri, out); 238 } 239 240 static void vcap_show_admin_info(struct vcap_control *vctrl, 241 struct vcap_admin *admin, 242 struct vcap_output_print *out) 243 { 244 const struct vcap_info *vcap = &vctrl->vcaps[admin->vtype]; 245 246 out->prf(out->dst, "name: %s\n", vcap->name); 247 out->prf(out->dst, "rows: %d\n", vcap->rows); 248 out->prf(out->dst, "sw_count: %d\n", vcap->sw_count); 249 out->prf(out->dst, "sw_width: %d\n", vcap->sw_width); 250 out->prf(out->dst, "sticky_width: %d\n", vcap->sticky_width); 251 out->prf(out->dst, "act_width: %d\n", vcap->act_width); 252 out->prf(out->dst, "default_cnt: %d\n", vcap->default_cnt); 253 out->prf(out->dst, "require_cnt_dis: %d\n", vcap->require_cnt_dis); 254 out->prf(out->dst, "version: %d\n", vcap->version); 255 out->prf(out->dst, "vtype: %d\n", admin->vtype); 256 out->prf(out->dst, "vinst: %d\n", admin->vinst); 257 out->prf(out->dst, "first_cid: %d\n", admin->first_cid); 258 out->prf(out->dst, "last_cid: %d\n", admin->last_cid); 259 out->prf(out->dst, "lookups: %d\n", admin->lookups); 260 out->prf(out->dst, "first_valid_addr: %d\n", admin->first_valid_addr); 261 out->prf(out->dst, "last_valid_addr: %d\n", admin->last_valid_addr); 262 out->prf(out->dst, "last_used_addr: %d\n", admin->last_used_addr); 263 } 264 265 static int vcap_show_admin(struct vcap_control *vctrl, 266 struct vcap_admin *admin, 267 struct vcap_output_print *out) 268 { 269 struct vcap_rule_internal *elem; 270 struct vcap_rule *vrule; 271 int ret = 0; 272 273 vcap_show_admin_info(vctrl, admin, out); 274 list_for_each_entry(elem, &admin->rules, list) { 275 vrule = vcap_get_rule(vctrl, elem->data.id); 276 if (IS_ERR_OR_NULL(vrule)) { 277 ret = PTR_ERR(vrule); 278 break; 279 } 280 281 out->prf(out->dst, "\n"); 282 vcap_show_admin_rule(vctrl, admin, out, to_intrule(vrule)); 283 vcap_free_rule(vrule); 284 } 285 return ret; 286 } 287 288 static int vcap_show_admin_raw(struct vcap_control *vctrl, 289 struct vcap_admin *admin, 290 struct vcap_output_print *out) 291 { 292 enum vcap_keyfield_set keysets[10]; 293 enum vcap_type vt = admin->vtype; 294 struct vcap_keyset_list kslist; 295 struct vcap_rule_internal *ri; 296 const struct vcap_set *info; 297 int addr, idx; 298 int ret; 299 300 if (list_empty(&admin->rules)) 301 return 0; 302 303 ret = vcap_api_check(vctrl); 304 if (ret) 305 return ret; 306 307 ri = list_first_entry(&admin->rules, struct vcap_rule_internal, list); 308 309 /* Go from higher to lower addresses searching for a keyset */ 310 kslist.keysets = keysets; 311 kslist.max = ARRAY_SIZE(keysets); 312 for (addr = admin->last_valid_addr; addr >= admin->first_valid_addr; 313 --addr) { 314 kslist.cnt = 0; 315 ret = vcap_addr_keysets(vctrl, ri->ndev, admin, addr, &kslist); 316 if (ret < 0) 317 continue; 318 info = vcap_keyfieldset(vctrl, vt, kslist.keysets[0]); 319 if (!info) 320 continue; 321 if (addr % info->sw_per_item) { 322 pr_info("addr: %d X%d error rule, keyset: %s\n", 323 addr, 324 info->sw_per_item, 325 vcap_keyset_name(vctrl, kslist.keysets[0])); 326 } else { 327 out->prf(out->dst, " addr: %d, X%d rule, keysets:", 328 addr, 329 info->sw_per_item); 330 for (idx = 0; idx < kslist.cnt; ++idx) 331 out->prf(out->dst, " %s", 332 vcap_keyset_name(vctrl, 333 kslist.keysets[idx])); 334 out->prf(out->dst, "\n"); 335 } 336 } 337 return 0; 338 } 339 340 /* Show the port configuration and status */ 341 static int vcap_port_debugfs_show(struct seq_file *m, void *unused) 342 { 343 struct vcap_port_debugfs_info *info = m->private; 344 struct vcap_admin *admin; 345 struct vcap_output_print out = { 346 .prf = (void *)seq_printf, 347 .dst = m, 348 }; 349 350 list_for_each_entry(admin, &info->vctrl->list, list) { 351 if (admin->vinst) 352 continue; 353 info->vctrl->ops->port_info(info->ndev, admin, &out); 354 } 355 return 0; 356 } 357 DEFINE_SHOW_ATTRIBUTE(vcap_port_debugfs); 358 359 void vcap_port_debugfs(struct device *dev, struct dentry *parent, 360 struct vcap_control *vctrl, 361 struct net_device *ndev) 362 { 363 struct vcap_port_debugfs_info *info; 364 365 info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); 366 if (!info) 367 return; 368 369 info->vctrl = vctrl; 370 info->ndev = ndev; 371 debugfs_create_file(netdev_name(ndev), 0444, parent, info, 372 &vcap_port_debugfs_fops); 373 } 374 EXPORT_SYMBOL_GPL(vcap_port_debugfs); 375 376 /* Show the full VCAP instance data (rules with all fields) */ 377 static int vcap_debugfs_show(struct seq_file *m, void *unused) 378 { 379 struct vcap_admin_debugfs_info *info = m->private; 380 struct vcap_output_print out = { 381 .prf = (void *)seq_printf, 382 .dst = m, 383 }; 384 385 return vcap_show_admin(info->vctrl, info->admin, &out); 386 } 387 DEFINE_SHOW_ATTRIBUTE(vcap_debugfs); 388 389 /* Show the raw VCAP instance data (rules with address info) */ 390 static int vcap_raw_debugfs_show(struct seq_file *m, void *unused) 391 { 392 struct vcap_admin_debugfs_info *info = m->private; 393 struct vcap_output_print out = { 394 .prf = (void *)seq_printf, 395 .dst = m, 396 }; 397 398 return vcap_show_admin_raw(info->vctrl, info->admin, &out); 399 } 400 DEFINE_SHOW_ATTRIBUTE(vcap_raw_debugfs); 401 402 struct dentry *vcap_debugfs(struct device *dev, struct dentry *parent, 403 struct vcap_control *vctrl) 404 { 405 struct vcap_admin_debugfs_info *info; 406 struct vcap_admin *admin; 407 struct dentry *dir; 408 char name[50]; 409 410 dir = debugfs_create_dir("vcaps", parent); 411 if (PTR_ERR_OR_ZERO(dir)) 412 return NULL; 413 list_for_each_entry(admin, &vctrl->list, list) { 414 sprintf(name, "raw_%s_%d", vctrl->vcaps[admin->vtype].name, 415 admin->vinst); 416 info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); 417 if (!info) 418 return NULL; 419 info->vctrl = vctrl; 420 info->admin = admin; 421 debugfs_create_file(name, 0444, dir, info, 422 &vcap_raw_debugfs_fops); 423 sprintf(name, "%s_%d", vctrl->vcaps[admin->vtype].name, 424 admin->vinst); 425 debugfs_create_file(name, 0444, dir, info, &vcap_debugfs_fops); 426 } 427 return dir; 428 } 429 EXPORT_SYMBOL_GPL(vcap_debugfs); 430 431 #ifdef CONFIG_VCAP_KUNIT_TEST 432 #include "vcap_api_debugfs_kunit.c" 433 #endif 434