brintos

brintos / linux-shallow public Read only

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