/** ?* pci_enable_device_mem - Initialize a device for use with Memory space ?* @dev: PCI device to be initialized ?* ?*? Initialize device before it's used by a driver. Ask low-level code ?*? to enable Memory resources. Wake up the device if it was suspended. ?*? Beware, this function can fail. ?*/ int pci_enable_device_mem(struct pci_dev *dev) { ?? ?return pci_enable_device_flags(dev, IORESOURCE_MEM); }
static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags) { ?? ?struct pci_dev *bridge; ?? ?int err; ?? ?int i, bars = 0;
?? ?/* ?? ? * Power state could be unknown at this point, either due to a fresh ?? ? * boot or a device removal call.? So get the current power state ?? ? * so that things like MSI message writing will behave as expected ?? ? * (e.g. if the device really is in D0 at enable time). ?? ? */ ?? ?if (dev->pm_cap) { ?? ??? ?u16 pmcsr; ?? ??? ?pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); ?? ??? ?dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK); ?? ?}
?? ?if (atomic_inc_return(&dev->enable_cnt) > 1) ?? ??? ?return 0;?? ??? ?/* already enabled */
?? ?bridge = pci_upstream_bridge(dev); ?? ?if (bridge) ?? ??? ?pci_enable_bridge(bridge);
?? ?/* only skip sriov related */ ?? ?for (i = 0; i <= PCI_ROM_RESOURCE; i++) ?? ??? ?if (dev->resource[i].flags & flags) ?? ??? ??? ?bars |= (1 << i); ?? ?for (i = PCI_BRIDGE_RESOURCES; i < DEVICE_COUNT_RESOURCE; i++) ?? ??? ?if (dev->resource[i].flags & flags) ?? ??? ??? ?bars |= (1 << i);
?? ?err = do_pci_enable_device(dev, bars); ?? ?if (err < 0) ?? ??? ?atomic_dec(&dev->enable_cnt); ?? ?return err; }
static int do_pci_enable_device(struct pci_dev *dev, int bars) { ?? ?int err; ?? ?struct pci_dev *bridge; ?? ?u16 cmd; ?? ?u8 pin;
?? ?err = pci_set_power_state(dev, PCI_D0); ?? ?if (err < 0 && err != -EIO) ?? ??? ?return err;
?? ?bridge = pci_upstream_bridge(dev); ?? ?if (bridge) ?? ??? ?pcie_aspm_powersave_config_link(bridge);
?? ?err = pcibios_enable_device(dev, bars); ?? ?if (err < 0) ?? ??? ?return err; ?? ?pci_fixup_device(pci_fixup_enable, dev);
?? ?if (dev->msi_enabled || dev->msix_enabled) ?? ??? ?return 0;
?? ?pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); ?? ?if (pin) { ?? ??? ?pci_read_config_word(dev, PCI_COMMAND, &cmd); ?? ??? ?if (cmd & PCI_COMMAND_INTX_DISABLE) ?? ??? ??? ?pci_write_config_word(dev, PCI_COMMAND, ?? ??? ??? ??? ??? ?????? cmd & ~PCI_COMMAND_INTX_DISABLE); ?? ?}
?? ?return 0; }
int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { ?? ?int error;
?? ?/* bound the state we're entering */ ?? ?if (state > PCI_D3cold) ?? ??? ?state = PCI_D3cold; ?? ?else if (state < PCI_D0) ?? ??? ?state = PCI_D0; ?? ?else if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev)) ?? ??? ?/* ?? ??? ? * If the device or the parent bridge do not support PCI PM, ?? ??? ? * ignore the request if we're doing anything other than putting ?? ??? ? * it into D0 (which would only happen on boot). ?? ??? ? */ ?? ??? ?return 0;
?? ?/* Check if we're already there */ ?? ?if (dev->current_state == state) ?? ??? ?return 0;
?? ?__pci_start_power_transition(dev, state);
?? ?/* This device is quirked not to be put into D3, so ?? ??? don't put it in D3 */ ?? ?if (state >= PCI_D3hot && (dev->dev_flags & PCI_DEV_FLAGS_NO_D3)) ?? ??? ?return 0;
?? ?/* ?? ? * To put device in D3cold, we put device into D3hot in native ?? ? * way, then put device into D3cold with platform ops ?? ? */ ?? ?error = pci_raw_set_power_state(dev, state > PCI_D3hot ? ?? ??? ??? ??? ??? ?PCI_D3hot : state);
?? ?if (!__pci_complete_power_transition(dev, state)) ?? ??? ?error = 0;
?? ?return error; }
static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state) { ?? ?u16 pmcsr; ?? ?bool need_restore = false;
?? ?/* Check if we're already there */ ?? ?if (dev->current_state == state) ?? ??? ?return 0;
?? ?if (!dev->pm_cap) ?? ??? ?return -EIO;
?? ?if (state < PCI_D0 || state > PCI_D3hot) ?? ??? ?return -EINVAL;
?? ?/* Validate current state: ?? ? * Can enter D0 from any state, but if we can only go deeper ?? ? * to sleep if we're already in a low power state ?? ? */ ?? ?if (state != PCI_D0 && dev->current_state <= PCI_D3cold ?? ???? && dev->current_state > state) { ?? ??? ?dev_err(&dev->dev, "invalid power transition (from state %d to %d)\n", ?? ??? ??? ?dev->current_state, state); ?? ??? ?return -EINVAL; ?? ?}
?? ?/* check if this device supports the desired state */ ?? ?if ((state == PCI_D1 && !dev->d1_support) ?? ??? || (state == PCI_D2 && !dev->d2_support)) ?? ??? ?return -EIO;
?? ?pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
?? ?/* If we're (effectively) in D3, force entire word to 0. ?? ? * This doesn't affect PME_Status, disables PME_En, and ?? ? * sets PowerState to 0. ?? ? */ ?? ?switch (dev->current_state) { ?? ?case PCI_D0: ?? ?case PCI_D1: ?? ?case PCI_D2: ?? ??? ?pmcsr &= ~PCI_PM_CTRL_STATE_MASK; ?? ??? ?pmcsr |= state; ?? ??? ?break; ?? ?case PCI_D3hot: ?? ?case PCI_D3cold: ?? ?case PCI_UNKNOWN: /* Boot-up */ ?? ??? ?if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot ?? ??? ? && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) ?? ??? ??? ?need_restore = true; ?? ??? ?/* Fall-through: force to D0 */ ?? ?default: ?? ??? ?pmcsr = 0; ?? ??? ?break; ?? ?}
?? ?/* enter specified state */ ?? ?pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
?? ?/* Mandatory power management transition delays */ ?? ?/* see PCI PM 1.1 5.6.1 table 18 */ ?? ?if (state == PCI_D3hot || dev->current_state == PCI_D3hot) ?? ??? ?pci_dev_d3_sleep(dev); ?? ?else if (state == PCI_D2 || dev->current_state == PCI_D2) ?? ??? ?udelay(PCI_PM_D2_DELAY);
?? ?pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); ?? ?dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK); ?? ?if (dev->current_state != state && printk_ratelimit()) ?? ??? ?dev_info(&dev->dev, "Refused to change power state, currently in D%d\n", ?? ??? ??? ? dev->current_state);
?? ?/* ?? ? * According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT ?? ? * INTERFACE SPECIFICATION, REV. 1.2", a device transitioning ?? ? * from D3hot to D0 _may_ perform an internal reset, thereby ?? ? * going to "D0 Uninitialized" rather than "D0 Initialized". ?? ? * For example, at least some versions of the 3c905B and the ?? ? * 3c556B exhibit this behaviour. ?? ? * ?? ? * At least some laptop BIOSen (e.g. the Thinkpad T21) leave ?? ? * devices in a D3hot state at boot.? Consequently, we need to ?? ? * restore at least the BARs so that the device will be ?? ? * accessible to its driver. ?? ? */ ?? ?if (need_restore) ?? ??? ?pci_restore_bars(dev);
?? ?if (dev->bus->self) ?? ??? ?pcie_aspm_pm_state_change(dev->bus->self);
?? ?return 0; }
/** ?* pci_restore_bars - restore a device's BAR values (e.g. after wake-up) ?* @dev: PCI device to have its BARs restored ?* ?* Restore the BAR values for a given device, so as to make it ?* accessible by its driver. ?*/ static void pci_restore_bars(struct pci_dev *dev) { ?? ?int i;
?? ?for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) ?? ??? ?pci_update_resource(dev, i); }
void pci_update_resource(struct pci_dev *dev, int resno) { ?? ?if (resno <= PCI_ROM_RESOURCE) ?? ??? ?pci_std_update_resource(dev, resno); #ifdef CONFIG_PCI_IOV ?? ?else if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END) ?? ??? ?pci_iov_update_resource(dev, resno); #endif }
static void pci_std_update_resource(struct pci_dev *dev, int resno) { ?? ?struct pci_bus_region region; ?? ?bool disable; ?? ?u16 cmd; ?? ?u32 new, check, mask; ?? ?int reg; ?? ?struct resource *res = dev->resource + resno;
?? ?/* Per SR-IOV spec 3.4.1.11, VF BARs are RO zero */ ?? ?if (dev->is_virtfn) ?? ??? ?return;
?? ?/* ?? ? * Ignore resources for unimplemented BARs and unused resource slots ?? ? * for 64 bit BARs. ?? ? */ ?? ?if (!res->flags) ?? ??? ?return;
?? ?if (res->flags & IORESOURCE_UNSET) ?? ??? ?return;
?? ?/* ?? ? * Ignore non-moveable resources.? This might be legacy resources for ?? ? * which no functional BAR register exists or another important ?? ? * system resource we shouldn't move around. ?? ? */ ?? ?if (res->flags & IORESOURCE_PCI_FIXED) ?? ??? ?return;
?? ?pcibios_resource_to_bus(dev->bus, ®ion, res); ?? ?new = region.start;
?? ?if (res->flags & IORESOURCE_IO) { ?? ??? ?mask = (u32)PCI_BASE_ADDRESS_IO_MASK; ?? ??? ?new |= res->flags & ~PCI_BASE_ADDRESS_IO_MASK; ?? ?} else if (resno == PCI_ROM_RESOURCE) { ?? ??? ?mask = PCI_ROM_ADDRESS_MASK; ?? ?} else { ?? ??? ?mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; ?? ??? ?new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK; ?? ?}
?? ?if (resno < PCI_ROM_RESOURCE) { ?? ??? ?reg = PCI_BASE_ADDRESS_0 + 4 * resno; ?? ?} else if (resno == PCI_ROM_RESOURCE) {
?? ??? ?/* ?? ??? ? * Apparently some Matrox devices have ROM BARs that read ?? ??? ? * as zero when disabled, so don't update ROM BARs unless ?? ??? ? * they're enabled.? See https://lkml.org/lkml/2005/8/30/138. ?? ??? ? */ ?? ??? ?if (!(res->flags & IORESOURCE_ROM_ENABLE)) ?? ??? ??? ?return;
?? ??? ?reg = dev->rom_base_reg; ?? ??? ?new |= PCI_ROM_ADDRESS_ENABLE; ?? ?} else ?? ??? ?return;
?? ?/* ?? ? * We can't update a 64-bit BAR atomically, so when possible, ?? ? * disable decoding so that a half-updated BAR won't conflict ?? ? * with another device. ?? ? */ ?? ?disable = (res->flags & IORESOURCE_MEM_64) && !dev->mmio_always_on; ?? ?if (disable) { ?? ??? ?pci_read_config_word(dev, PCI_COMMAND, &cmd); ?? ??? ?pci_write_config_word(dev, PCI_COMMAND, ?? ??? ??? ??? ?????? cmd & ~PCI_COMMAND_MEMORY); ?? ?}
?? ?pci_write_config_dword(dev, reg, new); ?? ?pci_read_config_dword(dev, reg, &check);
?? ?if ((new ^ check) & mask) { ?? ??? ?dev_err(&dev->dev, "BAR %d: error updating (%#08x != %#08x)\n", ?? ??? ??? ?resno, new, check); ?? ?}
?? ?if (res->flags & IORESOURCE_MEM_64) { ?? ??? ?new = region.start >> 16 >> 16; ?? ??? ?pci_write_config_dword(dev, reg + 4, new); ?? ??? ?pci_read_config_dword(dev, reg + 4, &check); ?? ??? ?if (check != new) { ?? ??? ??? ?dev_err(&dev->dev, "BAR %d: error updating (high %#08x != %#08x)\n", ?? ??? ??? ??? ?resno, new, check); ?? ??? ?} ?? ?}
?? ?if (disable) ?? ??? ?pci_write_config_word(dev, PCI_COMMAND, cmd); }
|