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); |
