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

s390/vfio-ap: Add write support to sysfs attr ap_config

Allow writing a complete set of masks to ap_config. Doing so will
cause the vfio-ap driver to replace the vfio-ap mediated device's
matrix masks with the given set of masks. If the given state cannot
be set, then no changes are made to the vfio-ap mediated device.

The format of the data written to ap_config is as follows:
{amask},{dmask},{cmask}\n

\n is a newline character.

amask, dmask, and cmask are masks identifying which adapters, domains,
and control domains should be assigned to the mediated device.

The format of a mask is as follows:
0xNN..NN

Where NN..NN is 64 hexadecimal characters representing a 256-bit value.
The leftmost (highest order) bit represents adapter/domain 0.

For an example set of masks that represent your mdev's current
configuration, simply cat ap_config.

This attribute is intended to be used by an mdevctl callout script
supporting the mdev type vfio_ap-passthrough to atomically update a
vfio-ap mediated device's state.

Signed-off-by: "Jason J. Herne" <jjherne@linux.ibm.com>
Reviewed-by: Tony Krowiak <akrowiak@linux.ibm.com>
Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
Link: https://lore.kernel.org/r/20240415152555.13152-5-jjherne@linux.ibm.com
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>

authored by

Jason J. Herne and committed by
Alexander Gordeev
8fb456bc f3e3a400

+180 -16
+177 -13
drivers/s390/crypto/vfio_ap_ops.c
··· 1119 1119 } 1120 1120 } 1121 1121 1122 - static void vfio_ap_mdev_hot_unplug_adapter(struct ap_matrix_mdev *matrix_mdev, 1123 - unsigned long apid) 1122 + static void vfio_ap_mdev_hot_unplug_adapters(struct ap_matrix_mdev *matrix_mdev, 1123 + unsigned long *apids) 1124 1124 { 1125 1125 struct vfio_ap_queue *q, *tmpq; 1126 1126 struct list_head qlist; 1127 + unsigned long apid; 1128 + bool apcb_update = false; 1127 1129 1128 1130 INIT_LIST_HEAD(&qlist); 1129 - vfio_ap_mdev_unlink_adapter(matrix_mdev, apid, &qlist); 1130 1131 1131 - if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm)) { 1132 - clear_bit_inv(apid, matrix_mdev->shadow_apcb.apm); 1133 - vfio_ap_mdev_update_guest_apcb(matrix_mdev); 1132 + for_each_set_bit_inv(apid, apids, AP_DEVICES) { 1133 + vfio_ap_mdev_unlink_adapter(matrix_mdev, apid, &qlist); 1134 + 1135 + if (test_bit_inv(apid, matrix_mdev->shadow_apcb.apm)) { 1136 + clear_bit_inv(apid, matrix_mdev->shadow_apcb.apm); 1137 + apcb_update = true; 1138 + } 1134 1139 } 1140 + 1141 + /* Only update apcb if needed to avoid impacting guest */ 1142 + if (apcb_update) 1143 + vfio_ap_mdev_update_guest_apcb(matrix_mdev); 1135 1144 1136 1145 vfio_ap_mdev_reset_qlist(&qlist); 1137 1146 ··· 1148 1139 vfio_ap_unlink_mdev_fr_queue(q); 1149 1140 list_del(&q->reset_qnode); 1150 1141 } 1142 + } 1143 + 1144 + static void vfio_ap_mdev_hot_unplug_adapter(struct ap_matrix_mdev *matrix_mdev, 1145 + unsigned long apid) 1146 + { 1147 + DECLARE_BITMAP(apids, AP_DEVICES); 1148 + 1149 + bitmap_zero(apids, AP_DEVICES); 1150 + set_bit_inv(apid, apids); 1151 + vfio_ap_mdev_hot_unplug_adapters(matrix_mdev, apids); 1151 1152 } 1152 1153 1153 1154 /** ··· 1320 1301 } 1321 1302 } 1322 1303 1323 - static void vfio_ap_mdev_hot_unplug_domain(struct ap_matrix_mdev *matrix_mdev, 1324 - unsigned long apqi) 1304 + static void vfio_ap_mdev_hot_unplug_domains(struct ap_matrix_mdev *matrix_mdev, 1305 + unsigned long *apqis) 1325 1306 { 1326 1307 struct vfio_ap_queue *q, *tmpq; 1327 1308 struct list_head qlist; 1309 + unsigned long apqi; 1310 + bool apcb_update = false; 1328 1311 1329 1312 INIT_LIST_HEAD(&qlist); 1330 - vfio_ap_mdev_unlink_domain(matrix_mdev, apqi, &qlist); 1331 1313 1332 - if (test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm)) { 1333 - clear_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm); 1334 - vfio_ap_mdev_update_guest_apcb(matrix_mdev); 1314 + for_each_set_bit_inv(apqi, apqis, AP_DOMAINS) { 1315 + vfio_ap_mdev_unlink_domain(matrix_mdev, apqi, &qlist); 1316 + 1317 + if (test_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm)) { 1318 + clear_bit_inv(apqi, matrix_mdev->shadow_apcb.aqm); 1319 + apcb_update = true; 1320 + } 1335 1321 } 1322 + 1323 + /* Only update apcb if needed to avoid impacting guest */ 1324 + if (apcb_update) 1325 + vfio_ap_mdev_update_guest_apcb(matrix_mdev); 1336 1326 1337 1327 vfio_ap_mdev_reset_qlist(&qlist); 1338 1328 ··· 1349 1321 vfio_ap_unlink_mdev_fr_queue(q); 1350 1322 list_del(&q->reset_qnode); 1351 1323 } 1324 + } 1325 + 1326 + static void vfio_ap_mdev_hot_unplug_domain(struct ap_matrix_mdev *matrix_mdev, 1327 + unsigned long apqi) 1328 + { 1329 + DECLARE_BITMAP(apqis, AP_DOMAINS); 1330 + 1331 + bitmap_zero(apqis, AP_DEVICES); 1332 + set_bit_inv(apqi, apqis); 1333 + vfio_ap_mdev_hot_unplug_domains(matrix_mdev, apqis); 1352 1334 } 1353 1335 1354 1336 /** ··· 1628 1590 return idx; 1629 1591 } 1630 1592 1593 + /* Number of characters needed for a complete hex mask representing the bits in .. */ 1594 + #define AP_DEVICES_STRLEN (AP_DEVICES / 4 + 3) 1595 + #define AP_DOMAINS_STRLEN (AP_DOMAINS / 4 + 3) 1596 + #define AP_CONFIG_STRLEN (AP_DEVICES_STRLEN + 2 * AP_DOMAINS_STRLEN) 1597 + 1598 + static int parse_bitmap(char **strbufptr, unsigned long *bitmap, int nbits) 1599 + { 1600 + char *curmask; 1601 + 1602 + curmask = strsep(strbufptr, ",\n"); 1603 + if (!curmask) 1604 + return -EINVAL; 1605 + 1606 + bitmap_clear(bitmap, 0, nbits); 1607 + return ap_hex2bitmap(curmask, bitmap, nbits); 1608 + } 1609 + 1610 + static int ap_matrix_overflow_check(struct ap_matrix_mdev *matrix_mdev) 1611 + { 1612 + unsigned long bit; 1613 + 1614 + for_each_set_bit_inv(bit, matrix_mdev->matrix.apm, AP_DEVICES) { 1615 + if (bit > matrix_mdev->matrix.apm_max) 1616 + return -ENODEV; 1617 + } 1618 + 1619 + for_each_set_bit_inv(bit, matrix_mdev->matrix.aqm, AP_DOMAINS) { 1620 + if (bit > matrix_mdev->matrix.aqm_max) 1621 + return -ENODEV; 1622 + } 1623 + 1624 + for_each_set_bit_inv(bit, matrix_mdev->matrix.adm, AP_DOMAINS) { 1625 + if (bit > matrix_mdev->matrix.adm_max) 1626 + return -ENODEV; 1627 + } 1628 + 1629 + return 0; 1630 + } 1631 + 1632 + static void ap_matrix_copy(struct ap_matrix *dst, struct ap_matrix *src) 1633 + { 1634 + /* This check works around false positive gcc -Wstringop-overread */ 1635 + if (!src) 1636 + return; 1637 + 1638 + bitmap_copy(dst->apm, src->apm, AP_DEVICES); 1639 + bitmap_copy(dst->aqm, src->aqm, AP_DOMAINS); 1640 + bitmap_copy(dst->adm, src->adm, AP_DOMAINS); 1641 + } 1642 + 1631 1643 static ssize_t ap_config_store(struct device *dev, struct device_attribute *attr, 1632 1644 const char *buf, size_t count) 1633 1645 { 1634 - return count; 1646 + struct ap_matrix_mdev *matrix_mdev = dev_get_drvdata(dev); 1647 + struct ap_matrix m_new, m_old, m_added, m_removed; 1648 + DECLARE_BITMAP(apm_filtered, AP_DEVICES); 1649 + unsigned long newbit; 1650 + char *newbuf, *rest; 1651 + int rc = count; 1652 + bool do_update; 1653 + 1654 + newbuf = kstrndup(buf, AP_CONFIG_STRLEN, GFP_KERNEL); 1655 + if (!newbuf) 1656 + return -ENOMEM; 1657 + rest = newbuf; 1658 + 1659 + mutex_lock(&ap_perms_mutex); 1660 + get_update_locks_for_mdev(matrix_mdev); 1661 + 1662 + /* Save old state */ 1663 + ap_matrix_copy(&m_old, &matrix_mdev->matrix); 1664 + if (parse_bitmap(&rest, m_new.apm, AP_DEVICES) || 1665 + parse_bitmap(&rest, m_new.aqm, AP_DOMAINS) || 1666 + parse_bitmap(&rest, m_new.adm, AP_DOMAINS)) { 1667 + rc = -EINVAL; 1668 + goto out; 1669 + } 1670 + 1671 + bitmap_andnot(m_removed.apm, m_old.apm, m_new.apm, AP_DEVICES); 1672 + bitmap_andnot(m_removed.aqm, m_old.aqm, m_new.aqm, AP_DOMAINS); 1673 + bitmap_andnot(m_added.apm, m_new.apm, m_old.apm, AP_DEVICES); 1674 + bitmap_andnot(m_added.aqm, m_new.aqm, m_old.aqm, AP_DOMAINS); 1675 + 1676 + /* Need new bitmaps in matrix_mdev for validation */ 1677 + ap_matrix_copy(&matrix_mdev->matrix, &m_new); 1678 + 1679 + /* Ensure new state is valid, else undo new state */ 1680 + rc = vfio_ap_mdev_validate_masks(matrix_mdev); 1681 + if (rc) { 1682 + ap_matrix_copy(&matrix_mdev->matrix, &m_old); 1683 + goto out; 1684 + } 1685 + rc = ap_matrix_overflow_check(matrix_mdev); 1686 + if (rc) { 1687 + ap_matrix_copy(&matrix_mdev->matrix, &m_old); 1688 + goto out; 1689 + } 1690 + rc = count; 1691 + 1692 + /* Need old bitmaps in matrix_mdev for unplug/unlink */ 1693 + ap_matrix_copy(&matrix_mdev->matrix, &m_old); 1694 + 1695 + /* Unlink removed adapters/domains */ 1696 + vfio_ap_mdev_hot_unplug_adapters(matrix_mdev, m_removed.apm); 1697 + vfio_ap_mdev_hot_unplug_domains(matrix_mdev, m_removed.aqm); 1698 + 1699 + /* Need new bitmaps in matrix_mdev for linking new adapters/domains */ 1700 + ap_matrix_copy(&matrix_mdev->matrix, &m_new); 1701 + 1702 + /* Link newly added adapters */ 1703 + for_each_set_bit_inv(newbit, m_added.apm, AP_DEVICES) 1704 + vfio_ap_mdev_link_adapter(matrix_mdev, newbit); 1705 + 1706 + for_each_set_bit_inv(newbit, m_added.aqm, AP_DOMAINS) 1707 + vfio_ap_mdev_link_domain(matrix_mdev, newbit); 1708 + 1709 + /* filter resources not bound to vfio-ap */ 1710 + do_update = vfio_ap_mdev_filter_matrix(matrix_mdev, apm_filtered); 1711 + do_update |= vfio_ap_mdev_filter_cdoms(matrix_mdev); 1712 + 1713 + /* Apply changes to shadow apbc if things changed */ 1714 + if (do_update) { 1715 + vfio_ap_mdev_update_guest_apcb(matrix_mdev); 1716 + reset_queues_for_apids(matrix_mdev, apm_filtered); 1717 + } 1718 + out: 1719 + release_update_locks_for_mdev(matrix_mdev); 1720 + mutex_unlock(&ap_perms_mutex); 1721 + kfree(newbuf); 1722 + return rc; 1635 1723 } 1636 1724 static DEVICE_ATTR_RW(ap_config); 1637 1725
+3 -3
drivers/s390/crypto/vfio_ap_private.h
··· 75 75 */ 76 76 struct ap_matrix { 77 77 unsigned long apm_max; 78 - DECLARE_BITMAP(apm, 256); 78 + DECLARE_BITMAP(apm, AP_DEVICES); 79 79 unsigned long aqm_max; 80 - DECLARE_BITMAP(aqm, 256); 80 + DECLARE_BITMAP(aqm, AP_DOMAINS); 81 81 unsigned long adm_max; 82 - DECLARE_BITMAP(adm, 256); 82 + DECLARE_BITMAP(adm, AP_DOMAINS); 83 83 }; 84 84 85 85 /**