X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=drivers%2Fpci%2Fpci.c;h=8e287a828d5d3c1886d91e5e122ea544a7fc446c;hb=e532c37858fdcc18e9a91d24c2e22cd21aa22561;hp=e179af3186f56b8298faee43d8106516de349d3c;hpb=3fe9d19f9e86a55679f5f2b38ec0a43a1a510cee;p=powerpc.git diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e179af3186..8e287a828d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -15,6 +15,7 @@ #include #include #include +#include #include /* isa_dma_bridge_buggy */ #include "pci.h" @@ -62,11 +63,38 @@ pci_max_busnr(void) return max; } +static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap) +{ + u8 id; + int ttl = 48; + + while (ttl--) { + pci_bus_read_config_byte(bus, devfn, pos, &pos); + if (pos < 0x40) + break; + pos &= ~3; + pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, + &id); + if (id == 0xff) + break; + if (id == cap) + return pos; + pos += PCI_CAP_LIST_NEXT; + } + return 0; +} + +int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap) +{ + return __pci_find_next_cap(dev->bus, dev->devfn, + pos + PCI_CAP_LIST_NEXT, cap); +} +EXPORT_SYMBOL_GPL(pci_find_next_capability); + static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_type, int cap) { u16 status; - u8 pos, id; - int ttl = 48; + u8 pos; pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status); if (!(status & PCI_STATUS_CAP_LIST)) @@ -75,24 +103,15 @@ static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_ty switch (hdr_type) { case PCI_HEADER_TYPE_NORMAL: case PCI_HEADER_TYPE_BRIDGE: - pci_bus_read_config_byte(bus, devfn, PCI_CAPABILITY_LIST, &pos); + pos = PCI_CAPABILITY_LIST; break; case PCI_HEADER_TYPE_CARDBUS: - pci_bus_read_config_byte(bus, devfn, PCI_CB_CAPABILITY_LIST, &pos); + pos = PCI_CB_CAPABILITY_LIST; break; default: return 0; } - while (ttl-- && pos >= 0x40) { - pos &= ~3; - pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, &id); - if (id == 0xff) - break; - if (id == cap) - return pos; - pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_NEXT, &pos); - } - return 0; + return __pci_find_next_cap(bus, devfn, pos, cap); } /** @@ -252,6 +271,8 @@ pci_restore_bars(struct pci_dev *dev) pci_update_resource(dev, &dev->resource[i], i); } +int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t); + /** * pci_set_power_state - Set the power state of a PCI device * @dev: PCI device to be suspended @@ -266,7 +287,6 @@ pci_restore_bars(struct pci_dev *dev) * -EIO if device does not support PCI PM. * 0 if we can successfully change the power state. */ -int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t); int pci_set_power_state(struct pci_dev *dev, pci_power_t state) { @@ -309,17 +329,25 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr); - /* If we're in D3, force entire word to 0. + /* 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. */ - if (dev->current_state >= PCI_D3hot) { - if (!(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) - need_restore = 1; - pmcsr = 0; - } else { + switch (dev->current_state) { + case PCI_D0: + case PCI_D1: + case PCI_D2: pmcsr &= ~PCI_PM_CTRL_STATE_MASK; pmcsr |= state; + break; + case PCI_UNKNOWN: /* Boot-up */ + if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot + && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) + need_restore = 1; + /* Fall-through: force to D0 */ + default: + pmcsr = 0; + break; } /* enter specified state */ @@ -798,6 +826,31 @@ pci_clear_mwi(struct pci_dev *dev) } } +/** + * pci_intx - enables/disables PCI INTx for device dev + * @pdev: the PCI device to operate on + * @enable: boolean: whether to enable or disable PCI INTx + * + * Enables/disables PCI INTx for device dev + */ +void +pci_intx(struct pci_dev *pdev, int enable) +{ + u16 pci_command, new; + + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + + if (enable) { + new = pci_command & ~PCI_COMMAND_INTX_DISABLE; + } else { + new = pci_command | PCI_COMMAND_INTX_DISABLE; + } + + if (new != pci_command) { + pci_write_config_word(pdev, PCI_COMMAND, new); + } +} + #ifndef HAVE_ARCH_PCI_SET_DMA_MASK /* * These can be overridden by arch-specific implementations @@ -875,6 +928,7 @@ EXPORT_SYMBOL(pci_request_region); EXPORT_SYMBOL(pci_set_master); EXPORT_SYMBOL(pci_set_mwi); EXPORT_SYMBOL(pci_clear_mwi); +EXPORT_SYMBOL_GPL(pci_intx); EXPORT_SYMBOL(pci_set_dma_mask); EXPORT_SYMBOL(pci_set_consistent_dma_mask); EXPORT_SYMBOL(pci_assign_resource);