Branch data Line data Source code
1 : : /* 2 : : * Sonics Silicon Backplane 3 : : * PCI Hostdevice wrapper 4 : : * 5 : : * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de> 6 : : * Copyright (c) 2005 Stefano Brivio <st3@riseup.net> 7 : : * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> 8 : : * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> 9 : : * Copyright (c) 2005-2007 Michael Buesch <m@bues.ch> 10 : : * 11 : : * Licensed under the GNU/GPL. See COPYING for details. 12 : : */ 13 : : 14 : : #include <linux/pm.h> 15 : : #include <linux/pci.h> 16 : : #include <linux/export.h> 17 : : #include <linux/slab.h> 18 : : #include <linux/ssb/ssb.h> 19 : : 20 : : 21 : : #ifdef CONFIG_PM_SLEEP 22 : 0 : static int ssb_pcihost_suspend(struct device *d) 23 : : { 24 : 0 : struct pci_dev *dev = to_pci_dev(d); 25 : 0 : struct ssb_bus *ssb = pci_get_drvdata(dev); 26 : 0 : int err; 27 : : 28 : 0 : err = ssb_bus_suspend(ssb); 29 [ # # ]: 0 : if (err) 30 : : return err; 31 : 0 : pci_save_state(dev); 32 : 0 : pci_disable_device(dev); 33 : : 34 : : /* if there is a wakeup enabled child device on ssb bus, 35 : : enable pci wakeup posibility. */ 36 : 0 : device_set_wakeup_enable(d, d->power.wakeup_path); 37 : : 38 : 0 : pci_prepare_to_sleep(dev); 39 : : 40 : 0 : return 0; 41 : : } 42 : : 43 : 0 : static int ssb_pcihost_resume(struct device *d) 44 : : { 45 : 0 : struct pci_dev *dev = to_pci_dev(d); 46 : 0 : struct ssb_bus *ssb = pci_get_drvdata(dev); 47 : 0 : int err; 48 : : 49 : 0 : pci_back_from_sleep(dev); 50 : 0 : err = pci_enable_device(dev); 51 [ # # ]: 0 : if (err) 52 : : return err; 53 : 0 : pci_restore_state(dev); 54 : 0 : err = ssb_bus_resume(ssb); 55 [ # # ]: 0 : if (err) 56 : 0 : return err; 57 : : 58 : : return 0; 59 : : } 60 : : 61 : : static const struct dev_pm_ops ssb_pcihost_pm_ops = { 62 : : SET_SYSTEM_SLEEP_PM_OPS(ssb_pcihost_suspend, ssb_pcihost_resume) 63 : : }; 64 : : 65 : : #endif /* CONFIG_PM_SLEEP */ 66 : : 67 : 0 : static int ssb_pcihost_probe(struct pci_dev *dev, 68 : : const struct pci_device_id *id) 69 : : { 70 : 0 : struct ssb_bus *ssb; 71 : 0 : int err = -ENOMEM; 72 : 0 : const char *name; 73 : 0 : u32 val; 74 : : 75 : 0 : ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); 76 [ # # ]: 0 : if (!ssb) 77 : 0 : goto out; 78 : 0 : err = pci_enable_device(dev); 79 [ # # ]: 0 : if (err) 80 : 0 : goto err_kfree_ssb; 81 [ # # ]: 0 : name = dev_name(&dev->dev); 82 [ # # # # ]: 0 : if (dev->driver && dev->driver->name) 83 : 0 : name = dev->driver->name; 84 : 0 : err = pci_request_regions(dev, name); 85 [ # # ]: 0 : if (err) 86 : 0 : goto err_pci_disable; 87 : 0 : pci_set_master(dev); 88 : : 89 : : /* Disable the RETRY_TIMEOUT register (0x41) to keep 90 : : * PCI Tx retries from interfering with C3 CPU state */ 91 : 0 : pci_read_config_dword(dev, 0x40, &val); 92 [ # # ]: 0 : if ((val & 0x0000ff00) != 0) 93 : 0 : pci_write_config_dword(dev, 0x40, val & 0xffff00ff); 94 : : 95 : 0 : err = ssb_bus_pcibus_register(ssb, dev); 96 [ # # ]: 0 : if (err) 97 : 0 : goto err_pci_release_regions; 98 : : 99 : 0 : pci_set_drvdata(dev, ssb); 100 : : 101 : : out: 102 : : return err; 103 : : 104 : : err_pci_release_regions: 105 : 0 : pci_release_regions(dev); 106 : 0 : err_pci_disable: 107 : 0 : pci_disable_device(dev); 108 : 0 : err_kfree_ssb: 109 : 0 : kfree(ssb); 110 : 0 : return err; 111 : : } 112 : : 113 : 0 : static void ssb_pcihost_remove(struct pci_dev *dev) 114 : : { 115 : 0 : struct ssb_bus *ssb = pci_get_drvdata(dev); 116 : : 117 : 0 : ssb_bus_unregister(ssb); 118 : 0 : pci_release_regions(dev); 119 : 0 : pci_disable_device(dev); 120 : 0 : kfree(ssb); 121 : 0 : pci_set_drvdata(dev, NULL); 122 : 0 : } 123 : : 124 : 21 : int ssb_pcihost_register(struct pci_driver *driver) 125 : : { 126 : 21 : driver->probe = ssb_pcihost_probe; 127 : 21 : driver->remove = ssb_pcihost_remove; 128 : : #ifdef CONFIG_PM_SLEEP 129 : 21 : driver->driver.pm = &ssb_pcihost_pm_ops; 130 : : #endif 131 : : 132 : 21 : return pci_register_driver(driver); 133 : : } 134 : : EXPORT_SYMBOL(ssb_pcihost_register);