diff options
Diffstat (limited to 'drivers/usb/core/hcd-pci.c')
| -rw-r--r-- | drivers/usb/core/hcd-pci.c | 60 | 
1 files changed, 39 insertions, 21 deletions
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index f71e8e307e0f..ce22f4a84ed0 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -192,13 +192,13 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  			"Found HC with no IRQ.  Check BIOS/PCI %s setup!\n",  			pci_name(dev));  		retval = -ENODEV; -		goto err1; +		goto disable_pci;  	}  	hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev));  	if (!hcd) {  		retval = -ENOMEM; -		goto err1; +		goto disable_pci;  	}  	if (driver->flags & HCD_MEMORY) { @@ -209,13 +209,13 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  				driver->description)) {  			dev_dbg(&dev->dev, "controller already in use\n");  			retval = -EBUSY; -			goto err2; +			goto clear_companion;  		}  		hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);  		if (hcd->regs == NULL) {  			dev_dbg(&dev->dev, "error mapping memory\n");  			retval = -EFAULT; -			goto err3; +			goto release_mem_region;  		}  	} else { @@ -236,7 +236,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  		if (region == PCI_ROM_RESOURCE) {  			dev_dbg(&dev->dev, "no i/o regions available\n");  			retval = -EBUSY; -			goto err2; +			goto clear_companion;  		}  	} @@ -244,24 +244,24 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  	retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);  	if (retval != 0) -		goto err4; +		goto unmap_registers;  	set_hs_companion(dev, hcd);  	if (pci_dev_run_wake(dev))  		pm_runtime_put_noidle(&dev->dev);  	return retval; - err4: +unmap_registers:  	if (driver->flags & HCD_MEMORY) {  		iounmap(hcd->regs); - err3: +release_mem_region:  		release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  	} else  		release_region(hcd->rsrc_start, hcd->rsrc_len); - err2: +clear_companion:  	clear_hs_companion(dev, hcd);  	usb_put_hcd(hcd); - err1: +disable_pci:  	pci_disable_device(dev);  	dev_err(&dev->dev, "init %s fail, %d\n", pci_name(dev), retval);  	return retval; @@ -335,7 +335,7 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev)  }  EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); -#ifdef	CONFIG_PM_OPS +#ifdef	CONFIG_PM  #ifdef	CONFIG_PPC_PMAC  static void powermac_set_asic(struct pci_dev *pci_dev, int enable) @@ -363,11 +363,17 @@ static int check_root_hub_suspended(struct device *dev)  	struct pci_dev		*pci_dev = to_pci_dev(dev);  	struct usb_hcd		*hcd = pci_get_drvdata(pci_dev); -	if (!(hcd->state == HC_STATE_SUSPENDED || -			hcd->state == HC_STATE_HALT)) { +	if (HCD_RH_RUNNING(hcd)) {  		dev_warn(dev, "Root hub is not suspended\n");  		return -EBUSY;  	} +	if (hcd->shared_hcd) { +		hcd = hcd->shared_hcd; +		if (HCD_RH_RUNNING(hcd)) { +			dev_warn(dev, "Secondary root hub is not suspended\n"); +			return -EBUSY; +		} +	}  	return 0;  } @@ -386,17 +392,22 @@ static int suspend_common(struct device *dev, bool do_wakeup)  	if (retval)  		return retval; -	if (hcd->driver->pci_suspend) { +	if (hcd->driver->pci_suspend && !HCD_DEAD(hcd)) {  		/* Optimization: Don't suspend if a root-hub wakeup is  		 * pending and it would cause the HCD to wake up anyway.  		 */  		if (do_wakeup && HCD_WAKEUP_PENDING(hcd))  			return -EBUSY; +		if (do_wakeup && hcd->shared_hcd && +				HCD_WAKEUP_PENDING(hcd->shared_hcd)) +			return -EBUSY;  		retval = hcd->driver->pci_suspend(hcd, do_wakeup);  		suspend_report_result(hcd->driver->pci_suspend, retval);  		/* Check again in case wakeup raced with pci_suspend */ -		if (retval == 0 && do_wakeup && HCD_WAKEUP_PENDING(hcd)) { +		if ((retval == 0 && do_wakeup && HCD_WAKEUP_PENDING(hcd)) || +				(retval == 0 && do_wakeup && hcd->shared_hcd && +				 HCD_WAKEUP_PENDING(hcd->shared_hcd))) {  			if (hcd->driver->pci_resume)  				hcd->driver->pci_resume(hcd, false);  			retval = -EBUSY; @@ -427,7 +438,9 @@ static int resume_common(struct device *dev, int event)  	struct usb_hcd		*hcd = pci_get_drvdata(pci_dev);  	int			retval; -	if (hcd->state != HC_STATE_SUSPENDED) { +	if (HCD_RH_RUNNING(hcd) || +			(hcd->shared_hcd && +			 HCD_RH_RUNNING(hcd->shared_hcd))) {  		dev_dbg(dev, "can't resume, not suspended!\n");  		return 0;  	} @@ -441,8 +454,10 @@ static int resume_common(struct device *dev, int event)  	pci_set_master(pci_dev);  	clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); +	if (hcd->shared_hcd) +		clear_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags); -	if (hcd->driver->pci_resume) { +	if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) {  		if (event != PM_EVENT_AUTO_RESUME)  			wait_for_companions(pci_dev, hcd); @@ -450,6 +465,8 @@ static int resume_common(struct device *dev, int event)  				event == PM_EVENT_RESTORE);  		if (retval) {  			dev_err(dev, "PCI post-resume error %d!\n", retval); +			if (hcd->shared_hcd) +				usb_hc_died(hcd->shared_hcd);  			usb_hc_died(hcd);  		}  	} @@ -475,10 +492,11 @@ static int hcd_pci_suspend_noirq(struct device *dev)  	pci_save_state(pci_dev); -	/* If the root hub is HALTed rather than SUSPENDed, -	 * disallow remote wakeup. +	/* If the root hub is dead rather than suspended, disallow remote +	 * wakeup.  usb_hc_died() should ensure that both hosts are marked as +	 * dying, so we only need to check the primary roothub.  	 */ -	if (hcd->state == HC_STATE_HALT) +	if (HCD_DEAD(hcd))  		device_set_wakeup_enable(dev, 0);  	dev_dbg(dev, "wakeup: %d\n", device_may_wakeup(dev)); @@ -580,4 +598,4 @@ const struct dev_pm_ops usb_hcd_pci_pm_ops = {  };  EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops); -#endif	/* CONFIG_PM_OPS */ +#endif	/* CONFIG_PM */  | 
