1// SPDX-License-Identifier: GPL-2.0 2/* 3 * configfs to configure the PCI endpoint 4 * 5 * Copyright (C) 2017 Texas Instruments 6 * Author: Kishon Vijay Abraham I <kishon@ti.com> 7 */ 8 9#include <linux/module.h> 10#include <linux/idr.h> 11#include <linux/slab.h> 12 13#include <linux/pci-epc.h> 14#include <linux/pci-epf.h> 15#include <linux/pci-ep-cfs.h> 16 17static DEFINE_IDR(functions_idr); 18static DEFINE_MUTEX(functions_mutex); 19static struct config_group *functions_group; 20static struct config_group *controllers_group; 21 22struct pci_epf_group { 23 struct config_group group; 24 struct pci_epf *epf; 25 int index; 26}; 27 28struct pci_epc_group { 29 struct config_group group; 30 struct pci_epc *epc; 31 bool start; 32}; 33 34static inline struct pci_epf_group *to_pci_epf_group(struct config_item *item) 35{ 36 return container_of(to_config_group(item), struct pci_epf_group, group); 37} 38 39static inline struct pci_epc_group *to_pci_epc_group(struct config_item *item) 40{ 41 return container_of(to_config_group(item), struct pci_epc_group, group); 42} 43 44static ssize_t pci_epc_start_store(struct config_item *item, const char *page, 45 size_t len) 46{ 47 int ret; 48 bool start; 49 struct pci_epc *epc; 50 struct pci_epc_group *epc_group = to_pci_epc_group(item); 51 52 epc = epc_group->epc; 53 54 ret = kstrtobool(page, &start); 55 if (ret) 56 return ret; 57 58 if (!start) { 59 pci_epc_stop(epc); 60 epc_group->start = 0; 61 return len; 62 } 63 64 ret = pci_epc_start(epc); 65 if (ret) { 66 dev_err(&epc->dev, "failed to start endpoint controller\n"); 67 return -EINVAL; 68 } 69 70 epc_group->start = start; 71 72 return len; 73} 74 75static ssize_t pci_epc_start_show(struct config_item *item, char *page) 76{ 77 return sprintf(page, "%d\n", 78 to_pci_epc_group(item)->start); 79} 80 81CONFIGFS_ATTR(pci_epc_, start); 82 83static struct configfs_attribute *pci_epc_attrs[] = { 84 &pci_epc_attr_start, 85 NULL, 86}; 87 88static int pci_epc_epf_link(struct config_item *epc_item, 89 struct config_item *epf_item) 90{ 91 int ret; 92 struct pci_epf_group *epf_group = to_pci_epf_group(epf_item); 93 struct pci_epc_group *epc_group = to_pci_epc_group(epc_item); 94 struct pci_epc *epc = epc_group->epc; 95 struct pci_epf *epf = epf_group->epf; 96 97 ret = pci_epc_add_epf(epc, epf); 98 if (ret) 99 return ret; 100 101 ret = pci_epf_bind(epf); 102 if (ret) { 103 pci_epc_remove_epf(epc, epf); 104 return ret; 105 } 106 107 return 0; 108} 109 110static void pci_epc_epf_unlink(struct config_item *epc_item, 111 struct config_item *epf_item) 112{ 113 struct pci_epc *epc; 114 struct pci_epf *epf; 115 struct pci_epf_group *epf_group = to_pci_epf_group(epf_item); 116 struct pci_epc_group *epc_group = to_pci_epc_group(epc_item); 117 118 WARN_ON_ONCE(epc_group->start); 119 120 epc = epc_group->epc; 121 epf = epf_group->epf; 122 pci_epf_unbind(epf); 123 pci_epc_remove_epf(epc, epf); 124} 125 126static struct configfs_item_operations pci_epc_item_ops = { 127 .allow_link = pci_epc_epf_link, 128 .drop_link = pci_epc_epf_unlink, 129}; 130 131static const struct config_item_type pci_epc_type = { 132 .ct_item_ops = &pci_epc_item_ops, 133 .ct_attrs = pci_epc_attrs, 134 .ct_owner = THIS_MODULE, 135}; 136 137struct config_group *pci_ep_cfs_add_epc_group(const char *name) 138{ 139 int ret; 140 struct pci_epc *epc; 141 struct config_group *group; 142 struct pci_epc_group *epc_group; 143 144 epc_group = kzalloc(sizeof(*epc_group), GFP_KERNEL); 145 if (!epc_group) { 146 ret = -ENOMEM; 147 goto err; 148 } 149 150 group = &epc_group->group; 151 152 config_group_init_type_name(group, name, &pci_epc_type); 153 ret = configfs_register_group(controllers_group, group); 154 if (ret) { 155 pr_err("failed to register configfs group for %s\n", name); 156 goto err_register_group; 157 } 158 159 epc = pci_epc_get(name); 160 if (IS_ERR(epc)) { 161 ret = PTR_ERR(epc); 162 goto err_epc_get; 163 } 164 165 epc_group->epc = epc; 166 167 return group; 168 169err_epc_get: 170 configfs_unregister_group(group); 171 172err_register_group: 173 kfree(epc_group); 174 175err: 176 return ERR_PTR(ret); 177} 178EXPORT_SYMBOL(pci_ep_cfs_add_epc_group); 179 180void pci_ep_cfs_remove_epc_group(struct config_group *group) 181{ 182 struct pci_epc_group *epc_group; 183 184 if (!group) 185 return; 186 187 epc_group = container_of(group, struct pci_epc_group, group); 188 pci_epc_put(epc_group->epc); 189 configfs_unregister_group(&epc_group->group); 190 kfree(epc_group); 191} 192EXPORT_SYMBOL(pci_ep_cfs_remove_epc_group); 193 194#define PCI_EPF_HEADER_R(_name) \ 195static ssize_t pci_epf_##_name##_show(struct config_item *item, char *page) \ 196{ \ 197 struct pci_epf *epf = to_pci_epf_group(item)->epf; \ 198 if (WARN_ON_ONCE(!epf->header)) \ 199 return -EINVAL; \ 200 return sprintf(page, "0x%04x\n", epf->header->_name); \ 201} 202 203#define PCI_EPF_HEADER_W_u32(_name) \ 204static ssize_t pci_epf_##_name##_store(struct config_item *item, \ 205 const char *page, size_t len) \ 206{ \ 207 u32 val; \ 208 int ret; \ 209 struct pci_epf *epf = to_pci_epf_group(item)->epf; \ 210 if (WARN_ON_ONCE(!epf->header)) \ 211 return -EINVAL; \ 212 ret = kstrtou32(page, 0, &val); \ 213 if (ret) \ 214 return ret; \ 215 epf->header->_name = val; \ 216 return len; \ 217} 218 219#define PCI_EPF_HEADER_W_u16(_name) \ 220static ssize_t pci_epf_##_name##_store(struct config_item *item, \ 221 const char *page, size_t len) \ 222{ \ 223 u16 val; \ 224 int ret; \ 225 struct pci_epf *epf = to_pci_epf_group(item)->epf; \ 226 if (WARN_ON_ONCE(!epf->header)) \ 227 return -EINVAL; \ 228 ret = kstrtou16(page, 0, &val); \ 229 if (ret) \ 230 return ret; \ 231 epf->header->_name = val; \ 232 return len; \ 233} 234 235#define PCI_EPF_HEADER_W_u8(_name) \ 236static ssize_t pci_epf_##_name##_store(struct config_item *item, \ 237 const char *page, size_t len) \ 238{ \ 239 u8 val; \ 240 int ret; \ 241 struct pci_epf *epf = to_pci_epf_group(item)->epf; \ 242 if (WARN_ON_ONCE(!epf->header)) \ 243 return -EINVAL; \ 244 ret = kstrtou8(page, 0, &val); \ 245 if (ret) \ 246 return ret; \ 247 epf->header->_name = val; \ 248 return len; \ 249} 250 251static ssize_t pci_epf_msi_interrupts_store(struct config_item *item, 252 const char *page, size_t len) 253{ 254 u8 val; 255 int ret; 256 257 ret = kstrtou8(page, 0, &val); 258 if (ret) 259 return ret; 260 261 to_pci_epf_group(item)->epf->msi_interrupts = val; 262 263 return len; 264} 265 266static ssize_t pci_epf_msi_interrupts_show(struct config_item *item, 267 char *page) 268{ 269 return sprintf(page, "%d\n", 270 to_pci_epf_group(item)->epf->msi_interrupts); 271} 272 273static ssize_t pci_epf_msix_interrupts_store(struct config_item *item, 274 const char *page, size_t len) 275{ 276 u16 val; 277 int ret; 278 279 ret = kstrtou16(page, 0, &val); 280 if (ret) 281 return ret; 282 283 to_pci_epf_group(item)->epf->msix_interrupts = val; 284 285 return len; 286} 287 288static ssize_t pci_epf_msix_interrupts_show(struct config_item *item, 289 char *page) 290{ 291 return sprintf(page, "%d\n", 292 to_pci_epf_group(item)->epf->msix_interrupts); 293} 294 295PCI_EPF_HEADER_R(vendorid) 296PCI_EPF_HEADER_W_u16(vendorid) 297 298PCI_EPF_HEADER_R(deviceid) 299PCI_EPF_HEADER_W_u16(deviceid) 300 301PCI_EPF_HEADER_R(revid) 302PCI_EPF_HEADER_W_u8(revid) 303 304PCI_EPF_HEADER_R(progif_code) 305PCI_EPF_HEADER_W_u8(progif_code) 306 307PCI_EPF_HEADER_R(subclass_code) 308PCI_EPF_HEADER_W_u8(subclass_code) 309 310PCI_EPF_HEADER_R(baseclass_code) 311PCI_EPF_HEADER_W_u8(baseclass_code) 312 313PCI_EPF_HEADER_R(cache_line_size) 314PCI_EPF_HEADER_W_u8(cache_line_size) 315 316PCI_EPF_HEADER_R(subsys_vendor_id) 317PCI_EPF_HEADER_W_u16(subsys_vendor_id) 318 319PCI_EPF_HEADER_R(subsys_id) 320PCI_EPF_HEADER_W_u16(subsys_id) 321 322PCI_EPF_HEADER_R(interrupt_pin) 323PCI_EPF_HEADER_W_u8(interrupt_pin) 324 325CONFIGFS_ATTR(pci_epf_, vendorid); 326CONFIGFS_ATTR(pci_epf_, deviceid); 327CONFIGFS_ATTR(pci_epf_, revid); 328CONFIGFS_ATTR(pci_epf_, progif_code); 329CONFIGFS_ATTR(pci_epf_, subclass_code); 330CONFIGFS_ATTR(pci_epf_, baseclass_code); 331CONFIGFS_ATTR(pci_epf_, cache_line_size); 332CONFIGFS_ATTR(pci_epf_, subsys_vendor_id); 333CONFIGFS_ATTR(pci_epf_, subsys_id); 334CONFIGFS_ATTR(pci_epf_, interrupt_pin); 335CONFIGFS_ATTR(pci_epf_, msi_interrupts); 336CONFIGFS_ATTR(pci_epf_, msix_interrupts); 337 338static struct configfs_attribute *pci_epf_attrs[] = { 339 &pci_epf_attr_vendorid, 340 &pci_epf_attr_deviceid, 341 &pci_epf_attr_revid, 342 &pci_epf_attr_progif_code, 343 &pci_epf_attr_subclass_code, 344 &pci_epf_attr_baseclass_code, 345 &pci_epf_attr_cache_line_size, 346 &pci_epf_attr_subsys_vendor_id, 347 &pci_epf_attr_subsys_id, 348 &pci_epf_attr_interrupt_pin, 349 &pci_epf_attr_msi_interrupts, 350 &pci_epf_attr_msix_interrupts, 351 NULL, 352}; 353 354static void pci_epf_release(struct config_item *item) 355{ 356 struct pci_epf_group *epf_group = to_pci_epf_group(item); 357 358 mutex_lock(&functions_mutex); 359 idr_remove(&functions_idr, epf_group->index); 360 mutex_unlock(&functions_mutex); 361 pci_epf_destroy(epf_group->epf); 362 kfree(epf_group); 363} 364 365static struct configfs_item_operations pci_epf_ops = { 366 .release = pci_epf_release, 367}; 368 369static const struct config_item_type pci_epf_type = { 370 .ct_item_ops = &pci_epf_ops, 371 .ct_attrs = pci_epf_attrs, 372 .ct_owner = THIS_MODULE, 373}; 374 375static struct config_group *pci_epf_make(struct config_group *group, 376 const char *name) 377{ 378 struct pci_epf_group *epf_group; 379 struct pci_epf *epf; 380 char *epf_name; 381 int index, err; 382 383 epf_group = kzalloc(sizeof(*epf_group), GFP_KERNEL); 384 if (!epf_group) 385 return ERR_PTR(-ENOMEM); 386 387 mutex_lock(&functions_mutex); 388 index = idr_alloc(&functions_idr, epf_group, 0, 0, GFP_KERNEL); 389 mutex_unlock(&functions_mutex); 390 if (index < 0) { 391 err = index; 392 goto free_group; 393 } 394 395 epf_group->index = index; 396 397 config_group_init_type_name(&epf_group->group, name, &pci_epf_type); 398 399 epf_name = kasprintf(GFP_KERNEL, "%s.%d", 400 group->cg_item.ci_name, epf_group->index); 401 if (!epf_name) { 402 err = -ENOMEM; 403 goto remove_idr; 404 } 405 406 epf = pci_epf_create(epf_name); 407 if (IS_ERR(epf)) { 408 pr_err("failed to create endpoint function device\n"); 409 err = -EINVAL; 410 goto free_name; 411 } 412 413 epf_group->epf = epf; 414 415 kfree(epf_name); 416 417 return &epf_group->group; 418 419free_name: 420 kfree(epf_name); 421 422remove_idr: 423 mutex_lock(&functions_mutex); 424 idr_remove(&functions_idr, epf_group->index); 425 mutex_unlock(&functions_mutex); 426 427free_group: 428 kfree(epf_group); 429 430 return ERR_PTR(err); 431} 432 433static void pci_epf_drop(struct config_group *group, struct config_item *item) 434{ 435 config_item_put(item); 436} 437 438static struct configfs_group_operations pci_epf_group_ops = { 439 .make_group = &pci_epf_make, 440 .drop_item = &pci_epf_drop, 441}; 442 443static const struct config_item_type pci_epf_group_type = { 444 .ct_group_ops = &pci_epf_group_ops, 445 .ct_owner = THIS_MODULE, 446}; 447 448struct config_group *pci_ep_cfs_add_epf_group(const char *name) 449{ 450 struct config_group *group; 451 452 group = configfs_register_default_group(functions_group, name, 453 &pci_epf_group_type); 454 if (IS_ERR(group)) 455 pr_err("failed to register configfs group for %s function\n", 456 name); 457 458 return group; 459} 460EXPORT_SYMBOL(pci_ep_cfs_add_epf_group); 461 462void pci_ep_cfs_remove_epf_group(struct config_group *group) 463{ 464 if (IS_ERR_OR_NULL(group)) 465 return; 466 467 configfs_unregister_default_group(group); 468} 469EXPORT_SYMBOL(pci_ep_cfs_remove_epf_group); 470 471static const struct config_item_type pci_functions_type = { 472 .ct_owner = THIS_MODULE, 473}; 474 475static const struct config_item_type pci_controllers_type = { 476 .ct_owner = THIS_MODULE, 477}; 478 479static const struct config_item_type pci_ep_type = { 480 .ct_owner = THIS_MODULE, 481}; 482 483static struct configfs_subsystem pci_ep_cfs_subsys = { 484 .su_group = { 485 .cg_item = { 486 .ci_namebuf = "pci_ep", 487 .ci_type = &pci_ep_type, 488 }, 489 }, 490 .su_mutex = __MUTEX_INITIALIZER(pci_ep_cfs_subsys.su_mutex), 491}; 492 493static int __init pci_ep_cfs_init(void) 494{ 495 int ret; 496 struct config_group *root = &pci_ep_cfs_subsys.su_group; 497 498 config_group_init(root); 499 500 ret = configfs_register_subsystem(&pci_ep_cfs_subsys); 501 if (ret) { 502 pr_err("Error %d while registering subsystem %s\n", 503 ret, root->cg_item.ci_namebuf); 504 goto err; 505 } 506 507 functions_group = configfs_register_default_group(root, "functions", 508 &pci_functions_type); 509 if (IS_ERR(functions_group)) { 510 ret = PTR_ERR(functions_group); 511 pr_err("Error %d while registering functions group\n", 512 ret); 513 goto err_functions_group; 514 } 515 516 controllers_group = 517 configfs_register_default_group(root, "controllers", 518 &pci_controllers_type); 519 if (IS_ERR(controllers_group)) { 520 ret = PTR_ERR(controllers_group); 521 pr_err("Error %d while registering controllers group\n", 522 ret); 523 goto err_controllers_group; 524 } 525 526 return 0; 527 528err_controllers_group: 529 configfs_unregister_default_group(functions_group); 530 531err_functions_group: 532 configfs_unregister_subsystem(&pci_ep_cfs_subsys); 533 534err: 535 return ret; 536} 537module_init(pci_ep_cfs_init); 538 539static void __exit pci_ep_cfs_exit(void) 540{ 541 configfs_unregister_default_group(controllers_group); 542 configfs_unregister_default_group(functions_group); 543 configfs_unregister_subsystem(&pci_ep_cfs_subsys); 544} 545module_exit(pci_ep_cfs_exit); 546 547MODULE_DESCRIPTION("PCI EP CONFIGFS"); 548MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>"); 549MODULE_LICENSE("GPL v2"); 550