Merge branch 'pci/hotplug'

- Fix RPA and RPA DLPAR refcount issues (Tyrel Datwyler)

  - Stop exporting pci_get_hp_params() (Alexandru Gagniuc)

  - Simplify _HPP, _HPX parsing (Alexandru Gagniuc)

  - Add support for _HPX Type 3 settings (Alexandru Gagniuc)

  - Tell firmware we support _HPX Type 3 via _OSC (Alexandru Gagniuc)

* pci/hotplug:
  PCI/ACPI: Advertise _HPX Type 3 support via _OSC
  PCI/ACPI: Implement _HPX Type 3 Setting Record
  PCI/ACPI: Remove the need for 'struct hotplug_params'
  PCI/ACPI: Do not export pci_get_hp_params()
  PCI: rpaphp: Get/put device node reference during slot alloc/dealloc
  PCI: rpadlpar: Fix leaked device_node references in add/remove paths
This commit is contained in:
Bjorn Helgaas 2019-05-13 18:34:31 -05:00
commit 3ea6f739dc
7 changed files with 307 additions and 73 deletions

View File

@ -145,6 +145,7 @@ static struct pci_osc_bit_struct pci_osc_support_bit[] = {
{ OSC_PCI_CLOCK_PM_SUPPORT, "ClockPM" }, { OSC_PCI_CLOCK_PM_SUPPORT, "ClockPM" },
{ OSC_PCI_SEGMENT_GROUPS_SUPPORT, "Segments" }, { OSC_PCI_SEGMENT_GROUPS_SUPPORT, "Segments" },
{ OSC_PCI_MSI_SUPPORT, "MSI" }, { OSC_PCI_MSI_SUPPORT, "MSI" },
{ OSC_PCI_HPX_TYPE_3_SUPPORT, "HPX-Type3" },
}; };
static struct pci_osc_bit_struct pci_osc_control_bit[] = { static struct pci_osc_bit_struct pci_osc_control_bit[] = {
@ -446,6 +447,7 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,
* PCI domains, so we indicate this in _OSC support capabilities. * PCI domains, so we indicate this in _OSC support capabilities.
*/ */
support = OSC_PCI_SEGMENT_GROUPS_SUPPORT; support = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
support |= OSC_PCI_HPX_TYPE_3_SUPPORT;
if (pci_ext_cfg_avail()) if (pci_ext_cfg_avail())
support |= OSC_PCI_EXT_CONFIG_SUPPORT; support |= OSC_PCI_EXT_CONFIG_SUPPORT;
if (pcie_aspm_support_enabled()) if (pcie_aspm_support_enabled())

View File

@ -51,6 +51,7 @@ static struct device_node *find_vio_slot_node(char *drc_name)
if (rc == 0) if (rc == 0)
break; break;
} }
of_node_put(parent);
return dn; return dn;
} }
@ -71,6 +72,7 @@ static struct device_node *find_php_slot_pci_node(char *drc_name,
return np; return np;
} }
/* Returns a device_node with its reference count incremented */
static struct device_node *find_dlpar_node(char *drc_name, int *node_type) static struct device_node *find_dlpar_node(char *drc_name, int *node_type)
{ {
struct device_node *dn; struct device_node *dn;
@ -306,6 +308,7 @@ int dlpar_add_slot(char *drc_name)
rc = dlpar_add_phb(drc_name, dn); rc = dlpar_add_phb(drc_name, dn);
break; break;
} }
of_node_put(dn);
printk(KERN_INFO "%s: slot %s added\n", DLPAR_MODULE_NAME, drc_name); printk(KERN_INFO "%s: slot %s added\n", DLPAR_MODULE_NAME, drc_name);
exit: exit:
@ -439,6 +442,7 @@ int dlpar_remove_slot(char *drc_name)
rc = dlpar_remove_pci_slot(drc_name, dn); rc = dlpar_remove_pci_slot(drc_name, dn);
break; break;
} }
of_node_put(dn);
vm_unmap_aliases(); vm_unmap_aliases();
printk(KERN_INFO "%s: slot %s removed\n", DLPAR_MODULE_NAME, drc_name); printk(KERN_INFO "%s: slot %s removed\n", DLPAR_MODULE_NAME, drc_name);

View File

@ -21,6 +21,7 @@
/* free up the memory used by a slot */ /* free up the memory used by a slot */
void dealloc_slot_struct(struct slot *slot) void dealloc_slot_struct(struct slot *slot)
{ {
of_node_put(slot->dn);
kfree(slot->name); kfree(slot->name);
kfree(slot); kfree(slot);
} }
@ -36,7 +37,7 @@ struct slot *alloc_slot_struct(struct device_node *dn,
slot->name = kstrdup(drc_name, GFP_KERNEL); slot->name = kstrdup(drc_name, GFP_KERNEL);
if (!slot->name) if (!slot->name)
goto error_slot; goto error_slot;
slot->dn = dn; slot->dn = of_node_get(dn);
slot->index = drc_index; slot->index = drc_index;
slot->power_domain = power_domain; slot->power_domain = power_domain;
slot->hotplug_slot.ops = &rpaphp_hotplug_slot_ops; slot->hotplug_slot.ops = &rpaphp_hotplug_slot_ops;

View File

@ -119,7 +119,7 @@ phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
} }
static acpi_status decode_type0_hpx_record(union acpi_object *record, static acpi_status decode_type0_hpx_record(union acpi_object *record,
struct hotplug_params *hpx) struct hpp_type0 *hpx0)
{ {
int i; int i;
union acpi_object *fields = record->package.elements; union acpi_object *fields = record->package.elements;
@ -132,12 +132,11 @@ static acpi_status decode_type0_hpx_record(union acpi_object *record,
for (i = 2; i < 6; i++) for (i = 2; i < 6; i++)
if (fields[i].type != ACPI_TYPE_INTEGER) if (fields[i].type != ACPI_TYPE_INTEGER)
return AE_ERROR; return AE_ERROR;
hpx->t0 = &hpx->type0_data; hpx0->revision = revision;
hpx->t0->revision = revision; hpx0->cache_line_size = fields[2].integer.value;
hpx->t0->cache_line_size = fields[2].integer.value; hpx0->latency_timer = fields[3].integer.value;
hpx->t0->latency_timer = fields[3].integer.value; hpx0->enable_serr = fields[4].integer.value;
hpx->t0->enable_serr = fields[4].integer.value; hpx0->enable_perr = fields[5].integer.value;
hpx->t0->enable_perr = fields[5].integer.value;
break; break;
default: default:
printk(KERN_WARNING printk(KERN_WARNING
@ -149,7 +148,7 @@ static acpi_status decode_type0_hpx_record(union acpi_object *record,
} }
static acpi_status decode_type1_hpx_record(union acpi_object *record, static acpi_status decode_type1_hpx_record(union acpi_object *record,
struct hotplug_params *hpx) struct hpp_type1 *hpx1)
{ {
int i; int i;
union acpi_object *fields = record->package.elements; union acpi_object *fields = record->package.elements;
@ -162,11 +161,10 @@ static acpi_status decode_type1_hpx_record(union acpi_object *record,
for (i = 2; i < 5; i++) for (i = 2; i < 5; i++)
if (fields[i].type != ACPI_TYPE_INTEGER) if (fields[i].type != ACPI_TYPE_INTEGER)
return AE_ERROR; return AE_ERROR;
hpx->t1 = &hpx->type1_data; hpx1->revision = revision;
hpx->t1->revision = revision; hpx1->max_mem_read = fields[2].integer.value;
hpx->t1->max_mem_read = fields[2].integer.value; hpx1->avg_max_split = fields[3].integer.value;
hpx->t1->avg_max_split = fields[3].integer.value; hpx1->tot_max_split = fields[4].integer.value;
hpx->t1->tot_max_split = fields[4].integer.value;
break; break;
default: default:
printk(KERN_WARNING printk(KERN_WARNING
@ -178,7 +176,7 @@ static acpi_status decode_type1_hpx_record(union acpi_object *record,
} }
static acpi_status decode_type2_hpx_record(union acpi_object *record, static acpi_status decode_type2_hpx_record(union acpi_object *record,
struct hotplug_params *hpx) struct hpp_type2 *hpx2)
{ {
int i; int i;
union acpi_object *fields = record->package.elements; union acpi_object *fields = record->package.elements;
@ -191,24 +189,23 @@ static acpi_status decode_type2_hpx_record(union acpi_object *record,
for (i = 2; i < 18; i++) for (i = 2; i < 18; i++)
if (fields[i].type != ACPI_TYPE_INTEGER) if (fields[i].type != ACPI_TYPE_INTEGER)
return AE_ERROR; return AE_ERROR;
hpx->t2 = &hpx->type2_data; hpx2->revision = revision;
hpx->t2->revision = revision; hpx2->unc_err_mask_and = fields[2].integer.value;
hpx->t2->unc_err_mask_and = fields[2].integer.value; hpx2->unc_err_mask_or = fields[3].integer.value;
hpx->t2->unc_err_mask_or = fields[3].integer.value; hpx2->unc_err_sever_and = fields[4].integer.value;
hpx->t2->unc_err_sever_and = fields[4].integer.value; hpx2->unc_err_sever_or = fields[5].integer.value;
hpx->t2->unc_err_sever_or = fields[5].integer.value; hpx2->cor_err_mask_and = fields[6].integer.value;
hpx->t2->cor_err_mask_and = fields[6].integer.value; hpx2->cor_err_mask_or = fields[7].integer.value;
hpx->t2->cor_err_mask_or = fields[7].integer.value; hpx2->adv_err_cap_and = fields[8].integer.value;
hpx->t2->adv_err_cap_and = fields[8].integer.value; hpx2->adv_err_cap_or = fields[9].integer.value;
hpx->t2->adv_err_cap_or = fields[9].integer.value; hpx2->pci_exp_devctl_and = fields[10].integer.value;
hpx->t2->pci_exp_devctl_and = fields[10].integer.value; hpx2->pci_exp_devctl_or = fields[11].integer.value;
hpx->t2->pci_exp_devctl_or = fields[11].integer.value; hpx2->pci_exp_lnkctl_and = fields[12].integer.value;
hpx->t2->pci_exp_lnkctl_and = fields[12].integer.value; hpx2->pci_exp_lnkctl_or = fields[13].integer.value;
hpx->t2->pci_exp_lnkctl_or = fields[13].integer.value; hpx2->sec_unc_err_sever_and = fields[14].integer.value;
hpx->t2->sec_unc_err_sever_and = fields[14].integer.value; hpx2->sec_unc_err_sever_or = fields[15].integer.value;
hpx->t2->sec_unc_err_sever_or = fields[15].integer.value; hpx2->sec_unc_err_mask_and = fields[16].integer.value;
hpx->t2->sec_unc_err_mask_and = fields[16].integer.value; hpx2->sec_unc_err_mask_or = fields[17].integer.value;
hpx->t2->sec_unc_err_mask_or = fields[17].integer.value;
break; break;
default: default:
printk(KERN_WARNING printk(KERN_WARNING
@ -219,17 +216,76 @@ static acpi_status decode_type2_hpx_record(union acpi_object *record,
return AE_OK; return AE_OK;
} }
static acpi_status acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx) static void parse_hpx3_register(struct hpx_type3 *hpx3_reg,
union acpi_object *reg_fields)
{
hpx3_reg->device_type = reg_fields[0].integer.value;
hpx3_reg->function_type = reg_fields[1].integer.value;
hpx3_reg->config_space_location = reg_fields[2].integer.value;
hpx3_reg->pci_exp_cap_id = reg_fields[3].integer.value;
hpx3_reg->pci_exp_cap_ver = reg_fields[4].integer.value;
hpx3_reg->pci_exp_vendor_id = reg_fields[5].integer.value;
hpx3_reg->dvsec_id = reg_fields[6].integer.value;
hpx3_reg->dvsec_rev = reg_fields[7].integer.value;
hpx3_reg->match_offset = reg_fields[8].integer.value;
hpx3_reg->match_mask_and = reg_fields[9].integer.value;
hpx3_reg->match_value = reg_fields[10].integer.value;
hpx3_reg->reg_offset = reg_fields[11].integer.value;
hpx3_reg->reg_mask_and = reg_fields[12].integer.value;
hpx3_reg->reg_mask_or = reg_fields[13].integer.value;
}
static acpi_status program_type3_hpx_record(struct pci_dev *dev,
union acpi_object *record,
const struct hotplug_program_ops *hp_ops)
{
union acpi_object *fields = record->package.elements;
u32 desc_count, expected_length, revision;
union acpi_object *reg_fields;
struct hpx_type3 hpx3;
int i;
revision = fields[1].integer.value;
switch (revision) {
case 1:
desc_count = fields[2].integer.value;
expected_length = 3 + desc_count * 14;
if (record->package.count != expected_length)
return AE_ERROR;
for (i = 2; i < expected_length; i++)
if (fields[i].type != ACPI_TYPE_INTEGER)
return AE_ERROR;
for (i = 0; i < desc_count; i++) {
reg_fields = fields + 3 + i * 14;
parse_hpx3_register(&hpx3, reg_fields);
hp_ops->program_type3(dev, &hpx3);
}
break;
default:
printk(KERN_WARNING
"%s: Type 3 Revision %d record not supported\n",
__func__, revision);
return AE_ERROR;
}
return AE_OK;
}
static acpi_status acpi_run_hpx(struct pci_dev *dev, acpi_handle handle,
const struct hotplug_program_ops *hp_ops)
{ {
acpi_status status; acpi_status status;
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object *package, *record, *fields; union acpi_object *package, *record, *fields;
struct hpp_type0 hpx0;
struct hpp_type1 hpx1;
struct hpp_type2 hpx2;
u32 type; u32 type;
int i; int i;
/* Clear the return buffer with zeros */
memset(hpx, 0, sizeof(struct hotplug_params));
status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer); status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
return status; return status;
@ -257,17 +313,28 @@ static acpi_status acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx)
type = fields[0].integer.value; type = fields[0].integer.value;
switch (type) { switch (type) {
case 0: case 0:
status = decode_type0_hpx_record(record, hpx); memset(&hpx0, 0, sizeof(hpx0));
status = decode_type0_hpx_record(record, &hpx0);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
goto exit; goto exit;
hp_ops->program_type0(dev, &hpx0);
break; break;
case 1: case 1:
status = decode_type1_hpx_record(record, hpx); memset(&hpx1, 0, sizeof(hpx1));
status = decode_type1_hpx_record(record, &hpx1);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
goto exit; goto exit;
hp_ops->program_type1(dev, &hpx1);
break; break;
case 2: case 2:
status = decode_type2_hpx_record(record, hpx); memset(&hpx2, 0, sizeof(hpx2));
status = decode_type2_hpx_record(record, &hpx2);
if (ACPI_FAILURE(status))
goto exit;
hp_ops->program_type2(dev, &hpx2);
break;
case 3:
status = program_type3_hpx_record(dev, record, hp_ops);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
goto exit; goto exit;
break; break;
@ -283,14 +350,16 @@ static acpi_status acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx)
return status; return status;
} }
static acpi_status acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp) static acpi_status acpi_run_hpp(struct pci_dev *dev, acpi_handle handle,
const struct hotplug_program_ops *hp_ops)
{ {
acpi_status status; acpi_status status;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *package, *fields; union acpi_object *package, *fields;
struct hpp_type0 hpp0;
int i; int i;
memset(hpp, 0, sizeof(struct hotplug_params)); memset(&hpp0, 0, sizeof(hpp0));
status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer); status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status))
@ -311,12 +380,13 @@ static acpi_status acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
} }
} }
hpp->t0 = &hpp->type0_data; hpp0.revision = 1;
hpp->t0->revision = 1; hpp0.cache_line_size = fields[0].integer.value;
hpp->t0->cache_line_size = fields[0].integer.value; hpp0.latency_timer = fields[1].integer.value;
hpp->t0->latency_timer = fields[1].integer.value; hpp0.enable_serr = fields[2].integer.value;
hpp->t0->enable_serr = fields[2].integer.value; hpp0.enable_perr = fields[3].integer.value;
hpp->t0->enable_perr = fields[3].integer.value;
hp_ops->program_type0(dev, &hpp0);
exit: exit:
kfree(buffer.pointer); kfree(buffer.pointer);
@ -328,7 +398,8 @@ static acpi_status acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
* @dev - the pci_dev for which we want parameters * @dev - the pci_dev for which we want parameters
* @hpp - allocated by the caller * @hpp - allocated by the caller
*/ */
int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp) int pci_acpi_program_hp_params(struct pci_dev *dev,
const struct hotplug_program_ops *hp_ops)
{ {
acpi_status status; acpi_status status;
acpi_handle handle, phandle; acpi_handle handle, phandle;
@ -351,10 +422,10 @@ int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp)
* this pci dev. * this pci dev.
*/ */
while (handle) { while (handle) {
status = acpi_run_hpx(handle, hpp); status = acpi_run_hpx(dev, handle, hp_ops);
if (ACPI_SUCCESS(status)) if (ACPI_SUCCESS(status))
return 0; return 0;
status = acpi_run_hpp(handle, hpp); status = acpi_run_hpp(dev, handle, hp_ops);
if (ACPI_SUCCESS(status)) if (ACPI_SUCCESS(status))
return 0; return 0;
if (acpi_is_root_bridge(handle)) if (acpi_is_root_bridge(handle))
@ -366,7 +437,6 @@ int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp)
} }
return -ENODEV; return -ENODEV;
} }
EXPORT_SYMBOL_GPL(pci_get_hp_params);
/** /**
* pciehp_is_native - Check whether a hotplug port is handled by the OS * pciehp_is_native - Check whether a hotplug port is handled by the OS

View File

@ -2077,6 +2077,119 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
*/ */
} }
static u16 hpx3_device_type(struct pci_dev *dev)
{
u16 pcie_type = pci_pcie_type(dev);
const int pcie_to_hpx3_type[] = {
[PCI_EXP_TYPE_ENDPOINT] = HPX_TYPE_ENDPOINT,
[PCI_EXP_TYPE_LEG_END] = HPX_TYPE_LEG_END,
[PCI_EXP_TYPE_RC_END] = HPX_TYPE_RC_END,
[PCI_EXP_TYPE_RC_EC] = HPX_TYPE_RC_EC,
[PCI_EXP_TYPE_ROOT_PORT] = HPX_TYPE_ROOT_PORT,
[PCI_EXP_TYPE_UPSTREAM] = HPX_TYPE_UPSTREAM,
[PCI_EXP_TYPE_DOWNSTREAM] = HPX_TYPE_DOWNSTREAM,
[PCI_EXP_TYPE_PCI_BRIDGE] = HPX_TYPE_PCI_BRIDGE,
[PCI_EXP_TYPE_PCIE_BRIDGE] = HPX_TYPE_PCIE_BRIDGE,
};
if (pcie_type >= ARRAY_SIZE(pcie_to_hpx3_type))
return 0;
return pcie_to_hpx3_type[pcie_type];
}
static u8 hpx3_function_type(struct pci_dev *dev)
{
if (dev->is_virtfn)
return HPX_FN_SRIOV_VIRT;
else if (pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV) > 0)
return HPX_FN_SRIOV_PHYS;
else
return HPX_FN_NORMAL;
}
static bool hpx3_cap_ver_matches(u8 pcie_cap_id, u8 hpx3_cap_id)
{
u8 cap_ver = hpx3_cap_id & 0xf;
if ((hpx3_cap_id & BIT(4)) && cap_ver >= pcie_cap_id)
return true;
else if (cap_ver == pcie_cap_id)
return true;
return false;
}
static void program_hpx_type3_register(struct pci_dev *dev,
const struct hpx_type3 *reg)
{
u32 match_reg, write_reg, header, orig_value;
u16 pos;
if (!(hpx3_device_type(dev) & reg->device_type))
return;
if (!(hpx3_function_type(dev) & reg->function_type))
return;
switch (reg->config_space_location) {
case HPX_CFG_PCICFG:
pos = 0;
break;
case HPX_CFG_PCIE_CAP:
pos = pci_find_capability(dev, reg->pci_exp_cap_id);
if (pos == 0)
return;
break;
case HPX_CFG_PCIE_CAP_EXT:
pos = pci_find_ext_capability(dev, reg->pci_exp_cap_id);
if (pos == 0)
return;
pci_read_config_dword(dev, pos, &header);
if (!hpx3_cap_ver_matches(PCI_EXT_CAP_VER(header),
reg->pci_exp_cap_ver))
return;
break;
case HPX_CFG_VEND_CAP: /* Fall through */
case HPX_CFG_DVSEC: /* Fall through */
default:
pci_warn(dev, "Encountered _HPX type 3 with unsupported config space location");
return;
}
pci_read_config_dword(dev, pos + reg->match_offset, &match_reg);
if ((match_reg & reg->match_mask_and) != reg->match_value)
return;
pci_read_config_dword(dev, pos + reg->reg_offset, &write_reg);
orig_value = write_reg;
write_reg &= reg->reg_mask_and;
write_reg |= reg->reg_mask_or;
if (orig_value == write_reg)
return;
pci_write_config_dword(dev, pos + reg->reg_offset, write_reg);
pci_dbg(dev, "Applied _HPX3 at [0x%x]: 0x%08x -> 0x%08x",
pos, orig_value, write_reg);
}
static void program_hpx_type3(struct pci_dev *dev, struct hpx_type3 *hpx3)
{
if (!hpx3)
return;
if (!pci_is_pcie(dev))
return;
program_hpx_type3_register(dev, hpx3);
}
int pci_configure_extended_tags(struct pci_dev *dev, void *ign) int pci_configure_extended_tags(struct pci_dev *dev, void *ign)
{ {
struct pci_host_bridge *host; struct pci_host_bridge *host;
@ -2257,8 +2370,12 @@ static void pci_configure_serr(struct pci_dev *dev)
static void pci_configure_device(struct pci_dev *dev) static void pci_configure_device(struct pci_dev *dev)
{ {
struct hotplug_params hpp; static const struct hotplug_program_ops hp_ops = {
int ret; .program_type0 = program_hpp_type0,
.program_type1 = program_hpp_type1,
.program_type2 = program_hpp_type2,
.program_type3 = program_hpx_type3,
};
pci_configure_mps(dev); pci_configure_mps(dev);
pci_configure_extended_tags(dev, NULL); pci_configure_extended_tags(dev, NULL);
@ -2267,14 +2384,7 @@ static void pci_configure_device(struct pci_dev *dev)
pci_configure_eetlp_prefix(dev); pci_configure_eetlp_prefix(dev);
pci_configure_serr(dev); pci_configure_serr(dev);
memset(&hpp, 0, sizeof(hpp)); pci_acpi_program_hp_params(dev, &hp_ops);
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)

View File

@ -513,7 +513,8 @@ extern bool osc_pc_lpi_support_confirmed;
#define OSC_PCI_CLOCK_PM_SUPPORT 0x00000004 #define OSC_PCI_CLOCK_PM_SUPPORT 0x00000004
#define OSC_PCI_SEGMENT_GROUPS_SUPPORT 0x00000008 #define OSC_PCI_SEGMENT_GROUPS_SUPPORT 0x00000008
#define OSC_PCI_MSI_SUPPORT 0x00000010 #define OSC_PCI_MSI_SUPPORT 0x00000010
#define OSC_PCI_SUPPORT_MASKS 0x0000001f #define OSC_PCI_HPX_TYPE_3_SUPPORT 0x00000100
#define OSC_PCI_SUPPORT_MASKS 0x0000011f
/* PCI Host Bridge _OSC: Capabilities DWORD 3: Control Field */ /* PCI Host Bridge _OSC: Capabilities DWORD 3: Control Field */
#define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL 0x00000001 #define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL 0x00000001

View File

@ -124,26 +124,72 @@ struct hpp_type2 {
u32 sec_unc_err_mask_or; u32 sec_unc_err_mask_or;
}; };
struct hotplug_params { /*
struct hpp_type0 *t0; /* Type0: NULL if not available */ * _HPX PCI Express Setting Record (Type 3)
struct hpp_type1 *t1; /* Type1: NULL if not available */ */
struct hpp_type2 *t2; /* Type2: NULL if not available */ struct hpx_type3 {
struct hpp_type0 type0_data; u16 device_type;
struct hpp_type1 type1_data; u16 function_type;
struct hpp_type2 type2_data; u16 config_space_location;
u16 pci_exp_cap_id;
u16 pci_exp_cap_ver;
u16 pci_exp_vendor_id;
u16 dvsec_id;
u16 dvsec_rev;
u16 match_offset;
u32 match_mask_and;
u32 match_value;
u16 reg_offset;
u32 reg_mask_and;
u32 reg_mask_or;
};
struct hotplug_program_ops {
void (*program_type0)(struct pci_dev *dev, struct hpp_type0 *hpp);
void (*program_type1)(struct pci_dev *dev, struct hpp_type1 *hpp);
void (*program_type2)(struct pci_dev *dev, struct hpp_type2 *hpp);
void (*program_type3)(struct pci_dev *dev, struct hpx_type3 *hpp);
};
enum hpx_type3_dev_type {
HPX_TYPE_ENDPOINT = BIT(0),
HPX_TYPE_LEG_END = BIT(1),
HPX_TYPE_RC_END = BIT(2),
HPX_TYPE_RC_EC = BIT(3),
HPX_TYPE_ROOT_PORT = BIT(4),
HPX_TYPE_UPSTREAM = BIT(5),
HPX_TYPE_DOWNSTREAM = BIT(6),
HPX_TYPE_PCI_BRIDGE = BIT(7),
HPX_TYPE_PCIE_BRIDGE = BIT(8),
};
enum hpx_type3_fn_type {
HPX_FN_NORMAL = BIT(0),
HPX_FN_SRIOV_PHYS = BIT(1),
HPX_FN_SRIOV_VIRT = BIT(2),
};
enum hpx_type3_cfg_loc {
HPX_CFG_PCICFG = 0,
HPX_CFG_PCIE_CAP = 1,
HPX_CFG_PCIE_CAP_EXT = 2,
HPX_CFG_VEND_CAP = 3,
HPX_CFG_DVSEC = 4,
HPX_CFG_MAX,
}; };
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
#include <linux/acpi.h> #include <linux/acpi.h>
int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp); int pci_acpi_program_hp_params(struct pci_dev *dev,
const struct hotplug_program_ops *hp_ops);
bool pciehp_is_native(struct pci_dev *bridge); bool pciehp_is_native(struct pci_dev *bridge);
int acpi_get_hp_hw_control_from_firmware(struct pci_dev *bridge); int acpi_get_hp_hw_control_from_firmware(struct pci_dev *bridge);
bool shpchp_is_native(struct pci_dev *bridge); bool shpchp_is_native(struct pci_dev *bridge);
int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle); int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle);
int acpi_pci_detect_ejectable(acpi_handle handle); int acpi_pci_detect_ejectable(acpi_handle handle);
#else #else
static inline int pci_get_hp_params(struct pci_dev *dev, static inline int pci_acpi_program_hp_params(struct pci_dev *dev,
struct hotplug_params *hpp) const struct hotplug_program_ops *hp_ops)
{ {
return -ENODEV; return -ENODEV;
} }