diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/bus.c | 4 | ||||
-rw-r--r-- | drivers/pci/hotplug/acpiphp_glue.c | 19 | ||||
-rw-r--r-- | drivers/pci/hotplug/fakephp.c | 2 | ||||
-rw-r--r-- | drivers/pci/hotplug/ibmphp_res.c | 14 | ||||
-rw-r--r-- | drivers/pci/pci-sysfs.c | 5 | ||||
-rw-r--r-- | drivers/pci/pci.c | 80 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 85 | ||||
-rw-r--r-- | drivers/pci/slot.c | 2 |
8 files changed, 167 insertions, 44 deletions
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 712250f5874..26301cb25e7 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -288,9 +288,9 @@ void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), next = dev->bus_list.next; /* Run device routines with the device locked */ - down(&dev->dev.sem); + device_lock(&dev->dev); retval = cb(dev, userdata); - up(&dev->dev.sem); + device_unlock(&dev->dev); if (retval) break; } diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index cb2fd01edda..b5dad9f3745 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -749,6 +749,24 @@ static int acpiphp_bus_trim(acpi_handle handle) return retval; } +static void acpiphp_set_acpi_region(struct acpiphp_slot *slot) +{ + struct acpiphp_func *func; + union acpi_object params[2]; + struct acpi_object_list arg_list; + + list_for_each_entry(func, &slot->funcs, sibling) { + arg_list.count = 2; + arg_list.pointer = params; + params[0].type = ACPI_TYPE_INTEGER; + params[0].integer.value = ACPI_ADR_SPACE_PCI_CONFIG; + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = 1; + /* _REG is optional, we don't care about if there is failure */ + acpi_evaluate_object(func->handle, "_REG", &arg_list, NULL); + } +} + /** * enable_device - enable, configure a slot * @slot: slot to be enabled @@ -805,6 +823,7 @@ static int __ref enable_device(struct acpiphp_slot *slot) pci_bus_assign_resources(bus); acpiphp_sanitize_bus(bus); acpiphp_set_hpp_values(bus); + acpiphp_set_acpi_region(slot); pci_enable_bridges(bus); pci_bus_add_devices(bus); diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c index 6151389fd90..0a894efd4b9 100644 --- a/drivers/pci/hotplug/fakephp.c +++ b/drivers/pci/hotplug/fakephp.c @@ -73,7 +73,7 @@ static void legacy_release(struct kobject *kobj) } static struct kobj_type legacy_ktype = { - .sysfs_ops = &(struct sysfs_ops){ + .sysfs_ops = &(const struct sysfs_ops){ .store = legacy_store, .show = legacy_show }, .release = &legacy_release, diff --git a/drivers/pci/hotplug/ibmphp_res.c b/drivers/pci/hotplug/ibmphp_res.c index ec73294d1fa..e2dc289f767 100644 --- a/drivers/pci/hotplug/ibmphp_res.c +++ b/drivers/pci/hotplug/ibmphp_res.c @@ -40,7 +40,7 @@ static void update_resources (struct bus_node *bus_cur, int type, int rangeno); static int once_over (void); static int remove_ranges (struct bus_node *, struct bus_node *); static int update_bridge_ranges (struct bus_node **); -static int add_range (int type, struct range_node *, struct bus_node *); +static int add_bus_range (int type, struct range_node *, struct bus_node *); static void fix_resources (struct bus_node *); static struct bus_node *find_bus_wprev (u8, struct bus_node **, u8); @@ -133,7 +133,7 @@ static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node newrange->rangeno = 1; else { /* need to insert our range */ - add_range (flag, newrange, newbus); + add_bus_range (flag, newrange, newbus); debug ("%d resource Primary Bus inserted on bus %x [%x - %x]\n", flag, newbus->busno, newrange->start, newrange->end); } @@ -384,7 +384,7 @@ int __init ibmphp_rsrc_init (void) * Input: type of the resource, range to add, current bus * Output: 0 or -1, bus and range ptrs ********************************************************************************/ -static int add_range (int type, struct range_node *range, struct bus_node *bus_cur) +static int add_bus_range (int type, struct range_node *range, struct bus_node *bus_cur) { struct range_node *range_cur = NULL; struct range_node *range_prev; @@ -455,7 +455,7 @@ static int add_range (int type, struct range_node *range, struct bus_node *bus_c /******************************************************************************* * This routine goes through the list of resources of type 'type' and updates - * the range numbers that they correspond to. It was called from add_range fnc + * the range numbers that they correspond to. It was called from add_bus_range fnc * * Input: bus, type of the resource, the rangeno starting from which to update ******************************************************************************/ @@ -1999,7 +1999,7 @@ static int __init update_bridge_ranges (struct bus_node **bus) if (bus_sec->noIORanges > 0) { if (!range_exists_already (range, bus_sec, IO)) { - add_range (IO, range, bus_sec); + add_bus_range (IO, range, bus_sec); ++bus_sec->noIORanges; } else { kfree (range); @@ -2048,7 +2048,7 @@ static int __init update_bridge_ranges (struct bus_node **bus) if (bus_sec->noMemRanges > 0) { if (!range_exists_already (range, bus_sec, MEM)) { - add_range (MEM, range, bus_sec); + add_bus_range (MEM, range, bus_sec); ++bus_sec->noMemRanges; } else { kfree (range); @@ -2102,7 +2102,7 @@ static int __init update_bridge_ranges (struct bus_node **bus) if (bus_sec->noPFMemRanges > 0) { if (!range_exists_already (range, bus_sec, PFMEM)) { - add_range (PFMEM, range, bus_sec); + add_bus_range (PFMEM, range, bus_sec); ++bus_sec->noPFMemRanges; } else { kfree (range); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 807224ec835..de296452c95 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -642,6 +642,7 @@ void pci_create_legacy_files(struct pci_bus *b) if (!b->legacy_io) goto kzalloc_err; + sysfs_bin_attr_init(b->legacy_io); b->legacy_io->attr.name = "legacy_io"; b->legacy_io->size = 0xffff; b->legacy_io->attr.mode = S_IRUSR | S_IWUSR; @@ -654,6 +655,7 @@ void pci_create_legacy_files(struct pci_bus *b) goto legacy_io_err; /* Allocated above after the legacy_io struct */ + sysfs_bin_attr_init(b->legacy_mem); b->legacy_mem = b->legacy_io + 1; b->legacy_mem->attr.name = "legacy_mem"; b->legacy_mem->size = 1024*1024; @@ -800,6 +802,7 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine) if (res_attr) { char *res_attr_name = (char *)(res_attr + 1); + sysfs_bin_attr_init(res_attr); if (write_combine) { pdev->res_attr_wc[num] = res_attr; sprintf(res_attr_name, "resource%d_wc", num); @@ -972,6 +975,7 @@ static int pci_create_capabilities_sysfs(struct pci_dev *dev) if (!attr) return -ENOMEM; + sysfs_bin_attr_init(attr); attr->size = dev->vpd->len; attr->attr.name = "vpd"; attr->attr.mode = S_IRUSR | S_IWUSR; @@ -1038,6 +1042,7 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) retval = -ENOMEM; goto err_resource_files; } + sysfs_bin_attr_init(attr); attr->size = rom_size; attr->attr.name = "rom"; attr->attr.mode = S_IRUSR; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 5b548aee9cb..cb1dd5f4988 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -303,6 +303,49 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap) } EXPORT_SYMBOL_GPL(pci_find_ext_capability); +/** + * pci_bus_find_ext_capability - find an extended capability + * @bus: the PCI bus to query + * @devfn: PCI device to query + * @cap: capability code + * + * Like pci_find_ext_capability() but works for pci devices that do not have a + * pci_dev structure set up yet. + * + * Returns the address of the requested capability structure within the + * device's PCI configuration space or 0 in case the device does not + * support it. + */ +int pci_bus_find_ext_capability(struct pci_bus *bus, unsigned int devfn, + int cap) +{ + u32 header; + int ttl; + int pos = PCI_CFG_SPACE_SIZE; + + /* minimum 8 bytes per capability */ + ttl = (PCI_CFG_SPACE_EXP_SIZE - PCI_CFG_SPACE_SIZE) / 8; + + if (!pci_bus_read_config_dword(bus, devfn, pos, &header)) + return 0; + if (header == 0xffffffff || header == 0) + return 0; + + while (ttl-- > 0) { + if (PCI_EXT_CAP_ID(header) == cap) + return pos; + + pos = PCI_EXT_CAP_NEXT(header); + if (pos < PCI_CFG_SPACE_SIZE) + break; + + if (!pci_bus_read_config_dword(bus, devfn, pos, &header)) + break; + } + + return 0; +} + static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap) { int rc, ttl = PCI_FIND_CAP_TTL; @@ -1540,8 +1583,10 @@ void pci_pm_init(struct pci_dev *dev) int pm; u16 pmc; + pm_runtime_forbid(&dev->dev); device_enable_async_suspend(&dev->dev); dev->wakeup_prepared = false; + dev->pm_cap = 0; /* find PCI PM capability in list */ @@ -2253,35 +2298,6 @@ void pci_msi_off(struct pci_dev *dev) } } -#ifndef HAVE_ARCH_PCI_SET_DMA_MASK -/* - * These can be overridden by arch-specific implementations - */ -int -pci_set_dma_mask(struct pci_dev *dev, u64 mask) -{ - if (!pci_dma_supported(dev, mask)) - return -EIO; - - dev->dma_mask = mask; - dev_dbg(&dev->dev, "using %dbit DMA mask\n", fls64(mask)); - - return 0; -} - -int -pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) -{ - if (!pci_dma_supported(dev, mask)) - return -EIO; - - dev->dev.coherent_dma_mask = mask; - dev_dbg(&dev->dev, "using %dbit consistent DMA mask\n", fls64(mask)); - - return 0; -} -#endif - #ifndef HAVE_ARCH_PCI_SET_DMA_MAX_SEGMENT_SIZE int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size) { @@ -2443,7 +2459,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) if (!probe) { pci_block_user_cfg_access(dev); /* block PM suspend, driver probe, etc. */ - down(&dev->dev.sem); + device_lock(&dev->dev); } rc = pci_dev_specific_reset(dev, probe); @@ -2465,7 +2481,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) rc = pci_parent_bus_reset(dev, probe); done: if (!probe) { - up(&dev->dev.sem); + device_unlock(&dev->dev); pci_unblock_user_cfg_access(dev); } @@ -3023,8 +3039,6 @@ EXPORT_SYMBOL(pci_set_mwi); EXPORT_SYMBOL(pci_try_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); EXPORT_SYMBOL(pci_find_parent_resource); EXPORT_SYMBOL(pci_select_bars); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 039e87b7144..81d19d5683a 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2533,6 +2533,91 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1518, quirk_i82576_sriov); #endif /* CONFIG_PCI_IOV */ +/* + * This is a quirk for the Ricoh MMC controller found as a part of + * some mulifunction chips. + + * This is very similiar and based on the ricoh_mmc driver written by + * Philip Langdale. Thank you for these magic sequences. + * + * These chips implement the four main memory card controllers (SD, MMC, MS, xD) + * and one or both of cardbus or firewire. + * + * It happens that they implement SD and MMC + * support as separate controllers (and PCI functions). The linux SDHCI + * driver supports MMC cards but the chip detects MMC cards in hardware + * and directs them to the MMC controller - so the SDHCI driver never sees + * them. + * + * To get around this, we must disable the useless MMC controller. + * At that point, the SDHCI controller will start seeing them + * It seems to be the case that the relevant PCI registers to deactivate the + * MMC controller live on PCI function 0, which might be the cardbus controller + * or the firewire controller, depending on the particular chip in question + * + * This has to be done early, because as soon as we disable the MMC controller + * other pci functions shift up one level, e.g. function #2 becomes function + * #1, and this will confuse the pci core. + */ + +#ifdef CONFIG_MMC_RICOH_MMC +static void ricoh_mmc_fixup_rl5c476(struct pci_dev *dev) +{ + /* disable via cardbus interface */ + u8 write_enable; + u8 write_target; + u8 disable; + + /* disable must be done via function #0 */ + if (PCI_FUNC(dev->devfn)) + return; + + pci_read_config_byte(dev, 0xB7, &disable); + if (disable & 0x02) + return; + + pci_read_config_byte(dev, 0x8E, &write_enable); + pci_write_config_byte(dev, 0x8E, 0xAA); + pci_read_config_byte(dev, 0x8D, &write_target); + pci_write_config_byte(dev, 0x8D, 0xB7); + pci_write_config_byte(dev, 0xB7, disable | 0x02); + pci_write_config_byte(dev, 0x8E, write_enable); + pci_write_config_byte(dev, 0x8D, write_target); + + dev_notice(&dev->dev, "proprietary Ricoh MMC controller disabled (via cardbus function)\n"); + dev_notice(&dev->dev, "MMC cards are now supported by standard SDHCI controller\n"); +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, ricoh_mmc_fixup_rl5c476); +DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, ricoh_mmc_fixup_rl5c476); + +static void ricoh_mmc_fixup_r5c832(struct pci_dev *dev) +{ + /* disable via firewire interface */ + u8 write_enable; + u8 disable; + + /* disable must be done via function #0 */ + if (PCI_FUNC(dev->devfn)) + return; + + pci_read_config_byte(dev, 0xCB, &disable); + + if (disable & 0x02) + return; + + pci_read_config_byte(dev, 0xCA, &write_enable); + pci_write_config_byte(dev, 0xCA, 0x57); + pci_write_config_byte(dev, 0xCB, disable | 0x02); + pci_write_config_byte(dev, 0xCA, write_enable); + + dev_notice(&dev->dev, "proprietary Ricoh MMC controller disabled (via firewire function)\n"); + dev_notice(&dev->dev, "MMC cards are now supported by standard SDHCI controller\n"); +} +DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832); +DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_R5C832, ricoh_mmc_fixup_r5c832); +#endif /*CONFIG_MMC_RICOH_MMC*/ + + static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end) { diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index 49c9e6c9779..f75a44d37fb 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -29,7 +29,7 @@ static ssize_t pci_slot_attr_store(struct kobject *kobj, return attribute->store ? attribute->store(slot, buf, len) : -EIO; } -static struct sysfs_ops pci_slot_sysfs_ops = { +static const struct sysfs_ops pci_slot_sysfs_ops = { .show = pci_slot_attr_show, .store = pci_slot_attr_store, }; |