^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * PCI Hotplug Driver for PowerPC PowerNV platform.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright Gavin Shan, IBM Corporation 2016.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/libfdt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/pci_hotplug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <asm/opal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/pnv-pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <asm/ppc-pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define DRIVER_VERSION "0.1"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define DRIVER_AUTHOR "Gavin Shan, IBM Corporation"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define DRIVER_DESC "PowerPC PowerNV PCI Hotplug Driver"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define SLOT_WARN(sl, x...) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) ((sl)->pdev ? pci_warn((sl)->pdev, x) : dev_warn(&(sl)->bus->dev, x))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct pnv_php_event {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) bool added;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct pnv_php_slot *php_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct work_struct work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) static LIST_HEAD(pnv_php_slot_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) static DEFINE_SPINLOCK(pnv_php_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static void pnv_php_register(struct device_node *dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static void pnv_php_unregister_one(struct device_node *dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static void pnv_php_unregister(struct device_node *dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static void pnv_php_disable_irq(struct pnv_php_slot *php_slot,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) bool disable_device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct pci_dev *pdev = php_slot->pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) int irq = php_slot->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) u16 ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (php_slot->irq > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) ctrl &= ~(PCI_EXP_SLTCTL_HPIE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) PCI_EXP_SLTCTL_PDCE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) PCI_EXP_SLTCTL_DLLSCE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) free_irq(php_slot->irq, php_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) php_slot->irq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (php_slot->wq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) destroy_workqueue(php_slot->wq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) php_slot->wq = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (disable_device || irq > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (pdev->msix_enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) pci_disable_msix(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) else if (pdev->msi_enabled)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) pci_disable_msi(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) pci_disable_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) static void pnv_php_free_slot(struct kref *kref)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct pnv_php_slot *php_slot = container_of(kref,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct pnv_php_slot, kref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) WARN_ON(!list_empty(&php_slot->children));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) pnv_php_disable_irq(php_slot, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) kfree(php_slot->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) kfree(php_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static inline void pnv_php_put_slot(struct pnv_php_slot *php_slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (!php_slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) kref_put(&php_slot->kref, pnv_php_free_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static struct pnv_php_slot *pnv_php_match(struct device_node *dn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct pnv_php_slot *php_slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct pnv_php_slot *target, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (php_slot->dn == dn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) kref_get(&php_slot->kref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return php_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) list_for_each_entry(tmp, &php_slot->children, link) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) target = pnv_php_match(dn, tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (target)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return target;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct pnv_php_slot *pnv_php_find_slot(struct device_node *dn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct pnv_php_slot *php_slot, *tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) spin_lock_irqsave(&pnv_php_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) list_for_each_entry(tmp, &pnv_php_slot_list, link) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) php_slot = pnv_php_match(dn, tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (php_slot) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) spin_unlock_irqrestore(&pnv_php_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) return php_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) spin_unlock_irqrestore(&pnv_php_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) EXPORT_SYMBOL_GPL(pnv_php_find_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) * Remove pdn for all children of the indicated device node.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * The function should remove pdn in a depth-first manner.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static void pnv_php_rmv_pdns(struct device_node *dn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct device_node *child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) for_each_child_of_node(dn, child) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) pnv_php_rmv_pdns(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) pci_remove_device_node_info(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) * Detach all child nodes of the indicated device nodes. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) * function should handle device nodes in depth-first manner.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) * We should not invoke of_node_release() as the memory for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) * individual device node is part of large memory block. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) * large block is allocated from memblock (system bootup) or
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) * kmalloc() when unflattening the device tree by OF changeset.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) * We can not free the large block allocated from memblock. For
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) * later case, it should be released at once.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) static void pnv_php_detach_device_nodes(struct device_node *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) struct device_node *dn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) for_each_child_of_node(parent, dn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) pnv_php_detach_device_nodes(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) of_node_put(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) of_detach_node(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) static void pnv_php_rmv_devtree(struct pnv_php_slot *php_slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) pnv_php_rmv_pdns(php_slot->dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * Decrease the refcount if the device nodes were created
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) * through OF changeset before detaching them.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) if (php_slot->fdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) of_changeset_destroy(&php_slot->ocs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) pnv_php_detach_device_nodes(php_slot->dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (php_slot->fdt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) kfree(php_slot->dt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) kfree(php_slot->fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) php_slot->dt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) php_slot->dn->child = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) php_slot->fdt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * As the nodes in OF changeset are applied in reverse order, we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * need revert the nodes in advance so that we have correct node
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * order after the changeset is applied.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static void pnv_php_reverse_nodes(struct device_node *parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) struct device_node *child, *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) /* In-depth first */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) for_each_child_of_node(parent, child)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) pnv_php_reverse_nodes(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) /* Reverse the nodes in the child list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) child = parent->child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) parent->child = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) while (child) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) next = child->sibling;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) child->sibling = parent->child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) parent->child = child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) child = next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) static int pnv_php_populate_changeset(struct of_changeset *ocs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) struct device_node *dn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) struct device_node *child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) for_each_child_of_node(dn, child) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) ret = of_changeset_attach_node(ocs, child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) of_node_put(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) ret = pnv_php_populate_changeset(ocs, child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) of_node_put(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) static void *pnv_php_add_one_pdn(struct device_node *dn, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) struct pci_controller *hose = (struct pci_controller *)data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) struct pci_dn *pdn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) pdn = pci_add_device_node_info(hose, dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (!pdn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) static void pnv_php_add_pdns(struct pnv_php_slot *slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) struct pci_controller *hose = pci_bus_to_host(slot->bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) pci_traverse_device_nodes(slot->dn, pnv_php_add_one_pdn, hose);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) static int pnv_php_add_devtree(struct pnv_php_slot *php_slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) void *fdt, *fdt1, *dt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) /* We don't know the FDT blob size. We try to get it through
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * maximal memory chunk and then copy it to another chunk that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * fits the real size.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) fdt1 = kzalloc(0x10000, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) if (!fdt1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) ret = pnv_pci_get_device_tree(php_slot->dn->phandle, fdt1, 0x10000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) SLOT_WARN(php_slot, "Error %d getting FDT blob\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) goto free_fdt1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) fdt = kmemdup(fdt1, fdt_totalsize(fdt1), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (!fdt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) goto free_fdt1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) /* Unflatten device tree blob */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) dt = of_fdt_unflatten_tree(fdt, php_slot->dn, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (!dt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) SLOT_WARN(php_slot, "Cannot unflatten FDT\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) goto free_fdt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /* Initialize and apply the changeset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) of_changeset_init(&php_slot->ocs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) pnv_php_reverse_nodes(php_slot->dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) ret = pnv_php_populate_changeset(&php_slot->ocs, php_slot->dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) pnv_php_reverse_nodes(php_slot->dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) SLOT_WARN(php_slot, "Error %d populating changeset\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) goto free_dt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) php_slot->dn->child = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) ret = of_changeset_apply(&php_slot->ocs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) SLOT_WARN(php_slot, "Error %d applying changeset\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) goto destroy_changeset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) /* Add device node firmware data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) pnv_php_add_pdns(php_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) php_slot->fdt = fdt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) php_slot->dt = dt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) kfree(fdt1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) destroy_changeset:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) of_changeset_destroy(&php_slot->ocs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) free_dt:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) kfree(dt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) php_slot->dn->child = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) free_fdt:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) kfree(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) free_fdt1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) kfree(fdt1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) static inline struct pnv_php_slot *to_pnv_php_slot(struct hotplug_slot *slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) return container_of(slot, struct pnv_php_slot, slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) int pnv_php_set_slot_power_state(struct hotplug_slot *slot,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) uint8_t state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) struct opal_msg msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) ret = pnv_pci_set_power_state(php_slot->id, state, &msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) if (ret > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (be64_to_cpu(msg.params[1]) != php_slot->dn->phandle ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) be64_to_cpu(msg.params[2]) != state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) SLOT_WARN(php_slot, "Wrong msg (%lld, %lld, %lld)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) be64_to_cpu(msg.params[1]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) be64_to_cpu(msg.params[2]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) be64_to_cpu(msg.params[3]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) return -ENOMSG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (be64_to_cpu(msg.params[3]) != OPAL_SUCCESS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) } else if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) goto error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) if (state == OPAL_PCI_SLOT_POWER_OFF || state == OPAL_PCI_SLOT_OFFLINE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) pnv_php_rmv_devtree(php_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) ret = pnv_php_add_devtree(php_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) error:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) SLOT_WARN(php_slot, "Error %d powering %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) ret, (state == OPAL_PCI_SLOT_POWER_ON) ? "on" : "off");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) EXPORT_SYMBOL_GPL(pnv_php_set_slot_power_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) static int pnv_php_get_power_state(struct hotplug_slot *slot, u8 *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) uint8_t power_state = OPAL_PCI_SLOT_POWER_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) * Retrieve power status from firmware. If we fail
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) * getting that, the power status fails back to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) * be on.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) ret = pnv_pci_get_power_state(php_slot->id, &power_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) SLOT_WARN(php_slot, "Error %d getting power status\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) *state = power_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) static int pnv_php_get_adapter_state(struct hotplug_slot *slot, u8 *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) uint8_t presence = OPAL_PCI_SLOT_EMPTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) * Retrieve presence status from firmware. If we can't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) * get that, it will fail back to be empty.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) ret = pnv_pci_get_presence_state(php_slot->id, &presence);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (ret >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) *state = presence;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) SLOT_WARN(php_slot, "Error %d getting presence\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) static int pnv_php_get_attention_state(struct hotplug_slot *slot, u8 *state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) *state = php_slot->attention_state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) static int pnv_php_set_attention_state(struct hotplug_slot *slot, u8 state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) struct pci_dev *bridge = php_slot->pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) u16 new, mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) php_slot->attention_state = state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) if (!bridge)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) mask = PCI_EXP_SLTCTL_AIC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) if (state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) new = PCI_EXP_SLTCTL_ATTN_IND_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) new = PCI_EXP_SLTCTL_ATTN_IND_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) pcie_capability_clear_and_set_word(bridge, PCI_EXP_SLTCTL, mask, new);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) static int pnv_php_enable(struct pnv_php_slot *php_slot, bool rescan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) struct hotplug_slot *slot = &php_slot->slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) uint8_t presence = OPAL_PCI_SLOT_EMPTY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) uint8_t power_status = OPAL_PCI_SLOT_POWER_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) /* Check if the slot has been configured */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) if (php_slot->state != PNV_PHP_STATE_REGISTERED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) /* Retrieve slot presence status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) ret = pnv_php_get_adapter_state(slot, &presence);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) * Proceed if there have nothing behind the slot. However,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) * we should leave the slot in registered state at the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) * beginning. Otherwise, the PCI devices inserted afterwards
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) * won't be probed and populated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) if (presence == OPAL_PCI_SLOT_EMPTY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) if (!php_slot->power_state_check) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) php_slot->power_state_check = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) goto scan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) * If the power supply to the slot is off, we can't detect
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) * adapter presence state. That means we have to turn the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) * slot on before going to probe slot's presence state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) * On the first time, we don't change the power status to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) * boost system boot with assumption that the firmware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) * supplies consistent slot power status: empty slot always
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) * has its power off and non-empty slot has its power on.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) if (!php_slot->power_state_check) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) php_slot->power_state_check = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) ret = pnv_php_get_power_state(slot, &power_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (power_status != OPAL_PCI_SLOT_POWER_ON)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) /* Check the power status. Scan the slot if it is already on */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) ret = pnv_php_get_power_state(slot, &power_status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) if (power_status == OPAL_PCI_SLOT_POWER_ON)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) goto scan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) /* Power is off, turn it on and then scan the slot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) ret = pnv_php_set_slot_power_state(slot, OPAL_PCI_SLOT_POWER_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) scan:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) if (presence == OPAL_PCI_SLOT_PRESENT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) if (rescan) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) pci_lock_rescan_remove();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) pci_hp_add_devices(php_slot->bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) pci_unlock_rescan_remove();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) /* Rescan for child hotpluggable slots */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) php_slot->state = PNV_PHP_STATE_POPULATED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) if (rescan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) pnv_php_register(php_slot->dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) php_slot->state = PNV_PHP_STATE_POPULATED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) static int pnv_php_reset_slot(struct hotplug_slot *slot, int probe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) struct pci_dev *bridge = php_slot->pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) uint16_t sts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) * The CAPI folks want pnv_php to drive OpenCAPI slots
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) * which don't have a bridge. Only claim to support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) * reset_slot() if we have a bridge device (for now...)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (probe)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) return !bridge;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) /* mask our interrupt while resetting the bridge */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if (php_slot->irq > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) disable_irq(php_slot->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) pci_bridge_secondary_bus_reset(bridge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) /* clear any state changes that happened due to the reset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) pcie_capability_read_word(php_slot->pdev, PCI_EXP_SLTSTA, &sts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) sts &= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) pcie_capability_write_word(php_slot->pdev, PCI_EXP_SLTSTA, sts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) if (php_slot->irq > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) enable_irq(php_slot->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) static int pnv_php_enable_slot(struct hotplug_slot *slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) return pnv_php_enable(php_slot, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) static int pnv_php_disable_slot(struct hotplug_slot *slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) struct pnv_php_slot *php_slot = to_pnv_php_slot(slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) * Allow to disable a slot already in the registered state to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) * cover cases where the slot couldn't be enabled and never
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) * reached the populated state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) if (php_slot->state != PNV_PHP_STATE_POPULATED &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) php_slot->state != PNV_PHP_STATE_REGISTERED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) /* Remove all devices behind the slot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) pci_lock_rescan_remove();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) pci_hp_remove_devices(php_slot->bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) pci_unlock_rescan_remove();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) /* Detach the child hotpluggable slots */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) pnv_php_unregister(php_slot->dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) /* Notify firmware and remove device nodes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) ret = pnv_php_set_slot_power_state(slot, OPAL_PCI_SLOT_POWER_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) php_slot->state = PNV_PHP_STATE_REGISTERED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) static const struct hotplug_slot_ops php_slot_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) .get_power_status = pnv_php_get_power_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) .get_adapter_status = pnv_php_get_adapter_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) .get_attention_status = pnv_php_get_attention_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) .set_attention_status = pnv_php_set_attention_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) .enable_slot = pnv_php_enable_slot,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) .disable_slot = pnv_php_disable_slot,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) .reset_slot = pnv_php_reset_slot,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) static void pnv_php_release(struct pnv_php_slot *php_slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) /* Remove from global or child list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) spin_lock_irqsave(&pnv_php_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) list_del(&php_slot->link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) spin_unlock_irqrestore(&pnv_php_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) /* Detach from parent */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) pnv_php_put_slot(php_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) pnv_php_put_slot(php_slot->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) static struct pnv_php_slot *pnv_php_alloc_slot(struct device_node *dn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) struct pnv_php_slot *php_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) struct pci_bus *bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) const char *label;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) uint64_t id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) ret = of_property_read_string(dn, "ibm,slot-label", &label);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) if (pnv_pci_get_slot_id(dn, &id))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) bus = pci_find_bus_by_node(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) if (!bus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) php_slot = kzalloc(sizeof(*php_slot), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) if (!php_slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) php_slot->name = kstrdup(label, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) if (!php_slot->name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) kfree(php_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) if (dn->child && PCI_DN(dn->child))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) php_slot->slot_no = PCI_SLOT(PCI_DN(dn->child)->devfn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) php_slot->slot_no = -1; /* Placeholder slot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) kref_init(&php_slot->kref);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) php_slot->state = PNV_PHP_STATE_INITIALIZED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) php_slot->dn = dn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) php_slot->pdev = bus->self;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) php_slot->bus = bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) php_slot->id = id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) php_slot->power_state_check = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) php_slot->slot.ops = &php_slot_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) INIT_LIST_HEAD(&php_slot->children);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) INIT_LIST_HEAD(&php_slot->link);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) return php_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) static int pnv_php_register_slot(struct pnv_php_slot *php_slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) struct pnv_php_slot *parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) struct device_node *dn = php_slot->dn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) /* Check if the slot is registered or not */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) parent = pnv_php_find_slot(php_slot->dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) if (parent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) pnv_php_put_slot(parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) return -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) /* Register PCI slot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) ret = pci_hp_register(&php_slot->slot, php_slot->bus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) php_slot->slot_no, php_slot->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) SLOT_WARN(php_slot, "Error %d registering slot\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) /* Attach to the parent's child list or global list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) while ((dn = of_get_parent(dn))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) if (!PCI_DN(dn)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) of_node_put(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) parent = pnv_php_find_slot(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) if (parent) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) of_node_put(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) of_node_put(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) spin_lock_irqsave(&pnv_php_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) php_slot->parent = parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) if (parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) list_add_tail(&php_slot->link, &parent->children);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) list_add_tail(&php_slot->link, &pnv_php_slot_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) spin_unlock_irqrestore(&pnv_php_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) php_slot->state = PNV_PHP_STATE_REGISTERED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) static int pnv_php_enable_msix(struct pnv_php_slot *php_slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) struct pci_dev *pdev = php_slot->pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) struct msix_entry entry;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) int nr_entries, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) u16 pcie_flag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) /* Get total number of MSIx entries */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) nr_entries = pci_msix_vec_count(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) if (nr_entries < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) return nr_entries;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) /* Check hotplug MSIx entry is in range */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) pcie_capability_read_word(pdev, PCI_EXP_FLAGS, &pcie_flag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) entry.entry = (pcie_flag & PCI_EXP_FLAGS_IRQ) >> 9;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) if (entry.entry >= nr_entries)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) /* Enable MSIx */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) ret = pci_enable_msix_exact(pdev, &entry, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) SLOT_WARN(php_slot, "Error %d enabling MSIx\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) return entry.vector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) static void pnv_php_event_handler(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) struct pnv_php_event *event =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) container_of(work, struct pnv_php_event, work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) struct pnv_php_slot *php_slot = event->php_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) if (event->added)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) pnv_php_enable_slot(&php_slot->slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) pnv_php_disable_slot(&php_slot->slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) kfree(event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) static irqreturn_t pnv_php_interrupt(int irq, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) struct pnv_php_slot *php_slot = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) struct pci_dev *pchild, *pdev = php_slot->pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) struct eeh_dev *edev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) struct eeh_pe *pe;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) struct pnv_php_event *event;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) u16 sts, lsts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) u8 presence;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) bool added;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) sts &= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) pci_dbg(pdev, "PCI slot [%s]: HP int! DLAct: %d, PresDet: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) php_slot->name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) !!(sts & PCI_EXP_SLTSTA_DLLSC),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) !!(sts & PCI_EXP_SLTSTA_PDC));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) if (sts & PCI_EXP_SLTSTA_DLLSC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lsts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) added = !!(lsts & PCI_EXP_LNKSTA_DLLLA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) } else if (!(php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) (sts & PCI_EXP_SLTSTA_PDC)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) ret = pnv_pci_get_presence_state(php_slot->id, &presence);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) SLOT_WARN(php_slot,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) "PCI slot [%s] error %d getting presence (0x%04x), to retry the operation.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) php_slot->name, ret, sts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) added = !!(presence == OPAL_PCI_SLOT_PRESENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) pci_dbg(pdev, "PCI slot [%s]: Spurious IRQ?\n", php_slot->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) return IRQ_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) /* Freeze the removed PE to avoid unexpected error reporting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) if (!added) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) pchild = list_first_entry_or_null(&php_slot->bus->devices,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) struct pci_dev, bus_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) edev = pchild ? pci_dev_to_eeh_dev(pchild) : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) pe = edev ? edev->pe : NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) if (pe) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) eeh_serialize_lock(&flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) eeh_pe_mark_isolated(pe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) eeh_serialize_unlock(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) eeh_pe_set_option(pe, EEH_OPT_FREEZE_PE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) * The PE is left in frozen state if the event is missed. It's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) * fine as the PCI devices (PE) aren't functional any more.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) event = kzalloc(sizeof(*event), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) if (!event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) SLOT_WARN(php_slot,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) "PCI slot [%s] missed hotplug event 0x%04x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) php_slot->name, sts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) pci_info(pdev, "PCI slot [%s] %s (IRQ: %d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) php_slot->name, added ? "added" : "removed", irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) INIT_WORK(&event->work, pnv_php_event_handler);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) event->added = added;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) event->php_slot = php_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) queue_work(php_slot->wq, &event->work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) static void pnv_php_init_irq(struct pnv_php_slot *php_slot, int irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) struct pci_dev *pdev = php_slot->pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) u32 broken_pdc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) u16 sts, ctrl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) /* Allocate workqueue */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) php_slot->wq = alloc_workqueue("pciehp-%s", 0, 0, php_slot->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) if (!php_slot->wq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) SLOT_WARN(php_slot, "Cannot alloc workqueue\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) pnv_php_disable_irq(php_slot, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) /* Check PDC (Presence Detection Change) is broken or not */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) ret = of_property_read_u32(php_slot->dn, "ibm,slot-broken-pdc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) &broken_pdc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) if (!ret && broken_pdc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) php_slot->flags |= PNV_PHP_FLAG_BROKEN_PDC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) /* Clear pending interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &sts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) if (php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) sts |= PCI_EXP_SLTSTA_DLLSC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) sts |= (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, sts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) /* Request the interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) ret = request_irq(irq, pnv_php_interrupt, IRQF_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) php_slot->name, php_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) pnv_php_disable_irq(php_slot, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) SLOT_WARN(php_slot, "Error %d enabling IRQ %d\n", ret, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) /* Enable the interrupts */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) if (php_slot->flags & PNV_PHP_FLAG_BROKEN_PDC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) ctrl &= ~PCI_EXP_SLTCTL_PDCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) ctrl |= (PCI_EXP_SLTCTL_HPIE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) PCI_EXP_SLTCTL_DLLSCE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) ctrl |= (PCI_EXP_SLTCTL_HPIE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) PCI_EXP_SLTCTL_PDCE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) PCI_EXP_SLTCTL_DLLSCE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, ctrl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) /* The interrupt is initialized successfully when @irq is valid */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) php_slot->irq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) static void pnv_php_enable_irq(struct pnv_php_slot *php_slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) struct pci_dev *pdev = php_slot->pdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) int irq, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) * The MSI/MSIx interrupt might have been occupied by other
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) * drivers. Don't populate the surprise hotplug capability
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) * in that case.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) if (pci_dev_msi_enabled(pdev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) ret = pci_enable_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) SLOT_WARN(php_slot, "Error %d enabling device\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) pci_set_master(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) /* Enable MSIx interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) irq = pnv_php_enable_msix(php_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) if (irq > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) pnv_php_init_irq(php_slot, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) * Use MSI if MSIx doesn't work. Fail back to legacy INTx
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) * if MSI doesn't work either
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) ret = pci_enable_msi(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) if (!ret || pdev->irq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) irq = pdev->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) pnv_php_init_irq(php_slot, irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) static int pnv_php_register_one(struct device_node *dn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) struct pnv_php_slot *php_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) u32 prop32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) /* Check if it's hotpluggable slot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) ret = of_property_read_u32(dn, "ibm,slot-pluggable", &prop32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) if (ret || !prop32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) ret = of_property_read_u32(dn, "ibm,reset-by-firmware", &prop32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) if (ret || !prop32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) php_slot = pnv_php_alloc_slot(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) if (!php_slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) ret = pnv_php_register_slot(php_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) goto free_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) ret = pnv_php_enable(php_slot, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) goto unregister_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) /* Enable interrupt if the slot supports surprise hotplug */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) ret = of_property_read_u32(dn, "ibm,slot-surprise-pluggable", &prop32);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) if (!ret && prop32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) pnv_php_enable_irq(php_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) unregister_slot:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) pnv_php_unregister_one(php_slot->dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) free_slot:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) pnv_php_put_slot(php_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) static void pnv_php_register(struct device_node *dn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) struct device_node *child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) * The parent slots should be registered before their
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) * child slots.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) for_each_child_of_node(dn, child) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) pnv_php_register_one(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) pnv_php_register(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) static void pnv_php_unregister_one(struct device_node *dn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) struct pnv_php_slot *php_slot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) php_slot = pnv_php_find_slot(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) if (!php_slot)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) php_slot->state = PNV_PHP_STATE_OFFLINE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) pci_hp_deregister(&php_slot->slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) pnv_php_release(php_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) pnv_php_put_slot(php_slot);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) static void pnv_php_unregister(struct device_node *dn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) struct device_node *child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) /* The child slots should go before their parent slots */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) for_each_child_of_node(dn, child) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) pnv_php_unregister(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) pnv_php_unregister_one(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) static int __init pnv_php_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) struct device_node *dn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) for_each_compatible_node(dn, NULL, "ibm,ioda2-phb")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) pnv_php_register(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) for_each_compatible_node(dn, NULL, "ibm,ioda3-phb")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) pnv_php_register(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) for_each_compatible_node(dn, NULL, "ibm,ioda2-npu2-opencapi-phb")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) pnv_php_register_one(dn); /* slot directly under the PHB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) static void __exit pnv_php_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) struct device_node *dn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) for_each_compatible_node(dn, NULL, "ibm,ioda2-phb")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) pnv_php_unregister(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) for_each_compatible_node(dn, NULL, "ibm,ioda3-phb")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) pnv_php_unregister(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) for_each_compatible_node(dn, NULL, "ibm,ioda2-npu2-opencapi-phb")
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) pnv_php_unregister_one(dn); /* slot directly under the PHB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) module_init(pnv_php_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) module_exit(pnv_php_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) MODULE_VERSION(DRIVER_VERSION);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) MODULE_AUTHOR(DRIVER_AUTHOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) MODULE_DESCRIPTION(DRIVER_DESC);