@@ -1119,20 +1119,29 @@ static void vfio_ap_mdev_unlink_adapter(struct ap_matrix_mdev *matrix_mdev,
11191119 }
11201120}
11211121
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 )
11241124{
11251125 struct vfio_ap_queue * q , * tmpq ;
11261126 struct list_head qlist ;
1127+ unsigned long apid ;
1128+ bool apcb_update = false;
11271129
11281130 INIT_LIST_HEAD (& qlist );
1129- vfio_ap_mdev_unlink_adapter (matrix_mdev , apid , & qlist );
11301131
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+ }
11341139 }
11351140
1141+ /* Only update apcb if needed to avoid impacting guest */
1142+ if (apcb_update )
1143+ vfio_ap_mdev_update_guest_apcb (matrix_mdev );
1144+
11361145 vfio_ap_mdev_reset_qlist (& qlist );
11371146
11381147 list_for_each_entry_safe (q , tmpq , & qlist , reset_qnode ) {
@@ -1141,6 +1150,16 @@ static void vfio_ap_mdev_hot_unplug_adapter(struct ap_matrix_mdev *matrix_mdev,
11411150 }
11421151}
11431152
1153+ static void vfio_ap_mdev_hot_unplug_adapter (struct ap_matrix_mdev * matrix_mdev ,
1154+ unsigned long apid )
1155+ {
1156+ DECLARE_BITMAP (apids , AP_DEVICES );
1157+
1158+ bitmap_zero (apids , AP_DEVICES );
1159+ set_bit_inv (apid , apids );
1160+ vfio_ap_mdev_hot_unplug_adapters (matrix_mdev , apids );
1161+ }
1162+
11441163/**
11451164 * unassign_adapter_store - parses the APID from @buf and clears the
11461165 * corresponding bit in the mediated matrix device's APM
@@ -1301,20 +1320,29 @@ static void vfio_ap_mdev_unlink_domain(struct ap_matrix_mdev *matrix_mdev,
13011320 }
13021321}
13031322
1304- static void vfio_ap_mdev_hot_unplug_domain (struct ap_matrix_mdev * matrix_mdev ,
1305- unsigned long apqi )
1323+ static void vfio_ap_mdev_hot_unplug_domains (struct ap_matrix_mdev * matrix_mdev ,
1324+ unsigned long * apqis )
13061325{
13071326 struct vfio_ap_queue * q , * tmpq ;
13081327 struct list_head qlist ;
1328+ unsigned long apqi ;
1329+ bool apcb_update = false;
13091330
13101331 INIT_LIST_HEAD (& qlist );
1311- vfio_ap_mdev_unlink_domain (matrix_mdev , apqi , & qlist );
13121332
1313- if (test_bit_inv (apqi , matrix_mdev -> shadow_apcb .aqm )) {
1314- clear_bit_inv (apqi , matrix_mdev -> shadow_apcb .aqm );
1315- vfio_ap_mdev_update_guest_apcb (matrix_mdev );
1333+ for_each_set_bit_inv (apqi , apqis , AP_DOMAINS ) {
1334+ vfio_ap_mdev_unlink_domain (matrix_mdev , apqi , & qlist );
1335+
1336+ if (test_bit_inv (apqi , matrix_mdev -> shadow_apcb .aqm )) {
1337+ clear_bit_inv (apqi , matrix_mdev -> shadow_apcb .aqm );
1338+ apcb_update = true;
1339+ }
13161340 }
13171341
1342+ /* Only update apcb if needed to avoid impacting guest */
1343+ if (apcb_update )
1344+ vfio_ap_mdev_update_guest_apcb (matrix_mdev );
1345+
13181346 vfio_ap_mdev_reset_qlist (& qlist );
13191347
13201348 list_for_each_entry_safe (q , tmpq , & qlist , reset_qnode ) {
@@ -1323,6 +1351,16 @@ static void vfio_ap_mdev_hot_unplug_domain(struct ap_matrix_mdev *matrix_mdev,
13231351 }
13241352}
13251353
1354+ static void vfio_ap_mdev_hot_unplug_domain (struct ap_matrix_mdev * matrix_mdev ,
1355+ unsigned long apqi )
1356+ {
1357+ DECLARE_BITMAP (apqis , AP_DOMAINS );
1358+
1359+ bitmap_zero (apqis , AP_DEVICES );
1360+ set_bit_inv (apqi , apqis );
1361+ vfio_ap_mdev_hot_unplug_domains (matrix_mdev , apqis );
1362+ }
1363+
13261364/**
13271365 * unassign_domain_store - parses the APQI from @buf and clears the
13281366 * corresponding bit in the mediated matrix device's AQM
@@ -1590,10 +1628,136 @@ static ssize_t ap_config_show(struct device *dev, struct device_attribute *attr,
15901628 return idx ;
15911629}
15921630
1631+ /* Number of characters needed for a complete hex mask representing the bits in .. */
1632+ #define AP_DEVICES_STRLEN (AP_DEVICES / 4 + 3)
1633+ #define AP_DOMAINS_STRLEN (AP_DOMAINS / 4 + 3)
1634+ #define AP_CONFIG_STRLEN (AP_DEVICES_STRLEN + 2 * AP_DOMAINS_STRLEN)
1635+
1636+ static int parse_bitmap (char * * strbufptr , unsigned long * bitmap , int nbits )
1637+ {
1638+ char * curmask ;
1639+
1640+ curmask = strsep (strbufptr , ",\n" );
1641+ if (!curmask )
1642+ return - EINVAL ;
1643+
1644+ bitmap_clear (bitmap , 0 , nbits );
1645+ return ap_hex2bitmap (curmask , bitmap , nbits );
1646+ }
1647+
1648+ static int ap_matrix_overflow_check (struct ap_matrix_mdev * matrix_mdev )
1649+ {
1650+ unsigned long bit ;
1651+
1652+ for_each_set_bit_inv (bit , matrix_mdev -> matrix .apm , AP_DEVICES ) {
1653+ if (bit > matrix_mdev -> matrix .apm_max )
1654+ return - ENODEV ;
1655+ }
1656+
1657+ for_each_set_bit_inv (bit , matrix_mdev -> matrix .aqm , AP_DOMAINS ) {
1658+ if (bit > matrix_mdev -> matrix .aqm_max )
1659+ return - ENODEV ;
1660+ }
1661+
1662+ for_each_set_bit_inv (bit , matrix_mdev -> matrix .adm , AP_DOMAINS ) {
1663+ if (bit > matrix_mdev -> matrix .adm_max )
1664+ return - ENODEV ;
1665+ }
1666+
1667+ return 0 ;
1668+ }
1669+
1670+ static void ap_matrix_copy (struct ap_matrix * dst , struct ap_matrix * src )
1671+ {
1672+ /* This check works around false positive gcc -Wstringop-overread */
1673+ if (!src )
1674+ return ;
1675+
1676+ bitmap_copy (dst -> apm , src -> apm , AP_DEVICES );
1677+ bitmap_copy (dst -> aqm , src -> aqm , AP_DOMAINS );
1678+ bitmap_copy (dst -> adm , src -> adm , AP_DOMAINS );
1679+ }
1680+
15931681static ssize_t ap_config_store (struct device * dev , struct device_attribute * attr ,
15941682 const char * buf , size_t count )
15951683{
1596- return count ;
1684+ struct ap_matrix_mdev * matrix_mdev = dev_get_drvdata (dev );
1685+ struct ap_matrix m_new , m_old , m_added , m_removed ;
1686+ DECLARE_BITMAP (apm_filtered , AP_DEVICES );
1687+ unsigned long newbit ;
1688+ char * newbuf , * rest ;
1689+ int rc = count ;
1690+ bool do_update ;
1691+
1692+ newbuf = kstrndup (buf , AP_CONFIG_STRLEN , GFP_KERNEL );
1693+ if (!newbuf )
1694+ return - ENOMEM ;
1695+ rest = newbuf ;
1696+
1697+ mutex_lock (& ap_perms_mutex );
1698+ get_update_locks_for_mdev (matrix_mdev );
1699+
1700+ /* Save old state */
1701+ ap_matrix_copy (& m_old , & matrix_mdev -> matrix );
1702+ if (parse_bitmap (& rest , m_new .apm , AP_DEVICES ) ||
1703+ parse_bitmap (& rest , m_new .aqm , AP_DOMAINS ) ||
1704+ parse_bitmap (& rest , m_new .adm , AP_DOMAINS )) {
1705+ rc = - EINVAL ;
1706+ goto out ;
1707+ }
1708+
1709+ bitmap_andnot (m_removed .apm , m_old .apm , m_new .apm , AP_DEVICES );
1710+ bitmap_andnot (m_removed .aqm , m_old .aqm , m_new .aqm , AP_DOMAINS );
1711+ bitmap_andnot (m_added .apm , m_new .apm , m_old .apm , AP_DEVICES );
1712+ bitmap_andnot (m_added .aqm , m_new .aqm , m_old .aqm , AP_DOMAINS );
1713+
1714+ /* Need new bitmaps in matrix_mdev for validation */
1715+ ap_matrix_copy (& matrix_mdev -> matrix , & m_new );
1716+
1717+ /* Ensure new state is valid, else undo new state */
1718+ rc = vfio_ap_mdev_validate_masks (matrix_mdev );
1719+ if (rc ) {
1720+ ap_matrix_copy (& matrix_mdev -> matrix , & m_old );
1721+ goto out ;
1722+ }
1723+ rc = ap_matrix_overflow_check (matrix_mdev );
1724+ if (rc ) {
1725+ ap_matrix_copy (& matrix_mdev -> matrix , & m_old );
1726+ goto out ;
1727+ }
1728+ rc = count ;
1729+
1730+ /* Need old bitmaps in matrix_mdev for unplug/unlink */
1731+ ap_matrix_copy (& matrix_mdev -> matrix , & m_old );
1732+
1733+ /* Unlink removed adapters/domains */
1734+ vfio_ap_mdev_hot_unplug_adapters (matrix_mdev , m_removed .apm );
1735+ vfio_ap_mdev_hot_unplug_domains (matrix_mdev , m_removed .aqm );
1736+
1737+ /* Need new bitmaps in matrix_mdev for linking new adapters/domains */
1738+ ap_matrix_copy (& matrix_mdev -> matrix , & m_new );
1739+
1740+ /* Link newly added adapters */
1741+ for_each_set_bit_inv (newbit , m_added .apm , AP_DEVICES )
1742+ vfio_ap_mdev_link_adapter (matrix_mdev , newbit );
1743+
1744+ for_each_set_bit_inv (newbit , m_added .aqm , AP_DOMAINS )
1745+ vfio_ap_mdev_link_domain (matrix_mdev , newbit );
1746+
1747+ /* filter resources not bound to vfio-ap */
1748+ do_update = vfio_ap_mdev_filter_matrix (matrix_mdev , apm_filtered );
1749+ do_update |= vfio_ap_mdev_filter_cdoms (matrix_mdev );
1750+
1751+ /* Apply changes to shadow apbc if things changed */
1752+ if (do_update ) {
1753+ vfio_ap_mdev_update_guest_apcb (matrix_mdev );
1754+ reset_queues_for_apids (matrix_mdev , apm_filtered );
1755+ }
1756+ out :
1757+ release_update_locks_for_mdev (matrix_mdev );
1758+ mutex_unlock (& ap_perms_mutex );
1759+ kfree (newbuf );
1760+ return rc ;
15971761}
15981762static DEVICE_ATTR_RW (ap_config );
15991763
0 commit comments