Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

genirq/msi: Use lock guards for MSI descriptor locking

Provide a lock guard for MSI descriptor locking and update the core code
accordingly.

No functional change intended.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Link: https://lore.kernel.org/all/20250319105506.144672678@linutronix.de



+45 -69
+2
include/linux/irqdomain.h
··· 281 281 282 282 void irq_domain_free_fwnode(struct fwnode_handle *fwnode); 283 283 284 + DEFINE_FREE(irq_domain_free_fwnode, struct fwnode_handle *, if (_T) irq_domain_free_fwnode(_T)) 285 + 284 286 struct irq_domain_chip_generic_info; 285 287 286 288 /**
+3
include/linux/msi.h
··· 232 232 void msi_lock_descs(struct device *dev); 233 233 void msi_unlock_descs(struct device *dev); 234 234 235 + DEFINE_LOCK_GUARD_1(msi_descs_lock, struct device, msi_lock_descs(_T->lock), 236 + msi_unlock_descs(_T->lock)); 237 + 235 238 struct msi_desc *msi_domain_first_desc(struct device *dev, unsigned int domid, 236 239 enum msi_desc_filter filter); 237 240
+40 -69
kernel/irq/msi.c
··· 448 448 unsigned int msi_domain_get_virq(struct device *dev, unsigned int domid, unsigned int index) 449 449 { 450 450 struct msi_desc *desc; 451 - unsigned int ret = 0; 452 451 bool pcimsi = false; 453 452 struct xarray *xa; 454 453 ··· 461 462 if (dev_is_pci(dev) && domid == MSI_DEFAULT_DOMAIN) 462 463 pcimsi = to_pci_dev(dev)->msi_enabled; 463 464 464 - msi_lock_descs(dev); 465 + guard(msi_descs_lock)(dev); 465 466 xa = &dev->msi.data->__domains[domid].store; 466 467 desc = xa_load(xa, pcimsi ? 0 : index); 467 468 if (desc && desc->irq) { ··· 470 471 * PCI-MSIX and platform MSI use a descriptor per 471 472 * interrupt. 472 473 */ 473 - if (pcimsi) { 474 - if (index < desc->nvec_used) 475 - ret = desc->irq + index; 476 - } else { 477 - ret = desc->irq; 478 - } 474 + if (!pcimsi) 475 + return desc->irq; 476 + if (index < desc->nvec_used) 477 + return desc->irq + index; 479 478 } 480 - 481 - msi_unlock_descs(dev); 482 - return ret; 479 + return 0; 483 480 } 484 481 EXPORT_SYMBOL_GPL(msi_domain_get_virq); 485 482 ··· 993 998 void *chip_data) 994 999 { 995 1000 struct irq_domain *domain, *parent = dev->msi.domain; 996 - struct fwnode_handle *fwnode, *fwnalloced = NULL; 997 - struct msi_domain_template *bundle; 998 1001 const struct msi_parent_ops *pops; 1002 + struct fwnode_handle *fwnode; 999 1003 1000 1004 if (!irq_domain_is_msi_parent(parent)) 1001 1005 return false; ··· 1002 1008 if (domid >= MSI_MAX_DEVICE_IRQDOMAINS) 1003 1009 return false; 1004 1010 1005 - bundle = kmemdup(template, sizeof(*bundle), GFP_KERNEL); 1011 + struct msi_domain_template *bundle __free(kfree) = 1012 + kmemdup(template, sizeof(*bundle), GFP_KERNEL); 1006 1013 if (!bundle) 1007 1014 return false; 1008 1015 ··· 1026 1031 * node as they are not guaranteed to have a fwnode. They are never 1027 1032 * looked up and always handled in the context of the device. 1028 1033 */ 1029 - if (bundle->info.flags & MSI_FLAG_USE_DEV_FWNODE) 1030 - fwnode = dev->fwnode; 1034 + struct fwnode_handle *fwnode_alloced __free(irq_domain_free_fwnode) = NULL; 1035 + 1036 + if (!(bundle->info.flags & MSI_FLAG_USE_DEV_FWNODE)) 1037 + fwnode = fwnode_alloced = irq_domain_alloc_named_fwnode(bundle->name); 1031 1038 else 1032 - fwnode = fwnalloced = irq_domain_alloc_named_fwnode(bundle->name); 1039 + fwnode = dev->fwnode; 1033 1040 1034 1041 if (!fwnode) 1035 - goto free_bundle; 1042 + return false; 1036 1043 1037 1044 if (msi_setup_device_data(dev)) 1038 - goto free_fwnode; 1045 + return false; 1039 1046 1040 - msi_lock_descs(dev); 1041 - 1047 + guard(msi_descs_lock)(dev); 1042 1048 if (WARN_ON_ONCE(msi_get_device_domain(dev, domid))) 1043 - goto fail; 1049 + return false; 1044 1050 1045 1051 if (!pops->init_dev_msi_info(dev, parent, parent, &bundle->info)) 1046 - goto fail; 1052 + return false; 1047 1053 1048 1054 domain = __msi_create_irq_domain(fwnode, &bundle->info, IRQ_DOMAIN_FLAG_MSI_DEVICE, parent); 1049 1055 if (!domain) 1050 - goto fail; 1056 + return false; 1051 1057 1058 + /* @bundle and @fwnode_alloced are now in use. Prevent cleanup */ 1059 + retain_and_null_ptr(bundle); 1060 + retain_and_null_ptr(fwnode_alloced); 1052 1061 domain->dev = dev; 1053 1062 dev->msi.data->__domains[domid].domain = domain; 1054 - msi_unlock_descs(dev); 1055 1063 return true; 1056 - 1057 - fail: 1058 - msi_unlock_descs(dev); 1059 - free_fwnode: 1060 - irq_domain_free_fwnode(fwnalloced); 1061 - free_bundle: 1062 - kfree(bundle); 1063 - return false; 1064 1064 } 1065 1065 1066 1066 /** ··· 1069 1079 struct msi_domain_info *info; 1070 1080 struct irq_domain *domain; 1071 1081 1072 - msi_lock_descs(dev); 1073 - 1082 + guard(msi_descs_lock)(dev); 1074 1083 domain = msi_get_device_domain(dev, domid); 1075 - 1076 1084 if (!domain || !irq_domain_is_msi_device(domain)) 1077 - goto unlock; 1085 + return; 1078 1086 1079 1087 dev->msi.data->__domains[domid].domain = NULL; 1080 1088 info = domain->host_data; ··· 1081 1093 irq_domain_remove(domain); 1082 1094 irq_domain_free_fwnode(fwnode); 1083 1095 kfree(container_of(info, struct msi_domain_template, info)); 1084 - 1085 - unlock: 1086 - msi_unlock_descs(dev); 1087 1096 } 1088 1097 1089 1098 /** ··· 1096 1111 { 1097 1112 struct msi_domain_info *info; 1098 1113 struct irq_domain *domain; 1099 - bool ret = false; 1100 1114 1101 - msi_lock_descs(dev); 1115 + guard(msi_descs_lock)(dev); 1102 1116 domain = msi_get_device_domain(dev, domid); 1103 1117 if (domain && irq_domain_is_msi_device(domain)) { 1104 1118 info = domain->host_data; 1105 - ret = info->bus_token == bus_token; 1119 + return info->bus_token == bus_token; 1106 1120 } 1107 - msi_unlock_descs(dev); 1108 - return ret; 1121 + return false; 1109 1122 } 1110 1123 1111 1124 static int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev, ··· 1374 1391 int msi_domain_alloc_irqs_range(struct device *dev, unsigned int domid, 1375 1392 unsigned int first, unsigned int last) 1376 1393 { 1377 - int ret; 1378 1394 1379 - msi_lock_descs(dev); 1380 - ret = msi_domain_alloc_irqs_range_locked(dev, domid, first, last); 1381 - msi_unlock_descs(dev); 1382 - return ret; 1395 + guard(msi_descs_lock)(dev); 1396 + return msi_domain_alloc_irqs_range_locked(dev, domid, first, last); 1383 1397 } 1384 1398 EXPORT_SYMBOL_GPL(msi_domain_alloc_irqs_range); 1385 1399 ··· 1480 1500 const struct irq_affinity_desc *affdesc, 1481 1501 union msi_instance_cookie *icookie) 1482 1502 { 1483 - struct msi_map map; 1484 - 1485 - msi_lock_descs(dev); 1486 - map = __msi_domain_alloc_irq_at(dev, domid, index, affdesc, icookie); 1487 - msi_unlock_descs(dev); 1488 - return map; 1503 + guard(msi_descs_lock)(dev); 1504 + return __msi_domain_alloc_irq_at(dev, domid, index, affdesc, icookie); 1489 1505 } 1490 1506 1491 1507 /** ··· 1518 1542 1519 1543 icookie.value = ((u64)type << 32) | hwirq; 1520 1544 1521 - msi_lock_descs(dev); 1545 + guard(msi_descs_lock)(dev); 1522 1546 if (WARN_ON_ONCE(msi_get_device_domain(dev, domid) != domain)) 1523 1547 map.index = -EINVAL; 1524 1548 else 1525 1549 map = __msi_domain_alloc_irq_at(dev, domid, MSI_ANY_INDEX, NULL, &icookie); 1526 - msi_unlock_descs(dev); 1527 - 1528 1550 return map.index >= 0 ? map.virq : map.index; 1529 1551 } 1530 1552 ··· 1615 1641 void msi_domain_free_irqs_range(struct device *dev, unsigned int domid, 1616 1642 unsigned int first, unsigned int last) 1617 1643 { 1618 - msi_lock_descs(dev); 1644 + guard(msi_descs_lock)(dev); 1619 1645 msi_domain_free_irqs_range_locked(dev, domid, first, last); 1620 - msi_unlock_descs(dev); 1621 1646 } 1622 1647 EXPORT_SYMBOL_GPL(msi_domain_free_irqs_all); 1623 1648 ··· 1646 1673 */ 1647 1674 void msi_domain_free_irqs_all(struct device *dev, unsigned int domid) 1648 1675 { 1649 - msi_lock_descs(dev); 1676 + guard(msi_descs_lock)(dev); 1650 1677 msi_domain_free_irqs_all_locked(dev, domid); 1651 - msi_unlock_descs(dev); 1652 1678 } 1653 1679 1654 1680 /** ··· 1666 1694 if (WARN_ON_ONCE(!dev || !desc || domain->bus_token != DOMAIN_BUS_WIRED_TO_MSI)) 1667 1695 return; 1668 1696 1669 - msi_lock_descs(dev); 1670 - if (!WARN_ON_ONCE(msi_get_device_domain(dev, MSI_DEFAULT_DOMAIN) != domain)) { 1671 - msi_domain_free_irqs_range_locked(dev, MSI_DEFAULT_DOMAIN, desc->msi_index, 1672 - desc->msi_index); 1673 - } 1674 - msi_unlock_descs(dev); 1697 + guard(msi_descs_lock)(dev); 1698 + if (WARN_ON_ONCE(msi_get_device_domain(dev, MSI_DEFAULT_DOMAIN) != domain)) 1699 + return; 1700 + msi_domain_free_irqs_range_locked(dev, MSI_DEFAULT_DOMAIN, desc->msi_index, 1701 + desc->msi_index); 1675 1702 } 1676 1703 1677 1704 /**