linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Alexandru Gagniuc <mr.nuke.me@gmail.com>
To: bhelgaas@google.com
Cc: austin_bolen@dell.com, alex_gagniuc@dellteam.com,
	keith.busch@intel.com, Shyam_Iyer@Dell.com, lukas@wunner.de,
	okaya@kernel.org, Alexandru Gagniuc <mr.nuke.me@gmail.com>,
	"Rafael J. Wysocki" <rjw@rjwysocki.net>,
	Len Brown <lenb@kernel.org>,
	linux-acpi@vger.kernel.org, linux-pci@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [RFC] PCI / ACPI: Implementing Type 3 _HPX records
Date: Thu, 10 Jan 2019 17:11:27 -0600	[thread overview]
Message-ID: <20190110231136.31163-1-mr.nuke.me@gmail.com> (raw)

_HPX Type 3 is intended to be more generic and allow configuration of
settings not possible with Type 2 tables. For example, FW could ensure
that the completion timeout value is set accordingly throughout the PCI
tree; some switches require very special handling.

Type 3 can come in an arbitrary number of ACPI packages. With the older
types we only ever had one descriptor. We could get lazy and store it
on the stack. The current flow is to parse the HPX table
--pci_get_hp_params()-- and then program the PCIe device registers.

In the current flow, we'll need to malloc(). Here's what I tried:
 1) devm_kmalloc() on the pci_dev
  This ended up giving me NULL dereference at boot time.
 2) Add a cleanup function to be called after writing the PCIe registers

This RFC implements method 2. The HPX3 stuff is still NDA'd, but the
housekeeping parts are in here. Is this a good way to do things? I'm not
too sure about the need to call cleanup() on a stack variable. But if
not that, then what else?

Alex

---
 drivers/pci/pci-acpi.c      | 88 +++++++++++++++++++++++++++++++++++++
 drivers/pci/probe.c         | 29 ++++++++++++
 include/linux/pci_hotplug.h | 17 +++++++
 3 files changed, 134 insertions(+)

diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index e1949f7efd9c..2ce1b68ce688 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -219,6 +219,65 @@ static acpi_status decode_type2_hpx_record(union acpi_object *record,
 	return AE_OK;
 }
 
+static acpi_status parse_hpx3_register(struct hpp_type3 *hpx3,
+				       union acpi_object *reg_fields)
+{
+	struct hpp_type3_register *hpx3_reg;
+
+	hpx3_reg = kzalloc(sizeof(*hpx3_reg), GFP_KERNEL);
+	if (!hpx3_reg)
+		return AE_NO_MEMORY;
+
+	/* Parse fields blurb */
+
+	list_add_tail(&hpx3_reg->list, &hpx3->regs);
+	return AE_OK;
+}
+
+static acpi_status decode_type3_hpx_record(union acpi_object *record,
+					   struct hotplug_params *hpx)
+{
+	union acpi_object *fields = record->package.elements;
+	u32 desc_count, expected_length, revision;
+	union acpi_object *reg_fields;
+	acpi_status ret;
+	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;
+
+		if (!hpx->t3) {
+			INIT_LIST_HEAD(&hpx->type3_data.regs);
+			hpx->t3 = &hpx->type3_data;
+		}
+
+		for (i = 0; i < desc_count; i++) {
+			reg_fields = fields + 3 + i * 14;
+			ret = parse_hpx3_register(hpx->t3, reg_fields);
+			if (ret != AE_OK)
+				return ret;
+		}
+
+		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(acpi_handle handle, struct hotplug_params *hpx)
 {
 	acpi_status status;
@@ -271,6 +330,11 @@ static acpi_status acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx)
 			if (ACPI_FAILURE(status))
 				goto exit;
 			break;
+		case 3:
+			status = decode_type3_hpx_record(record, hpx);
+			if (ACPI_FAILURE(status))
+				goto exit;
+			break;
 		default:
 			printk(KERN_ERR "%s: Type %d record not supported\n",
 			       __func__, type);
@@ -368,6 +432,30 @@ int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp)
 }
 EXPORT_SYMBOL_GPL(pci_get_hp_params);
 
+static int cleantup_type3_hpx_record(struct hpp_type3 *hpx3)
+{
+	struct hpp_type3_register *reg;
+	struct list_head *entry, *temp;
+
+	list_for_each_safe(entry, temp, &hpp->t3->regs){
+		reg = list_entry(entry, typeof(*reg), list);
+		list_del(entry);
+		kfree(reg);
+	}
+}
+
+/* pci_cleanup_hp_params
+ *
+ * @hpp - allocated by the caller
+ */
+void pci_cleanup_hp_params(struct hotplug_params *hpp)
+{
+
+	if (hpp->t3)
+		cleanup_type3_hpx_record(hpp->t3);
+}
+EXPORT_SYMBOL_GPL(pci_cleanup_hp_params);
+
 /**
  * pciehp_is_native - Check whether a hotplug port is handled by the OS
  * @bridge: Hotplug port to check
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 257b9f6f2ebb..35ef7d1f4f3b 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1979,6 +1979,32 @@ static void program_hpp_type2(struct pci_dev *dev, struct hpp_type2 *hpp)
 	 */
 }
 
+static void program_hpp_type3_register(struct pci_dev *dev,
+				       const struct hpp_type3_register *reg)
+{
+	/* Complicated ACPI-mandated blurb */
+}
+
+static void program_hpp_type3(struct pci_dev *dev, struct hpp_type3 *hpp)
+{
+	struct hpp_type3_register *reg;
+
+	if (!hpp)
+		return;
+
+	if (!pci_is_pcie(dev))
+		return;
+
+	if (hpp->revision > 1) {
+		pci_warn(dev, "PCIe settings rev %d not supported\n",
+			 hpp->revision);
+		return;
+	}
+
+	list_for_each_entry(reg, &hpp->regs, list)
+		program_hpp_type3_register(dev, reg);
+}
+
 int pci_configure_extended_tags(struct pci_dev *dev, void *ign)
 {
 	struct pci_host_bridge *host;
@@ -2145,9 +2171,12 @@ static void pci_configure_device(struct pci_dev *dev)
 	if (ret)
 		return;
 
+	program_hpp_type3(dev, hpp.t3);
 	program_hpp_type2(dev, hpp.t2);
 	program_hpp_type1(dev, hpp.t1);
 	program_hpp_type0(dev, hpp.t0);
+
+	pci_cleanup_hp_params(&hpp);
 }
 
 static void pci_release_capabilities(struct pci_dev *dev)
diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h
index 7acc9f91e72b..479da87a3774 100644
--- a/include/linux/pci_hotplug.h
+++ b/include/linux/pci_hotplug.h
@@ -124,18 +124,35 @@ struct hpp_type2 {
 	u32 sec_unc_err_mask_or;
 };
 
+/*
+ * PCI Express Setting Record (Type 3)
+ * The ACPI overlords can never get enough
+ */
+struct hpp_type3_register {
+	u32 crap_describing_entry_contents;
+	struct list_head list;
+};
+
+struct hpp_type3 {
+	u32 revision;
+	struct list_head regs;
+};
+
 struct hotplug_params {
 	struct hpp_type0 *t0;		/* Type0: NULL if not available */
 	struct hpp_type1 *t1;		/* Type1: NULL if not available */
 	struct hpp_type2 *t2;		/* Type2: NULL if not available */
+	struct hpp_type3 *t3;		/* Type3: NULL if not available */
 	struct hpp_type0 type0_data;
 	struct hpp_type1 type1_data;
 	struct hpp_type2 type2_data;
+	struct hpp_type3 type3_data;
 };
 
 #ifdef CONFIG_ACPI
 #include <linux/acpi.h>
 int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp);
+void pci_cleanup_hp_params(struct hotplug_params *hpp);
 bool pciehp_is_native(struct pci_dev *bridge);
 int acpi_get_hp_hw_control_from_firmware(struct pci_dev *bridge);
 bool shpchp_is_native(struct pci_dev *bridge);
-- 
2.19.2


             reply	other threads:[~2019-01-10 23:11 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-01-10 23:11 Alexandru Gagniuc [this message]
2019-01-14 20:01 ` [RFC] PCI / ACPI: Implementing Type 3 _HPX records Bjorn Helgaas
2019-01-17 19:02   ` Alex_Gagniuc
2019-01-21 17:42   ` [RFC v2] " Alexandru Gagniuc

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190110231136.31163-1-mr.nuke.me@gmail.com \
    --to=mr.nuke.me@gmail.com \
    --cc=Shyam_Iyer@Dell.com \
    --cc=alex_gagniuc@dellteam.com \
    --cc=austin_bolen@dell.com \
    --cc=bhelgaas@google.com \
    --cc=keith.busch@intel.com \
    --cc=lenb@kernel.org \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pci@vger.kernel.org \
    --cc=lukas@wunner.de \
    --cc=okaya@kernel.org \
    --cc=rjw@rjwysocki.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).