Skip to content

Commit

Permalink
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6
Browse files Browse the repository at this point in the history
  • Loading branch information
Linus Torvalds committed Oct 28, 2005
2 parents dbe0580 + f8977d0 commit 7efe5d7
Show file tree
Hide file tree
Showing 37 changed files with 739 additions and 6,349 deletions.
4 changes: 3 additions & 1 deletion Documentation/DocBook/kernel-api.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,9 @@ X!Edrivers/pci/search.c
-->
!Edrivers/pci/msi.c
!Edrivers/pci/bus.c
!Edrivers/pci/hotplug.c
<!-- FIXME: Removed for now since no structured comments in source
X!Edrivers/pci/hotplug.c
-->
!Edrivers/pci/probe.c
!Edrivers/pci/rom.c
</sect1>
Expand Down
59 changes: 59 additions & 0 deletions arch/i386/pci/fixup.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
* Exceptions for specific devices. Usually work-arounds for fatal design flaws.
*/

#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/pci.h>
#include <linux/init.h>
#include "pci.h"
Expand Down Expand Up @@ -384,3 +386,60 @@ static void __devinit pci_fixup_video(struct pci_dev *pdev)
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);

/*
* Some Toshiba laptops need extra code to enable their TI TSB43AB22/A.
*
* We pretend to bring them out of full D3 state, and restore the proper
* IRQ, PCI cache line size, and BARs, otherwise the device won't function
* properly. In some cases, the device will generate an interrupt on
* the wrong IRQ line, causing any devices sharing the the line it's
* *supposed* to use to be disabled by the kernel's IRQ debug code.
*/
static u16 toshiba_line_size;

static struct dmi_system_id __devinit toshiba_ohci1394_dmi_table[] = {
{
.ident = "Toshiba PS5 based laptop",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_VERSION, "PS5"),
},
},
{
.ident = "Toshiba PSM4 based laptop",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
DMI_MATCH(DMI_PRODUCT_VERSION, "PSM4"),
},
},
{ }
};

static void __devinit pci_pre_fixup_toshiba_ohci1394(struct pci_dev *dev)
{
if (!dmi_check_system(toshiba_ohci1394_dmi_table))
return; /* only applies to certain Toshibas (so far) */

dev->current_state = PCI_D3cold;
pci_read_config_word(dev, PCI_CACHE_LINE_SIZE, &toshiba_line_size);
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TI, 0x8032,
pci_pre_fixup_toshiba_ohci1394);

static void __devinit pci_post_fixup_toshiba_ohci1394(struct pci_dev *dev)
{
if (!dmi_check_system(toshiba_ohci1394_dmi_table))
return; /* only applies to certain Toshibas (so far) */

/* Restore config space on Toshiba laptops */
mdelay(10);
pci_write_config_word(dev, PCI_CACHE_LINE_SIZE, toshiba_line_size);
pci_write_config_word(dev, PCI_INTERRUPT_LINE, dev->irq);
pci_write_config_dword(dev, PCI_BASE_ADDRESS_0,
pci_resource_start(dev, 0));
pci_write_config_dword(dev, PCI_BASE_ADDRESS_1,
pci_resource_start(dev, 1));
}
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_TI, 0x8032,
pci_post_fixup_toshiba_ohci1394);
89 changes: 89 additions & 0 deletions drivers/pci/access.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,92 @@ EXPORT_SYMBOL(pci_bus_read_config_dword);
EXPORT_SYMBOL(pci_bus_write_config_byte);
EXPORT_SYMBOL(pci_bus_write_config_word);
EXPORT_SYMBOL(pci_bus_write_config_dword);

static u32 pci_user_cached_config(struct pci_dev *dev, int pos)
{
u32 data;

data = dev->saved_config_space[pos/sizeof(dev->saved_config_space[0])];
data >>= (pos % sizeof(dev->saved_config_space[0])) * 8;
return data;
}

#define PCI_USER_READ_CONFIG(size,type) \
int pci_user_read_config_##size \
(struct pci_dev *dev, int pos, type *val) \
{ \
unsigned long flags; \
int ret = 0; \
u32 data = -1; \
if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
spin_lock_irqsave(&pci_lock, flags); \
if (likely(!dev->block_ucfg_access)) \
ret = dev->bus->ops->read(dev->bus, dev->devfn, \
pos, sizeof(type), &data); \
else if (pos < sizeof(dev->saved_config_space)) \
data = pci_user_cached_config(dev, pos); \
spin_unlock_irqrestore(&pci_lock, flags); \
*val = (type)data; \
return ret; \
}

#define PCI_USER_WRITE_CONFIG(size,type) \
int pci_user_write_config_##size \
(struct pci_dev *dev, int pos, type val) \
{ \
unsigned long flags; \
int ret = -EIO; \
if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \
spin_lock_irqsave(&pci_lock, flags); \
if (likely(!dev->block_ucfg_access)) \
ret = dev->bus->ops->write(dev->bus, dev->devfn, \
pos, sizeof(type), val); \
spin_unlock_irqrestore(&pci_lock, flags); \
return ret; \
}

PCI_USER_READ_CONFIG(byte, u8)
PCI_USER_READ_CONFIG(word, u16)
PCI_USER_READ_CONFIG(dword, u32)
PCI_USER_WRITE_CONFIG(byte, u8)
PCI_USER_WRITE_CONFIG(word, u16)
PCI_USER_WRITE_CONFIG(dword, u32)

/**
* pci_block_user_cfg_access - Block userspace PCI config reads/writes
* @dev: pci device struct
*
* This function blocks any userspace PCI config accesses from occurring.
* When blocked, any writes will be bit bucketed and reads will return the
* data saved using pci_save_state for the first 64 bytes of config
* space and return 0xff for all other config reads.
**/
void pci_block_user_cfg_access(struct pci_dev *dev)
{
unsigned long flags;

pci_save_state(dev);

/* spinlock to synchronize with anyone reading config space now */
spin_lock_irqsave(&pci_lock, flags);
dev->block_ucfg_access = 1;
spin_unlock_irqrestore(&pci_lock, flags);
}
EXPORT_SYMBOL_GPL(pci_block_user_cfg_access);

/**
* pci_unblock_user_cfg_access - Unblock userspace PCI config reads/writes
* @dev: pci device struct
*
* This function allows userspace PCI config accesses to resume.
**/
void pci_unblock_user_cfg_access(struct pci_dev *dev)
{
unsigned long flags;

/* spinlock to synchronize with anyone reading saved config space */
spin_lock_irqsave(&pci_lock, flags);
dev->block_ucfg_access = 0;
spin_unlock_irqrestore(&pci_lock, flags);
}
EXPORT_SYMBOL_GPL(pci_unblock_user_cfg_access);
8 changes: 8 additions & 0 deletions drivers/pci/hotplug/acpiphp_glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ static LIST_HEAD(bridge_list);

static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
static void handle_hotplug_event_func (acpi_handle, u32, void *);
static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus);


/*
* initialization & terminatation routines
Expand Down Expand Up @@ -796,8 +799,13 @@ static int enable_device(struct acpiphp_slot *slot)
}
}

pci_bus_size_bridges(bus);
pci_bus_assign_resources(bus);
acpiphp_sanitize_bus(bus);
pci_enable_bridges(bus);
pci_bus_add_devices(bus);
acpiphp_set_hpp_values(DEVICE_ACPI_HANDLE(&bus->self->dev), bus);
acpiphp_configure_ioapics(DEVICE_ACPI_HANDLE(&bus->self->dev));

/* associate pci_dev to our representation */
list_for_each (l, &slot->funcs) {
Expand Down
25 changes: 21 additions & 4 deletions drivers/pci/hotplug/cpcihp_zt5550.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,20 @@ static void __iomem *csr_int_mask;

static int zt5550_hc_config(struct pci_dev *pdev)
{
int ret;

/* Since we know that no boards exist with two HC chips, treat it as an error */
if(hc_dev) {
err("too many host controller devices?");
return -EBUSY;
}

ret = pci_enable_device(pdev);
if(ret) {
err("cannot enable %s\n", pci_name(pdev));
return ret;
}

hc_dev = pdev;
dbg("hc_dev = %p", hc_dev);
dbg("pci resource start %lx", pci_resource_start(hc_dev, 1));
Expand All @@ -91,17 +100,17 @@ static int zt5550_hc_config(struct pci_dev *pdev)
if(!request_mem_region(pci_resource_start(hc_dev, 1),
pci_resource_len(hc_dev, 1), MY_NAME)) {
err("cannot reserve MMIO region");
return -ENOMEM;
ret = -ENOMEM;
goto exit_disable_device;
}

hc_registers =
ioremap(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1));
if(!hc_registers) {
err("cannot remap MMIO region %lx @ %lx",
pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1));
release_mem_region(pci_resource_start(hc_dev, 1),
pci_resource_len(hc_dev, 1));
return -ENODEV;
ret = -ENODEV;
goto exit_release_region;
}

csr_hc_index = hc_registers + CSR_HCINDEX;
Expand All @@ -124,6 +133,13 @@ static int zt5550_hc_config(struct pci_dev *pdev)
writeb((u8) ALL_DIRECT_INTS_MASK, csr_int_mask);
dbg("disabled timer0, timer1 and ENUM interrupts");
return 0;

exit_release_region:
release_mem_region(pci_resource_start(hc_dev, 1),
pci_resource_len(hc_dev, 1));
exit_disable_device:
pci_disable_device(hc_dev);
return ret;
}

static int zt5550_hc_cleanup(void)
Expand All @@ -134,6 +150,7 @@ static int zt5550_hc_cleanup(void)
iounmap(hc_registers);
release_mem_region(pci_resource_start(hc_dev, 1),
pci_resource_len(hc_dev, 1));
pci_disable_device(hc_dev);
return 0;
}

Expand Down
24 changes: 19 additions & 5 deletions drivers/pci/hotplug/cpqphp_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -794,20 +794,30 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
u32 rc;
struct controller *ctrl;
struct pci_func *func;
int err;

err = pci_enable_device(pdev);
if (err) {
printk(KERN_ERR MY_NAME ": cannot enable PCI device %s (%d)\n",
pci_name(pdev), err);
return err;
}

// Need to read VID early b/c it's used to differentiate CPQ and INTC discovery
rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id);
if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) {
err(msg_HPC_non_compaq_or_intel);
return -ENODEV;
rc = -ENODEV;
goto err_disable_device;
}
dbg("Vendor ID: %x\n", vendor_id);

rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
dbg("revision: %d\n", rev);
if (rc || ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!rev))) {
err(msg_HPC_rev_error);
return -ENODEV;
rc = -ENODEV;
goto err_disable_device;
}

/* Check for the proper subsytem ID's
Expand All @@ -820,18 +830,20 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid);
if (rc) {
err("%s : pci_read_config_word failed\n", __FUNCTION__);
return rc;
goto err_disable_device;
}
dbg("Subsystem Vendor ID: %x\n", subsystem_vid);
if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) {
err(msg_HPC_non_compaq_or_intel);
return -ENODEV;
rc = -ENODEV;
goto err_disable_device;
}

ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL);
if (!ctrl) {
err("%s : out of memory\n", __FUNCTION__);
return -ENOMEM;
rc = -ENOMEM;
goto err_disable_device;
}
memset(ctrl, 0, sizeof(struct controller));

Expand Down Expand Up @@ -1264,6 +1276,8 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
kfree(ctrl->pci_bus);
err_free_ctrl:
kfree(ctrl);
err_disable_device:
pci_disable_device(pdev);
return rc;
}

Expand Down
3 changes: 2 additions & 1 deletion drivers/pci/hotplug/rpaphp.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,10 @@ extern struct pci_bus *rpaphp_find_pci_bus(struct device_node *dn);
extern int rpaphp_claim_resource(struct pci_dev *dev, int resource);
extern int rpaphp_enable_pci_slot(struct slot *slot);
extern int register_pci_slot(struct slot *slot);
extern int rpaphp_unconfig_pci_adapter(struct slot *slot);
extern int rpaphp_get_pci_adapter_status(struct slot *slot, int is_init, u8 * value);

extern int rpaphp_config_pci_adapter(struct pci_bus *bus);
extern int rpaphp_unconfig_pci_adapter(struct pci_bus *bus);

/* rpaphp_core.c */
extern int rpaphp_add_slot(struct device_node *dn);
Expand Down
5 changes: 4 additions & 1 deletion drivers/pci/hotplug/rpaphp_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,11 @@ static int disable_slot(struct hotplug_slot *hotplug_slot)

dbg("DISABLING SLOT %s\n", slot->name);
down(&rpaphp_sem);
retval = rpaphp_unconfig_pci_adapter(slot);
retval = rpaphp_unconfig_pci_adapter(slot->bus);
up(&rpaphp_sem);
slot->state = NOT_CONFIGURED;
info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__,
slot->name);
exit:
dbg("%s - Exit: rc[%d]\n", __FUNCTION__, retval);
return retval;
Expand Down
11 changes: 3 additions & 8 deletions drivers/pci/hotplug/rpaphp_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -319,20 +319,15 @@ static void rpaphp_eeh_remove_bus_device(struct pci_dev *dev)
return;
}

int rpaphp_unconfig_pci_adapter(struct slot *slot)
int rpaphp_unconfig_pci_adapter(struct pci_bus *bus)
{
struct pci_dev *dev, *tmp;
int retval = 0;

list_for_each_entry_safe(dev, tmp, slot->pci_devs, bus_list) {
list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) {
rpaphp_eeh_remove_bus_device(dev);
pci_remove_bus_device(dev);
}

slot->state = NOT_CONFIGURED;
info("%s: devices in slot[%s] unconfigured.\n", __FUNCTION__,
slot->name);
return retval;
return 0;
}

static int setup_pci_hotplug_slot_info(struct slot *slot)
Expand Down
Loading

0 comments on commit 7efe5d7

Please sign in to comment.