| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 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> | 
| Michael Büsch | eb032b9 | 2011-07-04 20:50:05 +0200 | [diff] [blame] | 9 |  * Copyright (c) 2005-2007 Michael Buesch <m@bues.ch> | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 10 |  * | 
 | 11 |  * Licensed under the GNU/GPL. See COPYING for details. | 
 | 12 |  */ | 
 | 13 |  | 
 | 14 | #include <linux/pci.h> | 
| Paul Gortmaker | 1014c22 | 2011-07-27 22:07:02 -0400 | [diff] [blame] | 15 | #include <linux/export.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 16 | #include <linux/slab.h> | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 17 | #include <linux/ssb/ssb.h> | 
 | 18 |  | 
 | 19 |  | 
 | 20 | #ifdef CONFIG_PM | 
 | 21 | static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) | 
 | 22 | { | 
| Michael Buesch | 8fe2b65 | 2008-03-30 00:10:50 +0100 | [diff] [blame] | 23 | 	struct ssb_bus *ssb = pci_get_drvdata(dev); | 
 | 24 | 	int err; | 
 | 25 |  | 
 | 26 | 	err = ssb_bus_suspend(ssb); | 
 | 27 | 	if (err) | 
 | 28 | 		return err; | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 29 | 	pci_save_state(dev); | 
 | 30 | 	pci_disable_device(dev); | 
 | 31 | 	pci_set_power_state(dev, pci_choose_state(dev, state)); | 
 | 32 |  | 
 | 33 | 	return 0; | 
 | 34 | } | 
 | 35 |  | 
 | 36 | static int ssb_pcihost_resume(struct pci_dev *dev) | 
 | 37 | { | 
| Michael Buesch | 8fe2b65 | 2008-03-30 00:10:50 +0100 | [diff] [blame] | 38 | 	struct ssb_bus *ssb = pci_get_drvdata(dev); | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 39 | 	int err; | 
 | 40 |  | 
 | 41 | 	pci_set_power_state(dev, 0); | 
 | 42 | 	err = pci_enable_device(dev); | 
 | 43 | 	if (err) | 
 | 44 | 		return err; | 
 | 45 | 	pci_restore_state(dev); | 
| Michael Buesch | 8fe2b65 | 2008-03-30 00:10:50 +0100 | [diff] [blame] | 46 | 	err = ssb_bus_resume(ssb); | 
 | 47 | 	if (err) | 
 | 48 | 		return err; | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 49 |  | 
 | 50 | 	return 0; | 
 | 51 | } | 
 | 52 | #else /* CONFIG_PM */ | 
 | 53 | # define ssb_pcihost_suspend	NULL | 
 | 54 | # define ssb_pcihost_resume	NULL | 
 | 55 | #endif /* CONFIG_PM */ | 
 | 56 |  | 
| Greg Kroah-Hartman | 163247c | 2012-12-21 15:10:52 -0800 | [diff] [blame] | 57 | static int ssb_pcihost_probe(struct pci_dev *dev, | 
 | 58 | 			     const struct pci_device_id *id) | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 59 | { | 
 | 60 | 	struct ssb_bus *ssb; | 
 | 61 | 	int err = -ENOMEM; | 
 | 62 | 	const char *name; | 
| Larry Finger | e081685 | 2010-10-20 09:59:33 -0500 | [diff] [blame] | 63 | 	u32 val; | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 64 |  | 
 | 65 | 	ssb = kzalloc(sizeof(*ssb), GFP_KERNEL); | 
 | 66 | 	if (!ssb) | 
 | 67 | 		goto out; | 
 | 68 | 	err = pci_enable_device(dev); | 
 | 69 | 	if (err) | 
 | 70 | 		goto err_kfree_ssb; | 
| Kay Sievers | b7b05fe | 2008-10-30 15:51:57 +0100 | [diff] [blame] | 71 | 	name = dev_name(&dev->dev); | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 72 | 	if (dev->driver && dev->driver->name) | 
 | 73 | 		name = dev->driver->name; | 
 | 74 | 	err = pci_request_regions(dev, name); | 
 | 75 | 	if (err) | 
 | 76 | 		goto err_pci_disable; | 
 | 77 | 	pci_set_master(dev); | 
 | 78 |  | 
| Larry Finger | e081685 | 2010-10-20 09:59:33 -0500 | [diff] [blame] | 79 | 	/* Disable the RETRY_TIMEOUT register (0x41) to keep | 
 | 80 | 	 * PCI Tx retries from interfering with C3 CPU state */ | 
 | 81 | 	pci_read_config_dword(dev, 0x40, &val); | 
 | 82 | 	if ((val & 0x0000ff00) != 0) | 
 | 83 | 		pci_write_config_dword(dev, 0x40, val & 0xffff00ff); | 
 | 84 |  | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 85 | 	err = ssb_bus_pcibus_register(ssb, dev); | 
 | 86 | 	if (err) | 
 | 87 | 		goto err_pci_release_regions; | 
 | 88 |  | 
 | 89 | 	pci_set_drvdata(dev, ssb); | 
 | 90 |  | 
 | 91 | out: | 
 | 92 | 	return err; | 
 | 93 |  | 
 | 94 | err_pci_release_regions: | 
 | 95 | 	pci_release_regions(dev); | 
 | 96 | err_pci_disable: | 
 | 97 | 	pci_disable_device(dev); | 
 | 98 | err_kfree_ssb: | 
 | 99 | 	kfree(ssb); | 
 | 100 | 	return err; | 
 | 101 | } | 
 | 102 |  | 
 | 103 | static void ssb_pcihost_remove(struct pci_dev *dev) | 
 | 104 | { | 
 | 105 | 	struct ssb_bus *ssb = pci_get_drvdata(dev); | 
 | 106 |  | 
 | 107 | 	ssb_bus_unregister(ssb); | 
 | 108 | 	pci_release_regions(dev); | 
 | 109 | 	pci_disable_device(dev); | 
 | 110 | 	kfree(ssb); | 
 | 111 | 	pci_set_drvdata(dev, NULL); | 
 | 112 | } | 
 | 113 |  | 
| Greg Kroah-Hartman | 163247c | 2012-12-21 15:10:52 -0800 | [diff] [blame] | 114 | int ssb_pcihost_register(struct pci_driver *driver) | 
| Michael Buesch | 61e115a | 2007-09-18 15:12:50 -0400 | [diff] [blame] | 115 | { | 
 | 116 | 	driver->probe = ssb_pcihost_probe; | 
 | 117 | 	driver->remove = ssb_pcihost_remove; | 
 | 118 | 	driver->suspend = ssb_pcihost_suspend; | 
 | 119 | 	driver->resume = ssb_pcihost_resume; | 
 | 120 |  | 
 | 121 | 	return pci_register_driver(driver); | 
 | 122 | } | 
 | 123 | EXPORT_SYMBOL(ssb_pcihost_register); |