Pull xen updates from Juergen Gross: - fix a bug introduced in 5.5 in the Xen gntdev driver - fix the Xen balloon driver when running on ancient Xen versions - allow Xen stubdoms to control interrupt enable flags of passed-through PCI cards - release resources in Xen backends under memory pressure * tag 'for-linus-5.6-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip: xen/blkback: Consistently insert one empty line between functions xen/blkback: Remove unnecessary static variable name prefixes xen/blkback: Squeeze page pools if a memory pressure is detected xenbus/backend: Protect xenbus callback with lock xenbus/backend: Add memory pressure handler callback xen/gntdev: Do not use mm notifiers with autotranslating guests xen/balloon: Support xend-based toolstack take two xen-pciback: optionally allow interrupt enable flag writes
Unified · Split
| @@ -11,3 +11,16 @@ Description: · 10 unmodified lines | ||
| 11 | 11 | #echo 00:19.0-E0:2:FF > /sys/bus/pci/drivers/pciback/quirks |
| 12 | 12 | will allow the guest to read and write to the configuration |
| 13 | 13 | register 0x0E. |
| 14 | + | |
| 15 | +What: /sys/bus/pci/drivers/pciback/allow_interrupt_control | |
| 16 | +Date: Jan 2020 | |
| 17 | +KernelVersion: 5.6 | |
| 18 | +Contact: xen-devel@lists.xenproject.org | |
| 19 | +Description: | |
| 20 | + List of devices which can have interrupt control flag (INTx, | |
| 21 | + MSI, MSI-X) set by a connected guest. It is meant to be set | |
| 22 | + only when the guest is a stubdomain hosting device model (qemu) | |
| 23 | + and the actual device is assigned to a HVM. It is not safe | |
| 24 | + (similar to permissive attribute) to set for a devices assigned | |
| 25 | + to a PV guest. The device is automatically removed from this | |
| 26 | + list when the connected pcifront terminates. | |
| @@ -25,3 +25,13 @@ Description: · 24 unmodified lines | ||
| 25 | 25 | allocated without being in use. The time is in |
| 26 | 26 | seconds, 0 means indefinitely long. |
| 27 | 27 | The default is 60 seconds. |
| 28 | + | |
| 29 | +What: /sys/module/xen_blkback/parameters/buffer_squeeze_duration_ms | |
| 30 | +Date: December 2019 | |
| 31 | +KernelVersion: 5.6 | |
| 32 | +Contact: SeongJae Park <sjpark@amazon.de> | |
| 33 | +Description: | |
| 34 | + When memory pressure is reported to blkback this option | |
| 35 | + controls the duration in milliseconds that blkback will not | |
| 36 | + cache any page not backed by a grant mapping. | |
| 37 | + The default is 10ms. | |
| @@ -62,8 +62,8 @@ · 61 unmodified lines | ||
| 62 | 62 | * IO workloads. |
| 63 | 63 | */ |
| 64 | 64 | |
| 65 | −static int xen_blkif_max_buffer_pages = 1024; | |
| 66 | −module_param_named(max_buffer_pages, xen_blkif_max_buffer_pages, int, 0644); | |
| 65 | +static int max_buffer_pages = 1024; | |
| 66 | +module_param_named(max_buffer_pages, max_buffer_pages, int, 0644); | |
| 67 | 67 | MODULE_PARM_DESC(max_buffer_pages, |
| 68 | 68 | "Maximum number of free pages to keep in each block backend buffer"); |
| 69 | 69 | |
| @@ -78,8 +78,8 @@ MODULE_PARM_DESC(max_buffer_pages, · 8 unmodified lines | ||
| 78 | 78 | * algorithm. |
| 79 | 79 | */ |
| 80 | 80 | |
| 81 | −static int xen_blkif_max_pgrants = 1056; | |
| 82 | −module_param_named(max_persistent_grants, xen_blkif_max_pgrants, int, 0644); | |
| 81 | +static int max_pgrants = 1056; | |
| 82 | +module_param_named(max_persistent_grants, max_pgrants, int, 0644); | |
| 83 | 83 | MODULE_PARM_DESC(max_persistent_grants, |
| 84 | 84 | "Maximum number of grants to map persistently"); |
| 85 | 85 | |
| @@ -88,8 +88,8 @@ MODULE_PARM_DESC(max_persistent_grants, · 2 unmodified lines | ||
| 88 | 88 | * use. The time is in seconds, 0 means indefinitely long. |
| 89 | 89 | */ |
| 90 | 90 | |
| 91 | −static unsigned int xen_blkif_pgrant_timeout = 60; | |
| 92 | −module_param_named(persistent_grant_unused_seconds, xen_blkif_pgrant_timeout, | |
| 91 | +static unsigned int pgrant_timeout = 60; | |
| 92 | +module_param_named(persistent_grant_unused_seconds, pgrant_timeout, | |
| 93 | 93 | uint, 0644); |
| 94 | 94 | MODULE_PARM_DESC(persistent_grant_unused_seconds, |
| 95 | 95 | "Time in seconds an unused persistent grant is allowed to " |
| @@ -137,9 +137,8 @@ module_param(log_stats, int, 0644); · 41 unmodified lines | ||
| 137 | 137 | |
| 138 | 138 | static inline bool persistent_gnt_timeout(struct persistent_gnt *persistent_gnt) |
| 139 | 139 | { |
| 140 | − return xen_blkif_pgrant_timeout && | |
| 141 | − (jiffies - persistent_gnt->last_used >= | |
| 142 | − HZ * xen_blkif_pgrant_timeout); | |
| 140 | + return pgrant_timeout && (jiffies - persistent_gnt->last_used >= | |
| 141 | + HZ * pgrant_timeout); | |
| 143 | 142 | } |
| 144 | 143 | |
| 145 | 144 | static inline int get_free_page(struct xen_blkif_ring *ring, struct page **page) |
| @@ -234,7 +233,7 @@ static int add_persistent_gnt(struct xen_blkif_ring *ring, · 88 unmodified lines | ||
| 234 | 233 | struct persistent_gnt *this; |
| 235 | 234 | struct xen_blkif *blkif = ring->blkif; |
| 236 | 235 | |
| 237 | − if (ring->persistent_gnt_c >= xen_blkif_max_pgrants) { | |
| 236 | + if (ring->persistent_gnt_c >= max_pgrants) { | |
| 238 | 237 | if (!blkif->vbd.overflow_max_grants) |
| 239 | 238 | blkif->vbd.overflow_max_grants = 1; |
| 240 | 239 | return -EBUSY; |
| @@ -397,14 +396,13 @@ static void purge_persistent_gnt(struct xen_blkif_ring *ring) · 156 unmodified lines | ||
| 397 | 396 | goto out; |
| 398 | 397 | } |
| 399 | 398 | |
| 400 | − if (ring->persistent_gnt_c < xen_blkif_max_pgrants || | |
| 401 | − (ring->persistent_gnt_c == xen_blkif_max_pgrants && | |
| 399 | + if (ring->persistent_gnt_c < max_pgrants || | |
| 400 | + (ring->persistent_gnt_c == max_pgrants && | |
| 402 | 401 | !ring->blkif->vbd.overflow_max_grants)) { |
| 403 | 402 | num_clean = 0; |
| 404 | 403 | } else { |
| 405 | − num_clean = (xen_blkif_max_pgrants / 100) * LRU_PERCENT_CLEAN; | |
| 406 | − num_clean = ring->persistent_gnt_c - xen_blkif_max_pgrants + | |
| 407 | − num_clean; | |
| 404 | + num_clean = (max_pgrants / 100) * LRU_PERCENT_CLEAN; | |
| 405 | + num_clean = ring->persistent_gnt_c - max_pgrants + num_clean; | |
| 408 | 406 | num_clean = min(ring->persistent_gnt_c, num_clean); |
| 409 | 407 | pr_debug("Going to purge at least %u persistent grants\n", |
| 410 | 408 | num_clean); |
| @@ -599,8 +597,7 @@ static void print_stats(struct xen_blkif_ring *ring) · 188 unmodified lines | ||
| 599 | 597 | current->comm, ring->st_oo_req, |
| 600 | 598 | ring->st_rd_req, ring->st_wr_req, |
| 601 | 599 | ring->st_f_req, ring->st_ds_req, |
| 602 | − ring->persistent_gnt_c, | |
| 603 | − xen_blkif_max_pgrants); | |
| 600 | + ring->persistent_gnt_c, max_pgrants); | |
| 604 | 601 | ring->st_print = jiffies + msecs_to_jiffies(10 * 1000); |
| 605 | 602 | ring->st_rd_req = 0; |
| 606 | 603 | ring->st_wr_req = 0; |
| @@ -656,8 +653,11 @@ purge_gnt_list: · 49 unmodified lines | ||
| 656 | 653 | ring->next_lru = jiffies + msecs_to_jiffies(LRU_INTERVAL); |
| 657 | 654 | } |
| 658 | 655 | |
| 659 | − /* Shrink if we have more than xen_blkif_max_buffer_pages */ | |
| 660 | − shrink_free_pagepool(ring, xen_blkif_max_buffer_pages); | |
| 656 | + /* Shrink the free pages pool if it is too large. */ | |
| 657 | + if (time_before(jiffies, blkif->buffer_squeeze_end)) | |
| 658 | + shrink_free_pagepool(ring, 0); | |
| 659 | + else | |
| 660 | + shrink_free_pagepool(ring, max_buffer_pages); | |
| 661 | 661 | |
| 662 | 662 | if (log_stats && time_after(jiffies, ring->st_print)) |
| 663 | 663 | print_stats(ring); |
| @@ -884,7 +884,7 @@ again: · 220 unmodified lines | ||
| 884 | 884 | continue; |
| 885 | 885 | } |
| 886 | 886 | if (use_persistent_gnts && |
| 887 | − ring->persistent_gnt_c < xen_blkif_max_pgrants) { | |
| 887 | + ring->persistent_gnt_c < max_pgrants) { | |
| 888 | 888 | /* |
| 889 | 889 | * We are using persistent grants, the grant is |
| 890 | 890 | * not mapped but we might have room for it. |
| @@ -911,7 +911,7 @@ again: · 20 unmodified lines | ||
| 911 | 911 | pages[seg_idx]->persistent_gnt = persistent_gnt; |
| 912 | 912 | pr_debug("grant %u added to the tree of persistent grants, using %u/%u\n", |
| 913 | 913 | persistent_gnt->gnt, ring->persistent_gnt_c, |
| 914 | − xen_blkif_max_pgrants); | |
| 914 | + max_pgrants); | |
| 915 | 915 | goto next; |
| 916 | 916 | } |
| 917 | 917 | if (use_persistent_gnts && !blkif->vbd.overflow_max_grants) { |
| @@ -319,6 +319,7 @@ struct xen_blkif { · 318 unmodified lines | ||
| 319 | 319 | /* All rings for this device. */ |
| 320 | 320 | struct xen_blkif_ring *rings; |
| 321 | 321 | unsigned int nr_rings; |
| 322 | + unsigned long buffer_squeeze_end; | |
| 322 | 323 | }; |
| 323 | 324 | |
| 324 | 325 | struct seg_buf { |
| @@ -467,7 +467,6 @@ static void xenvbd_sysfs_delif(struct xenbus_device *dev) · 466 unmodified lines | ||
| 467 | 467 | device_remove_file(&dev->dev, &dev_attr_physical_device); |
| 468 | 468 | } |
| 469 | 469 | |
| 470 | − | |
| 471 | 470 | static void xen_vbd_free(struct xen_vbd *vbd) |
| 472 | 471 | { |
| 473 | 472 | if (vbd->bdev) |
| @@ -524,6 +523,7 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle, · 50 unmodified lines | ||
| 524 | 523 | handle, blkif->domid); |
| 525 | 524 | return 0; |
| 526 | 525 | } |
| 526 | + | |
| 527 | 527 | static int xen_blkbk_remove(struct xenbus_device *dev) |
| 528 | 528 | { |
| 529 | 529 | struct backend_info *be = dev_get_drvdata(&dev->dev); |
| @@ -607,6 +607,7 @@ static void xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info · 77 unmodified lines | ||
| 607 | 607 | if (err) |
| 608 | 608 | dev_warn(&dev->dev, "writing feature-discard (%d)", err); |
| 609 | 609 | } |
| 610 | + | |
| 610 | 611 | int xen_blkbk_barrier(struct xenbus_transaction xbt, |
| 611 | 612 | struct backend_info *be, int state) |
| 612 | 613 | { |
| @@ -691,7 +692,6 @@ fail: · 78 unmodified lines | ||
| 691 | 692 | return err; |
| 692 | 693 | } |
| 693 | 694 | |
| 694 | − | |
| 695 | 695 | /* |
| 696 | 696 | * Callback received when the hotplug scripts have placed the physical-device |
| 697 | 697 | * node. Read it and the mode node, and create a vbd. If the frontend is |
| @@ -783,7 +783,6 @@ static void backend_changed(struct xenbus_watch *watch, · 85 unmodified lines | ||
| 783 | 783 | } |
| 784 | 784 | } |
| 785 | 785 | |
| 786 | − | |
| 787 | 786 | /* |
| 788 | 787 | * Callback received when the frontend's state changes. |
| 789 | 788 | */ |
| @@ -858,9 +857,27 @@ static void frontend_changed(struct xenbus_device *dev, · 68 unmodified lines | ||
| 858 | 857 | } |
| 859 | 858 | } |
| 860 | 859 | |
| 860 | +/* Once a memory pressure is detected, squeeze free page pools for a while. */ | |
| 861 | +static unsigned int buffer_squeeze_duration_ms = 10; | |
| 862 | +module_param_named(buffer_squeeze_duration_ms, | |
| 863 | + buffer_squeeze_duration_ms, int, 0644); | |
| 864 | +MODULE_PARM_DESC(buffer_squeeze_duration_ms, | |
| 865 | +"Duration in ms to squeeze pages buffer when a memory pressure is detected"); | |
| 861 | 866 | |
| 862 | −/* ** Connection ** */ | |
| 867 | +/* | |
| 868 | + * Callback received when the memory pressure is detected. | |
| 869 | + */ | |
| 870 | +static void reclaim_memory(struct xenbus_device *dev) | |
| 871 | +{ | |
| 872 | + struct backend_info *be = dev_get_drvdata(&dev->dev); | |
| 863 | 873 | |
| 874 | + if (!be) | |
| 875 | + return; | |
| 876 | + be->blkif->buffer_squeeze_end = jiffies + | |
| 877 | + msecs_to_jiffies(buffer_squeeze_duration_ms); | |
| 878 | +} | |
| 879 | + | |
| 880 | +/* ** Connection ** */ | |
| 864 | 881 | |
| 865 | 882 | /* |
| 866 | 883 | * Write the physical details regarding the block device to the store, and |
| @@ -1152,6 +1169,7 @@ static struct xenbus_driver xen_blkbk_driver = { · 285 unmodified lines | ||
| 1152 | 1169 | .remove = xen_blkbk_remove, |
| 1153 | 1170 | .otherend_changed = frontend_changed, |
| 1154 | 1171 | .allow_rebind = true, |
| 1172 | + .reclaim_memory = reclaim_memory, | |
| 1155 | 1173 | }; |
| 1156 | 1174 | |
| 1157 | 1175 | int xen_blkif_xenbus_init(void) |
| @@ -1006,19 +1006,19 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) · 1005 unmodified lines | ||
| 1006 | 1006 | } |
| 1007 | 1007 | mutex_unlock(&priv->lock); |
| 1008 | 1008 | |
| 1009 | − /* | |
| 1010 | − * gntdev takes the address of the PTE in find_grant_ptes() and passes | |
| 1011 | − * it to the hypervisor in gntdev_map_grant_pages(). The purpose of | |
| 1012 | − * the notifier is to prevent the hypervisor pointer to the PTE from | |
| 1013 | − * going stale. | |
| 1014 | − * | |
| 1015 | − * Since this vma's mappings can't be touched without the mmap_sem, | |
| 1016 | − * and we are holding it now, there is no need for the notifier_range | |
| 1017 | − * locking pattern. | |
| 1018 | − */ | |
| 1019 | − mmu_interval_read_begin(&map->notifier); | |
| 1020 | − | |
| 1021 | 1009 | if (use_ptemod) { |
| 1010 | + /* | |
| 1011 | + * gntdev takes the address of the PTE in find_grant_ptes() and | |
| 1012 | + * passes it to the hypervisor in gntdev_map_grant_pages(). The | |
| 1013 | + * purpose of the notifier is to prevent the hypervisor pointer | |
| 1014 | + * to the PTE from going stale. | |
| 1015 | + * | |
| 1016 | + * Since this vma's mappings can't be touched without the | |
| 1017 | + * mmap_sem, and we are holding it now, there is no need for | |
| 1018 | + * the notifier_range locking pattern. | |
| 1019 | + */ | |
| 1020 | + mmu_interval_read_begin(&map->notifier); | |
| 1021 | + | |
| 1022 | 1022 | map->pages_vm_start = vma->vm_start; |
| 1023 | 1023 | err = apply_to_page_range(vma->vm_mm, vma->vm_start, |
| 1024 | 1024 | vma->vm_end - vma->vm_start, |
| @@ -94,7 +94,7 @@ static void watch_target(struct xenbus_watch *watch, · 93 unmodified lines | ||
| 94 | 94 | "%llu", &static_max) == 1)) |
| 95 | 95 | static_max >>= PAGE_SHIFT - 10; |
| 96 | 96 | else |
| 97 | − static_max = new_target; | |
| 97 | + static_max = balloon_stats.current_pages; | |
| 98 | 98 | |
| 99 | 99 | target_diff = (xen_pv_domain() || xen_initial_domain()) ? 0 |
| 100 | 100 | : static_max - balloon_stats.target_pages; |
| @@ -286,6 +286,43 @@ int xen_pcibk_config_write(struct pci_dev *dev, int offset, int size, u32 value) · 285 unmodified lines | ||
| 286 | 286 | return xen_pcibios_err_to_errno(err); |
| 287 | 287 | } |
| 288 | 288 | |
| 289 | +int xen_pcibk_get_interrupt_type(struct pci_dev *dev) | |
| 290 | +{ | |
| 291 | + int err; | |
| 292 | + u16 val; | |
| 293 | + int ret = 0; | |
| 294 | + | |
| 295 | + err = pci_read_config_word(dev, PCI_COMMAND, &val); | |
| 296 | + if (err) | |
| 297 | + return err; | |
| 298 | + if (!(val & PCI_COMMAND_INTX_DISABLE)) | |
| 299 | + ret |= INTERRUPT_TYPE_INTX; | |
| 300 | + | |
| 301 | + /* | |
| 302 | + * Do not trust dev->msi(x)_enabled here, as enabling could be done | |
| 303 | + * bypassing the pci_*msi* functions, by the qemu. | |
| 304 | + */ | |
| 305 | + if (dev->msi_cap) { | |
| 306 | + err = pci_read_config_word(dev, | |
| 307 | + dev->msi_cap + PCI_MSI_FLAGS, | |
| 308 | + &val); | |
| 309 | + if (err) | |
| 310 | + return err; | |
| 311 | + if (val & PCI_MSI_FLAGS_ENABLE) | |
| 312 | + ret |= INTERRUPT_TYPE_MSI; | |
| 313 | + } | |
| 314 | + if (dev->msix_cap) { | |
| 315 | + err = pci_read_config_word(dev, | |
| 316 | + dev->msix_cap + PCI_MSIX_FLAGS, | |
| 317 | + &val); | |
| 318 | + if (err) | |
| 319 | + return err; | |
| 320 | + if (val & PCI_MSIX_FLAGS_ENABLE) | |
| 321 | + ret |= INTERRUPT_TYPE_MSIX; | |
| 322 | + } | |
| 323 | + return ret; | |
| 324 | +} | |
| 325 | + | |
| 289 | 326 | void xen_pcibk_config_free_dyn_fields(struct pci_dev *dev) |
| 290 | 327 | { |
| 291 | 328 | struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev); |
| @@ -65,6 +65,11 @@ struct config_field_entry { · 64 unmodified lines | ||
| 65 | 65 | void *data; |
| 66 | 66 | }; |
| 67 | 67 | |
| 68 | +#define INTERRUPT_TYPE_NONE (1<<0) | |
| 69 | +#define INTERRUPT_TYPE_INTX (1<<1) | |
| 70 | +#define INTERRUPT_TYPE_MSI (1<<2) | |
| 71 | +#define INTERRUPT_TYPE_MSIX (1<<3) | |
| 72 | + | |
| 68 | 73 | extern bool xen_pcibk_permissive; |
| 69 | 74 | |
| 70 | 75 | #define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset) |
| @@ -126,4 +131,6 @@ int xen_pcibk_config_capability_init(void); · 55 unmodified lines | ||
| 126 | 131 | int xen_pcibk_config_header_add_fields(struct pci_dev *dev); |
| 127 | 132 | int xen_pcibk_config_capability_add_fields(struct pci_dev *dev); |
| 128 | 133 | |
| 134 | +int xen_pcibk_get_interrupt_type(struct pci_dev *dev); | |
| 135 | + | |
| 129 | 136 | #endif /* __XEN_PCIBACK_CONF_SPACE_H__ */ |
| @@ -189,6 +189,85 @@ static const struct config_field caplist_pm[] = { · 188 unmodified lines | ||
| 189 | 189 | {} |
| 190 | 190 | }; |
| 191 | 191 | |
| 192 | +static struct msi_msix_field_config { | |
| 193 | + u16 enable_bit; /* bit for enabling MSI/MSI-X */ | |
| 194 | + unsigned int int_type; /* interrupt type for exclusiveness check */ | |
| 195 | +} msi_field_config = { | |
| 196 | + .enable_bit = PCI_MSI_FLAGS_ENABLE, | |
| 197 | + .int_type = INTERRUPT_TYPE_MSI, | |
| 198 | +}, msix_field_config = { | |
| 199 | + .enable_bit = PCI_MSIX_FLAGS_ENABLE, | |
| 200 | + .int_type = INTERRUPT_TYPE_MSIX, | |
| 201 | +}; | |
| 202 | + | |
| 203 | +static void *msi_field_init(struct pci_dev *dev, int offset) | |
| 204 | +{ | |
| 205 | + return &msi_field_config; | |
| 206 | +} | |
| 207 | + | |
| 208 | +static void *msix_field_init(struct pci_dev *dev, int offset) | |
| 209 | +{ | |
| 210 | + return &msix_field_config; | |
| 211 | +} | |
| 212 | + | |
| 213 | +static int msi_msix_flags_write(struct pci_dev *dev, int offset, u16 new_value, | |
| 214 | + void *data) | |
| 215 | +{ | |
| 216 | + int err; | |
| 217 | + u16 old_value; | |
| 218 | + const struct msi_msix_field_config *field_config = data; | |
| 219 | + const struct xen_pcibk_dev_data *dev_data = pci_get_drvdata(dev); | |
| 220 | + | |
| 221 | + if (xen_pcibk_permissive || dev_data->permissive) | |
| 222 | + goto write; | |
| 223 | + | |
| 224 | + err = pci_read_config_word(dev, offset, &old_value); | |
| 225 | + if (err) | |
| 226 | + return err; | |
| 227 | + | |
| 228 | + if (new_value == old_value) | |
| 229 | + return 0; | |
| 230 | + | |
| 231 | + if (!dev_data->allow_interrupt_control || | |
| 232 | + (new_value ^ old_value) & ~field_config->enable_bit) | |
| 233 | + return PCIBIOS_SET_FAILED; | |
| 234 | + | |
| 235 | + if (new_value & field_config->enable_bit) { | |
| 236 | + /* don't allow enabling together with other interrupt types */ | |
| 237 | + int int_type = xen_pcibk_get_interrupt_type(dev); | |
| 238 | + | |
| 239 | + if (int_type == INTERRUPT_TYPE_NONE || | |
| 240 | + int_type == field_config->int_type) | |
| 241 | + goto write; | |
| 242 | + return PCIBIOS_SET_FAILED; | |
| 243 | + } | |
| 244 | + | |
| 245 | +write: | |
| 246 | + return pci_write_config_word(dev, offset, new_value); | |
| 247 | +} | |
| 248 | + | |
| 249 | +static const struct config_field caplist_msix[] = { | |
| 250 | + { | |
| 251 | + .offset = PCI_MSIX_FLAGS, | |
| 252 | + .size = 2, | |
| 253 | + .init = msix_field_init, | |
| 254 | + .u.w.read = xen_pcibk_read_config_word, | |
| 255 | + .u.w.write = msi_msix_flags_write, | |
| 256 | + }, | |
| 257 | + {} | |
| 258 | +}; | |
| 259 | + | |
| 260 | +static const struct config_field caplist_msi[] = { | |
| 261 | + { | |
| 262 | + .offset = PCI_MSI_FLAGS, | |
| 263 | + .size = 2, | |
| 264 | + .init = msi_field_init, | |
| 265 | + .u.w.read = xen_pcibk_read_config_word, | |
| 266 | + .u.w.write = msi_msix_flags_write, | |
| 267 | + }, | |
| 268 | + {} | |
| 269 | +}; | |
| 270 | + | |
| 192 | 271 | static struct xen_pcibk_config_capability xen_pcibk_config_capability_pm = { |
| 193 | 272 | .capability = PCI_CAP_ID_PM, |
| 194 | 273 | .fields = caplist_pm, |
| @@ -197,11 +276,21 @@ static struct xen_pcibk_config_capability xen_pcibk_config_capability_vpd = { · 2 unmodified lines | ||
| 197 | 276 | .capability = PCI_CAP_ID_VPD, |
| 198 | 277 | .fields = caplist_vpd, |
| 199 | 278 | }; |
| 279 | +static struct xen_pcibk_config_capability xen_pcibk_config_capability_msi = { | |
| 280 | + .capability = PCI_CAP_ID_MSI, | |
| 281 | + .fields = caplist_msi, | |
| 282 | +}; | |
| 283 | +static struct xen_pcibk_config_capability xen_pcibk_config_capability_msix = { | |
| 284 | + .capability = PCI_CAP_ID_MSIX, | |
| 285 | + .fields = caplist_msix, | |
| 286 | +}; | |
| 200 | 287 | |
| 201 | 288 | int xen_pcibk_config_capability_init(void) |
| 202 | 289 | { |
| 203 | 290 | register_capability(&xen_pcibk_config_capability_vpd); |
| 204 | 291 | register_capability(&xen_pcibk_config_capability_pm); |
| 292 | + register_capability(&xen_pcibk_config_capability_msi); | |
| 293 | + register_capability(&xen_pcibk_config_capability_msix); | |
| 205 | 294 | |
| 206 | 295 | return 0; |
| 207 | 296 | } |
| @@ -117,6 +117,25 @@ static int command_write(struct pci_dev *dev, int offset, u16 value, void *data) · 116 unmodified lines | ||
| 117 | 117 | pci_clear_mwi(dev); |
| 118 | 118 | } |
| 119 | 119 | |
| 120 | + if (dev_data && dev_data->allow_interrupt_control) { | |
| 121 | + if ((cmd->val ^ value) & PCI_COMMAND_INTX_DISABLE) { | |
| 122 | + if (value & PCI_COMMAND_INTX_DISABLE) { | |
| 123 | + pci_intx(dev, 0); | |
| 124 | + } else { | |
| 125 | + /* Do not allow enabling INTx together with MSI or MSI-X. */ | |
| 126 | + switch (xen_pcibk_get_interrupt_type(dev)) { | |
| 127 | + case INTERRUPT_TYPE_NONE: | |
| 128 | + pci_intx(dev, 1); | |
| 129 | + break; | |
| 130 | + case INTERRUPT_TYPE_INTX: | |
| 131 | + break; | |
| 132 | + default: | |
| 133 | + return PCIBIOS_SET_FAILED; | |
| 134 | + } | |
| 135 | + } | |
| 136 | + } | |
| 137 | + } | |
| 138 | + | |
| 120 | 139 | cmd->val = value; |
| 121 | 140 | |
| 122 | 141 | if (!xen_pcibk_permissive && (!dev_data || !dev_data->permissive)) |
| @@ -304,6 +304,8 @@ void pcistub_put_pci_dev(struct pci_dev *dev) · 303 unmodified lines | ||
| 304 | 304 | xen_pcibk_config_reset_dev(dev); |
| 305 | 305 | xen_pcibk_config_free_dyn_fields(dev); |
| 306 | 306 | |
| 307 | + dev_data->allow_interrupt_control = 0; | |
| 308 | + | |
| 307 | 309 | xen_unregister_device_domain_owner(dev); |
| 308 | 310 | |
| 309 | 311 | spin_lock_irqsave(&found_psdev->lock, flags); |
| @@ -1431,6 +1433,65 @@ static ssize_t permissive_show(struct device_driver *drv, char *buf) · 1121 unmodified lines | ||
| 1431 | 1433 | } |
| 1432 | 1434 | static DRIVER_ATTR_RW(permissive); |
| 1433 | 1435 | |
| 1436 | +static ssize_t allow_interrupt_control_store(struct device_driver *drv, | |
| 1437 | + const char *buf, size_t count) | |
| 1438 | +{ | |
| 1439 | + int domain, bus, slot, func; | |
| 1440 | + int err; | |
| 1441 | + struct pcistub_device *psdev; | |
| 1442 | + struct xen_pcibk_dev_data *dev_data; | |
| 1443 | + | |
| 1444 | + err = str_to_slot(buf, &domain, &bus, &slot, &func); | |
| 1445 | + if (err) | |
| 1446 | + goto out; | |
| 1447 | + | |
| 1448 | + psdev = pcistub_device_find(domain, bus, slot, func); | |
| 1449 | + if (!psdev) { | |
| 1450 | + err = -ENODEV; | |
| 1451 | + goto out; | |
| 1452 | + } | |
| 1453 | + | |
| 1454 | + dev_data = pci_get_drvdata(psdev->dev); | |
| 1455 | + /* the driver data for a device should never be null at this point */ | |
| 1456 | + if (!dev_data) { | |
| 1457 | + err = -ENXIO; | |
| 1458 | + goto release; | |
| 1459 | + } | |
| 1460 | + dev_data->allow_interrupt_control = 1; | |
| 1461 | +release: | |
| 1462 | + pcistub_device_put(psdev); | |
| 1463 | +out: | |
| 1464 | + if (!err) | |
| 1465 | + err = count; | |
| 1466 | + return err; | |
| 1467 | +} | |
| 1468 | + | |
| 1469 | +static ssize_t allow_interrupt_control_show(struct device_driver *drv, | |
| 1470 | + char *buf) | |
| 1471 | +{ | |
| 1472 | + struct pcistub_device *psdev; | |
| 1473 | + struct xen_pcibk_dev_data *dev_data; | |
| 1474 | + size_t count = 0; | |
| 1475 | + unsigned long flags; | |
| 1476 | + | |
| 1477 | + spin_lock_irqsave(&pcistub_devices_lock, flags); | |
| 1478 | + list_for_each_entry(psdev, &pcistub_devices, dev_list) { | |
| 1479 | + if (count >= PAGE_SIZE) | |
| 1480 | + break; | |
| 1481 | + if (!psdev->dev) | |
| 1482 | + continue; | |
| 1483 | + dev_data = pci_get_drvdata(psdev->dev); | |
| 1484 | + if (!dev_data || !dev_data->allow_interrupt_control) | |
| 1485 | + continue; | |
| 1486 | + count += | |
| 1487 | + scnprintf(buf + count, PAGE_SIZE - count, "%s\n", | |
| 1488 | + pci_name(psdev->dev)); | |
| 1489 | + } | |
| 1490 | + spin_unlock_irqrestore(&pcistub_devices_lock, flags); | |
| 1491 | + return count; | |
| 1492 | +} | |
| 1493 | +static DRIVER_ATTR_RW(allow_interrupt_control); | |
| 1494 | + | |
| 1434 | 1495 | static void pcistub_exit(void) |
| 1435 | 1496 | { |
| 1436 | 1497 | driver_remove_file(&xen_pcibk_pci_driver.driver, &driver_attr_new_slot); |
| @@ -1440,6 +1501,8 @@ static void pcistub_exit(void) · 3 unmodified lines | ||
| 1440 | 1501 | driver_remove_file(&xen_pcibk_pci_driver.driver, &driver_attr_quirks); |
| 1441 | 1502 | driver_remove_file(&xen_pcibk_pci_driver.driver, |
| 1442 | 1503 | &driver_attr_permissive); |
| 1504 | + driver_remove_file(&xen_pcibk_pci_driver.driver, | |
| 1505 | + &driver_attr_allow_interrupt_control); | |
| 1443 | 1506 | driver_remove_file(&xen_pcibk_pci_driver.driver, |
| 1444 | 1507 | &driver_attr_irq_handlers); |
| 1445 | 1508 | driver_remove_file(&xen_pcibk_pci_driver.driver, |
| @@ -1530,6 +1593,9 @@ static int __init pcistub_init(void) · 84 unmodified lines | ||
| 1530 | 1593 | if (!err) |
| 1531 | 1594 | err = driver_create_file(&xen_pcibk_pci_driver.driver, |
| 1532 | 1595 | &driver_attr_permissive); |
| 1596 | + if (!err) | |
| 1597 | + err = driver_create_file(&xen_pcibk_pci_driver.driver, | |
| 1598 | + &driver_attr_allow_interrupt_control); | |
| 1533 | 1599 | |
| 1534 | 1600 | if (!err) |
| 1535 | 1601 | err = driver_create_file(&xen_pcibk_pci_driver.driver, |
| @@ -45,6 +45,7 @@ struct xen_pcibk_dev_data { · 44 unmodified lines | ||
| 45 | 45 | struct list_head config_fields; |
| 46 | 46 | struct pci_saved_state *pci_saved_state; |
| 47 | 47 | unsigned int permissive:1; |
| 48 | + unsigned int allow_interrupt_control:1; | |
| 48 | 49 | unsigned int warned_on_write:1; |
| 49 | 50 | unsigned int enable_intx:1; |
| 50 | 51 | unsigned int isr_on:1; /* Whether the IRQ handler is installed. */ |
| @@ -239,7 +239,9 @@ int xenbus_dev_probe(struct device *_dev) · 238 unmodified lines | ||
| 239 | 239 | goto fail; |
| 240 | 240 | } |
| 241 | 241 | |
| 242 | + spin_lock(&dev->reclaim_lock); | |
| 242 | 243 | err = drv->probe(dev, id); |
| 244 | + spin_unlock(&dev->reclaim_lock); | |
| 243 | 245 | if (err) |
| 244 | 246 | goto fail_put; |
| 245 | 247 | |
| @@ -268,8 +270,11 @@ int xenbus_dev_remove(struct device *_dev) · 22 unmodified lines | ||
| 268 | 270 | |
| 269 | 271 | free_otherend_watch(dev); |
| 270 | 272 | |
| 271 | − if (drv->remove) | |
| 273 | + if (drv->remove) { | |
| 274 | + spin_lock(&dev->reclaim_lock); | |
| 272 | 275 | drv->remove(dev); |
| 276 | + spin_unlock(&dev->reclaim_lock); | |
| 277 | + } | |
| 273 | 278 | |
| 274 | 279 | module_put(drv->driver.owner); |
| 275 | 280 | |
| @@ -468,6 +473,7 @@ int xenbus_probe_node(struct xen_bus_type *bus, · 192 unmodified lines | ||
| 468 | 473 | goto fail; |
| 469 | 474 | |
| 470 | 475 | dev_set_name(&xendev->dev, "%s", devname); |
| 476 | + spin_lock_init(&xendev->reclaim_lock); | |
| 471 | 477 | |
| 472 | 478 | /* Register with generic device framework. */ |
| 473 | 479 | err = device_register(&xendev->dev); |
| @@ -247,6 +247,41 @@ static int backend_probe_and_watch(struct notifier_block *notifier, · 246 unmodified lines | ||
| 247 | 247 | return NOTIFY_DONE; |
| 248 | 248 | } |
| 249 | 249 | |
| 250 | +static int backend_reclaim_memory(struct device *dev, void *data) | |
| 251 | +{ | |
| 252 | + const struct xenbus_driver *drv; | |
| 253 | + struct xenbus_device *xdev; | |
| 254 | + | |
| 255 | + if (!dev->driver) | |
| 256 | + return 0; | |
| 257 | + drv = to_xenbus_driver(dev->driver); | |
| 258 | + if (drv && drv->reclaim_memory) { | |
| 259 | + xdev = to_xenbus_device(dev); | |
| 260 | + if (!spin_trylock(&xdev->reclaim_lock)) | |
| 261 | + return 0; | |
| 262 | + drv->reclaim_memory(xdev); | |
| 263 | + spin_unlock(&xdev->reclaim_lock); | |
| 264 | + } | |
| 265 | + return 0; | |
| 266 | +} | |
| 267 | + | |
| 268 | +/* | |
| 269 | + * Returns 0 always because we are using shrinker to only detect memory | |
| 270 | + * pressure. | |
| 271 | + */ | |
| 272 | +static unsigned long backend_shrink_memory_count(struct shrinker *shrinker, | |
| 273 | + struct shrink_control *sc) | |
| 274 | +{ | |
| 275 | + bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, | |
| 276 | + backend_reclaim_memory); | |
| 277 | + return 0; | |
| 278 | +} | |
| 279 | + | |
| 280 | +static struct shrinker backend_memory_shrinker = { | |
| 281 | + .count_objects = backend_shrink_memory_count, | |
| 282 | + .seeks = DEFAULT_SEEKS, | |
| 283 | +}; | |
| 284 | + | |
| 250 | 285 | static int __init xenbus_probe_backend_init(void) |
| 251 | 286 | { |
| 252 | 287 | static struct notifier_block xenstore_notifier = { |
| @@ -263,6 +298,9 @@ static int __init xenbus_probe_backend_init(void) · 10 unmodified lines | ||
| 263 | 298 | |
| 264 | 299 | register_xenstore_notifier(&xenstore_notifier); |
| 265 | 300 | |
| 301 | + if (register_shrinker(&backend_memory_shrinker)) | |
| 302 | + pr_warn("shrinker registration failed\n"); | |
| 303 | + | |
| 266 | 304 | return 0; |
| 267 | 305 | } |
| 268 | 306 | subsys_initcall(xenbus_probe_backend_init); |
| @@ -76,6 +76,7 @@ struct xenbus_device { · 75 unmodified lines | ||
| 76 | 76 | enum xenbus_state state; |
| 77 | 77 | struct completion down; |
| 78 | 78 | struct work_struct work; |
| 79 | + spinlock_t reclaim_lock; | |
| 79 | 80 | }; |
| 80 | 81 | |
| 81 | 82 | static inline struct xenbus_device *to_xenbus_device(struct device *dev) |
| @@ -105,6 +106,7 @@ struct xenbus_driver { · 23 unmodified lines | ||
| 105 | 106 | struct device_driver driver; |
| 106 | 107 | int (*read_otherend_details)(struct xenbus_device *dev); |
| 107 | 108 | int (*is_ready)(struct xenbus_device *dev); |
| 109 | + void (*reclaim_memory)(struct xenbus_device *dev); | |
| 108 | 110 | }; |
| 109 | 111 | |
| 110 | 112 | static inline struct xenbus_driver *to_xenbus_driver(struct device_driver *drv) |