Merge tag 'hyperv-fixes-signed-20211007' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 7 Oct 2021 16:44:48 +0000 (09:44 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 7 Oct 2021 16:44:48 +0000 (09:44 -0700)
Pull hyperv fixes from Wei Liu:

 - Replace uuid.h with types.h in a header (Andy Shevchenko)

 - Avoid sleeping in atomic context in PCI driver (Long Li)

 - Avoid sending IPI to self when it shouldn't (Vitaly Kuznetsov)

* tag 'hyperv-fixes-signed-20211007' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux:
  x86/hyperv: Avoid erroneously sending IPI to 'self'
  hyper-v: Replace uuid.h with types.h
  PCI: hv: Fix sleep while in non-sleep context when removing child devices from the bus

1  2 
drivers/pci/controller/pci-hyperv.c

@@@ -40,7 -40,6 +40,7 @@@
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/pci.h>
 +#include <linux/pci-ecam.h>
  #include <linux/delay.h>
  #include <linux/semaphore.h>
  #include <linux/irqdomain.h>
@@@ -65,7 -64,6 +65,7 @@@ enum pci_protocol_version_t 
        PCI_PROTOCOL_VERSION_1_1 = PCI_MAKE_VERSION(1, 1),      /* Win10 */
        PCI_PROTOCOL_VERSION_1_2 = PCI_MAKE_VERSION(1, 2),      /* RS1 */
        PCI_PROTOCOL_VERSION_1_3 = PCI_MAKE_VERSION(1, 3),      /* Vibranium */
 +      PCI_PROTOCOL_VERSION_1_4 = PCI_MAKE_VERSION(1, 4),      /* WS2022 */
  };
  
  #define CPU_AFFINITY_ALL      -1ULL
@@@ -75,7 -73,6 +75,7 @@@
   * first.
   */
  static enum pci_protocol_version_t pci_protocol_versions[] = {
 +      PCI_PROTOCOL_VERSION_1_4,
        PCI_PROTOCOL_VERSION_1_3,
        PCI_PROTOCOL_VERSION_1_2,
        PCI_PROTOCOL_VERSION_1_1,
@@@ -125,8 -122,6 +125,8 @@@ enum pci_message_type 
        PCI_CREATE_INTERRUPT_MESSAGE2   = PCI_MESSAGE_BASE + 0x17,
        PCI_DELETE_INTERRUPT_MESSAGE2   = PCI_MESSAGE_BASE + 0x18, /* unused */
        PCI_BUS_RELATIONS2              = PCI_MESSAGE_BASE + 0x19,
 +      PCI_RESOURCES_ASSIGNED3         = PCI_MESSAGE_BASE + 0x1A,
 +      PCI_CREATE_INTERRUPT_MESSAGE3   = PCI_MESSAGE_BASE + 0x1B,
        PCI_MESSAGE_MAXIMUM
  };
  
@@@ -240,21 -235,6 +240,21 @@@ struct hv_msi_desc2 
        u16     processor_array[32];
  } __packed;
  
 +/*
 + * struct hv_msi_desc3 - 1.3 version of hv_msi_desc
 + *    Everything is the same as in 'hv_msi_desc2' except that the size of the
 + *    'vector' field is larger to support bigger vector values. For ex: LPI
 + *    vectors on ARM.
 + */
 +struct hv_msi_desc3 {
 +      u32     vector;
 +      u8      delivery_mode;
 +      u8      reserved;
 +      u16     vector_count;
 +      u16     processor_count;
 +      u16     processor_array[32];
 +} __packed;
 +
  /**
   * struct tran_int_desc
   * @reserved:         unused, padding
@@@ -403,12 -383,6 +403,12 @@@ struct pci_create_interrupt2 
        struct hv_msi_desc2 int_desc;
  } __packed;
  
 +struct pci_create_interrupt3 {
 +      struct pci_message message_type;
 +      union win_slot_encoding wslot;
 +      struct hv_msi_desc3 int_desc;
 +} __packed;
 +
  struct pci_delete_interrupt {
        struct pci_message message_type;
        union win_slot_encoding wslot;
@@@ -474,13 -448,7 +474,13 @@@ enum hv_pcibus_state 
  };
  
  struct hv_pcibus_device {
 +#ifdef CONFIG_X86
        struct pci_sysdata sysdata;
 +#elif defined(CONFIG_ARM64)
 +      struct pci_config_window sysdata;
 +#endif
 +      struct pci_host_bridge *bridge;
 +      struct fwnode_handle *fwnode;
        /* Protocol version negotiated with the host */
        enum pci_protocol_version_t protocol_version;
        enum hv_pcibus_state state;
        spinlock_t device_list_lock;    /* Protect lists below */
        void __iomem *cfg_addr;
  
 -      struct list_head resources_for_children;
 -
        struct list_head children;
        struct list_head dr_list;
  
@@@ -1358,15 -1328,6 +1358,15 @@@ static u32 hv_compose_msi_req_v1
        return sizeof(*int_pkt);
  }
  
 +/*
 + * Create MSI w/ dummy vCPU set targeting just one vCPU, overwritten
 + * by subsequent retarget in hv_irq_unmask().
 + */
 +static int hv_compose_msi_req_get_cpu(struct cpumask *affinity)
 +{
 +      return cpumask_first_and(affinity, cpu_online_mask);
 +}
 +
  static u32 hv_compose_msi_req_v2(
        struct pci_create_interrupt2 *int_pkt, struct cpumask *affinity,
        u32 slot, u8 vector)
        int_pkt->int_desc.vector = vector;
        int_pkt->int_desc.vector_count = 1;
        int_pkt->int_desc.delivery_mode = APIC_DELIVERY_MODE_FIXED;
 +      cpu = hv_compose_msi_req_get_cpu(affinity);
 +      int_pkt->int_desc.processor_array[0] =
 +              hv_cpu_number_to_vp_number(cpu);
 +      int_pkt->int_desc.processor_count = 1;
  
 -      /*
 -       * Create MSI w/ dummy vCPU set targeting just one vCPU, overwritten
 -       * by subsequent retarget in hv_irq_unmask().
 -       */
 -      cpu = cpumask_first_and(affinity, cpu_online_mask);
 +      return sizeof(*int_pkt);
 +}
 +
 +static u32 hv_compose_msi_req_v3(
 +      struct pci_create_interrupt3 *int_pkt, struct cpumask *affinity,
 +      u32 slot, u32 vector)
 +{
 +      int cpu;
 +
 +      int_pkt->message_type.type = PCI_CREATE_INTERRUPT_MESSAGE3;
 +      int_pkt->wslot.slot = slot;
 +      int_pkt->int_desc.vector = vector;
 +      int_pkt->int_desc.reserved = 0;
 +      int_pkt->int_desc.vector_count = 1;
 +      int_pkt->int_desc.delivery_mode = APIC_DELIVERY_MODE_FIXED;
 +      cpu = hv_compose_msi_req_get_cpu(affinity);
        int_pkt->int_desc.processor_array[0] =
                hv_cpu_number_to_vp_number(cpu);
        int_pkt->int_desc.processor_count = 1;
@@@ -1433,7 -1379,6 +1433,7 @@@ static void hv_compose_msi_msg(struct i
                union {
                        struct pci_create_interrupt v1;
                        struct pci_create_interrupt2 v2;
 +                      struct pci_create_interrupt3 v3;
                } int_pkts;
        } __packed ctxt;
  
                                        cfg->vector);
                break;
  
 +      case PCI_PROTOCOL_VERSION_1_4:
 +              size = hv_compose_msi_req_v3(&ctxt.int_pkts.v3,
 +                                      dest,
 +                                      hpdev->desc.win_slot.slot,
 +                                      cfg->vector);
 +              break;
 +
        default:
                /* As we only negotiate protocol versions known to this driver,
                 * this path should never hit. However, this is it not a hot
@@@ -1628,7 -1566,7 +1628,7 @@@ static int hv_pcie_init_irq_domain(stru
        hbus->msi_info.handler = handle_edge_irq;
        hbus->msi_info.handler_name = "edge";
        hbus->msi_info.data = hbus;
 -      hbus->irq_domain = pci_msi_create_irq_domain(hbus->sysdata.fwnode,
 +      hbus->irq_domain = pci_msi_create_irq_domain(hbus->fwnode,
                                                     &hbus->msi_info,
                                                     x86_vector_domain);
        if (!hbus->irq_domain) {
                return -ENODEV;
        }
  
 +      dev_set_msi_domain(&hbus->bridge->dev, hbus->irq_domain);
 +
        return 0;
  }
  
@@@ -1861,7 -1797,7 +1861,7 @@@ static void hv_pci_assign_slots(struct 
  
                slot_nr = PCI_SLOT(wslot_to_devfn(hpdev->desc.win_slot.slot));
                snprintf(name, SLOT_NAME_SIZE, "%u", hpdev->desc.ser);
 -              hpdev->pci_slot = pci_create_slot(hbus->pci_bus, slot_nr,
 +              hpdev->pci_slot = pci_create_slot(hbus->bridge->bus, slot_nr,
                                          name, NULL);
                if (IS_ERR(hpdev->pci_slot)) {
                        pr_warn("pci_create slot %s failed\n", name);
@@@ -1891,7 -1827,7 +1891,7 @@@ static void hv_pci_remove_slots(struct 
  static void hv_pci_assign_numa_node(struct hv_pcibus_device *hbus)
  {
        struct pci_dev *dev;
 -      struct pci_bus *bus = hbus->pci_bus;
 +      struct pci_bus *bus = hbus->bridge->bus;
        struct hv_pci_dev *hv_dev;
  
        list_for_each_entry(dev, &bus->devices, bus_list) {
   */
  static int create_root_hv_pci_bus(struct hv_pcibus_device *hbus)
  {
 -      /* Register the device */
 -      hbus->pci_bus = pci_create_root_bus(&hbus->hdev->device,
 -                                          0, /* bus number is always zero */
 -                                          &hv_pcifront_ops,
 -                                          &hbus->sysdata,
 -                                          &hbus->resources_for_children);
 -      if (!hbus->pci_bus)
 -              return -ENODEV;
 +      int error;
 +      struct pci_host_bridge *bridge = hbus->bridge;
 +
 +      bridge->dev.parent = &hbus->hdev->device;
 +      bridge->sysdata = &hbus->sysdata;
 +      bridge->ops = &hv_pcifront_ops;
 +
 +      error = pci_scan_root_bus_bridge(bridge);
 +      if (error)
 +              return error;
  
        pci_lock_rescan_remove();
 -      pci_scan_child_bus(hbus->pci_bus);
        hv_pci_assign_numa_node(hbus);
 -      pci_bus_assign_resources(hbus->pci_bus);
 +      pci_bus_assign_resources(bridge->bus);
        hv_pci_assign_slots(hbus);
 -      pci_bus_add_devices(hbus->pci_bus);
 +      pci_bus_add_devices(bridge->bus);
        pci_unlock_rescan_remove();
        hbus->state = hv_pcibus_installed;
        return 0;
@@@ -2192,7 -2127,7 +2192,7 @@@ static void pci_devices_present_work(st
                 * because there may have been changes.
                 */
                pci_lock_rescan_remove();
 -              pci_scan_child_bus(hbus->pci_bus);
 +              pci_scan_child_bus(hbus->bridge->bus);
                hv_pci_assign_numa_node(hbus);
                hv_pci_assign_slots(hbus);
                pci_unlock_rescan_remove();
@@@ -2360,11 -2295,11 +2360,11 @@@ static void hv_eject_device_work(struc
        /*
         * Ejection can come before or after the PCI bus has been set up, so
         * attempt to find it and tear down the bus state, if it exists.  This
 -       * must be done without constructs like pci_domain_nr(hbus->pci_bus)
 -       * because hbus->pci_bus may not exist yet.
 +       * must be done without constructs like pci_domain_nr(hbus->bridge->bus)
 +       * because hbus->bridge->bus may not exist yet.
         */
        wslot = wslot_to_devfn(hpdev->desc.win_slot.slot);
 -      pdev = pci_get_domain_bus_and_slot(hbus->sysdata.domain, 0, wslot);
 +      pdev = pci_get_domain_bus_and_slot(hbus->bridge->domain_nr, 0, wslot);
        if (pdev) {
                pci_lock_rescan_remove();
                pci_stop_and_remove_bus_device(pdev);
@@@ -2727,7 -2662,8 +2727,7 @@@ static int hv_pci_allocate_bridge_windo
                /* Modify this resource to become a bridge window. */
                hbus->low_mmio_res->flags |= IORESOURCE_WINDOW;
                hbus->low_mmio_res->flags &= ~IORESOURCE_BUSY;
 -              pci_add_resource(&hbus->resources_for_children,
 -                               hbus->low_mmio_res);
 +              pci_add_resource(&hbus->bridge->windows, hbus->low_mmio_res);
        }
  
        if (hbus->high_mmio_space) {
                /* Modify this resource to become a bridge window. */
                hbus->high_mmio_res->flags |= IORESOURCE_WINDOW;
                hbus->high_mmio_res->flags &= ~IORESOURCE_BUSY;
 -              pci_add_resource(&hbus->resources_for_children,
 -                               hbus->high_mmio_res);
 +              pci_add_resource(&hbus->bridge->windows, hbus->high_mmio_res);
        }
  
        return 0;
@@@ -3065,7 -3002,6 +3065,7 @@@ static void hv_put_dom_num(u16 dom
  static int hv_pci_probe(struct hv_device *hdev,
                        const struct hv_vmbus_device_id *dev_id)
  {
 +      struct pci_host_bridge *bridge;
        struct hv_pcibus_device *hbus;
        u16 dom_req, dom;
        char *name;
         */
        BUILD_BUG_ON(sizeof(*hbus) > HV_HYP_PAGE_SIZE);
  
 +      bridge = devm_pci_alloc_host_bridge(&hdev->device, 0);
 +      if (!bridge)
 +              return -ENOMEM;
 +
        /*
         * With the recent 59bb47985c1d ("mm, sl[aou]b: guarantee natural
         * alignment for kmalloc(power-of-two)"), kzalloc() is able to allocate
        hbus = kzalloc(HV_HYP_PAGE_SIZE, GFP_KERNEL);
        if (!hbus)
                return -ENOMEM;
 +
 +      hbus->bridge = bridge;
        hbus->state = hv_pcibus_init;
        hbus->wslot_res_allocated = -1;
  
                         "PCI dom# 0x%hx has collision, using 0x%hx",
                         dom_req, dom);
  
 +      hbus->bridge->domain_nr = dom;
 +#ifdef CONFIG_X86
        hbus->sysdata.domain = dom;
 +#endif
  
        hbus->hdev = hdev;
        INIT_LIST_HEAD(&hbus->children);
        INIT_LIST_HEAD(&hbus->dr_list);
 -      INIT_LIST_HEAD(&hbus->resources_for_children);
        spin_lock_init(&hbus->config_lock);
        spin_lock_init(&hbus->device_list_lock);
        spin_lock_init(&hbus->retarget_msi_interrupt_lock);
        hbus->wq = alloc_ordered_workqueue("hv_pci_%x", 0,
 -                                         hbus->sysdata.domain);
 +                                         hbus->bridge->domain_nr);
        if (!hbus->wq) {
                ret = -ENOMEM;
                goto free_dom;
                goto unmap;
        }
  
 -      hbus->sysdata.fwnode = irq_domain_alloc_named_fwnode(name);
 +      hbus->fwnode = irq_domain_alloc_named_fwnode(name);
        kfree(name);
 -      if (!hbus->sysdata.fwnode) {
 +      if (!hbus->fwnode) {
                ret = -ENOMEM;
                goto unmap;
        }
@@@ -3265,7 -3193,7 +3265,7 @@@ exit_d0
  free_irq_domain:
        irq_domain_remove(hbus->irq_domain);
  free_fwnode:
 -      irq_domain_free_fwnode(hbus->sysdata.fwnode);
 +      irq_domain_free_fwnode(hbus->fwnode);
  unmap:
        iounmap(hbus->cfg_addr);
  free_config:
@@@ -3275,7 -3203,7 +3275,7 @@@ close
  destroy_wq:
        destroy_workqueue(hbus->wq);
  free_dom:
 -      hv_put_dom_num(hbus->sysdata.domain);
 +      hv_put_dom_num(hbus->bridge->domain_nr);
  free_bus:
        kfree(hbus);
        return ret;
@@@ -3301,9 -3229,17 +3301,17 @@@ static int hv_pci_bus_exit(struct hv_de
                return 0;
  
        if (!keep_devs) {
-               /* Delete any children which might still exist. */
+               struct list_head removed;
+               /* Move all present children to the list on stack */
+               INIT_LIST_HEAD(&removed);
                spin_lock_irqsave(&hbus->device_list_lock, flags);
-               list_for_each_entry_safe(hpdev, tmp, &hbus->children, list_entry) {
+               list_for_each_entry_safe(hpdev, tmp, &hbus->children, list_entry)
+                       list_move_tail(&hpdev->list_entry, &removed);
+               spin_unlock_irqrestore(&hbus->device_list_lock, flags);
+               /* Remove all children in the list */
+               list_for_each_entry_safe(hpdev, tmp, &removed, list_entry) {
                        list_del(&hpdev->list_entry);
                        if (hpdev->pci_slot)
                                pci_destroy_slot(hpdev->pci_slot);
                        put_pcichild(hpdev);
                        put_pcichild(hpdev);
                }
-               spin_unlock_irqrestore(&hbus->device_list_lock, flags);
        }
  
        ret = hv_send_resources_released(hdev);
@@@ -3367,9 -3302,9 +3374,9 @@@ static int hv_pci_remove(struct hv_devi
  
                /* Remove the bus from PCI's point of view. */
                pci_lock_rescan_remove();
 -              pci_stop_root_bus(hbus->pci_bus);
 +              pci_stop_root_bus(hbus->bridge->bus);
                hv_pci_remove_slots(hbus);
 -              pci_remove_root_bus(hbus->pci_bus);
 +              pci_remove_root_bus(hbus->bridge->bus);
                pci_unlock_rescan_remove();
        }
  
  
        iounmap(hbus->cfg_addr);
        hv_free_config_window(hbus);
 -      pci_free_resource_list(&hbus->resources_for_children);
        hv_pci_free_bridge_windows(hbus);
        irq_domain_remove(hbus->irq_domain);
 -      irq_domain_free_fwnode(hbus->sysdata.fwnode);
 +      irq_domain_free_fwnode(hbus->fwnode);
  
 -      hv_put_dom_num(hbus->sysdata.domain);
 +      hv_put_dom_num(hbus->bridge->domain_nr);
  
        kfree(hbus);
        return ret;
@@@ -3461,7 -3397,7 +3468,7 @@@ static int hv_pci_restore_msi_msg(struc
   */
  static void hv_pci_restore_msi_state(struct hv_pcibus_device *hbus)
  {
 -      pci_walk_bus(hbus->pci_bus, hv_pci_restore_msi_msg, NULL);
 +      pci_walk_bus(hbus->bridge->bus, hv_pci_restore_msi_msg, NULL);
  }
  
  static int hv_pci_resume(struct hv_device *hdev)