| 1 | // SPDX-License-Identifier: GPL-2.0+ | 
|---|
| 2 | /* | 
|---|
| 3 | * (C) Copyright David Brownell 2000-2002 | 
|---|
| 4 | */ | 
|---|
| 5 |  | 
|---|
| 6 | #include <linux/kernel.h> | 
|---|
| 7 | #include <linux/module.h> | 
|---|
| 8 | #include <linux/pci.h> | 
|---|
| 9 | #include <linux/usb.h> | 
|---|
| 10 | #include <linux/usb/hcd.h> | 
|---|
| 11 |  | 
|---|
| 12 | #include <asm/io.h> | 
|---|
| 13 | #include <asm/irq.h> | 
|---|
| 14 |  | 
|---|
| 15 | #ifdef CONFIG_PPC_PMAC | 
|---|
| 16 | #include <asm/machdep.h> | 
|---|
| 17 | #include <asm/pmac_feature.h> | 
|---|
| 18 | #endif | 
|---|
| 19 |  | 
|---|
| 20 | #include "usb.h" | 
|---|
| 21 |  | 
|---|
| 22 |  | 
|---|
| 23 | /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ | 
|---|
| 24 |  | 
|---|
| 25 | /* | 
|---|
| 26 | * Coordinate handoffs between EHCI and companion controllers | 
|---|
| 27 | * during EHCI probing and system resume. | 
|---|
| 28 | */ | 
|---|
| 29 |  | 
|---|
| 30 | static DECLARE_RWSEM(companions_rwsem); | 
|---|
| 31 |  | 
|---|
| 32 | #define CL_UHCI		PCI_CLASS_SERIAL_USB_UHCI | 
|---|
| 33 | #define CL_OHCI		PCI_CLASS_SERIAL_USB_OHCI | 
|---|
| 34 | #define CL_EHCI		PCI_CLASS_SERIAL_USB_EHCI | 
|---|
| 35 |  | 
|---|
| 36 | static inline int is_ohci_or_uhci(struct pci_dev *pdev) | 
|---|
| 37 | { | 
|---|
| 38 | return pdev->class == CL_OHCI || pdev->class == CL_UHCI; | 
|---|
| 39 | } | 
|---|
| 40 |  | 
|---|
| 41 | typedef void (*companion_fn)(struct pci_dev *pdev, struct usb_hcd *hcd, | 
|---|
| 42 | struct pci_dev *companion, struct usb_hcd *companion_hcd); | 
|---|
| 43 |  | 
|---|
| 44 | /* Iterate over PCI devices in the same slot as pdev and call fn for each */ | 
|---|
| 45 | static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd, | 
|---|
| 46 | companion_fn fn) | 
|---|
| 47 | { | 
|---|
| 48 | struct pci_dev		*companion; | 
|---|
| 49 | struct usb_hcd		*companion_hcd; | 
|---|
| 50 | unsigned int		slot = PCI_SLOT(pdev->devfn); | 
|---|
| 51 |  | 
|---|
| 52 | /* | 
|---|
| 53 | * Iterate through other PCI functions in the same slot. | 
|---|
| 54 | * If the function's drvdata isn't set then it isn't bound to | 
|---|
| 55 | * a USB host controller driver, so skip it. | 
|---|
| 56 | */ | 
|---|
| 57 | companion = NULL; | 
|---|
| 58 | for_each_pci_dev(companion) { | 
|---|
| 59 | if (companion->bus != pdev->bus || | 
|---|
| 60 | PCI_SLOT(companion->devfn) != slot) | 
|---|
| 61 | continue; | 
|---|
| 62 |  | 
|---|
| 63 | /* | 
|---|
| 64 | * Companion device should be either UHCI,OHCI or EHCI host | 
|---|
| 65 | * controller, otherwise skip. | 
|---|
| 66 | */ | 
|---|
| 67 | if (companion->class != CL_UHCI && companion->class != CL_OHCI && | 
|---|
| 68 | companion->class != CL_EHCI) | 
|---|
| 69 | continue; | 
|---|
| 70 |  | 
|---|
| 71 | companion_hcd = pci_get_drvdata(pdev: companion); | 
|---|
| 72 | if (!companion_hcd || !companion_hcd->self.root_hub) | 
|---|
| 73 | continue; | 
|---|
| 74 | fn(pdev, hcd, companion, companion_hcd); | 
|---|
| 75 | } | 
|---|
| 76 | } | 
|---|
| 77 |  | 
|---|
| 78 | /* | 
|---|
| 79 | * We're about to add an EHCI controller, which will unceremoniously grab | 
|---|
| 80 | * all the port connections away from its companions.  To prevent annoying | 
|---|
| 81 | * error messages, lock the companion's root hub and gracefully unconfigure | 
|---|
| 82 | * it beforehand.  Leave it locked until the EHCI controller is all set. | 
|---|
| 83 | */ | 
|---|
| 84 | static void ehci_pre_add(struct pci_dev *pdev, struct usb_hcd *hcd, | 
|---|
| 85 | struct pci_dev *companion, struct usb_hcd *companion_hcd) | 
|---|
| 86 | { | 
|---|
| 87 | struct usb_device *udev; | 
|---|
| 88 |  | 
|---|
| 89 | if (is_ohci_or_uhci(pdev: companion)) { | 
|---|
| 90 | udev = companion_hcd->self.root_hub; | 
|---|
| 91 | usb_lock_device(udev); | 
|---|
| 92 | usb_set_configuration(dev: udev, configuration: 0); | 
|---|
| 93 | } | 
|---|
| 94 | } | 
|---|
| 95 |  | 
|---|
| 96 | /* | 
|---|
| 97 | * Adding the EHCI controller has either succeeded or failed.  Set the | 
|---|
| 98 | * companion pointer accordingly, and in either case, reconfigure and | 
|---|
| 99 | * unlock the root hub. | 
|---|
| 100 | */ | 
|---|
| 101 | static void ehci_post_add(struct pci_dev *pdev, struct usb_hcd *hcd, | 
|---|
| 102 | struct pci_dev *companion, struct usb_hcd *companion_hcd) | 
|---|
| 103 | { | 
|---|
| 104 | struct usb_device *udev; | 
|---|
| 105 |  | 
|---|
| 106 | if (is_ohci_or_uhci(pdev: companion)) { | 
|---|
| 107 | if (dev_get_drvdata(dev: &pdev->dev)) {	/* Succeeded */ | 
|---|
| 108 | dev_dbg(&pdev->dev, "HS companion for %s\n", | 
|---|
| 109 | dev_name(&companion->dev)); | 
|---|
| 110 | companion_hcd->self.hs_companion = &hcd->self; | 
|---|
| 111 | } | 
|---|
| 112 | udev = companion_hcd->self.root_hub; | 
|---|
| 113 | usb_set_configuration(dev: udev, configuration: 1); | 
|---|
| 114 | usb_unlock_device(udev); | 
|---|
| 115 | } | 
|---|
| 116 | } | 
|---|
| 117 |  | 
|---|
| 118 | /* | 
|---|
| 119 | * We just added a non-EHCI controller.  Find the EHCI controller to | 
|---|
| 120 | * which it is a companion, and store a pointer to the bus structure. | 
|---|
| 121 | */ | 
|---|
| 122 | static void non_ehci_add(struct pci_dev *pdev, struct usb_hcd *hcd, | 
|---|
| 123 | struct pci_dev *companion, struct usb_hcd *companion_hcd) | 
|---|
| 124 | { | 
|---|
| 125 | if (is_ohci_or_uhci(pdev) && companion->class == CL_EHCI) { | 
|---|
| 126 | dev_dbg(&pdev->dev, "FS/LS companion for %s\n", | 
|---|
| 127 | dev_name(&companion->dev)); | 
|---|
| 128 | hcd->self.hs_companion = &companion_hcd->self; | 
|---|
| 129 | } | 
|---|
| 130 | } | 
|---|
| 131 |  | 
|---|
| 132 | /* We are removing an EHCI controller.  Clear the companions' pointers. */ | 
|---|
| 133 | static void ehci_remove(struct pci_dev *pdev, struct usb_hcd *hcd, | 
|---|
| 134 | struct pci_dev *companion, struct usb_hcd *companion_hcd) | 
|---|
| 135 | { | 
|---|
| 136 | if (is_ohci_or_uhci(pdev: companion)) | 
|---|
| 137 | companion_hcd->self.hs_companion = NULL; | 
|---|
| 138 | } | 
|---|
| 139 |  | 
|---|
| 140 | #ifdef	CONFIG_PM | 
|---|
| 141 |  | 
|---|
| 142 | /* An EHCI controller must wait for its companions before resuming. */ | 
|---|
| 143 | static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd, | 
|---|
| 144 | struct pci_dev *companion, struct usb_hcd *companion_hcd) | 
|---|
| 145 | { | 
|---|
| 146 | if (is_ohci_or_uhci(pdev: companion)) | 
|---|
| 147 | device_pm_wait_for_dev(sub: &pdev->dev, dev: &companion->dev); | 
|---|
| 148 | } | 
|---|
| 149 |  | 
|---|
| 150 | #endif	/* CONFIG_PM */ | 
|---|
| 151 |  | 
|---|
| 152 | /*-------------------------------------------------------------------------*/ | 
|---|
| 153 |  | 
|---|
| 154 | /* configure so an HC device and id are always provided */ | 
|---|
| 155 | /* always called with process context; sleeping is OK */ | 
|---|
| 156 |  | 
|---|
| 157 | /** | 
|---|
| 158 | * usb_hcd_pci_probe - initialize PCI-based HCDs | 
|---|
| 159 | * @dev: USB Host Controller being probed | 
|---|
| 160 | * @driver: USB HC driver handle | 
|---|
| 161 | * | 
|---|
| 162 | * Context: task context, might sleep | 
|---|
| 163 | * | 
|---|
| 164 | * Allocates basic PCI resources for this USB host controller, and | 
|---|
| 165 | * then invokes the start() method for the HCD associated with it | 
|---|
| 166 | * through the hotplug entry's driver_data. | 
|---|
| 167 | * | 
|---|
| 168 | * Store this function in the HCD's struct pci_driver as probe(). | 
|---|
| 169 | * | 
|---|
| 170 | * Return: 0 if successful. | 
|---|
| 171 | */ | 
|---|
| 172 | int usb_hcd_pci_probe(struct pci_dev *dev, const struct hc_driver *driver) | 
|---|
| 173 | { | 
|---|
| 174 | struct usb_hcd		*hcd; | 
|---|
| 175 | int			retval; | 
|---|
| 176 | int			hcd_irq = 0; | 
|---|
| 177 |  | 
|---|
| 178 | if (usb_disabled()) | 
|---|
| 179 | return -ENODEV; | 
|---|
| 180 |  | 
|---|
| 181 | if (!driver) | 
|---|
| 182 | return -EINVAL; | 
|---|
| 183 |  | 
|---|
| 184 | if (pci_enable_device(dev) < 0) | 
|---|
| 185 | return -ENODEV; | 
|---|
| 186 |  | 
|---|
| 187 | /* | 
|---|
| 188 | * The xHCI driver has its own irq management | 
|---|
| 189 | * make sure irq setup is not touched for xhci in generic hcd code | 
|---|
| 190 | */ | 
|---|
| 191 | if ((driver->flags & HCD_MASK) < HCD_USB3) { | 
|---|
| 192 | retval = pci_alloc_irq_vectors(dev, min_vecs: 1, max_vecs: 1, | 
|---|
| 193 | PCI_IRQ_INTX | PCI_IRQ_MSI); | 
|---|
| 194 | if (retval < 0) { | 
|---|
| 195 | dev_err(&dev->dev, | 
|---|
| 196 | "Found HC with no IRQ. Check BIOS/PCI %s setup!\n", | 
|---|
| 197 | pci_name(dev)); | 
|---|
| 198 | retval = -ENODEV; | 
|---|
| 199 | goto disable_pci; | 
|---|
| 200 | } | 
|---|
| 201 | hcd_irq = pci_irq_vector(dev, nr: 0); | 
|---|
| 202 | } | 
|---|
| 203 |  | 
|---|
| 204 | hcd = usb_create_hcd(driver, dev: &dev->dev, bus_name: pci_name(pdev: dev)); | 
|---|
| 205 | if (!hcd) { | 
|---|
| 206 | retval = -ENOMEM; | 
|---|
| 207 | goto free_irq_vectors; | 
|---|
| 208 | } | 
|---|
| 209 |  | 
|---|
| 210 | hcd->amd_resume_bug = usb_hcd_amd_resume_bug(dev, driver); | 
|---|
| 211 |  | 
|---|
| 212 | if (driver->flags & HCD_MEMORY) { | 
|---|
| 213 | /* XHCI, EHCI, OHCI */ | 
|---|
| 214 | hcd->rsrc_start = pci_resource_start(dev, 0); | 
|---|
| 215 | hcd->rsrc_len = pci_resource_len(dev, 0); | 
|---|
| 216 | if (!devm_request_mem_region(&dev->dev, hcd->rsrc_start, | 
|---|
| 217 | hcd->rsrc_len, driver->description)) { | 
|---|
| 218 | dev_dbg(&dev->dev, "controller already in use\n"); | 
|---|
| 219 | retval = -EBUSY; | 
|---|
| 220 | goto put_hcd; | 
|---|
| 221 | } | 
|---|
| 222 | hcd->regs = devm_ioremap(dev: &dev->dev, offset: hcd->rsrc_start, | 
|---|
| 223 | size: hcd->rsrc_len); | 
|---|
| 224 | if (hcd->regs == NULL) { | 
|---|
| 225 | dev_dbg(&dev->dev, "error mapping memory\n"); | 
|---|
| 226 | retval = -EFAULT; | 
|---|
| 227 | goto put_hcd; | 
|---|
| 228 | } | 
|---|
| 229 |  | 
|---|
| 230 | } else { | 
|---|
| 231 | /* UHCI */ | 
|---|
| 232 | int	region; | 
|---|
| 233 |  | 
|---|
| 234 | for (region = 0; region < PCI_STD_NUM_BARS; region++) { | 
|---|
| 235 | if (!(pci_resource_flags(dev, region) & | 
|---|
| 236 | IORESOURCE_IO)) | 
|---|
| 237 | continue; | 
|---|
| 238 |  | 
|---|
| 239 | hcd->rsrc_start = pci_resource_start(dev, region); | 
|---|
| 240 | hcd->rsrc_len = pci_resource_len(dev, region); | 
|---|
| 241 | if (devm_request_region(&dev->dev, hcd->rsrc_start, | 
|---|
| 242 | hcd->rsrc_len, driver->description)) | 
|---|
| 243 | break; | 
|---|
| 244 | } | 
|---|
| 245 | if (region == PCI_STD_NUM_BARS) { | 
|---|
| 246 | dev_dbg(&dev->dev, "no i/o regions available\n"); | 
|---|
| 247 | retval = -EBUSY; | 
|---|
| 248 | goto put_hcd; | 
|---|
| 249 | } | 
|---|
| 250 | } | 
|---|
| 251 |  | 
|---|
| 252 | pci_set_master(dev); | 
|---|
| 253 |  | 
|---|
| 254 | /* Note: dev_set_drvdata must be called while holding the rwsem */ | 
|---|
| 255 | if (dev->class == CL_EHCI) { | 
|---|
| 256 | down_write(sem: &companions_rwsem); | 
|---|
| 257 | dev_set_drvdata(dev: &dev->dev, data: hcd); | 
|---|
| 258 | for_each_companion(pdev: dev, hcd, fn: ehci_pre_add); | 
|---|
| 259 | retval = usb_add_hcd(hcd, irqnum: hcd_irq, IRQF_SHARED); | 
|---|
| 260 | if (retval != 0) | 
|---|
| 261 | dev_set_drvdata(dev: &dev->dev, NULL); | 
|---|
| 262 | for_each_companion(pdev: dev, hcd, fn: ehci_post_add); | 
|---|
| 263 | up_write(sem: &companions_rwsem); | 
|---|
| 264 | } else { | 
|---|
| 265 | down_read(sem: &companions_rwsem); | 
|---|
| 266 | dev_set_drvdata(dev: &dev->dev, data: hcd); | 
|---|
| 267 | retval = usb_add_hcd(hcd, irqnum: hcd_irq, IRQF_SHARED); | 
|---|
| 268 | if (retval != 0) | 
|---|
| 269 | dev_set_drvdata(dev: &dev->dev, NULL); | 
|---|
| 270 | else | 
|---|
| 271 | for_each_companion(pdev: dev, hcd, fn: non_ehci_add); | 
|---|
| 272 | up_read(sem: &companions_rwsem); | 
|---|
| 273 | } | 
|---|
| 274 |  | 
|---|
| 275 | if (retval != 0) | 
|---|
| 276 | goto put_hcd; | 
|---|
| 277 | device_wakeup_enable(dev: hcd->self.controller); | 
|---|
| 278 |  | 
|---|
| 279 | if (pci_dev_run_wake(dev)) | 
|---|
| 280 | pm_runtime_put_noidle(dev: &dev->dev); | 
|---|
| 281 | return retval; | 
|---|
| 282 |  | 
|---|
| 283 | put_hcd: | 
|---|
| 284 | usb_put_hcd(hcd); | 
|---|
| 285 | free_irq_vectors: | 
|---|
| 286 | if ((driver->flags & HCD_MASK) < HCD_USB3) | 
|---|
| 287 | pci_free_irq_vectors(dev); | 
|---|
| 288 | disable_pci: | 
|---|
| 289 | pci_disable_device(dev); | 
|---|
| 290 | dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval); | 
|---|
| 291 | return retval; | 
|---|
| 292 | } | 
|---|
| 293 | EXPORT_SYMBOL_GPL(usb_hcd_pci_probe); | 
|---|
| 294 |  | 
|---|
| 295 |  | 
|---|
| 296 | /* may be called without controller electrically present */ | 
|---|
| 297 | /* may be called with controller, bus, and devices active */ | 
|---|
| 298 |  | 
|---|
| 299 | /** | 
|---|
| 300 | * usb_hcd_pci_remove - shutdown processing for PCI-based HCDs | 
|---|
| 301 | * @dev: USB Host Controller being removed | 
|---|
| 302 | * | 
|---|
| 303 | * Context: task context, might sleep | 
|---|
| 304 | * | 
|---|
| 305 | * Reverses the effect of usb_hcd_pci_probe(), first invoking | 
|---|
| 306 | * the HCD's stop() method.  It is always called from a thread | 
|---|
| 307 | * context, normally "rmmod", "apmd", or something similar. | 
|---|
| 308 | * | 
|---|
| 309 | * Store this function in the HCD's struct pci_driver as remove(). | 
|---|
| 310 | */ | 
|---|
| 311 | void usb_hcd_pci_remove(struct pci_dev *dev) | 
|---|
| 312 | { | 
|---|
| 313 | struct usb_hcd		*hcd; | 
|---|
| 314 | int			hcd_driver_flags; | 
|---|
| 315 |  | 
|---|
| 316 | hcd = pci_get_drvdata(pdev: dev); | 
|---|
| 317 | if (!hcd) | 
|---|
| 318 | return; | 
|---|
| 319 |  | 
|---|
| 320 | hcd_driver_flags = hcd->driver->flags; | 
|---|
| 321 |  | 
|---|
| 322 | if (pci_dev_run_wake(dev)) | 
|---|
| 323 | pm_runtime_get_noresume(dev: &dev->dev); | 
|---|
| 324 |  | 
|---|
| 325 | /* Fake an interrupt request in order to give the driver a chance | 
|---|
| 326 | * to test whether the controller hardware has been removed (e.g., | 
|---|
| 327 | * cardbus physical eject). | 
|---|
| 328 | */ | 
|---|
| 329 | local_irq_disable(); | 
|---|
| 330 | usb_hcd_irq(irq: 0, hcd: hcd); | 
|---|
| 331 | local_irq_enable(); | 
|---|
| 332 |  | 
|---|
| 333 | /* Note: dev_set_drvdata must be called while holding the rwsem */ | 
|---|
| 334 | if (dev->class == CL_EHCI) { | 
|---|
| 335 | down_write(sem: &companions_rwsem); | 
|---|
| 336 | for_each_companion(pdev: dev, hcd, fn: ehci_remove); | 
|---|
| 337 | usb_remove_hcd(hcd); | 
|---|
| 338 | dev_set_drvdata(dev: &dev->dev, NULL); | 
|---|
| 339 | up_write(sem: &companions_rwsem); | 
|---|
| 340 | } else { | 
|---|
| 341 | /* Not EHCI; just clear the companion pointer */ | 
|---|
| 342 | down_read(sem: &companions_rwsem); | 
|---|
| 343 | hcd->self.hs_companion = NULL; | 
|---|
| 344 | usb_remove_hcd(hcd); | 
|---|
| 345 | dev_set_drvdata(dev: &dev->dev, NULL); | 
|---|
| 346 | up_read(sem: &companions_rwsem); | 
|---|
| 347 | } | 
|---|
| 348 | usb_put_hcd(hcd); | 
|---|
| 349 | if ((hcd_driver_flags & HCD_MASK) < HCD_USB3) | 
|---|
| 350 | pci_free_irq_vectors(dev); | 
|---|
| 351 | pci_disable_device(dev); | 
|---|
| 352 | } | 
|---|
| 353 | EXPORT_SYMBOL_GPL(usb_hcd_pci_remove); | 
|---|
| 354 |  | 
|---|
| 355 | /** | 
|---|
| 356 | * usb_hcd_pci_shutdown - shutdown host controller | 
|---|
| 357 | * @dev: USB Host Controller being shutdown | 
|---|
| 358 | */ | 
|---|
| 359 | void usb_hcd_pci_shutdown(struct pci_dev *dev) | 
|---|
| 360 | { | 
|---|
| 361 | struct usb_hcd		*hcd; | 
|---|
| 362 |  | 
|---|
| 363 | hcd = pci_get_drvdata(pdev: dev); | 
|---|
| 364 | if (!hcd) | 
|---|
| 365 | return; | 
|---|
| 366 |  | 
|---|
| 367 | if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && | 
|---|
| 368 | hcd->driver->shutdown) { | 
|---|
| 369 | hcd->driver->shutdown(hcd); | 
|---|
| 370 | if (usb_hcd_is_primary_hcd(hcd) && hcd->irq > 0) | 
|---|
| 371 | free_irq(hcd->irq, hcd); | 
|---|
| 372 | pci_disable_device(dev); | 
|---|
| 373 | } | 
|---|
| 374 | } | 
|---|
| 375 | EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); | 
|---|
| 376 |  | 
|---|
| 377 | #ifdef	CONFIG_PM | 
|---|
| 378 |  | 
|---|
| 379 | #ifdef	CONFIG_PPC_PMAC | 
|---|
| 380 | static void powermac_set_asic(struct pci_dev *pci_dev, int enable) | 
|---|
| 381 | { | 
|---|
| 382 | /* Enanble or disable ASIC clocks for USB */ | 
|---|
| 383 | if (machine_is(powermac)) { | 
|---|
| 384 | struct device_node	*of_node; | 
|---|
| 385 |  | 
|---|
| 386 | of_node = pci_device_to_OF_node(pci_dev); | 
|---|
| 387 | if (of_node) | 
|---|
| 388 | pmac_call_feature(PMAC_FTR_USB_ENABLE, | 
|---|
| 389 | of_node, 0, enable); | 
|---|
| 390 | } | 
|---|
| 391 | } | 
|---|
| 392 |  | 
|---|
| 393 | #else | 
|---|
| 394 |  | 
|---|
| 395 | static inline void powermac_set_asic(struct pci_dev *pci_dev, int enable) | 
|---|
| 396 | {} | 
|---|
| 397 |  | 
|---|
| 398 | #endif	/* CONFIG_PPC_PMAC */ | 
|---|
| 399 |  | 
|---|
| 400 | static int check_root_hub_suspended(struct device *dev) | 
|---|
| 401 | { | 
|---|
| 402 | struct usb_hcd		*hcd = dev_get_drvdata(dev); | 
|---|
| 403 |  | 
|---|
| 404 | if (HCD_RH_RUNNING(hcd)) { | 
|---|
| 405 | dev_warn(dev, "Root hub is not suspended\n"); | 
|---|
| 406 | return -EBUSY; | 
|---|
| 407 | } | 
|---|
| 408 | if (hcd->shared_hcd) { | 
|---|
| 409 | hcd = hcd->shared_hcd; | 
|---|
| 410 | if (HCD_RH_RUNNING(hcd)) { | 
|---|
| 411 | dev_warn(dev, "Secondary root hub is not suspended\n"); | 
|---|
| 412 | return -EBUSY; | 
|---|
| 413 | } | 
|---|
| 414 | } | 
|---|
| 415 | return 0; | 
|---|
| 416 | } | 
|---|
| 417 |  | 
|---|
| 418 | static int suspend_common(struct device *dev, pm_message_t msg) | 
|---|
| 419 | { | 
|---|
| 420 | struct pci_dev		*pci_dev = to_pci_dev(dev); | 
|---|
| 421 | struct usb_hcd		*hcd = pci_get_drvdata(pdev: pci_dev); | 
|---|
| 422 | bool			do_wakeup; | 
|---|
| 423 | int			retval; | 
|---|
| 424 |  | 
|---|
| 425 | if (PMSG_IS_AUTO(msg)) | 
|---|
| 426 | do_wakeup = true; | 
|---|
| 427 | else if (PMSG_NO_WAKEUP(msg)) | 
|---|
| 428 | do_wakeup = false; | 
|---|
| 429 | else | 
|---|
| 430 | do_wakeup = device_may_wakeup(dev); | 
|---|
| 431 |  | 
|---|
| 432 | /* Root hub suspend should have stopped all downstream traffic, | 
|---|
| 433 | * and all bus master traffic.  And done so for both the interface | 
|---|
| 434 | * and the stub usb_device (which we check here).  But maybe it | 
|---|
| 435 | * didn't; writing sysfs power/state files ignores such rules... | 
|---|
| 436 | */ | 
|---|
| 437 | retval = check_root_hub_suspended(dev); | 
|---|
| 438 | if (retval) | 
|---|
| 439 | return retval; | 
|---|
| 440 |  | 
|---|
| 441 | if (hcd->driver->pci_suspend && !HCD_DEAD(hcd)) { | 
|---|
| 442 | /* Optimization: Don't suspend if a root-hub wakeup is | 
|---|
| 443 | * pending and it would cause the HCD to wake up anyway. | 
|---|
| 444 | */ | 
|---|
| 445 | if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) | 
|---|
| 446 | return -EBUSY; | 
|---|
| 447 | if (do_wakeup && hcd->shared_hcd && | 
|---|
| 448 | HCD_WAKEUP_PENDING(hcd->shared_hcd)) | 
|---|
| 449 | return -EBUSY; | 
|---|
| 450 | retval = hcd->driver->pci_suspend(hcd, do_wakeup); | 
|---|
| 451 | suspend_report_result(dev, hcd->driver->pci_suspend, retval); | 
|---|
| 452 |  | 
|---|
| 453 | /* Check again in case wakeup raced with pci_suspend */ | 
|---|
| 454 | if ((retval == 0 && do_wakeup && HCD_WAKEUP_PENDING(hcd)) || | 
|---|
| 455 | (retval == 0 && do_wakeup && hcd->shared_hcd && | 
|---|
| 456 | HCD_WAKEUP_PENDING(hcd->shared_hcd))) { | 
|---|
| 457 | if (hcd->driver->pci_resume) | 
|---|
| 458 | hcd->driver->pci_resume(hcd, msg); | 
|---|
| 459 | retval = -EBUSY; | 
|---|
| 460 | } | 
|---|
| 461 | if (retval) | 
|---|
| 462 | return retval; | 
|---|
| 463 | } | 
|---|
| 464 |  | 
|---|
| 465 | /* If MSI-X is enabled, the driver will have synchronized all vectors | 
|---|
| 466 | * in pci_suspend(). If MSI or legacy PCI is enabled, that will be | 
|---|
| 467 | * synchronized here. | 
|---|
| 468 | */ | 
|---|
| 469 | if (!hcd->msix_enabled) | 
|---|
| 470 | synchronize_irq(irq: pci_irq_vector(dev: pci_dev, nr: 0)); | 
|---|
| 471 |  | 
|---|
| 472 | /* Downstream ports from this root hub should already be quiesced, so | 
|---|
| 473 | * there will be no DMA activity.  Now we can shut down the upstream | 
|---|
| 474 | * link (except maybe for PME# resume signaling).  We'll enter a | 
|---|
| 475 | * low power state during suspend_noirq, if the hardware allows. | 
|---|
| 476 | */ | 
|---|
| 477 | pci_disable_device(dev: pci_dev); | 
|---|
| 478 | return retval; | 
|---|
| 479 | } | 
|---|
| 480 |  | 
|---|
| 481 | static int resume_common(struct device *dev, pm_message_t msg) | 
|---|
| 482 | { | 
|---|
| 483 | struct pci_dev		*pci_dev = to_pci_dev(dev); | 
|---|
| 484 | struct usb_hcd		*hcd = pci_get_drvdata(pdev: pci_dev); | 
|---|
| 485 | int			retval; | 
|---|
| 486 |  | 
|---|
| 487 | if (HCD_RH_RUNNING(hcd) || | 
|---|
| 488 | (hcd->shared_hcd && | 
|---|
| 489 | HCD_RH_RUNNING(hcd->shared_hcd))) { | 
|---|
| 490 | dev_dbg(dev, "can't resume, not suspended!\n"); | 
|---|
| 491 | return 0; | 
|---|
| 492 | } | 
|---|
| 493 |  | 
|---|
| 494 | retval = pci_enable_device(dev: pci_dev); | 
|---|
| 495 | if (retval < 0) { | 
|---|
| 496 | dev_err(dev, "can't re-enable after resume, %d!\n", retval); | 
|---|
| 497 | return retval; | 
|---|
| 498 | } | 
|---|
| 499 |  | 
|---|
| 500 | pci_set_master(dev: pci_dev); | 
|---|
| 501 |  | 
|---|
| 502 | if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) { | 
|---|
| 503 |  | 
|---|
| 504 | /* | 
|---|
| 505 | * Only EHCI controllers have to wait for their companions. | 
|---|
| 506 | * No locking is needed because PCI controller drivers do not | 
|---|
| 507 | * get unbound during system resume. | 
|---|
| 508 | */ | 
|---|
| 509 | if (pci_dev->class == CL_EHCI && msg.event != PM_EVENT_AUTO_RESUME) | 
|---|
| 510 | for_each_companion(pdev: pci_dev, hcd, | 
|---|
| 511 | fn: ehci_wait_for_companions); | 
|---|
| 512 |  | 
|---|
| 513 | retval = hcd->driver->pci_resume(hcd, msg); | 
|---|
| 514 | if (retval) { | 
|---|
| 515 | dev_err(dev, "PCI post-resume error %d!\n", retval); | 
|---|
| 516 | usb_hc_died(hcd); | 
|---|
| 517 | } | 
|---|
| 518 | } | 
|---|
| 519 | return retval; | 
|---|
| 520 | } | 
|---|
| 521 |  | 
|---|
| 522 | #ifdef	CONFIG_PM_SLEEP | 
|---|
| 523 |  | 
|---|
| 524 | static int hcd_pci_suspend(struct device *dev) | 
|---|
| 525 | { | 
|---|
| 526 | return suspend_common(dev, PMSG_SUSPEND); | 
|---|
| 527 | } | 
|---|
| 528 |  | 
|---|
| 529 | static int hcd_pci_freeze(struct device *dev) | 
|---|
| 530 | { | 
|---|
| 531 | return suspend_common(dev, PMSG_FREEZE); | 
|---|
| 532 | } | 
|---|
| 533 |  | 
|---|
| 534 | static int hcd_pci_suspend_noirq(struct device *dev) | 
|---|
| 535 | { | 
|---|
| 536 | struct pci_dev		*pci_dev = to_pci_dev(dev); | 
|---|
| 537 | struct usb_hcd		*hcd = pci_get_drvdata(pdev: pci_dev); | 
|---|
| 538 | int			retval; | 
|---|
| 539 |  | 
|---|
| 540 | retval = check_root_hub_suspended(dev); | 
|---|
| 541 | if (retval) | 
|---|
| 542 | return retval; | 
|---|
| 543 |  | 
|---|
| 544 | pci_save_state(dev: pci_dev); | 
|---|
| 545 |  | 
|---|
| 546 | /* If the root hub is dead rather than suspended, disallow remote | 
|---|
| 547 | * wakeup.  usb_hc_died() should ensure that both hosts are marked as | 
|---|
| 548 | * dying, so we only need to check the primary roothub. | 
|---|
| 549 | */ | 
|---|
| 550 | if (HCD_DEAD(hcd)) | 
|---|
| 551 | device_set_wakeup_enable(dev, enable: 0); | 
|---|
| 552 | dev_dbg(dev, "wakeup: %d\n", device_may_wakeup(dev)); | 
|---|
| 553 |  | 
|---|
| 554 | /* Possibly enable remote wakeup, | 
|---|
| 555 | * choose the appropriate low-power state, and go to that state. | 
|---|
| 556 | */ | 
|---|
| 557 | retval = pci_prepare_to_sleep(dev: pci_dev); | 
|---|
| 558 | if (retval == -EIO) {		/* Low-power not supported */ | 
|---|
| 559 | dev_dbg(dev, "--> PCI D0 legacy\n"); | 
|---|
| 560 | retval = 0; | 
|---|
| 561 | } else if (retval == 0) { | 
|---|
| 562 | dev_dbg(dev, "--> PCI %s\n", | 
|---|
| 563 | pci_power_name(pci_dev->current_state)); | 
|---|
| 564 | } else { | 
|---|
| 565 | suspend_report_result(dev, pci_prepare_to_sleep, retval); | 
|---|
| 566 | return retval; | 
|---|
| 567 | } | 
|---|
| 568 |  | 
|---|
| 569 | powermac_set_asic(pci_dev, enable: 0); | 
|---|
| 570 | return retval; | 
|---|
| 571 | } | 
|---|
| 572 |  | 
|---|
| 573 | static int hcd_pci_poweroff_late(struct device *dev) | 
|---|
| 574 | { | 
|---|
| 575 | struct pci_dev		*pci_dev = to_pci_dev(dev); | 
|---|
| 576 | struct usb_hcd		*hcd = pci_get_drvdata(pdev: pci_dev); | 
|---|
| 577 |  | 
|---|
| 578 | if (hcd->driver->pci_poweroff_late && !HCD_DEAD(hcd)) | 
|---|
| 579 | return hcd->driver->pci_poweroff_late(hcd, device_may_wakeup(dev)); | 
|---|
| 580 |  | 
|---|
| 581 | return 0; | 
|---|
| 582 | } | 
|---|
| 583 |  | 
|---|
| 584 | static int hcd_pci_resume_noirq(struct device *dev) | 
|---|
| 585 | { | 
|---|
| 586 | powermac_set_asic(to_pci_dev(dev), enable: 1); | 
|---|
| 587 | return 0; | 
|---|
| 588 | } | 
|---|
| 589 |  | 
|---|
| 590 | static int hcd_pci_resume(struct device *dev) | 
|---|
| 591 | { | 
|---|
| 592 | return resume_common(dev, PMSG_RESUME); | 
|---|
| 593 | } | 
|---|
| 594 |  | 
|---|
| 595 | static int hcd_pci_restore(struct device *dev) | 
|---|
| 596 | { | 
|---|
| 597 | return resume_common(dev, PMSG_RESTORE); | 
|---|
| 598 | } | 
|---|
| 599 |  | 
|---|
| 600 | #else | 
|---|
| 601 |  | 
|---|
| 602 | #define hcd_pci_suspend		NULL | 
|---|
| 603 | #define hcd_pci_freeze			NULL | 
|---|
| 604 | #define hcd_pci_suspend_noirq	NULL | 
|---|
| 605 | #define hcd_pci_poweroff_late	NULL | 
|---|
| 606 | #define hcd_pci_resume_noirq	NULL | 
|---|
| 607 | #define hcd_pci_resume		NULL | 
|---|
| 608 | #define hcd_pci_restore		NULL | 
|---|
| 609 |  | 
|---|
| 610 | #endif	/* CONFIG_PM_SLEEP */ | 
|---|
| 611 |  | 
|---|
| 612 | static int hcd_pci_runtime_suspend(struct device *dev) | 
|---|
| 613 | { | 
|---|
| 614 | int	retval; | 
|---|
| 615 |  | 
|---|
| 616 | retval = suspend_common(dev, PMSG_AUTO_SUSPEND); | 
|---|
| 617 | if (retval == 0) | 
|---|
| 618 | powermac_set_asic(to_pci_dev(dev), enable: 0); | 
|---|
| 619 | dev_dbg(dev, "hcd_pci_runtime_suspend: %d\n", retval); | 
|---|
| 620 | return retval; | 
|---|
| 621 | } | 
|---|
| 622 |  | 
|---|
| 623 | static int hcd_pci_runtime_resume(struct device *dev) | 
|---|
| 624 | { | 
|---|
| 625 | int	retval; | 
|---|
| 626 |  | 
|---|
| 627 | powermac_set_asic(to_pci_dev(dev), enable: 1); | 
|---|
| 628 | retval = resume_common(dev, PMSG_AUTO_RESUME); | 
|---|
| 629 | dev_dbg(dev, "hcd_pci_runtime_resume: %d\n", retval); | 
|---|
| 630 | return retval; | 
|---|
| 631 | } | 
|---|
| 632 |  | 
|---|
| 633 | const struct dev_pm_ops usb_hcd_pci_pm_ops = { | 
|---|
| 634 | .suspend	= hcd_pci_suspend, | 
|---|
| 635 | .suspend_noirq	= hcd_pci_suspend_noirq, | 
|---|
| 636 | .resume_noirq	= hcd_pci_resume_noirq, | 
|---|
| 637 | .resume		= hcd_pci_resume, | 
|---|
| 638 | .freeze		= hcd_pci_freeze, | 
|---|
| 639 | .freeze_noirq	= check_root_hub_suspended, | 
|---|
| 640 | .thaw_noirq	= NULL, | 
|---|
| 641 | .thaw		= hcd_pci_resume, | 
|---|
| 642 | .poweroff	= hcd_pci_suspend, | 
|---|
| 643 | .poweroff_late	= hcd_pci_poweroff_late, | 
|---|
| 644 | .poweroff_noirq	= hcd_pci_suspend_noirq, | 
|---|
| 645 | .restore_noirq	= hcd_pci_resume_noirq, | 
|---|
| 646 | .restore	= hcd_pci_restore, | 
|---|
| 647 | .runtime_suspend = hcd_pci_runtime_suspend, | 
|---|
| 648 | .runtime_resume	= hcd_pci_runtime_resume, | 
|---|
| 649 | }; | 
|---|
| 650 | EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops); | 
|---|
| 651 |  | 
|---|
| 652 | #endif	/* CONFIG_PM */ | 
|---|
| 653 |  | 
|---|