mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-19 00:54:41 +08:00
Merge branch 'pci/hotplug' into next
* pci/hotplug: PCI: pciehp: Prevent NULL dereference during probe PCI: pciehp: Reduce PCIe slot_ctrl to 16 bits PCI: Configure *all* devices, not just hot-added ones PCI: Preserve MPS and MRRS when applying _HPX settings PCI: Apply _HPP settings to all hot-added PCI devices PCI: Preserve BIOS PCI_COMMAND_SERR and PCI_COMMAND_PARITY settings PCI: Apply _HPP settings to PCIe devices as well as PCI and PCI-X PCI: Remove unused pci_configure_slot() ACPI / hotplug / PCI: Remove pci_configure_slot() usage PCI: shpchp: Remove pci_configure_slot() usage PCI: pciehp: Remove pci_configure_slot() usage PCI: Add pci_configure_device() during enumeration PCI: Move pci_configure_slot() to drivers/pci/probe.c PCI: Shuffle pci-acpi.c functions to group them logically PCI: Whitespace cleanup in pci-acpi.c PCI: Move pci_get_hp_params() to drivers/pci/pci-acpi.c PCI: pciehp: Configure hot-added display devices PCI: Remove "no hotplug settings from platform" warning
This commit is contained in:
commit
2f419d7659
@ -24,7 +24,7 @@ obj-$(CONFIG_HOTPLUG_PCI_S390) += s390_pci_hpc.o
|
|||||||
|
|
||||||
obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o
|
obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o
|
||||||
|
|
||||||
pci_hotplug-objs := pci_hotplug_core.o pcihp_slot.o
|
pci_hotplug-objs := pci_hotplug_core.o
|
||||||
|
|
||||||
ifdef CONFIG_HOTPLUG_PCI_CPCI
|
ifdef CONFIG_HOTPLUG_PCI_CPCI
|
||||||
pci_hotplug-objs += cpci_hotplug_core.o \
|
pci_hotplug-objs += cpci_hotplug_core.o \
|
||||||
|
@ -46,215 +46,6 @@
|
|||||||
|
|
||||||
static bool debug_acpi;
|
static bool 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",
|
|
||||||
__func__, 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",
|
|
||||||
__func__, 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",
|
|
||||||
__func__, 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",
|
|
||||||
__func__, type);
|
|
||||||
status = AE_ERROR;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
exit:
|
|
||||||
kfree(buffer.pointer);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static acpi_status
|
|
||||||
acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
|
|
||||||
{
|
|
||||||
acpi_status status;
|
|
||||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
|
||||||
union acpi_object *package, *fields;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
memset(hpp, 0, sizeof(struct hotplug_params));
|
|
||||||
|
|
||||||
status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer);
|
|
||||||
if (ACPI_FAILURE(status))
|
|
||||||
return status;
|
|
||||||
|
|
||||||
package = (union acpi_object *) buffer.pointer;
|
|
||||||
if (package->type != ACPI_TYPE_PACKAGE ||
|
|
||||||
package->package.count != 4) {
|
|
||||||
status = AE_ERROR;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
fields = package->package.elements;
|
|
||||||
for (i = 0; i < 4; i++) {
|
|
||||||
if (fields[i].type != ACPI_TYPE_INTEGER) {
|
|
||||||
status = AE_ERROR;
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hpp->t0 = &hpp->type0_data;
|
|
||||||
hpp->t0->revision = 1;
|
|
||||||
hpp->t0->cache_line_size = fields[0].integer.value;
|
|
||||||
hpp->t0->latency_timer = fields[1].integer.value;
|
|
||||||
hpp->t0->enable_serr = fields[2].integer.value;
|
|
||||||
hpp->t0->enable_perr = fields[3].integer.value;
|
|
||||||
|
|
||||||
exit:
|
|
||||||
kfree(buffer.pointer);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* acpi_run_oshp - get control of hotplug from the firmware
|
/* acpi_run_oshp - get control of hotplug from the firmware
|
||||||
*
|
*
|
||||||
* @handle - the handle of the hotplug controller.
|
* @handle - the handle of the hotplug controller.
|
||||||
@ -283,48 +74,6 @@ static acpi_status acpi_run_oshp(acpi_handle handle)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* pci_get_hp_params
|
|
||||||
*
|
|
||||||
* @dev - the pci_dev for which we want parameters
|
|
||||||
* @hpp - allocated by the caller
|
|
||||||
*/
|
|
||||||
int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp)
|
|
||||||
{
|
|
||||||
acpi_status status;
|
|
||||||
acpi_handle handle, phandle;
|
|
||||||
struct pci_bus *pbus;
|
|
||||||
|
|
||||||
handle = NULL;
|
|
||||||
for (pbus = dev->bus; pbus; pbus = pbus->parent) {
|
|
||||||
handle = acpi_pci_get_bridge_handle(pbus);
|
|
||||||
if (handle)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* _HPP settings apply to all child buses, until another _HPP is
|
|
||||||
* encountered. If we don't find an _HPP for the input pci dev,
|
|
||||||
* look for it in the parent device scope since that would apply to
|
|
||||||
* this pci dev.
|
|
||||||
*/
|
|
||||||
while (handle) {
|
|
||||||
status = acpi_run_hpx(handle, hpp);
|
|
||||||
if (ACPI_SUCCESS(status))
|
|
||||||
return 0;
|
|
||||||
status = acpi_run_hpp(handle, hpp);
|
|
||||||
if (ACPI_SUCCESS(status))
|
|
||||||
return 0;
|
|
||||||
if (acpi_is_root_bridge(handle))
|
|
||||||
break;
|
|
||||||
status = acpi_get_parent(handle, &phandle);
|
|
||||||
if (ACPI_FAILURE(status))
|
|
||||||
break;
|
|
||||||
handle = phandle;
|
|
||||||
}
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(pci_get_hp_params);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* acpi_get_hp_hw_control_from_firmware
|
* acpi_get_hp_hw_control_from_firmware
|
||||||
* @dev: the pci_dev of the bridge that has a hotplug controller
|
* @dev: the pci_dev of the bridge that has a hotplug controller
|
||||||
|
@ -61,7 +61,6 @@ static DEFINE_MUTEX(bridge_mutex);
|
|||||||
static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type);
|
static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type);
|
||||||
static void acpiphp_post_dock_fixup(struct acpi_device *adev);
|
static void acpiphp_post_dock_fixup(struct acpi_device *adev);
|
||||||
static void acpiphp_sanitize_bus(struct pci_bus *bus);
|
static void acpiphp_sanitize_bus(struct pci_bus *bus);
|
||||||
static void acpiphp_set_hpp_values(struct pci_bus *bus);
|
|
||||||
static void hotplug_event(u32 type, struct acpiphp_context *context);
|
static void hotplug_event(u32 type, struct acpiphp_context *context);
|
||||||
static void free_bridge(struct kref *kref);
|
static void free_bridge(struct kref *kref);
|
||||||
|
|
||||||
@ -510,7 +509,7 @@ static void enable_slot(struct acpiphp_slot *slot)
|
|||||||
__pci_bus_assign_resources(bus, &add_list, NULL);
|
__pci_bus_assign_resources(bus, &add_list, NULL);
|
||||||
|
|
||||||
acpiphp_sanitize_bus(bus);
|
acpiphp_sanitize_bus(bus);
|
||||||
acpiphp_set_hpp_values(bus);
|
pcie_bus_configure_settings(bus);
|
||||||
acpiphp_set_acpi_region(slot);
|
acpiphp_set_acpi_region(slot);
|
||||||
|
|
||||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||||
@ -702,14 +701,6 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void acpiphp_set_hpp_values(struct pci_bus *bus)
|
|
||||||
{
|
|
||||||
struct pci_dev *dev;
|
|
||||||
|
|
||||||
list_for_each_entry(dev, &bus->devices, bus_list)
|
|
||||||
pci_configure_slot(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove devices for which we could not assign resources, call
|
* Remove devices for which we could not assign resources, call
|
||||||
* arch specific code to fix-up the bus
|
* arch specific code to fix-up the bus
|
||||||
|
@ -92,7 +92,7 @@ struct controller {
|
|||||||
struct slot *slot;
|
struct slot *slot;
|
||||||
wait_queue_head_t queue; /* sleep & wake process */
|
wait_queue_head_t queue; /* sleep & wake process */
|
||||||
u32 slot_cap;
|
u32 slot_cap;
|
||||||
u32 slot_ctrl;
|
u16 slot_ctrl;
|
||||||
struct timer_list poll_timer;
|
struct timer_list poll_timer;
|
||||||
unsigned long cmd_started; /* jiffies */
|
unsigned long cmd_started; /* jiffies */
|
||||||
unsigned int cmd_busy:1;
|
unsigned int cmd_busy:1;
|
||||||
|
@ -262,6 +262,13 @@ static int pciehp_probe(struct pcie_device *dev)
|
|||||||
goto err_out_none;
|
goto err_out_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!dev->port->subordinate) {
|
||||||
|
/* Can happen if we run out of bus numbers during probe */
|
||||||
|
dev_err(&dev->device,
|
||||||
|
"Hotplug bridge without secondary bus, ignoring\n");
|
||||||
|
goto err_out_none;
|
||||||
|
}
|
||||||
|
|
||||||
ctrl = pcie_init(dev);
|
ctrl = pcie_init(dev);
|
||||||
if (!ctrl) {
|
if (!ctrl) {
|
||||||
dev_err(&dev->device, "Controller initialization failed\n");
|
dev_err(&dev->device, "Controller initialization failed\n");
|
||||||
|
@ -171,7 +171,7 @@ static void pcie_wait_cmd(struct controller *ctrl)
|
|||||||
* interrupts.
|
* interrupts.
|
||||||
*/
|
*/
|
||||||
if (!rc)
|
if (!rc)
|
||||||
ctrl_info(ctrl, "Timeout on hotplug command %#010x (issued %u msec ago)\n",
|
ctrl_info(ctrl, "Timeout on hotplug command %#06x (issued %u msec ago)\n",
|
||||||
ctrl->slot_ctrl,
|
ctrl->slot_ctrl,
|
||||||
jiffies_to_msecs(now - ctrl->cmd_started));
|
jiffies_to_msecs(now - ctrl->cmd_started));
|
||||||
}
|
}
|
||||||
|
@ -65,14 +65,7 @@ int pciehp_configure_device(struct slot *p_slot)
|
|||||||
pci_hp_add_bridge(dev);
|
pci_hp_add_bridge(dev);
|
||||||
|
|
||||||
pci_assign_unassigned_bridge_resources(bridge);
|
pci_assign_unassigned_bridge_resources(bridge);
|
||||||
|
pcie_bus_configure_settings(parent);
|
||||||
list_for_each_entry(dev, &parent->devices, bus_list) {
|
|
||||||
if ((dev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
pci_configure_slot(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
pci_bus_add_devices(parent);
|
pci_bus_add_devices(parent);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -1,180 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 1995,2001 Compaq Computer Corporation
|
|
||||||
* Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
|
|
||||||
* Copyright (C) 2001 IBM Corp.
|
|
||||||
* Copyright (C) 2003-2004 Intel Corporation
|
|
||||||
* (c) Copyright 2009 Hewlett-Packard Development Company, L.P.
|
|
||||||
*
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or (at
|
|
||||||
* your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but
|
|
||||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
|
|
||||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
|
||||||
* details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/pci.h>
|
|
||||||
#include <linux/export.h>
|
|
||||||
#include <linux/pci_hotplug.h>
|
|
||||||
|
|
||||||
static struct hpp_type0 pci_default_type0 = {
|
|
||||||
.revision = 1,
|
|
||||||
.cache_line_size = 8,
|
|
||||||
.latency_timer = 0x40,
|
|
||||||
.enable_serr = 0,
|
|
||||||
.enable_perr = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp)
|
|
||||||
{
|
|
||||||
u16 pci_cmd, pci_bctl;
|
|
||||||
|
|
||||||
if (!hpp) {
|
|
||||||
/*
|
|
||||||
* Perhaps we *should* use default settings for PCIe, but
|
|
||||||
* pciehp didn't, so we won't either.
|
|
||||||
*/
|
|
||||||
if (pci_is_pcie(dev))
|
|
||||||
return;
|
|
||||||
dev_info(&dev->dev, "using default PCI settings\n");
|
|
||||||
hpp = &pci_default_type0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hpp->revision > 1) {
|
|
||||||
dev_warn(&dev->dev,
|
|
||||||
"PCI settings rev %d not supported; using defaults\n",
|
|
||||||
hpp->revision);
|
|
||||||
hpp = &pci_default_type0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_type1(struct pci_dev *dev, struct hpp_type1 *hpp)
|
|
||||||
{
|
|
||||||
if (hpp)
|
|
||||||
dev_warn(&dev->dev, "PCI-X settings not supported\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
|
|
||||||
{
|
|
||||||
int pos;
|
|
||||||
u32 reg32;
|
|
||||||
|
|
||||||
if (!hpp)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (hpp->revision > 1) {
|
|
||||||
dev_warn(&dev->dev, "PCIe settings rev %d not supported\n",
|
|
||||||
hpp->revision);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize Device Control Register */
|
|
||||||
pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
|
|
||||||
~hpp->pci_exp_devctl_and, hpp->pci_exp_devctl_or);
|
|
||||||
|
|
||||||
/* Initialize Link Control Register */
|
|
||||||
if (dev->subordinate)
|
|
||||||
pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL,
|
|
||||||
~hpp->pci_exp_lnkctl_and, hpp->pci_exp_lnkctl_or);
|
|
||||||
|
|
||||||
/* Find Advanced Error Reporting Enhanced Capability */
|
|
||||||
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
|
|
||||||
if (!pos)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Initialize Uncorrectable Error Mask Register */
|
|
||||||
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, ®32);
|
|
||||||
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, ®32);
|
|
||||||
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, ®32);
|
|
||||||
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, ®32);
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void pci_configure_slot(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
struct pci_dev *cdev;
|
|
||||||
struct hotplug_params hpp;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL ||
|
|
||||||
(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
|
|
||||||
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
pcie_bus_configure_settings(dev->bus);
|
|
||||||
|
|
||||||
memset(&hpp, 0, sizeof(hpp));
|
|
||||||
ret = pci_get_hp_params(dev, &hpp);
|
|
||||||
if (ret)
|
|
||||||
dev_warn(&dev->dev, "no hotplug settings from platform\n");
|
|
||||||
|
|
||||||
program_hpp_type2(dev, hpp.t2);
|
|
||||||
program_hpp_type1(dev, hpp.t1);
|
|
||||||
program_hpp_type0(dev, hpp.t0);
|
|
||||||
|
|
||||||
if (dev->subordinate) {
|
|
||||||
list_for_each_entry(cdev, &dev->subordinate->devices,
|
|
||||||
bus_list)
|
|
||||||
pci_configure_slot(cdev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(pci_configure_slot);
|
|
@ -69,13 +69,7 @@ int shpchp_configure_device(struct slot *p_slot)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pci_assign_unassigned_bridge_resources(bridge);
|
pci_assign_unassigned_bridge_resources(bridge);
|
||||||
|
pcie_bus_configure_settings(parent);
|
||||||
list_for_each_entry(dev, &parent->devices, bus_list) {
|
|
||||||
if (PCI_SLOT(dev->devfn) != p_slot->device)
|
|
||||||
continue;
|
|
||||||
pci_configure_slot(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
pci_bus_add_devices(parent);
|
pci_bus_add_devices(parent);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/pci_hotplug.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/pci-aspm.h>
|
#include <linux/pci-aspm.h>
|
||||||
#include <linux/pci-acpi.h>
|
#include <linux/pci-acpi.h>
|
||||||
@ -17,6 +18,267 @@
|
|||||||
#include <linux/pm_qos.h>
|
#include <linux/pm_qos.h>
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
|
|
||||||
|
phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
|
||||||
|
{
|
||||||
|
acpi_status status = AE_NOT_EXIST;
|
||||||
|
unsigned long long mcfg_addr;
|
||||||
|
|
||||||
|
if (handle)
|
||||||
|
status = acpi_evaluate_integer(handle, METHOD_NAME__CBA,
|
||||||
|
NULL, &mcfg_addr);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (phys_addr_t)mcfg_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
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",
|
||||||
|
__func__, 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",
|
||||||
|
__func__, 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",
|
||||||
|
__func__, 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",
|
||||||
|
__func__, type);
|
||||||
|
status = AE_ERROR;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
kfree(buffer.pointer);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static acpi_status acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
|
||||||
|
{
|
||||||
|
acpi_status status;
|
||||||
|
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||||
|
union acpi_object *package, *fields;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(hpp, 0, sizeof(struct hotplug_params));
|
||||||
|
|
||||||
|
status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
return status;
|
||||||
|
|
||||||
|
package = (union acpi_object *) buffer.pointer;
|
||||||
|
if (package->type != ACPI_TYPE_PACKAGE ||
|
||||||
|
package->package.count != 4) {
|
||||||
|
status = AE_ERROR;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
fields = package->package.elements;
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
if (fields[i].type != ACPI_TYPE_INTEGER) {
|
||||||
|
status = AE_ERROR;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hpp->t0 = &hpp->type0_data;
|
||||||
|
hpp->t0->revision = 1;
|
||||||
|
hpp->t0->cache_line_size = fields[0].integer.value;
|
||||||
|
hpp->t0->latency_timer = fields[1].integer.value;
|
||||||
|
hpp->t0->enable_serr = fields[2].integer.value;
|
||||||
|
hpp->t0->enable_perr = fields[3].integer.value;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
kfree(buffer.pointer);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pci_get_hp_params
|
||||||
|
*
|
||||||
|
* @dev - the pci_dev for which we want parameters
|
||||||
|
* @hpp - allocated by the caller
|
||||||
|
*/
|
||||||
|
int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp)
|
||||||
|
{
|
||||||
|
acpi_status status;
|
||||||
|
acpi_handle handle, phandle;
|
||||||
|
struct pci_bus *pbus;
|
||||||
|
|
||||||
|
handle = NULL;
|
||||||
|
for (pbus = dev->bus; pbus; pbus = pbus->parent) {
|
||||||
|
handle = acpi_pci_get_bridge_handle(pbus);
|
||||||
|
if (handle)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* _HPP settings apply to all child buses, until another _HPP is
|
||||||
|
* encountered. If we don't find an _HPP for the input pci dev,
|
||||||
|
* look for it in the parent device scope since that would apply to
|
||||||
|
* this pci dev.
|
||||||
|
*/
|
||||||
|
while (handle) {
|
||||||
|
status = acpi_run_hpx(handle, hpp);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
return 0;
|
||||||
|
status = acpi_run_hpp(handle, hpp);
|
||||||
|
if (ACPI_SUCCESS(status))
|
||||||
|
return 0;
|
||||||
|
if (acpi_is_root_bridge(handle))
|
||||||
|
break;
|
||||||
|
status = acpi_get_parent(handle, &phandle);
|
||||||
|
if (ACPI_FAILURE(status))
|
||||||
|
break;
|
||||||
|
handle = phandle;
|
||||||
|
}
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(pci_get_hp_params);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pci_acpi_wake_bus - Root bus wakeup notification fork function.
|
* pci_acpi_wake_bus - Root bus wakeup notification fork function.
|
||||||
* @work: Work item to handle.
|
* @work: Work item to handle.
|
||||||
@ -84,20 +346,6 @@ acpi_status pci_acpi_add_pm_notifier(struct acpi_device *dev,
|
|||||||
return acpi_add_pm_notifier(dev, &pci_dev->dev, pci_acpi_wake_dev);
|
return acpi_add_pm_notifier(dev, &pci_dev->dev, pci_acpi_wake_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
|
|
||||||
{
|
|
||||||
acpi_status status = AE_NOT_EXIST;
|
|
||||||
unsigned long long mcfg_addr;
|
|
||||||
|
|
||||||
if (handle)
|
|
||||||
status = acpi_evaluate_integer(handle, METHOD_NAME__CBA,
|
|
||||||
NULL, &mcfg_addr);
|
|
||||||
if (ACPI_FAILURE(status))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return (phys_addr_t)mcfg_addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* _SxD returns the D-state with the highest power
|
* _SxD returns the D-state with the highest power
|
||||||
* (lowest D-state number) supported in the S-state "x".
|
* (lowest D-state number) supported in the S-state "x".
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/pci_hotplug.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/cpumask.h>
|
#include <linux/cpumask.h>
|
||||||
@ -1249,6 +1250,137 @@ int pci_setup_device(struct pci_dev *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct hpp_type0 pci_default_type0 = {
|
||||||
|
.revision = 1,
|
||||||
|
.cache_line_size = 8,
|
||||||
|
.latency_timer = 0x40,
|
||||||
|
.enable_serr = 0,
|
||||||
|
.enable_perr = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void program_hpp_type0(struct pci_dev *dev, struct hpp_type0 *hpp)
|
||||||
|
{
|
||||||
|
u16 pci_cmd, pci_bctl;
|
||||||
|
|
||||||
|
if (!hpp)
|
||||||
|
hpp = &pci_default_type0;
|
||||||
|
|
||||||
|
if (hpp->revision > 1) {
|
||||||
|
dev_warn(&dev->dev,
|
||||||
|
"PCI settings rev %d not supported; using defaults\n",
|
||||||
|
hpp->revision);
|
||||||
|
hpp = &pci_default_type0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
if (hpp->enable_perr)
|
||||||
|
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;
|
||||||
|
if (hpp->enable_perr)
|
||||||
|
pci_bctl |= PCI_BRIDGE_CTL_PARITY;
|
||||||
|
pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void program_hpp_type1(struct pci_dev *dev, struct hpp_type1 *hpp)
|
||||||
|
{
|
||||||
|
if (hpp)
|
||||||
|
dev_warn(&dev->dev, "PCI-X settings not supported\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
|
||||||
|
{
|
||||||
|
int pos;
|
||||||
|
u32 reg32;
|
||||||
|
|
||||||
|
if (!hpp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (hpp->revision > 1) {
|
||||||
|
dev_warn(&dev->dev, "PCIe settings rev %d not supported\n",
|
||||||
|
hpp->revision);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Don't allow _HPX to change MPS or MRRS settings. We manage
|
||||||
|
* those to make sure they're consistent with the rest of the
|
||||||
|
* platform.
|
||||||
|
*/
|
||||||
|
hpp->pci_exp_devctl_and |= PCI_EXP_DEVCTL_PAYLOAD |
|
||||||
|
PCI_EXP_DEVCTL_READRQ;
|
||||||
|
hpp->pci_exp_devctl_or &= ~(PCI_EXP_DEVCTL_PAYLOAD |
|
||||||
|
PCI_EXP_DEVCTL_READRQ);
|
||||||
|
|
||||||
|
/* Initialize Device Control Register */
|
||||||
|
pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL,
|
||||||
|
~hpp->pci_exp_devctl_and, hpp->pci_exp_devctl_or);
|
||||||
|
|
||||||
|
/* Initialize Link Control Register */
|
||||||
|
if (dev->subordinate)
|
||||||
|
pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL,
|
||||||
|
~hpp->pci_exp_lnkctl_and, hpp->pci_exp_lnkctl_or);
|
||||||
|
|
||||||
|
/* Find Advanced Error Reporting Enhanced Capability */
|
||||||
|
pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
|
||||||
|
if (!pos)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Initialize Uncorrectable Error Mask Register */
|
||||||
|
pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, ®32);
|
||||||
|
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, ®32);
|
||||||
|
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, ®32);
|
||||||
|
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, ®32);
|
||||||
|
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 pci_configure_device(struct pci_dev *dev)
|
||||||
|
{
|
||||||
|
struct hotplug_params hpp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset(&hpp, 0, sizeof(hpp));
|
||||||
|
ret = pci_get_hp_params(dev, &hpp);
|
||||||
|
if (ret)
|
||||||
|
return;
|
||||||
|
|
||||||
|
program_hpp_type2(dev, hpp.t2);
|
||||||
|
program_hpp_type1(dev, hpp.t1);
|
||||||
|
program_hpp_type0(dev, hpp.t0);
|
||||||
|
}
|
||||||
|
|
||||||
static void pci_release_capabilities(struct pci_dev *dev)
|
static void pci_release_capabilities(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
pci_vpd_release(dev);
|
pci_vpd_release(dev);
|
||||||
@ -1391,6 +1523,8 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
pci_configure_device(dev);
|
||||||
|
|
||||||
device_initialize(&dev->dev);
|
device_initialize(&dev->dev);
|
||||||
dev->dev.release = pci_release_dev;
|
dev->dev.release = pci_release_dev;
|
||||||
|
|
||||||
|
@ -187,6 +187,4 @@ static inline int pci_get_hp_params(struct pci_dev *dev,
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void pci_configure_slot(struct pci_dev *dev);
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user