File Index
Files and directories
Sign in
FILE

core.c

File preview with syntax highlighting.

linux-6.19.14/drivers/pci/pwrctrl/core.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (C) 2024 Linaro Ltd.
  4 */
  5
  6#include <linux/device.h>
  7#include <linux/export.h>
  8#include <linux/kernel.h>
  9#include <linux/pci.h>
 10#include <linux/pci-pwrctrl.h>
 11#include <linux/property.h>
 12#include <linux/slab.h>
 13
 14static int pci_pwrctrl_notify(struct notifier_block *nb, unsigned long action,
 15			      void *data)
 16{
 17	struct pci_pwrctrl *pwrctrl = container_of(nb, struct pci_pwrctrl, nb);
 18	struct device *dev = data;
 19
 20	if (dev_fwnode(dev) != dev_fwnode(pwrctrl->dev))
 21		return NOTIFY_DONE;
 22
 23	switch (action) {
 24	case BUS_NOTIFY_ADD_DEVICE:
 25		/*
 26		 * We will have two struct device objects bound to two different
 27		 * drivers on different buses but consuming the same DT node. We
 28		 * must not bind the pins twice in this case but only once for
 29		 * the first device to be added.
 30		 *
 31		 * If we got here then the PCI device is the second after the
 32		 * power control platform device. Mark its OF node as reused.
 33		 */
 34		dev->of_node_reused = true;
 35		break;
 36	}
 37
 38	return NOTIFY_DONE;
 39}
 40
 41static void rescan_work_func(struct work_struct *work)
 42{
 43	struct pci_pwrctrl *pwrctrl = container_of(work,
 44						   struct pci_pwrctrl, work);
 45
 46	pci_lock_rescan_remove();
 47	pci_rescan_bus(to_pci_host_bridge(pwrctrl->dev->parent)->bus);
 48	pci_unlock_rescan_remove();
 49}
 50
 51/**
 52 * pci_pwrctrl_init() - Initialize the PCI power control context struct
 53 *
 54 * @pwrctrl: PCI power control data
 55 * @dev: Parent device
 56 */
 57void pci_pwrctrl_init(struct pci_pwrctrl *pwrctrl, struct device *dev)
 58{
 59	pwrctrl->dev = dev;
 60	INIT_WORK(&pwrctrl->work, rescan_work_func);
 61}
 62EXPORT_SYMBOL_GPL(pci_pwrctrl_init);
 63
 64/**
 65 * pci_pwrctrl_device_set_ready() - Notify the pwrctrl subsystem that the PCI
 66 * device is powered-up and ready to be detected.
 67 *
 68 * @pwrctrl: PCI power control data.
 69 *
 70 * Returns:
 71 * 0 on success, negative error number on error.
 72 *
 73 * Note:
 74 * This function returning 0 doesn't mean the device was detected. It means,
 75 * that the bus rescan was successfully started. The device will get bound to
 76 * its PCI driver asynchronously.
 77 */
 78int pci_pwrctrl_device_set_ready(struct pci_pwrctrl *pwrctrl)
 79{
 80	int ret;
 81
 82	if (!pwrctrl->dev)
 83		return -ENODEV;
 84
 85	pwrctrl->nb.notifier_call = pci_pwrctrl_notify;
 86	ret = bus_register_notifier(&pci_bus_type, &pwrctrl->nb);
 87	if (ret)
 88		return ret;
 89
 90	schedule_work(&pwrctrl->work);
 91
 92	return 0;
 93}
 94EXPORT_SYMBOL_GPL(pci_pwrctrl_device_set_ready);
 95
 96/**
 97 * pci_pwrctrl_device_unset_ready() - Notify the pwrctrl subsystem that the PCI
 98 * device is about to be powered-down.
 99 *
100 * @pwrctrl: PCI power control data.
101 */
102void pci_pwrctrl_device_unset_ready(struct pci_pwrctrl *pwrctrl)
103{
104	cancel_work_sync(&pwrctrl->work);
105
106	/*
107	 * We don't have to delete the link here. Typically, this function
108	 * is only called when the power control device is being detached. If
109	 * it is being detached then the child PCI device must have already
110	 * been unbound too or the device core wouldn't let us unbind.
111	 */
112	bus_unregister_notifier(&pci_bus_type, &pwrctrl->nb);
113}
114EXPORT_SYMBOL_GPL(pci_pwrctrl_device_unset_ready);
115
116static void devm_pci_pwrctrl_device_unset_ready(void *data)
117{
118	struct pci_pwrctrl *pwrctrl = data;
119
120	pci_pwrctrl_device_unset_ready(pwrctrl);
121}
122
123/**
124 * devm_pci_pwrctrl_device_set_ready - Managed variant of
125 * pci_pwrctrl_device_set_ready().
126 *
127 * @dev: Device managing this pwrctrl provider.
128 * @pwrctrl: PCI power control data.
129 *
130 * Returns:
131 * 0 on success, negative error number on error.
132 */
133int devm_pci_pwrctrl_device_set_ready(struct device *dev,
134				      struct pci_pwrctrl *pwrctrl)
135{
136	int ret;
137
138	ret = pci_pwrctrl_device_set_ready(pwrctrl);
139	if (ret)
140		return ret;
141
142	return devm_add_action_or_reset(dev,
143					devm_pci_pwrctrl_device_unset_ready,
144					pwrctrl);
145}
146EXPORT_SYMBOL_GPL(devm_pci_pwrctrl_device_set_ready);
147
148MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@linaro.org>");
149MODULE_DESCRIPTION("PCI Device Power Control core driver");
150MODULE_LICENSE("GPL");
~/ Read-only file preview.