From: "Sean O. Stalley" <sean.stalley-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
To: bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org,
rajatxjain-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
mst-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org,
zajec5-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
gong.chen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org,
linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: sean.stalley-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org
Subject: [PATCH 2/2] PCI: Add support for Enhanced Allocation devices
Date: Thu, 20 Aug 2015 09:59:07 -0700 [thread overview]
Message-ID: <1440089947-2839-3-git-send-email-sean.stalley@intel.com> (raw)
In-Reply-To: <1440089947-2839-1-git-send-email-sean.stalley-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
Add support for devices using Enhanced Allocation entries instead of BARs.
This patch allows the kernel to parse the EA Extended Capability structure
in PCI configspace and claim the BAR-equivalent resources.
Signed-off-by: Sean O. Stalley <sean.stalley-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
drivers/pci/pci.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++
drivers/pci/pci.h | 1 +
drivers/pci/probe.c | 3 +
3 files changed, 223 insertions(+)
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 0008c95..c8217a8 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -2134,6 +2134,225 @@ void pci_pm_init(struct pci_dev *dev)
}
}
+static unsigned long pci_ea_set_flags(struct pci_dev *dev, u8 prop)
+{
+ unsigned long flags = IORESOURCE_PCI_FIXED;
+
+ switch (prop) {
+ case PCI_EA_P_MEM:
+ flags |= IORESOURCE_MEM;
+ break;
+ case PCI_EA_P_MEM_PREFETCH:
+ flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
+ break;
+ case PCI_EA_P_IO:
+ flags |= IORESOURCE_IO;
+ break;
+ default:
+ dev_warn(&dev->dev, "%s: Property type %x not supported\n",
+ __func__, prop);
+ return 0;
+ }
+
+ return flags;
+}
+
+static struct resource *pci_ea_get_parent_resource(struct pci_dev *dev,
+ struct resource *res)
+{
+ struct resource *parent;
+
+ parent = pci_find_parent_resource(dev, res);
+ if (parent)
+ return parent;
+
+ /* for resources not claimed by a bridge */
+ if (res->flags & IORESOURCE_MEM)
+ return &iomem_resource;
+
+ if (res->flags & IORESOURCE_IO)
+ return &ioport_resource;
+
+ return NULL;
+}
+
+/* claim the memory for this device in the proper location */
+static void pci_ea_claim_resource(struct pci_dev *dev, struct resource *res)
+{
+ struct resource *parent;
+ struct resource *conflict;
+
+ parent = pci_ea_get_parent_resource(dev, res);
+ if (!parent) {
+ dev_warn(&dev->dev, "can't find parent resource for EA entry %s %pR\n",
+ res->name, res);
+ return;
+ }
+
+ /* claim the appropriate resource */
+ conflict = request_resource_conflict(parent, res);
+ if (conflict) {
+ dev_warn(&dev->dev, "can't claim EA entry %s %pR: address conflict with %s %pR\n",
+ res->name, res, conflict->name, conflict);
+ }
+}
+
+static struct resource *pci_ea_get_resource(struct pci_dev *dev, u8 bei)
+{
+ if (bei <= PCI_STD_RESOURCE_END)
+ return &dev->resource[bei];
+ else if (bei == PCI_EA_BEI_ROM)
+ return &dev->resource[PCI_ROM_RESOURCE];
+ else
+ return NULL;
+}
+
+/* Read an Enhanced Allocation (EA) entry */
+static int pci_ea_read(struct pci_dev *dev, int offset)
+{
+ struct resource *res;
+ int ent_offset = offset;
+ int ent_size;
+ resource_size_t start;
+ resource_size_t end;
+ unsigned long flags;
+ u32 dw0;
+ u32 base;
+ u32 max_offset;
+ bool support_64 = (sizeof(resource_size_t) >= 8);
+
+ pci_read_config_dword(dev, ent_offset, &dw0);
+ ent_offset += 4;
+
+ /* Entry size field indicates DWORDs after 1st */
+ ent_size = ((dw0 & PCI_EA_ES) + 1) << 2;
+
+ if (!(dw0 & PCI_EA_ENABLE)) {
+ dev_err(&dev->dev, "%s: Entry not enabled\n", __func__);
+ goto out;
+ }
+
+ res = pci_ea_get_resource(dev, PCI_EA_BEI(dw0));
+ if (!res) {
+ dev_err(&dev->dev, "%s: Unsupported EA entry BEI\n", __func__);
+ goto out;
+ }
+
+ flags = pci_ea_set_flags(dev, PCI_EA_PP(dw0));
+ if (!flags)
+ flags = pci_ea_set_flags(dev, PCI_EA_SP(dw0));
+ if (!flags) {
+ dev_err(&dev->dev, "%s: Entry EA properties not supported\n",
+ __func__);
+ goto out;
+ }
+
+ /* Read Base */
+ pci_read_config_dword(dev, ent_offset, &base);
+ start = (base & PCI_EA_FIELD_MASK);
+ ent_offset += 4;
+
+ /* Read MaxOffset */
+ pci_read_config_dword(dev, ent_offset, &max_offset);
+ ent_offset += 4;
+
+ /* Read Base MSBs (if 64-bit entry) */
+ if (base & PCI_EA_IS_64) {
+ u32 base_upper;
+
+ pci_read_config_dword(dev, ent_offset, &base_upper);
+ ent_offset += 4;
+
+ flags |= IORESOURCE_MEM_64;
+
+ /* entry starts above 32-bit boundary, can't use */
+ if (!support_64 && base_upper)
+ goto out;
+
+ if (support_64)
+ start |= ((u64)base_upper << 32);
+ }
+
+ dev_dbg(&dev->dev, "%s: start = %pa\n", __func__, &start);
+
+ end = start + (max_offset | 0x03);
+
+ /* Read MaxOffset MSBs (if 64-bit entry) */
+ if (max_offset & PCI_EA_IS_64) {
+ u32 max_offset_upper;
+
+ pci_read_config_dword(dev, ent_offset, &max_offset_upper);
+ ent_offset += 4;
+
+ flags |= IORESOURCE_MEM_64;
+
+ /* entry too big, can't use */
+ if (!support_64 && max_offset_upper)
+ goto out;
+
+ if (support_64)
+ end += ((u64)max_offset_upper << 32);
+ }
+
+ dev_dbg(&dev->dev, "%s: end = %pa\n", __func__, &end);
+
+ if (end < start) {
+ dev_err(&dev->dev, "EA Entry crosses address boundary\n");
+ goto out;
+ }
+
+ if (ent_size != ent_offset - offset) {
+ dev_err(&dev->dev, "EA entry size does not match length read\n"
+ "(Entry Size:%u Length Read:%u)\n",
+ ent_size, ent_offset - offset);
+ goto out;
+ }
+
+ res->name = pci_name(dev);
+ res->start = start;
+ res->end = end;
+ res->flags = flags;
+
+ pci_ea_claim_resource(dev, res);
+
+out:
+ return offset + ent_size;
+}
+
+/* Enhanced Allocation Initalization */
+void pci_ea_init(struct pci_dev *dev)
+{
+ int ea;
+ u8 num_ent;
+ int offset;
+ int i;
+
+ /* find PCI EA capability in list */
+ ea = pci_find_capability(dev, PCI_CAP_ID_EA);
+ if (!ea)
+ return;
+
+ dev_dbg(&dev->dev, "%s: capability found!\n", __func__);
+
+ /* determine the number of entries */
+ pci_bus_read_config_byte(dev->bus, dev->devfn, ea + PCI_EA_NUM_ENT,
+ &num_ent);
+ num_ent &= PCI_EA_NUM_ENT_MASK;
+
+ offset = ea + PCI_EA_FIRST_ENT;
+
+ /* Skip DWORD 2 for type 1 functions */
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)
+ offset += 4;
+ /* TODO: Support fixed bus numbers */
+
+ for (i = 0; i < num_ent; ++i) {
+ /* parse each EA entry */
+ dev_dbg(&dev->dev, "%s: parsing entry %i...\n", __func__, i);
+ offset = pci_ea_read(dev, offset);
+ }
+}
+
static void pci_add_saved_cap(struct pci_dev *pci_dev,
struct pci_cap_saved_state *new_cap)
{
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4ff0ff1..92fbef0 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -76,6 +76,7 @@ bool pci_dev_keep_suspended(struct pci_dev *dev);
void pci_config_pm_runtime_get(struct pci_dev *dev);
void pci_config_pm_runtime_put(struct pci_dev *dev);
void pci_pm_init(struct pci_dev *dev);
+void pci_ea_init(struct pci_dev *dev);
void pci_allocate_cap_save_buffers(struct pci_dev *dev);
void pci_free_cap_save_buffers(struct pci_dev *dev);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index cefd636..4cadf35 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1522,6 +1522,9 @@ static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
static void pci_init_capabilities(struct pci_dev *dev)
{
+ /* Enhanced Allocation */
+ pci_ea_init(dev);
+
/* MSI/MSI-X list */
pci_msi_init_pci_dev(dev);
--
1.9.1
next prev parent reply other threads:[~2015-08-20 16:59 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-08-20 16:59 [PATCH 0/2] PCI: Add support for PCI Enhanced Allocation "BARs" Sean O. Stalley
2015-08-20 16:59 ` [PATCH 1/2] PCI: Add Enhanced Allocation register entries Sean O. Stalley
[not found] ` <1440089947-2839-1-git-send-email-sean.stalley-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2015-08-20 16:59 ` Sean O. Stalley [this message]
2015-09-01 23:14 ` [PATCH 2/2] PCI: Add support for Enhanced Allocation devices Yinghai Lu
[not found] ` <CAE9FiQUQacSJXPqv9GQJ4AF0TN7uxcBiAYHVbHwvFhEfWgWKHg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-09-02 17:46 ` Sean O. Stalley
[not found] ` <20150902174612.GA2700-KQ5zpJUXklQTH34CoL1+91DQ4js95KgL@public.gmane.org>
2015-09-02 19:25 ` Bjorn Helgaas
2015-09-02 20:01 ` Sean O. Stalley
[not found] ` <20150902200127.GA3347-KQ5zpJUXklQTH34CoL1+91DQ4js95KgL@public.gmane.org>
2015-09-02 21:21 ` Bjorn Helgaas
[not found] ` <20150902212159.GC829-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
2015-09-03 0:29 ` Sean O. Stalley
2015-09-03 14:46 ` Bjorn Helgaas
[not found] ` <20150903144654.GF829-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org>
2015-09-03 18:23 ` Sean O. Stalley
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=1440089947-2839-3-git-send-email-sean.stalley@intel.com \
--to=sean.stalley-ral2jqcrhueavxtiumwx3w@public.gmane.org \
--cc=bhelgaas-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org \
--cc=gong.chen-VuQAYsv1563Yd54FQh9/CA@public.gmane.org \
--cc=linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=linux-pci-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=mst-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org \
--cc=rajatxjain-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
--cc=zajec5-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
/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).