2013-04-12 22:44:52

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 00/29] PCI: Add for_each_pci_resource and addon_res support

First part is for_each_pci_resource support:
Now pci device resource iteration is done via "for (i=0...)" open code.
That make code hard to read esp when only bridge or sriov resources
are involved.

We want to replace those open code with for_each_pci_resource() to make
the code more readable.
Also will add addon_resource handling, and need to make addon resource
to be treated as normal PCI resources during iteration, add
for_each_pci_resource will make that support transition more simple.

To make for_each_pci_resource more efficient. We will use preset bitmap
of different type for searching next idx.

Second part is addon_res support:
Now there is some non normal pci resources other than standard,rom,
sriov, bridges.
Some could be same as standard reg, but using different position.
Some could have own way to read/write to them.
Kernel are using different way to hack those resources like abusing
pci bridge resource spot on non bridge pci device.

Add addon_resources list in pci_dev for those non-standard resources.
With this patch, will treat addon-resource like standard resources with
special ops.

At last replace some quirk_io with addon_res.

could get from
git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-pci-for-each-res-addon

-v4: split one patch out, and remove PCI_NO_....

Notes: We still need to keep _idx as we use it all the time, and drivers still
use them to get resource.

Thanks

Yinghai Lu


Ram Pai (1):
PCI: pci resource iterator

Yinghai Lu (28):
PCI: Clean up quirk_io_region
PCI: Add pci_dev_resource_n()
PCI: Update pci_resource_start etc to use pci_dev_resource_n()
PCI: Add pci_dev_resource_idx() helper
PCI: Add is_pci_*_resource_idx() helpers
PCI, x86: Use for_each_pci_resource() with
pci_allocate_bridge_resources
PCI, x86: Use for_each_pci_resource() with pci_allocate_dev_resources
PCI: Use for_each_pci_resource() with IOV releated functions
PCI, acpiphp: Use for_each_pci_resource() helper
PCI, pciehp: Use for_each_pci_resource() helper
PCI: Use for_each_pci_resource() in pci_enable_dev
PCI: Use for_each_pci_resource() in pci_reassigndev
PCI: Use for_each_pci_resource() with pci bar reassign funcs
PCI: Use for_each_pci_resource() in pci_assign_resource
PCI, x86: Use for_each_pci_resource() with noassign_bars
PCI: Use for_each_pci_resource() in pci_dev_driver()
PCI: Use for_each_pci_resource() in pci resource release
PCI: Use for_each_pci_resource() in pci bases reading
PCI, x86: Use for_each_pci_resource() with mrst
PCI, xen: Use for_each_pci_resource() with xen pci
PCI: Add addon_resource support for pci devices
PCI: Treat addon res as std resources
PCI: Add helpers to add addon_resource
PCI: Update pci_resource_bar() to support addon_resource
PCI: Assign/update resource to addon_res
PCI: Make piix4 quirk to use addon_res
PCI: Make quirk_io_region to use addon_res
PCI: Use addon_fixed_resource with ati fixed resource

arch/x86/pci/common.c | 3 +-
arch/x86/pci/i386.c | 58 +++------
arch/x86/pci/mrst.c | 7 +-
drivers/pci/hotplug/acpiphp_glue.c | 4 +-
drivers/pci/hotplug/pciehp_hpc.c | 5 +-
drivers/pci/iov.c | 31 +++--
drivers/pci/pci-driver.c | 7 +-
drivers/pci/pci.c | 27 ++--
drivers/pci/probe.c | 176 ++++++++++++++++++++++++-
drivers/pci/quirks.c | 258 ++++++++++++++++++++++---------------
drivers/pci/remove.c | 5 +-
drivers/pci/setup-bus.c | 28 ++--
drivers/pci/setup-res.c | 38 ++++--
drivers/pci/xen-pcifront.c | 4 +-
include/linux/pci.h | 116 +++++++++++++++--
15 files changed, 541 insertions(+), 226 deletions(-)

--
1.8.1.4


2013-04-12 22:45:10

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 23/29] PCI: Treat addon res as std resources

Replace PCI_STD_... with PCI_STD..._ADDON_... in the loop
of for_each_pci_resource.

Signed-off-by: Yinghai Lu <[email protected]>
---
arch/x86/pci/i386.c | 2 +-
drivers/pci/hotplug/acpiphp_glue.c | 2 +-
drivers/pci/pci-driver.c | 3 ++-
drivers/pci/pci.c | 6 +++---
4 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 4dafa08..a3a7e89 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -240,7 +240,7 @@ static void pcibios_allocate_dev_resources(struct pci_dev *dev, int pass)
struct resource *r;

pci_read_config_word(dev, PCI_COMMAND, &command);
- for_each_pci_resource(dev, r, idx, PCI_STD_IOV_RES) {
+ for_each_pci_resource(dev, r, idx, PCI_STD_IOV_ADDON_RES) {
if (r->parent) /* Already allocated */
continue;
if (!r->start) /* Address not assigned at all */
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index c35b2b1..702871c 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -1088,7 +1088,7 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
struct resource *res;

list_for_each_entry(dev, &bus->devices, bus_list) {
- for_each_pci_resource(dev, res, i, PCI_STD_ROM_IOV_RES) {
+ for_each_pci_resource(dev, res, i, PCI_STD_ROM_IOV_ADDON_RES) {
if ((res->flags & type_mask) && !res->start &&
res->end) {
/* Could not assign a required resources
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 009f6c2..73238a8 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -1173,7 +1173,8 @@ pci_dev_driver(const struct pci_dev *dev)
struct resource *res;
int i;

- for_each_pci_resource((struct pci_dev *)dev, res, i, PCI_STD_ROM_RES)
+ for_each_pci_resource((struct pci_dev *)dev, res, i,
+ PCI_STD_ROM_ADDON_RES)
if (res->flags & IORESOURCE_BUSY)
return &pci_compat_driver;
}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index d6203e9..c1010be 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -442,7 +442,7 @@ pci_restore_bars(struct pci_dev *dev)
int i;
struct resource *res;

- for_each_pci_resource(dev, res, i, PCI_STD_ROM_IOV_RES)
+ for_each_pci_resource(dev, res, i, PCI_STD_ROM_IOV_ADDON_RES)
pci_update_resource(dev, i);
}

@@ -1172,7 +1172,7 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
return 0; /* already enabled */

/* only skip sriov related */
- for_each_pci_resource(dev, res, i, PCI_STD_ROM_BRIDGE_RES) {
+ for_each_pci_resource(dev, res, i, PCI_STD_ROM_BRIDGE_ADDON_RES) {
/* TODO: check i with bits of bars */
if (res->flags & flags)
bars |= (1 << i);
@@ -3782,7 +3782,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
command &= ~PCI_COMMAND_MEMORY;
pci_write_config_word(dev, PCI_COMMAND, command);

- for_each_pci_resource(dev, r, i, PCI_STD_ROM_IOV_RES) {
+ for_each_pci_resource(dev, r, i, PCI_STD_ROM_IOV_ADDON_RES) {
r = &dev->resource[i];
if (!(r->flags & IORESOURCE_MEM))
continue;
--
1.8.1.4

2013-04-12 22:45:14

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 11/29] PCI, pciehp: Use for_each_pci_resource() helper

Signed-off-by: Yinghai Lu <[email protected]>
Cc: Kenji Kaneshige <[email protected]>
Cc: Yijing Wang <[email protected]>
---
drivers/pci/hotplug/pciehp_hpc.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 5127f3f..2df1ae3 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -807,6 +807,7 @@ static inline void dbg_ctrl(struct controller *ctrl)
int i;
u16 reg16;
struct pci_dev *pdev = ctrl->pcie->port;
+ struct resource *res;

if (!pciehp_debug)
return;
@@ -822,11 +823,11 @@ static inline void dbg_ctrl(struct controller *ctrl)
pdev->subsystem_vendor);
ctrl_info(ctrl, " PCIe Cap offset : 0x%02x\n",
pci_pcie_cap(pdev));
- for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ for_each_pci_resource(pdev, res, i, PCI_ALL_RES) {
if (!pci_resource_len(pdev, i))
continue;
ctrl_info(ctrl, " PCI resource [%d] : %pR\n",
- i, &pdev->resource[i]);
+ i, res);
}
ctrl_info(ctrl, "Slot Capabilities : 0x%08x\n", ctrl->slot_cap);
ctrl_info(ctrl, " Physical Slot Number : %d\n", PSN(ctrl));
--
1.8.1.4

2013-04-12 22:45:23

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 16/29] PCI, x86: Use for_each_pci_resource() with noassign_bars

Replace those open code, and make code more readable.

Signed-off-by: Yinghai Lu <[email protected]>
Cc: [email protected]
Cc: Myron Stowe <[email protected]>
---
arch/x86/pci/common.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 901177d..a2afe2e 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -136,8 +136,7 @@ static void pcibios_fixup_device_resources(struct pci_dev *dev)
* resource so the kernel doesn't attmept to assign
* it later on in pci_assign_unassigned_resources
*/
- for (bar = 0; bar <= PCI_STD_RESOURCE_END; bar++) {
- bar_r = &dev->resource[bar];
+ for_each_pci_resource(dev, bar_r, bar, PCI_STD_RES) {
if (bar_r->start == 0 && bar_r->end != 0) {
bar_r->flags = 0;
bar_r->end = 0;
--
1.8.1.4

2013-04-12 22:45:33

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 27/29] PCI: Make piix4 quirk to use addon_res

After they are put in add-on resources, they will be safely claimed later.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/quirks.c | 95 +++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 79 insertions(+), 16 deletions(-)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 2dac170..6706182 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -382,14 +382,14 @@ static void quirk_ali7101_acpi(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi);

-static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable)
+static int piix4_read_io(struct pci_dev *dev, struct resource *res, int port)
{
u32 devres;
u32 mask, size, base;
+ struct pci_bus_region bus_region;

pci_read_config_dword(dev, port, &devres);
- if ((devres & enable) != enable)
- return;
+
mask = (devres >> 16) & 15;
base = devres & 0xffff;
size = 16;
@@ -399,23 +399,54 @@ static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int p
break;
size = bit;
}
- /*
- * For now we only print it out. Eventually we'll want to
- * reserve it (at least if it's in the 0x1000+ range), but
- * let's get enough confirmation reports first.
- */
base &= -size;
- dev_info(&dev->dev, "%s PIO at %04x-%04x\n", name, base, base + size - 1);
+
+ bus_region.start = base;
+ bus_region.end = base + size - 1;
+ res->flags |= IORESOURCE_IO;
+ pcibios_bus_to_resource(dev, res, &bus_region);
+ dev_info(&dev->dev, "PIO at %pR\n", res);
+
+ return 0;
}
+static int piix4_write_io(struct pci_dev *dev, struct resource *res, int port)
+{
+ u32 devres;
+ struct pci_bus_region bus_region;
+ unsigned size = to_pci_dev_addon_resource(res)->size;

-static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable)
+ pcibios_resource_to_bus(dev, &bus_region, res);
+
+ pci_read_config_dword(dev, port, &devres);
+ devres &= 0xffff0000 | (size - 1);
+ devres |= bus_region.start & 0xffff & (~(size - 1));
+ pci_write_config_dword(dev, port, devres);
+
+ return 0;
+}
+static struct resource_ops piix4_io_ops = {
+ .read = piix4_read_io,
+ .write = piix4_write_io,
+};
+static void piix4_io_quirk(struct pci_dev *dev, char *name, unsigned int port,
+ unsigned int enable)
{
u32 devres;
- u32 mask, size, base;

pci_read_config_dword(dev, port, &devres);
if ((devres & enable) != enable)
return;
+
+ pci_add_dev_addon_resource(dev, port, 0, &piix4_io_ops, name);
+}
+
+static int piix4_read_mem(struct pci_dev *dev, struct resource *res, int port)
+{
+ u32 devres;
+ u32 mask, size, base;
+ struct pci_bus_region bus_region;
+
+ pci_read_config_dword(dev, port, &devres);
base = devres & 0xffff0000;
mask = (devres & 0x3f) << 16;
size = 128 << 16;
@@ -425,12 +456,44 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int
break;
size = bit;
}
- /*
- * For now we only print it out. Eventually we'll want to
- * reserve it, but let's get enough confirmation reports first.
- */
base &= -size;
- dev_info(&dev->dev, "%s MMIO at %04x-%04x\n", name, base, base + size - 1);
+ bus_region.start = base;
+ bus_region.end = base + size - 1;
+ res->flags |= IORESOURCE_MEM;
+ pcibios_bus_to_resource(dev, res, &bus_region);
+ dev_info(&dev->dev, "MMIO at %pR\n", res);
+
+ return 0;
+}
+static int piix4_write_mem(struct pci_dev *dev, struct resource *res, int port)
+{
+ u32 devres;
+ struct pci_bus_region bus_region;
+ unsigned size = to_pci_dev_addon_resource(res)->size;
+
+ pcibios_resource_to_bus(dev, &bus_region, res);
+
+ pci_read_config_dword(dev, port, &devres);
+ devres &= 0x0000ffff | ((size - 1) & 0xffff0000);
+ devres |= bus_region.start & 0xffff0000 & (~(size - 1));
+ pci_write_config_dword(dev, port, devres);
+
+ return 0;
+}
+static struct resource_ops piix4_mem_ops = {
+ .read = piix4_read_mem,
+ .write = piix4_write_mem,
+};
+static void piix4_mem_quirk(struct pci_dev *dev, char *name, unsigned int port,
+ unsigned int enable)
+{
+ u32 devres;
+
+ pci_read_config_dword(dev, port, &devres);
+ if ((devres & enable) != enable)
+ return;
+
+ pci_add_dev_addon_resource(dev, port, 0, &piix4_mem_ops, name);
}

/*
--
1.8.1.4

2013-04-12 22:45:31

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 09/29] PCI: Use for_each_pci_resource() with IOV releated functions

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/iov.c | 31 +++++++++++++++----------------
1 file changed, 15 insertions(+), 16 deletions(-)

diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index ee599f2..baf6c80 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -93,17 +93,20 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)
pci_setup_device(virtfn);
virtfn->dev.parent = dev->dev.parent;

- for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
- res = dev->resource + PCI_IOV_RESOURCES + i;
+ for_each_pci_resource(dev, res, i, PCI_IOV_RES) {
+ struct resource *virtfn_res;
+
if (!res->parent)
continue;
- virtfn->resource[i].name = pci_name(virtfn);
- virtfn->resource[i].flags = res->flags;
+
+ virtfn_res = pci_dev_resource_n(virtfn, i - PCI_IOV_RESOURCES);
+ virtfn_res->name = pci_name(virtfn);
+ virtfn_res->flags = res->flags;
size = resource_size(res);
do_div(size, iov->total_VFs);
- virtfn->resource[i].start = res->start + size * id;
- virtfn->resource[i].end = virtfn->resource[i].start + size - 1;
- rc = request_resource(res, &virtfn->resource[i]);
+ virtfn_res->start = res->start + size * id;
+ virtfn_res->end = virtfn_res->start + size - 1;
+ rc = request_resource(res, virtfn_res);
BUG_ON(rc);
}

@@ -305,9 +308,8 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
return -EIO;

nres = 0;
- for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
- bars |= (1 << (i + PCI_IOV_RESOURCES));
- res = dev->resource + PCI_IOV_RESOURCES + i;
+ for_each_pci_resource(dev, res, i, PCI_IOV_RES) {
+ bars |= 1 << i;
if (res->parent)
nres++;
}
@@ -465,10 +467,9 @@ found:
pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz);

nres = 0;
- for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
- res = dev->resource + PCI_IOV_RESOURCES + i;
+ for_each_pci_resource(dev, res, i, PCI_IOV_RES) {
i += __pci_read_base(dev, pci_bar_unknown, res,
- pos + PCI_SRIOV_BAR + i * 4);
+ pos + PCI_SRIOV_BAR + (i - PCI_IOV_RESOURCES) * 4);
if (!res->flags)
continue;
if (resource_size(res) & (PAGE_SIZE - 1)) {
@@ -511,10 +512,8 @@ found:
return 0;

failed:
- for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
- res = dev->resource + PCI_IOV_RESOURCES + i;
+ for_each_pci_resource(dev, res, i, PCI_IOV_RES)
res->flags = 0;
- }

return rc;
}
--
1.8.1.4

2013-04-12 22:46:11

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 26/29] PCI: Assign/update resource to addon_res

Extend pci_update_resource to check resno and call addon resources
ops to update bar for it.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/setup-res.c | 24 ++++++++++++++++++------
1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 94ef232..6a85dcf 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -35,7 +35,7 @@ void pci_update_resource(struct pci_dev *dev, int resno)
u32 new, check, mask;
int reg;
enum pci_bar_type type;
- struct resource *res = dev->resource + resno;
+ struct resource *res = pci_dev_resource_n(dev, resno);

/*
* Ignore resources for unimplemented BARs and unused resource slots
@@ -52,6 +52,21 @@ void pci_update_resource(struct pci_dev *dev, int resno)
if (res->flags & IORESOURCE_PCI_FIXED)
return;

+ if (resno >= PCI_NUM_RESOURCES) {
+ struct pci_dev_addon_resource *addon_res;
+
+ addon_res = to_pci_dev_addon_resource(res);
+ reg = addon_res->reg_addr;
+ if (addon_res->ops) {
+ addon_res->ops->write(dev, res, reg);
+ return;
+ }
+ } else
+ reg = pci_resource_bar(dev, resno, &type);
+
+ if (!reg)
+ return;
+
pcibios_resource_to_bus(dev, &region, res);

new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
@@ -60,9 +75,6 @@ void pci_update_resource(struct pci_dev *dev, int resno)
else
mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;

- reg = pci_resource_bar(dev, resno, &type);
- if (!reg)
- return;
if (type != pci_bar_unknown) {
if (!(res->flags & IORESOURCE_ROM_ENABLE))
return;
@@ -286,7 +298,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
if (!ret) {
res->flags &= ~IORESOURCE_STARTALIGN;
dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
- if (resno < PCI_BRIDGE_RESOURCES)
+ if (!is_pci_bridge_resource_idx(resno))
pci_update_resource(dev, resno);
}
return ret;
@@ -311,7 +323,7 @@ int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsiz
if (!ret) {
res->flags &= ~IORESOURCE_STARTALIGN;
dev_info(&dev->dev, "BAR %d: reassigned %pR\n", resno, res);
- if (resno < PCI_BRIDGE_RESOURCES)
+ if (!is_pci_bridge_resource_idx(resno))
pci_update_resource(dev, resno);
}
return ret;
--
1.8.1.4

2013-04-12 22:46:10

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 28/29] PCI: Make quirk_io_region to use addon_res

After they are put in add-on resources, they will be safely claimed later.

-v2: According to Bjorn, split change about quirk_io_region calling
pci_read_config_word to another patch.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/quirks.c | 91 ++++++++++++++++++++++++++++++++--------------------
1 file changed, 57 insertions(+), 34 deletions(-)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 6706182..53aea7c9 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -324,12 +324,52 @@ static void quirk_cs5536_vsa(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_cs5536_vsa);

-static void quirk_io_region(struct pci_dev *dev, int port,
- unsigned size, int nr, const char *name)
+static int quirk_read_io(struct pci_dev *dev, struct resource *res, int port)
{
+ struct pci_bus_region bus_region;
u16 region;
+ unsigned size = to_pci_dev_addon_resource(res)->size;
+
+ pci_read_config_word(dev, port, &region);
+ region &= ~(size - 1);
+
+ /* Convert from PCI bus to resource space. */
+ bus_region.start = region;
+ bus_region.end = region + size - 1;
+
+ pcibios_bus_to_resource(dev, res, &bus_region);
+
+ res->flags |= IORESOURCE_IO;
+ dev_info(&dev->dev, "PIO at %pR\n", res);
+
+ return 0;
+}
+static int quirk_write_io(struct pci_dev *dev, struct resource *res, int port)
+{
struct pci_bus_region bus_region;
- struct resource *res = dev->resource + nr;
+ u16 region;
+ unsigned size = to_pci_dev_addon_resource(res)->size;
+
+ pci_read_config_word(dev, port, &region);
+ region &= size - 1;
+
+ /* Convert to PCI bus space. */
+ pcibios_resource_to_bus(dev, &bus_region, res);
+ region |= bus_region.start & (~(size - 1));
+
+ pci_write_config_word(dev, port, region);
+
+ return 0;
+}
+static struct resource_ops quirk_io_ops = {
+ .read = quirk_read_io,
+ .write = quirk_write_io,
+};
+
+static void quirk_io_region(struct pci_dev *dev, int port,
+ unsigned size, char *name)
+{
+ u16 region;

pci_read_config_word(dev, port, &region);
region &= ~(size - 1);
@@ -337,18 +377,7 @@ static void quirk_io_region(struct pci_dev *dev, int port,
if (!region)
return;

- res->name = pci_name(dev);
- res->start = region;
- res->end = region + size - 1;
- res->flags = IORESOURCE_IO;
-
- /* Convert from PCI bus to resource space. */
- bus_region.start = res->start;
- bus_region.end = res->end;
- pcibios_bus_to_resource(dev, res, &bus_region);
-
- if (!pci_claim_resource(dev, nr))
- dev_info(&dev->dev, "quirk: %pR claimed by %s\n", res, name);
+ pci_add_dev_addon_resource(dev, port, size, &quirk_io_ops, name);
}

/*
@@ -377,8 +406,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_
*/
static void quirk_ali7101_acpi(struct pci_dev *dev)
{
- quirk_io_region(dev, 0xE0, 64, PCI_BRIDGE_RESOURCES, "ali7101 ACPI");
- quirk_io_region(dev, 0xE2, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB");
+ quirk_io_region(dev, 0xE0, 64, "ali7101 ACPI");
+ quirk_io_region(dev, 0xE2, 32, "ali7101 SMB");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi);

@@ -506,8 +535,8 @@ static void quirk_piix4_acpi(struct pci_dev *dev)
{
u32 res_a;

- quirk_io_region(dev, 0x40, 64, PCI_BRIDGE_RESOURCES, "PIIX4 ACPI");
- quirk_io_region(dev, 0x90, 16, PCI_BRIDGE_RESOURCES+1, "PIIX4 SMB");
+ quirk_io_region(dev, 0x40, 64, "PIIX4 ACPI");
+ quirk_io_region(dev, 0x90, 16, "PIIX4 SMB");

/* Device resource A has enables for some of the other ones */
pci_read_config_dword(dev, 0x5c, &res_a);
@@ -563,13 +592,11 @@ static void quirk_ich4_lpc_acpi(struct pci_dev *dev)

pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable);
if (enable & ICH4_ACPI_EN)
- quirk_io_region(dev, ICH_PMBASE, 128, PCI_BRIDGE_RESOURCES,
- "ICH4 ACPI/GPIO/TCO");
+ quirk_io_region(dev, ICH_PMBASE, 128, "ICH4 ACPI/GPIO/TCO");

pci_read_config_byte(dev, ICH4_GPIO_CNTL, &enable);
if (enable & ICH4_GPIO_EN)
- quirk_io_region(dev, ICH4_GPIOBASE, 64, PCI_BRIDGE_RESOURCES+1,
- "ICH4 GPIO");
+ quirk_io_region(dev, ICH4_GPIOBASE, 64, "ICH4 GPIO");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi);
@@ -588,13 +615,11 @@ static void ich6_lpc_acpi_gpio(struct pci_dev *dev)

pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable);
if (enable & ICH6_ACPI_EN)
- quirk_io_region(dev, ICH_PMBASE, 128, PCI_BRIDGE_RESOURCES,
- "ICH6 ACPI/GPIO/TCO");
+ quirk_io_region(dev, ICH_PMBASE, 128, "ICH6 ACPI/GPIO/TCO");

pci_read_config_byte(dev, ICH6_GPIO_CNTL, &enable);
if (enable & ICH6_GPIO_EN)
- quirk_io_region(dev, ICH6_GPIOBASE, 64, PCI_BRIDGE_RESOURCES+1,
- "ICH6 GPIO");
+ quirk_io_region(dev, ICH6_GPIOBASE, 64, "ICH6 GPIO");
}

static void ich6_lpc_generic_decode(struct pci_dev *dev, unsigned reg, const char *name, int dynsize)
@@ -693,8 +718,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_1, qui
static void quirk_vt82c586_acpi(struct pci_dev *dev)
{
if (dev->revision & 0x10)
- quirk_io_region(dev, 0x48, 256, PCI_BRIDGE_RESOURCES,
- "vt82c586 ACPI");
+ quirk_io_region(dev, 0x48, 256, "vt82c586 ACPI");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi);

@@ -708,10 +732,9 @@ static void quirk_vt82c686_acpi(struct pci_dev *dev)
{
quirk_vt82c586_acpi(dev);

- quirk_io_region(dev, 0x70, 128, PCI_BRIDGE_RESOURCES+1,
- "vt82c686 HW-mon");
+ quirk_io_region(dev, 0x70, 128, "vt82c686 HW-mon");

- quirk_io_region(dev, 0x90, 16, PCI_BRIDGE_RESOURCES+2, "vt82c686 SMB");
+ quirk_io_region(dev, 0x90, 16, "vt82c686 SMB");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi);

@@ -722,8 +745,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt
*/
static void quirk_vt8235_acpi(struct pci_dev *dev)
{
- quirk_io_region(dev, 0x88, 128, PCI_BRIDGE_RESOURCES, "vt8235 PM");
- quirk_io_region(dev, 0xd0, 16, PCI_BRIDGE_RESOURCES+1, "vt8235 SMB");
+ quirk_io_region(dev, 0x88, 128, "vt8235 PM");
+ quirk_io_region(dev, 0xd0, 16, "vt8235 SMB");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_vt8235_acpi);

--
1.8.1.4

2013-04-12 22:46:32

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 03/29] PCI: Update pci_resource_start etc to use pci_dev_resource_n()

Now pci_resource_start is using dev->resource[n] directly.
Replace it with pci_dev_resource[n] to prepare for addon resource support.

-v2: fix warning about const pointer that Fengguang found.

Signed-off-by: Yinghai Lu <[email protected]>
---
include/linux/pci.h | 35 +++++++++++++++++++++++++----------
1 file changed, 25 insertions(+), 10 deletions(-)

diff --git a/include/linux/pci.h b/include/linux/pci.h
index ffff013..6d450d2 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1455,16 +1455,31 @@ static inline struct pci_dev *pci_dev_get(struct pci_dev *dev)

/* these helpers provide future and backwards compatibility
* for accessing popular PCI BAR info */
-#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start)
-#define pci_resource_end(dev, bar) ((dev)->resource[(bar)].end)
-#define pci_resource_flags(dev, bar) ((dev)->resource[(bar)].flags)
-#define pci_resource_len(dev,bar) \
- ((pci_resource_start((dev), (bar)) == 0 && \
- pci_resource_end((dev), (bar)) == \
- pci_resource_start((dev), (bar))) ? 0 : \
- \
- (pci_resource_end((dev), (bar)) - \
- pci_resource_start((dev), (bar)) + 1))
+static inline resource_size_t pci_resource_start(const struct pci_dev *dev,
+ int bar)
+{
+ return pci_dev_resource_n((struct pci_dev *)dev, bar)->start;
+}
+static inline resource_size_t pci_resource_end(const struct pci_dev *dev,
+ int bar)
+{
+ return pci_dev_resource_n((struct pci_dev *)dev, bar)->end;
+}
+static inline unsigned long pci_resource_flags(const struct pci_dev *dev,
+ int bar)
+{
+ return pci_dev_resource_n((struct pci_dev *)dev, bar)->flags;
+}
+static inline resource_size_t pci_resource_len(const struct pci_dev *dev,
+ int bar)
+{
+ struct resource *res = pci_dev_resource_n((struct pci_dev *)dev, bar);
+
+ if (res->start == 0 && res->end == res->start)
+ return 0;
+
+ return res->end - res->start + 1;
+}

/* Similar to the helpers above, these manipulate per-pci_dev
* driver-specific data. They are really just a wrapper around
--
1.8.1.4

2013-04-12 22:46:39

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 14/29] PCI: Use for_each_pci_resource() with pci bar reassign funcs

Replace those open code, and make code more readable.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/setup-bus.c | 28 ++++++++++++----------------
1 file changed, 12 insertions(+), 16 deletions(-)

diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 7e8739e..b23ef4c 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -106,7 +106,7 @@ static resource_size_t get_res_add_size(struct list_head *head,

list_for_each_entry(dev_res, head, list) {
if (dev_res->res == res) {
- int idx = res - &dev_res->dev->resource[0];
+ int idx = pci_dev_resource_idx(dev_res->dev, res);

dev_printk(KERN_DEBUG, &dev_res->dev->dev,
"res[%d]=%pR get_res_add_size add_size %llx\n",
@@ -124,15 +124,13 @@ static resource_size_t get_res_add_size(struct list_head *head,
static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head)
{
int i;
+ struct resource *r;

- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- struct resource *r;
+ for_each_pci_resource(dev, r, i, PCI_ALL_RES) {
struct pci_dev_resource *dev_res, *tmp;
resource_size_t r_align;
struct list_head *n;

- r = &dev->resource[i];
-
if (r->flags & IORESOURCE_PCI_FIXED)
continue;

@@ -237,7 +235,7 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
if (!found_match)/* just skip */
continue;

- idx = res - &add_res->dev->resource[0];
+ idx = pci_dev_resource_idx(add_res->dev, res);
add_size = add_res->add_size;
if (!resource_size(res)) {
res->start = add_res->start;
@@ -280,7 +278,7 @@ static void assign_requested_resources_sorted(struct list_head *head,

list_for_each_entry(dev_res, head, list) {
res = dev_res->res;
- idx = res - &dev_res->dev->resource[0];
+ idx = pci_dev_resource_idx(dev_res->dev, res);
if (resource_size(res) &&
pci_assign_resource(dev_res->dev, idx)) {
if (fail_head) {
@@ -757,9 +755,9 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
io_align = min_align = window_alignment(bus, IORESOURCE_IO);
list_for_each_entry(dev, &bus->devices, bus_list) {
int i;
+ struct resource *r;

- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- struct resource *r = &dev->resource[i];
+ for_each_pci_resource(dev, r, i, PCI_ALL_RES) {
unsigned long r_size;

if (r->parent || !(r->flags & IORESOURCE_IO))
@@ -870,9 +868,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,

list_for_each_entry(dev, &bus->devices, bus_list) {
int i;
+ struct resource *r;

- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- struct resource *r = &dev->resource[i];
+ for_each_pci_resource(dev, r, i, PCI_ALL_RES) {
resource_size_t r_size;

if (r->parent || (r->flags & mask) != type)
@@ -1196,9 +1194,7 @@ static void pci_bridge_release_resources(struct pci_bus *bus,
IORESOURCE_PREFETCH;

dev = bus->self;
- for (idx = PCI_BRIDGE_RESOURCES; idx <= PCI_BRIDGE_RESOURCE_END;
- idx++) {
- r = &dev->resource[idx];
+ for_each_pci_resource(dev, r, idx, PCI_BRIDGE_RES) {
if ((r->flags & type_mask) != type)
continue;
if (!r->parent)
@@ -1369,9 +1365,9 @@ static void __init pci_realloc_detect(void)

for_each_pci_dev(dev) {
int i;
+ struct resource *r;

- for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) {
- struct resource *r = &dev->resource[i];
+ for_each_pci_resource(dev, r, i, PCI_IOV_RES) {

/* Not assigned, or rejected by kernel ? */
if (r->flags && !r->start) {
--
1.8.1.4

2013-04-12 22:46:44

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 17/29] PCI: Use for_each_pci_resource() in pci_dev_driver()

Replace those open code, and make code more readable.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/pci-driver.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 1fa1e48..009f6c2 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -1170,9 +1170,11 @@ pci_dev_driver(const struct pci_dev *dev)
if (dev->driver)
return dev->driver;
else {
+ struct resource *res;
int i;
- for(i=0; i<=PCI_ROM_RESOURCE; i++)
- if (dev->resource[i].flags & IORESOURCE_BUSY)
+
+ for_each_pci_resource((struct pci_dev *)dev, res, i, PCI_STD_ROM_RES)
+ if (res->flags & IORESOURCE_BUSY)
return &pci_compat_driver;
}
return NULL;
--
1.8.1.4

2013-04-12 22:46:53

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 10/29] PCI, acpiphp: Use for_each_pci_resource() helper

Signed-off-by: Yinghai Lu <[email protected]>
Cc: Rafael J. Wysocki <[email protected]>
Cc: Toshi Kani <[email protected]>
Cc: Jiang Liu <[email protected]>
---
drivers/pci/hotplug/acpiphp_glue.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 270fdba..c35b2b1 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -1085,10 +1085,10 @@ static void acpiphp_sanitize_bus(struct pci_bus *bus)
struct pci_dev *dev;
int i;
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM;
+ struct resource *res;

list_for_each_entry(dev, &bus->devices, bus_list) {
- for (i=0; i<PCI_BRIDGE_RESOURCES; i++) {
- struct resource *res = &dev->resource[i];
+ for_each_pci_resource(dev, res, i, PCI_STD_ROM_IOV_RES) {
if ((res->flags & type_mask) && !res->start &&
res->end) {
/* Could not assign a required resources
--
1.8.1.4

2013-04-12 22:47:10

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 25/29] PCI: Update pci_resource_bar() to support addon_resource

Need to loop addon resource list to retrieve reg_addr in it.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/pci.c | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index c1010be..7677c6b 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3613,6 +3613,13 @@ int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
reg = pci_iov_resource_bar(dev, resno, type);
if (reg)
return reg;
+ } else if (resno >= PCI_NUM_RESOURCES) {
+ struct resource *res = pci_dev_resource_n(dev, resno);
+
+ if (res) {
+ *type = pci_bar_unknown;
+ return to_pci_dev_addon_resource(res)->reg_addr;
+ }
}

dev_err(&dev->dev, "BAR %d: invalid resource\n", resno);
--
1.8.1.4

2013-04-12 22:47:25

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 19/29] PCI: Use for_each_pci_resource() in pci bases reading

Replace those open code, and make code more readable.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index ac751a6..263a575 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -354,9 +354,11 @@ out:
static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
{
unsigned int pos, reg;
+ struct resource *res;

- for (pos = 0; pos < howmany; pos++) {
- struct resource *res = &dev->resource[pos];
+ for_each_pci_resource(dev, res, pos, PCI_STD_RES) {
+ if (pos >= howmany)
+ break;
reg = PCI_BASE_ADDRESS_0 + (pos << 2);
pos += __pci_read_base(dev, pci_bar_unknown, res, reg);
}
--
1.8.1.4

2013-04-12 22:47:46

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 04/29] PCI: Add pci_dev_resource_idx() helper

Use resource pointer to get index in pci resources array/list.

-v2: export symbol for acpiphp compiling error, found by
Steven Newbury <[email protected]>

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 9 +++++++++
include/linux/pci.h | 1 +
2 files changed, 10 insertions(+)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 9cb3eb3..1df75f7 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -114,6 +114,15 @@ struct resource *pci_dev_resource_n(struct pci_dev *dev, int n)
}
EXPORT_SYMBOL(pci_dev_resource_n);

+int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res)
+{
+ if (res >= dev->resource &&
+ res <= dev->resource + (PCI_NUM_RESOURCES - 1))
+ return res - dev->resource;
+
+ return -1;
+}
+
static u64 pci_size(u64 base, u64 maxbase, u64 mask)
{
u64 size = mask & maxbase; /* Find the significant bits */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 6d450d2..f4da78d 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -354,6 +354,7 @@ struct pci_dev {
};

struct resource *pci_dev_resource_n(struct pci_dev *dev, int n);
+int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res);

static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
{
--
1.8.1.4

2013-04-12 22:46:37

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 02/29] PCI: Add pci_dev_resource_n()

Now pci device resource iteration is done via "for (i=0...)" open code.
That make code hard to read esp when only bridge or sriov resources
are involved.

We want to replace those open code with for_each_pci_resource().
Also want to add addon_resource handling, and need to make addon resource
to be treated as normal PCI resources during iteration.

Add pci_device_resource_n() instead of using dev->resources[n].
Use it with for_each_pci_resource macro and addon_resource support.

-v2: Add EXPORT_SYMBOL to find building error found by Gary Hade

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 9 +++++++++
include/linux/pci.h | 2 ++
2 files changed, 11 insertions(+)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index b494066..9cb3eb3 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -105,6 +105,15 @@ static int __init pcibus_class_init(void)
}
postcore_initcall(pcibus_class_init);

+struct resource *pci_dev_resource_n(struct pci_dev *dev, int n)
+{
+ if (n >= 0 && n < PCI_NUM_RESOURCES)
+ return &dev->resource[n];
+
+ return NULL;
+}
+EXPORT_SYMBOL(pci_dev_resource_n);
+
static u64 pci_size(u64 base, u64 maxbase, u64 mask)
{
u64 size = mask & maxbase; /* Find the significant bits */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index bcd9769..ffff013 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -353,6 +353,8 @@ struct pci_dev {
size_t romlen; /* Length of ROM if it's not from the BAR */
};

+struct resource *pci_dev_resource_n(struct pci_dev *dev, int n);
+
static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
{
#ifdef CONFIG_PCI_IOV
--
1.8.1.4

2013-04-12 22:46:31

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 01/29] PCI: Clean up quirk_io_region

Before every quirk_io_region calling, pci_read_config_word is called.
We can fold that calling into quirk_io_region() to make
code more readable.

According to Bjorn, split this one as separated patch from
addon resource patch.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/quirks.c | 132 ++++++++++++++++++---------------------------------
1 file changed, 47 insertions(+), 85 deletions(-)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 4273a2d..2dac170 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -324,29 +324,32 @@ static void quirk_cs5536_vsa(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_cs5536_vsa);

-static void quirk_io_region(struct pci_dev *dev, unsigned region,
- unsigned size, int nr, const char *name)
+static void quirk_io_region(struct pci_dev *dev, int port,
+ unsigned size, int nr, const char *name)
{
- region &= ~(size-1);
- if (region) {
- struct pci_bus_region bus_region;
- struct resource *res = dev->resource + nr;
+ u16 region;
+ struct pci_bus_region bus_region;
+ struct resource *res = dev->resource + nr;

- res->name = pci_name(dev);
- res->start = region;
- res->end = region + size - 1;
- res->flags = IORESOURCE_IO;
+ pci_read_config_word(dev, port, &region);
+ region &= ~(size - 1);

- /* Convert from PCI bus to resource space. */
- bus_region.start = res->start;
- bus_region.end = res->end;
- pcibios_bus_to_resource(dev, res, &bus_region);
+ if (!region)
+ return;

- if (pci_claim_resource(dev, nr) == 0)
- dev_info(&dev->dev, "quirk: %pR claimed by %s\n",
- res, name);
- }
-}
+ res->name = pci_name(dev);
+ res->start = region;
+ res->end = region + size - 1;
+ res->flags = IORESOURCE_IO;
+
+ /* Convert from PCI bus to resource space. */
+ bus_region.start = res->start;
+ bus_region.end = res->end;
+ pcibios_bus_to_resource(dev, res, &bus_region);
+
+ if (!pci_claim_resource(dev, nr))
+ dev_info(&dev->dev, "quirk: %pR claimed by %s\n", res, name);
+}

/*
* ATI Northbridge setups MCE the processor if you even
@@ -374,12 +377,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_
*/
static void quirk_ali7101_acpi(struct pci_dev *dev)
{
- u16 region;
-
- pci_read_config_word(dev, 0xE0, &region);
- quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES, "ali7101 ACPI");
- pci_read_config_word(dev, 0xE2, &region);
- quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB");
+ quirk_io_region(dev, 0xE0, 64, PCI_BRIDGE_RESOURCES, "ali7101 ACPI");
+ quirk_io_region(dev, 0xE2, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi);

@@ -442,12 +441,10 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int
*/
static void quirk_piix4_acpi(struct pci_dev *dev)
{
- u32 region, res_a;
+ u32 res_a;

- pci_read_config_dword(dev, 0x40, &region);
- quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES, "PIIX4 ACPI");
- pci_read_config_dword(dev, 0x90, &region);
- quirk_io_region(dev, region, 16, PCI_BRIDGE_RESOURCES+1, "PIIX4 SMB");
+ quirk_io_region(dev, 0x40, 64, PCI_BRIDGE_RESOURCES, "PIIX4 ACPI");
+ quirk_io_region(dev, 0x90, 16, PCI_BRIDGE_RESOURCES+1, "PIIX4 SMB");

/* Device resource A has enables for some of the other ones */
pci_read_config_dword(dev, 0x5c, &res_a);
@@ -491,7 +488,6 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, qui
*/
static void quirk_ich4_lpc_acpi(struct pci_dev *dev)
{
- u32 region;
u8 enable;

/*
@@ -503,22 +499,14 @@ static void quirk_ich4_lpc_acpi(struct pci_dev *dev)
*/

pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable);
- if (enable & ICH4_ACPI_EN) {
- pci_read_config_dword(dev, ICH_PMBASE, &region);
- region &= PCI_BASE_ADDRESS_IO_MASK;
- if (region >= PCIBIOS_MIN_IO)
- quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES,
- "ICH4 ACPI/GPIO/TCO");
- }
+ if (enable & ICH4_ACPI_EN)
+ quirk_io_region(dev, ICH_PMBASE, 128, PCI_BRIDGE_RESOURCES,
+ "ICH4 ACPI/GPIO/TCO");

pci_read_config_byte(dev, ICH4_GPIO_CNTL, &enable);
- if (enable & ICH4_GPIO_EN) {
- pci_read_config_dword(dev, ICH4_GPIOBASE, &region);
- region &= PCI_BASE_ADDRESS_IO_MASK;
- if (region >= PCIBIOS_MIN_IO)
- quirk_io_region(dev, region, 64,
- PCI_BRIDGE_RESOURCES + 1, "ICH4 GPIO");
- }
+ if (enable & ICH4_GPIO_EN)
+ quirk_io_region(dev, ICH4_GPIOBASE, 64, PCI_BRIDGE_RESOURCES+1,
+ "ICH4 GPIO");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi);
@@ -533,26 +521,17 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, qui

static void ich6_lpc_acpi_gpio(struct pci_dev *dev)
{
- u32 region;
u8 enable;

pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable);
- if (enable & ICH6_ACPI_EN) {
- pci_read_config_dword(dev, ICH_PMBASE, &region);
- region &= PCI_BASE_ADDRESS_IO_MASK;
- if (region >= PCIBIOS_MIN_IO)
- quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES,
- "ICH6 ACPI/GPIO/TCO");
- }
+ if (enable & ICH6_ACPI_EN)
+ quirk_io_region(dev, ICH_PMBASE, 128, PCI_BRIDGE_RESOURCES,
+ "ICH6 ACPI/GPIO/TCO");

pci_read_config_byte(dev, ICH6_GPIO_CNTL, &enable);
- if (enable & ICH6_GPIO_EN) {
- pci_read_config_dword(dev, ICH6_GPIOBASE, &region);
- region &= PCI_BASE_ADDRESS_IO_MASK;
- if (region >= PCIBIOS_MIN_IO)
- quirk_io_region(dev, region, 64,
- PCI_BRIDGE_RESOURCES + 1, "ICH6 GPIO");
- }
+ if (enable & ICH6_GPIO_EN)
+ quirk_io_region(dev, ICH6_GPIOBASE, 64, PCI_BRIDGE_RESOURCES+1,
+ "ICH6 GPIO");
}

static void ich6_lpc_generic_decode(struct pci_dev *dev, unsigned reg, const char *name, int dynsize)
@@ -650,13 +629,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_1, qui
*/
static void quirk_vt82c586_acpi(struct pci_dev *dev)
{
- u32 region;
-
- if (dev->revision & 0x10) {
- pci_read_config_dword(dev, 0x48, &region);
- region &= PCI_BASE_ADDRESS_IO_MASK;
- quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI");
- }
+ if (dev->revision & 0x10)
+ quirk_io_region(dev, 0x48, 256, PCI_BRIDGE_RESOURCES,
+ "vt82c586 ACPI");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi);

@@ -668,18 +643,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt
*/
static void quirk_vt82c686_acpi(struct pci_dev *dev)
{
- u16 hm;
- u32 smb;
-
quirk_vt82c586_acpi(dev);

- pci_read_config_word(dev, 0x70, &hm);
- hm &= PCI_BASE_ADDRESS_IO_MASK;
- quirk_io_region(dev, hm, 128, PCI_BRIDGE_RESOURCES + 1, "vt82c686 HW-mon");
+ quirk_io_region(dev, 0x70, 128, PCI_BRIDGE_RESOURCES+1,
+ "vt82c686 HW-mon");

- pci_read_config_dword(dev, 0x90, &smb);
- smb &= PCI_BASE_ADDRESS_IO_MASK;
- quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2, "vt82c686 SMB");
+ quirk_io_region(dev, 0x90, 16, PCI_BRIDGE_RESOURCES+2, "vt82c686 SMB");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi);

@@ -690,15 +659,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt
*/
static void quirk_vt8235_acpi(struct pci_dev *dev)
{
- u16 pm, smb;
-
- pci_read_config_word(dev, 0x88, &pm);
- pm &= PCI_BASE_ADDRESS_IO_MASK;
- quirk_io_region(dev, pm, 128, PCI_BRIDGE_RESOURCES, "vt8235 PM");
-
- pci_read_config_word(dev, 0xd0, &smb);
- smb &= PCI_BASE_ADDRESS_IO_MASK;
- quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 1, "vt8235 SMB");
+ quirk_io_region(dev, 0x88, 128, PCI_BRIDGE_RESOURCES, "vt8235 PM");
+ quirk_io_region(dev, 0xd0, 16, PCI_BRIDGE_RESOURCES+1, "vt8235 SMB");
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_vt8235_acpi);

--
1.8.1.4

2013-04-12 22:45:12

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 20/29] PCI, x86: Use for_each_pci_resource() with mrst

Signed-off-by: Yinghai Lu <[email protected]>
Cc: [email protected]
Cc: Huang Ying <[email protected]>
Cc: "Rafael J. Wysocki" <[email protected]>
---
arch/x86/pci/mrst.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/arch/x86/pci/mrst.c b/arch/x86/pci/mrst.c
index 6eb18c4..884ea69 100644
--- a/arch/x86/pci/mrst.c
+++ b/arch/x86/pci/mrst.c
@@ -280,6 +280,7 @@ static void pci_fixed_bar_fixup(struct pci_dev *dev)
unsigned long offset;
u32 size;
int i;
+ struct resource *res;

if (!pci_soc_mode)
return;
@@ -294,10 +295,10 @@ static void pci_fixed_bar_fixup(struct pci_dev *dev)
PCI_DEVFN(2, 2) == dev->devfn)
return;

- for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+ for_each_pci_resource(dev, res, i, PCI_STD_RES) {
pci_read_config_dword(dev, offset + 8 + (i * 4), &size);
- dev->resource[i].end = dev->resource[i].start + size - 1;
- dev->resource[i].flags |= IORESOURCE_PCI_FIXED;
+ res->end = res->start + size - 1;
+ res->flags |= IORESOURCE_PCI_FIXED;
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixed_bar_fixup);
--
1.8.1.4

2013-04-12 22:45:09

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 22/29] PCI: Add addon_resource support for pci devices

Now there is some non normal pci resources other than standard,rom,
sriov, bridges.
Some could be same as standard reg, but using different position.
Some could have own way to read/write to them.

Kernel are using different way to hack those resources like abusing
pci bridge resource spot on non bridge pci device.

Add addon_resources list in pci_dev for those non-standard resources.
With this patch, will treat addon-resource like standard resources with
special ops.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 38 +++++++++++++++++++++++++++++++++++++-
include/linux/pci.h | 28 +++++++++++++++++++++++++++-
2 files changed, 64 insertions(+), 2 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 263a575..9e659c7 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -107,22 +107,53 @@ postcore_initcall(pcibus_class_init);

struct resource *pci_dev_resource_n(struct pci_dev *dev, int n)
{
- if (n >= 0 && n < PCI_NUM_RESOURCES)
+ struct pci_dev_addon_resource *addon_res;
+
+ if (n < 0)
+ return NULL;
+
+ if (n < PCI_NUM_RESOURCES)
return &dev->resource[n];

+ n -= PCI_NUM_RESOURCES;
+ list_for_each_entry(addon_res, &dev->addon_resources, list) {
+ if (n-- == 0)
+ return &addon_res->res;
+ }
+
return NULL;
}
EXPORT_SYMBOL(pci_dev_resource_n);

int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res)
{
+ struct pci_dev_addon_resource *addon_res;
+ int n;
+
if (res >= dev->resource &&
res <= dev->resource + (PCI_NUM_RESOURCES - 1))
return res - dev->resource;

+ n = PCI_NUM_RESOURCES;
+ list_for_each_entry(addon_res, &dev->addon_resources, list) {
+ if (res == &addon_res->res)
+ return n;
+ n++;
+ }
+
return -1;
}

+static void pci_release_dev_addon_resource(struct pci_dev *dev)
+{
+ struct pci_dev_addon_resource *addon_res, *tmp;
+
+ list_for_each_entry_safe(addon_res, tmp, &dev->addon_resources, list) {
+ list_del(&addon_res->list);
+ kfree(addon_res);
+ }
+}
+
static void __init_res_idx_mask(unsigned long *mask, int flag)
{
bitmap_zero(mask, PCI_NUM_RESOURCES);
@@ -167,6 +198,9 @@ int pci_next_resource_idx(int i, int flag)
if (i < PCI_NUM_RESOURCES)
return i;

+ if (flag & PCI_ADDON_RES)
+ return i;
+
return -1;
}
EXPORT_SYMBOL(pci_next_resource_idx);
@@ -1199,6 +1233,7 @@ static void pci_release_dev(struct device *dev)
pci_dev = to_pci_dev(dev);
pci_release_capabilities(pci_dev);
pci_release_of_node(pci_dev);
+ pci_release_dev_addon_resource(pci_dev);
kfree(pci_dev);
}

@@ -1276,6 +1311,7 @@ struct pci_dev *alloc_pci_dev(void)
return NULL;

INIT_LIST_HEAD(&dev->bus_list);
+ INIT_LIST_HEAD(&dev->addon_resources);

return dev;
}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 044c474..c337c51 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -323,6 +323,7 @@ struct pci_dev {
*/
unsigned int irq;
struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
+ struct list_head addon_resources; /* addon I/O and memory resource */

bool match_driver; /* Skip attaching driver */
/* These fields are used by common fixups */
@@ -376,6 +377,21 @@ struct pci_dev {
size_t romlen; /* Length of ROM if it's not from the BAR */
};

+struct resource_ops {
+ int (*read)(struct pci_dev *dev, struct resource *res, int addr);
+ int (*write)(struct pci_dev *dev, struct resource *res, int addr);
+};
+
+struct pci_dev_addon_resource {
+ struct list_head list;
+ int reg_addr;
+ int size;
+ struct resource res;
+ struct resource_ops *ops;
+};
+#define to_pci_dev_addon_resource(n) \
+ container_of(n, struct pci_dev_addon_resource, res)
+
struct resource *pci_dev_resource_n(struct pci_dev *dev, int n);
int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res);

@@ -384,8 +400,10 @@ int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res);
#define PCI_IOV_RES (1<<2)
#define PCI_BRIDGE_RES (1<<3)
#define PCI_RES_BLOCK_NUM 4
+/* addon does not need to use bitmap. */
+#define PCI_ADDON_RES (1<<4)

-#define PCI_ALL_RES (PCI_STD_RES | PCI_ROM_RES | PCI_BRIDGE_RES | PCI_IOV_RES)
+#define PCI_ALL_RES (PCI_STD_RES | PCI_ROM_RES | PCI_BRIDGE_RES | PCI_IOV_RES | PCI_ADDON_RES)
#define PCI_ROM_IOV_BRIDGE_RES (PCI_ROM_RES | PCI_BRIDGE_RES | PCI_IOV_RES)
#define PCI_STD_ROM_BRIDGE_RES (PCI_STD_RES | PCI_ROM_RES | PCI_BRIDGE_RES)
#define PCI_STD_IOV_BRIDGE_RES (PCI_STD_RES | PCI_IOV_RES | PCI_BRIDGE_RES)
@@ -393,6 +411,14 @@ int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res);
#define PCI_STD_ROM_RES (PCI_STD_RES | PCI_ROM_RES)
#define PCI_STD_IOV_RES (PCI_STD_RES | PCI_IOV_RES)
#define PCI_STD_ROM_IOV_RES (PCI_STD_RES | PCI_ROM_RES | PCI_IOV_RES)
+/* try to treat add on as std */
+#define PCI_STD_ADDON_RES (PCI_STD_RES | PCI_ADDON_RES)
+#define PCI_STD_ROM_BRIDGE_ADDON_RES (PCI_STD_RES | PCI_ROM_RES | PCI_BRIDGE_RES | PCI_ADDON_RES)
+#define PCI_STD_IOV_BRIDGE_ADDON_RES (PCI_STD_RES | PCI_IOV_RES | PCI_BRIDGE_RES | PCI_ADDON_RES)
+#define PCI_STD_ROM_IOV_ADDON_RES (PCI_STD_RES | PCI_ROM_RES | PCI_IOV_RES | PCI_ADDON_RES)
+#define PCI_STD_ROM_ADDON_RES (PCI_STD_RES | PCI_ROM_RES | PCI_ADDON_RES)
+#define PCI_STD_IOV_ADDON_RES (PCI_STD_RES | PCI_IOV_RES | PCI_ADDON_RES)
+#define PCI_STD_ROM_IOV_ADDON_RES (PCI_STD_RES | PCI_ROM_RES | PCI_IOV_RES | PCI_ADDON_RES)

int pci_next_resource_idx(int i, int flag);

--
1.8.1.4

2013-04-12 22:49:35

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 07/29] PCI, x86: Use for_each_pci_resource() with pci_allocate_bridge_resources

Signed-off-by: Yinghai Lu <[email protected]>
---
arch/x86/pci/i386.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 94919e3..7c3395a 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -206,8 +206,7 @@ static void pcibios_allocate_bridge_resources(struct pci_dev *dev)
int idx;
struct resource *r;

- for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
- r = &dev->resource[idx];
+ for_each_pci_resource(dev, r, idx, PCI_BRIDGE_RES) {
if (!r->flags)
continue;
if (!r->start || pci_claim_resource(dev, idx) < 0) {
--
1.8.1.4

2013-04-12 22:45:07

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 21/29] PCI, xen: Use for_each_pci_resource() with xen pci

Signed-off-by: Yinghai Lu <[email protected]>
Cc: Konrad Rzeszutek Wilk <[email protected]>
Cc: [email protected]
Reviewed-by: Konrad Rzeszutek Wilk <[email protected]>
---
drivers/pci/xen-pcifront.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index 966abc6..c90835f 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -395,9 +395,7 @@ static int pcifront_claim_resource(struct pci_dev *dev, void *data)
int i;
struct resource *r;

- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- r = &dev->resource[i];
-
+ for_each_pci_resource(dev, r, i, PCI_ALL_RES) {
if (!r->parent && r->start && r->flags) {
dev_info(&pdev->xdev->dev, "claiming resource %s/%d\n",
pci_name(dev), i);
--
1.8.1.4

2013-04-12 22:49:58

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 29/29] PCI: Use addon_fixed_resource with ati fixed resource

After they are put in addon_res list, they will be safely claimed later.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/quirks.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 53aea7c9..5d26965 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -386,10 +386,12 @@ static void quirk_io_region(struct pci_dev *dev, int port,
*/
static void quirk_ati_exploding_mce(struct pci_dev *dev)
{
- dev_info(&dev->dev, "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb\n");
+ dev_info(&dev->dev, "ATI Northbridge, will reserve I/O ports 0x3b0 to 0x3bb\n");
/* Mae rhaid i ni beidio ag edrych ar y lleoliadiau I/O hyn */
- request_region(0x3b0, 0x0C, "RadeonIGP");
- request_region(0x3d3, 0x01, "RadeonIGP");
+ pci_add_dev_addon_fixed_resource(dev, 0x3B0, 0x0C, IORESOURCE_IO, 0,
+ "RadeonIGP");
+ pci_add_dev_addon_fixed_resource(dev, 0x3d3, 0x01, IORESOURCE_IO, 0,
+ "RadeonIGP");
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce);

--
1.8.1.4

2013-04-12 22:45:03

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 12/29] PCI: Use for_each_pci_resource() in pci_enable_dev

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/pci.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index b099e00..c29f062 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -440,8 +440,9 @@ static void
pci_restore_bars(struct pci_dev *dev)
{
int i;
+ struct resource *res;

- for (i = 0; i < PCI_BRIDGE_RESOURCES; i++)
+ for_each_pci_resource(dev, res, i, PCI_STD_ROM_IOV_RES)
pci_update_resource(dev, i);
}

@@ -1153,6 +1154,7 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
{
int err;
int i, bars = 0;
+ struct resource *res;

/*
* Power state could be unknown at this point, either due to a fresh
@@ -1170,12 +1172,11 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
return 0; /* already enabled */

/* only skip sriov related */
- for (i = 0; i <= PCI_ROM_RESOURCE; i++)
- if (dev->resource[i].flags & flags)
- bars |= (1 << i);
- for (i = PCI_BRIDGE_RESOURCES; i < DEVICE_COUNT_RESOURCE; i++)
- if (dev->resource[i].flags & flags)
+ for_each_pci_resource(dev, res, i, PCI_STD_ROM_BRIDGE_RES) {
+ /* TODO: check i with bits of bars */
+ if (res->flags & flags)
bars |= (1 << i);
+ }

err = do_pci_enable_device(dev, bars);
if (err < 0)
@@ -2557,7 +2558,7 @@ static int __pci_request_region(struct pci_dev *pdev, int bar, const char *res_n

err_out:
dev_warn(&pdev->dev, "BAR %d: can't reserve %pR\n", bar,
- &pdev->resource[bar]);
+ pci_dev_resource_n(pdev, bar));
return -EBUSY;
}

--
1.8.1.4

2013-04-12 22:50:51

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 15/29] PCI: Use for_each_pci_resource() in pci_assign_resource

Also replace dev->resource[n] with pci_dev_resource_n().

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/setup-res.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 81b88bd..94ef232 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -110,7 +110,7 @@ void pci_update_resource(struct pci_dev *dev, int resno)

int pci_claim_resource(struct pci_dev *dev, int resource)
{
- struct resource *res = &dev->resource[resource];
+ struct resource *res = pci_dev_resource_n(dev, resource);
struct resource *root, *conflict;

root = pci_find_parent_resource(dev, res);
@@ -200,7 +200,7 @@ static int pci_revert_fw_address(struct resource *res, struct pci_dev *dev,
static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
int resno, resource_size_t size, resource_size_t align)
{
- struct resource *res = dev->resource + resno;
+ struct resource *res = pci_dev_resource_n(dev, resno);
resource_size_t min;
int ret;

@@ -227,7 +227,7 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
static int _pci_assign_resource(struct pci_dev *dev, int resno,
resource_size_t size, resource_size_t min_align)
{
- struct resource *res = dev->resource + resno;
+ struct resource *res = pci_dev_resource_n(dev, resno);
struct pci_bus *bus;
int ret;
char *type;
@@ -259,7 +259,7 @@ static int _pci_assign_resource(struct pci_dev *dev, int resno,

int pci_assign_resource(struct pci_dev *dev, int resno)
{
- struct resource *res = dev->resource + resno;
+ struct resource *res = pci_dev_resource_n(dev, resno);
resource_size_t align, size;
struct pci_bus *bus;
int ret;
@@ -295,7 +295,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
int pci_reassign_resource(struct pci_dev *dev, int resno, resource_size_t addsize,
resource_size_t min_align)
{
- struct resource *res = dev->resource + resno;
+ struct resource *res = pci_dev_resource_n(dev, resno);
resource_size_t new_size;
int ret;

@@ -326,12 +326,10 @@ int pci_enable_resources(struct pci_dev *dev, int mask)
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;

- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+ for_each_pci_resource(dev, r, i, PCI_ALL_RES) {
if (!(mask & (1 << i)))
continue;

- r = &dev->resource[i];
-
if (!(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
continue;
if ((i == PCI_ROM_RESOURCE) &&
--
1.8.1.4

2013-04-12 22:50:49

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 18/29] PCI: Use for_each_pci_resource() in pci resource release

Replace those open code, and make code more readable.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/remove.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index cc875e6..af8ace9 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -6,15 +6,14 @@
static void pci_free_resources(struct pci_dev *dev)
{
int i;
+ struct resource *res;

msi_remove_pci_irq_vectors(dev);

pci_cleanup_rom(dev);
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- struct resource *res = dev->resource + i;
+ for_each_pci_resource(dev, res, i, PCI_ALL_RES)
if (res->parent)
release_resource(res);
- }
}

static void pci_stop_dev(struct pci_dev *dev)
--
1.8.1.4

2013-04-12 22:45:00

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 08/29] PCI, x86: Use for_each_pci_resource() with pci_allocate_dev_resources

We can replace two layer loop with for_each_pci_resource(), and make
the code more readable.

Signed-off-by: Yinghai Lu <[email protected]>
Cc: [email protected]
---
arch/x86/pci/i386.c | 55 +++++++++++++++++++----------------------------------
1 file changed, 20 insertions(+), 35 deletions(-)

diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 7c3395a..4dafa08 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -233,49 +233,34 @@ static void pcibios_allocate_bus_resources(struct pci_bus *bus)
pcibios_allocate_bus_resources(child);
}

-struct pci_check_idx_range {
- int start;
- int end;
-};
-
static void pcibios_allocate_dev_resources(struct pci_dev *dev, int pass)
{
- int idx, disabled, i;
+ int idx, disabled;
u16 command;
struct resource *r;

- struct pci_check_idx_range idx_range[] = {
- { PCI_STD_RESOURCES, PCI_STD_RESOURCE_END },
-#ifdef CONFIG_PCI_IOV
- { PCI_IOV_RESOURCES, PCI_IOV_RESOURCE_END },
-#endif
- };
-
pci_read_config_word(dev, PCI_COMMAND, &command);
- for (i = 0; i < ARRAY_SIZE(idx_range); i++)
- for (idx = idx_range[i].start; idx <= idx_range[i].end; idx++) {
- r = &dev->resource[idx];
- if (r->parent) /* Already allocated */
- continue;
- if (!r->start) /* Address not assigned at all */
- continue;
- if (r->flags & IORESOURCE_IO)
- disabled = !(command & PCI_COMMAND_IO);
- else
- disabled = !(command & PCI_COMMAND_MEMORY);
- if (pass == disabled) {
- dev_dbg(&dev->dev,
- "BAR %d: reserving %pr (d=%d, p=%d)\n",
- idx, r, disabled, pass);
- if (pci_claim_resource(dev, idx) < 0) {
- /* We'll assign a new address later */
- pcibios_save_fw_addr(dev,
- idx, r->start);
- r->end -= r->start;
- r->start = 0;
- }
+ for_each_pci_resource(dev, r, idx, PCI_STD_IOV_RES) {
+ if (r->parent) /* Already allocated */
+ continue;
+ if (!r->start) /* Address not assigned at all */
+ continue;
+ if (r->flags & IORESOURCE_IO)
+ disabled = !(command & PCI_COMMAND_IO);
+ else
+ disabled = !(command & PCI_COMMAND_MEMORY);
+ if (pass == disabled) {
+ dev_dbg(&dev->dev,
+ "BAR %d: reserving %pr (d=%d, p=%d)\n",
+ idx, r, disabled, pass);
+ if (pci_claim_resource(dev, idx) < 0) {
+ /* We'll assign a new address later */
+ pcibios_save_fw_addr(dev, idx, r->start);
+ r->end -= r->start;
+ r->start = 0;
}
}
+ }
if (!pass) {
r = &dev->resource[PCI_ROM_RESOURCE];
if (r->flags & IORESOURCE_ROM_ENABLE) {
--
1.8.1.4

2013-04-12 22:44:59

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 05/29] PCI: Add is_pci_*_resource_idx() helpers

According to resource pointer find out if the resource is some type resource
like bridge, sriov, or std.

Signed-off-by: Yinghai Lu <[email protected]>
---
include/linux/pci.h | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)

diff --git a/include/linux/pci.h b/include/linux/pci.h
index f4da78d..14b7de4 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -107,6 +107,29 @@ enum {
DEVICE_COUNT_RESOURCE = PCI_NUM_RESOURCES,
};

+static inline bool is_pci_std_resource_idx(int i)
+{
+ return i >= PCI_STD_RESOURCES && i <= PCI_STD_RESOURCE_END;
+}
+
+static inline bool is_pci_rom_resource_idx(int i)
+{
+ return i == PCI_ROM_RESOURCE;
+}
+
+static inline bool is_pci_iov_resource_idx(int i)
+{
+#ifdef CONFIG_PCI_IOV
+ return i >= PCI_IOV_RESOURCES && i <= PCI_IOV_RESOURCE_END;
+#endif
+ return false;
+}
+
+static inline bool is_pci_bridge_resource_idx(int i)
+{
+ return i >= PCI_BRIDGE_RESOURCES && i <= PCI_BRIDGE_RESOURCE_END;
+}
+
typedef int __bitwise pci_power_t;

#define PCI_D0 ((pci_power_t __force) 0)
--
1.8.1.4

2013-04-12 22:51:38

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 24/29] PCI: Add helpers to add addon_resource

Add helper to put add_on resources into pci devices resource list.

-v2: change one function to static according to Fengguang.

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/pci.h | 5 ++++
2 files changed, 73 insertions(+)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 9e659c7..f3038c2 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -144,6 +144,74 @@ int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res)
return -1;
}

+static struct pci_dev_addon_resource *pci_alloc_dev_addon_resource(
+ struct pci_dev *dev, int addr, char *name)
+{
+ struct pci_dev_addon_resource *addon_res;
+
+ addon_res = kzalloc(sizeof(*addon_res), GFP_KERNEL);
+
+ if (!addon_res)
+ return NULL;
+
+ addon_res->reg_addr = addr;
+
+ if (name)
+ addon_res->res.name = name;
+ else
+ addon_res->res.name = pci_name(dev);
+
+ list_add_tail(&addon_res->list, &dev->addon_resources);
+
+ return addon_res;
+}
+
+struct pci_dev_addon_resource *pci_add_dev_addon_fixed_resource(
+ struct pci_dev *dev, int start, int size, int flags,
+ int addr, char *name)
+{
+ struct pci_dev_addon_resource *addon_res;
+ struct resource *res;
+
+ addon_res = pci_alloc_dev_addon_resource(dev, addr, name);
+ if (addon_res)
+ return NULL;
+
+ res = &addon_res->res;
+ res->start = start;
+ res->end = start + size - 1;
+ res->flags = flags | IORESOURCE_PCI_FIXED;
+
+ dev_printk(KERN_DEBUG, &dev->dev,
+ "addon fixed resource %s %pR added\n", res->name, res);
+
+ return addon_res;
+}
+
+struct pci_dev_addon_resource *pci_add_dev_addon_resource(struct pci_dev *dev,
+ int addr, int size, struct resource_ops *ops, char *name)
+{
+ struct pci_dev_addon_resource *addon_res;
+ struct resource *res;
+
+ addon_res = pci_alloc_dev_addon_resource(dev, addr, name);
+ if (!addon_res)
+ return NULL;
+
+ res = &addon_res->res;
+ if (ops) {
+ addon_res->ops = ops;
+ addon_res->size = size;
+ ops->read(dev, res, addr);
+ } else
+ __pci_read_base(dev, pci_bar_unknown, res, addr);
+
+ dev_printk(KERN_DEBUG, &dev->dev,
+ "addon resource %s %pR added\n", res->name, res);
+
+ return addon_res;
+}
+
static void pci_release_dev_addon_resource(struct pci_dev *dev)
{
struct pci_dev_addon_resource *addon_res, *tmp;
diff --git a/include/linux/pci.h b/include/linux/pci.h
index c337c51..243226c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -394,6 +394,11 @@ struct pci_dev_addon_resource {

struct resource *pci_dev_resource_n(struct pci_dev *dev, int n);
int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res);
+struct pci_dev_addon_resource *pci_add_dev_addon_fixed_resource(
+ struct pci_dev *dev, int start, int size, int flags,
+ int addr, char *name);
+struct pci_dev_addon_resource *pci_add_dev_addon_resource(struct pci_dev *dev,
+ int addr, int size, struct resource_ops *ops, char *name);

#define PCI_STD_RES (1<<0)
#define PCI_ROM_RES (1<<1)
--
1.8.1.4

2013-04-12 22:51:58

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 13/29] PCI: Use for_each_pci_resource() in pci_reassigndev

Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/pci.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index c29f062..d6203e9 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3782,7 +3782,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
command &= ~PCI_COMMAND_MEMORY;
pci_write_config_word(dev, PCI_COMMAND, command);

- for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
+ for_each_pci_resource(dev, r, i, PCI_STD_ROM_IOV_RES) {
r = &dev->resource[i];
if (!(r->flags & IORESOURCE_MEM))
continue;
@@ -3802,8 +3802,7 @@ void pci_reassigndev_resource_alignment(struct pci_dev *dev)
*/
if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
- for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
- r = &dev->resource[i];
+ for_each_pci_resource(dev, r, i, PCI_BRIDGE_RES) {
if (!(r->flags & IORESOURCE_MEM))
continue;
r->end = resource_size(r) - 1;
--
1.8.1.4

2013-04-12 22:44:56

by Yinghai Lu

[permalink] [raw]
Subject: [PATCH v4 06/29] PCI: pci resource iterator

From: Ram Pai <[email protected]>

Currently pci_dev structure holds an array of 17 PCI resources; six base
BARs, one ROM BAR, four BRIDGE BARs, six sriov BARs. This is wasteful.
A bridge device just needs the 4 bridge resources. A non-bridge device
just needs the six base resources and one ROM resource. The sriov
resources are needed only if the device has SRIOV capability.

The pci_dev structure needs to be re-organized to avoid unnecessary
bloating. However too much code outside the pci-bus driver, assumes the
internal details of the pci_dev structure, thus making it hard to
re-organize the datastructure.

As a first step this patch provides generic methods to access the
resource structure of the pci_dev.

Finally we can re-organize the resource structure in the pci_dev
structure and correspondingly update the methods.

-v2: Consolidated iterator interface as per Bjorn's suggestion.
-v3: Add the idx back - Yinghai Lu
-v7: Change to use bitmap for searching - Yinghai Lu
-v8: Fix acpiphp module compiling error that is found by
Steven Newbury <[email protected]> - Yinghai Lu
-v9: According to Bjorn, remove PCI_NO_... that is too confusing
- Yinghai Lu

Signed-off-by: Ram Pai <[email protected]>
Signed-off-by: Yinghai Lu <[email protected]>
---
drivers/pci/probe.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/pci.h | 24 ++++++++++++++++++++++++
2 files changed, 72 insertions(+)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 1df75f7..ac751a6 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -123,6 +123,54 @@ int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res)
return -1;
}

+static void __init_res_idx_mask(unsigned long *mask, int flag)
+{
+ bitmap_zero(mask, PCI_NUM_RESOURCES);
+ if (flag & PCI_STD_RES)
+ bitmap_set(mask, PCI_STD_RESOURCES,
+ PCI_STD_RESOURCE_END - PCI_STD_RESOURCES + 1);
+ if (flag & PCI_ROM_RES)
+ bitmap_set(mask, PCI_ROM_RESOURCE, 1);
+#ifdef CONFIG_PCI_IOV
+ if (flag & PCI_IOV_RES)
+ bitmap_set(mask, PCI_IOV_RESOURCES,
+ PCI_IOV_RESOURCE_END - PCI_IOV_RESOURCES + 1);
+#endif
+ if (flag & PCI_BRIDGE_RES)
+ bitmap_set(mask, PCI_BRIDGE_RESOURCES,
+ PCI_BRIDGE_RESOURCE_END - PCI_BRIDGE_RESOURCES + 1);
+}
+
+static DECLARE_BITMAP(res_idx_mask[1 << PCI_RES_BLOCK_NUM], PCI_NUM_RESOURCES);
+static int __init pci_res_idx_mask_init(void)
+{
+ int i;
+
+ for (i = 0; i < (1 << PCI_RES_BLOCK_NUM); i++)
+ __init_res_idx_mask(res_idx_mask[i], i);
+
+ return 0;
+}
+postcore_initcall(pci_res_idx_mask_init);
+
+static inline unsigned long *get_res_idx_mask(int flag)
+{
+ return res_idx_mask[flag & ((1 << PCI_RES_BLOCK_NUM) - 1)];
+}
+
+int pci_next_resource_idx(int i, int flag)
+{
+ i++;
+ if (i < PCI_NUM_RESOURCES)
+ i = find_next_bit(get_res_idx_mask(flag), PCI_NUM_RESOURCES, i);
+
+ if (i < PCI_NUM_RESOURCES)
+ return i;
+
+ return -1;
+}
+EXPORT_SYMBOL(pci_next_resource_idx);
+
static u64 pci_size(u64 base, u64 maxbase, u64 mask)
{
u64 size = mask & maxbase; /* Find the significant bits */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 14b7de4..044c474 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -379,6 +379,30 @@ struct pci_dev {
struct resource *pci_dev_resource_n(struct pci_dev *dev, int n);
int pci_dev_resource_idx(struct pci_dev *dev, struct resource *res);

+#define PCI_STD_RES (1<<0)
+#define PCI_ROM_RES (1<<1)
+#define PCI_IOV_RES (1<<2)
+#define PCI_BRIDGE_RES (1<<3)
+#define PCI_RES_BLOCK_NUM 4
+
+#define PCI_ALL_RES (PCI_STD_RES | PCI_ROM_RES | PCI_BRIDGE_RES | PCI_IOV_RES)
+#define PCI_ROM_IOV_BRIDGE_RES (PCI_ROM_RES | PCI_BRIDGE_RES | PCI_IOV_RES)
+#define PCI_STD_ROM_BRIDGE_RES (PCI_STD_RES | PCI_ROM_RES | PCI_BRIDGE_RES)
+#define PCI_STD_IOV_BRIDGE_RES (PCI_STD_RES | PCI_IOV_RES | PCI_BRIDGE_RES)
+#define PCI_STD_ROM_IOV_RES (PCI_STD_RES | PCI_ROM_RES | PCI_IOV_RES)
+#define PCI_STD_ROM_RES (PCI_STD_RES | PCI_ROM_RES)
+#define PCI_STD_IOV_RES (PCI_STD_RES | PCI_IOV_RES)
+#define PCI_STD_ROM_IOV_RES (PCI_STD_RES | PCI_ROM_RES | PCI_IOV_RES)
+
+int pci_next_resource_idx(int i, int flag);
+
+#define for_each_pci_resource(dev, res, i, flag) \
+ for (i = pci_next_resource_idx(-1, flag), \
+ res = pci_dev_resource_n(dev, i); \
+ res; \
+ i = pci_next_resource_idx(i, flag), \
+ res = pci_dev_resource_n(dev, i))
+
static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
{
#ifdef CONFIG_PCI_IOV
--
1.8.1.4

2013-04-15 18:23:55

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v4 01/29] PCI: Clean up quirk_io_region

On Fri, Apr 12, 2013 at 4:44 PM, Yinghai Lu <[email protected]> wrote:
> Before every quirk_io_region calling, pci_read_config_word is called.
> We can fold that calling into quirk_io_region() to make
> code more readable.
>
> According to Bjorn, split this one as separated patch from
> addon resource patch.
>
> Signed-off-by: Yinghai Lu <[email protected]>

I applied this to my pci/misc branch for v3.10. Nice cleanup, thanks.

I changed quirk_io_region() so that instead of filling in
res->start/end with bus addresses, then copying those into bus_region,
and finally converting bus-to-region, we just fill in bus_region
directly. That is a couple lines short and res never contains a bus
address. There's no reason to keep bad examples of putting bus
addresses into a struct resource.

Bjorn

> ---
> drivers/pci/quirks.c | 132 ++++++++++++++++++---------------------------------
> 1 file changed, 47 insertions(+), 85 deletions(-)
>
> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
> index 4273a2d..2dac170 100644
> --- a/drivers/pci/quirks.c
> +++ b/drivers/pci/quirks.c
> @@ -324,29 +324,32 @@ static void quirk_cs5536_vsa(struct pci_dev *dev)
> }
> DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_cs5536_vsa);
>
> -static void quirk_io_region(struct pci_dev *dev, unsigned region,
> - unsigned size, int nr, const char *name)
> +static void quirk_io_region(struct pci_dev *dev, int port,
> + unsigned size, int nr, const char *name)
> {
> - region &= ~(size-1);
> - if (region) {
> - struct pci_bus_region bus_region;
> - struct resource *res = dev->resource + nr;
> + u16 region;
> + struct pci_bus_region bus_region;
> + struct resource *res = dev->resource + nr;
>
> - res->name = pci_name(dev);
> - res->start = region;
> - res->end = region + size - 1;
> - res->flags = IORESOURCE_IO;
> + pci_read_config_word(dev, port, &region);
> + region &= ~(size - 1);
>
> - /* Convert from PCI bus to resource space. */
> - bus_region.start = res->start;
> - bus_region.end = res->end;
> - pcibios_bus_to_resource(dev, res, &bus_region);
> + if (!region)
> + return;
>
> - if (pci_claim_resource(dev, nr) == 0)
> - dev_info(&dev->dev, "quirk: %pR claimed by %s\n",
> - res, name);
> - }
> -}
> + res->name = pci_name(dev);
> + res->start = region;
> + res->end = region + size - 1;
> + res->flags = IORESOURCE_IO;
> +
> + /* Convert from PCI bus to resource space. */
> + bus_region.start = res->start;
> + bus_region.end = res->end;
> + pcibios_bus_to_resource(dev, res, &bus_region);
> +
> + if (!pci_claim_resource(dev, nr))
> + dev_info(&dev->dev, "quirk: %pR claimed by %s\n", res, name);
> +}
>
> /*
> * ATI Northbridge setups MCE the processor if you even
> @@ -374,12 +377,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_
> */
> static void quirk_ali7101_acpi(struct pci_dev *dev)
> {
> - u16 region;
> -
> - pci_read_config_word(dev, 0xE0, &region);
> - quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES, "ali7101 ACPI");
> - pci_read_config_word(dev, 0xE2, &region);
> - quirk_io_region(dev, region, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB");
> + quirk_io_region(dev, 0xE0, 64, PCI_BRIDGE_RESOURCES, "ali7101 ACPI");
> + quirk_io_region(dev, 0xE2, 32, PCI_BRIDGE_RESOURCES+1, "ali7101 SMB");
> }
> DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi);
>
> @@ -442,12 +441,10 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int
> */
> static void quirk_piix4_acpi(struct pci_dev *dev)
> {
> - u32 region, res_a;
> + u32 res_a;
>
> - pci_read_config_dword(dev, 0x40, &region);
> - quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES, "PIIX4 ACPI");
> - pci_read_config_dword(dev, 0x90, &region);
> - quirk_io_region(dev, region, 16, PCI_BRIDGE_RESOURCES+1, "PIIX4 SMB");
> + quirk_io_region(dev, 0x40, 64, PCI_BRIDGE_RESOURCES, "PIIX4 ACPI");
> + quirk_io_region(dev, 0x90, 16, PCI_BRIDGE_RESOURCES+1, "PIIX4 SMB");
>
> /* Device resource A has enables for some of the other ones */
> pci_read_config_dword(dev, 0x5c, &res_a);
> @@ -491,7 +488,6 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, qui
> */
> static void quirk_ich4_lpc_acpi(struct pci_dev *dev)
> {
> - u32 region;
> u8 enable;
>
> /*
> @@ -503,22 +499,14 @@ static void quirk_ich4_lpc_acpi(struct pci_dev *dev)
> */
>
> pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable);
> - if (enable & ICH4_ACPI_EN) {
> - pci_read_config_dword(dev, ICH_PMBASE, &region);
> - region &= PCI_BASE_ADDRESS_IO_MASK;
> - if (region >= PCIBIOS_MIN_IO)
> - quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES,
> - "ICH4 ACPI/GPIO/TCO");
> - }
> + if (enable & ICH4_ACPI_EN)
> + quirk_io_region(dev, ICH_PMBASE, 128, PCI_BRIDGE_RESOURCES,
> + "ICH4 ACPI/GPIO/TCO");
>
> pci_read_config_byte(dev, ICH4_GPIO_CNTL, &enable);
> - if (enable & ICH4_GPIO_EN) {
> - pci_read_config_dword(dev, ICH4_GPIOBASE, &region);
> - region &= PCI_BASE_ADDRESS_IO_MASK;
> - if (region >= PCIBIOS_MIN_IO)
> - quirk_io_region(dev, region, 64,
> - PCI_BRIDGE_RESOURCES + 1, "ICH4 GPIO");
> - }
> + if (enable & ICH4_GPIO_EN)
> + quirk_io_region(dev, ICH4_GPIOBASE, 64, PCI_BRIDGE_RESOURCES+1,
> + "ICH4 GPIO");
> }
> DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, quirk_ich4_lpc_acpi);
> DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, quirk_ich4_lpc_acpi);
> @@ -533,26 +521,17 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, qui
>
> static void ich6_lpc_acpi_gpio(struct pci_dev *dev)
> {
> - u32 region;
> u8 enable;
>
> pci_read_config_byte(dev, ICH_ACPI_CNTL, &enable);
> - if (enable & ICH6_ACPI_EN) {
> - pci_read_config_dword(dev, ICH_PMBASE, &region);
> - region &= PCI_BASE_ADDRESS_IO_MASK;
> - if (region >= PCIBIOS_MIN_IO)
> - quirk_io_region(dev, region, 128, PCI_BRIDGE_RESOURCES,
> - "ICH6 ACPI/GPIO/TCO");
> - }
> + if (enable & ICH6_ACPI_EN)
> + quirk_io_region(dev, ICH_PMBASE, 128, PCI_BRIDGE_RESOURCES,
> + "ICH6 ACPI/GPIO/TCO");
>
> pci_read_config_byte(dev, ICH6_GPIO_CNTL, &enable);
> - if (enable & ICH6_GPIO_EN) {
> - pci_read_config_dword(dev, ICH6_GPIOBASE, &region);
> - region &= PCI_BASE_ADDRESS_IO_MASK;
> - if (region >= PCIBIOS_MIN_IO)
> - quirk_io_region(dev, region, 64,
> - PCI_BRIDGE_RESOURCES + 1, "ICH6 GPIO");
> - }
> + if (enable & ICH6_GPIO_EN)
> + quirk_io_region(dev, ICH6_GPIOBASE, 64, PCI_BRIDGE_RESOURCES+1,
> + "ICH6 GPIO");
> }
>
> static void ich6_lpc_generic_decode(struct pci_dev *dev, unsigned reg, const char *name, int dynsize)
> @@ -650,13 +629,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_1, qui
> */
> static void quirk_vt82c586_acpi(struct pci_dev *dev)
> {
> - u32 region;
> -
> - if (dev->revision & 0x10) {
> - pci_read_config_dword(dev, 0x48, &region);
> - region &= PCI_BASE_ADDRESS_IO_MASK;
> - quirk_io_region(dev, region, 256, PCI_BRIDGE_RESOURCES, "vt82c586 ACPI");
> - }
> + if (dev->revision & 0x10)
> + quirk_io_region(dev, 0x48, 256, PCI_BRIDGE_RESOURCES,
> + "vt82c586 ACPI");
> }
> DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi);
>
> @@ -668,18 +643,12 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt
> */
> static void quirk_vt82c686_acpi(struct pci_dev *dev)
> {
> - u16 hm;
> - u32 smb;
> -
> quirk_vt82c586_acpi(dev);
>
> - pci_read_config_word(dev, 0x70, &hm);
> - hm &= PCI_BASE_ADDRESS_IO_MASK;
> - quirk_io_region(dev, hm, 128, PCI_BRIDGE_RESOURCES + 1, "vt82c686 HW-mon");
> + quirk_io_region(dev, 0x70, 128, PCI_BRIDGE_RESOURCES+1,
> + "vt82c686 HW-mon");
>
> - pci_read_config_dword(dev, 0x90, &smb);
> - smb &= PCI_BASE_ADDRESS_IO_MASK;
> - quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2, "vt82c686 SMB");
> + quirk_io_region(dev, 0x90, 16, PCI_BRIDGE_RESOURCES+2, "vt82c686 SMB");
> }
> DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt82c686_acpi);
>
> @@ -690,15 +659,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vt
> */
> static void quirk_vt8235_acpi(struct pci_dev *dev)
> {
> - u16 pm, smb;
> -
> - pci_read_config_word(dev, 0x88, &pm);
> - pm &= PCI_BASE_ADDRESS_IO_MASK;
> - quirk_io_region(dev, pm, 128, PCI_BRIDGE_RESOURCES, "vt8235 PM");
> -
> - pci_read_config_word(dev, 0xd0, &smb);
> - smb &= PCI_BASE_ADDRESS_IO_MASK;
> - quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 1, "vt8235 SMB");
> + quirk_io_region(dev, 0x88, 128, PCI_BRIDGE_RESOURCES, "vt8235 PM");
> + quirk_io_region(dev, 0xd0, 16, PCI_BRIDGE_RESOURCES+1, "vt8235 SMB");
> }
> DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_vt8235_acpi);
>
> --
> 1.8.1.4
>

2013-04-25 19:54:19

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v4 00/29] PCI: Add for_each_pci_resource and addon_res support

On Fri, Apr 12, 2013 at 4:44 PM, Yinghai Lu <[email protected]> wrote:
> First part is for_each_pci_resource support:
> Now pci device resource iteration is done via "for (i=0...)" open code.
> That make code hard to read esp when only bridge or sriov resources
> are involved.

The "for (i = 0; ...)" code *is* a bit ugly with the various constants
for different types of resources, but it does have the advantage that
it is very simple and easy to understand. The new code improves the
callers, but the implementation of for_each_pci_resource() is not very
straightforward.

The diffstat (541 insertions(+), 226 deletions(-)) doesn't really
indicate that this is an overall simplification. I know this also
adds some functionality, but even without the addon stuff, this adds
110 more lines than it removes.

> We want to replace those open code with for_each_pci_resource() to make
> the code more readable.
> Also will add addon_resource handling, and need to make addon resource
> to be treated as normal PCI resources during iteration, add
> for_each_pci_resource will make that support transition more simple.
>
> To make for_each_pci_resource more efficient. We will use preset bitmap
> of different type for searching next idx.
>
> Second part is addon_res support:
> Now there is some non normal pci resources other than standard,rom,
> sriov, bridges.
> Some could be same as standard reg, but using different position.
> Some could have own way to read/write to them.
> Kernel are using different way to hack those resources like abusing
> pci bridge resource spot on non bridge pci device.
>
> Add addon_resources list in pci_dev for those non-standard resources.
> With this patch, will treat addon-resource like standard resources with
> special ops.
>
> At last replace some quirk_io with addon_res.
>
> could get from
> git://git.kernel.org/pub/scm/linux/kernel/git/yinghai/linux-yinghai.git for-pci-for-each-res-addon
>
> -v4: split one patch out, and remove PCI_NO_....
>
> Notes: We still need to keep _idx as we use it all the time, and drivers still
> use them to get resource.
>
> Thanks
>
> Yinghai Lu
>
>
> Ram Pai (1):
> PCI: pci resource iterator
>
> Yinghai Lu (28):
> PCI: Clean up quirk_io_region
> PCI: Add pci_dev_resource_n()
> PCI: Update pci_resource_start etc to use pci_dev_resource_n()
> PCI: Add pci_dev_resource_idx() helper
> PCI: Add is_pci_*_resource_idx() helpers
> PCI, x86: Use for_each_pci_resource() with
> pci_allocate_bridge_resources
> PCI, x86: Use for_each_pci_resource() with pci_allocate_dev_resources
> PCI: Use for_each_pci_resource() with IOV releated functions
> PCI, acpiphp: Use for_each_pci_resource() helper
> PCI, pciehp: Use for_each_pci_resource() helper
> PCI: Use for_each_pci_resource() in pci_enable_dev
> PCI: Use for_each_pci_resource() in pci_reassigndev
> PCI: Use for_each_pci_resource() with pci bar reassign funcs
> PCI: Use for_each_pci_resource() in pci_assign_resource
> PCI, x86: Use for_each_pci_resource() with noassign_bars
> PCI: Use for_each_pci_resource() in pci_dev_driver()
> PCI: Use for_each_pci_resource() in pci resource release
> PCI: Use for_each_pci_resource() in pci bases reading
> PCI, x86: Use for_each_pci_resource() with mrst
> PCI, xen: Use for_each_pci_resource() with xen pci
> PCI: Add addon_resource support for pci devices
> PCI: Treat addon res as std resources
> PCI: Add helpers to add addon_resource
> PCI: Update pci_resource_bar() to support addon_resource
> PCI: Assign/update resource to addon_res
> PCI: Make piix4 quirk to use addon_res
> PCI: Make quirk_io_region to use addon_res
> PCI: Use addon_fixed_resource with ati fixed resource
>
> arch/x86/pci/common.c | 3 +-
> arch/x86/pci/i386.c | 58 +++------
> arch/x86/pci/mrst.c | 7 +-
> drivers/pci/hotplug/acpiphp_glue.c | 4 +-
> drivers/pci/hotplug/pciehp_hpc.c | 5 +-
> drivers/pci/iov.c | 31 +++--
> drivers/pci/pci-driver.c | 7 +-
> drivers/pci/pci.c | 27 ++--
> drivers/pci/probe.c | 176 ++++++++++++++++++++++++-
> drivers/pci/quirks.c | 258 ++++++++++++++++++++++---------------
> drivers/pci/remove.c | 5 +-
> drivers/pci/setup-bus.c | 28 ++--
> drivers/pci/setup-res.c | 38 ++++--
> drivers/pci/xen-pcifront.c | 4 +-
> include/linux/pci.h | 116 +++++++++++++++--
> 15 files changed, 541 insertions(+), 226 deletions(-)
>
> --
> 1.8.1.4
>

2013-04-25 20:39:56

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v4 27/29] PCI: Make piix4 quirk to use addon_res

On Fri, Apr 12, 2013 at 4:44 PM, Yinghai Lu <[email protected]> wrote:
> After they are put in add-on resources, they will be safely claimed later.

It took me a while to understand what's going on here, but this is
actually a pretty cool idea. It would be nice to explain a little
about what the patch is doing and how these "pseudo-BARs" work, though
:)

> Signed-off-by: Yinghai Lu <[email protected]>
> ---
> drivers/pci/quirks.c | 95 +++++++++++++++++++++++++++++++++++++++++++---------
> 1 file changed, 79 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
> index 2dac170..6706182 100644
> --- a/drivers/pci/quirks.c
> +++ b/drivers/pci/quirks.c
> @@ -382,14 +382,14 @@ static void quirk_ali7101_acpi(struct pci_dev *dev)
> }
> DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi);
>
> -static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable)
> +static int piix4_read_io(struct pci_dev *dev, struct resource *res, int port)

We're reading from "port," which is really the address of a dword in
config space, not a port, so I would have called it "pos" like
__pci_read_base() did. If I understand correctly, we're reading a
BAR-like register that contains the base address of an I/O port
region.

"piix4_read_io_base(struct pci_dev *dev, struct resource *res, int
pos)" would make more sense to me.

> {
> u32 devres;
> u32 mask, size, base;
> + struct pci_bus_region bus_region;
>
> pci_read_config_dword(dev, port, &devres);
> - if ((devres & enable) != enable)
> - return;
> +
> mask = (devres >> 16) & 15;
> base = devres & 0xffff;
> size = 16;
> @@ -399,23 +399,54 @@ static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int p
> break;
> size = bit;
> }
> - /*
> - * For now we only print it out. Eventually we'll want to
> - * reserve it (at least if it's in the 0x1000+ range), but
> - * let's get enough confirmation reports first.
> - */
> base &= -size;
> - dev_info(&dev->dev, "%s PIO at %04x-%04x\n", name, base, base + size - 1);
> +
> + bus_region.start = base;
> + bus_region.end = base + size - 1;
> + res->flags |= IORESOURCE_IO;
> + pcibios_bus_to_resource(dev, res, &bus_region);
> + dev_info(&dev->dev, "PIO at %pR\n", res);
> +
> + return 0;
> }
> +static int piix4_write_io(struct pci_dev *dev, struct resource *res, int port)
> +{
> + u32 devres;
> + struct pci_bus_region bus_region;
> + unsigned size = to_pci_dev_addon_resource(res)->size;
>
> -static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable)
> + pcibios_resource_to_bus(dev, &bus_region, res);
> +
> + pci_read_config_dword(dev, port, &devres);
> + devres &= 0xffff0000 | (size - 1);
> + devres |= bus_region.start & 0xffff & (~(size - 1));
> + pci_write_config_dword(dev, port, devres);
> +
> + return 0;
> +}
> +static struct resource_ops piix4_io_ops = {
> + .read = piix4_read_io,
> + .write = piix4_write_io,
> +};
> +static void piix4_io_quirk(struct pci_dev *dev, char *name, unsigned int port,
> + unsigned int enable)

I think these (piix4_io_quirk() and piix4_mem_quirk()) would read
better if they were something like:

piix4_add_io_bar(struct pci_dev *dev, unsigned int pos, u32
enable, char *name);

> {
> u32 devres;
> - u32 mask, size, base;
>
> pci_read_config_dword(dev, port, &devres);
> if ((devres & enable) != enable)
> return;
> +
> + pci_add_dev_addon_resource(dev, port, 0, &piix4_io_ops, name);
> +}
> +
> +static int piix4_read_mem(struct pci_dev *dev, struct resource *res, int port)
> +{
> + u32 devres;
> + u32 mask, size, base;
> + struct pci_bus_region bus_region;
> +
> + pci_read_config_dword(dev, port, &devres);
> base = devres & 0xffff0000;
> mask = (devres & 0x3f) << 16;
> size = 128 << 16;
> @@ -425,12 +456,44 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int
> break;
> size = bit;
> }
> - /*
> - * For now we only print it out. Eventually we'll want to
> - * reserve it, but let's get enough confirmation reports first.
> - */
> base &= -size;
> - dev_info(&dev->dev, "%s MMIO at %04x-%04x\n", name, base, base + size - 1);
> + bus_region.start = base;
> + bus_region.end = base + size - 1;
> + res->flags |= IORESOURCE_MEM;
> + pcibios_bus_to_resource(dev, res, &bus_region);
> + dev_info(&dev->dev, "MMIO at %pR\n", res);
> +
> + return 0;
> +}
> +static int piix4_write_mem(struct pci_dev *dev, struct resource *res, int port)
> +{
> + u32 devres;
> + struct pci_bus_region bus_region;
> + unsigned size = to_pci_dev_addon_resource(res)->size;
> +
> + pcibios_resource_to_bus(dev, &bus_region, res);
> +
> + pci_read_config_dword(dev, port, &devres);
> + devres &= 0x0000ffff | ((size - 1) & 0xffff0000);
> + devres |= bus_region.start & 0xffff0000 & (~(size - 1));
> + pci_write_config_dword(dev, port, devres);
> +
> + return 0;
> +}
> +static struct resource_ops piix4_mem_ops = {
> + .read = piix4_read_mem,
> + .write = piix4_write_mem,
> +};
> +static void piix4_mem_quirk(struct pci_dev *dev, char *name, unsigned int port,
> + unsigned int enable)
> +{
> + u32 devres;
> +
> + pci_read_config_dword(dev, port, &devres);
> + if ((devres & enable) != enable)
> + return;
> +
> + pci_add_dev_addon_resource(dev, port, 0, &piix4_mem_ops, name);
> }
>
> /*
> --
> 1.8.1.4
>

2013-04-26 15:23:11

by Bjorn Helgaas

[permalink] [raw]
Subject: Re: [PATCH v4 27/29] PCI: Make piix4 quirk to use addon_res

[+cc Rafael, linux-acpi]

On Thu, Apr 25, 2013 at 2:39 PM, Bjorn Helgaas <[email protected]> wrote:
> On Fri, Apr 12, 2013 at 4:44 PM, Yinghai Lu <[email protected]> wrote:
>> After they are put in add-on resources, they will be safely claimed later.
>
> It took me a while to understand what's going on here, but this is
> actually a pretty cool idea. It would be nice to explain a little
> about what the patch is doing and how these "pseudo-BARs" work, though
> :)

After thinking about this overnight, I'm not so sure about this. I
think the point of this is to manage resources that are consumed by
the device but don't conform to the PCI spec. Most resources don't
need quirks because they're either described by standard BAR registers
or by the exceptions for "legacy I/O devices," e.g., IDE or VGA.

I would expect that the "architected" way to deal with non-standard
resources like this is to describe them via a PNP0C02 or similar ACPI
device. That way, the OS would not need device-specific quirks like
this.

If we do add something like this patch, we're also adding a way for
Linux to *write* these non-standard BARs, which means they can become
out-of-sync with the ACPI description of them. I think the BIOS is
entitled to assume that if it describes a resource via _CRS and it
doesn't provide a corresponding _SRS, the resource will remain
unchanged by the OS.

Bjorn

>> Signed-off-by: Yinghai Lu <[email protected]>
>> ---
>> drivers/pci/quirks.c | 95 +++++++++++++++++++++++++++++++++++++++++++---------
>> 1 file changed, 79 insertions(+), 16 deletions(-)
>>
>> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
>> index 2dac170..6706182 100644
>> --- a/drivers/pci/quirks.c
>> +++ b/drivers/pci/quirks.c
>> @@ -382,14 +382,14 @@ static void quirk_ali7101_acpi(struct pci_dev *dev)
>> }
>> DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi);
>>
>> -static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable)
>> +static int piix4_read_io(struct pci_dev *dev, struct resource *res, int port)
>
> We're reading from "port," which is really the address of a dword in
> config space, not a port, so I would have called it "pos" like
> __pci_read_base() did. If I understand correctly, we're reading a
> BAR-like register that contains the base address of an I/O port
> region.
>
> "piix4_read_io_base(struct pci_dev *dev, struct resource *res, int
> pos)" would make more sense to me.
>
>> {
>> u32 devres;
>> u32 mask, size, base;
>> + struct pci_bus_region bus_region;
>>
>> pci_read_config_dword(dev, port, &devres);
>> - if ((devres & enable) != enable)
>> - return;
>> +
>> mask = (devres >> 16) & 15;
>> base = devres & 0xffff;
>> size = 16;
>> @@ -399,23 +399,54 @@ static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int p
>> break;
>> size = bit;
>> }
>> - /*
>> - * For now we only print it out. Eventually we'll want to
>> - * reserve it (at least if it's in the 0x1000+ range), but
>> - * let's get enough confirmation reports first.
>> - */
>> base &= -size;
>> - dev_info(&dev->dev, "%s PIO at %04x-%04x\n", name, base, base + size - 1);
>> +
>> + bus_region.start = base;
>> + bus_region.end = base + size - 1;
>> + res->flags |= IORESOURCE_IO;
>> + pcibios_bus_to_resource(dev, res, &bus_region);
>> + dev_info(&dev->dev, "PIO at %pR\n", res);
>> +
>> + return 0;
>> }
>> +static int piix4_write_io(struct pci_dev *dev, struct resource *res, int port)
>> +{
>> + u32 devres;
>> + struct pci_bus_region bus_region;
>> + unsigned size = to_pci_dev_addon_resource(res)->size;
>>
>> -static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable)
>> + pcibios_resource_to_bus(dev, &bus_region, res);
>> +
>> + pci_read_config_dword(dev, port, &devres);
>> + devres &= 0xffff0000 | (size - 1);
>> + devres |= bus_region.start & 0xffff & (~(size - 1));
>> + pci_write_config_dword(dev, port, devres);
>> +
>> + return 0;
>> +}
>> +static struct resource_ops piix4_io_ops = {
>> + .read = piix4_read_io,
>> + .write = piix4_write_io,
>> +};
>> +static void piix4_io_quirk(struct pci_dev *dev, char *name, unsigned int port,
>> + unsigned int enable)
>
> I think these (piix4_io_quirk() and piix4_mem_quirk()) would read
> better if they were something like:
>
> piix4_add_io_bar(struct pci_dev *dev, unsigned int pos, u32
> enable, char *name);
>
>> {
>> u32 devres;
>> - u32 mask, size, base;
>>
>> pci_read_config_dword(dev, port, &devres);
>> if ((devres & enable) != enable)
>> return;
>> +
>> + pci_add_dev_addon_resource(dev, port, 0, &piix4_io_ops, name);
>> +}
>> +
>> +static int piix4_read_mem(struct pci_dev *dev, struct resource *res, int port)
>> +{
>> + u32 devres;
>> + u32 mask, size, base;
>> + struct pci_bus_region bus_region;
>> +
>> + pci_read_config_dword(dev, port, &devres);
>> base = devres & 0xffff0000;
>> mask = (devres & 0x3f) << 16;
>> size = 128 << 16;
>> @@ -425,12 +456,44 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int
>> break;
>> size = bit;
>> }
>> - /*
>> - * For now we only print it out. Eventually we'll want to
>> - * reserve it, but let's get enough confirmation reports first.
>> - */
>> base &= -size;
>> - dev_info(&dev->dev, "%s MMIO at %04x-%04x\n", name, base, base + size - 1);
>> + bus_region.start = base;
>> + bus_region.end = base + size - 1;
>> + res->flags |= IORESOURCE_MEM;
>> + pcibios_bus_to_resource(dev, res, &bus_region);
>> + dev_info(&dev->dev, "MMIO at %pR\n", res);
>> +
>> + return 0;
>> +}
>> +static int piix4_write_mem(struct pci_dev *dev, struct resource *res, int port)
>> +{
>> + u32 devres;
>> + struct pci_bus_region bus_region;
>> + unsigned size = to_pci_dev_addon_resource(res)->size;
>> +
>> + pcibios_resource_to_bus(dev, &bus_region, res);
>> +
>> + pci_read_config_dword(dev, port, &devres);
>> + devres &= 0x0000ffff | ((size - 1) & 0xffff0000);
>> + devres |= bus_region.start & 0xffff0000 & (~(size - 1));
>> + pci_write_config_dword(dev, port, devres);
>> +
>> + return 0;
>> +}
>> +static struct resource_ops piix4_mem_ops = {
>> + .read = piix4_read_mem,
>> + .write = piix4_write_mem,
>> +};
>> +static void piix4_mem_quirk(struct pci_dev *dev, char *name, unsigned int port,
>> + unsigned int enable)
>> +{
>> + u32 devres;
>> +
>> + pci_read_config_dword(dev, port, &devres);
>> + if ((devres & enable) != enable)
>> + return;
>> +
>> + pci_add_dev_addon_resource(dev, port, 0, &piix4_mem_ops, name);
>> }
>>
>> /*
>> --
>> 1.8.1.4
>>

2013-04-26 20:21:25

by Rafael J. Wysocki

[permalink] [raw]
Subject: Re: [PATCH v4 27/29] PCI: Make piix4 quirk to use addon_res

On Friday, April 26, 2013 09:22:47 AM Bjorn Helgaas wrote:
> [+cc Rafael, linux-acpi]
>
> On Thu, Apr 25, 2013 at 2:39 PM, Bjorn Helgaas <[email protected]> wrote:
> > On Fri, Apr 12, 2013 at 4:44 PM, Yinghai Lu <[email protected]> wrote:
> >> After they are put in add-on resources, they will be safely claimed later.
> >
> > It took me a while to understand what's going on here, but this is
> > actually a pretty cool idea. It would be nice to explain a little
> > about what the patch is doing and how these "pseudo-BARs" work, though
> > :)
>
> After thinking about this overnight, I'm not so sure about this. I
> think the point of this is to manage resources that are consumed by
> the device but don't conform to the PCI spec. Most resources don't
> need quirks because they're either described by standard BAR registers
> or by the exceptions for "legacy I/O devices," e.g., IDE or VGA.
>
> I would expect that the "architected" way to deal with non-standard
> resources like this is to describe them via a PNP0C02 or similar ACPI
> device. That way, the OS would not need device-specific quirks like
> this.
>
> If we do add something like this patch, we're also adding a way for
> Linux to *write* these non-standard BARs, which means they can become
> out-of-sync with the ACPI description of them. I think the BIOS is
> entitled to assume that if it describes a resource via _CRS and it
> doesn't provide a corresponding _SRS, the resource will remain
> unchanged by the OS.

Agreed.

Thanks,
Rafael


> >> Signed-off-by: Yinghai Lu <[email protected]>
> >> ---
> >> drivers/pci/quirks.c | 95 +++++++++++++++++++++++++++++++++++++++++++---------
> >> 1 file changed, 79 insertions(+), 16 deletions(-)
> >>
> >> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
> >> index 2dac170..6706182 100644
> >> --- a/drivers/pci/quirks.c
> >> +++ b/drivers/pci/quirks.c
> >> @@ -382,14 +382,14 @@ static void quirk_ali7101_acpi(struct pci_dev *dev)
> >> }
> >> DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi);
> >>
> >> -static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable)
> >> +static int piix4_read_io(struct pci_dev *dev, struct resource *res, int port)
> >
> > We're reading from "port," which is really the address of a dword in
> > config space, not a port, so I would have called it "pos" like
> > __pci_read_base() did. If I understand correctly, we're reading a
> > BAR-like register that contains the base address of an I/O port
> > region.
> >
> > "piix4_read_io_base(struct pci_dev *dev, struct resource *res, int
> > pos)" would make more sense to me.
> >
> >> {
> >> u32 devres;
> >> u32 mask, size, base;
> >> + struct pci_bus_region bus_region;
> >>
> >> pci_read_config_dword(dev, port, &devres);
> >> - if ((devres & enable) != enable)
> >> - return;
> >> +
> >> mask = (devres >> 16) & 15;
> >> base = devres & 0xffff;
> >> size = 16;
> >> @@ -399,23 +399,54 @@ static void piix4_io_quirk(struct pci_dev *dev, const char *name, unsigned int p
> >> break;
> >> size = bit;
> >> }
> >> - /*
> >> - * For now we only print it out. Eventually we'll want to
> >> - * reserve it (at least if it's in the 0x1000+ range), but
> >> - * let's get enough confirmation reports first.
> >> - */
> >> base &= -size;
> >> - dev_info(&dev->dev, "%s PIO at %04x-%04x\n", name, base, base + size - 1);
> >> +
> >> + bus_region.start = base;
> >> + bus_region.end = base + size - 1;
> >> + res->flags |= IORESOURCE_IO;
> >> + pcibios_bus_to_resource(dev, res, &bus_region);
> >> + dev_info(&dev->dev, "PIO at %pR\n", res);
> >> +
> >> + return 0;
> >> }
> >> +static int piix4_write_io(struct pci_dev *dev, struct resource *res, int port)
> >> +{
> >> + u32 devres;
> >> + struct pci_bus_region bus_region;
> >> + unsigned size = to_pci_dev_addon_resource(res)->size;
> >>
> >> -static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int port, unsigned int enable)
> >> + pcibios_resource_to_bus(dev, &bus_region, res);
> >> +
> >> + pci_read_config_dword(dev, port, &devres);
> >> + devres &= 0xffff0000 | (size - 1);
> >> + devres |= bus_region.start & 0xffff & (~(size - 1));
> >> + pci_write_config_dword(dev, port, devres);
> >> +
> >> + return 0;
> >> +}
> >> +static struct resource_ops piix4_io_ops = {
> >> + .read = piix4_read_io,
> >> + .write = piix4_write_io,
> >> +};
> >> +static void piix4_io_quirk(struct pci_dev *dev, char *name, unsigned int port,
> >> + unsigned int enable)
> >
> > I think these (piix4_io_quirk() and piix4_mem_quirk()) would read
> > better if they were something like:
> >
> > piix4_add_io_bar(struct pci_dev *dev, unsigned int pos, u32
> > enable, char *name);
> >
> >> {
> >> u32 devres;
> >> - u32 mask, size, base;
> >>
> >> pci_read_config_dword(dev, port, &devres);
> >> if ((devres & enable) != enable)
> >> return;
> >> +
> >> + pci_add_dev_addon_resource(dev, port, 0, &piix4_io_ops, name);
> >> +}
> >> +
> >> +static int piix4_read_mem(struct pci_dev *dev, struct resource *res, int port)
> >> +{
> >> + u32 devres;
> >> + u32 mask, size, base;
> >> + struct pci_bus_region bus_region;
> >> +
> >> + pci_read_config_dword(dev, port, &devres);
> >> base = devres & 0xffff0000;
> >> mask = (devres & 0x3f) << 16;
> >> size = 128 << 16;
> >> @@ -425,12 +456,44 @@ static void piix4_mem_quirk(struct pci_dev *dev, const char *name, unsigned int
> >> break;
> >> size = bit;
> >> }
> >> - /*
> >> - * For now we only print it out. Eventually we'll want to
> >> - * reserve it, but let's get enough confirmation reports first.
> >> - */
> >> base &= -size;
> >> - dev_info(&dev->dev, "%s MMIO at %04x-%04x\n", name, base, base + size - 1);
> >> + bus_region.start = base;
> >> + bus_region.end = base + size - 1;
> >> + res->flags |= IORESOURCE_MEM;
> >> + pcibios_bus_to_resource(dev, res, &bus_region);
> >> + dev_info(&dev->dev, "MMIO at %pR\n", res);
> >> +
> >> + return 0;
> >> +}
> >> +static int piix4_write_mem(struct pci_dev *dev, struct resource *res, int port)
> >> +{
> >> + u32 devres;
> >> + struct pci_bus_region bus_region;
> >> + unsigned size = to_pci_dev_addon_resource(res)->size;
> >> +
> >> + pcibios_resource_to_bus(dev, &bus_region, res);
> >> +
> >> + pci_read_config_dword(dev, port, &devres);
> >> + devres &= 0x0000ffff | ((size - 1) & 0xffff0000);
> >> + devres |= bus_region.start & 0xffff0000 & (~(size - 1));
> >> + pci_write_config_dword(dev, port, devres);
> >> +
> >> + return 0;
> >> +}
> >> +static struct resource_ops piix4_mem_ops = {
> >> + .read = piix4_read_mem,
> >> + .write = piix4_write_mem,
> >> +};
> >> +static void piix4_mem_quirk(struct pci_dev *dev, char *name, unsigned int port,
> >> + unsigned int enable)
> >> +{
> >> + u32 devres;
> >> +
> >> + pci_read_config_dword(dev, port, &devres);
> >> + if ((devres & enable) != enable)
> >> + return;
> >> +
> >> + pci_add_dev_addon_resource(dev, port, 0, &piix4_mem_ops, name);
> >> }
> >>
> >> /*
> >> --
> >> 1.8.1.4
> >>
--
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.