Commit 789e7dc8 authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6: (30 commits)
  [PATCH] PCI Hotplug: Fix recovery path from errors during pcie_init()
  [PATCH] PCI Hotplug: fake NULL pointer dereferences in IBM Hot Plug Controller Driver
  [PATCH] shpchp: Cleanup improper info messages
  [PATCH] shpchp: Remove Unused hpc_evelnt_lock
  [PATCH] shpchp: Cleanup interrupt polling timer
  [PATCH] shpchp: Cleanup SHPC commands
  [PATCH] shpchp: Cleanup interrupt handler
  [PATCH] shpchp: Remove unnecessary hpc_ctlr_handle check
  [PATCH] pciehp: Implement get_address callback
  [PATCH] pciehp: Add missing pci_dev_put
  [PATCH] pciehp: Replace pci_find_slot() with pci_get_slot()
  [PATCH] SGI Hotplug: Incorrect power status
  [PATCH] shpchp: Create shpchpd at controller probe time
  [PATCH] shpchp: Mask Global SERR and Intr at controller release time
  [PATCH] SHPC: Fix SHPC Contoller SERR-INT Register bits access
  [PATCH] SHPC: Fix SHPC Logical Slot Register bits access
  [PATCH] SHPC: Cleanup SHPC Logical Slot Register bits access
  [PATCH] SHPC: Cleanup SHPC Logical Slot Register access
  [PATCH] SHPC: Cleanup SHPC register access
  [PATCH] pciehp: Fix programming hotplug parameters
  ...
parents 28e4b224 9c64f977
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/pci.h> #include <linux/pci.h>
...@@ -33,10 +34,184 @@ ...@@ -33,10 +34,184 @@
#include <acpi/actypes.h> #include <acpi/actypes.h>
#include "pci_hotplug.h" #include "pci_hotplug.h"
#define MY_NAME "acpi_pcihp"
#define dbg(fmt, arg...) do { if (debug_acpi) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## 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 METHOD_NAME__SUN "_SUN" #define METHOD_NAME__SUN "_SUN"
#define METHOD_NAME__HPP "_HPP" #define METHOD_NAME__HPP "_HPP"
#define METHOD_NAME_OSHP "OSHP" #define METHOD_NAME_OSHP "OSHP"
static int debug_acpi;
static acpi_status
decode_type0_hpx_record(union acpi_object *record, struct hotplug_params *hpx)
{
int i;
union acpi_object *fields = record->package.elements;
u32 revision = fields[1].integer.value;
switch (revision) {
case 1:
if (record->package.count != 6)
return AE_ERROR;
for (i = 2; i < 6; i++)
if (fields[i].type != ACPI_TYPE_INTEGER)
return AE_ERROR;
hpx->t0 = &hpx->type0_data;
hpx->t0->revision = revision;
hpx->t0->cache_line_size = fields[2].integer.value;
hpx->t0->latency_timer = fields[3].integer.value;
hpx->t0->enable_serr = fields[4].integer.value;
hpx->t0->enable_perr = fields[5].integer.value;
break;
default:
printk(KERN_WARNING
"%s: Type 0 Revision %d record not supported\n",
__FUNCTION__, revision);
return AE_ERROR;
}
return AE_OK;
}
static acpi_status
decode_type1_hpx_record(union acpi_object *record, struct hotplug_params *hpx)
{
int i;
union acpi_object *fields = record->package.elements;
u32 revision = fields[1].integer.value;
switch (revision) {
case 1:
if (record->package.count != 5)
return AE_ERROR;
for (i = 2; i < 5; i++)
if (fields[i].type != ACPI_TYPE_INTEGER)
return AE_ERROR;
hpx->t1 = &hpx->type1_data;
hpx->t1->revision = revision;
hpx->t1->max_mem_read = fields[2].integer.value;
hpx->t1->avg_max_split = fields[3].integer.value;
hpx->t1->tot_max_split = fields[4].integer.value;
break;
default:
printk(KERN_WARNING
"%s: Type 1 Revision %d record not supported\n",
__FUNCTION__, revision);
return AE_ERROR;
}
return AE_OK;
}
static acpi_status
decode_type2_hpx_record(union acpi_object *record, struct hotplug_params *hpx)
{
int i;
union acpi_object *fields = record->package.elements;
u32 revision = fields[1].integer.value;
switch (revision) {
case 1:
if (record->package.count != 18)
return AE_ERROR;
for (i = 2; i < 18; i++)
if (fields[i].type != ACPI_TYPE_INTEGER)
return AE_ERROR;
hpx->t2 = &hpx->type2_data;
hpx->t2->revision = revision;
hpx->t2->unc_err_mask_and = fields[2].integer.value;
hpx->t2->unc_err_mask_or = fields[3].integer.value;
hpx->t2->unc_err_sever_and = fields[4].integer.value;
hpx->t2->unc_err_sever_or = fields[5].integer.value;
hpx->t2->cor_err_mask_and = fields[6].integer.value;
hpx->t2->cor_err_mask_or = fields[7].integer.value;
hpx->t2->adv_err_cap_and = fields[8].integer.value;
hpx->t2->adv_err_cap_or = fields[9].integer.value;
hpx->t2->pci_exp_devctl_and = fields[10].integer.value;
hpx->t2->pci_exp_devctl_or = fields[11].integer.value;
hpx->t2->pci_exp_lnkctl_and = fields[12].integer.value;
hpx->t2->pci_exp_lnkctl_or = fields[13].integer.value;
hpx->t2->sec_unc_err_sever_and = fields[14].integer.value;
hpx->t2->sec_unc_err_sever_or = fields[15].integer.value;
hpx->t2->sec_unc_err_mask_and = fields[16].integer.value;
hpx->t2->sec_unc_err_mask_or = fields[17].integer.value;
break;
default:
printk(KERN_WARNING
"%s: Type 2 Revision %d record not supported\n",
__FUNCTION__, revision);
return AE_ERROR;
}
return AE_OK;
}
static acpi_status
acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx)
{
acpi_status status;
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object *package, *record, *fields;
u32 type;
int i;
/* Clear the return buffer with zeros */
memset(hpx, 0, sizeof(struct hotplug_params));
status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer);
if (ACPI_FAILURE(status))
return status;
package = (union acpi_object *)buffer.pointer;
if (package->type != ACPI_TYPE_PACKAGE) {
status = AE_ERROR;
goto exit;
}
for (i = 0; i < package->package.count; i++) {
record = &package->package.elements[i];
if (record->type != ACPI_TYPE_PACKAGE) {
status = AE_ERROR;
goto exit;
}
fields = record->package.elements;
if (fields[0].type != ACPI_TYPE_INTEGER ||
fields[1].type != ACPI_TYPE_INTEGER) {
status = AE_ERROR;
goto exit;
}
type = fields[0].integer.value;
switch (type) {
case 0:
status = decode_type0_hpx_record(record, hpx);
if (ACPI_FAILURE(status))
goto exit;
break;
case 1:
status = decode_type1_hpx_record(record, hpx);
if (ACPI_FAILURE(status))
goto exit;
break;
case 2:
status = decode_type2_hpx_record(record, hpx);
if (ACPI_FAILURE(status))
goto exit;
break;
default:
printk(KERN_ERR "%s: Type %d record not supported\n",
__FUNCTION__, type);
status = AE_ERROR;
goto exit;
}
}
exit:
kfree(buffer.pointer);
return status;
}
static acpi_status static acpi_status
acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
...@@ -50,6 +225,9 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) ...@@ -50,6 +225,9 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
acpi_get_name(handle, ACPI_FULL_PATHNAME, &string); acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
/* Clear the return buffer with zeros */
memset(hpp, 0, sizeof(struct hotplug_params));
/* get _hpp */ /* get _hpp */
status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf); status = acpi_evaluate_object(handle, METHOD_NAME__HPP, NULL, &ret_buf);
switch (status) { switch (status) {
...@@ -58,7 +236,7 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) ...@@ -58,7 +236,7 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
if (!ret_buf.pointer) { if (!ret_buf.pointer) {
printk(KERN_ERR "%s:%s alloc for _HPP fail\n", printk(KERN_ERR "%s:%s alloc for _HPP fail\n",
__FUNCTION__, (char *)string.pointer); __FUNCTION__, (char *)string.pointer);
acpi_os_free(string.pointer); kfree(string.pointer);
return AE_NO_MEMORY; return AE_NO_MEMORY;
} }
status = acpi_evaluate_object(handle, METHOD_NAME__HPP, status = acpi_evaluate_object(handle, METHOD_NAME__HPP,
...@@ -69,7 +247,7 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) ...@@ -69,7 +247,7 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
pr_debug("%s:%s _HPP fail=0x%x\n", __FUNCTION__, pr_debug("%s:%s _HPP fail=0x%x\n", __FUNCTION__,
(char *)string.pointer, status); (char *)string.pointer, status);
acpi_os_free(string.pointer); kfree(string.pointer);
return status; return status;
} }
} }
...@@ -98,19 +276,20 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) ...@@ -98,19 +276,20 @@ acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
} }
} }
hpp->cache_line_size = nui[0]; hpp->t0 = &hpp->type0_data;
hpp->latency_timer = nui[1]; hpp->t0->cache_line_size = nui[0];
hpp->enable_serr = nui[2]; hpp->t0->latency_timer = nui[1];
hpp->enable_perr = nui[3]; hpp->t0->enable_serr = nui[2];
hpp->t0->enable_perr = nui[3];
pr_debug(" _HPP: cache_line_size=0x%x\n", hpp->cache_line_size); pr_debug(" _HPP: cache_line_size=0x%x\n", hpp->t0->cache_line_size);
pr_debug(" _HPP: latency timer =0x%x\n", hpp->latency_timer); pr_debug(" _HPP: latency timer =0x%x\n", hpp->t0->latency_timer);
pr_debug(" _HPP: enable SERR =0x%x\n", hpp->enable_serr); pr_debug(" _HPP: enable SERR =0x%x\n", hpp->t0->enable_serr);
pr_debug(" _HPP: enable PERR =0x%x\n", hpp->enable_perr); pr_debug(" _HPP: enable PERR =0x%x\n", hpp->t0->enable_perr);
free_and_return: free_and_return:
acpi_os_free(string.pointer); kfree(string.pointer);
acpi_os_free(ret_buf.pointer); kfree(ret_buf.pointer);
return status; return status;
} }
...@@ -130,13 +309,17 @@ acpi_status acpi_run_oshp(acpi_handle handle) ...@@ -130,13 +309,17 @@ acpi_status acpi_run_oshp(acpi_handle handle)
/* run OSHP */ /* run OSHP */
status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL); status = acpi_evaluate_object(handle, METHOD_NAME_OSHP, NULL, NULL);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
printk(KERN_ERR "%s:%s OSHP fails=0x%x\n", __FUNCTION__, if (status != AE_NOT_FOUND)
(char *)string.pointer, status); printk(KERN_ERR "%s:%s OSHP fails=0x%x\n",
__FUNCTION__, (char *)string.pointer, status);
else
dbg("%s:%s OSHP not found\n",
__FUNCTION__, (char *)string.pointer);
else else
pr_debug("%s:%s OSHP passes\n", __FUNCTION__, pr_debug("%s:%s OSHP passes\n", __FUNCTION__,
(char *)string.pointer); (char *)string.pointer);
acpi_os_free(string.pointer); kfree(string.pointer);
return status; return status;
} }
EXPORT_SYMBOL_GPL(acpi_run_oshp); EXPORT_SYMBOL_GPL(acpi_run_oshp);
...@@ -145,14 +328,27 @@ EXPORT_SYMBOL_GPL(acpi_run_oshp); ...@@ -145,14 +328,27 @@ EXPORT_SYMBOL_GPL(acpi_run_oshp);
/* acpi_get_hp_params_from_firmware /* acpi_get_hp_params_from_firmware
* *
* @dev - the pci_dev of the newly added device * @bus - the pci_bus of the bus on which the device is newly added
* @hpp - allocated by the caller * @hpp - allocated by the caller
*/ */
acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev, acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
struct hotplug_params *hpp) struct hotplug_params *hpp)
{ {
acpi_status status = AE_NOT_FOUND; acpi_status status = AE_NOT_FOUND;
struct pci_dev *pdev = dev; acpi_handle handle, phandle;
struct pci_bus *pbus = bus;
struct pci_dev *pdev;
do {
pdev = pbus->self;
if (!pdev) {
handle = acpi_get_pci_rootbridge_handle(
pci_domain_nr(pbus), pbus->number);
break;
}
handle = DEVICE_ACPI_HANDLE(&(pdev->dev));
pbus = pbus->parent;
} while (!handle);
/* /*
* _HPP settings apply to all child buses, until another _HPP is * _HPP settings apply to all child buses, until another _HPP is
...@@ -160,15 +356,19 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev, ...@@ -160,15 +356,19 @@ acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev,
* look for it in the parent device scope since that would apply to * look for it in the parent device scope since that would apply to
* this pci dev. If we don't find any _HPP, use hardcoded defaults * this pci dev. If we don't find any _HPP, use hardcoded defaults
*/ */
while (pdev && (ACPI_FAILURE(status))) { while (handle) {
acpi_handle handle = DEVICE_ACPI_HANDLE(&(pdev->dev)); status = acpi_run_hpx(handle, hpp);
if (!handle) if (ACPI_SUCCESS(status))
break; break;
status = acpi_run_hpp(handle, hpp); status = acpi_run_hpp(handle, hpp);
if (!(pdev->bus->parent)) if (ACPI_SUCCESS(status))
break; break;
/* Check if a parent object supports _HPP */ if (acpi_root_bridge(handle))
pdev = pdev->bus->parent->self; break;
status = acpi_get_parent(handle, &phandle);
if (ACPI_FAILURE(status))
break;
handle = phandle;
} }
return status; return status;
} }
...@@ -192,20 +392,23 @@ int acpi_root_bridge(acpi_handle handle) ...@@ -192,20 +392,23 @@ int acpi_root_bridge(acpi_handle handle)
if ((info->valid & ACPI_VALID_HID) && if ((info->valid & ACPI_VALID_HID) &&
!strcmp(PCI_ROOT_HID_STRING, !strcmp(PCI_ROOT_HID_STRING,
info->hardware_id.value)) { info->hardware_id.value)) {
acpi_os_free(buffer.pointer); kfree(buffer.pointer);
return 1; return 1;
} }
if (info->valid & ACPI_VALID_CID) { if (info->valid & ACPI_VALID_CID) {
for (i=0; i < info->compatibility_id.count; i++) { for (i=0; i < info->compatibility_id.count; i++) {
if (!strcmp(PCI_ROOT_HID_STRING, if (!strcmp(PCI_ROOT_HID_STRING,
info->compatibility_id.id[i].value)) { info->compatibility_id.id[i].value)) {
acpi_os_free(buffer.pointer); kfree(buffer.pointer);
return 1; return 1;
} }
} }
} }
acpi_os_free(buffer.pointer); kfree(buffer.pointer);
} }
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(acpi_root_bridge); EXPORT_SYMBOL_GPL(acpi_root_bridge);
module_param(debug_acpi, bool, 0644);
MODULE_PARM_DESC(debug_acpi, "Debugging mode for ACPI enabled or not");
...@@ -75,6 +75,10 @@ struct acpiphp_bridge { ...@@ -75,6 +75,10 @@ struct acpiphp_bridge {
struct list_head list; struct list_head list;
acpi_handle handle; acpi_handle handle;
struct acpiphp_slot *slots; struct acpiphp_slot *slots;
/* Ejectable PCI-to-PCI bridge (PCI bridge and PCI function) */
struct acpiphp_func *func;
int type; int type;
int nr_slots; int nr_slots;
...@@ -122,6 +126,7 @@ struct acpiphp_slot { ...@@ -122,6 +126,7 @@ struct acpiphp_slot {
*/ */
struct acpiphp_func { struct acpiphp_func {
struct acpiphp_slot *slot; /* parent */ struct acpiphp_slot *slot; /* parent */
struct acpiphp_bridge *bridge; /* Ejectable PCI-to-PCI bridge */
struct list_head sibling; struct list_head sibling;
struct pci_dev *pci_dev; struct pci_dev *pci_dev;
......
...@@ -286,13 +286,19 @@ static void decode_hpp(struct acpiphp_bridge *bridge) ...@@ -286,13 +286,19 @@ static void decode_hpp(struct acpiphp_bridge *bridge)
{ {
acpi_status status; acpi_status status;
status = acpi_get_hp_params_from_firmware(bridge->pci_dev, &bridge->hpp); status = acpi_get_hp_params_from_firmware(bridge->pci_bus, &bridge->hpp);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status) ||
!bridge->hpp.t0 || (bridge->hpp.t0->revision > 1)) {
/* use default numbers */ /* use default numbers */
bridge->hpp.cache_line_size = 0x10; printk(KERN_WARNING
bridge->hpp.latency_timer = 0x40; "%s: Could not get hotplug parameters. Use defaults\n",
bridge->hpp.enable_serr = 0; __FUNCTION__);
bridge->hpp.enable_perr = 0; bridge->hpp.t0 = &bridge->hpp.type0_data;
bridge->hpp.t0->revision = 0;
bridge->hpp.t0->cache_line_size = 0x10;
bridge->hpp.t0->latency_timer = 0x40;
bridge->hpp.t0->enable_serr = 0;
bridge->hpp.t0->enable_perr = 0;
} }
} }
...@@ -319,6 +325,13 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) ...@@ -319,6 +325,13 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
/* install notify handler */ /* install notify handler */
if (bridge->type != BRIDGE_TYPE_HOST) { if (bridge->type != BRIDGE_TYPE_HOST) {
if ((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func) {
status = acpi_remove_notify_handler(bridge->func->handle,
ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_func);
if (ACPI_FAILURE(status))
err("failed to remove notify handler\n");
}
status = acpi_install_notify_handler(bridge->handle, status = acpi_install_notify_handler(bridge->handle,
ACPI_SYSTEM_NOTIFY, ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_bridge, handle_hotplug_event_bridge,
...@@ -331,6 +344,66 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge) ...@@ -331,6 +344,66 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
} }
/* find acpiphp_func from acpiphp_bridge */
static struct acpiphp_func *acpiphp_bridge_handle_to_function(acpi_handle handle)
{
struct list_head *node, *l;
struct acpiphp_bridge *bridge;
struct acpiphp_slot *slot;
struct acpiphp_func *func;
list_for_each(node, &bridge_list) {
bridge = list_entry(node, struct acpiphp_bridge, list);
for (slot = bridge->slots; slot; slot = slot->next) {
list_for_each(l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func,
sibling);
if (func->handle == handle)
return func;
}
}
}
return NULL;
}
static inline void config_p2p_bridge_flags(struct acpiphp_bridge *bridge)
{
acpi_handle dummy_handle;
if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
"_STA", &dummy_handle)))
bridge->flags |= BRIDGE_HAS_STA;
if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
"_EJ0", &dummy_handle)))
bridge->flags |= BRIDGE_HAS_EJ0;
if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
"_PS0", &dummy_handle)))
bridge->flags |= BRIDGE_HAS_PS0;
if (ACPI_SUCCESS(acpi_get_handle(bridge->handle,
"_PS3", &dummy_handle)))
bridge->flags |= BRIDGE_HAS_PS3;
/* is this ejectable p2p bridge? */
if (bridge->flags & BRIDGE_HAS_EJ0) {
struct acpiphp_func *func;
dbg("found ejectable p2p bridge\n");
/* make link between PCI bridge and PCI function */
func = acpiphp_bridge_handle_to_function(bridge->handle);
if (!func)
return;
bridge->func = func;
func->bridge = bridge;
}
}
/* allocate and initialize host bridge data structure */ /* allocate and initialize host bridge data structure */
static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus) static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus)
{ {
...@@ -364,6 +437,7 @@ static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev) ...@@ -364,6 +437,7 @@ static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev)
bridge->type = BRIDGE_TYPE_P2P; bridge->type = BRIDGE_TYPE_P2P;
bridge->handle = handle; bridge->handle = handle;
config_p2p_bridge_flags(bridge);
bridge->pci_dev = pci_dev_get(pci_dev); bridge->pci_dev = pci_dev_get(pci_dev);
bridge->pci_bus = pci_dev->subordinate; bridge->pci_bus = pci_dev->subordinate;
...@@ -423,7 +497,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -423,7 +497,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
find_p2p_bridge, dev->subordinate, NULL); find_p2p_bridge, dev->subordinate, NULL);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
warn("find_p2p_bridge faied (error code = 0x%x)\n", status); warn("find_p2p_bridge failed (error code = 0x%x)\n", status);
out: out:
pci_dev_put(dev); pci_dev_put(dev);
...@@ -478,7 +552,6 @@ static int add_bridge(acpi_handle handle) ...@@ -478,7 +552,6 @@ static int add_bridge(acpi_handle handle)
if (detect_ejectable_slots(handle) > 0) { if (detect_ejectable_slots(handle) > 0) {
dbg("found PCI host-bus bridge with hot-pluggable slots\n"); dbg("found PCI host-bus bridge with hot-pluggable slots\n");
add_host_bridge(handle, pci_bus); add_host_bridge(handle, pci_bus);
return 0;
} }
/* search P2P bridges under this host bridge */ /* search P2P bridges under this host bridge */
...@@ -486,7 +559,7 @@ static int add_bridge(acpi_handle handle) ...@@ -486,7 +559,7 @@ static int add_bridge(acpi_handle handle)
find_p2p_bridge, pci_bus, NULL); find_p2p_bridge, pci_bus, NULL);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
warn("find_p2p_bridge faied (error code = 0x%x)\n",status); warn("find_p2p_bridge failed (error code = 0x%x)\n", status);
return 0; return 0;
} }
...@@ -516,6 +589,16 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge) ...@@ -516,6 +589,16 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
err("failed to remove notify handler\n"); err("failed to remove notify handler\n");
if ((bridge->type != BRIDGE_TYPE_HOST) &&
((bridge->flags & BRIDGE_HAS_EJ0) && bridge->func)) {
status = acpi_install_notify_handler(bridge->func->handle,
ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_func,
bridge->func);
if (ACPI_FAILURE(status))
err("failed to install interrupt notify handler\n");
}
slot = bridge->slots; slot = bridge->slots;
while (slot) { while (slot) {
struct acpiphp_slot *next = slot->next; struct acpiphp_slot *next = slot->next;
...@@ -549,6 +632,11 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv) ...@@ -549,6 +632,11 @@ cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
{ {
struct acpiphp_bridge *bridge; struct acpiphp_bridge *bridge;
/* cleanup p2p bridges under this P2P bridge
in a depth-first manner */
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
cleanup_p2p_bridge, NULL, NULL);
if (!(bridge = acpiphp_handle_to_bridge(handle))) if (!(bridge = acpiphp_handle_to_bridge(handle)))
return AE_OK; return AE_OK;
cleanup_bridge(bridge); cleanup_bridge(bridge);
...@@ -559,15 +647,14 @@ static void remove_bridge(acpi_handle handle) ...@@ -559,15 +647,14 @@ static void remove_bridge(acpi_handle handle)
{ {
struct acpiphp_bridge *bridge; struct acpiphp_bridge *bridge;
/* cleanup p2p bridges under this host bridge
in a depth-first manner */
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
(u32)1, cleanup_p2p_bridge, NULL, NULL);
bridge = acpiphp_handle_to_bridge(handle); bridge = acpiphp_handle_to_bridge(handle);
if (bridge) { if (bridge)
cleanup_bridge(bridge); cleanup_bridge(bridge);
} else {
/* clean-up p2p bridges under this host bridge */
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
ACPI_UINT32_MAX, cleanup_p2p_bridge,
NULL, NULL);
}
} }
static struct pci_dev * get_apic_pci_info(acpi_handle handle) static struct pci_dev * get_apic_pci_info(acpi_handle handle)
...@@ -634,7 +721,7 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base) ...@@ -634,7 +721,7 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
break; break;
} }
out: out:
acpi_os_free(buffer.pointer); kfree(buffer.pointer);
return result; return result;
} }
...@@ -797,36 +884,6 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus) ...@@ -797,36 +884,6 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
} }
/**
* get_func - get a pointer to acpiphp_func given a slot, device
* @slot: slot to search
* @dev: pci_dev struct to match.
*
* This function will increase the reference count of pci_dev,
* so callers should call pci_dev_put when complete.
*
*/
static struct acpiphp_func *
get_func(struct acpiphp_slot *slot, struct pci_dev *dev)
{
struct acpiphp_func *func = NULL;
struct pci_bus *bus = slot->bridge->pci_bus;
struct pci_dev *pdev;
list_for_each_entry(func, &slot->funcs, sibling) {
pdev = pci_get_slot(bus, PCI_DEVFN(slot->device,
func->function));
if (pdev) {
if (pdev == dev)
break;
pci_dev_put(pdev);
}
}
return func;
}
/** /**
* acpiphp_bus_add - add a new bus to acpi subsystem * acpiphp_bus_add - add a new bus to acpi subsystem
* @func: acpiphp_func of the bridge * @func: acpiphp_func of the bridge
...@@ -872,6 +929,28 @@ static int acpiphp_bus_add(struct acpiphp_func *func) ...@@ -872,6 +929,28 @@ static int acpiphp_bus_add(struct acpiphp_func *func)
} }
/**
* acpiphp_bus_trim - trim a bus from acpi subsystem
* @handle: handle to acpi namespace
*
*/
int acpiphp_bus_trim(acpi_handle handle)
{
struct acpi_device *device;
int retval;
retval = acpi_bus_get_device(handle, &device);
if (retval) {
dbg("acpi_device not found\n");
return retval;
}
retval = acpi_bus_trim(device, 1);
if (retval)
err("cannot remove from acpi list\n");
return retval;
}
/** /**
* enable_device - enable, configure a slot * enable_device - enable, configure a slot
...@@ -889,6 +968,7 @@ static int enable_device(struct acpiphp_slot *slot) ...@@ -889,6 +968,7 @@ static int enable_device(struct acpiphp_slot *slot)
struct acpiphp_func *func; struct acpiphp_func *func;
int retval = 0; int retval = 0;
int num, max, pass; int num, max, pass;
acpi_status status;
if (slot->flags & SLOT_ENABLED) if (slot->flags & SLOT_ENABLED)
goto err_exit; goto err_exit;
...@@ -918,19 +998,17 @@ static int enable_device(struct acpiphp_slot *slot) ...@@ -918,19 +998,17 @@ static int enable_device(struct acpiphp_slot *slot)
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) {
max = pci_scan_bridge(bus, dev, max, pass); max = pci_scan_bridge(bus, dev, max, pass);
if (pass && dev->subordinate) { if (pass && dev->subordinate)
pci_bus_size_bridges(dev->subordinate); pci_bus_size_bridges(dev->subordinate);
func = get_func(slot, dev);
if (func) {
acpiphp_bus_add(func);
/* side effect of get_func */
pci_dev_put(dev);
}
}
} }
} }
} }
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
acpiphp_bus_add(func);
}
pci_bus_assign_resources(bus); pci_bus_assign_resources(bus);
acpiphp_sanitize_bus(bus); acpiphp_sanitize_bus(bus);
pci_enable_bridges(bus); pci_enable_bridges(bus);
...@@ -943,6 +1021,17 @@ static int enable_device(struct acpiphp_slot *slot) ...@@ -943,6 +1021,17 @@ static int enable_device(struct acpiphp_slot *slot)
func = list_entry(l, struct acpiphp_func, sibling); func = list_entry(l, struct acpiphp_func, sibling);
func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device, func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
func->function)); func->function));
if (!func->pci_dev)
continue;
if (func->pci_dev->hdr_type != PCI_HEADER_TYPE_BRIDGE &&
func->pci_dev->hdr_type != PCI_HEADER_TYPE_CARDBUS)
continue;
status = find_p2p_bridge(func->handle, (u32)1, bus, NULL);
if (ACPI_FAILURE(status))
warn("find_p2p_bridge failed (error code = 0x%x)\n",
status);
} }
slot->flags |= SLOT_ENABLED; slot->flags |= SLOT_ENABLED;
...@@ -967,6 +1056,18 @@ static int disable_device(struct acpiphp_slot *slot) ...@@ -967,6 +1056,18 @@ static int disable_device(struct acpiphp_slot *slot)
list_for_each (l, &slot->funcs) { list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling); func = list_entry(l, struct acpiphp_func, sibling);
if (func->bridge) {
/* cleanup p2p bridges under this P2P bridge */
cleanup_p2p_bridge(func->bridge->handle,
(u32)1, NULL, NULL);
func->bridge = NULL;
}
acpiphp_bus_trim(func->handle);
/* try to remove anyway.
* acpiphp_bus_add might have been failed */
if (!func->pci_dev) if (!func->pci_dev)
continue; continue;
...@@ -1111,16 +1212,17 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge) ...@@ -1111,16 +1212,17 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge)
(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
return; return;
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
bridge->hpp.cache_line_size); bridge->hpp.t0->cache_line_size);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, pci_write_config_byte(dev, PCI_LATENCY_TIMER,
bridge->hpp.latency_timer); bridge->hpp.t0->latency_timer);
pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
if (bridge->hpp.enable_serr) if (bridge->hpp.t0->enable_serr)
pci_cmd |= PCI_COMMAND_SERR; pci_cmd |= PCI_COMMAND_SERR;
else else
pci_cmd &= ~PCI_COMMAND_SERR; pci_cmd &= ~PCI_COMMAND_SERR;
if (bridge->hpp.enable_perr) if (bridge->hpp.t0->enable_perr)
pci_cmd |= PCI_COMMAND_PARITY; pci_cmd |= PCI_COMMAND_PARITY;
else else
pci_cmd &= ~PCI_COMMAND_PARITY; pci_cmd &= ~PCI_COMMAND_PARITY;
...@@ -1129,13 +1231,13 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge) ...@@ -1129,13 +1231,13 @@ static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge)
/* Program bridge control value and child devices */ /* Program bridge control value and child devices */
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER,
bridge->hpp.latency_timer); bridge->hpp.t0->latency_timer);
pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl);
if (bridge->hpp.enable_serr) if (bridge->hpp.t0->enable_serr)
pci_bctl |= PCI_BRIDGE_CTL_SERR; pci_bctl |= PCI_BRIDGE_CTL_SERR;
else else
pci_bctl &= ~PCI_BRIDGE_CTL_SERR; pci_bctl &= ~PCI_BRIDGE_CTL_SERR;
if (bridge->hpp.enable_perr) if (bridge->hpp.t0->enable_perr)
pci_bctl |= PCI_BRIDGE_CTL_PARITY; pci_bctl |= PCI_BRIDGE_CTL_PARITY;
else else
pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; pci_bctl &= ~PCI_BRIDGE_CTL_PARITY;
...@@ -1155,6 +1257,7 @@ static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus) ...@@ -1155,6 +1257,7 @@ static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus)
memset(&bridge, 0, sizeof(bridge)); memset(&bridge, 0, sizeof(bridge));
bridge.handle = handle; bridge.handle = handle;
bridge.pci_bus = bus;
bridge.pci_dev = bus->self; bridge.pci_dev = bus->self;
decode_hpp(&bridge); decode_hpp(&bridge);
list_for_each_entry(dev, &bus->devices, bus_list) list_for_each_entry(dev, &bus->devices, bus_list)
...@@ -1297,6 +1400,13 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont ...@@ -1297,6 +1400,13 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_NOTIFY_EJECT_REQUEST:
/* request device eject */ /* request device eject */
dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
if ((bridge->type != BRIDGE_TYPE_HOST) &&
(bridge->flags & BRIDGE_HAS_EJ0)) {
struct acpiphp_slot *slot;
slot = bridge->func->slot;
if (!acpiphp_disable_slot(slot))
acpiphp_eject_slot(slot);
}
break; break;
case ACPI_NOTIFY_FREQUENCY_MISMATCH: case ACPI_NOTIFY_FREQUENCY_MISMATCH:
...@@ -1490,9 +1600,15 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot) ...@@ -1490,9 +1600,15 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot)
if (retval) if (retval)
goto err_exit; goto err_exit;
if (get_slot_status(slot) == ACPI_STA_ALL) if (get_slot_status(slot) == ACPI_STA_ALL) {
/* configure all functions */ /* configure all functions */
retval = enable_device(slot); retval = enable_device(slot);
if (retval)
power_off_slot(slot);
} else {
dbg("%s: Slot status is not ACPI_STA_ALL\n", __FUNCTION__);
power_off_slot(slot);
}
err_exit: err_exit:
mutex_unlock(&slot->crit_sect); mutex_unlock(&slot->crit_sect);
......
...@@ -285,7 +285,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) ...@@ -285,7 +285,7 @@ static int get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
(ulong) hotplug_slot, (ulong) value); (ulong) hotplug_slot, (ulong) value);
ibmphp_lock_operations(); ibmphp_lock_operations();
if (hotplug_slot && value) { if (hotplug_slot) {
pslot = hotplug_slot->private; pslot = hotplug_slot->private;
if (pslot) { if (pslot) {
memcpy(&myslot, pslot, sizeof(struct slot)); memcpy(&myslot, pslot, sizeof(struct slot));
...@@ -315,7 +315,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) ...@@ -315,7 +315,7 @@ static int get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value)
debug("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", debug("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n",
(ulong) hotplug_slot, (ulong) value); (ulong) hotplug_slot, (ulong) value);
ibmphp_lock_operations(); ibmphp_lock_operations();
if (hotplug_slot && value) { if (hotplug_slot) {
pslot = hotplug_slot->private; pslot = hotplug_slot->private;
if (pslot) { if (pslot) {
memcpy(&myslot, pslot, sizeof(struct slot)); memcpy(&myslot, pslot, sizeof(struct slot));
...@@ -342,7 +342,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) ...@@ -342,7 +342,7 @@ static int get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
debug("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", debug("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n",
(ulong) hotplug_slot, (ulong) value); (ulong) hotplug_slot, (ulong) value);
ibmphp_lock_operations(); ibmphp_lock_operations();
if (hotplug_slot && value) { if (hotplug_slot) {
pslot = hotplug_slot->private; pslot = hotplug_slot->private;
if (pslot) { if (pslot) {
memcpy(&myslot, pslot, sizeof(struct slot)); memcpy(&myslot, pslot, sizeof(struct slot));
...@@ -369,7 +369,7 @@ static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 * value) ...@@ -369,7 +369,7 @@ static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 * value)
debug("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", debug("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n",
(ulong) hotplug_slot, (ulong) value); (ulong) hotplug_slot, (ulong) value);
ibmphp_lock_operations(); ibmphp_lock_operations();
if (hotplug_slot && value) { if (hotplug_slot) {
pslot = hotplug_slot->private; pslot = hotplug_slot->private;
if (pslot) { if (pslot) {
memcpy(&myslot, pslot, sizeof(struct slot)); memcpy(&myslot, pslot, sizeof(struct slot));
...@@ -401,7 +401,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe ...@@ -401,7 +401,7 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
ibmphp_lock_operations(); ibmphp_lock_operations();
if (hotplug_slot && value) { if (hotplug_slot) {
pslot = hotplug_slot->private; pslot = hotplug_slot->private;
if (pslot) { if (pslot) {
rc = 0; rc = 0;
...@@ -441,7 +441,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe ...@@ -441,7 +441,7 @@ static int get_cur_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
ibmphp_lock_operations(); ibmphp_lock_operations();
if (hotplug_slot && value) { if (hotplug_slot) {
pslot = hotplug_slot->private; pslot = hotplug_slot->private;
if (pslot) { if (pslot) {
rc = get_cur_bus_info(&pslot); rc = get_cur_bus_info(&pslot);
......
...@@ -176,11 +176,51 @@ extern int pci_hp_change_slot_info (struct hotplug_slot *slot, ...@@ -176,11 +176,51 @@ extern int pci_hp_change_slot_info (struct hotplug_slot *slot,
struct hotplug_slot_info *info); struct hotplug_slot_info *info);
extern struct subsystem pci_hotplug_slots_subsys; extern struct subsystem pci_hotplug_slots_subsys;
/* PCI Setting Record (Type 0) */
struct hpp_type0 {
u32 revision;
u8 cache_line_size;
u8 latency_timer;
u8 enable_serr;
u8 enable_perr;
};
/* PCI-X Setting Record (Type 1) */
struct hpp_type1 {
u32 revision;
u8 max_mem_read;
u8 avg_max_split;
u16 tot_max_split;
};
/* PCI Express Setting Record (Type 2) */
struct hpp_type2 {
u32 revision;
u32 unc_err_mask_and;
u32 unc_err_mask_or;
u32 unc_err_sever_and;
u32 unc_err_sever_or;
u32 cor_err_mask_and;
u32 cor_err_mask_or;
u32 adv_err_cap_and;
u32 adv_err_cap_or;
u16 pci_exp_devctl_and;
u16 pci_exp_devctl_or;
u16 pci_exp_lnkctl_and;
u16 pci_exp_lnkctl_or;
u32 sec_unc_err_sever_and;
u32 sec_unc_err_sever_or;
u32 sec_unc_err_mask_and;
u32 sec_unc_err_mask_or;
};
struct hotplug_params { struct hotplug_params {
u8 cache_line_size; struct hpp_type0 *t0; /* Type0: NULL if not available */
u8 latency_timer; struct hpp_type1 *t1; /* Type1: NULL if not available */
u8 enable_serr; struct hpp_type2 *t2; /* Type2: NULL if not available */
u8 enable_perr; struct hpp_type0 type0_data;
struct hpp_type1 type1_data;
struct hpp_type2 type2_data;
}; };
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
...@@ -188,7 +228,7 @@ struct hotplug_params { ...@@ -188,7 +228,7 @@ struct hotplug_params {
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
#include <acpi/actypes.h> #include <acpi/actypes.h>
extern acpi_status acpi_run_oshp(acpi_handle handle); extern acpi_status acpi_run_oshp(acpi_handle handle);
extern acpi_status acpi_get_hp_params_from_firmware(struct pci_dev *dev, extern acpi_status acpi_get_hp_params_from_firmware(struct pci_bus *bus,
struct hotplug_params *hpp); struct hotplug_params *hpp);
int acpi_root_bridge(acpi_handle handle); int acpi_root_bridge(acpi_handle handle);
#endif #endif
......
...@@ -284,7 +284,7 @@ struct hpc_ops { ...@@ -284,7 +284,7 @@ struct hpc_ops {
static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev, static inline int pciehp_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, hpp))) if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev->bus, hpp)))
return -ENODEV; return -ENODEV;
return 0; return 0;
} }
......
...@@ -69,6 +69,7 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value); ...@@ -69,6 +69,7 @@ static int get_power_status (struct hotplug_slot *slot, u8 *value);
static int get_attention_status (struct hotplug_slot *slot, u8 *value); static int get_attention_status (struct hotplug_slot *slot, u8 *value);
static int get_latch_status (struct hotplug_slot *slot, u8 *value); static int get_latch_status (struct hotplug_slot *slot, u8 *value);
static int get_adapter_status (struct hotplug_slot *slot, u8 *value); static int get_adapter_status (struct hotplug_slot *slot, u8 *value);
static int get_address (struct hotplug_slot *slot, u32 *value);
static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value);
...@@ -81,6 +82,7 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = { ...@@ -81,6 +82,7 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
.get_attention_status = get_attention_status, .get_attention_status = get_attention_status,
.get_latch_status = get_latch_status, .get_latch_status = get_latch_status,
.get_adapter_status = get_adapter_status, .get_adapter_status = get_adapter_status,
.get_address = get_address,
.get_max_bus_speed = get_max_bus_speed, .get_max_bus_speed = get_max_bus_speed,
.get_cur_bus_speed = get_cur_bus_speed, .get_cur_bus_speed = get_cur_bus_speed,
}; };
...@@ -331,6 +333,18 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value) ...@@ -331,6 +333,18 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
return 0; return 0;
} }
static int get_address(struct hotplug_slot *hotplug_slot, u32 *value)
{
struct slot *slot = hotplug_slot->private;
struct pci_bus *bus = slot->ctrl->pci_dev->subordinate;
dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
*value = (pci_domain_nr(bus) << 16) | (slot->bus << 8) | slot->device;
return 0;
}
static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
{ {
struct slot *slot = hotplug_slot->private; struct slot *slot = hotplug_slot->private;
......
...@@ -1288,7 +1288,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) ...@@ -1288,7 +1288,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status)) {
dbg("Gained control for hotplug HW for pci %s (%s)\n", dbg("Gained control for hotplug HW for pci %s (%s)\n",
pci_name(dev), (char *)string.pointer); pci_name(dev), (char *)string.pointer);
acpi_os_free(string.pointer); kfree(string.pointer);
return 0; return 0;
} }
if (acpi_root_bridge(handle)) if (acpi_root_bridge(handle))
...@@ -1302,7 +1302,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) ...@@ -1302,7 +1302,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
err("Cannot get control of hotplug hardware for pci %s\n", err("Cannot get control of hotplug hardware for pci %s\n",
pci_name(dev)); pci_name(dev));
acpi_os_free(string.pointer); kfree(string.pointer);
return -1; return -1;
} }
#endif #endif
...@@ -1404,9 +1404,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ...@@ -1404,9 +1404,6 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, 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); pdev->subsystem_vendor, pdev->subsystem_device);
if (pci_enable_device(pdev))
goto abort_free_ctlr;
mutex_init(&ctrl->crit_sect); mutex_init(&ctrl->crit_sect);
/* setup wait queue */ /* setup wait queue */
init_waitqueue_head(&ctrl->queue); init_waitqueue_head(&ctrl->queue);
...@@ -1474,7 +1471,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ...@@ -1474,7 +1471,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
if (rc) { if (rc) {
err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__); err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
goto abort_free_ctlr; goto abort_free_irq;
} }
intr_enable = intr_enable | PRSN_DETECT_ENABLE; intr_enable = intr_enable | PRSN_DETECT_ENABLE;
...@@ -1500,19 +1497,19 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ...@@ -1500,19 +1497,19 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word); rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
if (rc) { if (rc) {
err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__); err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
goto abort_free_ctlr; goto abort_free_irq;
} }
rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status); rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
if (rc) { if (rc) {
err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__); err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
goto abort_free_ctlr; goto abort_disable_intr;
} }
temp_word = 0x1F; /* Clear all events */ temp_word = 0x1F; /* Clear all events */
rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word); rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
if (rc) { if (rc) {
err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__); err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
goto abort_free_ctlr; goto abort_disable_intr;
} }
if (pciehp_force) { if (pciehp_force) {
...@@ -1521,7 +1518,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ...@@ -1521,7 +1518,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
} else { } else {
rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev);
if (rc) if (rc)
goto abort_free_ctlr; goto abort_disable_intr;
} }
/* Add this HPC instance into the HPC list */ /* Add this HPC instance into the HPC list */
...@@ -1548,6 +1545,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev) ...@@ -1548,6 +1545,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
return 0; return 0;
/* We end up here for the many possible ways to fail this API. */ /* 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);
if (!rc) {
temp_word &= ~(intr_enable | HP_INTR_ENABLE);
rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), 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);
else
free_irq(php_ctlr->irq, ctrl);
abort_free_ctlr: abort_free_ctlr:
pcie_cap_base = saved_cap_base; pcie_cap_base = saved_cap_base;
kfree(php_ctlr); kfree(php_ctlr);
......
...@@ -34,6 +34,144 @@ ...@@ -34,6 +34,144 @@
#include "../pci.h" #include "../pci.h"
#include "pciehp.h" #include "pciehp.h"
static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp)
{
u16 pci_cmd, pci_bctl;
if (hpp->revision > 1) {
printk(KERN_WARNING "%s: Rev.%d type0 record not supported\n",
__FUNCTION__, hpp->revision);
return;
}
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpp->cache_line_size);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp->latency_timer);
pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
if (hpp->enable_serr)
pci_cmd |= PCI_COMMAND_SERR;
else
pci_cmd &= ~PCI_COMMAND_SERR;
if (hpp->enable_perr)
pci_cmd |= PCI_COMMAND_PARITY;
else
pci_cmd &= ~PCI_COMMAND_PARITY;
pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
/* Program bridge control value */
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER,
hpp->latency_timer);
pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl);
if (hpp->enable_serr)
pci_bctl |= PCI_BRIDGE_CTL_SERR;
else
pci_bctl &= ~PCI_BRIDGE_CTL_SERR;
if (hpp->enable_perr)
pci_bctl |= PCI_BRIDGE_CTL_PARITY;
else
pci_bctl &= ~PCI_BRIDGE_CTL_PARITY;
pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl);
}
}
static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
{
int pos;
u16 reg16;
u32 reg32;
if (hpp->revision > 1) {
printk(KERN_WARNING "%s: Rev.%d type2 record not supported\n",
__FUNCTION__, hpp->revision);
return;
}
/* Find PCI Express capability */
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
if (!pos)
return;
/* Initialize Device Control Register */
pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &reg16);
reg16 = (reg16 & hpp->pci_exp_devctl_and) | hpp->pci_exp_devctl_or;
pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, reg16);
/* Initialize Link Control Register */
if (dev->subordinate) {
pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &reg16);
reg16 = (reg16 & hpp->pci_exp_lnkctl_and)
| hpp->pci_exp_lnkctl_or;
pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, reg16);
}
/* Find Advanced Error Reporting Enhanced Capability */
pos = 256;
do {
pci_read_config_dword(dev, pos, &reg32);
if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR)
break;
} while ((pos = PCI_EXT_CAP_NEXT(reg32)));
if (!pos)
return;
/* Initialize Uncorrectable Error Mask Register */
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, &reg32);
reg32 = (reg32 & hpp->unc_err_mask_and) | hpp->unc_err_mask_or;
pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, reg32);
/* Initialize Uncorrectable Error Severity Register */
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &reg32);
reg32 = (reg32 & hpp->unc_err_sever_and) | hpp->unc_err_sever_or;
pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, reg32);
/* Initialize Correctable Error Mask Register */
pci_read_config_dword(dev, pos + PCI_ERR_COR_MASK, &reg32);
reg32 = (reg32 & hpp->cor_err_mask_and) | hpp->cor_err_mask_or;
pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, reg32);
/* Initialize Advanced Error Capabilities and Control Register */
pci_read_config_dword(dev, pos + PCI_ERR_CAP, &reg32);
reg32 = (reg32 & hpp->adv_err_cap_and) | hpp->adv_err_cap_or;
pci_write_config_dword(dev, pos + PCI_ERR_CAP, reg32);
/*
* FIXME: The following two registers are not supported yet.
*
* o Secondary Uncorrectable Error Severity Register
* o Secondary Uncorrectable Error Mask Register
*/
}
static void program_fw_provided_values(struct pci_dev *dev)
{
struct pci_dev *cdev;
struct hotplug_params hpp;
/* Program hpp values for this device */
if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL ||
(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
return;
if (pciehp_get_hp_params_from_firmware(dev, &hpp)) {
printk(KERN_WARNING "%s: Could not get hotplug parameters\n",
__FUNCTION__);
return;
}
if (hpp.t2)
program_hpp_type2(dev, hpp.t2);
if (hpp.t0)
program_hpp_type0(dev, hpp.t0);
/* Program child devices */
if (dev->subordinate) {
list_for_each_entry(cdev, &dev->subordinate->devices,
bus_list)
program_fw_provided_values(cdev);
}
}
static int pciehp_add_bridge(struct pci_dev *dev) static int pciehp_add_bridge(struct pci_dev *dev)
{ {
struct pci_bus *parent = dev->bus; struct pci_bus *parent = dev->bus;
...@@ -66,10 +204,11 @@ int pciehp_configure_device(struct slot *p_slot) ...@@ -66,10 +204,11 @@ int pciehp_configure_device(struct slot *p_slot)
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate; struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
int num, fn; int num, fn;
dev = pci_find_slot(p_slot->bus, PCI_DEVFN(p_slot->device, 0)); dev = pci_get_slot(parent, PCI_DEVFN(p_slot->device, 0));
if (dev) { if (dev) {
err("Device %s already exists at %x:%x, cannot hot-add\n", err("Device %s already exists at %x:%x, cannot hot-add\n",
pci_name(dev), p_slot->bus, p_slot->device); pci_name(dev), p_slot->bus, p_slot->device);
pci_dev_put(dev);
return -EINVAL; return -EINVAL;
} }
...@@ -86,14 +225,15 @@ int pciehp_configure_device(struct slot *p_slot) ...@@ -86,14 +225,15 @@ int pciehp_configure_device(struct slot *p_slot)
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) { if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
err("Cannot hot-add display device %s\n", err("Cannot hot-add display device %s\n",
pci_name(dev)); pci_name(dev));
pci_dev_put(dev);
continue; continue;
} }
if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) || if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
(dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) { (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
pciehp_add_bridge(dev); pciehp_add_bridge(dev);
} }
/* TBD: program firmware provided _HPP values */ program_fw_provided_values(dev);
/* program_fw_provided_values(dev); */ pci_dev_put(dev);
} }
pci_bus_assign_resources(parent); pci_bus_assign_resources(parent);
...@@ -106,18 +246,20 @@ int pciehp_unconfigure_device(struct slot *p_slot) ...@@ -106,18 +246,20 @@ int pciehp_unconfigure_device(struct slot *p_slot)
int rc = 0; int rc = 0;
int j; int j;
u8 bctl = 0; u8 bctl = 0;
struct pci_bus *parent = p_slot->ctrl->pci_dev->subordinate;
dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus, dbg("%s: bus/dev = %x/%x\n", __FUNCTION__, p_slot->bus,
p_slot->device); p_slot->device);
for (j=0; j<8 ; j++) { for (j=0; j<8 ; j++) {
struct pci_dev* temp = pci_find_slot(p_slot->bus, struct pci_dev* temp = pci_get_slot(parent,
(p_slot->device << 3) | j); (p_slot->device << 3) | j);
if (!temp) if (!temp)
continue; continue;
if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) { if ((temp->class >> 16) == PCI_BASE_CLASS_DISPLAY) {
err("Cannot remove display device %s\n", err("Cannot remove display device %s\n",
pci_name(temp)); pci_name(temp));
pci_dev_put(temp);
continue; continue;
} }
if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) { if (temp->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
...@@ -125,10 +267,12 @@ int pciehp_unconfigure_device(struct slot *p_slot) ...@@ -125,10 +267,12 @@ int pciehp_unconfigure_device(struct slot *p_slot)
if (bctl & PCI_BRIDGE_CTL_VGA) { if (bctl & PCI_BRIDGE_CTL_VGA) {
err("Cannot remove display device %s\n", err("Cannot remove display device %s\n",
pci_name(temp)); pci_name(temp));
pci_dev_put(temp);
continue; continue;
} }
} }
pci_remove_bus_device(temp); pci_remove_bus_device(temp);
pci_dev_put(temp);
} }
/* /*
* Some PCI Express root ports require fixup after hot-plug operation. * Some PCI Express root ports require fixup after hot-plug operation.
......
...@@ -18,11 +18,13 @@ ...@@ -18,11 +18,13 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <asm/sn/addrs.h> #include <asm/sn/addrs.h>
#include <asm/sn/geo.h>
#include <asm/sn/l1.h> #include <asm/sn/l1.h>
#include <asm/sn/module.h> #include <asm/sn/module.h>
#include <asm/sn/pcibr_provider.h> #include <asm/sn/pcibr_provider.h>
#include <asm/sn/pcibus_provider_defs.h> #include <asm/sn/pcibus_provider_defs.h>
#include <asm/sn/pcidev.h> #include <asm/sn/pcidev.h>
#include <asm/sn/sn_feature_sets.h>
#include <asm/sn/sn_sal.h> #include <asm/sn/sn_sal.h>
#include <asm/sn/types.h> #include <asm/sn/types.h>
...@@ -102,8 +104,7 @@ static struct hotplug_slot_attribute sn_slot_path_attr = __ATTR_RO(path); ...@@ -102,8 +104,7 @@ static struct hotplug_slot_attribute sn_slot_path_attr = __ATTR_RO(path);
static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device)
{ {
struct pcibus_info *pcibus_info; struct pcibus_info *pcibus_info;
int bricktype; u16 busnum, segment, ioboard_type;
int bus_num;
pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
...@@ -111,12 +112,14 @@ static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) ...@@ -111,12 +112,14 @@ static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device)
if (!(pcibus_info->pbi_valid_devices & (1 << device))) if (!(pcibus_info->pbi_valid_devices & (1 << device)))
return -EPERM; return -EPERM;
bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid); ioboard_type = sn_ioboard_to_pci_bus(pci_bus);
bus_num = pcibus_info->pbi_buscommon.bs_persist_busnum & 0xf; busnum = pcibus_info->pbi_buscommon.bs_persist_busnum;
segment = pci_domain_nr(pci_bus) & 0xf;
/* Do not allow hotplug operations on base I/O cards */ /* Do not allow hotplug operations on base I/O cards */
if ((bricktype == L1_BRICKTYPE_IX || bricktype == L1_BRICKTYPE_IA) && if ((ioboard_type == L1_BRICKTYPE_IX ||
(bus_num == 1 && device != 1)) ioboard_type == L1_BRICKTYPE_IA) &&
(segment == 1 && busnum == 0 && device != 1))
return -EPERM; return -EPERM;
return 1; return 1;
...@@ -125,23 +128,23 @@ static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device) ...@@ -125,23 +128,23 @@ static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device)
static int sn_pci_bus_valid(struct pci_bus *pci_bus) static int sn_pci_bus_valid(struct pci_bus *pci_bus)
{ {
struct pcibus_info *pcibus_info; struct pcibus_info *pcibus_info;
int asic_type; u32 asic_type;
int bricktype; u16 ioboard_type;
pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
/* Don't register slots hanging off the TIOCA bus */ /* Don't register slots hanging off the TIOCA bus */
pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
asic_type = pcibus_info->pbi_buscommon.bs_asic_type; asic_type = pcibus_info->pbi_buscommon.bs_asic_type;
if (asic_type == PCIIO_ASIC_TYPE_TIOCA) if (asic_type == PCIIO_ASIC_TYPE_TIOCA)
return -EPERM; return -EPERM;
/* Only register slots in I/O Bricks that support hotplug */ /* Only register slots in I/O Bricks that support hotplug */
bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid); ioboard_type = sn_ioboard_to_pci_bus(pci_bus);
switch (bricktype) { switch (ioboard_type) {
case L1_BRICKTYPE_IX: case L1_BRICKTYPE_IX:
case L1_BRICKTYPE_PX: case L1_BRICKTYPE_PX:
case L1_BRICKTYPE_IA: case L1_BRICKTYPE_IA:
case L1_BRICKTYPE_PA: case L1_BRICKTYPE_PA:
case L1_BOARDTYPE_PCIX3SLOT:
return 1; return 1;
break; break;
default: default:
...@@ -175,14 +178,11 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, ...@@ -175,14 +178,11 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot,
slot->pci_bus = pci_bus; slot->pci_bus = pci_bus;
sprintf(bss_hotplug_slot->name, "%04x:%02x:%02x", sprintf(bss_hotplug_slot->name, "%04x:%02x:%02x",
pci_domain_nr(pci_bus), pci_domain_nr(pci_bus),
((int)pcibus_info->pbi_buscommon.bs_persist_busnum) & 0xf, ((u16)pcibus_info->pbi_buscommon.bs_persist_busnum),
device + 1); device + 1);
sprintf(slot->physical_path, "module_%c%c%c%c%.2d",
'0'+RACK_GET_CLASS(MODULE_GET_RACK(pcibus_info->pbi_moduleid)), sn_generate_path(pci_bus, slot->physical_path);
'0'+RACK_GET_GROUP(MODULE_GET_RACK(pcibus_info->pbi_moduleid)),
'0'+RACK_GET_NUM(MODULE_GET_RACK(pcibus_info->pbi_moduleid)),
MODULE_GET_BTCHAR(pcibus_info->pbi_moduleid),
MODULE_GET_BPOS(pcibus_info->pbi_moduleid));
slot->hotplug_slot = bss_hotplug_slot; slot->hotplug_slot = bss_hotplug_slot;
list_add(&slot->hp_list, &sn_hp_list); list_add(&slot->hp_list, &sn_hp_list);
...@@ -461,10 +461,12 @@ static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot, ...@@ -461,10 +461,12 @@ static inline int get_power_status(struct hotplug_slot *bss_hotplug_slot,
{ {
struct slot *slot = bss_hotplug_slot->private; struct slot *slot = bss_hotplug_slot->private;
struct pcibus_info *pcibus_info; struct pcibus_info *pcibus_info;
u32 power;
pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus); pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
mutex_lock(&sn_hotplug_mutex); mutex_lock(&sn_hotplug_mutex);
*value = pcibus_info->pbi_enabled_devices & (1 << slot->device_num); power = pcibus_info->pbi_enabled_devices & (1 << slot->device_num);
*value = power ? 1 : 0;
mutex_unlock(&sn_hotplug_mutex); mutex_unlock(&sn_hotplug_mutex);
return 0; return 0;
} }
...@@ -553,8 +555,8 @@ static int sn_pci_hotplug_init(void) ...@@ -553,8 +555,8 @@ static int sn_pci_hotplug_init(void)
int rc; int rc;
int registered = 0; int registered = 0;
if (sn_sal_rev() < SGI_HOTPLUG_PROM_REV) { if (!sn_prom_feature_available(PRF_HOTPLUG_SUPPORT)) {
printk(KERN_ERR "%s: PROM version must be greater than 4.30\n", printk(KERN_ERR "%s: PROM version does not support hotplug.\n",
__FUNCTION__); __FUNCTION__);
return -EPERM; return -EPERM;
} }
......
...@@ -168,9 +168,9 @@ struct controller { ...@@ -168,9 +168,9 @@ struct controller {
* error Messages * error Messages
*/ */
#define msg_initialization_err "Initialization failure, error=%d\n" #define msg_initialization_err "Initialization failure, error=%d\n"
#define msg_button_on "PCI slot #%d - powering on due to button press.\n" #define msg_button_on "PCI slot #%s - powering on due to button press.\n"
#define msg_button_off "PCI slot #%d - powering off 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 #%d - action canceled 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 */ /* sysfs functions for the hotplug controller info */
extern void shpchp_create_ctrl_files (struct controller *ctrl); extern void shpchp_create_ctrl_files (struct controller *ctrl);
...@@ -196,7 +196,7 @@ extern void queue_pushbutton_work(void *data); ...@@ -196,7 +196,7 @@ extern void queue_pushbutton_work(void *data);
static inline int get_hp_params_from_firmware(struct pci_dev *dev, 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, hpp))) if (ACPI_FAILURE(acpi_get_hp_params_from_firmware(dev->bus, hpp)))
return -ENODEV; return -ENODEV;
return 0; return 0;
} }
......
...@@ -491,16 +491,9 @@ static int __init shpcd_init(void) ...@@ -491,16 +491,9 @@ static int __init shpcd_init(void)
shpchp_poll_mode = 1; shpchp_poll_mode = 1;
#endif #endif
shpchp_wq = create_singlethread_workqueue("shpchpd");
if (!shpchp_wq)
return -ENOMEM;
retval = pci_register_driver(&shpc_driver); retval = pci_register_driver(&shpc_driver);
dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval); dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval);
info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
if (retval) {
destroy_workqueue(shpchp_wq);
}
return retval; return retval;
} }
...@@ -508,7 +501,6 @@ static void __exit shpcd_cleanup(void) ...@@ -508,7 +501,6 @@ static void __exit shpcd_cleanup(void)
{ {
dbg("unload_shpchpd()\n"); dbg("unload_shpchpd()\n");
pci_unregister_driver(&shpc_driver); pci_unregister_driver(&shpc_driver);
destroy_workqueue(shpchp_wq);
info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n"); info(DRIVER_DESC " version: " DRIVER_VERSION " unloaded\n");
} }
......
...@@ -72,7 +72,7 @@ u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id) ...@@ -72,7 +72,7 @@ u8 shpchp_handle_attention_button(u8 hp_slot, void *inst_id)
/* /*
* Button pressed - See if need to TAKE ACTION!!! * Button pressed - See if need to TAKE ACTION!!!
*/ */
info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot); info("Button pressed on Slot(%s)\n", p_slot->name);
event_type = INT_BUTTON_PRESS; event_type = INT_BUTTON_PRESS;
queue_interrupt_event(p_slot, event_type); queue_interrupt_event(p_slot, event_type);
...@@ -101,7 +101,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) ...@@ -101,7 +101,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
/* /*
* Switch opened * Switch opened
*/ */
info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot); info("Latch open on Slot(%s)\n", p_slot->name);
event_type = INT_SWITCH_OPEN; event_type = INT_SWITCH_OPEN;
if (p_slot->pwr_save && p_slot->presence_save) { if (p_slot->pwr_save && p_slot->presence_save) {
event_type = INT_POWER_FAULT; event_type = INT_POWER_FAULT;
...@@ -111,7 +111,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id) ...@@ -111,7 +111,7 @@ u8 shpchp_handle_switch_change(u8 hp_slot, void *inst_id)
/* /*
* Switch closed * Switch closed
*/ */
info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot); info("Latch close on Slot(%s)\n", p_slot->name);
event_type = INT_SWITCH_CLOSE; event_type = INT_SWITCH_CLOSE;
} }
...@@ -139,13 +139,13 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id) ...@@ -139,13 +139,13 @@ u8 shpchp_handle_presence_change(u8 hp_slot, void *inst_id)
/* /*
* Card Present * Card Present
*/ */
info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot); info("Card present on Slot(%s)\n", p_slot->name);
event_type = INT_PRESENCE_ON; event_type = INT_PRESENCE_ON;
} else { } else {
/* /*
* Not Present * Not Present
*/ */
info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot); info("Card not present on Slot(%s)\n", p_slot->name);
event_type = INT_PRESENCE_OFF; event_type = INT_PRESENCE_OFF;
} }
...@@ -169,14 +169,14 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id) ...@@ -169,14 +169,14 @@ u8 shpchp_handle_power_fault(u8 hp_slot, void *inst_id)
/* /*
* Power fault Cleared * Power fault Cleared
*/ */
info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot); info("Power fault cleared on Slot(%s)\n", p_slot->name);
p_slot->status = 0x00; p_slot->status = 0x00;
event_type = INT_POWER_FAULT_CLEAR; event_type = INT_POWER_FAULT_CLEAR;
} else { } else {
/* /*
* Power fault * Power fault
*/ */
info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot); info("Power fault on Slot(%s)\n", p_slot->name);
event_type = INT_POWER_FAULT; event_type = INT_POWER_FAULT;
/* set power fault status for this board */ /* set power fault status for this board */
p_slot->status = 0xFF; p_slot->status = 0xFF;
...@@ -496,10 +496,10 @@ static void handle_button_press_event(struct slot *p_slot) ...@@ -496,10 +496,10 @@ static void handle_button_press_event(struct slot *p_slot)
p_slot->hpc_ops->get_power_status(p_slot, &getstatus); p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (getstatus) { if (getstatus) {
p_slot->state = BLINKINGOFF_STATE; p_slot->state = BLINKINGOFF_STATE;
info(msg_button_off, p_slot->number); info(msg_button_off, p_slot->name);
} else { } else {
p_slot->state = BLINKINGON_STATE; p_slot->state = BLINKINGON_STATE;
info(msg_button_on, p_slot->number); info(msg_button_on, p_slot->name);
} }
/* blink green LED and turn off amber */ /* blink green LED and turn off amber */
p_slot->hpc_ops->green_led_blink(p_slot); p_slot->hpc_ops->green_led_blink(p_slot);
...@@ -522,7 +522,7 @@ static void handle_button_press_event(struct slot *p_slot) ...@@ -522,7 +522,7 @@ static void handle_button_press_event(struct slot *p_slot)
else else
p_slot->hpc_ops->green_led_off(p_slot); p_slot->hpc_ops->green_led_off(p_slot);
p_slot->hpc_ops->set_attention_status(p_slot, 0); p_slot->hpc_ops->set_attention_status(p_slot, 0);
info(msg_button_cancel, p_slot->number); info(msg_button_cancel, p_slot->name);
p_slot->state = STATIC_STATE; p_slot->state = STATIC_STATE;
break; break;
case POWEROFF_STATE: case POWEROFF_STATE:
...@@ -575,17 +575,17 @@ static int shpchp_enable_slot (struct slot *p_slot) ...@@ -575,17 +575,17 @@ static int shpchp_enable_slot (struct slot *p_slot)
mutex_lock(&p_slot->ctrl->crit_sect); mutex_lock(&p_slot->ctrl->crit_sect);
rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (rc || !getstatus) { if (rc || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); info("No adapter on slot(%s)\n", p_slot->name);
goto out; goto out;
} }
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) { if (rc || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); info("Latch open on slot(%s)\n", p_slot->name);
goto out; goto out;
} }
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) { if (rc || getstatus) {
info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); info("Already enabled on slot(%s)\n", p_slot->name);
goto out; goto out;
} }
...@@ -634,17 +634,17 @@ static int shpchp_disable_slot (struct slot *p_slot) ...@@ -634,17 +634,17 @@ static int shpchp_disable_slot (struct slot *p_slot)
rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (rc || !getstatus) { if (rc || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); info("No adapter on slot(%s)\n", p_slot->name);
goto out; goto out;
} }
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) { if (rc || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); info("Latch open on slot(%s)\n", p_slot->name);
goto out; goto out;
} }
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || !getstatus) { if (rc || !getstatus) {
info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); info("Already disabled slot(%s)\n", p_slot->name);
goto out; goto out;
} }
......
...@@ -90,77 +90,94 @@ ...@@ -90,77 +90,94 @@
#define MRLSENSOR 0x40000000 #define MRLSENSOR 0x40000000
#define ATTN_BUTTON 0x80000000 #define ATTN_BUTTON 0x80000000
/* Slot Status Field Definitions */ /*
/* Slot State */ * Interrupt Locator Register definitions
#define PWR_ONLY 0x0001 */
#define ENABLED 0x0002 #define CMD_INTR_PENDING (1 << 0)
#define DISABLED 0x0003 #define SLOT_INTR_PENDING(i) (1 << (i + 1))
/* Power Indicator State */
#define PWR_LED_ON 0x0004
#define PWR_LED_BLINK 0x0008
#define PWR_LED_OFF 0x000c
/* Attention Indicator State */
#define ATTEN_LED_ON 0x0010
#define ATTEN_LED_BLINK 0x0020
#define ATTEN_LED_OFF 0x0030
/* Power Fault */
#define pwr_fault 0x0040
/* Attention Button */
#define ATTEN_BUTTON 0x0080
/* MRL Sensor */
#define MRL_SENSOR 0x0100
/* 66 MHz Capable */
#define IS_66MHZ_CAP 0x0200
/* PRSNT1#/PRSNT2# */
#define SLOT_EMP 0x0c00
/* PCI-X Capability */
#define NON_PCIX 0x0000
#define PCIX_66 0x1000
#define PCIX_133 0x3000
#define PCIX_266 0x4000 /* For PI = 2 only */
#define PCIX_533 0x5000 /* For PI = 2 only */
/* SHPC 'write' operations/commands */
/* Slot operation - 0x00h to 0x3Fh */
#define NO_CHANGE 0x00
/* Slot state - Bits 0 & 1 of controller command register */
#define SET_SLOT_PWR 0x01
#define SET_SLOT_ENABLE 0x02
#define SET_SLOT_DISABLE 0x03
/* Power indicator state - Bits 2 & 3 of controller command register*/ /*
#define SET_PWR_ON 0x04 * Controller SERR-INT Register
#define SET_PWR_BLINK 0x08 */
#define SET_PWR_OFF 0x0C #define GLOBAL_INTR_MASK (1 << 0)
#define GLOBAL_SERR_MASK (1 << 1)
#define COMMAND_INTR_MASK (1 << 2)
#define ARBITER_SERR_MASK (1 << 3)
#define COMMAND_DETECTED (1 << 16)
#define ARBITER_DETECTED (1 << 17)
#define SERR_INTR_RSVDZ_MASK 0xfffc0000
/* Attention indicator state - Bits 4 & 5 of controller command register*/ /*
#define SET_ATTN_ON 0x010 * Logical Slot Register definitions
#define SET_ATTN_BLINK 0x020 */
#define SET_ATTN_OFF 0x030 #define SLOT_REG(i) (SLOT1 + (4 * i))
#define SLOT_STATE_SHIFT (0)
#define SLOT_STATE_MASK (3 << 0)
#define SLOT_STATE_PWRONLY (1)
#define SLOT_STATE_ENABLED (2)
#define SLOT_STATE_DISABLED (3)
#define PWR_LED_STATE_SHIFT (2)
#define PWR_LED_STATE_MASK (3 << 2)
#define ATN_LED_STATE_SHIFT (4)
#define ATN_LED_STATE_MASK (3 << 4)
#define ATN_LED_STATE_ON (1)
#define ATN_LED_STATE_BLINK (2)
#define ATN_LED_STATE_OFF (3)
#define POWER_FAULT (1 << 6)
#define ATN_BUTTON (1 << 7)
#define MRL_SENSOR (1 << 8)
#define MHZ66_CAP (1 << 9)
#define PRSNT_SHIFT (10)
#define PRSNT_MASK (3 << 10)
#define PCIX_CAP_SHIFT (12)
#define PCIX_CAP_MASK_PI1 (3 << 12)
#define PCIX_CAP_MASK_PI2 (7 << 12)
#define PRSNT_CHANGE_DETECTED (1 << 16)
#define ISO_PFAULT_DETECTED (1 << 17)
#define BUTTON_PRESS_DETECTED (1 << 18)
#define MRL_CHANGE_DETECTED (1 << 19)
#define CON_PFAULT_DETECTED (1 << 20)
#define PRSNT_CHANGE_INTR_MASK (1 << 24)
#define ISO_PFAULT_INTR_MASK (1 << 25)
#define BUTTON_PRESS_INTR_MASK (1 << 26)
#define MRL_CHANGE_INTR_MASK (1 << 27)
#define CON_PFAULT_INTR_MASK (1 << 28)
#define MRL_CHANGE_SERR_MASK (1 << 29)
#define CON_PFAULT_SERR_MASK (1 << 30)
#define SLOT_REG_RSVDZ_MASK (1 << 15) | (7 << 21)
/* Set bus speed/mode A - 0x40h to 0x47h */ /*
#define SETA_PCI_33MHZ 0x40 * SHPC Command Code definitnions
*
* Slot Operation 00h - 3Fh
* Set Bus Segment Speed/Mode A 40h - 47h
* Power-Only All Slots 48h
* Enable All Slots 49h
* Set Bus Segment Speed/Mode B (PI=2) 50h - 5Fh
* Reserved Command Codes 60h - BFh
* Vendor Specific Commands C0h - FFh
*/
#define SET_SLOT_PWR 0x01 /* Slot Operation */
#define SET_SLOT_ENABLE 0x02
#define SET_SLOT_DISABLE 0x03
#define SET_PWR_ON 0x04
#define SET_PWR_BLINK 0x08
#define SET_PWR_OFF 0x0c
#define SET_ATTN_ON 0x10
#define SET_ATTN_BLINK 0x20
#define SET_ATTN_OFF 0x30
#define SETA_PCI_33MHZ 0x40 /* Set Bus Segment Speed/Mode A */
#define SETA_PCI_66MHZ 0x41 #define SETA_PCI_66MHZ 0x41
#define SETA_PCIX_66MHZ 0x42 #define SETA_PCIX_66MHZ 0x42
#define SETA_PCIX_100MHZ 0x43 #define SETA_PCIX_100MHZ 0x43
#define SETA_PCIX_133MHZ 0x44 #define SETA_PCIX_133MHZ 0x44
#define RESERV_1 0x45 #define SETA_RESERVED1 0x45
#define RESERV_2 0x46 #define SETA_RESERVED2 0x46
#define RESERV_3 0x47 #define SETA_RESERVED3 0x47
#define SET_PWR_ONLY_ALL 0x48 /* Power-Only All Slots */
/* Set bus speed/mode B - 0x50h to 0x5fh */ #define SET_ENABLE_ALL 0x49 /* Enable All Slots */
#define SETB_PCI_33MHZ 0x50 #define SETB_PCI_33MHZ 0x50 /* Set Bus Segment Speed/Mode B */
#define SETB_PCI_66MHZ 0x51 #define SETB_PCI_66MHZ 0x51
#define SETB_PCIX_66MHZ_PM 0x52 #define SETB_PCIX_66MHZ_PM 0x52
#define SETB_PCIX_100MHZ_PM 0x53 #define SETB_PCIX_100MHZ_PM 0x53
...@@ -174,81 +191,115 @@ ...@@ -174,81 +191,115 @@
#define SETB_PCIX_66MHZ_533 0x5b #define SETB_PCIX_66MHZ_533 0x5b
#define SETB_PCIX_100MHZ_533 0x5c #define SETB_PCIX_100MHZ_533 0x5c
#define SETB_PCIX_133MHZ_533 0x5d #define SETB_PCIX_133MHZ_533 0x5d
#define SETB_RESERVED1 0x5e
#define SETB_RESERVED2 0x5f
/*
/* Power-on all slots - 0x48h */ * SHPC controller command error code
#define SET_PWR_ON_ALL 0x48 */
/* Enable all slots - 0x49h */
#define SET_ENABLE_ALL 0x49
/* SHPC controller command error code */
#define SWITCH_OPEN 0x1 #define SWITCH_OPEN 0x1
#define INVALID_CMD 0x2 #define INVALID_CMD 0x2
#define INVALID_SPEED_MODE 0x4 #define INVALID_SPEED_MODE 0x4
/* For accessing SHPC Working Register Set */ /*
* For accessing SHPC Working Register Set via PCI Configuration Space
*/
#define DWORD_SELECT 0x2 #define DWORD_SELECT 0x2
#define DWORD_DATA 0x4 #define DWORD_DATA 0x4
#define BASE_OFFSET 0x0
/* Field Offset in Logical Slot Register - byte boundary */ /* Field Offset in Logical Slot Register - byte boundary */
#define SLOT_EVENT_LATCH 0x2 #define SLOT_EVENT_LATCH 0x2
#define SLOT_SERR_INT_MASK 0x3 #define SLOT_SERR_INT_MASK 0x3
static spinlock_t hpc_event_lock;
DEFINE_DBG_BUFFER /* Debug string buffer for entire HPC defined here */ 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 struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */
static int ctlr_seq_num = 0; /* Controller sequenc # */ static int ctlr_seq_num = 0; /* Controller sequenc # */
static spinlock_t list_lock; static spinlock_t list_lock;
static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs); static atomic_t shpchp_num_controllers = ATOMIC_INIT(0);
static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds); static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs);
static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec);
static int hpc_check_cmd_status(struct controller *ctrl); static int hpc_check_cmd_status(struct controller *ctrl);
/* This is the interrupt polling timeout function. */ static inline u8 shpc_readb(struct controller *ctrl, int reg)
static void int_poll_timeout(unsigned long lphp_ctlr)
{ {
struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr; return readb(ctrl->hpc_ctlr_handle->creg + reg);
}
DBG_ENTER_ROUTINE static inline void shpc_writeb(struct controller *ctrl, int reg, u8 val)
{
writeb(val, ctrl->hpc_ctlr_handle->creg + reg);
}
if ( !php_ctlr ) { static inline u16 shpc_readw(struct controller *ctrl, int reg)
err("%s: Invalid HPC controller handle!\n", __FUNCTION__); {
return; return readw(ctrl->hpc_ctlr_handle->creg + reg);
} }
/* Poll for interrupt events. regs == NULL => polling */ static inline void shpc_writew(struct controller *ctrl, int reg, u16 val)
shpc_isr( 0, (void *)php_ctlr, NULL ); {
writew(val, ctrl->hpc_ctlr_handle->creg + reg);
}
init_timer(&php_ctlr->int_poll_timer); static inline u32 shpc_readl(struct controller *ctrl, int reg)
if (!shpchp_poll_time) {
shpchp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/ return readl(ctrl->hpc_ctlr_handle->creg + reg);
}
start_int_poll_timer(php_ctlr, shpchp_poll_time); static inline void shpc_writel(struct controller *ctrl, int reg, u32 val)
{
return; writel(val, ctrl->hpc_ctlr_handle->creg + reg);
} }
/* This function starts the interrupt polling timer. */ static inline int shpc_indirect_read(struct controller *ctrl, int index,
static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds) u32 *value)
{ {
if (!php_ctlr) { int rc;
err("%s: Invalid HPC controller handle!\n", __FUNCTION__); u32 cap_offset = ctrl->cap_offset;
return; struct pci_dev *pdev = ctrl->pci_dev;
}
rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index);
if (rc)
return rc;
return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value);
}
/*
* This is the interrupt polling timeout function.
*/
static void int_poll_timeout(unsigned long lphp_ctlr)
{
struct php_ctlr_state_s *php_ctlr =
(struct php_ctlr_state_s *)lphp_ctlr;
DBG_ENTER_ROUTINE
/* Poll for interrupt events. regs == NULL => polling */
shpc_isr(0, php_ctlr->callback_instance_id, NULL);
init_timer(&php_ctlr->int_poll_timer);
if (!shpchp_poll_time)
shpchp_poll_time = 2; /* default polling interval is 2 sec */
if ( ( seconds <= 0 ) || ( seconds > 60 ) ) start_int_poll_timer(php_ctlr, shpchp_poll_time);
seconds = 2; /* Clamp to sane value */
php_ctlr->int_poll_timer.function = &int_poll_timeout; DBG_LEAVE_ROUTINE
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);
return; /*
* This function starts the interrupt polling timer.
*/
static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, 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);
} }
static inline int shpc_wait_cmd(struct controller *ctrl) static inline int shpc_wait_cmd(struct controller *ctrl)
...@@ -272,7 +323,7 @@ static inline int shpc_wait_cmd(struct controller *ctrl) ...@@ -272,7 +323,7 @@ static inline int shpc_wait_cmd(struct controller *ctrl)
static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
{ {
struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; struct controller *ctrl = slot->ctrl;
u16 cmd_status; u16 cmd_status;
int retval = 0; int retval = 0;
u16 temp_word; u16 temp_word;
...@@ -282,14 +333,8 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) ...@@ -282,14 +333,8 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
mutex_lock(&slot->ctrl->cmd_lock); mutex_lock(&slot->ctrl->cmd_lock);
if (!php_ctlr) {
err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
retval = -EINVAL;
goto out;
}
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
cmd_status = readw(php_ctlr->creg + CMD_STATUS); cmd_status = shpc_readw(ctrl, CMD_STATUS);
if (!(cmd_status & 0x1)) if (!(cmd_status & 0x1))
break; break;
...@@ -297,7 +342,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) ...@@ -297,7 +342,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
msleep(100); msleep(100);
} }
cmd_status = readw(php_ctlr->creg + CMD_STATUS); cmd_status = shpc_readw(ctrl, CMD_STATUS);
if (cmd_status & 0x1) { if (cmd_status & 0x1) {
/* After 1 sec and and the controller is still busy */ /* After 1 sec and and the controller is still busy */
...@@ -314,7 +359,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) ...@@ -314,7 +359,7 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
* command. * command.
*/ */
slot->ctrl->cmd_busy = 1; slot->ctrl->cmd_busy = 1;
writew(temp_word, php_ctlr->creg + CMD); shpc_writew(ctrl, CMD, temp_word);
/* /*
* Wait for command completion. * Wait for command completion.
...@@ -338,18 +383,12 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd) ...@@ -338,18 +383,12 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
static int hpc_check_cmd_status(struct controller *ctrl) static int hpc_check_cmd_status(struct controller *ctrl)
{ {
struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
u16 cmd_status; u16 cmd_status;
int retval = 0; int retval = 0;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
if (!ctrl->hpc_ctlr_handle) {
err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
return -1;
}
cmd_status = readw(php_ctlr->creg + CMD_STATUS) & 0x000F; cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
switch (cmd_status >> 1) { switch (cmd_status >> 1) {
case 0: case 0:
...@@ -378,37 +417,27 @@ static int hpc_check_cmd_status(struct controller *ctrl) ...@@ -378,37 +417,27 @@ static int hpc_check_cmd_status(struct controller *ctrl)
static int hpc_get_attention_status(struct slot *slot, u8 *status) 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;
u32 slot_reg; u32 slot_reg;
u16 slot_status; u8 state;
u8 atten_led_state;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
if (!slot->ctrl->hpc_ctlr_handle) { slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
err("%s: Invalid HPC controller handle!\n", __FUNCTION__); state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;
return -1;
}
slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
slot_status = (u16) slot_reg;
atten_led_state = (slot_status & 0x0030) >> 4;
switch (atten_led_state) { switch (state) {
case 0: case ATN_LED_STATE_ON:
*status = 0xFF; /* Reserved */
break;
case 1:
*status = 1; /* On */ *status = 1; /* On */
break; break;
case 2: case ATN_LED_STATE_BLINK:
*status = 2; /* Blink */ *status = 2; /* Blink */
break; break;
case 3: case ATN_LED_STATE_OFF:
*status = 0; /* Off */ *status = 0; /* Off */
break; break;
default: default:
*status = 0xFF; *status = 0xFF; /* Reserved */
break; break;
} }
...@@ -418,64 +447,44 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status) ...@@ -418,64 +447,44 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
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;
u32 slot_reg; u32 slot_reg;
u16 slot_status; u8 state;
u8 slot_state;
int retval = 0;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
if (!slot->ctrl->hpc_ctlr_handle) { slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
err("%s: Invalid HPC controller handle!\n", __FUNCTION__); state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;
return -1;
}
slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
slot_status = (u16) slot_reg;
slot_state = (slot_status & 0x0003);
switch (slot_state) { switch (state) {
case 0: case SLOT_STATE_PWRONLY:
*status = 0xFF;
break;
case 1:
*status = 2; /* Powered only */ *status = 2; /* Powered only */
break; break;
case 2: case SLOT_STATE_ENABLED:
*status = 1; /* Enabled */ *status = 1; /* Enabled */
break; break;
case 3: case SLOT_STATE_DISABLED:
*status = 0; /* Disabled */ *status = 0; /* Disabled */
break; break;
default: default:
*status = 0xFF; *status = 0xFF; /* Reserved */
break; break;
} }
DBG_LEAVE_ROUTINE DBG_LEAVE_ROUTINE
return retval; return 0;
} }
static int hpc_get_latch_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;
u32 slot_reg; u32 slot_reg;
u16 slot_status;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
if (!slot->ctrl->hpc_ctlr_handle) { slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
err("%s: Invalid HPC controller handle!\n", __FUNCTION__); *status = !!(slot_reg & MRL_SENSOR); /* 0 -> close; 1 -> open */
return -1;
}
slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
slot_status = (u16)slot_reg;
*status = ((slot_status & 0x0100) == 0) ? 0 : 1; /* 0 -> close; 1 -> open */
DBG_LEAVE_ROUTINE DBG_LEAVE_ROUTINE
return 0; return 0;
...@@ -483,22 +492,15 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status) ...@@ -483,22 +492,15 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status)
static int hpc_get_adapter_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;
u32 slot_reg; u32 slot_reg;
u16 slot_status; u8 state;
u8 card_state;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
if (!slot->ctrl->hpc_ctlr_handle) { slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
err("%s: Invalid HPC controller handle!\n", __FUNCTION__); state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;
return -1; *status = (state != 0x3) ? 1 : 0;
}
slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
slot_status = (u16)slot_reg;
card_state = (u8)((slot_status & 0x0C00) >> 10);
*status = (card_state != 0x3) ? 1 : 0;
DBG_LEAVE_ROUTINE DBG_LEAVE_ROUTINE
return 0; return 0;
...@@ -506,16 +508,11 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status) ...@@ -506,16 +508,11 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) static int hpc_get_prog_int(struct slot *slot, u8 *prog_int)
{ {
struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; struct controller *ctrl = slot->ctrl;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
if (!slot->ctrl->hpc_ctlr_handle) {
err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
return -1;
}
*prog_int = readb(php_ctlr->creg + PROG_INTERFACE); *prog_int = shpc_readb(ctrl, PROG_INTERFACE);
DBG_LEAVE_ROUTINE DBG_LEAVE_ROUTINE
return 0; return 0;
...@@ -524,13 +521,27 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int) ...@@ -524,13 +521,27 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int)
static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
{ {
int retval = 0; int retval = 0;
struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; struct controller *ctrl = slot->ctrl;
u32 slot_reg = readl(php_ctlr->creg + SLOT1 + 4 * slot->hp_slot); u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
u8 pcix_cap = (slot_reg >> 12) & 7; u8 m66_cap = !!(slot_reg & MHZ66_CAP);
u8 m66_cap = (slot_reg >> 9) & 1; u8 pi, pcix_cap;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
if ((retval = hpc_get_prog_int(slot, &pi)))
return retval;
switch (pi) {
case 1:
pcix_cap = (slot_reg & PCIX_CAP_MASK_PI1) >> PCIX_CAP_SHIFT;
break;
case 2:
pcix_cap = (slot_reg & PCIX_CAP_MASK_PI2) >> PCIX_CAP_SHIFT;
break;
default:
return -ENODEV;
}
dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n", dbg("%s: slot_reg = %x, pcix_cap = %x, m66_cap = %x\n",
__FUNCTION__, slot_reg, pcix_cap, m66_cap); __FUNCTION__, slot_reg, pcix_cap, m66_cap);
...@@ -564,20 +575,15 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value) ...@@ -564,20 +575,15 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
{ {
struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; struct controller *ctrl = slot->ctrl;
u16 sec_bus_status; u16 sec_bus_status;
u8 pi; u8 pi;
int retval = 0; int retval = 0;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
if (!slot->ctrl->hpc_ctlr_handle) { pi = shpc_readb(ctrl, PROG_INTERFACE);
err("%s: Invalid HPC controller handle!\n", __FUNCTION__); sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
return -1;
}
pi = readb(php_ctlr->creg + PROG_INTERFACE);
sec_bus_status = readw(php_ctlr->creg + SEC_BUS_CONFIG);
if (pi == 2) { if (pi == 2) {
*mode = (sec_bus_status & 0x0100) >> 8; *mode = (sec_bus_status & 0x0100) >> 8;
...@@ -593,128 +599,53 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode) ...@@ -593,128 +599,53 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
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;
u32 slot_reg; u32 slot_reg;
u16 slot_status;
u8 pwr_fault_state, status;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
if (!slot->ctrl->hpc_ctlr_handle) { slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
return -1;
}
slot_reg = readl(php_ctlr->creg + SLOT1 + 4*(slot->hp_slot));
slot_status = (u16) slot_reg;
pwr_fault_state = (slot_status & 0x0040) >> 7;
status = (pwr_fault_state == 1) ? 0 : 1;
DBG_LEAVE_ROUTINE DBG_LEAVE_ROUTINE
/* Note: Logic 0 => fault */ /* Note: Logic 0 => fault */
return status; return !(slot_reg & POWER_FAULT);
} }
static int hpc_set_attention_status(struct slot *slot, u8 value) static int hpc_set_attention_status(struct slot *slot, u8 value)
{ {
struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
u8 slot_cmd = 0; u8 slot_cmd = 0;
int rc = 0;
if (!slot->ctrl->hpc_ctlr_handle) {
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;
}
switch (value) { switch (value) {
case 0 : case 0 :
slot_cmd = 0x30; /* OFF */ slot_cmd = SET_ATTN_OFF; /* OFF */
break; break;
case 1: case 1:
slot_cmd = 0x10; /* ON */ slot_cmd = SET_ATTN_ON; /* ON */
break; break;
case 2: case 2:
slot_cmd = 0x20; /* BLINK */ slot_cmd = SET_ATTN_BLINK; /* BLINK */
break; break;
default: default:
return -1; return -1;
} }
shpc_write_cmd(slot, slot->hp_slot, slot_cmd); return shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
return rc;
} }
static void hpc_set_green_led_on(struct slot *slot) static void hpc_set_green_led_on(struct slot *slot)
{ {
struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; shpc_write_cmd(slot, slot->hp_slot, SET_PWR_ON);
u8 slot_cmd;
if (!slot->ctrl->hpc_ctlr_handle) {
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 ;
}
slot_cmd = 0x04;
shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
return;
} }
static void hpc_set_green_led_off(struct slot *slot) static void hpc_set_green_led_off(struct slot *slot)
{ {
struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; shpc_write_cmd(slot, slot->hp_slot, SET_PWR_OFF);
u8 slot_cmd;
if (!slot->ctrl->hpc_ctlr_handle) {
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 ;
}
slot_cmd = 0x0C;
shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
return;
} }
static void hpc_set_green_led_blink(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; shpc_write_cmd(slot, slot->hp_slot, SET_PWR_BLINK);
u8 slot_cmd;
if (!slot->ctrl->hpc_ctlr_handle) {
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 ;
}
slot_cmd = 0x08;
shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
return;
} }
int shpc_get_ctlr_slot_config(struct controller *ctrl, int shpc_get_ctlr_slot_config(struct controller *ctrl,
...@@ -724,21 +655,17 @@ int shpc_get_ctlr_slot_config(struct controller *ctrl, ...@@ -724,21 +655,17 @@ int shpc_get_ctlr_slot_config(struct controller *ctrl,
int *updown, /* physical_slot_num increament: 1 or -1 */ int *updown, /* physical_slot_num increament: 1 or -1 */
int *flags) int *flags)
{ {
struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; u32 slot_config;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
if (!ctrl->hpc_ctlr_handle) { slot_config = shpc_readl(ctrl, SLOT_CONFIG);
err("%s: Invalid HPC controller handle!\n", __FUNCTION__); *first_device_num = (slot_config & FIRST_DEV_NUM) >> 8;
return -1; *num_ctlr_slots = slot_config & SLOT_NUM;
} *physical_slot_num = (slot_config & PSN) >> 16;
*updown = ((slot_config & UPDOWN) >> 29) ? 1 : -1;
*first_device_num = php_ctlr->slot_device_offset; /* Obtained in shpc_init() */
*num_ctlr_slots = php_ctlr->num_slots; /* Obtained in shpc_init() */
*physical_slot_num = (readl(php_ctlr->creg + SLOT_CONFIG) & PSN) >> 16;
dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num); dbg("%s: physical_slot_num = %x\n", __FUNCTION__, *physical_slot_num);
*updown = ((readl(php_ctlr->creg + SLOT_CONFIG) & UPDOWN ) >> 29) ? 1 : -1;
DBG_LEAVE_ROUTINE DBG_LEAVE_ROUTINE
return 0; return 0;
...@@ -749,22 +676,34 @@ static void hpc_release_ctlr(struct controller *ctrl) ...@@ -749,22 +676,34 @@ static void hpc_release_ctlr(struct controller *ctrl)
struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle; struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
struct php_ctlr_state_s *p, *p_prev; struct php_ctlr_state_s *p, *p_prev;
int i; int i;
u32 slot_reg, serr_int;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
if (!ctrl->hpc_ctlr_handle) {
err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
return ;
}
/* /*
* Mask all slot event interrupts * Mask event interrupts and SERRs of all slots
*/ */
for (i = 0; i < ctrl->num_slots; i++) for (i = 0; i < ctrl->num_slots; i++) {
writel(0xffff3fff, php_ctlr->creg + SLOT1 + (4 * i)); slot_reg = shpc_readl(ctrl, SLOT_REG(i));
slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK |
BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK |
CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK |
CON_PFAULT_SERR_MASK);
slot_reg &= ~SLOT_REG_RSVDZ_MASK;
shpc_writel(ctrl, SLOT_REG(i), slot_reg);
}
cleanup_slots(ctrl); cleanup_slots(ctrl);
/*
* Mask SERR and System Interrut generation
*/
serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE);
serr_int |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK |
COMMAND_INTR_MASK | ARBITER_SERR_MASK);
serr_int &= ~SERR_INTR_RSVDZ_MASK;
shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
if (shpchp_poll_mode) { if (shpchp_poll_mode) {
del_timer(&php_ctlr->int_poll_timer); del_timer(&php_ctlr->int_poll_timer);
} else { } else {
...@@ -800,113 +739,79 @@ static void hpc_release_ctlr(struct controller *ctrl) ...@@ -800,113 +739,79 @@ static void hpc_release_ctlr(struct controller *ctrl)
kfree(php_ctlr); kfree(php_ctlr);
/*
* If this is the last controller to be released, destroy the
* shpchpd work queue
*/
if (atomic_dec_and_test(&shpchp_num_controllers))
destroy_workqueue(shpchp_wq);
DBG_LEAVE_ROUTINE DBG_LEAVE_ROUTINE
} }
static int hpc_power_on_slot(struct slot * slot) static int hpc_power_on_slot(struct slot * slot)
{ {
struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; int retval;
u8 slot_cmd;
int retval = 0;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
if (!slot->ctrl->hpc_ctlr_handle) { retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR);
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;
}
slot_cmd = 0x01;
retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
if (retval) { if (retval) {
err("%s: Write command failed!\n", __FUNCTION__); err("%s: Write command failed!\n", __FUNCTION__);
return -1; return retval;
} }
DBG_LEAVE_ROUTINE DBG_LEAVE_ROUTINE
return retval; return 0;
} }
static int hpc_slot_enable(struct slot * slot) static int hpc_slot_enable(struct slot * slot)
{ {
struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; int retval;
u8 slot_cmd;
int retval = 0;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
if (!slot->ctrl->hpc_ctlr_handle) { /* Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
err("%s: Invalid HPC controller handle!\n", __FUNCTION__); retval = shpc_write_cmd(slot, slot->hp_slot,
return -1; SET_SLOT_ENABLE | SET_PWR_BLINK | SET_ATTN_OFF);
}
if (slot->hp_slot >= php_ctlr->num_slots) {
err("%s: Invalid HPC slot number!\n", __FUNCTION__);
return -1;
}
/* 3A => Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
slot_cmd = 0x3A;
retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
if (retval) { if (retval) {
err("%s: Write command failed!\n", __FUNCTION__); err("%s: Write command failed!\n", __FUNCTION__);
return -1; return retval;
} }
DBG_LEAVE_ROUTINE DBG_LEAVE_ROUTINE
return retval; return 0;
} }
static int hpc_slot_disable(struct slot * slot) static int hpc_slot_disable(struct slot * slot)
{ {
struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; int retval;
u8 slot_cmd;
int retval = 0;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
if (!slot->ctrl->hpc_ctlr_handle) { /* Slot - Disable, Power Indicator - Off, Attention Indicator - On */
err("%s: Invalid HPC controller handle!\n", __FUNCTION__); retval = shpc_write_cmd(slot, slot->hp_slot,
return -1; SET_SLOT_DISABLE | SET_PWR_OFF | SET_ATTN_ON);
}
if (slot->hp_slot >= php_ctlr->num_slots) {
err("%s: Invalid HPC slot number!\n", __FUNCTION__);
return -1;
}
/* 1F => Slot - Disable, Power Indicator - Off, Attention Indicator - On */
slot_cmd = 0x1F;
retval = shpc_write_cmd(slot, slot->hp_slot, slot_cmd);
if (retval) { if (retval) {
err("%s: Write command failed!\n", __FUNCTION__); err("%s: Write command failed!\n", __FUNCTION__);
return -1; return retval;
} }
DBG_LEAVE_ROUTINE DBG_LEAVE_ROUTINE
return retval; return 0;
} }
static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
{ {
int retval; int retval;
struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; struct controller *ctrl = slot->ctrl;
u8 pi, cmd; u8 pi, cmd;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
pi = readb(php_ctlr->creg + PROG_INTERFACE); pi = shpc_readb(ctrl, PROG_INTERFACE);
if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX)) if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX))
return -EINVAL; return -EINVAL;
...@@ -965,100 +870,86 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value) ...@@ -965,100 +870,86 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
return retval; return retval;
} }
static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs)
{ {
struct controller *ctrl = NULL; struct controller *ctrl = (struct controller *)dev_id;
struct php_ctlr_state_s *php_ctlr; struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
u8 schedule_flag = 0; u32 serr_int, slot_reg, intr_loc, intr_loc2;
u8 temp_byte;
u32 temp_dword, intr_loc, intr_loc2;
int hp_slot; int hp_slot;
if (!dev_id)
return IRQ_NONE;
if (!shpchp_poll_mode) {
ctrl = (struct controller *)dev_id;
php_ctlr = ctrl->hpc_ctlr_handle;
} else {
php_ctlr = (struct php_ctlr_state_s *) dev_id;
ctrl = (struct controller *)php_ctlr->callback_instance_id;
}
if (!ctrl)
return IRQ_NONE;
if (!php_ctlr || !php_ctlr->creg)
return IRQ_NONE;
/* Check to see if it was our interrupt */ /* Check to see if it was our interrupt */
intr_loc = readl(php_ctlr->creg + INTR_LOC); intr_loc = shpc_readl(ctrl, INTR_LOC);
if (!intr_loc) if (!intr_loc)
return IRQ_NONE; 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) { if(!shpchp_poll_mode) {
/* Mask Global Interrupt Mask - see implementation note on p. 139 */ /*
/* of SHPC spec rev 1.0*/ * Mask Global Interrupt Mask - see implementation
temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); * note on p. 139 of SHPC spec rev 1.0
temp_dword |= 0x00000001; */
writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE);
serr_int |= GLOBAL_INTR_MASK;
serr_int &= ~SERR_INTR_RSVDZ_MASK;
shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
intr_loc2 = readl(php_ctlr->creg + INTR_LOC); 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 & 0x0001) { if (intr_loc & CMD_INTR_PENDING) {
/* /*
* Command Complete Interrupt Pending * Command Complete Interrupt Pending
* RO only - clear by writing 1 to the Command Completion * RO only - clear by writing 1 to the Command Completion
* Detect bit in Controller SERR-INT register * Detect bit in Controller SERR-INT register
*/ */
temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE);
temp_dword &= 0xfffdffff; serr_int &= ~SERR_INTR_RSVDZ_MASK;
writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
ctrl->cmd_busy = 0; ctrl->cmd_busy = 0;
wake_up_interruptible(&ctrl->queue); wake_up_interruptible(&ctrl->queue);
} }
if ((intr_loc = (intr_loc >> 1)) == 0) if (!(intr_loc & ~CMD_INTR_PENDING))
goto out; 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 */ /* To find out which slot has interrupt pending */
if ((intr_loc >> hp_slot) & 0x01) { if (!(intr_loc & SLOT_INTR_PENDING(hp_slot)))
temp_dword = readl(php_ctlr->creg + SLOT1 + (4*hp_slot)); continue;
dbg("%s: Slot %x with intr, slot register = %x\n",
__FUNCTION__, hp_slot, temp_dword); slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));
temp_byte = (temp_dword >> 16) & 0xFF; dbg("%s: Slot %x with intr, slot register = %x\n",
if ((php_ctlr->switch_change_callback) && (temp_byte & 0x08)) __FUNCTION__, hp_slot, slot_reg);
schedule_flag += php_ctlr->switch_change_callback(
hp_slot, php_ctlr->callback_instance_id); if (slot_reg & MRL_CHANGE_DETECTED)
if ((php_ctlr->attention_button_callback) && (temp_byte & 0x04)) php_ctlr->switch_change_callback(
schedule_flag += php_ctlr->attention_button_callback( hp_slot, php_ctlr->callback_instance_id);
hp_slot, php_ctlr->callback_instance_id);
if ((php_ctlr->presence_change_callback) && (temp_byte & 0x01)) if (slot_reg & BUTTON_PRESS_DETECTED)
schedule_flag += php_ctlr->presence_change_callback( php_ctlr->attention_button_callback(
hp_slot , php_ctlr->callback_instance_id); hp_slot, php_ctlr->callback_instance_id);
if ((php_ctlr->power_fault_callback) && (temp_byte & 0x12))
schedule_flag += php_ctlr->power_fault_callback( if (slot_reg & PRSNT_CHANGE_DETECTED)
hp_slot, php_ctlr->callback_instance_id); php_ctlr->presence_change_callback(
hp_slot , php_ctlr->callback_instance_id);
/* Clear all slot events */
temp_dword = 0xe01f3fff; if (slot_reg & (ISO_PFAULT_DETECTED | CON_PFAULT_DETECTED))
writel(temp_dword, php_ctlr->creg + SLOT1 + (4*hp_slot)); php_ctlr->power_fault_callback(
hp_slot, php_ctlr->callback_instance_id);
intr_loc2 = readl(php_ctlr->creg + INTR_LOC);
dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); /* Clear all slot events */
} slot_reg &= ~SLOT_REG_RSVDZ_MASK;
shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);
} }
out: out:
if (!shpchp_poll_mode) { if (!shpchp_poll_mode) {
/* Unmask Global Interrupt Mask */ /* Unmask Global Interrupt Mask */
temp_dword = readl(php_ctlr->creg + SERR_INTR_ENABLE); serr_int = shpc_readl(ctrl, SERR_INTR_ENABLE);
temp_dword &= 0xfffffffe; serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK);
writel(temp_dword, php_ctlr->creg + SERR_INTR_ENABLE); shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -1067,11 +958,11 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs) ...@@ -1067,11 +958,11 @@ static irqreturn_t shpc_isr(int IRQ, void *dev_id, struct pt_regs *regs)
static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
{ {
int retval = 0; int retval = 0;
struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; struct controller *ctrl = slot->ctrl;
enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
u8 pi = readb(php_ctlr->creg + PROG_INTERFACE); u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
u32 slot_avail1 = readl(php_ctlr->creg + SLOT_AVAIL1); u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1);
u32 slot_avail2 = readl(php_ctlr->creg + SLOT_AVAIL2); u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2);
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
...@@ -1114,10 +1005,10 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value) ...@@ -1114,10 +1005,10 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value) static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
{ {
int retval = 0; int retval = 0;
struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle; struct controller *ctrl = slot->ctrl;
enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN; enum pci_bus_speed bus_speed = PCI_SPEED_UNKNOWN;
u16 sec_bus_reg = readw(php_ctlr->creg + SEC_BUS_CONFIG); u16 sec_bus_reg = shpc_readw(ctrl, SEC_BUS_CONFIG);
u8 pi = readb(php_ctlr->creg + PROG_INTERFACE); u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7); u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7);
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
...@@ -1206,28 +1097,14 @@ static struct hpc_ops shpchp_hpc_ops = { ...@@ -1206,28 +1097,14 @@ static struct hpc_ops shpchp_hpc_ops = {
.release_ctlr = hpc_release_ctlr, .release_ctlr = hpc_release_ctlr,
}; };
inline static int shpc_indirect_creg_read(struct controller *ctrl, int index,
u32 *value)
{
int rc;
u32 cap_offset = ctrl->cap_offset;
struct pci_dev *pdev = ctrl->pci_dev;
rc = pci_write_config_byte(pdev, cap_offset + DWORD_SELECT, index);
if (rc)
return rc;
return pci_read_config_dword(pdev, cap_offset + DWORD_DATA, value);
}
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; struct php_ctlr_state_s *php_ctlr, *p;
void *instance_id = ctrl; void *instance_id = ctrl;
int rc, num_slots = 0; int rc, num_slots = 0;
u8 hp_slot; u8 hp_slot;
static int first = 1;
u32 shpc_base_offset; u32 shpc_base_offset;
u32 tempdword, slot_reg; u32 tempdword, slot_reg, slot_config;
u8 i; u8 i;
DBG_ENTER_ROUTINE DBG_ENTER_ROUTINE
...@@ -1257,13 +1134,13 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) ...@@ -1257,13 +1134,13 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
} }
dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset); dbg("%s: cap_offset = %x\n", __FUNCTION__, ctrl->cap_offset);
rc = shpc_indirect_creg_read(ctrl, 0, &shpc_base_offset); rc = shpc_indirect_read(ctrl, 0, &shpc_base_offset);
if (rc) { if (rc) {
err("%s: cannot read base_offset\n", __FUNCTION__); err("%s: cannot read base_offset\n", __FUNCTION__);
goto abort_free_ctlr; goto abort_free_ctlr;
} }
rc = shpc_indirect_creg_read(ctrl, 3, &tempdword); rc = shpc_indirect_read(ctrl, 3, &tempdword);
if (rc) { if (rc) {
err("%s: cannot read slot config\n", __FUNCTION__); err("%s: cannot read slot config\n", __FUNCTION__);
goto abort_free_ctlr; goto abort_free_ctlr;
...@@ -1272,7 +1149,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) ...@@ -1272,7 +1149,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots); dbg("%s: num_slots (indirect) %x\n", __FUNCTION__, num_slots);
for (i = 0; i < 9 + num_slots; i++) { for (i = 0; i < 9 + num_slots; i++) {
rc = shpc_indirect_creg_read(ctrl, i, &tempdword); rc = shpc_indirect_read(ctrl, i, &tempdword);
if (rc) { if (rc) {
err("%s: cannot read creg (index = %d)\n", err("%s: cannot read creg (index = %d)\n",
__FUNCTION__, i); __FUNCTION__, i);
...@@ -1287,11 +1164,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) ...@@ -1287,11 +1164,6 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
ctrl->mmio_size = 0x24 + 0x4 * num_slots; ctrl->mmio_size = 0x24 + 0x4 * num_slots;
} }
if (first) {
spin_lock_init(&hpc_event_lock);
first = 0;
}
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); pdev->subsystem_device);
...@@ -1326,29 +1198,39 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) ...@@ -1326,29 +1198,39 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
php_ctlr->power_fault_callback = shpchp_handle_power_fault; php_ctlr->power_fault_callback = shpchp_handle_power_fault;
php_ctlr->callback_instance_id = instance_id; php_ctlr->callback_instance_id = instance_id;
ctrl->hpc_ctlr_handle = php_ctlr;
ctrl->hpc_ops = &shpchp_hpc_ops;
/* Return PCI Controller Info */ /* Return PCI Controller Info */
php_ctlr->slot_device_offset = (readl(php_ctlr->creg + SLOT_CONFIG) & FIRST_DEV_NUM ) >> 8; slot_config = shpc_readl(ctrl, SLOT_CONFIG);
php_ctlr->num_slots = readl(php_ctlr->creg + SLOT_CONFIG) & SLOT_NUM; 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: slot_device_offset %x\n", __FUNCTION__, php_ctlr->slot_device_offset);
dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots); dbg("%s: num_slots %x\n", __FUNCTION__, php_ctlr->num_slots);
/* Mask Global Interrupt Mask & Command Complete Interrupt Mask */ /* Mask Global Interrupt Mask & Command Complete Interrupt Mask */
tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);
dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
tempdword = 0x0003000f; tempdword |= (GLOBAL_INTR_MASK | GLOBAL_SERR_MASK |
writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE); COMMAND_INTR_MASK | ARBITER_SERR_MASK);
tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); tempdword &= ~SERR_INTR_RSVDZ_MASK;
shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword);
tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);
dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
/* Mask the MRL sensor SERR Mask of individual slot in /* Mask the MRL sensor SERR Mask of individual slot in
* Slot SERR-INT Mask & clear all the existing event if any * 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 < php_ctlr->num_slots; hp_slot++) {
slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot ); slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));
dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
hp_slot, slot_reg); hp_slot, slot_reg);
tempdword = 0xffff3fff; slot_reg |= (PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK |
writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot)); BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK |
CON_PFAULT_INTR_MASK | MRL_CHANGE_SERR_MASK |
CON_PFAULT_SERR_MASK);
slot_reg &= ~SLOT_REG_RSVDZ_MASK;
shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);
} }
if (shpchp_poll_mode) {/* Install interrupt polling code */ if (shpchp_poll_mode) {/* Install interrupt polling code */
...@@ -1392,24 +1274,37 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev) ...@@ -1392,24 +1274,37 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
} }
spin_unlock(&list_lock); spin_unlock(&list_lock);
ctlr_seq_num++; ctlr_seq_num++;
ctrl->hpc_ctlr_handle = php_ctlr;
ctrl->hpc_ops = &shpchp_hpc_ops;
/*
* If this is the first controller to be initialized,
* initialize the shpchpd work queue
*/
if (atomic_add_return(1, &shpchp_num_controllers) == 1) {
shpchp_wq = create_singlethread_workqueue("shpchpd");
if (!shpchp_wq)
return -ENOMEM;
}
/*
* 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 < php_ctlr->num_slots; hp_slot++) {
slot_reg = readl(php_ctlr->creg + SLOT1 + 4*hp_slot ); slot_reg = shpc_readl(ctrl, SLOT_REG(hp_slot));
dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__, dbg("%s: Default Logical Slot Register %d value %x\n", __FUNCTION__,
hp_slot, slot_reg); hp_slot, slot_reg);
tempdword = 0xe01f3fff; slot_reg &= ~(PRSNT_CHANGE_INTR_MASK | ISO_PFAULT_INTR_MASK |
writel(tempdword, php_ctlr->creg + SLOT1 + (4*hp_slot)); BUTTON_PRESS_INTR_MASK | MRL_CHANGE_INTR_MASK |
CON_PFAULT_INTR_MASK | SLOT_REG_RSVDZ_MASK);
shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);
} }
if (!shpchp_poll_mode) { if (!shpchp_poll_mode) {
/* Unmask all general input interrupts and SERR */ /* Unmask all general input interrupts and SERR */
tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);
tempdword = 0x0000000a; tempdword &= ~(GLOBAL_INTR_MASK | COMMAND_INTR_MASK |
writel(tempdword, php_ctlr->creg + SERR_INTR_ENABLE); SERR_INTR_RSVDZ_MASK);
tempdword = readl(php_ctlr->creg + SERR_INTR_ENABLE); shpc_writel(ctrl, SERR_INTR_ENABLE, tempdword);
tempdword = shpc_readl(ctrl, SERR_INTR_ENABLE);
dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword); dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
} }
......
...@@ -47,21 +47,28 @@ static void program_fw_provided_values(struct pci_dev *dev) ...@@ -47,21 +47,28 @@ static void program_fw_provided_values(struct pci_dev *dev)
return; return;
/* use default values if we can't get them from firmware */ /* use default values if we can't get them from firmware */
if (get_hp_params_from_firmware(dev, &hpp)) { if (get_hp_params_from_firmware(dev, &hpp) ||
hpp.cache_line_size = 8; !hpp.t0 || (hpp.t0->revision > 1)) {
hpp.latency_timer = 0x40; printk(KERN_WARNING
hpp.enable_serr = 0; "%s: Could not get hotplug parameters. Use defaults\n",
hpp.enable_perr = 0; __FUNCTION__);
hpp.t0 = &hpp.type0_data;
hpp.t0->revision = 0;
hpp.t0->cache_line_size = 8;
hpp.t0->latency_timer = 0x40;
hpp.t0->enable_serr = 0;
hpp.t0->enable_perr = 0;
} }
pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, hpp.cache_line_size); pci_write_config_byte(dev,
pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp.latency_timer); PCI_CACHE_LINE_SIZE, hpp.t0->cache_line_size);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, hpp.t0->latency_timer);
pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
if (hpp.enable_serr) if (hpp.t0->enable_serr)
pci_cmd |= PCI_COMMAND_SERR; pci_cmd |= PCI_COMMAND_SERR;
else else
pci_cmd &= ~PCI_COMMAND_SERR; pci_cmd &= ~PCI_COMMAND_SERR;
if (hpp.enable_perr) if (hpp.t0->enable_perr)
pci_cmd |= PCI_COMMAND_PARITY; pci_cmd |= PCI_COMMAND_PARITY;
else else
pci_cmd &= ~PCI_COMMAND_PARITY; pci_cmd &= ~PCI_COMMAND_PARITY;
...@@ -70,13 +77,13 @@ static void program_fw_provided_values(struct pci_dev *dev) ...@@ -70,13 +77,13 @@ static void program_fw_provided_values(struct pci_dev *dev)
/* Program bridge control value and child devices */ /* Program bridge control value and child devices */
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER,
hpp.latency_timer); hpp.t0->latency_timer);
pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl);
if (hpp.enable_serr) if (hpp.t0->enable_serr)
pci_bctl |= PCI_BRIDGE_CTL_SERR; pci_bctl |= PCI_BRIDGE_CTL_SERR;
else else
pci_bctl &= ~PCI_BRIDGE_CTL_SERR; pci_bctl &= ~PCI_BRIDGE_CTL_SERR;
if (hpp.enable_perr) if (hpp.t0->enable_perr)
pci_bctl |= PCI_BRIDGE_CTL_PARITY; pci_bctl |= PCI_BRIDGE_CTL_PARITY;
else else
pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; pci_bctl &= ~PCI_BRIDGE_CTL_PARITY;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment