summaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/Kconfig2
-rw-r--r--drivers/pci/hotplug/Kconfig12
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c12
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c3
-rw-r--r--drivers/pci/hotplug/cpqphp_nvram.c8
-rw-r--r--drivers/pci/hotplug/pciehp.h194
-rw-r--r--drivers/pci/hotplug/pciehp_core.c292
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c223
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c827
-rw-r--r--drivers/pci/hotplug/rpaphp_slot.c47
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c155
-rw-r--r--drivers/pci/hotplug/shpchp.h240
-rw-r--r--drivers/pci/hotplug/shpchp_core.c120
-rw-r--r--drivers/pci/hotplug/shpchp_ctrl.c41
-rw-r--r--drivers/pci/hotplug/shpchp_hpc.c406
-rw-r--r--drivers/pci/htirq.c9
-rw-r--r--drivers/pci/msi.c325
-rw-r--r--drivers/pci/pci-driver.c22
-rw-r--r--drivers/pci/pci.c411
-rw-r--r--drivers/pci/pci.h14
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c2
-rw-r--r--drivers/pci/pcie/portdrv_pci.c2
-rw-r--r--drivers/pci/probe.c80
-rw-r--r--drivers/pci/proc.c8
-rw-r--r--drivers/pci/quirks.c367
-rw-r--r--drivers/pci/search.c94
-rw-r--r--drivers/pci/setup-bus.c2
-rw-r--r--drivers/pci/setup-res.c19
28 files changed, 1786 insertions, 2151 deletions
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index f1dd81a..3cfb0a3 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -19,7 +19,7 @@ config PCI_MSI
config PCI_MULTITHREAD_PROBE
bool "PCI Multi-threaded probe (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ depends on PCI && EXPERIMENTAL && BROKEN
help
Say Y here if you want the PCI core to spawn a new thread for
every PCI device that is probed. This can cause a huge
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index 6e780db..be92695 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -76,7 +76,8 @@ config HOTPLUG_PCI_IBM
config HOTPLUG_PCI_ACPI
tristate "ACPI PCI Hotplug driver"
- depends on (!ACPI_DOCK && ACPI && HOTPLUG_PCI) || (ACPI_DOCK && HOTPLUG_PCI)
+ depends on HOTPLUG_PCI
+ depends on (!ACPI_DOCK && ACPI) || (ACPI_DOCK)
help
Say Y here if you have a system that supports PCI Hotplug using
ACPI.
@@ -144,15 +145,6 @@ config HOTPLUG_PCI_SHPC
When in doubt, say N.
-config HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
- bool "Use polling mechanism for hot-plug events (for testing purpose)"
- depends on HOTPLUG_PCI_SHPC
- help
- Say Y here if you want to use the polling mechanism for hot-plug
- events for early platform testing.
-
- When in doubt, say N.
-
config HOTPLUG_PCI_RPA
tristate "RPA PCI Hotplug driver"
depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 0b9d0db..fca978f 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -773,13 +773,13 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
goto out;
table = obj->buffer.pointer;
- switch (((acpi_table_entry_header *)table)->type) {
- case ACPI_MADT_IOSAPIC:
- *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base;
+ switch (((struct acpi_subtable_header *)table)->type) {
+ case ACPI_MADT_TYPE_IO_SAPIC:
+ *gsi_base = ((struct acpi_madt_io_sapic *)table)->global_irq_base;
result = 0;
break;
- case ACPI_MADT_IOAPIC:
- *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base;
+ case ACPI_MADT_TYPE_IO_APIC:
+ *gsi_base = ((struct acpi_madt_io_apic *)table)->global_irq_base;
result = 0;
break;
default:
@@ -1682,7 +1682,7 @@ int __init acpiphp_glue_init(void)
*
* This function frees all data allocated in acpiphp_glue_init()
*/
-void __exit acpiphp_glue_exit(void)
+void acpiphp_glue_exit(void)
{
acpi_pci_unregister_driver(&acpi_pci_hp_driver);
}
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index bd40aee..7f03881 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -319,13 +319,12 @@ static int ibm_get_table_from_acpi(char **bufp)
if (bufp == NULL)
goto read_table_done;
- lbuf = kmalloc(size, GFP_KERNEL);
+ lbuf = kzalloc(size, GFP_KERNEL);
dbg("%s: element count: %i, ASL table size: %i, &table = 0x%p\n",
__FUNCTION__, package->package.count, size, lbuf);
if (lbuf) {
*bufp = lbuf;
- memset(lbuf, 0, size);
} else {
size = -ENOMEM;
goto read_table_done;
diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c
index 298a6cf..ae5e974 100644
--- a/drivers/pci/hotplug/cpqphp_nvram.c
+++ b/drivers/pci/hotplug/cpqphp_nvram.c
@@ -520,7 +520,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
return 2;
while (nummem--) {
- mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
if (!mem_node)
break;
@@ -548,7 +548,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
}
while (numpmem--) {
- p_mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ p_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
if (!p_mem_node)
break;
@@ -576,7 +576,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
}
while (numio--) {
- io_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ io_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
if (!io_node)
break;
@@ -604,7 +604,7 @@ int compaq_nvram_load (void __iomem *rom_start, struct controller *ctrl)
}
while (numbus--) {
- bus_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
+ bus_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
if (!bus_node)
break;
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 4fb12fc..d19fcae 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -44,15 +44,20 @@ extern int pciehp_poll_time;
extern int pciehp_debug;
extern int pciehp_force;
-/*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
-#define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
-#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
-
+#define dbg(format, arg...) \
+ do { \
+ if (pciehp_debug) \
+ printk("%s: " format, MY_NAME , ## arg); \
+ } while (0)
+#define err(format, arg...) \
+ printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) \
+ printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) \
+ printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+#define SLOT_NAME_SIZE 10
struct slot {
- struct slot *next;
u8 bus;
u8 device;
u32 number;
@@ -63,6 +68,8 @@ struct slot {
struct hpc_ops *hpc_ops;
struct hotplug_slot *hotplug_slot;
struct list_head slot_list;
+ char name[SLOT_NAME_SIZE];
+ unsigned long last_emi_toggle;
};
struct event_info {
@@ -70,34 +77,15 @@ struct event_info {
u8 hp_slot;
};
-typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id);
-
-struct php_ctlr_state_s {
- struct php_ctlr_state_s *pnext;
- struct pci_dev *pci_dev;
- unsigned int irq;
- unsigned long flags; /* spinlock's */
- u32 slot_device_offset;
- u32 num_slots;
- struct timer_list int_poll_timer; /* Added for poll event */
- php_intr_callback_t attention_button_callback;
- php_intr_callback_t switch_change_callback;
- php_intr_callback_t presence_change_callback;
- php_intr_callback_t power_fault_callback;
- void *callback_instance_id;
- struct ctrl_reg *creg; /* Ptr to controller register space */
-};
-
#define MAX_EVENTS 10
struct controller {
struct controller *next;
struct mutex crit_sect; /* critical section mutex */
struct mutex ctrl_lock; /* controller lock */
- struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
int num_slots; /* Number of slots on ctlr */
int slot_num_inc; /* 1 or -1 */
struct pci_dev *pci_dev;
- struct pci_bus *pci_bus;
+ struct list_head slot_list;
struct event_info event_queue[MAX_EVENTS];
struct slot *slot;
struct hpc_ops *hpc_ops;
@@ -112,6 +100,8 @@ struct controller {
u8 ctrlcap;
u16 vendor_id;
u8 cap_base;
+ struct timer_list poll_timer;
+ volatile int cmd_busy;
};
#define INT_BUTTON_IGNORE 0
@@ -131,8 +121,6 @@ struct controller {
#define POWERON_STATE 3
#define POWEROFF_STATE 4
-#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400
-
/* Error messages */
#define INTERLOCK_OPEN 0x00000002
#define ADD_NOT_SUPPORTED 0x00000003
@@ -144,10 +132,6 @@ struct controller {
#define WRONG_BUS_FREQUENCY 0x0000000D
#define POWER_FAILURE 0x0000000E
-#define REMOVE_NOT_SUPPORTED 0x00000003
-
-#define DISABLE_CARD 1
-
/* Field definitions in Slot Capabilities Register */
#define ATTN_BUTTN_PRSN 0x00000001
#define PWR_CTRL_PRSN 0x00000002
@@ -155,6 +139,7 @@ struct controller {
#define ATTN_LED_PRSN 0x00000008
#define PWR_LED_PRSN 0x00000010
#define HP_SUPR_RM_SUP 0x00000020
+#define EMI_PRSN 0x00020000
#define ATTN_BUTTN(cap) (cap & ATTN_BUTTN_PRSN)
#define POWER_CTRL(cap) (cap & PWR_CTRL_PRSN)
@@ -162,130 +147,65 @@ struct controller {
#define ATTN_LED(cap) (cap & ATTN_LED_PRSN)
#define PWR_LED(cap) (cap & PWR_LED_PRSN)
#define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP)
-
-/*
- * error Messages
- */
-#define msg_initialization_err "Initialization failure, error=%d\n"
-#define msg_button_on "PCI slot #%s - powering on due to button press.\n"
-#define msg_button_off "PCI slot #%s - powering off due to button press.\n"
-#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n"
-#define msg_button_ignore "PCI slot #%s - button press ignored. (action in progress...)\n"
-
-/* controller functions */
-extern int pciehp_event_start_thread (void);
-extern void pciehp_event_stop_thread (void);
-extern int pciehp_enable_slot (struct slot *slot);
-extern int pciehp_disable_slot (struct slot *slot);
-
-extern u8 pciehp_handle_attention_button (u8 hp_slot, void *inst_id);
-extern u8 pciehp_handle_switch_change (u8 hp_slot, void *inst_id);
-extern u8 pciehp_handle_presence_change (u8 hp_slot, void *inst_id);
-extern u8 pciehp_handle_power_fault (u8 hp_slot, void *inst_id);
-/* extern void long_delay (int delay); */
-
-/* pci functions */
-extern int pciehp_configure_device (struct slot *p_slot);
-extern int pciehp_unconfigure_device (struct slot *p_slot);
-
-
+#define EMI(cap) (cap & EMI_PRSN)
+
+extern int pciehp_event_start_thread(void);
+extern void pciehp_event_stop_thread(void);
+extern int pciehp_enable_slot(struct slot *slot);
+extern int pciehp_disable_slot(struct slot *slot);
+extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
+extern int pciehp_configure_device(struct slot *p_slot);
+extern int pciehp_unconfigure_device(struct slot *p_slot);
+int pcie_init(struct controller *ctrl, struct pcie_device *dev);
/* Global variables */
extern struct controller *pciehp_ctrl_list;
-/* Inline functions */
-
static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
{
- struct slot *p_slot, *tmp_slot = NULL;
-
- p_slot = ctrl->slot;
+ struct slot *slot;
- while (p_slot && (p_slot->device != device)) {
- tmp_slot = p_slot;
- p_slot = p_slot->next;
+ list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
+ if (slot->device == device)
+ return slot;
}
- if (p_slot == NULL) {
- err("ERROR: pciehp_find_slot device=0x%x\n", device);
- p_slot = tmp_slot;
- }
-
- return p_slot;
-}
-
-static inline int wait_for_ctrl_irq(struct controller *ctrl)
-{
- int retval = 0;
-
- DECLARE_WAITQUEUE(wait, current);
-
- add_wait_queue(&ctrl->queue, &wait);
- if (!pciehp_poll_mode)
- /* Sleep for up to 1 second */
- msleep_interruptible(1000);
- else
- msleep_interruptible(2500);
-
- remove_wait_queue(&ctrl->queue, &wait);
- if (signal_pending(current))
- retval = -EINTR;
-
- return retval;
-}
-
-#define SLOT_NAME_SIZE 10
-static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
-{
- snprintf(buffer, buffer_size, "%04d_%04d", slot->bus, slot->number);
+ err("%s: slot (device=0x%x) not found\n", __FUNCTION__, device);
+ return NULL;
}
-enum php_ctlr_type {
- PCI,
- ISA,
- ACPI
-};
-
-int pcie_init(struct controller *ctrl, struct pcie_device *dev);
-
-/* This has no meaning for PCI Express, as there is only 1 slot per port */
-int pcie_get_ctlr_slot_config(struct controller *ctrl,
- int *num_ctlr_slots,
- int *first_device_num,
- int *physical_slot_num,
- u8 *ctrlcap);
-
struct hpc_ops {
- int (*power_on_slot) (struct slot *slot);
- int (*power_off_slot) (struct slot *slot);
- int (*get_power_status) (struct slot *slot, u8 *status);
- int (*get_attention_status) (struct slot *slot, u8 *status);
- int (*set_attention_status) (struct slot *slot, u8 status);
- int (*get_latch_status) (struct slot *slot, u8 *status);
- int (*get_adapter_status) (struct slot *slot, u8 *status);
-
- int (*get_max_bus_speed) (struct slot *slot, enum pci_bus_speed *speed);
- int (*get_cur_bus_speed) (struct slot *slot, enum pci_bus_speed *speed);
-
- int (*get_max_lnk_width) (struct slot *slot, enum pcie_link_width *value);
- int (*get_cur_lnk_width) (struct slot *slot, enum pcie_link_width *value);
-
- int (*query_power_fault) (struct slot *slot);
- void (*green_led_on) (struct slot *slot);
- void (*green_led_off) (struct slot *slot);
- void (*green_led_blink) (struct slot *slot);
- void (*release_ctlr) (struct controller *ctrl);
- int (*check_lnk_status) (struct controller *ctrl);
+ int (*power_on_slot)(struct slot *slot);
+ int (*power_off_slot)(struct slot *slot);
+ int (*get_power_status)(struct slot *slot, u8 *status);
+ int (*get_attention_status)(struct slot *slot, u8 *status);
+ int (*set_attention_status)(struct slot *slot, u8 status);
+ int (*get_latch_status)(struct slot *slot, u8 *status);
+ int (*get_adapter_status)(struct slot *slot, u8 *status);
+ int (*get_emi_status)(struct slot *slot, u8 *status);
+ int (*toggle_emi)(struct slot *slot);
+ int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
+ int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
+ int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val);
+ int (*get_cur_lnk_width)(struct slot *slot, enum pcie_link_width *val);
+ int (*query_power_fault)(struct slot *slot);
+ void (*green_led_on)(struct slot *slot);
+ void (*green_led_off)(struct slot *slot);
+ void (*green_led_blink)(struct slot *slot);
+ void (*release_ctlr)(struct controller *ctrl);
+ int (*check_lnk_status)(struct controller *ctrl);
};
-
#ifdef CONFIG_ACPI
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/actypes.h>
#include <linux/pci-acpi.h>
-#define pciehp_get_hp_hw_control_from_firmware(dev) \
+#define pciehp_get_hp_hw_control_from_firmware(dev) \
pciehp_acpi_get_hp_hw_control_from_firmware(dev)
static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
struct hotplug_params *hpp)
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index f13f313..a92eda6 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -34,6 +34,7 @@
#include <linux/pci.h>
#include "pciehp.h"
#include <linux/interrupt.h>
+#include <linux/time.h>
/* Global variables */
int pciehp_debug;
@@ -87,6 +88,95 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
.get_cur_bus_speed = get_cur_bus_speed,
};
+/*
+ * Check the status of the Electro Mechanical Interlock (EMI)
+ */
+static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+ struct slot *slot = hotplug_slot->private;
+ return (slot->hpc_ops->get_emi_status(slot, value));
+}
+
+/*
+ * sysfs interface for the Electro Mechanical Interlock (EMI)
+ * 1 == locked, 0 == unlocked
+ */
+static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf)
+{
+ int retval;
+ u8 value;
+
+ retval = get_lock_status(slot, &value);
+ if (retval)
+ goto lock_read_exit;
+ retval = sprintf (buf, "%d\n", value);
+
+lock_read_exit:
+ return retval;
+}
+
+/*
+ * Change the status of the Electro Mechanical Interlock (EMI)
+ * This is a toggle - in addition there must be at least 1 second
+ * in between toggles.
+ */
+static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status)
+{
+ struct slot *slot = hotplug_slot->private;
+ int retval;
+ u8 value;
+
+ mutex_lock(&slot->ctrl->crit_sect);
+
+ /* has it been >1 sec since our last toggle? */
+ if ((get_seconds() - slot->last_emi_toggle) < 1)
+ return -EINVAL;
+
+ /* see what our current state is */
+ retval = get_lock_status(hotplug_slot, &value);
+ if (retval || (value == status))
+ goto set_lock_exit;
+
+ slot->hpc_ops->toggle_emi(slot);
+set_lock_exit:
+ mutex_unlock(&slot->ctrl->crit_sect);
+ return 0;
+}
+
+/*
+ * sysfs interface which allows the user to toggle the Electro Mechanical
+ * Interlock. Valid values are either 0 or 1. 0 == unlock, 1 == lock
+ */
+static ssize_t lock_write_file(struct hotplug_slot *slot, const char *buf,
+ size_t count)
+{
+ unsigned long llock;
+ u8 lock;
+ int retval = 0;
+
+ llock = simple_strtoul(buf, NULL, 10);
+ lock = (u8)(llock & 0xff);
+
+ switch (lock) {
+ case 0:
+ case 1:
+ retval = set_lock_status(slot, lock);
+ break;
+ default:
+ err ("%d is an invalid lock value\n", lock);
+ retval = -EINVAL;
+ }
+ if (retval)
+ return retval;
+ return count;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_lock = {
+ .attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+ .show = lock_read_file,
+ .store = lock_write_file
+};
+
/**
* release_slot - free up the memory used by a slot
* @hotplug_slot: slot to free
@@ -98,148 +188,108 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
kfree(slot->hotplug_slot->info);
- kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
kfree(slot);
}
+static void make_slot_name(struct slot *slot)
+{
+ snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
+ slot->bus, slot->number);
+}
+
static int init_slots(struct controller *ctrl)
{
struct slot *slot;
- struct hpc_ops *hpc_ops;
struct hotplug_slot *hotplug_slot;
- struct hotplug_slot_info *hotplug_slot_info;
- u8 number_of_slots;
- u8 slot_device;
- u32 slot_number;
- int result = -ENOMEM;
+ struct hotplug_slot_info *info;
+ int retval = -ENOMEM;
+ int i;
- number_of_slots = ctrl->num_slots;
- slot_device = ctrl->slot_device_offset;
- slot_number = ctrl->first_slot;
-
- while (number_of_slots) {
+ for (i = 0; i < ctrl->num_slots; i++) {
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
if (!slot)
goto error;
- slot->hotplug_slot =
- kzalloc(sizeof(*(slot->hotplug_slot)),
- GFP_KERNEL);
- if (!slot->hotplug_slot)
+ hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
+ if (!hotplug_slot)
goto error_slot;
- hotplug_slot = slot->hotplug_slot;
+ slot->hotplug_slot = hotplug_slot;
- hotplug_slot->info =
- kzalloc(sizeof(*(hotplug_slot->info)),
- GFP_KERNEL);
- if (!hotplug_slot->info)
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
goto error_hpslot;
- hotplug_slot_info = hotplug_slot->info;
- hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
- if (!hotplug_slot->name)
- goto error_info;
+ hotplug_slot->info = info;
- slot->ctrl = ctrl;
- slot->bus = ctrl->slot_bus;
- slot->device = slot_device;
- slot->hpc_ops = hpc_ops = ctrl->hpc_ops;
+ hotplug_slot->name = slot->name;
+ slot->hp_slot = i;
+ slot->ctrl = ctrl;
+ slot->bus = ctrl->pci_dev->subordinate->number;
+ slot->device = ctrl->slot_device_offset + i;
+ slot->hpc_ops = ctrl->hpc_ops;
slot->number = ctrl->first_slot;
- slot->hp_slot = slot_device - ctrl->slot_device_offset;
/* register this slot with the hotplug pci core */
hotplug_slot->private = slot;
hotplug_slot->release = &release_slot;
- make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot);
+ make_slot_name(slot);
hotplug_slot->ops = &pciehp_hotplug_slot_ops;
- hpc_ops->get_power_status(slot,
- &(hotplug_slot_info->power_status));
- hpc_ops->get_attention_status(slot,
- &(hotplug_slot_info->attention_status));
- hpc_ops->get_latch_status(slot,
- &(hotplug_slot_info->latch_status));
- hpc_ops->get_adapter_status(slot,
- &(hotplug_slot_info->adapter_status));
+ get_power_status(hotplug_slot, &info->power_status);
+ get_attention_status(hotplug_slot, &info->attention_status);
+ get_latch_status(hotplug_slot, &info->latch_status);
+ get_adapter_status(hotplug_slot, &info->adapter_status);
dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
- "slot_device_offset=%x\n",
- slot->bus, slot->device, slot->hp_slot, slot->number,
- ctrl->slot_device_offset);
- result = pci_hp_register(hotplug_slot);
- if (result) {
- err ("pci_hp_register failed with error %d\n", result);
- goto error_name;
+ "slot_device_offset=%x\n", slot->bus, slot->device,
+ slot->hp_slot, slot->number, ctrl->slot_device_offset);
+ retval = pci_hp_register(hotplug_slot);
+ if (retval) {
+ err ("pci_hp_register failed with error %d\n", retval);
+ goto error_info;
+ }
+ /* create additional sysfs entries */
+ if (EMI(ctrl->ctrlcap)) {
+ retval = sysfs_create_file(&hotplug_slot->kobj,
+ &hotplug_slot_attr_lock.attr);
+ if (retval) {
+ pci_hp_deregister(hotplug_slot);
+ err("cannot create additional sysfs entries\n");
+ goto error_info;
+ }
}
- slot->next = ctrl->slot;
- ctrl->slot = slot;
-
- number_of_slots--;
- slot_device++;
- slot_number += ctrl->slot_num_inc;
+ list_add(&slot->slot_list, &ctrl->slot_list);
}
return 0;
-
-error_name:
- kfree(hotplug_slot->name);
error_info:
- kfree(hotplug_slot_info);
+ kfree(info);
error_hpslot:
kfree(hotplug_slot);
error_slot:
kfree(slot);
error:
- return result;
-}
-
-
-static int cleanup_slots (struct controller * ctrl)
-{
- struct slot *old_slot, *next_slot;
-
- old_slot = ctrl->slot;
- ctrl->slot = NULL;
-
- while (old_slot) {
- next_slot = old_slot->next;
- pci_hp_deregister (old_slot->hotplug_slot);
- old_slot = next_slot;
- }
-
-
- return(0);
+ return retval;
}
-static int get_ctlr_slot_config(struct controller *ctrl)
+static void cleanup_slots(struct controller *ctrl)
{
- int num_ctlr_slots; /* Not needed; PCI Express has 1 slot per port*/
- int first_device_num; /* Not needed */
- int physical_slot_num;
- u8 ctrlcap;
- int rc;
+ struct list_head *tmp;
+ struct list_head *next;
+ struct slot *slot;
- rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &ctrlcap);
- if (rc) {
- err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device);
- return (-1);
+ list_for_each_safe(tmp, next, &ctrl->slot_list) {
+ slot = list_entry(tmp, struct slot, slot_list);
+ list_del(&slot->slot_list);
+ if (EMI(ctrl->ctrlcap))
+ sysfs_remove_file(&slot->hotplug_slot->kobj,
+ &hotplug_slot_attr_lock.attr);
+ pci_hp_deregister(slot->hotplug_slot);
}
-
- ctrl->num_slots = num_ctlr_slots; /* PCI Express has 1 slot per port */
- ctrl->slot_device_offset = first_device_num;
- ctrl->first_slot = physical_slot_num;
- ctrl->ctrlcap = ctrlcap;
-
- dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) ctrlcap(%x) for b:d (%x:%x)\n",
- __FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, ctrlcap,
- ctrl->bus, ctrl->device);
-
- return (0);
}
-
/*
* set_attention_status - Turns the Amber LED for a slot on, off or blink
*/
@@ -378,8 +428,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
int rc;
struct controller *ctrl;
struct slot *t_slot;
- int first_device_num = 0 ; /* first PCI device number supported by this PCIE */
- int num_ctlr_slots; /* number of slots supported by this HPC */
u8 value;
struct pci_dev *pdev;
@@ -388,6 +436,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
err("%s : out of memory\n", __FUNCTION__);
goto err_out_none;
}
+ INIT_LIST_HEAD(&ctrl->slot_list);
pdev = dev->port;
ctrl->pci_dev = pdev;
@@ -400,13 +449,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
pci_set_drvdata(pdev, ctrl);
- ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL);
- if (!ctrl->pci_bus) {
- err("%s: out of memory\n", __FUNCTION__);
- rc = -ENOMEM;
- goto err_out_unmap_mmio_region;
- }
- memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus));
ctrl->bus = pdev->bus->number; /* ctrl bus */
ctrl->slot_bus = pdev->subordinate->number; /* bus controlled by this HPC */
@@ -415,26 +457,14 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__,
ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
- /*
- * Save configuration headers for this and subordinate PCI buses
- */
-
- rc = get_ctlr_slot_config(ctrl);
- if (rc) {
- err(msg_initialization_err, rc);
- goto err_out_free_ctrl_bus;
- }
- first_device_num = ctrl->slot_device_offset;
- num_ctlr_slots = ctrl->num_slots;
-
/* Setup the slot information structures */
rc = init_slots(ctrl);
if (rc) {
- err(msg_initialization_err, 6);
- goto err_out_free_ctrl_slot;
+ err("%s: slot initialization failed\n", PCIE_MODULE_NAME);
+ goto err_out_release_ctlr;
}
- t_slot = pciehp_find_slot(ctrl, first_device_num);
+ t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
/* Finish setting up the hot plug ctrl device */
ctrl->next_event = 0;
@@ -447,32 +477,18 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
pciehp_ctrl_list = ctrl;
}
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
-
if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
- if (rc) {
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
+ if (rc)
goto err_out_free_ctrl_slot;
- } else
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
}
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
-
return 0;
err_out_free_ctrl_slot:
cleanup_slots(ctrl);
-err_out_free_ctrl_bus:
- kfree(ctrl->pci_bus);
-err_out_unmap_mmio_region:
+err_out_release_ctlr:
ctrl->hpc_ops->release_ctlr(ctrl);
err_out_free_ctrl:
kfree(ctrl);
@@ -506,8 +522,6 @@ static void __exit unload_pciehpd(void)
while (ctrl) {
cleanup_slots(ctrl);
- kfree (ctrl->pci_bus);
-
ctrl->hpc_ops->release_ctlr(ctrl);
tctrl = ctrl;
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 372c63e..4283ef5 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -48,9 +48,8 @@ static inline char *slot_name(struct slot *p_slot)
return p_slot->hotplug_slot->name;
}
-u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 rc = 0;
u8 getstatus;
@@ -101,9 +100,8 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
}
-u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 rc = 0;
u8 getstatus;
@@ -143,9 +141,8 @@ u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
return rc;
}
-u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 presence_save, rc = 0;
struct event_info *taskInfo;
@@ -187,9 +184,8 @@ u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
return rc;
}
-u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 rc = 0;
struct event_info *taskInfo;
@@ -233,35 +229,25 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
static void set_slot_off(struct controller *ctrl, struct slot * pslot)
{
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
if (POWER_CTRL(ctrl->ctrlcap)) {
if (pslot->hpc_ops->power_off_slot(pslot)) {
- err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
- mutex_unlock(&ctrl->ctrl_lock);
+ err("%s: Issue of Slot Power Off command failed\n",
+ __FUNCTION__);
return;
}
- wait_for_ctrl_irq (ctrl);
}
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
pslot->hpc_ops->green_led_off(pslot);
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)) {
- if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
- err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
- mutex_unlock(&ctrl->ctrl_lock);
+ if (ATTN_LED(ctrl->ctrlcap)) {
+ if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
+ err("%s: Issue of Set Attention Led command failed\n",
+ __FUNCTION__);
return;
}
- wait_for_ctrl_irq (ctrl);
}
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
}
/**
@@ -274,7 +260,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
static int board_added(struct slot *p_slot)
{
u8 hp_slot;
- int rc = 0;
+ int retval = 0;
struct controller *ctrl = p_slot->ctrl;
hp_slot = p_slot->device - ctrl->slot_device_offset;
@@ -283,53 +269,38 @@ static int board_added(struct slot *p_slot)
__FUNCTION__, p_slot->device,
ctrl->slot_device_offset, hp_slot);
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
if (POWER_CTRL(ctrl->ctrlcap)) {
/* Power on slot */
- rc = p_slot->hpc_ops->power_on_slot(p_slot);
- if (rc) {
- mutex_unlock(&ctrl->ctrl_lock);
- return -1;
- }
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
+ retval = p_slot->hpc_ops->power_on_slot(p_slot);
+ if (retval)
+ return retval;
}
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_blink(p_slot);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
/* Wait for ~1 second */
- wait_for_ctrl_irq (ctrl);
+ msleep(1000);
- /* Check link training status */
- rc = p_slot->hpc_ops->check_lnk_status(ctrl);
- if (rc) {
+ /* Check link training status */
+ retval = p_slot->hpc_ops->check_lnk_status(ctrl);
+ if (retval) {
err("%s: Failed to check link status\n", __FUNCTION__);
set_slot_off(ctrl, p_slot);
- return rc;
+ return retval;
}
/* Check for a power fault */
if (p_slot->hpc_ops->query_power_fault(p_slot)) {
dbg("%s: power fault detected\n", __FUNCTION__);
- rc = POWER_FAILURE;
+ retval = POWER_FAILURE;
goto err_exit;
}
- rc = pciehp_configure_device(p_slot);
- if (rc) {
+ retval = pciehp_configure_device(p_slot);
+ if (retval) {
err("Cannot add device 0x%x:%x\n", p_slot->bus,
- p_slot->device);
+ p_slot->device);
goto err_exit;
}
@@ -338,26 +309,16 @@ static int board_added(struct slot *p_slot)
*/
if (pcie_mch_quirk)
pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
- if (PWR_LED(ctrl->ctrlcap)) {
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_on(p_slot);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
- }
+
return 0;
err_exit:
set_slot_off(ctrl, p_slot);
- return -1;
+ return retval;
}
-
/**
* remove_board - Turns off slot and LED's
*
@@ -366,44 +327,32 @@ static int remove_board(struct slot *p_slot)
{
u8 device;
u8 hp_slot;
- int rc;
+ int retval = 0;
struct controller *ctrl = p_slot->ctrl;
- if (pciehp_unconfigure_device(p_slot))
- return 1;
+ retval = pciehp_unconfigure_device(p_slot);
+ if (retval)
+ return retval;
device = p_slot->device;
-
hp_slot = p_slot->device - ctrl->slot_device_offset;
p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
if (POWER_CTRL(ctrl->ctrlcap)) {
/* power off slot */
- rc = p_slot->hpc_ops->power_off_slot(p_slot);
- if (rc) {
- err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
- mutex_unlock(&ctrl->ctrl_lock);
- return rc;
+ retval = p_slot->hpc_ops->power_off_slot(p_slot);
+ if (retval) {
+ err("%s: Issue of Slot Disable command failed\n",
+ __FUNCTION__);
+ return retval;
}
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
}
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
/* turn off Green LED */
p_slot->hpc_ops->green_led_off(p_slot);
-
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
return 0;
}
@@ -448,18 +397,10 @@ static void pciehp_pushbutton_thread(unsigned long slot)
dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__,
p_slot->bus, p_slot->device);
- if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
- /* Wait for exclusive access to hardware */
- mutex_lock(&p_slot->ctrl->ctrl_lock);
-
+ if (pciehp_enable_slot(p_slot) &&
+ PWR_LED(p_slot->ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (p_slot->ctrl);
-
- /* Done with exclusive hardware access */
- mutex_unlock(&p_slot->ctrl->ctrl_lock);
- }
p_slot->state = STATIC_STATE;
}
@@ -498,18 +439,10 @@ static void pciehp_surprise_rm_thread(unsigned long slot)
dbg("%s: adding bus:device(%x:%x)\n",
__FUNCTION__, p_slot->bus, p_slot->device);
- if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
- /* Wait for exclusive access to hardware */
- mutex_lock(&p_slot->ctrl->ctrl_lock);
-
+ if (pciehp_enable_slot(p_slot) &&
+ PWR_LED(p_slot->ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (p_slot->ctrl);
-
- /* Done with exclusive hardware access */
- mutex_unlock(&p_slot->ctrl->ctrl_lock);
- }
p_slot->state = STATIC_STATE;
}
@@ -620,46 +553,24 @@ static void interrupt_event_handler(struct controller *ctrl)
switch (p_slot->state) {
case BLINKINGOFF_STATE:
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_on(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)) {
- p_slot->hpc_ops->set_attention_status(p_slot, 0);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
+ if (ATTN_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->set_attention_status(p_slot, 0);
break;
case BLINKINGON_STATE:
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)){
- p_slot->hpc_ops->set_attention_status(p_slot, 0);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
+ if (ATTN_LED(ctrl->ctrlcap))
+ p_slot->hpc_ops->set_attention_status(p_slot, 0);
break;
default:
warn("Not a valid state\n");
return;
}
- info(msg_button_cancel, slot_name(p_slot));
+ info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot));
p_slot->state = STATIC_STATE;
}
/* ***********Button Pressed (No action on 1st press...) */
@@ -672,34 +583,21 @@ static void interrupt_event_handler(struct controller *ctrl)
/* slot is on */
dbg("slot is on\n");
p_slot->state = BLINKINGOFF_STATE;
- info(msg_button_off, slot_name(p_slot));
+ info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot));
} else {
/* slot is off */
dbg("slot is off\n");
p_slot->state = BLINKINGON_STATE;
- info(msg_button_on, slot_name(p_slot));
+ info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot));
}
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
/* blink green LED and turn off amber */
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_blink(p_slot);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
- if (ATTN_LED(ctrl->ctrlcap)) {
+ if (ATTN_LED(ctrl->ctrlcap))
p_slot->hpc_ops->set_attention_status(p_slot, 0);
- /* Wait for the command to complete */
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
-
init_timer(&p_slot->task_event);
p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
@@ -712,21 +610,11 @@ static void interrupt_event_handler(struct controller *ctrl)
else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
if (POWER_CTRL(ctrl->ctrlcap)) {
dbg("power fault\n");
- /* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->ctrl_lock);
-
- if (ATTN_LED(ctrl->ctrlcap)) {
+ if (ATTN_LED(ctrl->ctrlcap))
p_slot->hpc_ops->set_attention_status(p_slot, 1);
- wait_for_ctrl_irq (ctrl);
- }
- if (PWR_LED(ctrl->ctrlcap)) {
+ if (PWR_LED(ctrl->ctrlcap))
p_slot->hpc_ops->green_led_off(p_slot);
- wait_for_ctrl_irq (ctrl);
- }
-
- /* Done with exclusive hardware access */
- mutex_unlock(&ctrl->ctrl_lock);
}
}
/***********SURPRISE REMOVAL********************/
@@ -754,7 +642,6 @@ static void interrupt_event_handler(struct controller *ctrl)
}
}
-
int pciehp_enable_slot(struct slot *p_slot)
{
u8 getstatus = 0;
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 6d3f580..fbc64aa 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -35,6 +35,7 @@
#include <linux/timer.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/time.h>
#include "../pci.h"
#include "pciehp.h"
@@ -105,34 +106,30 @@ enum ctrl_offsets {
ROOTCTRL = offsetof(struct ctrl_reg, root_ctrl),
ROOTSTATUS = offsetof(struct ctrl_reg, root_status),
};
-static int pcie_cap_base = 0; /* Base of the PCI Express capability item structure */
-
-#define PCIE_CAP_ID(cb) ( cb + PCIECAPID )
-#define NXT_CAP_PTR(cb) ( cb + NXTCAPPTR )
-#define CAP_REG(cb) ( cb + CAPREG )
-#define DEV_CAP(cb) ( cb + DEVCAP )
-#define DEV_CTRL(cb) ( cb + DEVCTRL )
-#define DEV_STATUS(cb) ( cb + DEVSTATUS )
-#define LNK_CAP(cb) ( cb + LNKCAP )
-#define LNK_CTRL(cb) ( cb + LNKCTRL )
-#define LNK_STATUS(cb) ( cb + LNKSTATUS )
-#define SLOT_CAP(cb) ( cb + SLOTCAP )
-#define SLOT_CTRL(cb) ( cb + SLOTCTRL )
-#define SLOT_STATUS(cb) ( cb + SLOTSTATUS )
-#define ROOT_CTRL(cb) ( cb + ROOTCTRL )
-#define ROOT_STATUS(cb) ( cb + ROOTSTATUS )
-
-#define hp_register_read_word(pdev, reg , value) \
- pci_read_config_word(pdev, reg, &value)
-
-#define hp_register_read_dword(pdev, reg , value) \
- pci_read_config_dword(pdev, reg, &value)
-
-#define hp_register_write_word(pdev, reg , value) \
- pci_write_config_word(pdev, reg, value)
-
-#define hp_register_dwrite_word(pdev, reg , value) \
- pci_write_config_dword(pdev, reg, value)
+
+static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_read_config_word(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_read_config_dword(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_write_config_word(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
+{
+ struct pci_dev *dev = ctrl->pci_dev;
+ return pci_write_config_dword(dev, ctrl->cap_base + reg, value);
+}
/* Field definitions in PCI Express Capabilities Register */
#define CAP_VER 0x000F
@@ -196,6 +193,7 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct
#define ATTN_LED_CTRL 0x00C0
#define PWR_LED_CTRL 0x0300
#define PWR_CTRL 0x0400
+#define EMI_CTRL 0x0800
/* Attention indicator and Power indicator states */
#define LED_ON 0x01
@@ -206,6 +204,10 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct
#define POWER_ON 0
#define POWER_OFF 0x0400
+/* EMI Status defines */
+#define EMI_DISENGAGED 0
+#define EMI_ENGAGED 1
+
/* Field definitions in Slot Status Register */
#define ATTN_BUTTN_PRESSED 0x0001
#define PWR_FAULT_DETECTED 0x0002
@@ -214,114 +216,117 @@ static int pcie_cap_base = 0; /* Base of the PCI Express capability item struct
#define CMD_COMPLETED 0x0010
#define MRL_STATE 0x0020
#define PRSN_STATE 0x0040
+#define EMI_STATE 0x0080
+#define EMI_STATUS_BIT 7
static spinlock_t hpc_event_lock;
DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
-static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */
static int ctlr_seq_num = 0; /* Controller sequence # */
-static spinlock_t list_lock;
-
-static irqreturn_t pcie_isr(int IRQ, void *dev_id);
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+static irqreturn_t pcie_isr(int irq, void *dev_id);
+static void start_int_poll_timer(struct controller *ctrl, int sec);
/* This is the interrupt polling timeout function. */
-static void int_poll_timeout(unsigned long lphp_ctlr)
+static void int_poll_timeout(unsigned long data)
{
- struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
+ struct controller *ctrl = (struct controller *)data;
DBG_ENTER_ROUTINE
- if ( !php_ctlr ) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return;
- }
-
/* Poll for interrupt events. regs == NULL => polling */
- pcie_isr( 0, (void *)php_ctlr );
-
- init_timer(&php_ctlr->int_poll_timer);
+ pcie_isr(0, ctrl);
+ init_timer(&ctrl->poll_timer);
if (!pciehp_poll_time)
pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
- start_int_poll_timer(php_ctlr, pciehp_poll_time);
-
- return;
+ start_int_poll_timer(ctrl, pciehp_poll_time);
}
/* This function starts the interrupt polling timer. */
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
+static void start_int_poll_timer(struct controller *ctrl, int sec)
{
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return;
- }
+ /* Clamp to sane value */
+ if ((sec <= 0) || (sec > 60))
+ sec = 2;
+
+ ctrl->poll_timer.function = &int_poll_timeout;
+ ctrl->poll_timer.data = (unsigned long)ctrl;
+ ctrl->poll_timer.expires = jiffies + sec * HZ;
+ add_timer(&ctrl->poll_timer);
+}
- if ( ( seconds <= 0 ) || ( seconds > 60 ) )
- seconds = 2; /* Clamp to sane value */
+static inline int pcie_wait_cmd(struct controller *ctrl)
+{
+ int retval = 0;
+ unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
+ unsigned long timeout = msecs_to_jiffies(msecs);
+ int rc;
- php_ctlr->int_poll_timer.function = &int_poll_timeout;
- php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr; /* Instance data */
- php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;
- add_timer(&php_ctlr->int_poll_timer);
+ rc = wait_event_interruptible_timeout(ctrl->queue,
+ !ctrl->cmd_busy, timeout);
+ if (!rc)
+ dbg("Command not completed in 1000 msec\n");
+ else if (rc < 0) {
+ retval = -EINTR;
+ info("Command was interrupted by a signal\n");
+ }
- return;
+ return retval;
}
static int pcie_write_cmd(struct slot *slot, u16 cmd)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
int retval = 0;
u16 slot_status;
DBG_ENTER_ROUTINE
-
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
+ mutex_lock(&ctrl->ctrl_lock);
+
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
- return retval;
- }
-
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+ goto out;
+ }
+
if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
- /* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue
- the next command according to spec. Just print out the error message */
- dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__);
+ /* After 1 sec and CMD_COMPLETED still not set, just
+ proceed forward to issue the next command according
+ to spec. Just print out the error message */
+ dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",
+ __FUNCTION__);
}
- retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), cmd | CMD_CMPL_INTR_ENABLE);
+ ctrl->cmd_busy = 1;
+ retval = pciehp_writew(ctrl, SLOTCTRL, (cmd | CMD_CMPL_INTR_ENABLE));
if (retval) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
- return retval;
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
+ goto out;
}
+ /*
+ * Wait for command completion.
+ */
+ retval = pcie_wait_cmd(ctrl);
+ out:
+ mutex_unlock(&ctrl->ctrl_lock);
DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_check_lnk_status(struct controller *ctrl)
{
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
u16 lnk_status;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(ctrl->cap_base), lnk_status);
-
+ retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -340,26 +345,21 @@ static int hpc_check_lnk_status(struct controller *ctrl)
static int hpc_get_attention_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_ctrl;
u8 atten_led_state;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
- dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ dbg("%s: SLOTCTRL %x, value read %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6;
@@ -385,27 +385,22 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
return 0;
}
-static int hpc_get_power_status(struct slot * slot, u8 *status)
+static int hpc_get_power_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_ctrl;
u8 pwr_state;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
- dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ dbg("%s: SLOTCTRL %x value read %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
pwr_state = (slot_ctrl & PWR_CTRL) >> 10;
@@ -428,21 +423,15 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
static int hpc_get_latch_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_status;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -454,22 +443,16 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status)
static int hpc_get_adapter_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_status;
u8 card_state;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return retval;
}
card_state = (u8)((slot_status & PRSN_STATE) >> 6);
@@ -479,24 +462,18 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
return 0;
}
-static int hpc_query_power_fault(struct slot * slot)
+static int hpc_query_power_fault(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_status;
u8 pwr_fault;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (retval) {
- err("%s : Cannot check for power fault\n", __FUNCTION__);
+ err("%s: Cannot check for power fault\n", __FUNCTION__);
return retval;
}
pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
@@ -505,28 +482,63 @@ static int hpc_query_power_fault(struct slot * slot)
return pwr_fault;
}
-static int hpc_set_attention_status(struct slot *slot, u8 value)
+static int hpc_get_emi_status(struct slot *slot, u8 *status)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
+ u16 slot_status;
+ int retval = 0;
+
+ DBG_ENTER_ROUTINE
+
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ if (retval) {
+ err("%s : Cannot check EMI status\n", __FUNCTION__);
+ return retval;
+ }
+ *status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;
+
+ DBG_LEAVE_ROUTINE
+ return retval;
+}
+
+static int hpc_toggle_emi(struct slot *slot)
+{
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd = 0;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
+ if (rc) {
+ err("%s : hp_register_read_word SLOT_CTRL failed\n",
+ __FUNCTION__);
+ return rc;
}
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ slot_cmd = (slot_ctrl | EMI_CTRL);
+ if (!pciehp_poll_mode)
+ slot_cmd = slot_cmd | HP_INTR_ENABLE;
+ pcie_write_cmd(slot, slot_cmd);
+ slot->last_emi_toggle = get_seconds();
+ DBG_LEAVE_ROUTINE
+ return rc;
+}
+
+static int hpc_set_attention_status(struct slot *slot, u8 value)
+{
+ struct controller *ctrl = slot->ctrl;
+ u16 slot_cmd = 0;
+ u16 slot_ctrl;
+ int rc = 0;
+
+ DBG_ENTER_ROUTINE
+
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return rc;
}
@@ -547,7 +559,8 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
slot_cmd = slot_cmd | HP_INTR_ENABLE;
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return rc;
@@ -556,27 +569,16 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
static void hpc_set_green_led_on(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return ;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return;
}
slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100;
@@ -585,34 +587,24 @@ static void hpc_set_green_led_on(struct slot *slot)
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return;
}
static void hpc_set_green_led_off(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return ;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return;
}
@@ -621,7 +613,8 @@ static void hpc_set_green_led_off(struct slot *slot)
if (!pciehp_poll_mode)
slot_cmd = slot_cmd | HP_INTR_ENABLE;
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return;
@@ -629,27 +622,16 @@ static void hpc_set_green_led_off(struct slot *slot)
static void hpc_set_green_led_blink(struct slot *slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
int rc = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return ;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return;
}
@@ -659,126 +641,54 @@ static void hpc_set_green_led_blink(struct slot *slot)
slot_cmd = slot_cmd | HP_INTR_ENABLE;
pcie_write_cmd(slot, slot_cmd);
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return;
}
-int pcie_get_ctlr_slot_config(struct controller *ctrl,
- int *num_ctlr_slots, /* number of slots in this HPC; only 1 in PCIE */
- int *first_device_num, /* PCI dev num of the first slot in this PCIE */
- int *physical_slot_num, /* phy slot num of the first slot in this PCIE */
- u8 *ctrlcap)
-{
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
- u32 slot_cap;
- int rc = 0;
-
- DBG_ENTER_ROUTINE
-
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- *first_device_num = 0;
- *num_ctlr_slots = 1;
-
- rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
-
- if (rc) {
- err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__);
- return -1;
- }
-
- *physical_slot_num = slot_cap >> 19;
- dbg("%s: PSN %d \n", __FUNCTION__, *physical_slot_num);
-
- *ctrlcap = slot_cap & 0x0000007f;
-
- DBG_LEAVE_ROUTINE
- return 0;
-}
-
static void hpc_release_ctlr(struct controller *ctrl)
{
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
- struct php_ctlr_state_s *p, *p_prev;
-
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return ;
- }
-
- if (pciehp_poll_mode) {
- del_timer(&php_ctlr->int_poll_timer);
- } else {
- if (php_ctlr->irq) {
- free_irq(php_ctlr->irq, ctrl);
- php_ctlr->irq = 0;
- }
- }
- if (php_ctlr->pci_dev)
- php_ctlr->pci_dev = NULL;
-
- spin_lock(&list_lock);
- p = php_ctlr_list_head;
- p_prev = NULL;
- while (p) {
- if (p == php_ctlr) {
- if (p_prev)
- p_prev->pnext = p->pnext;
- else
- php_ctlr_list_head = p->pnext;
- break;
- } else {
- p_prev = p;
- p = p->pnext;
- }
- }
- spin_unlock(&list_lock);
-
- kfree(php_ctlr);
+ if (pciehp_poll_mode)
+ del_timer(&ctrl->poll_timer);
+ else
+ free_irq(ctrl->pci_dev->irq, ctrl);
DBG_LEAVE_ROUTINE
-
}
static int hpc_power_on_slot(struct slot * slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl, slot_status;
-
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
/* Clear sticky power-fault bit from previous power failures */
- hp_register_read_word(php_ctlr->pci_dev,
- SLOT_STATUS(slot->ctrl->cap_base), slot_status);
+ retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+ if (retval) {
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+ return retval;
+ }
slot_status &= PWR_FAULT_DETECTED;
- if (slot_status)
- hp_register_write_word(php_ctlr->pci_dev,
- SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ if (slot_status) {
+ retval = pciehp_writew(ctrl, SLOTSTATUS, slot_status);
+ if (retval) {
+ err("%s: Cannot write to SLOTSTATUS register\n",
+ __FUNCTION__);
+ return retval;
+ }
+ }
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
@@ -798,7 +708,8 @@ static int hpc_power_on_slot(struct slot * slot)
err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd);
return -1;
}
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
@@ -807,29 +718,18 @@ static int hpc_power_on_slot(struct slot * slot)
static int hpc_power_off_slot(struct slot * slot)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
u16 slot_cmd;
u16 slot_ctrl;
-
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
- slot->hp_slot = 0;
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
- retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+ retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
return retval;
}
@@ -854,47 +754,25 @@ static int hpc_power_off_slot(struct slot * slot)
err("%s: Write command failed!\n", __FUNCTION__);
return -1;
}
- dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+ dbg("%s: SLOTCTRL %x write cmd %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
DBG_LEAVE_ROUTINE
return retval;
}
-static irqreturn_t pcie_isr(int IRQ, void *dev_id)
+static irqreturn_t pcie_isr(int irq, void *dev_id)
{
- struct controller *ctrl = NULL;
- struct php_ctlr_state_s *php_ctlr;
- u8 schedule_flag = 0;
+ struct controller *ctrl = (struct controller *)dev_id;
u16 slot_status, intr_detect, intr_loc;
u16 temp_word;
int hp_slot = 0; /* only 1 slot per PCI Express port */
int rc = 0;
- if (!dev_id)
- return IRQ_NONE;
-
- if (!pciehp_poll_mode) {
- ctrl = dev_id;
- php_ctlr = ctrl->hpc_ctlr_handle;
- } else {
- php_ctlr = dev_id;
- ctrl = (struct controller *)php_ctlr->callback_instance_id;
- }
-
- if (!ctrl) {
- dbg("%s: dev_id %p ctlr == NULL\n", __FUNCTION__, (void*) dev_id);
- return IRQ_NONE;
- }
-
- if (!php_ctlr) {
- dbg("%s: php_ctlr == NULL\n", __FUNCTION__);
- return IRQ_NONE;
- }
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
return IRQ_NONE;
}
@@ -910,33 +788,38 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
/* Mask Hot-plug Interrupt Enable */
if (!pciehp_poll_mode) {
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOT_CTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
- dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
+ dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n",
+ __FUNCTION__, temp_word);
temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
-
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOT_STATUS register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
- dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status);
+ dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n",
+ __FUNCTION__, slot_status);
/* Clear command complete interrupt caused by this write */
temp_word = 0x1f;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
}
@@ -945,60 +828,65 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
/*
* Command Complete Interrupt Pending
*/
+ ctrl->cmd_busy = 0;
wake_up_interruptible(&ctrl->queue);
}
- if ((php_ctlr->switch_change_callback) && (intr_loc & MRL_SENS_CHANGED))
- schedule_flag += php_ctlr->switch_change_callback(
- hp_slot, php_ctlr->callback_instance_id);
- if ((php_ctlr->attention_button_callback) && (intr_loc & ATTN_BUTTN_PRESSED))
- schedule_flag += php_ctlr->attention_button_callback(
- hp_slot, php_ctlr->callback_instance_id);
- if ((php_ctlr->presence_change_callback) && (intr_loc & PRSN_DETECT_CHANGED))
- schedule_flag += php_ctlr->presence_change_callback(
- hp_slot , php_ctlr->callback_instance_id);
- if ((php_ctlr->power_fault_callback) && (intr_loc & PWR_FAULT_DETECTED))
- schedule_flag += php_ctlr->power_fault_callback(
- hp_slot, php_ctlr->callback_instance_id);
+ if (intr_loc & MRL_SENS_CHANGED)
+ pciehp_handle_switch_change(hp_slot, ctrl);
+
+ if (intr_loc & ATTN_BUTTN_PRESSED)
+ pciehp_handle_attention_button(hp_slot, ctrl);
+
+ if (intr_loc & PRSN_DETECT_CHANGED)
+ pciehp_handle_presence_change(hp_slot, ctrl);
+
+ if (intr_loc & PWR_FAULT_DETECTED)
+ pciehp_handle_power_fault(hp_slot, ctrl);
/* Clear all events after serving them */
temp_word = 0x1F;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
return IRQ_NONE;
}
/* Unmask Hot-plug Interrupt Enable */
if (!pciehp_poll_mode) {
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__);
temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
-
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOT_STATUS register\n",
+ __FUNCTION__);
return IRQ_NONE;
}
/* Clear command complete interrupt caused by this write */
temp_word = 0x1F;
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS failed\n",
+ __FUNCTION__);
return IRQ_NONE;
}
- dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word);
+ dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
+ __FUNCTION__, temp_word);
}
return IRQ_HANDLED;
@@ -1006,27 +894,16 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_speed lnk_speed;
u32 lnk_cap;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
-
+ retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
- err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
return retval;
}
@@ -1047,27 +924,16 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_width lnk_wdth;
u32 lnk_cap;
int retval = 0;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
-
+ retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
if (retval) {
- err("%s : hp_register_read_dword LNK_CAP failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
return retval;
}
@@ -1109,27 +975,16 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value
static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
int retval = 0;
u16 lnk_status;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
-
+ retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -1150,27 +1005,16 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
{
- struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+ struct controller *ctrl = slot->ctrl;
enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
int retval = 0;
u16 lnk_status;
DBG_ENTER_ROUTINE
- if (!php_ctlr) {
- err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
- return -1;
- }
-
- if (slot->hp_slot >= php_ctlr->num_slots) {
- err("%s: Invalid HPC slot number!\n", __FUNCTION__);
- return -1;
- }
-
- retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
-
+ retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
if (retval) {
- err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
return retval;
}
@@ -1218,6 +1062,8 @@ static struct hpc_ops pciehp_hpc_ops = {
.get_attention_status = hpc_get_attention_status,
.get_latch_status = hpc_get_latch_status,
.get_adapter_status = hpc_get_adapter_status,
+ .get_emi_status = hpc_get_emi_status,
+ .toggle_emi = hpc_toggle_emi,
.get_max_bus_speed = hpc_get_max_lnk_speed,
.get_cur_bus_speed = hpc_get_cur_lnk_speed,
@@ -1305,38 +1151,24 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
int pcie_init(struct controller * ctrl, struct pcie_device *dev)
{
- struct php_ctlr_state_s *php_ctlr, *p;
- void *instance_id = ctrl;
int rc;
static int first = 1;
u16 temp_word;
u16 cap_reg;
u16 intr_enable = 0;
u32 slot_cap;
- int cap_base, saved_cap_base;
+ int cap_base;
u16 slot_status, slot_ctrl;
struct pci_dev *pdev;
DBG_ENTER_ROUTINE
- spin_lock_init(&list_lock);
- php_ctlr = (struct php_ctlr_state_s *) kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
-
- if (!php_ctlr) { /* allocate controller state data */
- err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
- goto abort;
- }
-
- memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
-
pdev = dev->port;
- php_ctlr->pci_dev = pdev; /* save pci_dev in context */
+ ctrl->pci_dev = pdev; /* save pci_dev in context */
dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n",
__FUNCTION__, pdev->vendor, pdev->device);
- saved_cap_base = pcie_cap_base;
-
if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) {
dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__);
goto abort_free_ctlr;
@@ -1344,14 +1176,15 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
ctrl->cap_base = cap_base;
- dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base);
+ dbg("%s: pcie_cap_base %x\n", __FUNCTION__, cap_base);
- rc = hp_register_read_word(pdev, CAP_REG(ctrl->cap_base), cap_reg);
+ rc = pciehp_readw(ctrl, CAPREG, &cap_reg);
if (rc) {
- err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+ err("%s: Cannot read CAPREG register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG(ctrl->cap_base), cap_reg);
+ dbg("%s: CAPREG offset %x cap_reg %x\n",
+ __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040)
&& ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
@@ -1359,31 +1192,34 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
goto abort_free_ctlr;
}
- rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
+ rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
if (rc) {
- err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP(ctrl->cap_base), slot_cap);
+ dbg("%s: SLOTCAP offset %x slot_cap %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap);
if (!(slot_cap & HP_CAP)) {
dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
goto abort_free_ctlr;
}
/* For debugging purpose */
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), slot_status);
+ dbg("%s: SLOTSTATUS offset %x slot_status %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status);
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
+ dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
if (first) {
spin_lock_init(&hpc_event_lock);
@@ -1405,69 +1241,64 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
/* setup wait queue */
init_waitqueue_head(&ctrl->queue);
- /* find the IRQ */
- php_ctlr->irq = dev->irq;
-
- /* Save interrupt callback info */
- php_ctlr->attention_button_callback = pciehp_handle_attention_button;
- php_ctlr->switch_change_callback = pciehp_handle_switch_change;
- php_ctlr->presence_change_callback = pciehp_handle_presence_change;
- php_ctlr->power_fault_callback = pciehp_handle_power_fault;
- php_ctlr->callback_instance_id = instance_id;
-
/* return PCI Controller Info */
- php_ctlr->slot_device_offset = 0;
- php_ctlr->num_slots = 1;
+ ctrl->slot_device_offset = 0;
+ ctrl->num_slots = 1;
+ ctrl->first_slot = slot_cap >> 19;
+ ctrl->ctrlcap = slot_cap & 0x0000007f;
/* Mask Hot-plug Interrupt Enable */
- rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word);
+ dbg("%s: SLOTCTRL %x value read %x\n",
+ __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
- rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_free_ctlr;
}
temp_word = 0x1F; /* Clear all events */
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
goto abort_free_ctlr;
}
- if (pciehp_poll_mode) {/* Install interrupt polling code */
- /* Install and start the interrupt polling timer */
- init_timer(&php_ctlr->int_poll_timer);
- start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */
+ if (pciehp_poll_mode) {
+ /* Install interrupt polling timer. Start with 10 sec delay */
+ init_timer(&ctrl->poll_timer);
+ start_int_poll_timer(ctrl, 10);
} else {
/* Installs the interrupt handler */
- rc = request_irq(php_ctlr->irq, pcie_isr, IRQF_SHARED, MY_NAME, (void *) ctrl);
- dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
+ rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED,
+ MY_NAME, (void *)ctrl);
+ dbg("%s: request_irq %d for hpc%d (returns %d)\n",
+ __FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc);
if (rc) {
- err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
+ err("Can't get irq %d for the hotplug controller\n",
+ ctrl->pci_dev->irq);
goto abort_free_ctlr;
}
}
-
dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
- rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (rc) {
- err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
goto abort_free_irq;
}
@@ -1491,21 +1322,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
}
/* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
- rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
goto abort_free_irq;
}
- rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+ rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
if (rc) {
- err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
goto abort_disable_intr;
}
temp_word = 0x1F; /* Clear all events */
- rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
if (rc) {
- err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
goto abort_disable_intr;
}
@@ -1518,24 +1349,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
goto abort_disable_intr;
}
- /* Add this HPC instance into the HPC list */
- spin_lock(&list_lock);
- if (php_ctlr_list_head == 0) {
- php_ctlr_list_head = php_ctlr;
- p = php_ctlr_list_head;
- p->pnext = NULL;
- } else {
- p = php_ctlr_list_head;
-
- while (p->pnext)
- p = p->pnext;
-
- p->pnext = php_ctlr;
- }
- spin_unlock(&list_lock);
-
ctlr_seq_num++;
- ctrl->hpc_ctlr_handle = php_ctlr;
ctrl->hpc_ops = &pciehp_hpc_ops;
DBG_LEAVE_ROUTINE
@@ -1543,24 +1357,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
/* We end up here for the many possible ways to fail this API. */
abort_disable_intr:
- rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
if (!rc) {
temp_word &= ~(intr_enable | HP_INTR_ENABLE);
- rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+ rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
}
if (rc)
err("%s : disabling interrupts failed\n", __FUNCTION__);
abort_free_irq:
if (pciehp_poll_mode)
- del_timer_sync(&php_ctlr->int_poll_timer);
+ del_timer_sync(&ctrl->poll_timer);
else
- free_irq(php_ctlr->irq, ctrl);
+ free_irq(ctrl->pci_dev->irq, ctrl);
abort_free_ctlr:
- pcie_cap_base = saved_cap_base;
- kfree(php_ctlr);
-abort:
DBG_LEAVE_ROUTINE
return -1;
}
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
index b771196..3009193 100644
--- a/drivers/pci/hotplug/rpaphp_slot.c
+++ b/drivers/pci/hotplug/rpaphp_slot.c
@@ -47,21 +47,11 @@ static ssize_t location_read_file (struct hotplug_slot *php_slot, char *buf)
return retval;
}
-static struct hotplug_slot_attribute hotplug_slot_attr_location = {
+static struct hotplug_slot_attribute php_attr_location = {
.attr = {.name = "phy_location", .mode = S_IFREG | S_IRUGO},
.show = location_read_file,
};
-static void rpaphp_sysfs_add_attr_location (struct hotplug_slot *slot)
-{
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_location.attr);
-}
-
-static void rpaphp_sysfs_remove_attr_location (struct hotplug_slot *slot)
-{
- sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_location.attr);
-}
-
/* free up the memory used by a slot */
static void rpaphp_release_slot(struct hotplug_slot *hotplug_slot)
{
@@ -145,7 +135,7 @@ int rpaphp_deregister_slot(struct slot *slot)
list_del(&slot->rpaphp_slot_list);
/* remove "phy_location" file */
- rpaphp_sysfs_remove_attr_location(php_slot);
+ sysfs_remove_file(&php_slot->kobj, &php_attr_location.attr);
retval = pci_hp_deregister(php_slot);
if (retval)
@@ -160,36 +150,45 @@ EXPORT_SYMBOL_GPL(rpaphp_deregister_slot);
int rpaphp_register_slot(struct slot *slot)
{
+ struct hotplug_slot *php_slot = slot->hotplug_slot;
int retval;
dbg("%s registering slot:path[%s] index[%x], name[%s] pdomain[%x] type[%d]\n",
__FUNCTION__, slot->dn->full_name, slot->index, slot->name,
slot->power_domain, slot->type);
+
/* should not try to register the same slot twice */
- if (is_registered(slot)) { /* should't be here */
+ if (is_registered(slot)) {
err("rpaphp_register_slot: slot[%s] is already registered\n", slot->name);
- rpaphp_release_slot(slot->hotplug_slot);
- return -EAGAIN;
+ retval = -EAGAIN;
+ goto register_fail;
}
- retval = pci_hp_register(slot->hotplug_slot);
+
+ retval = pci_hp_register(php_slot);
if (retval) {
err("pci_hp_register failed with error %d\n", retval);
- rpaphp_release_slot(slot->hotplug_slot);
- return retval;
+ goto register_fail;
}
-
- /* create "phy_locatoin" file */
- rpaphp_sysfs_add_attr_location(slot->hotplug_slot);
- /* add slot to our internal list */
- dbg("%s adding slot[%s] to rpaphp_slot_list\n",
- __FUNCTION__, slot->name);
+ /* create "phy_location" file */
+ retval = sysfs_create_file(&php_slot->kobj, &php_attr_location.attr);
+ if (retval) {
+ err("sysfs_create_file failed with error %d\n", retval);
+ goto sysfs_fail;
+ }
+ /* add slot to our internal list */
list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
info("Slot [%s](PCI location=%s) registered\n", slot->name,
slot->location);
num_slots++;
return 0;
+
+sysfs_fail:
+ pci_hp_deregister(php_slot);
+register_fail:
+ rpaphp_release_slot(php_slot);
+ return retval;
}
int rpaphp_get_power_status(struct slot *slot, u8 * value)
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index 5d188c5..78cf071 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -28,6 +28,8 @@
#include <asm/sn/sn_feature_sets.h>
#include <asm/sn/sn_sal.h>
#include <asm/sn/types.h>
+#include <linux/acpi.h>
+#include <asm/sn/acpi.h>
#include "../pci.h"
@@ -35,14 +37,17 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");
MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver");
-#define PCIIO_ASIC_TYPE_TIOCA 4
+
+/* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */
#define PCI_SLOT_ALREADY_UP 2 /* slot already up */
#define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */
#define PCI_L1_ERR 7 /* L1 console command error */
#define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */
+
+
+#define PCIIO_ASIC_TYPE_TIOCA 4
#define PCI_L1_QSIZE 128 /* our L1 message buffer size */
#define SN_MAX_HP_SLOTS 32 /* max hotplug slots */
-#define SGI_HOTPLUG_PROM_REV 0x0430 /* Min. required PROM version */
#define SN_SLOT_NAME_SIZE 33 /* size of name string */
/* internal list head */
@@ -227,7 +232,7 @@ static void sn_bus_free_data(struct pci_dev *dev)
}
static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
- int device_num)
+ int device_num, char **ssdt)
{
struct slot *slot = bss_hotplug_slot->private;
struct pcibus_info *pcibus_info;
@@ -240,7 +245,8 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
* Power-on and initialize the slot in the SN
* PCI infrastructure.
*/
- rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp);
+ rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt);
+
if (rc == PCI_SLOT_ALREADY_UP) {
dev_dbg(slot->pci_bus->self, "is already active\n");
@@ -335,6 +341,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
int func, num_funcs;
int new_ppb = 0;
int rc;
+ char *ssdt = NULL;
void pcibios_fixup_device_resources(struct pci_dev *);
/* Serialize the Linux PCI infrastructure */
@@ -342,14 +349,29 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
/*
* Power-on and initialize the slot in the SN
- * PCI infrastructure.
+ * PCI infrastructure. Also, retrieve the ACPI SSDT
+ * table for the slot (if ACPI capable PROM).
*/
- rc = sn_slot_enable(bss_hotplug_slot, slot->device_num);
+ rc = sn_slot_enable(bss_hotplug_slot, slot->device_num, &ssdt);
if (rc) {
mutex_unlock(&sn_hotplug_mutex);
return rc;
}
+ if (ssdt)
+ ssdt = __va(ssdt);
+ /* Add the new SSDT for the slot to the ACPI namespace */
+ if (SN_ACPI_BASE_SUPPORT() && ssdt) {
+ acpi_status ret;
+
+ ret = acpi_load_table((struct acpi_table_header *)ssdt);
+ if (ACPI_FAILURE(ret)) {
+ printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n",
+ __FUNCTION__, ret);
+ /* try to continue on */
+ }
+ }
+
num_funcs = pci_scan_slot(slot->pci_bus,
PCI_DEVFN(slot->device_num + 1, 0));
if (!num_funcs) {
@@ -374,7 +396,10 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
* pdi_host_pcidev_info).
*/
pcibios_fixup_device_resources(dev);
- sn_pci_fixup_slot(dev);
+ if (SN_ACPI_BASE_SUPPORT())
+ sn_acpi_slot_fixup(dev);
+ else
+ sn_io_slot_fixup(dev);
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
unsigned char sec_bus;
pci_read_config_byte(dev, PCI_SECONDARY_BUS,
@@ -388,6 +413,63 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
}
}
+ /*
+ * Add the slot's devices to the ACPI infrastructure */
+ if (SN_ACPI_BASE_SUPPORT() && ssdt) {
+ unsigned long adr;
+ struct acpi_device *pdevice;
+ struct acpi_device *device;
+ acpi_handle phandle;
+ acpi_handle chandle = NULL;
+ acpi_handle rethandle;
+ acpi_status ret;
+
+ phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
+
+ if (acpi_bus_get_device(phandle, &pdevice)) {
+ dev_dbg(slot->pci_bus->self,
+ "no parent device, assuming NULL\n");
+ pdevice = NULL;
+ }
+
+ /*
+ * Walk the rootbus node's immediate children looking for
+ * the slot's device node(s). There can be more than
+ * one for multifunction devices.
+ */
+ for (;;) {
+ rethandle = NULL;
+ ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
+ phandle, chandle,
+ &rethandle);
+
+ if (ret == AE_NOT_FOUND || rethandle == NULL)
+ break;
+
+ chandle = rethandle;
+
+ ret = acpi_evaluate_integer(chandle, METHOD_NAME__ADR,
+ NULL, &adr);
+
+ if (ACPI_SUCCESS(ret) &&
+ (adr>>16) == (slot->device_num + 1)) {
+
+ ret = acpi_bus_add(&device, pdevice, chandle,
+ ACPI_BUS_TYPE_DEVICE);
+ if (ACPI_FAILURE(ret)) {
+ printk(KERN_ERR "%s: acpi_bus_add "
+ "failed (0x%x) for slot %d "
+ "func %d\n", __FUNCTION__,
+ ret, (int)(adr>>16),
+ (int)(adr&0xffff));
+ /* try to continue on */
+ } else {
+ acpi_bus_start(device);
+ }
+ }
+ }
+ }
+
/* Call the driver for the new device */
pci_bus_add_devices(slot->pci_bus);
/* Call the drivers for the new devices subordinate to PPB */
@@ -412,6 +494,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
struct pci_dev *dev;
int func;
int rc;
+ acpi_owner_id ssdt_id = 0;
/* Acquire update access to the bus */
mutex_lock(&sn_hotplug_mutex);
@@ -422,6 +505,52 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
if (rc)
goto leaving;
+ /* free the ACPI resources for the slot */
+ if (SN_ACPI_BASE_SUPPORT() &&
+ PCI_CONTROLLER(slot->pci_bus)->acpi_handle) {
+ unsigned long adr;
+ struct acpi_device *device;
+ acpi_handle phandle;
+ acpi_handle chandle = NULL;
+ acpi_handle rethandle;
+ acpi_status ret;
+
+ /* Get the rootbus node pointer */
+ phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
+
+ /*
+ * Walk the rootbus node's immediate children looking for
+ * the slot's device node(s). There can be more than
+ * one for multifunction devices.
+ */
+ for (;;) {
+ rethandle = NULL;
+ ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
+ phandle, chandle,
+ &rethandle);
+
+ if (ret == AE_NOT_FOUND || rethandle == NULL)
+ break;
+
+ chandle = rethandle;
+
+ ret = acpi_evaluate_integer(chandle,
+ METHOD_NAME__ADR,
+ NULL, &adr);
+ if (ACPI_SUCCESS(ret) &&
+ (adr>>16) == (slot->device_num + 1)) {
+ /* retain the owner id */
+ acpi_get_id(chandle, &ssdt_id);
+
+ ret = acpi_bus_get_device(chandle,
+ &device);
+ if (ACPI_SUCCESS(ret))
+ acpi_bus_trim(device, 1);
+ }
+ }
+
+ }
+
/* Free the SN resources assigned to the Linux device.*/
for (func = 0; func < 8; func++) {
dev = pci_get_slot(slot->pci_bus,
@@ -434,6 +563,18 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
}
}
+ /* Remove the SSDT for the slot from the ACPI namespace */
+ if (SN_ACPI_BASE_SUPPORT() && ssdt_id) {
+ acpi_status ret;
+ ret = acpi_unload_table_id(ssdt_id);
+ if (ACPI_FAILURE(ret)) {
+ printk(KERN_ERR "%s: acpi_unload_table_id "
+ "failed (0x%x) for id %d\n",
+ __FUNCTION__, ret, ssdt_id);
+ /* try to continue on */
+ }
+ }
+
/* free the collected sysdata pointers */
sn_bus_free_sysdata();
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 5075769..01d31a1 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -47,11 +47,17 @@ extern int shpchp_poll_time;
extern int shpchp_debug;
extern struct workqueue_struct *shpchp_wq;
-/*#define dbg(format, arg...) do { if (shpchp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
-#define dbg(format, arg...) do { if (shpchp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
-#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
+#define dbg(format, arg...) \
+ do { \
+ if (shpchp_debug) \
+ printk("%s: " format, MY_NAME , ## arg); \
+ } while (0)
+#define err(format, arg...) \
+ printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) \
+ printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...) \
+ printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
#define SLOT_NAME_SIZE 10
struct slot {
@@ -83,34 +89,27 @@ struct event_info {
struct controller {
struct mutex crit_sect; /* critical section mutex */
struct mutex cmd_lock; /* command lock */
- struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
int num_slots; /* Number of slots on ctlr */
int slot_num_inc; /* 1 or -1 */
struct pci_dev *pci_dev;
struct list_head slot_list;
struct hpc_ops *hpc_ops;
wait_queue_head_t queue; /* sleep & wake process */
- u8 bus;
- u8 device;
- u8 function;
u8 slot_device_offset;
- u8 add_support;
u32 pcix_misc2_reg; /* for amd pogo errata */
- enum pci_bus_speed speed;
u32 first_slot; /* First physical slot number */
- u8 slot_bus; /* Bus where the slots handled by this controller sit */
u32 cap_offset;
unsigned long mmio_base;
unsigned long mmio_size;
+ void __iomem *creg;
+ struct timer_list poll_timer;
};
-
/* Define AMD SHPC ID */
-#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450
+#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450
#define PCI_DEVICE_ID_AMD_POGO_7458 0x7458
/* AMD PCIX bridge registers */
-
#define PCIX_MEM_BASE_LIMIT_OFFSET 0x1C
#define PCIX_MISCII_OFFSET 0x48
#define PCIX_MISC_BRIDGE_ERRORS_OFFSET 0x80
@@ -145,8 +144,6 @@ struct controller {
#define POWERON_STATE 3
#define POWEROFF_STATE 4
-#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400
-
/* Error messages */
#define INTERLOCK_OPEN 0x00000002
#define ADD_NOT_SUPPORTED 0x00000003
@@ -158,50 +155,32 @@ struct controller {
#define WRONG_BUS_FREQUENCY 0x0000000D
#define POWER_FAILURE 0x0000000E
-#define REMOVE_NOT_SUPPORTED 0x00000003
-
-#define DISABLE_CARD 1
-
-/*
- * error Messages
- */
-#define msg_initialization_err "Initialization failure, error=%d\n"
-#define msg_button_on "PCI slot #%s - powering on due to button press.\n"
-#define msg_button_off "PCI slot #%s - powering off due to button press.\n"
-#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n"
-
-/* sysfs functions for the hotplug controller info */
extern int __must_check shpchp_create_ctrl_files(struct controller *ctrl);
-
-extern int shpchp_sysfs_enable_slot(struct slot *slot);
-extern int shpchp_sysfs_disable_slot(struct slot *slot);
-
-extern u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id);
-extern u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id);
-extern u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id);
-extern u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id);
-
-/* pci functions */
-extern int shpchp_save_config(struct controller *ctrl, int busnumber, int num_ctlr_slots, int first_device_num);
-extern int shpchp_configure_device(struct slot *p_slot);
-extern int shpchp_unconfigure_device(struct slot *p_slot);
-extern void shpchp_remove_ctrl_files(struct controller *ctrl);
-extern void cleanup_slots(struct controller *ctrl);
-extern void queue_pushbutton_work(struct work_struct *work);
-
+extern void shpchp_remove_ctrl_files(struct controller *ctrl);
+extern int shpchp_sysfs_enable_slot(struct slot *slot);
+extern int shpchp_sysfs_disable_slot(struct slot *slot);
+extern u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
+extern u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
+extern u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
+extern u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
+extern int shpchp_configure_device(struct slot *p_slot);
+extern int shpchp_unconfigure_device(struct slot *p_slot);
+extern void cleanup_slots(struct controller *ctrl);
+extern void queue_pushbutton_work(struct work_struct *work);
+extern int shpc_init( struct controller *ctrl, struct pci_dev *pdev);
#ifdef CONFIG_ACPI
static inline int get_hp_params_from_firmware(struct pci_dev *dev,
- struct hotplug_params *hpp)
+ struct hotplug_params *hpp)
{
if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev->bus, hpp)))
return -ENODEV;
return 0;
}
-#define get_hp_hw_control_from_firmware(pdev) \
- do { \
- if (DEVICE_ACPI_HANDLE(&(pdev->dev))) \
- acpi_run_oshp(DEVICE_ACPI_HANDLE(&(pdev->dev))); \
+#define get_hp_hw_control_from_firmware(pdev) \
+ do { \
+ if (DEVICE_ACPI_HANDLE(&(pdev->dev))) \
+ acpi_run_oshp(DEVICE_ACPI_HANDLE(&(pdev->dev)));\
} while (0)
#else
#define get_hp_params_from_firmware(dev, hpp) (-ENODEV)
@@ -222,108 +201,40 @@ struct ctrl_reg {
volatile u32 serr_loc;
volatile u32 serr_intr_enable;
volatile u32 slot1;
- volatile u32 slot2;
- volatile u32 slot3;
- volatile u32 slot4;
- volatile u32 slot5;
- volatile u32 slot6;
- volatile u32 slot7;
- volatile u32 slot8;
- volatile u32 slot9;
- volatile u32 slot10;
- volatile u32 slot11;
- volatile u32 slot12;
} __attribute__ ((packed));
/* offsets to the controller registers based on the above structure layout */
enum ctrl_offsets {
- BASE_OFFSET = offsetof(struct ctrl_reg, base_offset),
- SLOT_AVAIL1 = offsetof(struct ctrl_reg, slot_avail1),
- SLOT_AVAIL2 = offsetof(struct ctrl_reg, slot_avail2),
- SLOT_CONFIG = offsetof(struct ctrl_reg, slot_config),
- SEC_BUS_CONFIG = offsetof(struct ctrl_reg, sec_bus_config),
- MSI_CTRL = offsetof(struct ctrl_reg, msi_ctrl),
- PROG_INTERFACE = offsetof(struct ctrl_reg, prog_interface),
- CMD = offsetof(struct ctrl_reg, cmd),
- CMD_STATUS = offsetof(struct ctrl_reg, cmd_status),
- INTR_LOC = offsetof(struct ctrl_reg, intr_loc),
- SERR_LOC = offsetof(struct ctrl_reg, serr_loc),
- SERR_INTR_ENABLE = offsetof(struct ctrl_reg, serr_intr_enable),
- SLOT1 = offsetof(struct ctrl_reg, slot1),
- SLOT2 = offsetof(struct ctrl_reg, slot2),
- SLOT3 = offsetof(struct ctrl_reg, slot3),
- SLOT4 = offsetof(struct ctrl_reg, slot4),
- SLOT5 = offsetof(struct ctrl_reg, slot5),
- SLOT6 = offsetof(struct ctrl_reg, slot6),
- SLOT7 = offsetof(struct ctrl_reg, slot7),
- SLOT8 = offsetof(struct ctrl_reg, slot8),
- SLOT9 = offsetof(struct ctrl_reg, slot9),
- SLOT10 = offsetof(struct ctrl_reg, slot10),
- SLOT11 = offsetof(struct ctrl_reg, slot11),
- SLOT12 = offsetof(struct ctrl_reg, slot12),
-};
-typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id);
-struct php_ctlr_state_s {
- struct php_ctlr_state_s *pnext;
- struct pci_dev *pci_dev;
- unsigned int irq;
- unsigned long flags; /* spinlock's */
- u32 slot_device_offset;
- u32 num_slots;
- struct timer_list int_poll_timer; /* Added for poll event */
- php_intr_callback_t attention_button_callback;
- php_intr_callback_t switch_change_callback;
- php_intr_callback_t presence_change_callback;
- php_intr_callback_t power_fault_callback;
- void *callback_instance_id;
- void __iomem *creg; /* Ptr to controller register space */
+ BASE_OFFSET = offsetof(struct ctrl_reg, base_offset),
+ SLOT_AVAIL1 = offsetof(struct ctrl_reg, slot_avail1),
+ SLOT_AVAIL2 = offsetof(struct ctrl_reg, slot_avail2),
+ SLOT_CONFIG = offsetof(struct ctrl_reg, slot_config),
+ SEC_BUS_CONFIG = offsetof(struct ctrl_reg, sec_bus_config),
+ MSI_CTRL = offsetof(struct ctrl_reg, msi_ctrl),
+ PROG_INTERFACE = offsetof(struct ctrl_reg, prog_interface),
+ CMD = offsetof(struct ctrl_reg, cmd),
+ CMD_STATUS = offsetof(struct ctrl_reg, cmd_status),
+ INTR_LOC = offsetof(struct ctrl_reg, intr_loc),
+ SERR_LOC = offsetof(struct ctrl_reg, serr_loc),
+ SERR_INTR_ENABLE = offsetof(struct ctrl_reg, serr_intr_enable),
+ SLOT1 = offsetof(struct ctrl_reg, slot1),
};
-/* Inline functions */
-
-/* Inline functions to check the sanity of a pointer that is passed to us */
-static inline int slot_paranoia_check (struct slot *slot, const char *function)
+static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot)
{
- if (!slot) {
- dbg("%s - slot == NULL", function);
- return -1;
- }
- if (!slot->hotplug_slot) {
- dbg("%s - slot->hotplug_slot == NULL!", function);
- return -1;
- }
- return 0;
-}
-
-static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function)
-{
- struct slot *slot;
-
- if (!hotplug_slot) {
- dbg("%s - hotplug_slot == NULL\n", function);
- return NULL;
- }
-
- slot = (struct slot *)hotplug_slot->private;
- if (slot_paranoia_check (slot, function))
- return NULL;
- return slot;
+ return hotplug_slot->private;
}
-static inline struct slot *shpchp_find_slot (struct controller *ctrl, u8 device)
+static inline struct slot *shpchp_find_slot(struct controller *ctrl, u8 device)
{
struct slot *slot;
- if (!ctrl)
- return NULL;
-
list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
if (slot->device == device)
return slot;
}
err("%s: slot (device=0x%x) not found\n", __FUNCTION__, device);
-
return NULL;
}
@@ -400,44 +311,27 @@ static inline void amd_pogo_errata_restore_misc_reg(struct slot *p_slot)
pci_write_config_dword(p_slot->ctrl->pci_dev, PCIX_MISCII_OFFSET, pcix_misc2_temp);
}
-enum php_ctlr_type {
- PCI,
- ISA,
- ACPI
-};
-
-int shpc_init( struct controller *ctrl, struct pci_dev *pdev);
-
-int shpc_get_ctlr_slot_config( struct controller *ctrl,
- int *num_ctlr_slots,
- int *first_device_num,
- int *physical_slot_num,
- int *updown,
- int *flags);
-
struct hpc_ops {
- int (*power_on_slot ) (struct slot *slot);
- int (*slot_enable ) (struct slot *slot);
- int (*slot_disable ) (struct slot *slot);
- int (*set_bus_speed_mode) (struct slot *slot, enum pci_bus_speed speed);
- int (*get_power_status) (struct slot *slot, u8 *status);
- int (*get_attention_status) (struct slot *slot, u8 *status);
- int (*set_attention_status) (struct slot *slot, u8 status);
- int (*get_latch_status) (struct slot *slot, u8 *status);
- int (*get_adapter_status) (struct slot *slot, u8 *status);
-
- int (*get_max_bus_speed) (struct slot *slot, enum pci_bus_speed *speed);
- int (*get_cur_bus_speed) (struct slot *slot, enum pci_bus_speed *speed);
- int (*get_adapter_speed) (struct slot *slot, enum pci_bus_speed *speed);
- int (*get_mode1_ECC_cap) (struct slot *slot, u8 *mode);
- int (*get_prog_int) (struct slot *slot, u8 *prog_int);
-
- int (*query_power_fault) (struct slot *slot);
- void (*green_led_on) (struct slot *slot);
- void (*green_led_off) (struct slot *slot);
- void (*green_led_blink) (struct slot *slot);
- void (*release_ctlr) (struct controller *ctrl);
- int (*check_cmd_status) (struct controller *ctrl);
+ int (*power_on_slot)(struct slot *slot);
+ int (*slot_enable)(struct slot *slot);
+ int (*slot_disable)(struct slot *slot);
+ int (*set_bus_speed_mode)(struct slot *slot, enum pci_bus_speed speed);
+ int (*get_power_status)(struct slot *slot, u8 *status);
+ int (*get_attention_status)(struct slot *slot, u8 *status);
+ int (*set_attention_status)(struct slot *slot, u8 status);
+ int (*get_latch_status)(struct slot *slot, u8 *status);
+ int (*get_adapter_status)(struct slot *slot, u8 *status);
+ int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
+ int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
+ int (*get_adapter_speed)(struct slot *slot, enum pci_bus_speed *speed);
+ int (*get_mode1_ECC_cap)(struct slot *slot, u8 *mode);
+ int (*get_prog_int)(struct slot *slot, u8 *prog_int);
+ int (*query_power_fault)(struct slot *slot);
+ void (*green_led_on)(struct slot *slot);
+ void (*green_led_off)(struct slot *slot);
+ void (*green_led_blink)(struct slot *slot);
+ void (*release_ctlr)(struct controller *ctrl);
+ int (*check_cmd_status)(struct controller *ctrl);
};
#endif /* _SHPCHP_H */
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 4eac85b..5f4bc08 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -104,23 +104,6 @@ static void make_slot_name(struct slot *slot)
slot->bus, slot->number);
}
-
-
-
-static int
-shpchprm_get_physical_slot_number(struct controller *ctrl, u32 *sun,
- u8 busnum, u8 devnum)
-{
- int offset = devnum - ctrl->slot_device_offset;
-
- dbg("%s: ctrl->slot_num_inc %d, offset %d\n", __FUNCTION__,
- ctrl->slot_num_inc, offset);
- *sun = (u8) (ctrl->first_slot + ctrl->slot_num_inc *offset);
- return 0;
-}
-
-
-
static int init_slots(struct controller *ctrl)
{
struct slot *slot;
@@ -128,7 +111,6 @@ static int init_slots(struct controller *ctrl)
struct hotplug_slot_info *info;
int retval = -ENOMEM;
int i;
- u32 sun;
for (i = 0; i < ctrl->num_slots; i++) {
slot = kzalloc(sizeof(*slot), GFP_KERNEL);
@@ -149,16 +131,11 @@ static int init_slots(struct controller *ctrl)
slot->hp_slot = i;
slot->ctrl = ctrl;
- slot->bus = ctrl->slot_bus;
+ slot->bus = ctrl->pci_dev->subordinate->number;
slot->device = ctrl->slot_device_offset + i;
slot->hpc_ops = ctrl->hpc_ops;
+ slot->number = ctrl->first_slot + (ctrl->slot_num_inc * i);
mutex_init(&slot->lock);
-
- if (shpchprm_get_physical_slot_number(ctrl, &sun,
- slot->bus, slot->device))
- goto error_info;
-
- slot->number = sun;
INIT_DELAYED_WORK(&slot->work, queue_pushbutton_work);
/* register this slot with the hotplug pci core */
@@ -211,42 +188,12 @@ void cleanup_slots(struct controller *ctrl)
}
}
-static int get_ctlr_slot_config(struct controller *ctrl)
-{
- int num_ctlr_slots;
- int first_device_num;
- int physical_slot_num;
- int updown;
- int rc;
- int flags;
-
- rc = shpc_get_ctlr_slot_config(ctrl, &num_ctlr_slots,
- &first_device_num, &physical_slot_num,
- &updown, &flags);
- if (rc) {
- err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n",
- __FUNCTION__, ctrl->bus, ctrl->device);
- return -1;
- }
-
- ctrl->num_slots = num_ctlr_slots;
- ctrl->slot_device_offset = first_device_num;
- ctrl->first_slot = physical_slot_num;
- ctrl->slot_num_inc = updown; /* either -1 or 1 */
-
- dbg("%s: num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) updown(%d) for b:d "
- "(%x:%x)\n", __FUNCTION__, num_ctlr_slots, first_device_num,
- physical_slot_num, updown, ctrl->bus, ctrl->device);
-
- return 0;
-}
-
/*
* set_attention_status - Turns the Amber LED for a slot on, off or blink
*/
static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -258,7 +205,7 @@ static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
static int enable_slot (struct hotplug_slot *hotplug_slot)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -267,7 +214,7 @@ static int enable_slot (struct hotplug_slot *hotplug_slot)
static int disable_slot (struct hotplug_slot *hotplug_slot)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -276,7 +223,7 @@ static int disable_slot (struct hotplug_slot *hotplug_slot)
static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -290,7 +237,7 @@ static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -304,7 +251,7 @@ static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -318,7 +265,7 @@ static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -332,7 +279,7 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
static int get_address (struct hotplug_slot *hotplug_slot, u32 *value)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
struct pci_bus *bus = slot->ctrl->pci_dev->subordinate;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -344,7 +291,7 @@ static int get_address (struct hotplug_slot *hotplug_slot, u32 *value)
static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -358,7 +305,7 @@ static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_sp
static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
{
- struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+ struct slot *slot = get_slot(hotplug_slot);
int retval;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
@@ -385,9 +332,6 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int rc;
struct controller *ctrl;
- struct slot *t_slot;
- int first_device_num; /* first PCI device number */
- int num_ctlr_slots; /* number of slots implemented */
if (!is_shpc_capable(pdev))
return -ENODEV;
@@ -408,47 +352,13 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, ctrl);
- ctrl->bus = pdev->bus->number;
- ctrl->slot_bus = pdev->subordinate->number;
- ctrl->device = PCI_SLOT(pdev->devfn);
- ctrl->function = PCI_FUNC(pdev->devfn);
-
- dbg("ctrl bus=0x%x, device=%x, function=%x, irq=%x\n",
- ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
-
- /*
- * Save configuration headers for this and subordinate PCI buses
- */
- rc = get_ctlr_slot_config(ctrl);
- if (rc) {
- err(msg_initialization_err, rc);
- goto err_out_release_ctlr;
- }
- first_device_num = ctrl->slot_device_offset;
- num_ctlr_slots = ctrl->num_slots;
-
- ctrl->add_support = 1;
-
/* Setup the slot information structures */
rc = init_slots(ctrl);
if (rc) {
- err(msg_initialization_err, 6);
+ err("%s: slot initialization failed\n", SHPC_MODULE_NAME);
goto err_out_release_ctlr;
}
- /* Now hpc_functions (slot->hpc_ops->functions) are ready */
- t_slot = shpchp_find_slot(ctrl, first_device_num);
-
- /* Check for operation bus speed */
- rc = t_slot->hpc_ops->get_cur_bus_speed(t_slot, &ctrl->speed);
- dbg("%s: t_slot->hp_slot %x\n", __FUNCTION__,t_slot->hp_slot);
-
- if (rc || ctrl->speed == PCI_SPEED_UNKNOWN) {
- err(SHPC_MODULE_NAME ": Can't get current bus speed. "
- "Set to 33MHz PCI.\n");
- ctrl->speed = PCI_SPEED_33MHz;
- }
-
rc = shpchp_create_ctrl_files(ctrl);
if (rc)
goto err_cleanup_slots;
@@ -491,10 +401,6 @@ static int __init shpcd_init(void)
{
int retval = 0;
-#ifdef CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
- shpchp_poll_mode = 1;
-#endif
-
retval = pci_register_driver(&shpc_driver);
dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c
index 158ac78..b746bd2 100644
--- a/drivers/pci/hotplug/shpchp_ctrl.c
+++ b/drivers/pci/hotplug/shpchp_ctrl.c
@@ -57,15 +57,14 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
return 0;
}
-u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
+u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u32 event_type;
/* Attention Button Change */
dbg("shpchp: Attention button interrupt received.\n");
-
+
p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
@@ -81,9 +80,8 @@ u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
}
-u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
+u8 shpchp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u8 getstatus;
u32 event_type;
@@ -120,9 +118,8 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
return 1;
}
-u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
+u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u32 event_type;
@@ -131,7 +128,7 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
- /*
+ /*
* Save the presence state
*/
p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
@@ -154,9 +151,8 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
return 1;
}
-u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id)
+u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
{
- struct controller *ctrl = (struct controller *) inst_id;
struct slot *p_slot;
u32 event_type;
@@ -188,12 +184,12 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id)
return 1;
}
-/* The following routines constitute the bulk of the
+/* The following routines constitute the bulk of the
hotplug controller logic
*/
static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
enum pci_bus_speed speed)
-{
+{
int rc = 0;
dbg("%s: change to speed %d\n", __FUNCTION__, speed);
@@ -208,7 +204,7 @@ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
static int fix_bus_speed(struct controller *ctrl, struct slot *pslot,
u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp,
enum pci_bus_speed msp)
-{
+{
int rc = 0;
/*
@@ -261,23 +257,23 @@ static int board_added(struct slot *p_slot)
err("%s: Failed to power on slot\n", __FUNCTION__);
return -1;
}
-
+
if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
if (slots_not_empty)
return WRONG_BUS_FREQUENCY;
-
+
if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
return WRONG_BUS_FREQUENCY;
}
-
+
/* turn on board, blink green LED, turn off Amber LED */
if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
return rc;
}
}
-
+
rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp);
if (rc) {
err("%s: Can't get adapter speed or bus mode mismatch\n",
@@ -382,7 +378,7 @@ static int remove_board(struct slot *p_slot)
err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
return rc;
}
-
+
rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
if (rc) {
err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
@@ -497,10 +493,12 @@ static void handle_button_press_event(struct slot *p_slot)
p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (getstatus) {
p_slot->state = BLINKINGOFF_STATE;
- info(msg_button_off, p_slot->name);
+ info("PCI slot #%s - powering off due to button "
+ "press.\n", p_slot->name);
} else {
p_slot->state = BLINKINGON_STATE;
- info(msg_button_on, p_slot->name);
+ info("PCI slot #%s - powering on due to button "
+ "press.\n", p_slot->name);
}
/* blink green LED and turn off amber */
p_slot->hpc_ops->green_led_blink(p_slot);
@@ -523,7 +521,8 @@ static void handle_button_press_event(struct slot *p_slot)
else
p_slot->hpc_ops->green_led_off(p_slot);
p_slot->hpc_ops->set_attention_status(p_slot, 0);
- info(msg_button_cancel, p_slot->name);
+ info("PCI slot #%s - action canceled due to button press\n",
+ p_slot->name);
p_slot->state = STATIC_STATE;
break;
case POWEROFF_STATE:
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index 83a5226..5183a45 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -35,38 +35,6 @@
#include "shpchp.h"
-#ifdef DEBUG
-#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */
-#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */
-#define DBG_K_INFO ((unsigned int)0x00000004) /* Info messages */
-#define DBG_K_ERROR ((unsigned int)0x00000008) /* Error messages */
-#define DBG_K_TRACE (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
-#define DBG_K_STANDARD (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
-/* Redefine this flagword to set debug level */
-#define DEBUG_LEVEL DBG_K_STANDARD
-
-#define DEFINE_DBG_BUFFER char __dbg_str_buf[256];
-
-#define DBG_PRINT( dbg_flags, args... ) \
- do { \
- if ( DEBUG_LEVEL & ( dbg_flags ) ) \
- { \
- int len; \
- len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
- __FILE__, __LINE__, __FUNCTION__ ); \
- sprintf( __dbg_str_buf + len, args ); \
- printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
- } \
- } while (0)
-
-#define DBG_ENTER_ROUTINE DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
-#define DBG_LEAVE_ROUTINE DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
-#else
-#define DEFINE_DBG_BUFFER
-#define DBG_ENTER_ROUTINE
-#define DBG_LEAVE_ROUTINE
-#endif /* DEBUG */
-
/* Slot Available Register I field definition */
#define SLOT_33MHZ 0x0000001f
#define SLOT_66MHZ_PCIX 0x00001f00
@@ -211,45 +179,40 @@
#define SLOT_EVENT_LATCH 0x2
#define SLOT_SERR_INT_MASK 0x3
-DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */
-static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */
-static int ctlr_seq_num = 0; /* Controller sequenc # */
-static spinlock_t list_lock;
-
static atomic_t shpchp_num_controllers = ATOMIC_INIT(0);
static irqreturn_t shpc_isr(int irq, void *dev_id);
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec);
+static void start_int_poll_timer(struct controller *ctrl, int sec);
static int hpc_check_cmd_status(struct controller *ctrl);
static inline u8 shpc_readb(struct controller *ctrl, int reg)
{
- return readb(ctrl->hpc_ctlr_handle->creg + reg);
+ return readb(ctrl->creg + reg);
}
static inline void shpc_writeb(struct controller *ctrl, int reg, u8 val)
{
- writeb(val, ctrl->hpc_ctlr_handle->creg + reg);
+ writeb(val, ctrl->creg + reg);
}
static inline u16 shpc_readw(struct controller *ctrl, int reg)
{
- return readw(ctrl->hpc_ctlr_handle->creg + reg);
+ return readw(ctrl->creg + reg);
}
static inline void shpc_writew(struct controller *ctrl, int reg, u16 val)
{
- writew(val, ctrl->hpc_ctlr_handle->creg + reg);
+ writew(val, ctrl->creg + reg);
}
static inline u32 shpc_readl(struct controller *ctrl, int reg)
{
- return readl(ctrl->hpc_ctlr_handle->creg + reg);
+ return readl(ctrl->creg + reg);
}
static inline void shpc_writel(struct controller *ctrl, int reg, u32 val)
{
- writel(val, ctrl->hpc_ctlr_handle->creg + reg);
+ writel(val, ctrl->creg + reg);
}
static inline int shpc_indirect_read(struct controller *ctrl, int index,
@@ -268,38 +231,33 @@ static inline int shpc_indirect_read(struct controller *ctrl, int index,
/*
* This is the interrupt polling timeout function.
*/
-static void int_poll_timeout(unsigned long lphp_ctlr)
+static void int_poll_timeout(unsigned long data)
{
- struct php_ctlr_state_s *php_ctlr =
- (struct php_ctlr_state_s *)lphp_ctlr;
-
- DBG_ENTER_ROUTINE
+ struct controller *ctrl = (struct controller *)data;
/* Poll for interrupt events. regs == NULL => polling */
- shpc_isr(0, php_ctlr->callback_instance_id);
+ shpc_isr(0, ctrl);
- init_timer(&php_ctlr->int_poll_timer);
+ init_timer(&ctrl->poll_timer);
if (!shpchp_poll_time)
shpchp_poll_time = 2; /* default polling interval is 2 sec */
- start_int_poll_timer(php_ctlr, shpchp_poll_time);
-
- DBG_LEAVE_ROUTINE
+ start_int_poll_timer(ctrl, shpchp_poll_time);
}
/*
* This function starts the interrupt polling timer.
*/
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec)
+static void start_int_poll_timer(struct controller *ctrl, int sec)
{
/* Clamp to sane value */
if ((sec <= 0) || (sec > 60))
sec = 2;
- php_ctlr->int_poll_timer.function = &int_poll_timeout;
- php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr;
- php_ctlr->int_poll_timer.expires = jiffies + sec * HZ;
- add_timer(&php_ctlr->int_poll_timer);
+ ctrl->poll_timer.function = &int_poll_timeout;
+ ctrl->poll_timer.data = (unsigned long)ctrl;
+ ctrl->poll_timer.expires = jiffies + sec * HZ;
+ add_timer(&ctrl->poll_timer);
}
static inline int is_ctrl_busy(struct controller *ctrl)
@@ -358,8 +316,6 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
int retval = 0;
u16 temp_word;
- DBG_ENTER_ROUTINE
-
mutex_lock(&slot->ctrl->cmd_lock);
if (!shpc_poll_ctrl_busy(ctrl)) {
@@ -373,9 +329,9 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
++t_slot;
temp_word = (t_slot << 8) | (cmd & 0xFF);
dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd);
-
+
/* To make sure the Controller Busy bit is 0 before we send out the
- * command.
+ * command.
*/
shpc_writew(ctrl, CMD, temp_word);
@@ -394,20 +350,14 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
}
out:
mutex_unlock(&slot->ctrl->cmd_lock);
-
- DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_check_cmd_status(struct controller *ctrl)
{
- u16 cmd_status;
int retval = 0;
+ u16 cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
- DBG_ENTER_ROUTINE
-
- cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
-
switch (cmd_status >> 1) {
case 0:
retval = 0;
@@ -428,7 +378,6 @@ static int hpc_check_cmd_status(struct controller *ctrl)
retval = cmd_status;
}
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -436,13 +385,8 @@ static int hpc_check_cmd_status(struct controller *ctrl)
static int hpc_get_attention_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
- u8 state;
-
- DBG_ENTER_ROUTINE
-
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u8 state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;
switch (state) {
case ATN_LED_STATE_ON:
@@ -459,20 +403,14 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
break;
}
- DBG_LEAVE_ROUTINE
return 0;
}
static int hpc_get_power_status(struct slot * slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
- u8 state;
-
- DBG_ENTER_ROUTINE
-
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u8 state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;
switch (state) {
case SLOT_STATE_PWRONLY:
@@ -489,7 +427,6 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
break;
}
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -497,30 +434,21 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
static int hpc_get_latch_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
-
- DBG_ENTER_ROUTINE
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
*status = !!(slot_reg & MRL_SENSOR); /* 0 -> close; 1 -> open */
- DBG_LEAVE_ROUTINE
return 0;
}
static int hpc_get_adapter_status(struct slot *slot, u8 *status)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
- u8 state;
-
- DBG_ENTER_ROUTINE
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u8 state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;
*status = (state != 0x3) ? 1 : 0;
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -528,11 +456,8 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int)
{
struct controller *ctrl = slot->ctrl;
- DBG_ENTER_ROUTINE
-
*prog_int = shpc_readb(ctrl, PROG_INTERFACE);
- DBG_LEAVE_ROUTINE
return 0;
}
@@ -544,8 +469,6 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
u8 m66_cap = !!(slot_reg & MHZ66_CAP);
u8 pi, pcix_cap;
- DBG_ENTER_ROUTINE
-
if ((retval = hpc_get_prog_int(slot, &pi)))
return retval;
@@ -587,21 +510,15 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
}
dbg("Adapter speed = %d\n", *value);
- DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
{
- struct controller *ctrl = slot->ctrl;
- u16 sec_bus_status;
- u8 pi;
int retval = 0;
-
- DBG_ENTER_ROUTINE
-
- pi = shpc_readb(ctrl, PROG_INTERFACE);
- sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
+ struct controller *ctrl = slot->ctrl;
+ u16 sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
+ u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
if (pi == 2) {
*mode = (sec_bus_status & 0x0100) >> 8;
@@ -610,21 +527,14 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
}
dbg("Mode 1 ECC cap = %d\n", *mode);
-
- DBG_LEAVE_ROUTINE
return retval;
}
static int hpc_query_power_fault(struct slot * slot)
{
struct controller *ctrl = slot->ctrl;
- u32 slot_reg;
-
- DBG_ENTER_ROUTINE
-
- slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+ u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
- DBG_LEAVE_ROUTINE
/* Note: Logic 0 => fault */
return !(slot_reg & POWER_FAULT);
}
@@ -634,7 +544,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
u8 slot_cmd = 0;
switch (value) {
- case 0 :
+ case 0 :
slot_cmd = SET_ATTN_OFF; /* OFF */
break;
case 1:
@@ -666,38 +576,11 @@ static void hpc_set_green_led_blink(struct slot *slot)
shpc_write_cmd(slot, slot->hp_slot, SET_PWR_BLINK);
}
-int shpc_get_ctlr_slot_config(struct controller *ctrl,
- int *num_ctlr_slots, /* number of slots in this HPC */
- int *first_device_num, /* PCI dev num of the first slot in this SHPC */
- int *physical_slot_num, /* phy slot num of the first slot in this SHPC */
- int *updown, /* physical_slot_num increament: 1 or -1 */
- int *flags)
-{
- u32 slot_config;
-
- DBG_ENTER_ROUTINE
-
- slot_config = shpc_readl(ctrl, SLOT_CONFIG);
- *first_device_num = (slot_config & FIRST_DEV_NUM) >> 8;
- *num_ctlr_slots = slot_config & SLOT_NUM;
- *physical_slot_num = (slot_config & PSN) >> 16;
- *updown = ((slot_config & UPDOWN) >> 29) ? 1 : -1;
-
- dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num);
-
- DBG_LEAVE_ROUTINE
- return 0;
-}
-
static void hpc_release_ctlr(struct controller *ctrl)
{
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
- struct php_ctlr_state_s *p, *p_prev;
int i;
u32 slot_reg, serr_int;
- DBG_ENTER_ROUTINE
-
/*
* Mask event interrupts and SERRs of all slots
*/
@@ -722,40 +605,15 @@ static void hpc_release_ctlr(struct controller *ctrl)
serr_int &= ~SERR_INTR_RSVDZ_MASK;
shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
- if (shpchp_poll_mode) {
- del_timer(&php_ctlr->int_poll_timer);
- } else {
- if (php_ctlr->irq) {
- free_irq(php_ctlr->irq, ctrl);
- php_ctlr->irq = 0;
- pci_disable_msi(php_ctlr->pci_dev);
- }
- }
-
- if (php_ctlr->pci_dev) {
- iounmap(php_ctlr->creg);
- release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
- php_ctlr->pci_dev = NULL;
- }
-
- spin_lock(&list_lock);
- p = php_ctlr_list_head;
- p_prev = NULL;
- while (p) {
- if (p == php_ctlr) {
- if (p_prev)
- p_prev->pnext = p->pnext;
- else
- php_ctlr_list_head = p->pnext;
- break;
- } else {
- p_prev = p;
- p = p->pnext;
- }
+ if (shpchp_poll_mode)
+ del_timer(&ctrl->poll_timer);
+ else {
+ free_irq(ctrl->pci_dev->irq, ctrl);
+ pci_disable_msi(ctrl->pci_dev);
}
- spin_unlock(&list_lock);
- kfree(php_ctlr);
+ iounmap(ctrl->creg);
+ release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
/*
* If this is the last controller to be released, destroy the
@@ -763,62 +621,43 @@ static void hpc_release_ctlr(struct controller *ctrl)
*/
if (atomic_dec_and_test(&shpchp_num_controllers))
destroy_workqueue(shpchp_wq);
-
-DBG_LEAVE_ROUTINE
-
}
static int hpc_power_on_slot(struct slot * slot)
{
int retval;
- DBG_ENTER_ROUTINE
-
retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR);
- if (retval) {
+ if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- return retval;
- }
-
- DBG_LEAVE_ROUTINE
- return 0;
+ return retval;
}
static int hpc_slot_enable(struct slot * slot)
{
int retval;
- DBG_ENTER_ROUTINE
-
/* Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
retval = shpc_write_cmd(slot, slot->hp_slot,
SET_SLOT_ENABLE | SET_PWR_BLINK | SET_ATTN_OFF);
- if (retval) {
+ if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- return retval;
- }
- DBG_LEAVE_ROUTINE
- return 0;
+ return retval;
}
static int hpc_slot_disable(struct slot * slot)
{
int retval;
- DBG_ENTER_ROUTINE
-
/* Slot - Disable, Power Indicator - Off, Attention Indicator - On */
retval = shpc_write_cmd(slot, slot->hp_slot,
SET_SLOT_DISABLE | SET_PWR_OFF | SET_ATTN_ON);
- if (retval) {
+ if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- return retval;
- }
- DBG_LEAVE_ROUTINE
- return 0;
+ return retval;
}
static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
@@ -827,8 +666,6 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
struct controller *ctrl = slot->ctrl;
u8 pi, cmd;
- DBG_ENTER_ROUTINE
-
pi = shpc_readb(ctrl, PROG_INTERFACE);
if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX))
return -EINVAL;
@@ -884,14 +721,12 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
if (retval)
err("%s: Write command failed!\n", __FUNCTION__);
- DBG_LEAVE_ROUTINE
return retval;
}
static irqreturn_t shpc_isr(int irq, void *dev_id)
{
struct controller *ctrl = (struct controller *)dev_id;
- struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
u32 serr_int, slot_reg, intr_loc, intr_loc2;
int hp_slot;
@@ -900,7 +735,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
if (!intr_loc)
return IRQ_NONE;
- dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc);
+ dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc);
if(!shpchp_poll_mode) {
/*
@@ -913,12 +748,12 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
intr_loc2 = shpc_readl(ctrl, INTR_LOC);
- dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
+ dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
}
if (intr_loc & CMD_INTR_PENDING) {
- /*
- * Command Complete Interrupt Pending
+ /*
+ * Command Complete Interrupt Pending
* RO only - clear by writing 1 to the Command Completion
* Detect bit in Controller SERR-INT register
*/
@@ -932,7 +767,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
if (!(intr_loc & ~CMD_INTR_PENDING))
goto out;
- for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
+ for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
/* To find out which slot has interrupt pending */
if (!(intr_loc & SLOT_INTR_PENDING(hp_slot)))
continue;
@@ -942,20 +777,16 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
__FUNCTION__, hp_slot, slot_reg);
if (slot_reg & MRL_CHANGE_DETECTED)
- php_ctlr->switch_change_callback(
- hp_slot, php_ctlr->callback_instance_id);
+ shpchp_handle_switch_change(hp_slot, ctrl);
if (slot_reg & BUTTON_PRESS_DETECTED)
- php_ctlr->attention_button_callback(
- hp_slot, php_ctlr->callback_instance_id);
+ shpchp_handle_attention_button(hp_slot, ctrl);
if (slot_reg & PRSNT_CHANGE_DETECTED)
- php_ctlr->presence_change_callback(
- hp_slot , php_ctlr->callback_instance_id);
+ shpchp_handle_presence_change(hp_slot, ctrl);
if (slot_reg & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED))
- php_ctlr->power_fault_callback(
- hp_slot, php_ctlr->callback_instance_id);
+ shpchp_handle_power_fault(hp_slot, ctrl);
/* Clear all slot events */
slot_reg &= ~SLOT_REG_RSVDZ_MASK;
@@ -968,7 +799,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK);
shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
}
-
+
return IRQ_HANDLED;
}
@@ -981,8 +812,6 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1);
u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2);
- DBG_ENTER_ROUTINE
-
if (pi == 2) {
if (slot_avail2 & SLOT_133MHZ_PCIX_533)
bus_speed = PCI_SPEED_133MHz_PCIX_533;
@@ -1015,7 +844,7 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
*value = bus_speed;
dbg("Max bus speed = %d\n", bus_speed);
- DBG_LEAVE_ROUTINE
+
return retval;
}
@@ -1028,8 +857,6 @@ static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7);
- DBG_ENTER_ROUTINE
-
if ((pi == 1) && (speed_mode > 4)) {
*value = PCI_SPEED_UNKNOWN;
return -ENODEV;
@@ -1085,7 +912,6 @@ static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
}
dbg("Current bus speed = %d\n", bus_speed);
- DBG_LEAVE_ROUTINE
return retval;
}
@@ -1093,7 +919,7 @@ static struct hpc_ops shpchp_hpc_ops = {
.power_on_slot = hpc_power_on_slot,
.slot_enable = hpc_slot_enable,
.slot_disable = hpc_slot_disable,
- .set_bus_speed_mode = hpc_set_bus_speed_mode,
+ .set_bus_speed_mode = hpc_set_bus_speed_mode,
.set_attention_status = hpc_set_attention_status,
.get_power_status = hpc_get_power_status,
.get_attention_status = hpc_get_attention_status,
@@ -1110,34 +936,20 @@ static struct hpc_ops shpchp_hpc_ops = {
.green_led_on = hpc_set_green_led_on,
.green_led_off = hpc_set_green_led_off,
.green_led_blink = hpc_set_green_led_blink,
-
+
.release_ctlr = hpc_release_ctlr,
};
-int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
+int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
{
- struct php_ctlr_state_s *php_ctlr, *p;
- void *instance_id = ctrl;
int rc = -1, num_slots = 0;
u8 hp_slot;
u32 shpc_base_offset;
u32 tempdword, slot_reg, slot_config;
u8 i;
- DBG_ENTER_ROUTINE
-
ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */
- spin_lock_init(&list_lock);
- php_ctlr = kzalloc(sizeof(*php_ctlr), GFP_KERNEL);
-
- if (!php_ctlr) { /* allocate controller state data */
- err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
- goto abort;
- }
-
- php_ctlr->pci_dev = pdev; /* save pci_dev in context */
-
if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==
PCI_DEVICE_ID_AMD_GOLAM_7450)) {
/* amd shpc driver doesn't use Base Offset; assume 0 */
@@ -1147,20 +959,20 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
ctrl->cap_offset = pci_find_capability(pdev, PCI_CAP_ID_SHPC);
if (!ctrl->cap_offset) {
err("%s : cap_offset == 0\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset);
rc = shpc_indirect_read(ctrl, 0, &shpc_base_offset);
if (rc) {
err("%s: cannot read base_offset\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
rc = shpc_indirect_read(ctrl, 3, &tempdword);
if (rc) {
err("%s: cannot read slot config\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
num_slots = tempdword & SLOT_NUM;
dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots);
@@ -1170,7 +982,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
if (rc) {
err("%s: cannot read creg (index = %d)\n",
__FUNCTION__, i);
- goto abort_free_ctlr;
+ goto abort;
}
dbg("%s: offset %d: value %x\n", __FUNCTION__,i,
tempdword);
@@ -1181,30 +993,30 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
ctrl->mmio_size = 0x24 + 0x4 * num_slots;
}
- info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
+ info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
pdev->subsystem_device);
-
+
rc = pci_enable_device(pdev);
if (rc) {
err("%s: pci_enable_device failed\n", __FUNCTION__);
- goto abort_free_ctlr;
+ goto abort;
}
if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) {
err("%s: cannot reserve MMIO region\n", __FUNCTION__);
rc = -1;
- goto abort_free_ctlr;
+ goto abort;
}
- php_ctlr->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size);
- if (!php_ctlr->creg) {
+ ctrl->creg = ioremap(ctrl->mmio_base, ctrl->mmio_size);
+ if (!ctrl->creg) {
err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__,
ctrl->mmio_size, ctrl->mmio_base);
release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
rc = -1;
- goto abort_free_ctlr;
+ goto abort;
}
- dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
+ dbg("%s: ctrl->creg %p\n", __FUNCTION__, ctrl->creg);
mutex_init(&ctrl->crit_sect);
mutex_init(&ctrl->cmd_lock);
@@ -1212,23 +1024,14 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
/* Setup wait queue */
init_waitqueue_head(&ctrl->queue);
- /* Find the IRQ */
- php_ctlr->irq = pdev->irq;
- php_ctlr->attention_button_callback = shpchp_handle_attention_button,
- php_ctlr->switch_change_callback = shpchp_handle_switch_change;
- php_ctlr->presence_change_callback = shpchp_handle_presence_change;
- php_ctlr->power_fault_callback = shpchp_handle_power_fault;
- php_ctlr->callback_instance_id = instance_id;
-
- ctrl->hpc_ctlr_handle = php_ctlr;
ctrl->hpc_ops = &shpchp_hpc_ops;
/* Return PCI Controller Info */
slot_config = shpc_readl(ctrl, SLOT_CONFIG);
- php_ctlr->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8;
- php_ctlr->num_slots = slot_config & SLOT_NUM;
- dbg("%s: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset);
- dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots);
+ ctrl->slot_device_offset = (slot_config & FIRST_DEV_NUM) >> 8;
+ ctrl->num_slots = slot_config & SLOT_NUM;
+ ctrl->first_slot = (slot_config & PSN) >> 16;
+ ctrl->slot_num_inc = ((slot_config & UPDOWN) >> 29) ? 1 : -1;
/* Mask Global Interrupt Mask & Command Complete Interrupt Mask */
tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);
@@ -1243,7 +1046,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
/* Mask the MRL sensor SERR Mask of individual slot in
* Slot SERR-INT Mask & clear all the existing event if any
*/
- for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
+ for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));
dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
hp_slot, slot_reg);
@@ -1254,25 +1057,28 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
slot_reg &= ~SLOT_REG_RSVDZ_MASK;
shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);
}
-
- if (shpchp_poll_mode) {/* Install interrupt polling code */
- /* Install and start the interrupt polling timer */
- init_timer(&php_ctlr->int_poll_timer);
- start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */
+
+ if (shpchp_poll_mode) {
+ /* Install interrupt polling timer. Start with 10 sec delay */
+ init_timer(&ctrl->poll_timer);
+ start_int_poll_timer(ctrl, 10);
} else {
/* Installs the interrupt handler */
rc = pci_enable_msi(pdev);
if (rc) {
info("Can't get msi for the hotplug controller\n");
info("Use INTx for the hotplug controller\n");
- } else
- php_ctlr->irq = pdev->irq;
-
- rc = request_irq(php_ctlr->irq, shpc_isr, IRQF_SHARED, MY_NAME, (void *) ctrl);
- dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
+ }
+
+ rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED,
+ MY_NAME, (void *)ctrl);
+ dbg("%s: request_irq %d for hpc%d (returns %d)\n",
+ __FUNCTION__, ctrl->pci_dev->irq,
+ atomic_read(&shpchp_num_controllers), rc);
if (rc) {
- err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
- goto abort_free_ctlr;
+ err("Can't get irq %d for the hotplug controller\n",
+ ctrl->pci_dev->irq);
+ goto abort_iounmap;
}
}
dbg("%s: HPC at b:d:f:irq=0x%x:%x:%x:%x\n", __FUNCTION__,
@@ -1280,24 +1086,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
PCI_FUNC(pdev->devfn), pdev->irq);
get_hp_hw_control_from_firmware(pdev);
- /* Add this HPC instance into the HPC list */
- spin_lock(&list_lock);
- if (php_ctlr_list_head == 0) {
- php_ctlr_list_head = php_ctlr;
- p = php_ctlr_list_head;
- p->pnext = NULL;
- } else {
- p = php_ctlr_list_head;
-
- while (p->pnext)
- p = p->pnext;
-
- p->pnext = php_ctlr;
- }
- spin_unlock(&list_lock);
-
- ctlr_seq_num++;
-
/*
* If this is the first controller to be initialized,
* initialize the shpchpd work queue
@@ -1306,14 +1094,14 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
shpchp_wq = create_singlethread_workqueue("shpchpd");
if (!shpchp_wq) {
rc = -ENOMEM;
- goto abort_free_ctlr;
+ goto abort_iounmap;
}
}
/*
* Unmask all event interrupts of all slots
*/
- for (hp_slot = 0; hp_slot < php_ctlr->num_slots; hp_slot++) {
+ for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));
dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
hp_slot, slot_reg);
@@ -1332,15 +1120,11 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
}
- DBG_LEAVE_ROUTINE
return 0;
/* We end up here for the many possible ways to fail this API. */
-abort_free_ctlr:
- if (php_ctlr->creg)
- iounmap(php_ctlr->creg);
- kfree(php_ctlr);
+abort_iounmap:
+ iounmap(ctrl->creg);
abort:
- DBG_LEAVE_ROUTINE
return rc;
}
diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c
index 0a8d1cc..279c940 100644
--- a/drivers/pci/htirq.c
+++ b/drivers/pci/htirq.c
@@ -99,14 +99,7 @@ int __ht_create_irq(struct pci_dev *dev, int idx, ht_irq_update_t *update)
int pos;
int irq;
- pos = pci_find_capability(dev, PCI_CAP_ID_HT);
- while (pos) {
- u8 subtype;
- pci_read_config_byte(dev, pos + 3, &subtype);
- if (subtype == HT_CAPTYPE_IRQ)
- break;
- pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_HT);
- }
+ pos = pci_find_ht_capability(dev, HT_CAPTYPE_IRQ);
if (!pos)
return -EINVAL;
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index ed3f7e1..68555c1 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -24,8 +24,6 @@
#include "pci.h"
#include "msi.h"
-static DEFINE_SPINLOCK(msi_lock);
-static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
static struct kmem_cache* msi_cachep;
static int pci_msi_enable = 1;
@@ -44,13 +42,13 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
{
struct msi_desc *entry;
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
BUG_ON(!entry || !entry->dev);
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
if (entry->msi_attrib.maskbit) {
- int pos;
- u32 mask_bits;
+ int pos;
+ u32 mask_bits;
pos = (long)entry->mask_base;
pci_read_config_dword(entry->dev, pos, &mask_bits);
@@ -74,7 +72,7 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
void read_msi_msg(unsigned int irq, struct msi_msg *msg)
{
- struct msi_desc *entry = get_irq_data(irq);
+ struct msi_desc *entry = get_irq_msi(irq);
switch(entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
{
@@ -113,7 +111,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
void write_msi_msg(unsigned int irq, struct msi_msg *msg)
{
- struct msi_desc *entry = get_irq_data(irq);
+ struct msi_desc *entry = get_irq_msi(irq);
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
{
@@ -162,6 +160,7 @@ void unmask_msi_irq(unsigned int irq)
}
static int msi_free_irq(struct pci_dev* dev, int irq);
+
static int msi_init(void)
{
static int status = -ENOMEM;
@@ -169,13 +168,6 @@ static int msi_init(void)
if (!status)
return status;
- if (pci_msi_quirk) {
- pci_msi_enable = 0;
- printk(KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n");
- status = -EINVAL;
- return status;
- }
-
status = msi_cache_init();
if (status < 0) {
pci_msi_enable = 0;
@@ -200,46 +192,6 @@ static struct msi_desc* alloc_msi_entry(void)
return entry;
}
-static void attach_msi_entry(struct msi_desc *entry, int irq)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- msi_desc[irq] = entry;
- spin_unlock_irqrestore(&msi_lock, flags);
-}
-
-static int create_msi_irq(void)
-{
- struct msi_desc *entry;
- int irq;
-
- entry = alloc_msi_entry();
- if (!entry)
- return -ENOMEM;
-
- irq = create_irq();
- if (irq < 0) {
- kmem_cache_free(msi_cachep, entry);
- return -EBUSY;
- }
-
- set_irq_data(irq, entry);
-
- return irq;
-}
-
-static void destroy_msi_irq(unsigned int irq)
-{
- struct msi_desc *entry;
-
- entry = get_irq_data(irq);
- set_irq_chip(irq, NULL);
- set_irq_data(irq, NULL);
- destroy_irq(irq);
- kmem_cache_free(msi_cachep, entry);
-}
-
static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
{
u16 control;
@@ -278,36 +230,8 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type)
pci_intx(dev, 1); /* enable intx */
}
-static int msi_lookup_irq(struct pci_dev *dev, int type)
-{
- int irq;
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- for (irq = 0; irq < NR_IRQS; irq++) {
- if (!msi_desc[irq] || msi_desc[irq]->dev != dev ||
- msi_desc[irq]->msi_attrib.type != type ||
- msi_desc[irq]->msi_attrib.default_irq != dev->irq)
- continue;
- spin_unlock_irqrestore(&msi_lock, flags);
- /* This pre-assigned MSI irq for this device
- already exits. Override dev->irq with this irq */
- dev->irq = irq;
- return 0;
- }
- spin_unlock_irqrestore(&msi_lock, flags);
-
- return -EACCES;
-}
-
-void pci_scan_msi_device(struct pci_dev *dev)
-{
- if (!dev)
- return;
-}
-
#ifdef CONFIG_PM
-int pci_save_msi_state(struct pci_dev *dev)
+static int __pci_save_msi_state(struct pci_dev *dev)
{
int pos, i = 0;
u16 control;
@@ -345,7 +269,7 @@ int pci_save_msi_state(struct pci_dev *dev)
return 0;
}
-void pci_restore_msi_state(struct pci_dev *dev)
+static void __pci_restore_msi_state(struct pci_dev *dev)
{
int i = 0, pos;
u16 control;
@@ -373,14 +297,16 @@ void pci_restore_msi_state(struct pci_dev *dev)
kfree(save_state);
}
-int pci_save_msix_state(struct pci_dev *dev)
+static int __pci_save_msix_state(struct pci_dev *dev)
{
int pos;
- int temp;
int irq, head, tail = 0;
u16 control;
struct pci_cap_saved_state *save_state;
+ if (!dev->msix_enabled)
+ return 0;
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (pos <= 0 || dev->no_msi)
return 0;
@@ -398,38 +324,46 @@ int pci_save_msix_state(struct pci_dev *dev)
*((u16 *)&save_state->data[0]) = control;
/* save the table */
- temp = dev->irq;
- if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
- kfree(save_state);
- return -EINVAL;
- }
-
- irq = head = dev->irq;
+ irq = head = dev->first_msi_irq;
while (head != tail) {
struct msi_desc *entry;
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
read_msi_msg(irq, &entry->msg_save);
- tail = msi_desc[irq]->link.tail;
+ tail = entry->link.tail;
irq = tail;
}
- dev->irq = temp;
save_state->cap_nr = PCI_CAP_ID_MSIX;
pci_add_saved_cap(dev, save_state);
return 0;
}
-void pci_restore_msix_state(struct pci_dev *dev)
+int pci_save_msi_state(struct pci_dev *dev)
+{
+ int rc;
+
+ rc = __pci_save_msi_state(dev);
+ if (rc)
+ return rc;
+
+ rc = __pci_save_msix_state(dev);
+
+ return rc;
+}
+
+static void __pci_restore_msix_state(struct pci_dev *dev)
{
u16 save;
int pos;
int irq, head, tail = 0;
struct msi_desc *entry;
- int temp;
struct pci_cap_saved_state *save_state;
+ if (!dev->msix_enabled)
+ return;
+
save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX);
if (!save_state)
return;
@@ -442,23 +376,25 @@ void pci_restore_msix_state(struct pci_dev *dev)
return;
/* route the table */
- temp = dev->irq;
- if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX))
- return;
- irq = head = dev->irq;
+ irq = head = dev->first_msi_irq;
while (head != tail) {
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
write_msi_msg(irq, &entry->msg_save);
- tail = msi_desc[irq]->link.tail;
+ tail = entry->link.tail;
irq = tail;
}
- dev->irq = temp;
pci_write_config_word(dev, msi_control_reg(pos), save);
enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
}
-#endif
+
+void pci_restore_msi_state(struct pci_dev *dev)
+{
+ __pci_restore_msi_state(dev);
+ __pci_restore_msix_state(dev);
+}
+#endif /* CONFIG_PM */
/**
* msi_capability_init - configure device's MSI capability structure
@@ -471,7 +407,6 @@ void pci_restore_msix_state(struct pci_dev *dev)
**/
static int msi_capability_init(struct pci_dev *dev)
{
- int status;
struct msi_desc *entry;
int pos, irq;
u16 control;
@@ -479,13 +414,10 @@ static int msi_capability_init(struct pci_dev *dev)
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
pci_read_config_word(dev, msi_control_reg(pos), &control);
/* MSI Entry Initialization */
- irq = create_msi_irq();
- if (irq < 0)
- return irq;
+ entry = alloc_msi_entry();
+ if (!entry)
+ return -ENOMEM;
- entry = get_irq_data(irq);
- entry->link.head = irq;
- entry->link.tail = irq;
entry->msi_attrib.type = PCI_CAP_ID_MSI;
entry->msi_attrib.is_64 = is_64bit_address(control);
entry->msi_attrib.entry_nr = 0;
@@ -511,13 +443,16 @@ static int msi_capability_init(struct pci_dev *dev)
maskbits);
}
/* Configure MSI capability structure */
- status = arch_setup_msi_irq(irq, dev);
- if (status < 0) {
- destroy_msi_irq(irq);
- return status;
+ irq = arch_setup_msi_irq(dev, entry);
+ if (irq < 0) {
+ kmem_cache_free(msi_cachep, entry);
+ return irq;
}
+ entry->link.head = irq;
+ entry->link.tail = irq;
+ dev->first_msi_irq = irq;
+ set_irq_msi(irq, entry);
- attach_msi_entry(entry, irq);
/* Set MSI enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
@@ -539,7 +474,6 @@ static int msix_capability_init(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{
struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
- int status;
int irq, pos, i, j, nr_entries, temp = 0;
unsigned long phys_addr;
u32 table_offset;
@@ -562,13 +496,11 @@ static int msix_capability_init(struct pci_dev *dev,
/* MSI-X Table Initialization */
for (i = 0; i < nvec; i++) {
- irq = create_msi_irq();
- if (irq < 0)
+ entry = alloc_msi_entry();
+ if (!entry)
break;
- entry = get_irq_data(irq);
j = entries[i].entry;
- entries[i].vector = irq;
entry->msi_attrib.type = PCI_CAP_ID_MSIX;
entry->msi_attrib.is_64 = 1;
entry->msi_attrib.entry_nr = j;
@@ -577,6 +509,14 @@ static int msix_capability_init(struct pci_dev *dev,
entry->msi_attrib.pos = pos;
entry->dev = dev;
entry->mask_base = base;
+
+ /* Configure MSI-X capability structure */
+ irq = arch_setup_msi_irq(dev, entry);
+ if (irq < 0) {
+ kmem_cache_free(msi_cachep, entry);
+ break;
+ }
+ entries[i].vector = irq;
if (!head) {
entry->link.head = irq;
entry->link.tail = irq;
@@ -589,14 +529,8 @@ static int msix_capability_init(struct pci_dev *dev,
}
temp = irq;
tail = entry;
- /* Configure MSI-X capability structure */
- status = arch_setup_msi_irq(irq, dev);
- if (status < 0) {
- destroy_msi_irq(irq);
- break;
- }
- attach_msi_entry(entry, irq);
+ set_irq_msi(irq, entry);
}
if (i != nvec) {
int avail = i - 1;
@@ -613,6 +547,7 @@ static int msix_capability_init(struct pci_dev *dev,
avail = -EBUSY;
return avail;
}
+ dev->first_msi_irq = entries[0].vector;
/* Set MSI-X enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
@@ -660,13 +595,11 @@ int pci_msi_supported(struct pci_dev * dev)
**/
int pci_enable_msi(struct pci_dev* dev)
{
- int pos, temp, status;
+ int pos, status;
if (pci_msi_supported(dev) < 0)
return -EINVAL;
- temp = dev->irq;
-
status = msi_init();
if (status < 0)
return status;
@@ -675,15 +608,14 @@ int pci_enable_msi(struct pci_dev* dev)
if (!pos)
return -EINVAL;
- WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI));
+ WARN_ON(!!dev->msi_enabled);
/* Check whether driver already requested for MSI-X irqs */
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ if (pos > 0 && dev->msix_enabled) {
printk(KERN_INFO "PCI: %s: Can't enable MSI. "
- "Device already has MSI-X irq assigned\n",
+ "Device already has MSI-X enabled\n",
pci_name(dev));
- dev->irq = temp;
return -EINVAL;
}
status = msi_capability_init(dev);
@@ -695,13 +627,15 @@ void pci_disable_msi(struct pci_dev* dev)
struct msi_desc *entry;
int pos, default_irq;
u16 control;
- unsigned long flags;
if (!pci_msi_enable)
return;
if (!dev)
return;
+ if (!dev->msi_enabled)
+ return;
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
if (!pos)
return;
@@ -710,28 +644,26 @@ void pci_disable_msi(struct pci_dev* dev)
if (!(control & PCI_MSI_FLAGS_ENABLE))
return;
+
disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
- spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[dev->irq];
+ entry = get_irq_msi(dev->first_msi_irq);
if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
- spin_unlock_irqrestore(&msi_lock, flags);
return;
}
- if (irq_has_action(dev->irq)) {
- spin_unlock_irqrestore(&msi_lock, flags);
+ if (irq_has_action(dev->first_msi_irq)) {
printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
"free_irq() on MSI irq %d\n",
- pci_name(dev), dev->irq);
- BUG_ON(irq_has_action(dev->irq));
+ pci_name(dev), dev->first_msi_irq);
+ BUG_ON(irq_has_action(dev->first_msi_irq));
} else {
default_irq = entry->msi_attrib.default_irq;
- spin_unlock_irqrestore(&msi_lock, flags);
- msi_free_irq(dev, dev->irq);
+ msi_free_irq(dev, dev->first_msi_irq);
/* Restore dev->irq to its default pin-assertion irq */
dev->irq = default_irq;
}
+ dev->first_msi_irq = 0;
}
static int msi_free_irq(struct pci_dev* dev, int irq)
@@ -739,27 +671,20 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
struct msi_desc *entry;
int head, entry_nr, type;
void __iomem *base;
- unsigned long flags;
- arch_teardown_msi_irq(irq);
-
- spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[irq];
+ entry = get_irq_msi(irq);
if (!entry || entry->dev != dev) {
- spin_unlock_irqrestore(&msi_lock, flags);
return -EINVAL;
}
type = entry->msi_attrib.type;
entry_nr = entry->msi_attrib.entry_nr;
head = entry->link.head;
base = entry->mask_base;
- msi_desc[entry->link.head]->link.tail = entry->link.tail;
- msi_desc[entry->link.tail]->link.head = entry->link.head;
- entry->dev = NULL;
- msi_desc[irq] = NULL;
- spin_unlock_irqrestore(&msi_lock, flags);
+ get_irq_msi(entry->link.head)->link.tail = entry->link.tail;
+ get_irq_msi(entry->link.tail)->link.head = entry->link.head;
- destroy_msi_irq(irq);
+ arch_teardown_msi_irq(irq);
+ kmem_cache_free(msi_cachep, entry);
if (type == PCI_CAP_ID_MSIX) {
writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
@@ -790,7 +715,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
{
int status, pos, nr_entries;
- int i, j, temp;
+ int i, j;
u16 control;
if (!entries || pci_msi_supported(dev) < 0)
@@ -818,16 +743,14 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
return -EINVAL; /* duplicate entry */
}
}
- temp = dev->irq;
- WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX));
+ WARN_ON(!!dev->msix_enabled);
/* Check whether driver already requested for MSI irq */
if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
- !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
+ dev->msi_enabled) {
printk(KERN_INFO "PCI: %s: Can't enable MSI-X. "
"Device already has an MSI irq assigned\n",
pci_name(dev));
- dev->irq = temp;
return -EINVAL;
}
status = msix_capability_init(dev, entries, nvec);
@@ -836,7 +759,8 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
void pci_disable_msix(struct pci_dev* dev)
{
- int pos, temp;
+ int irq, head, tail = 0, warning = 0;
+ int pos;
u16 control;
if (!pci_msi_enable)
@@ -844,6 +768,9 @@ void pci_disable_msix(struct pci_dev* dev)
if (!dev)
return;
+ if (!dev->msix_enabled)
+ return;
+
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
if (!pos)
return;
@@ -854,31 +781,23 @@ void pci_disable_msix(struct pci_dev* dev)
disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
- temp = dev->irq;
- if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
- int irq, head, tail = 0, warning = 0;
- unsigned long flags;
-
- irq = head = dev->irq;
- dev->irq = temp; /* Restore pin IRQ */
- while (head != tail) {
- spin_lock_irqsave(&msi_lock, flags);
- tail = msi_desc[irq]->link.tail;
- spin_unlock_irqrestore(&msi_lock, flags);
- if (irq_has_action(irq))
- warning = 1;
- else if (irq != head) /* Release MSI-X irq */
- msi_free_irq(dev, irq);
- irq = tail;
- }
- msi_free_irq(dev, irq);
- if (warning) {
- printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
- "free_irq() on all MSI-X irqs\n",
- pci_name(dev));
- BUG_ON(warning > 0);
- }
+ irq = head = dev->first_msi_irq;
+ while (head != tail) {
+ tail = get_irq_msi(irq)->link.tail;
+ if (irq_has_action(irq))
+ warning = 1;
+ else if (irq != head) /* Release MSI-X irq */
+ msi_free_irq(dev, irq);
+ irq = tail;
+ }
+ msi_free_irq(dev, irq);
+ if (warning) {
+ printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
+ "free_irq() on all MSI-X irqs\n",
+ pci_name(dev));
+ BUG_ON(warning > 0);
}
+ dev->first_msi_irq = 0;
}
/**
@@ -892,35 +811,26 @@ void pci_disable_msix(struct pci_dev* dev)
**/
void msi_remove_pci_irq_vectors(struct pci_dev* dev)
{
- int pos, temp;
- unsigned long flags;
-
if (!pci_msi_enable || !dev)
return;
- temp = dev->irq; /* Save IOAPIC IRQ */
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
- if (irq_has_action(dev->irq)) {
+ if (dev->msi_enabled) {
+ if (irq_has_action(dev->first_msi_irq)) {
printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
"called without free_irq() on MSI irq %d\n",
- pci_name(dev), dev->irq);
- BUG_ON(irq_has_action(dev->irq));
+ pci_name(dev), dev->first_msi_irq);
+ BUG_ON(irq_has_action(dev->first_msi_irq));
} else /* Release MSI irq assigned to this device */
- msi_free_irq(dev, dev->irq);
- dev->irq = temp; /* Restore IOAPIC IRQ */
+ msi_free_irq(dev, dev->first_msi_irq);
}
- pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ if (dev->msix_enabled) {
int irq, head, tail = 0, warning = 0;
void __iomem *base = NULL;
- irq = head = dev->irq;
+ irq = head = dev->first_msi_irq;
while (head != tail) {
- spin_lock_irqsave(&msi_lock, flags);
- tail = msi_desc[irq]->link.tail;
- base = msi_desc[irq]->mask_base;
- spin_unlock_irqrestore(&msi_lock, flags);
+ tail = get_irq_msi(irq)->link.tail;
+ base = get_irq_msi(irq)->mask_base;
if (irq_has_action(irq))
warning = 1;
else if (irq != head) /* Release MSI-X irq */
@@ -935,7 +845,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev)
pci_name(dev));
BUG_ON(warning > 0);
}
- dev->irq = temp; /* Restore IOAPIC IRQ */
}
}
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index e5ae3a0..4438ae1 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -150,8 +150,7 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
}
/**
- * pci_match_device - Tell if a PCI device structure has a matching
- * PCI device id structure
+ * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
* @drv: the PCI driver to match against
* @dev: the PCI device structure to match against
*
@@ -162,14 +161,9 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
const struct pci_device_id *pci_match_device(struct pci_driver *drv,
struct pci_dev *dev)
{
- const struct pci_device_id *id;
struct pci_dynid *dynid;
- id = pci_match_id(drv->id_table, dev);
- if (id)
- return id;
-
- /* static ids didn't match, lets look at the dynamic ones */
+ /* Look at the dynamic ids first, before the static ones */
spin_lock(&drv->dynids.lock);
list_for_each_entry(dynid, &drv->dynids.list, node) {
if (pci_match_one_device(&dynid->id, dev)) {
@@ -178,7 +172,8 @@ const struct pci_device_id *pci_match_device(struct pci_driver *drv,
}
}
spin_unlock(&drv->dynids.lock);
- return NULL;
+
+ return pci_match_id(drv->id_table, dev);
}
static int pci_call_probe(struct pci_driver *drv, struct pci_dev *dev,
@@ -329,8 +324,7 @@ static int pci_default_resume(struct pci_dev *pci_dev)
/* restore the PCI config space */
pci_restore_state(pci_dev);
/* if the device was enabled before suspend, reenable */
- if (atomic_read(&pci_dev->enable_cnt))
- retval = __pci_enable_device(pci_dev);
+ retval = __pci_reenable_device(pci_dev);
/* if the device was busmaster before the suspend, make it busmaster again */
if (pci_dev->is_busmaster)
pci_set_master(pci_dev);
@@ -357,6 +351,8 @@ static int pci_device_resume_early(struct device * dev)
struct pci_dev * pci_dev = to_pci_dev(dev);
struct pci_driver * drv = pci_dev->driver;
+ pci_fixup_device(pci_fixup_resume, pci_dev);
+
if (drv && drv->resume_early)
error = drv->resume_early(pci_dev);
return error;
@@ -425,7 +421,8 @@ static struct kobj_type pci_driver_kobj_type = {
* If no error occurred, the driver remains registered even if
* no device was claimed during registration.
*/
-int __pci_register_driver(struct pci_driver *drv, struct module *owner)
+int __pci_register_driver(struct pci_driver *drv, struct module *owner,
+ const char *mod_name)
{
int error;
@@ -433,6 +430,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner)
drv->driver.name = drv->name;
drv->driver.bus = &pci_bus_type;
drv->driver.owner = owner;
+ drv->driver.mod_name = mod_name;
drv->driver.kobj.ktype = &pci_driver_kobj_type;
if (pci_multithread_probe)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 5a14b73..8b44cff 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -68,12 +68,14 @@ pci_max_busnr(void)
#endif /* 0 */
-static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos, int cap)
+#define PCI_FIND_CAP_TTL 48
+
+static int __pci_find_next_cap_ttl(struct pci_bus *bus, unsigned int devfn,
+ u8 pos, int cap, int *ttl)
{
u8 id;
- int ttl = 48;
- while (ttl--) {
+ while ((*ttl)--) {
pci_bus_read_config_byte(bus, devfn, pos, &pos);
if (pos < 0x40)
break;
@@ -89,6 +91,14 @@ static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn, u8 pos,
return 0;
}
+static int __pci_find_next_cap(struct pci_bus *bus, unsigned int devfn,
+ u8 pos, int cap)
+{
+ int ttl = PCI_FIND_CAP_TTL;
+
+ return __pci_find_next_cap_ttl(bus, devfn, pos, cap, &ttl);
+}
+
int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap)
{
return __pci_find_next_cap(dev->bus, dev->devfn,
@@ -96,10 +106,10 @@ int pci_find_next_capability(struct pci_dev *dev, u8 pos, int 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)
+static int __pci_bus_find_cap_start(struct pci_bus *bus,
+ unsigned int devfn, u8 hdr_type)
{
u16 status;
- u8 pos;
pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);
if (!(status & PCI_STATUS_CAP_LIST))
@@ -108,15 +118,14 @@ 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:
- pos = PCI_CAPABILITY_LIST;
- break;
+ return PCI_CAPABILITY_LIST;
case PCI_HEADER_TYPE_CARDBUS:
- pos = PCI_CB_CAPABILITY_LIST;
- break;
+ return PCI_CB_CAPABILITY_LIST;
default:
return 0;
}
- return __pci_find_next_cap(bus, devfn, pos, cap);
+
+ return 0;
}
/**
@@ -140,7 +149,13 @@ static int __pci_bus_find_cap(struct pci_bus *bus, unsigned int devfn, u8 hdr_ty
*/
int pci_find_capability(struct pci_dev *dev, int cap)
{
- return __pci_bus_find_cap(dev->bus, dev->devfn, dev->hdr_type, cap);
+ int pos;
+
+ pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
+ if (pos)
+ pos = __pci_find_next_cap(dev->bus, dev->devfn, pos, cap);
+
+ return pos;
}
/**
@@ -158,11 +173,16 @@ int pci_find_capability(struct pci_dev *dev, int cap)
*/
int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
{
+ int pos;
u8 hdr_type;
pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type);
- return __pci_bus_find_cap(bus, devfn, hdr_type & 0x7f, cap);
+ pos = __pci_bus_find_cap_start(bus, devfn, hdr_type & 0x7f);
+ if (pos)
+ pos = __pci_find_next_cap(bus, devfn, pos, cap);
+
+ return pos;
}
/**
@@ -214,6 +234,75 @@ int pci_find_ext_capability(struct pci_dev *dev, int cap)
}
EXPORT_SYMBOL_GPL(pci_find_ext_capability);
+static int __pci_find_next_ht_cap(struct pci_dev *dev, int pos, int ht_cap)
+{
+ int rc, ttl = PCI_FIND_CAP_TTL;
+ u8 cap, mask;
+
+ if (ht_cap == HT_CAPTYPE_SLAVE || ht_cap == HT_CAPTYPE_HOST)
+ mask = HT_3BIT_CAP_MASK;
+ else
+ mask = HT_5BIT_CAP_MASK;
+
+ pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn, pos,
+ PCI_CAP_ID_HT, &ttl);
+ while (pos) {
+ rc = pci_read_config_byte(dev, pos + 3, &cap);
+ if (rc != PCIBIOS_SUCCESSFUL)
+ return 0;
+
+ if ((cap & mask) == ht_cap)
+ return pos;
+
+ pos = __pci_find_next_cap_ttl(dev->bus, dev->devfn,
+ pos + PCI_CAP_LIST_NEXT,
+ PCI_CAP_ID_HT, &ttl);
+ }
+
+ return 0;
+}
+/**
+ * pci_find_next_ht_capability - query a device's Hypertransport capabilities
+ * @dev: PCI device to query
+ * @pos: Position from which to continue searching
+ * @ht_cap: Hypertransport capability code
+ *
+ * To be used in conjunction with pci_find_ht_capability() to search for
+ * all capabilities matching @ht_cap. @pos should always be a value returned
+ * from pci_find_ht_capability().
+ *
+ * NB. To be 100% safe against broken PCI devices, the caller should take
+ * steps to avoid an infinite loop.
+ */
+int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap)
+{
+ return __pci_find_next_ht_cap(dev, pos + PCI_CAP_LIST_NEXT, ht_cap);
+}
+EXPORT_SYMBOL_GPL(pci_find_next_ht_capability);
+
+/**
+ * pci_find_ht_capability - query a device's Hypertransport capabilities
+ * @dev: PCI device to query
+ * @ht_cap: Hypertransport capability code
+ *
+ * Tell if a device supports a given Hypertransport capability.
+ * Returns an address within the device's PCI configuration space
+ * or 0 in case the device does not support the request capability.
+ * The address points to the PCI capability, of type PCI_CAP_ID_HT,
+ * which has a Hypertransport capability matching @ht_cap.
+ */
+int pci_find_ht_capability(struct pci_dev *dev, int ht_cap)
+{
+ int pos;
+
+ pos = __pci_bus_find_cap_start(dev->bus, dev->devfn, dev->hdr_type);
+ if (pos)
+ pos = __pci_find_next_ht_cap(dev, pos, ht_cap);
+
+ return pos;
+}
+EXPORT_SYMBOL_GPL(pci_find_ht_capability);
+
/**
* pci_find_parent_resource - return resource region of parent bus of given region
* @dev: PCI device structure contains resources to be searched
@@ -303,6 +392,14 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
if (state > PCI_D3hot)
state = PCI_D3hot;
+ /*
+ * If the device or the parent bridge can't support PCI PM, ignore
+ * the request if we're doing anything besides putting it into D0
+ * (which would only happen on boot).
+ */
+ if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
+ return 0;
+
/* 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
@@ -314,13 +411,6 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
} else if (dev->current_state == state)
return 0; /* we're already there */
- /*
- * If the device or the parent bridge can't support PCI PM, ignore
- * the request if we're doing anything besides putting it into D0
- * (which would only happen on boot).
- */
- if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
- return 0;
/* find PCI PM capability in list */
pm = pci_find_capability(dev, PCI_CAP_ID_PM);
@@ -544,8 +634,6 @@ pci_save_state(struct pci_dev *dev)
pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]);
if ((i = pci_save_msi_state(dev)) != 0)
return i;
- if ((i = pci_save_msix_state(dev)) != 0)
- return i;
if ((i = pci_save_pcie_state(dev)) != 0)
return i;
if ((i = pci_save_pcix_state(dev)) != 0)
@@ -583,22 +671,11 @@ pci_restore_state(struct pci_dev *dev)
}
pci_restore_pcix_state(dev);
pci_restore_msi_state(dev);
- pci_restore_msix_state(dev);
+
return 0;
}
-/**
- * pci_enable_device_bars - Initialize some of a device for use
- * @dev: PCI device to be initialized
- * @bars: bitmask of BAR's that must be configured
- *
- * Initialize device before it's used by a driver. Ask low-level code
- * to enable selected I/O and memory resources. Wake up the device if it
- * was suspended. Beware, this function can fail.
- */
-
-int
-pci_enable_device_bars(struct pci_dev *dev, int bars)
+static int do_pci_enable_device(struct pci_dev *dev, int bars)
{
int err;
@@ -608,30 +685,47 @@ pci_enable_device_bars(struct pci_dev *dev, int bars)
err = pcibios_enable_device(dev, bars);
if (err < 0)
return err;
+ pci_fixup_device(pci_fixup_enable, dev);
+
+ return 0;
+}
+
+/**
+ * __pci_reenable_device - Resume abandoned device
+ * @dev: PCI device to be resumed
+ *
+ * Note this function is a backend of pci_default_resume and is not supposed
+ * to be called by normal code, write proper resume handler and use it instead.
+ */
+int
+__pci_reenable_device(struct pci_dev *dev)
+{
+ if (atomic_read(&dev->enable_cnt))
+ return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
return 0;
}
/**
- * __pci_enable_device - Initialize device before it's used by a driver.
+ * pci_enable_device_bars - Initialize some of a device for use
* @dev: PCI device to be initialized
+ * @bars: bitmask of BAR's that must be configured
*
* Initialize device before it's used by a driver. Ask low-level code
- * to enable I/O and memory. Wake up the device if it was suspended.
- * Beware, this function can fail.
- *
- * Note this function is a backend and is not supposed to be called by
- * normal code, use pci_enable_device() instead.
+ * to enable selected I/O and memory resources. Wake up the device if it
+ * was suspended. Beware, this function can fail.
*/
int
-__pci_enable_device(struct pci_dev *dev)
+pci_enable_device_bars(struct pci_dev *dev, int bars)
{
int err;
- err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
- if (err)
- return err;
- pci_fixup_device(pci_fixup_enable, dev);
- return 0;
+ if (atomic_add_return(1, &dev->enable_cnt) > 1)
+ return 0; /* already enabled */
+
+ err = do_pci_enable_device(dev, bars);
+ if (err < 0)
+ atomic_dec(&dev->enable_cnt);
+ return err;
}
/**
@@ -647,13 +741,105 @@ __pci_enable_device(struct pci_dev *dev)
*/
int pci_enable_device(struct pci_dev *dev)
{
- int result;
- if (atomic_add_return(1, &dev->enable_cnt) > 1)
- return 0; /* already enabled */
- result = __pci_enable_device(dev);
- if (result < 0)
- atomic_dec(&dev->enable_cnt);
- return result;
+ return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
+}
+
+/*
+ * Managed PCI resources. This manages device on/off, intx/msi/msix
+ * on/off and BAR regions. pci_dev itself records msi/msix status, so
+ * there's no need to track it separately. pci_devres is initialized
+ * when a device is enabled using managed PCI device enable interface.
+ */
+struct pci_devres {
+ unsigned int disable:1;
+ unsigned int orig_intx:1;
+ unsigned int restore_intx:1;
+ u32 region_mask;
+};
+
+static void pcim_release(struct device *gendev, void *res)
+{
+ struct pci_dev *dev = container_of(gendev, struct pci_dev, dev);
+ struct pci_devres *this = res;
+ int i;
+
+ if (dev->msi_enabled)
+ pci_disable_msi(dev);
+ if (dev->msix_enabled)
+ pci_disable_msix(dev);
+
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++)
+ if (this->region_mask & (1 << i))
+ pci_release_region(dev, i);
+
+ if (this->restore_intx)
+ pci_intx(dev, this->orig_intx);
+
+ if (this->disable)
+ pci_disable_device(dev);
+}
+
+static struct pci_devres * get_pci_dr(struct pci_dev *pdev)
+{
+ struct pci_devres *dr, *new_dr;
+
+ dr = devres_find(&pdev->dev, pcim_release, NULL, NULL);
+ if (dr)
+ return dr;
+
+ new_dr = devres_alloc(pcim_release, sizeof(*new_dr), GFP_KERNEL);
+ if (!new_dr)
+ return NULL;
+ return devres_get(&pdev->dev, new_dr, NULL, NULL);
+}
+
+static struct pci_devres * find_pci_dr(struct pci_dev *pdev)
+{
+ if (pci_is_managed(pdev))
+ return devres_find(&pdev->dev, pcim_release, NULL, NULL);
+ return NULL;
+}
+
+/**
+ * pcim_enable_device - Managed pci_enable_device()
+ * @pdev: PCI device to be initialized
+ *
+ * Managed pci_enable_device().
+ */
+int pcim_enable_device(struct pci_dev *pdev)
+{
+ struct pci_devres *dr;
+ int rc;
+
+ dr = get_pci_dr(pdev);
+ if (unlikely(!dr))
+ return -ENOMEM;
+ WARN_ON(!!dr->disable);
+
+ rc = pci_enable_device(pdev);
+ if (!rc) {
+ pdev->is_managed = 1;
+ dr->disable = 1;
+ }
+ return rc;
+}
+
+/**
+ * pcim_pin_device - Pin managed PCI device
+ * @pdev: PCI device to pin
+ *
+ * Pin managed PCI device @pdev. Pinned device won't be disabled on
+ * driver detach. @pdev must have been enabled with
+ * pcim_enable_device().
+ */
+void pcim_pin_device(struct pci_dev *pdev)
+{
+ struct pci_devres *dr;
+
+ dr = find_pci_dr(pdev);
+ WARN_ON(!dr || !dr->disable);
+ if (dr)
+ dr->disable = 0;
}
/**
@@ -679,8 +865,13 @@ void __attribute__ ((weak)) pcibios_disable_device (struct pci_dev *dev) {}
void
pci_disable_device(struct pci_dev *dev)
{
+ struct pci_devres *dr;
u16 pci_command;
+ dr = find_pci_dr(dev);
+ if (dr)
+ dr->disable = 0;
+
if (atomic_sub_return(1, &dev->enable_cnt) != 0)
return;
@@ -779,6 +970,8 @@ pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
*/
void pci_release_region(struct pci_dev *pdev, int bar)
{
+ struct pci_devres *dr;
+
if (pci_resource_len(pdev, bar) == 0)
return;
if (pci_resource_flags(pdev, bar) & IORESOURCE_IO)
@@ -787,6 +980,10 @@ void pci_release_region(struct pci_dev *pdev, int bar)
else if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM)
release_mem_region(pci_resource_start(pdev, bar),
pci_resource_len(pdev, bar));
+
+ dr = find_pci_dr(pdev);
+ if (dr)
+ dr->region_mask &= ~(1 << bar);
}
/**
@@ -805,6 +1002,8 @@ void pci_release_region(struct pci_dev *pdev, int bar)
*/
int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
{
+ struct pci_devres *dr;
+
if (pci_resource_len(pdev, bar) == 0)
return 0;
@@ -818,7 +1017,11 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
pci_resource_len(pdev, bar), res_name))
goto err_out;
}
-
+
+ dr = find_pci_dr(pdev);
+ if (dr)
+ dr->region_mask |= 1 << bar;
+
return 0;
err_out:
@@ -832,6 +1035,47 @@ err_out:
return -EBUSY;
}
+/**
+ * pci_release_selected_regions - Release selected PCI I/O and memory resources
+ * @pdev: PCI device whose resources were previously reserved
+ * @bars: Bitmask of BARs to be released
+ *
+ * Release selected PCI I/O and memory resources previously reserved.
+ * Call this function only after all use of the PCI regions has ceased.
+ */
+void pci_release_selected_regions(struct pci_dev *pdev, int bars)
+{
+ int i;
+
+ for (i = 0; i < 6; i++)
+ if (bars & (1 << i))
+ pci_release_region(pdev, i);
+}
+
+/**
+ * pci_request_selected_regions - Reserve selected PCI I/O and memory resources
+ * @pdev: PCI device whose resources are to be reserved
+ * @bars: Bitmask of BARs to be requested
+ * @res_name: Name to be associated with resource
+ */
+int pci_request_selected_regions(struct pci_dev *pdev, int bars,
+ const char *res_name)
+{
+ int i;
+
+ for (i = 0; i < 6; i++)
+ if (bars & (1 << i))
+ if(pci_request_region(pdev, i, res_name))
+ goto err_out;
+ return 0;
+
+err_out:
+ while(--i >= 0)
+ if (bars & (1 << i))
+ pci_release_region(pdev, i);
+
+ return -EBUSY;
+}
/**
* pci_release_regions - Release reserved PCI I/O and memory resources
@@ -844,10 +1088,7 @@ err_out:
void pci_release_regions(struct pci_dev *pdev)
{
- int i;
-
- for (i = 0; i < 6; i++)
- pci_release_region(pdev, i);
+ pci_release_selected_regions(pdev, (1 << 6) - 1);
}
/**
@@ -865,18 +1106,7 @@ void pci_release_regions(struct pci_dev *pdev)
*/
int pci_request_regions(struct pci_dev *pdev, const char *res_name)
{
- int i;
-
- for (i = 0; i < 6; i++)
- if(pci_request_region(pdev, i, res_name))
- goto err_out;
- return 0;
-
-err_out:
- while(--i >= 0)
- pci_release_region(pdev, i);
-
- return -EBUSY;
+ return pci_request_selected_regions(pdev, ((1 << 6) - 1), res_name);
}
/**
@@ -1029,7 +1259,15 @@ pci_intx(struct pci_dev *pdev, int enable)
}
if (new != pci_command) {
+ struct pci_devres *dr;
+
pci_write_config_word(pdev, PCI_COMMAND, new);
+
+ dr = find_pci_dr(pdev);
+ if (dr && !dr->restore_intx) {
+ dr->restore_intx = 1;
+ dr->orig_intx = !enable;
+ }
}
}
@@ -1059,7 +1297,23 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
return 0;
}
#endif
-
+
+/**
+ * pci_select_bars - Make BAR mask from the type of resource
+ * @pdev: the PCI device for which BAR mask is made
+ * @flags: resource type mask to be selected
+ *
+ * This helper routine makes bar mask from the type of resource.
+ */
+int pci_select_bars(struct pci_dev *dev, unsigned long flags)
+{
+ int i, bars = 0;
+ for (i = 0; i < PCI_NUM_RESOURCES; i++)
+ if (pci_resource_flags(dev, i) & flags)
+ bars |= (1 << i);
+ return bars;
+}
+
static int __devinit pci_init(void)
{
struct pci_dev *dev = NULL;
@@ -1092,15 +1346,11 @@ early_param("pci", pci_setup);
device_initcall(pci_init);
-#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
-/* FIXME: Some boxes have multiple ISA bridges! */
-struct pci_dev *isa_bridge;
-EXPORT_SYMBOL(isa_bridge);
-#endif
-
EXPORT_SYMBOL_GPL(pci_restore_bars);
EXPORT_SYMBOL(pci_enable_device_bars);
EXPORT_SYMBOL(pci_enable_device);
+EXPORT_SYMBOL(pcim_enable_device);
+EXPORT_SYMBOL(pcim_pin_device);
EXPORT_SYMBOL(pci_disable_device);
EXPORT_SYMBOL(pci_find_capability);
EXPORT_SYMBOL(pci_bus_find_capability);
@@ -1108,6 +1358,8 @@ EXPORT_SYMBOL(pci_release_regions);
EXPORT_SYMBOL(pci_request_regions);
EXPORT_SYMBOL(pci_release_region);
EXPORT_SYMBOL(pci_request_region);
+EXPORT_SYMBOL(pci_release_selected_regions);
+EXPORT_SYMBOL(pci_request_selected_regions);
EXPORT_SYMBOL(pci_set_master);
EXPORT_SYMBOL(pci_set_mwi);
EXPORT_SYMBOL(pci_clear_mwi);
@@ -1116,13 +1368,10 @@ 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);
EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_save_state);
EXPORT_SYMBOL(pci_restore_state);
EXPORT_SYMBOL(pci_enable_wake);
-/* Quirk info */
-
-EXPORT_SYMBOL(isa_dma_bridge_buggy);
-EXPORT_SYMBOL(pci_pci_problems);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 398852f..a4f2d58 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1,6 +1,6 @@
/* Functions internal to the PCI core code */
-extern int __must_check __pci_enable_device(struct pci_dev *);
+extern int __must_check __pci_reenable_device(struct pci_dev *);
extern int pci_uevent(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size);
extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
@@ -43,12 +43,8 @@ extern void pci_remove_legacy_files(struct pci_bus *bus);
/* Lock for read/write access to pci device and bus lists */
extern struct rw_semaphore pci_bus_sem;
-#ifdef CONFIG_PCI_MSI
-extern int pci_msi_quirk;
-#else
-#define pci_msi_quirk 0
-#endif
extern unsigned int pci_pm_d3_delay;
+
#ifdef CONFIG_PCI_MSI
void disable_msi_mode(struct pci_dev *dev, int pos, int type);
void pci_no_msi(void);
@@ -56,17 +52,15 @@ void pci_no_msi(void);
static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { }
static inline void pci_no_msi(void) { }
#endif
+
#if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
int pci_save_msi_state(struct pci_dev *dev);
-int pci_save_msix_state(struct pci_dev *dev);
void pci_restore_msi_state(struct pci_dev *dev);
-void pci_restore_msix_state(struct pci_dev *dev);
#else
static inline int pci_save_msi_state(struct pci_dev *dev) { return 0; }
-static inline int pci_save_msix_state(struct pci_dev *dev) { return 0; }
static inline void pci_restore_msi_state(struct pci_dev *dev) {}
-static inline void pci_restore_msix_state(struct pci_dev *dev) {}
#endif
+
static inline int pci_no_d1d2(struct pci_dev *dev)
{
unsigned int parent_dstates = 0;
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 55866b6..6f5fabb 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -148,7 +148,7 @@ static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev)
{
struct aer_rpc *rpc;
- if (!(rpc = (struct aer_rpc *)kmalloc(sizeof(struct aer_rpc),
+ if (!(rpc = kmalloc(sizeof(struct aer_rpc),
GFP_KERNEL)))
return NULL;
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index b4da795..f17e7ed 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -90,7 +90,7 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
return -ENODEV;
pci_set_master(dev);
- if (!dev->irq) {
+ if (!dev->irq && dev->pin) {
printk(KERN_WARNING
"%s->Dev[%04x:%04x] has invalid IRQ. Check vendor BIOS\n",
__FUNCTION__, dev->device, dev->vendor);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 6a3c1e7..2fe1d69 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -144,6 +144,32 @@ static u32 pci_size(u32 base, u32 maxbase, u32 mask)
return size;
}
+static u64 pci_size64(u64 base, u64 maxbase, u64 mask)
+{
+ u64 size = mask & maxbase; /* Find the significant bits */
+ if (!size)
+ return 0;
+
+ /* Get the lowest of them to find the decode size, and
+ from that the extent. */
+ size = (size & ~(size-1)) - 1;
+
+ /* base == maxbase can be valid only if the BAR has
+ already been programmed with all 1s. */
+ if (base == maxbase && ((base | size) & mask) != mask)
+ return 0;
+
+ return size;
+}
+
+static inline int is_64bit_memory(u32 mask)
+{
+ if ((mask & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
+ (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64))
+ return 1;
+ return 0;
+}
+
static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
{
unsigned int pos, reg, next;
@@ -151,6 +177,10 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
struct resource *res;
for(pos=0; pos<howmany; pos = next) {
+ u64 l64;
+ u64 sz64;
+ u32 raw_sz;
+
next = pos+1;
res = &dev->resource[pos];
res->name = pci_name(dev);
@@ -163,9 +193,16 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
continue;
if (l == 0xffffffff)
l = 0;
- if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+ raw_sz = sz;
+ if ((l & PCI_BASE_ADDRESS_SPACE) ==
+ PCI_BASE_ADDRESS_SPACE_MEMORY) {
sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK);
- if (!sz)
+ /*
+ * For 64bit prefetchable memory sz could be 0, if the
+ * real size is bigger than 4G, so we need to check
+ * szhi for that.
+ */
+ if (!is_64bit_memory(l) && !sz)
continue;
res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
@@ -178,30 +215,36 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
}
res->end = res->start + (unsigned long) sz;
res->flags |= pci_calc_resource_flags(l);
- if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
- == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+ if (is_64bit_memory(l)) {
u32 szhi, lhi;
+
pci_read_config_dword(dev, reg+4, &lhi);
pci_write_config_dword(dev, reg+4, ~0);
pci_read_config_dword(dev, reg+4, &szhi);
pci_write_config_dword(dev, reg+4, lhi);
- szhi = pci_size(lhi, szhi, 0xffffffff);
+ sz64 = ((u64)szhi << 32) | raw_sz;
+ l64 = ((u64)lhi << 32) | l;
+ sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK);
next++;
#if BITS_PER_LONG == 64
- res->start |= ((unsigned long) lhi) << 32;
- res->end = res->start + sz;
- if (szhi) {
- /* This BAR needs > 4GB? Wow. */
- res->end |= (unsigned long)szhi<<32;
+ if (!sz64) {
+ res->start = 0;
+ res->end = 0;
+ res->flags = 0;
+ continue;
}
+ res->start = l64 & PCI_BASE_ADDRESS_MEM_MASK;
+ res->end = res->start + sz64;
#else
- if (szhi) {
- printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev));
+ if (sz64 > 0x100000000ULL) {
+ printk(KERN_ERR "PCI: Unable to handle 64-bit "
+ "BAR for device %s\n", pci_name(dev));
res->start = 0;
res->flags = 0;
} else if (lhi) {
/* 64-bit wide address, treat as disabled */
- pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
+ pci_write_config_dword(dev, reg,
+ l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
pci_write_config_dword(dev, reg+4, 0);
res->start = 0;
res->end = sz;
@@ -639,6 +682,8 @@ static void pci_read_irq(struct pci_dev *dev)
dev->irq = irq;
}
+#define LEGACY_IO_RESOURCE (IORESOURCE_IO | IORESOURCE_PCI_FIXED)
+
/**
* pci_setup_device - fill in class and map information of a device
* @dev: the device structure to fill
@@ -692,18 +737,18 @@ static int pci_setup_device(struct pci_dev * dev)
if ((progif & 1) == 0) {
dev->resource[0].start = 0x1F0;
dev->resource[0].end = 0x1F7;
- dev->resource[0].flags = IORESOURCE_IO;
+ dev->resource[0].flags = LEGACY_IO_RESOURCE;
dev->resource[1].start = 0x3F6;
dev->resource[1].end = 0x3F6;
- dev->resource[1].flags = IORESOURCE_IO;
+ dev->resource[1].flags = LEGACY_IO_RESOURCE;
}
if ((progif & 4) == 0) {
dev->resource[2].start = 0x170;
dev->resource[2].end = 0x177;
- dev->resource[2].flags = IORESOURCE_IO;
+ dev->resource[2].flags = LEGACY_IO_RESOURCE;
dev->resource[3].start = 0x376;
dev->resource[3].end = 0x376;
- dev->resource[3].flags = IORESOURCE_IO;
+ dev->resource[3].flags = LEGACY_IO_RESOURCE;
}
}
break;
@@ -900,7 +945,6 @@ pci_scan_single_device(struct pci_bus *bus, int devfn)
return NULL;
pci_device_add(dev, bus);
- pci_scan_msi_device(dev);
return dev;
}
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 99cf333..4a6760a 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -23,7 +23,7 @@ static loff_t
proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
{
loff_t new = -1;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
mutex_lock(&inode->i_mutex);
switch (whence) {
@@ -48,7 +48,7 @@ proc_bus_pci_lseek(struct file *file, loff_t off, int whence)
static ssize_t
proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
- const struct inode *ino = file->f_dentry->d_inode;
+ const struct inode *ino = file->f_path.dentry->d_inode;
const struct proc_dir_entry *dp = PDE(ino);
struct pci_dev *dev = dp->data;
unsigned int pos = *ppos;
@@ -130,7 +130,7 @@ proc_bus_pci_read(struct file *file, char __user *buf, size_t nbytes, loff_t *pp
static ssize_t
proc_bus_pci_write(struct file *file, const char __user *buf, size_t nbytes, loff_t *ppos)
{
- const struct inode *ino = file->f_dentry->d_inode;
+ const struct inode *ino = file->f_path.dentry->d_inode;
const struct proc_dir_entry *dp = PDE(ino);
struct pci_dev *dev = dp->data;
int pos = *ppos;
@@ -245,7 +245,7 @@ static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned i
#ifdef HAVE_PCI_MMAP
static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file->f_path.dentry->d_inode;
const struct proc_dir_entry *dp = PDE(inode);
struct pci_dev *dev = dp->data;
struct pci_filp_private *fpriv = file->private_data;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 9ca9b9b..1e6eda2 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -36,7 +36,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX,PCI_DEVICE_ID_MELLANOX_TAVOR_BRID
/* Deal with broken BIOS'es that neglect to enable passive release,
which can cause problems in combination with the 82441FX/PPro MTRRs */
-static void __devinit quirk_passive_release(struct pci_dev *dev)
+static void quirk_passive_release(struct pci_dev *dev)
{
struct pci_dev *d = NULL;
unsigned char dlc;
@@ -53,6 +53,7 @@ static void __devinit quirk_passive_release(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_passive_release );
/* The VIA VP2/VP3/MVP3 seem to have some 'features'. There may be a workaround
but VIA don't answer queries. If you happen to have good contacts at VIA
@@ -60,7 +61,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441, quirk_pa
This appears to be BIOS not version dependent. So presumably there is a
chipset level fix */
-int isa_dma_bridge_buggy; /* Exported */
+int isa_dma_bridge_buggy;
+EXPORT_SYMBOL(isa_dma_bridge_buggy);
static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev)
{
@@ -82,6 +84,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_2, quirk_isa_d
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_3, quirk_isa_dma_hangs );
int pci_pci_problems;
+EXPORT_SYMBOL(pci_pci_problems);
/*
* Chipsets where PCI->PCI transfers vanish or hang
@@ -93,6 +96,8 @@ static void __devinit quirk_nopcipci(struct pci_dev *dev)
pci_pci_problems |= PCIPCI_FAIL;
}
}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci );
static void __devinit quirk_nopciamd(struct pci_dev *dev)
{
@@ -104,9 +109,6 @@ static void __devinit quirk_nopciamd(struct pci_dev *dev)
pci_pci_problems |= PCIAGP_FAIL;
}
}
-
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopciamd );
/*
@@ -134,7 +136,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82439TX, quir
* Updated based on further information from the site and also on
* information provided by VIA
*/
-static void __devinit quirk_vialatency(struct pci_dev *dev)
+static void quirk_vialatency(struct pci_dev *dev)
{
struct pci_dev *p;
u8 rev;
@@ -185,6 +187,10 @@ exit:
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency );
+/* Must restore this on a resume from RAM */
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8361, quirk_vialatency );
/*
* VIA Apollo VP3 needs ETBF on BT848/878
@@ -532,7 +538,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_vt8235
* TODO: When we have device-specific interrupt routers,
* this code will go away from quirks.
*/
-static void __devinit quirk_via_ioapic(struct pci_dev *dev)
+static void quirk_via_ioapic(struct pci_dev *dev)
{
u8 tmp;
@@ -548,6 +554,7 @@ static void __devinit quirk_via_ioapic(struct pci_dev *dev)
pci_write_config_byte (dev, 0x58, tmp);
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic );
/*
* VIA 8237: Some BIOSs don't set the 'Bypass APIC De-Assert Message' Bit.
@@ -555,7 +562,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_i
* Set this bit to get rid of cycle wastage.
* Otherwise uncritical.
*/
-static void __devinit quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev)
+static void quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev)
{
u8 misc_control2;
#define BYPASS_APIC_DEASSERT 8
@@ -567,6 +574,7 @@ static void __devinit quirk_via_vt8237_bypass_apic_deassert(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_vt8237_bypass_apic_deassert);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_vt8237_bypass_apic_deassert);
/*
* The AMD io apic can hang the box when an apic irq is masked.
@@ -600,7 +608,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw );
#define AMD8131_revB0 0x11
#define AMD8131_MISC 0x40
#define AMD8131_NIOAMODE_BIT 0
-static void __init quirk_amd_8131_ioapic(struct pci_dev *dev)
+static void quirk_amd_8131_ioapic(struct pci_dev *dev)
{
unsigned char revid, tmp;
@@ -616,6 +624,7 @@ static void __init quirk_amd_8131_ioapic(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic);
#endif /* CONFIG_X86_IO_APIC */
@@ -641,48 +650,67 @@ static void __devinit quirk_via_acpi(struct pci_dev *d)
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi );
+
/*
- * Via 686A/B: The PCI_INTERRUPT_LINE register for the on-chip
- * devices, USB0/1, AC97, MC97, and ACPI, has an unusual feature:
- * when written, it makes an internal connection to the PIC.
- * For these devices, this register is defined to be 4 bits wide.
- * Normally this is fine. However for IO-APIC motherboards, or
- * non-x86 architectures (yes Via exists on PPC among other places),
- * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get
- * interrupts delivered properly.
- *
- * Some of the on-chip devices are actually '586 devices' so they are
- * listed here.
+ * VIA bridges which have VLink
*/
-static int via_irq_fixup_needed = -1;
+static int via_vlink_dev_lo = -1, via_vlink_dev_hi = 18;
-/*
- * As some VIA hardware is available in PCI-card form, we need to restrict
- * this quirk to VIA PCI hardware built onto VIA-based motherboards only.
- * We try to locate a VIA southbridge before deciding whether the quirk
- * should be applied.
+static void quirk_via_bridge(struct pci_dev *dev)
+{
+ /* See what bridge we have and find the device ranges */
+ switch (dev->device) {
+ case PCI_DEVICE_ID_VIA_82C686:
+ /* The VT82C686 is special, it attaches to PCI and can have
+ any device number. All its subdevices are functions of
+ that single device. */
+ via_vlink_dev_lo = PCI_SLOT(dev->devfn);
+ via_vlink_dev_hi = PCI_SLOT(dev->devfn);
+ break;
+ case PCI_DEVICE_ID_VIA_8237:
+ case PCI_DEVICE_ID_VIA_8237A:
+ via_vlink_dev_lo = 15;
+ break;
+ case PCI_DEVICE_ID_VIA_8235:
+ via_vlink_dev_lo = 16;
+ break;
+ case PCI_DEVICE_ID_VIA_8231:
+ case PCI_DEVICE_ID_VIA_8233_0:
+ case PCI_DEVICE_ID_VIA_8233A:
+ case PCI_DEVICE_ID_VIA_8233C_0:
+ via_vlink_dev_lo = 17;
+ break;
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, quirk_via_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_0, quirk_via_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233A, quirk_via_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233C_0, quirk_via_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_via_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_bridge);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A, quirk_via_bridge);
+
+/**
+ * quirk_via_vlink - VIA VLink IRQ number update
+ * @dev: PCI device
+ *
+ * If the device we are dealing with is on a PIC IRQ we need to
+ * ensure that the IRQ line register which usually is not relevant
+ * for PCI cards, is actually written so that interrupts get sent
+ * to the right place.
+ * We only do this on systems where a VIA south bridge was detected,
+ * and only for VIA devices on the motherboard (see quirk_via_bridge
+ * above).
*/
-static const struct pci_device_id via_irq_fixup_tbl[] = {
- {
- .vendor = PCI_VENDOR_ID_VIA,
- .device = PCI_ANY_ID,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .class = PCI_CLASS_BRIDGE_ISA << 8,
- .class_mask = 0xffff00,
- },
- { 0, },
-};
-
-static void quirk_via_irq(struct pci_dev *dev)
+
+static void quirk_via_vlink(struct pci_dev *dev)
{
u8 irq, new_irq;
- if (via_irq_fixup_needed == -1)
- via_irq_fixup_needed = pci_dev_present(via_irq_fixup_tbl);
-
- if (!via_irq_fixup_needed)
+ /* Check if we have VLink at all */
+ if (via_vlink_dev_lo == -1)
return;
new_irq = dev->irq;
@@ -691,15 +719,23 @@ static void quirk_via_irq(struct pci_dev *dev)
if (!new_irq || new_irq > 15)
return;
+ /* Internal device ? */
+ if (dev->bus->number != 0 || PCI_SLOT(dev->devfn) > via_vlink_dev_hi ||
+ PCI_SLOT(dev->devfn) < via_vlink_dev_lo)
+ return;
+
+ /* This is an internal VLink device on a PIC interrupt. The BIOS
+ ought to have set this but may not have, so we redo it */
+
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
if (new_irq != irq) {
- printk(KERN_INFO "PCI: VIA IRQ fixup for %s, from %d to %d\n",
+ printk(KERN_INFO "PCI: VIA VLink IRQ fixup for %s, from %d to %d\n",
pci_name(dev), irq, new_irq);
udelay(15); /* unknown if delay really needed */
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
}
}
-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq);
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_vlink);
/*
* VIA VT82C598 has its device ID settable and many BIOSes
@@ -720,13 +756,14 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt
* do this even if the Linux CardBus driver is not loaded, because
* the Linux i82365 driver does not (and should not) handle CardBus.
*/
-static void __devinit quirk_cardbus_legacy(struct pci_dev *dev)
+static void quirk_cardbus_legacy(struct pci_dev *dev)
{
if ((PCI_CLASS_BRIDGE_CARDBUS << 8) ^ dev->class)
return;
pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0);
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
+DECLARE_PCI_FIXUP_RESUME(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
/*
* Following the PCI ordering rules is optional on the AMD762. I'm not
@@ -735,7 +772,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy);
* To be fair to AMD, it follows the spec by default, its BIOS people
* who turn it off!
*/
-static void __devinit quirk_amd_ordering(struct pci_dev *dev)
+static void quirk_amd_ordering(struct pci_dev *dev)
{
u32 pcic;
pci_read_config_dword(dev, 0x4C, &pcic);
@@ -749,6 +786,7 @@ static void __devinit quirk_amd_ordering(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering );
/*
* DreamWorks provided workaround for Dunord I-3000 problem
@@ -784,7 +822,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA, 0x605, quirk_transparent_bridge
* datasheets found at http://www.national.com/ds/GX for info on what
* these bits do. <christer@weinigel.se>
*/
-static void __init quirk_mediagx_master(struct pci_dev *dev)
+static void quirk_mediagx_master(struct pci_dev *dev)
{
u8 reg;
pci_read_config_byte(dev, 0x41, &reg);
@@ -795,13 +833,14 @@ static void __init quirk_mediagx_master(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master );
/*
* Ensure C0 rev restreaming is off. This is normally done by
* the BIOS but in the odd case it is not the results are corruption
* hence the presence of a Linux check
*/
-static void __init quirk_disable_pxb(struct pci_dev *pdev)
+static void quirk_disable_pxb(struct pci_dev *pdev)
{
u16 config;
u8 rev;
@@ -817,7 +856,25 @@ static void __init quirk_disable_pxb(struct pci_dev *pdev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, quirk_disable_pxb );
+
+static void __devinit quirk_sb600_sata(struct pci_dev *pdev)
+{
+ /* set sb600 sata to ahci mode */
+ if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+ u8 tmp;
+
+ pci_read_config_byte(pdev, 0x40, &tmp);
+ pci_write_config_byte(pdev, 0x40, tmp|1);
+ pci_write_config_byte(pdev, 0x9, 1);
+ pci_write_config_byte(pdev, 0xa, 6);
+ pci_write_config_byte(pdev, 0x40, tmp);
+
+ pdev->class = PCI_CLASS_STORAGE_SATA_AHCI;
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, quirk_sb600_sata);
/*
* Serverworks CSB5 IDE does not fully support native mode
@@ -874,7 +931,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, quirk_e
* runs everywhere at present we suppress the printk output in most
* irrelevant cases.
*/
-static void __init k8t_sound_hostbridge(struct pci_dev *dev)
+static void k8t_sound_hostbridge(struct pci_dev *dev)
{
unsigned char val;
@@ -893,8 +950,8 @@ static void __init k8t_sound_hostbridge(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_hostbridge);
-#ifndef CONFIG_ACPI_SLEEP
/*
* On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge
* is not activated. The myth is that Asus said that they do not want the
@@ -906,12 +963,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, k8t_sound_ho
* bridge. Unfortunately, this device has no subvendor/subdevice ID. So it
* becomes necessary to do this tweak in two steps -- I've chosen the Host
* bridge as trigger.
- *
- * Actually, leaving it unhidden and not redoing the quirk over suspend2ram
- * will cause thermal management to break down, and causing machine to
- * overheat.
*/
-static int __initdata asus_hides_smbus;
+static int asus_hides_smbus;
static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
{
@@ -924,47 +977,51 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
case 0x1626: /* L3C notebook */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB)
switch(dev->subsystem_device) {
case 0x80b1: /* P4GE-V */
case 0x80b2: /* P4PE */
case 0x8093: /* P4B533-V */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB)
switch(dev->subsystem_device) {
case 0x8030: /* P4T533 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_7205_0)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_7205_0)
switch (dev->subsystem_device) {
case 0x8070: /* P4G8X Deluxe */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH)
switch (dev->subsystem_device) {
case 0x80c9: /* PU-DLS */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
switch (dev->subsystem_device) {
case 0x1751: /* M2N notebook */
case 0x1821: /* M5N notebook */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
switch (dev->subsystem_device) {
case 0x184b: /* W1N notebook */
case 0x186a: /* M6Ne notebook */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) {
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
+ switch (dev->subsystem_device) {
+ case 0x80f2: /* P4P800-X */
+ asus_hides_smbus = 1;
+ }
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
switch (dev->subsystem_device) {
case 0x1882: /* M6V notebook */
case 0x1977: /* A6VA notebook */
asus_hides_smbus = 1;
}
- }
} else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_HP)) {
if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
switch(dev->subsystem_device) {
@@ -972,25 +1029,24 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
case 0x0890: /* HP Compaq nc6000 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
switch (dev->subsystem_device) {
case 0x12bc: /* HP D330L */
case 0x12bd: /* HP D530 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) {
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
switch (dev->subsystem_device) {
case 0x099c: /* HP Compaq nx6110 */
asus_hides_smbus = 1;
}
- }
} else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) {
if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
switch(dev->subsystem_device) {
case 0x0001: /* Toshiba Satellite A40 */
asus_hides_smbus = 1;
}
- if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+ else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
switch(dev->subsystem_device) {
case 0x0001: /* Toshiba Tecra M2 */
asus_hides_smbus = 1;
@@ -1019,7 +1075,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, as
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge );
-static void __init asus_hides_smbus_lpc(struct pci_dev *dev)
+static void asus_hides_smbus_lpc(struct pci_dev *dev)
{
u16 val;
@@ -1042,8 +1098,14 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asu
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc );
-static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev)
+static void asus_hides_smbus_lpc_ich6(struct pci_dev *dev)
{
u32 val, rcba;
void __iomem *base;
@@ -1059,20 +1121,28 @@ static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev)
printk(KERN_INFO "PCI: Enabled ICH6/i801 SMBus device\n");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 );
-
-#endif
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc_ich6 );
/*
* SiS 96x south bridge: BIOS typically hides SMBus device...
*/
-static void __init quirk_sis_96x_smbus(struct pci_dev *dev)
+static void quirk_sis_96x_smbus(struct pci_dev *dev)
{
u8 val = 0;
- printk(KERN_INFO "Enabling SiS 96x SMBus.\n");
- pci_read_config_byte(dev, 0x77, &val);
- pci_write_config_byte(dev, 0x77, val & ~0x10);
pci_read_config_byte(dev, 0x77, &val);
+ if (val & 0x10) {
+ printk(KERN_INFO "Enabling SiS 96x SMBus.\n");
+ pci_write_config_byte(dev, 0x77, val & ~0x10);
+ }
}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
/*
* ... This is further complicated by the fact that some SiS96x south
@@ -1082,11 +1152,9 @@ static void __init quirk_sis_96x_smbus(struct pci_dev *dev)
*
* We can also enable the sis96x bit in the discovery register..
*/
-static int __devinitdata sis_96x_compatible = 0;
-
#define SIS_DETECT_REGISTER 0x40
-static void __init quirk_sis_503(struct pci_dev *dev)
+static void quirk_sis_503(struct pci_dev *dev)
{
u8 reg;
u16 devid;
@@ -1099,36 +1167,25 @@ static void __init quirk_sis_503(struct pci_dev *dev)
return;
}
- /* Make people aware that we changed the config.. */
- printk(KERN_WARNING "Uncovering SIS%x that hid as a SIS503 (compatible=%d)\n", devid, sis_96x_compatible);
-
/*
- * Ok, it now shows up as a 96x.. The 96x quirks are after
- * the 503 quirk in the quirk table, so they'll automatically
- * run and enable things like the SMBus device
+ * Ok, it now shows up as a 96x.. run the 96x quirk by
+ * hand in case it has already been processed.
+ * (depends on link order, which is apparently not guaranteed)
*/
dev->device = devid;
+ quirk_sis_96x_smbus(dev);
}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 );
-static void __init quirk_sis_96x_compatible(struct pci_dev *dev)
-{
- sis_96x_compatible = 1;
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_645, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_646, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_648, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_650, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_651, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_735, quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, quirk_sis_503 );
/*
* On ASUS A8V and A8V Deluxe boards, the onboard AC97 audio controller
* and MC97 modem controller are disabled when a second PCI soundcard is
* present. This patch, tweaking the VT8237 ISA bridge, enables them.
* -- bjd
*/
-static void __init asus_hides_ac97_lpc(struct pci_dev *dev)
+static void asus_hides_ac97_lpc(struct pci_dev *dev)
{
u8 val;
int asus_hides_ac97 = 0;
@@ -1152,12 +1209,7 @@ static void __init asus_hides_ac97_lpc(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
-
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_961, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
#if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
@@ -1167,7 +1219,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_
* the PCI scanning.
*/
-static void __devinit quirk_jmicron_dualfn(struct pci_dev *pdev)
+static void quirk_jmicron_dualfn(struct pci_dev *pdev)
{
u32 conf;
u8 hdr;
@@ -1189,8 +1241,8 @@ static void __devinit quirk_jmicron_dualfn(struct pci_dev *pdev)
pci_read_config_dword(pdev, 0x40, &conf);
/* Enable dual function mode, AHCI on fn 0, IDE fn1 */
/* Set the class codes correctly and then direct IDE 0 */
- conf &= ~0x000F0200; /* Clear bit 9 and 16-19 */
- conf |= 0x00C20002; /* Set bit 1, 17, 22, 23 */
+ conf &= ~0x000FF200; /* Clear bit 9 and 12-19 */
+ conf |= 0x00C2A102; /* Set 1, 8, 13, 15, 17, 22, 23 */
pci_write_config_dword(pdev, 0x40, conf);
/* Reconfigure so that the PCI scanner discovers the
@@ -1203,8 +1255,8 @@ static void __devinit quirk_jmicron_dualfn(struct pci_dev *pdev)
break;
}
}
-
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
#endif
@@ -1346,6 +1398,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_co
int pcie_mch_quirk;
+EXPORT_SYMBOL(pcie_mch_quirk);
static void __devinit quirk_pcie_mch(struct pci_dev *pdev)
{
@@ -1407,6 +1460,24 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2609, quirk_intel_pcie_pm);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm);
+/*
+ * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size
+ * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes.
+ * Re-allocate the region if needed...
+ */
+static void __init quirk_tc86c001_ide(struct pci_dev *dev)
+{
+ struct resource *r = &dev->resource[0];
+
+ if (r->start & 0x8) {
+ r->start = 0;
+ r->end = 0xf;
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2,
+ PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
+ quirk_tc86c001_ide);
+
static void __devinit quirk_netmos(struct pci_dev *dev)
{
unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;
@@ -1532,6 +1603,8 @@ extern struct pci_fixup __start_pci_fixups_final[];
extern struct pci_fixup __end_pci_fixups_final[];
extern struct pci_fixup __start_pci_fixups_enable[];
extern struct pci_fixup __end_pci_fixups_enable[];
+extern struct pci_fixup __start_pci_fixups_resume[];
+extern struct pci_fixup __end_pci_fixups_resume[];
void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
@@ -1559,12 +1632,18 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
end = __end_pci_fixups_enable;
break;
+ case pci_fixup_resume:
+ start = __start_pci_fixups_resume;
+ end = __end_pci_fixups_resume;
+ break;
+
default:
/* stupid compiler warning, you would think with an enum... */
return;
}
pci_do_fixups(dev, start, end);
}
+EXPORT_SYMBOL(pci_fixup_device);
/* Enable 1k I/O space granularity on the Intel P64H2 */
static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
@@ -1592,11 +1671,36 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io);
+/* Fix the IOBL_ADR for 1k I/O space granularity on the Intel P64H2
+ * The IOBL_ADR gets re-written to 4k boundaries in pci_setup_bridge()
+ * in drivers/pci/setup-bus.c
+ */
+static void __devinit quirk_p64h2_1k_io_fix_iobl(struct pci_dev *dev)
+{
+ u16 en1k, iobl_adr, iobl_adr_1k;
+ struct resource *res = dev->resource + PCI_BRIDGE_RESOURCES;
+
+ pci_read_config_word(dev, 0x40, &en1k);
+
+ if (en1k & 0x200) {
+ pci_read_config_word(dev, PCI_IO_BASE, &iobl_adr);
+
+ iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00);
+
+ if (iobl_adr != iobl_adr_1k) {
+ printk(KERN_INFO "PCI: Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1 KB Granularity\n",
+ iobl_adr,iobl_adr_1k);
+ pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k);
+ }
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1460, quirk_p64h2_1k_io_fix_iobl);
+
/* Under some circumstances, AER is not linked with extended capabilities.
* Force it to be linked by setting the corresponding control bit in the
* config space.
*/
-static void __devinit quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev)
+static void quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev)
{
uint8_t b;
if (pci_read_config_byte(dev, 0xf41, &b) == 0) {
@@ -1610,11 +1714,10 @@ static void __devinit quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
quirk_nvidia_ck804_pcie_aer_ext_cap);
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
+ quirk_nvidia_ck804_pcie_aer_ext_cap);
#ifdef CONFIG_PCI_MSI
-/* To disable MSI globally */
-int pci_msi_quirk;
-
/* The Serverworks PCI-X chipset does not support MSI. We cannot easily rely
* on setting PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
* some other busses controlled by the chipset even if Linux is not aware of it.
@@ -1623,8 +1726,8 @@ int pci_msi_quirk;
*/
static void __init quirk_svw_msi(struct pci_dev *dev)
{
- pci_msi_quirk = 1;
- printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
+ pci_no_msi();
+ printk(KERN_WARNING "PCI: MSI quirk detected. MSI deactivated.\n");
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi);
@@ -1644,19 +1747,23 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_
* return 1 if a HT MSI capability is found and enabled */
static int __devinit msi_ht_cap_enabled(struct pci_dev *dev)
{
- u8 pos;
- int ttl;
- for (pos = pci_find_capability(dev, PCI_CAP_ID_HT), ttl = 48;
- pos && ttl;
- pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_HT), ttl--) {
- u32 cap_hdr;
- /* MSI mapping section according to Hypertransport spec */
- if (pci_read_config_dword(dev, pos, &cap_hdr) == 0
- && (cap_hdr & 0xf8000000) == 0xa8000000 /* MSI mapping */) {
- printk(KERN_INFO "PCI: Found HT MSI mapping on %s with capability %s\n",
- pci_name(dev), cap_hdr & 0x10000 ? "enabled" : "disabled");
- return (cap_hdr & 0x10000) != 0; /* MSI mapping cap enabled */
+ int pos, ttl = 48;
+
+ pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+ while (pos && ttl--) {
+ u8 flags;
+
+ if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+ &flags) == 0)
+ {
+ printk(KERN_INFO "PCI: Found %s HT MSI Mapping on %s\n",
+ flags & HT_MSI_FLAGS_ENABLE ?
+ "enabled" : "disabled", pci_name(dev));
+ return (flags & HT_MSI_FLAGS_ENABLE) != 0;
}
+
+ pos = pci_find_next_ht_capability(dev, pos,
+ HT_CAPTYPE_MSI_MAPPING);
}
return 0;
}
@@ -1688,8 +1795,9 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
* a single one having MSI is enough to be sure that MSI are supported.
*/
pdev = pci_get_slot(dev->bus, 0);
- if (dev->subordinate && !msi_ht_cap_enabled(dev)
- && !msi_ht_cap_enabled(pdev)) {
+ if (!pdev)
+ return;
+ if (!msi_ht_cap_enabled(dev) && !msi_ht_cap_enabled(pdev)) {
printk(KERN_WARNING "PCI: MSI quirk detected. "
"MSI disabled on chipset %s.\n",
pci_name(dev));
@@ -1700,8 +1808,3 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
quirk_nvidia_ck804_msi_ht_cap);
#endif /* CONFIG_PCI_MSI */
-
-EXPORT_SYMBOL(pcie_mch_quirk);
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pci_fixup_device);
-#endif
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 2f13eba..ff98ead 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -193,6 +193,15 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor,
struct pci_dev *dev;
WARN_ON(in_interrupt());
+
+ /*
+ * pci_find_subsys() can be called on the ide_setup() path, super-early
+ * in boot. But the down_read() will enable local interrupts, which
+ * can cause some machines to crash. So here we detect and flag that
+ * situation and bail out early.
+ */
+ if (unlikely(list_empty(&pci_devices)))
+ return NULL;
down_read(&pci_bus_sem);
n = from ? from->global_list.next : pci_devices.next;
@@ -259,6 +268,15 @@ pci_get_subsys(unsigned int vendor, unsigned int device,
struct pci_dev *dev;
WARN_ON(in_interrupt());
+
+ /*
+ * pci_get_subsys() can potentially be called by drivers super-early
+ * in boot. But the down_read() will enable local interrupts, which
+ * can cause some machines to crash. So here we detect and flag that
+ * situation and bail out early.
+ */
+ if (unlikely(list_empty(&pci_devices)))
+ return NULL;
down_read(&pci_bus_sem);
n = from ? from->global_list.next : pci_devices.next;
@@ -340,43 +358,6 @@ exit:
}
/**
- * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id
- * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
- * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
- * @from: Previous PCI device found in search, or %NULL for new search.
- *
- * Iterates through the list of known PCI devices in the reverse order of
- * pci_find_device().
- * If a PCI device is found with a matching @vendor and @device, a pointer to
- * its device structure is returned. Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL as the @from argument.
- * Otherwise if @from is not %NULL, searches continue from previous device
- * on the global list.
- */
-struct pci_dev *
-pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from)
-{
- struct list_head *n;
- struct pci_dev *dev;
-
- WARN_ON(in_interrupt());
- down_read(&pci_bus_sem);
- n = from ? from->global_list.prev : pci_devices.prev;
-
- while (n && (n != &pci_devices)) {
- dev = pci_dev_g(n);
- if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
- (device == PCI_ANY_ID || dev->device == device))
- goto exit;
- n = n->prev;
- }
- dev = NULL;
-exit:
- up_read(&pci_bus_sem);
- return dev;
-}
-
-/**
* pci_get_class - begin or continue searching for a PCI device by class
* @class: search for a PCI device with this class designation
* @from: Previous PCI device found in search, or %NULL for new search.
@@ -413,6 +394,24 @@ exit:
return dev;
}
+const struct pci_device_id *pci_find_present(const struct pci_device_id *ids)
+{
+ struct pci_dev *dev;
+ const struct pci_device_id *found = NULL;
+
+ WARN_ON(in_interrupt());
+ down_read(&pci_bus_sem);
+ while (ids->vendor || ids->subvendor || ids->class_mask) {
+ list_for_each_entry(dev, &pci_devices, global_list) {
+ if ((found = pci_match_one_device(ids, dev)) != NULL)
+ break;
+ }
+ ids++;
+ }
+ up_read(&pci_bus_sem);
+ return found;
+}
+
/**
* pci_dev_present - Returns 1 if device matching the device list is present, 0 if not.
* @ids: A pointer to a null terminated list of struct pci_device_id structures
@@ -426,28 +425,13 @@ exit:
*/
int pci_dev_present(const struct pci_device_id *ids)
{
- struct pci_dev *dev;
- int found = 0;
-
- WARN_ON(in_interrupt());
- down_read(&pci_bus_sem);
- while (ids->vendor || ids->subvendor || ids->class_mask) {
- list_for_each_entry(dev, &pci_devices, global_list) {
- if (pci_match_one_device(ids, dev)) {
- found = 1;
- goto exit;
- }
- }
- ids++;
- }
-exit:
- up_read(&pci_bus_sem);
- return found;
+ return pci_find_present(ids) == NULL ? 0 : 1;
}
+
EXPORT_SYMBOL(pci_dev_present);
+EXPORT_SYMBOL(pci_find_present);
EXPORT_SYMBOL(pci_find_device);
-EXPORT_SYMBOL(pci_find_device_reverse);
EXPORT_SYMBOL(pci_find_slot);
/* For boot time work */
EXPORT_SYMBOL(pci_find_bus);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 8f7bcf5..89f3036 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -41,7 +41,7 @@
* have a P2P bridge below a cardbus bridge, we need 4K.
*/
#define CARDBUS_IO_SIZE (256)
-#define CARDBUS_MEM_SIZE (32*1024*1024)
+#define CARDBUS_MEM_SIZE (64*1024*1024)
static void __devinit
pbus_assign_resources_sorted(struct pci_bus *bus)
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index ab78e4b..cb4ced3 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -33,11 +33,22 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
u32 new, check, mask;
int reg;
- /* Ignore resources for unimplemented BARs and unused resource slots
- for 64 bit BARs. */
+ /*
+ * Ignore resources for unimplemented BARs and unused resource slots
+ * for 64 bit BARs.
+ */
if (!res->flags)
return;
+ /*
+ * Ignore non-moveable resources. This might be legacy resources for
+ * which no functional BAR register exists or another important
+ * system resource we should better not move around in system address
+ * space.
+ */
+ if (res->flags & IORESOURCE_PCI_FIXED)
+ return;
+
pcibios_resource_to_bus(dev, &region, res);
pr_debug(" got res [%llx:%llx] bus [%lx:%lx] flags %lx for "
@@ -212,6 +223,10 @@ pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
resource_size_t r_align;
r = &dev->resource[i];
+
+ if (r->flags & IORESOURCE_PCI_FIXED)
+ continue;
+
r_align = r->end - r->start;
if (!(r->flags) || r->parent)
OpenPOWER on IntegriCloud