From 52409fae3e4b8d16b68b61902fc09075cd97b75d Mon Sep 17 00:00:00 2001 From: Dominik Sliwa Date: Sun, 2 Jul 2017 16:41:37 +0200 Subject: Backports generated from 4.11 kernel Initial commit. Signed-off-by: Dominik Sliwa --- drivers/ssb/pcihost_wrapper.c | 136 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 drivers/ssb/pcihost_wrapper.c (limited to 'drivers/ssb/pcihost_wrapper.c') diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c new file mode 100644 index 0000000..c891cf1 --- /dev/null +++ b/drivers/ssb/pcihost_wrapper.c @@ -0,0 +1,136 @@ +/* + * Sonics Silicon Backplane + * PCI Hostdevice wrapper + * + * Copyright (c) 2005 Martin Langer + * Copyright (c) 2005 Stefano Brivio + * Copyright (c) 2005 Danny van Dyk + * Copyright (c) 2005 Andreas Jaggi + * Copyright (c) 2005-2007 Michael Buesch + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include +#include +#include +#include +#include + + +#ifdef CONFIG_PM_SLEEP +static int ssb_pcihost_suspend(struct device *d) +{ + struct pci_dev *dev = to_pci_dev(d); + struct ssb_bus *ssb = pci_get_drvdata(dev); + int err; + + err = ssb_bus_suspend(ssb); + if (err) + return err; + pci_save_state(dev); + pci_disable_device(dev); + + /* if there is a wakeup enabled child device on ssb bus, + enable pci wakeup posibility. */ +#if LINUX_VERSION_IS_GEQ(3,2,0) + device_set_wakeup_enable(d, d->power.wakeup_path); +#endif /* LINUX_VERSION_IS_GEQ(3,2,0) */ + + pci_prepare_to_sleep(dev); + + return 0; +} + +static int ssb_pcihost_resume(struct device *d) +{ + struct pci_dev *dev = to_pci_dev(d); + struct ssb_bus *ssb = pci_get_drvdata(dev); + int err; + + pci_back_from_sleep(dev); + err = pci_enable_device(dev); + if (err) + return err; + pci_restore_state(dev); + err = ssb_bus_resume(ssb); + if (err) + return err; + + return 0; +} + +static const struct dev_pm_ops ssb_pcihost_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ssb_pcihost_suspend, ssb_pcihost_resume) +}; + +#endif /* CONFIG_PM_SLEEP */ + +static int ssb_pcihost_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct ssb_bus *ssb; + int err = -ENOMEM; + const char *name; + u32 val; + + ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); + if (!ssb) + goto out; + err = pci_enable_device(dev); + if (err) + goto err_kfree_ssb; + name = dev_name(&dev->dev); + if (dev->driver && dev->driver->name) + name = dev->driver->name; + err = pci_request_regions(dev, name); + if (err) + goto err_pci_disable; + pci_set_master(dev); + + /* Disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_read_config_dword(dev, 0x40, &val); + if ((val & 0x0000ff00) != 0) + pci_write_config_dword(dev, 0x40, val & 0xffff00ff); + + err = ssb_bus_pcibus_register(ssb, dev); + if (err) + goto err_pci_release_regions; + + pci_set_drvdata(dev, ssb); + +out: + return err; + +err_pci_release_regions: + pci_release_regions(dev); +err_pci_disable: + pci_disable_device(dev); +err_kfree_ssb: + kfree(ssb); + return err; +} + +static void ssb_pcihost_remove(struct pci_dev *dev) +{ + struct ssb_bus *ssb = pci_get_drvdata(dev); + + ssb_bus_unregister(ssb); + pci_release_regions(dev); + pci_disable_device(dev); + kfree(ssb); + pci_set_drvdata(dev, NULL); +} + +int ssb_pcihost_register(struct pci_driver *driver) +{ + driver->probe = ssb_pcihost_probe; + driver->remove = ssb_pcihost_remove; +#ifdef CONFIG_PM_SLEEP + driver->driver.pm = &ssb_pcihost_pm_ops; +#endif + + return pci_register_driver(driver); +} +EXPORT_SYMBOL(ssb_pcihost_register); -- cgit v1.2.3