diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2008-02-29 20:42:56 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2008-03-13 19:56:58 -0400 |
commit | ea8d006b91ac58ec5a0862d09e0b629db399517f (patch) | |
tree | c6f848d1ed3e7d71fd23dcee975d3449bcb7932b /drivers/firewire | |
parent | efbf390a2d940315efff174455243e61f23c03b9 (diff) |
firewire: fw-ohci: PPC PMac platform code
Copied from ohci1394.c. This code is necessary to prevent machine check
exceptions when reloading or resuming the driver.
Tested on a 1st generation PowerBook G4 Titanium, which also needs the
pci_probe() hunk.
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
I was able to reproduce the system exception on resume with a 3rd-gen
Titanium PowerBook G4 667, and this patch does let the system resume
successfully now.
Not quite clear if there was possibly an updated version coming using
pci_enable_device() instead of the pair of pmac_call_feature() calls,
but either way, this is a definite must-have, at least for older ppc
macs -- my Aluminum PowerBook G4/1.67 suspends and resumes without this
patch just fine.
Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'drivers/firewire')
-rw-r--r-- | drivers/firewire/fw-ohci.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index f9440a760da6..182be8672dfd 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c | |||
@@ -33,6 +33,10 @@ | |||
33 | #include <asm/page.h> | 33 | #include <asm/page.h> |
34 | #include <asm/system.h> | 34 | #include <asm/system.h> |
35 | 35 | ||
36 | #ifdef CONFIG_PPC_PMAC | ||
37 | #include <asm/pmac_feature.h> | ||
38 | #endif | ||
39 | |||
36 | #include "fw-ohci.h" | 40 | #include "fw-ohci.h" |
37 | #include "fw-transaction.h" | 41 | #include "fw-transaction.h" |
38 | 42 | ||
@@ -2048,6 +2052,18 @@ pci_probe(struct pci_dev *dev, const struct pci_device_id *ent) | |||
2048 | int err; | 2052 | int err; |
2049 | size_t size; | 2053 | size_t size; |
2050 | 2054 | ||
2055 | #ifdef CONFIG_PPC_PMAC | ||
2056 | /* Necessary on some machines if fw-ohci was loaded/ unloaded before */ | ||
2057 | if (machine_is(powermac)) { | ||
2058 | struct device_node *ofn = pci_device_to_OF_node(dev); | ||
2059 | |||
2060 | if (ofn) { | ||
2061 | pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 1); | ||
2062 | pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1); | ||
2063 | } | ||
2064 | } | ||
2065 | #endif /* CONFIG_PPC_PMAC */ | ||
2066 | |||
2051 | ohci = kzalloc(sizeof(*ohci), GFP_KERNEL); | 2067 | ohci = kzalloc(sizeof(*ohci), GFP_KERNEL); |
2052 | if (ohci == NULL) { | 2068 | if (ohci == NULL) { |
2053 | fw_error("Could not malloc fw_ohci data.\n"); | 2069 | fw_error("Could not malloc fw_ohci data.\n"); |
@@ -2182,6 +2198,19 @@ static void pci_remove(struct pci_dev *dev) | |||
2182 | pci_disable_device(dev); | 2198 | pci_disable_device(dev); |
2183 | fw_card_put(&ohci->card); | 2199 | fw_card_put(&ohci->card); |
2184 | 2200 | ||
2201 | #ifdef CONFIG_PPC_PMAC | ||
2202 | /* On UniNorth, power down the cable and turn off the chip clock | ||
2203 | * to save power on laptops */ | ||
2204 | if (machine_is(powermac)) { | ||
2205 | struct device_node *ofn = pci_device_to_OF_node(dev); | ||
2206 | |||
2207 | if (ofn) { | ||
2208 | pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0); | ||
2209 | pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, ofn, 0, 0); | ||
2210 | } | ||
2211 | } | ||
2212 | #endif /* CONFIG_PPC_PMAC */ | ||
2213 | |||
2185 | fw_notify("Removed fw-ohci device.\n"); | 2214 | fw_notify("Removed fw-ohci device.\n"); |
2186 | } | 2215 | } |
2187 | 2216 | ||
@@ -2202,6 +2231,16 @@ static int pci_suspend(struct pci_dev *pdev, pm_message_t state) | |||
2202 | if (err) | 2231 | if (err) |
2203 | fw_error("pci_set_power_state failed with %d\n", err); | 2232 | fw_error("pci_set_power_state failed with %d\n", err); |
2204 | 2233 | ||
2234 | /* PowerMac suspend code comes last */ | ||
2235 | #ifdef CONFIG_PPC_PMAC | ||
2236 | if (machine_is(powermac)) { | ||
2237 | struct device_node *ofn = pci_device_to_OF_node(pdev); | ||
2238 | |||
2239 | if (ofn) | ||
2240 | pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 0); | ||
2241 | } | ||
2242 | #endif /* CONFIG_PPC_PMAC */ | ||
2243 | |||
2205 | return 0; | 2244 | return 0; |
2206 | } | 2245 | } |
2207 | 2246 | ||
@@ -2210,6 +2249,16 @@ static int pci_resume(struct pci_dev *pdev) | |||
2210 | struct fw_ohci *ohci = pci_get_drvdata(pdev); | 2249 | struct fw_ohci *ohci = pci_get_drvdata(pdev); |
2211 | int err; | 2250 | int err; |
2212 | 2251 | ||
2252 | /* PowerMac resume code comes first */ | ||
2253 | #ifdef CONFIG_PPC_PMAC | ||
2254 | if (machine_is(powermac)) { | ||
2255 | struct device_node *ofn = pci_device_to_OF_node(pdev); | ||
2256 | |||
2257 | if (ofn) | ||
2258 | pmac_call_feature(PMAC_FTR_1394_ENABLE, ofn, 0, 1); | ||
2259 | } | ||
2260 | #endif /* CONFIG_PPC_PMAC */ | ||
2261 | |||
2213 | pci_set_power_state(pdev, PCI_D0); | 2262 | pci_set_power_state(pdev, PCI_D0); |
2214 | pci_restore_state(pdev); | 2263 | pci_restore_state(pdev); |
2215 | err = pci_enable_device(pdev); | 2264 | err = pci_enable_device(pdev); |