This series of patches rebases on powerpc/next branch, plus below additional
patches:
<This series of patches>
<Followup 3 patches from Gavin on SRIOV EEH, which aren't posted>
https://patchwork.ozlabs.org/patch/581315/ (PATCH[1/9] Richard's SRIOV EEH)
https://patchwork.ozlabs.org/patch/582639/ (PATCH[1/1] Gavin's EEH fix)
https://patchwork.ozlabs.org/patch/582093/ (PATCH[1/1] Gavin's EEH fix)
https://patchwork.ozlabs.org/patch/580626/ (PATCH[1/4] Gavin's PCI fix)
https://patchwork.ozlabs.org/patch/580153/ (PATCH[1/1] Andrew's EEH minor fix)
https://patchwork.ozlabs.org/patch/566827/ (PATCH[1/1] Russell's P5IOC2 removal)
https://patchwork.ozlabs.org/patch/534154/ (PATCH[1/7] Richard's SRIOV rework)
commit 388f7b1 ("Linux 4.5-rc3")
The series of patches intend to support PCI slot for PowerPC PowerNV platform,
which is running on top of skiboot firmware. The patchset requires corresponding
changes from skiboot firmware, which is sent to skiboot@lists.ozlabs.org
for review. The PCI slots are exposed by skiboot with device node properties,
and kernel utilizes those properties to populated PCI slots accordingly.
The original PCI infrastructure on PowerNV platform can't support hotplug
because the PE is assigned during PHB fixup time, which is called for once
during system boot time. For this, the PCI infrastructure on PowerNV platform
has been reworked for a lot. After that, the PE and its corresponding resources
(IODT, M32DT, M64 segments, DMA32 and bypass window) are assigned upon updating
PCI bridge's resources, which might decide PE# assigned to the PE (e.g. M64
resources, on P8 strictly speaking). Each PE will maintain a reference count,
which is (number of child PCI devices + 1). That indicates when last child PCI
device leaves the PE, the PE and its included resources will be relased and put
back into free pool again. With this design, the PE will be released when EEH PE
is released. PATCH[1 - 23] are related to this part.
From skiboot perspective, PCI slot is providing (hot/fundamental/complete)
resets to EEH. The kernel gets to know if skiboot supports various reset on one
particular PCI slot through device-tree node. If it does, EEH will utilize the
functionality provided by skiboot. Besides, the device-tree nodes have to change
in order to support PCI hotplug. For example, when one PCI adapter inserted to
one slot, its device-tree node should be added to the system dynamically. Conversely,
the device-tree node should be removed from the system when the PCI adapter is going
to be offline. Since pci_dn and eeh_dev have same life cyle as PCI device nodes,
they should be added/removed accordingly during PCI hotplug. PATCH[24 - 39] are
doing the related work.
The OF driver is changed to support unflattening FDT blob for sub-stree, which
is covered by PATCH[40 - 44].
The last one, PATCH[45], is the standalone PCI hotplug driver for PowerPC PowerNV
platform.
=======
Testing
=======
1. Unplug adapters behind non-empty slot, then plug them.
1.1 Check status
# cat /sys/bus/pci/slots/C10/address
0003:09:00
# cat /sys/bus/pci/slots/C10/adapter
1
# cat /sys/bus/pci/slots/C10/power
1
# lspci
0003:09:00.0 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.1 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.2 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.3 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
# lspci -t
# lspci -t
-+-[0003:00]---00.0-[01-13]----00.0-[02-13]--+-01.0-[03]----00.0
| +-08.0-[04-08]--
| +-09.0-[09]--+-00.0
| | +-00.1
| | +-00.2
| | \-00.3
| +-10.0-[0a-0e]--
| \-11.0-[0f-13]--
1.2 Unplug adapter 0003:09.00.x
# echo 0 > /sys/bus/pci/slots/C10/power
# lspci -t
-+-[0003:00]---00.0-[01-13]----00.0-[02-13]--+-01.0-[03]----00.0
| +-08.0-[04-08]--
| +-09.0-[09]--
| +-10.0-[0a-0e]--
| \-11.0-[0f-13]--
1.3 Plug adapter 0003:09.00.x
# echo 1 > /sys/bus/pci/slots/C10/power
# lspci -t
-+-[0003:00]---00.0-[01-13]----00.0-[02-13]--+-01.0-[03]----00.0
| +-08.0-[04-08]--
| +-09.0-[09]--+-00.0
| | +-00.1
| | +-00.2
| | \-00.3
| +-10.0-[0a-0e]--
| \-11.0-[0f-13]--
1.4 Inject EEH error to adapter 0003:09:00.x, which is recovered.
# cat /sys/bus/pci/devices/0003:09:00.0/eeh_pe_config_addr
0x1
# echo 1:0:4:0:0 > /sys/kernel/debug/powerpc/PCI0003/err_injct
# lspci -ns 0003:09:00.0
# dmesg | grep EEH
EEH: Frozen PHB#3-PE#1 detected
EEH: PE location: U78C9.001.WZS00CF-P1-C10, PHB location: N/A
EEH: Detected PCI bus error on PHB#3-PE#1
EEH: This PCI device has failed 1 times in the last hour
EEH: Notify device drivers to shutdown
EEH: Collect temporary log
EEH: Reset without hotplug activity
EEH: Notify device drivers the completion of reset
EEH: Notify device driver to resume
2. Plug adapter and then unplug it. This requires hack in skiboot
to skip probing the adapters behind the target (C12 in the
testing) for once.
2.1 Check status
# cat /sys/bus/pci/slots/C12/address
0001:06
# cat /sys/bus/pci/slots/C12/power
0
# cat /sys/bus/pci/slots/C12/adapter
1
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--
2.2 Plug adapter 0001:06:00.x
# echo 1 > /sys/bus/pci/slots/C12/power
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--+-00.0
\-00.1
# lspci
0001:06:00.0 Ethernet controller: \
Broadcom Corporation NetXtreme II BCM57810 10 Gigabit Ethernet (rev 10)
0001:06:00.1 Ethernet controller: \
Broadcom Corporation NetXtreme II BCM57810 10 Gigabit Ethernet (rev 10)
2.3 Inject EEH error to adapter 0001:06:00.x, which is recovered
# cat /sys/bus/pci/devices/0001:06:00.0/eeh_pe_config_addr
0x2
# echo 2:0:4:0:0 > /sys/kernel/debug/powerpc/PCI0001/err_injct
# dmesg | grep EEH
EEH: Frozen PHB#1-PE#2 detected
EEH: PE location: U78C9.001.WZS00CF-P1-C12, PHB location: N/A
EEH: Detected PCI bus error on PHB#1-PE#2
EEH: This PCI device has failed 1 times in the last hour
EEH: Notify device drivers to shutdown
EEH: Collect temporary log
EEH: Reset without hotplug activity
EEH: Notify device drivers the completion of reset
EEH: Notify device driver to resume
2.4 Unplug adapter 0001:06:00.x
# echo 0 > /sys/bus/pci/slots/C12/power
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--
=========
Changelog
=========
v8:
* Rebased to linux-powerpc next branch.
* Resolve comments from Alexey and Daniel on PCI part
* Resolve comments from Rob on fdt.c
* Retested (refer to the "Testing section")
v7:
* Reworked revision to some extent.
* Rebased to powerpc/next repository.
* Reorder/split/merge/drop according - Alexey.
* Defined macros and use array to track IO/M32/M64/DMA32 segments - Alexey.
* Merged 3 files to one for the hotplug driver - Alexey.
* As part of OPAL API, defined macros for PCI slot power state, hotplug
message type. Defined macros for PCI slot power confirmed state in
hotplug driver.
* Misc comments from Alexey.
* Reworked unflatten_dt_node() to avoid recursive function calls.
* Use EXPORT_SYMBOL_GPL() and document function's input/output - Rob/Frank.
v6:
* Patch reorder, split, squash - Alexey.
* Minor coding style - Alexey.
* Better function names for pcibios_{add,remove}_pci_devices - Bjorn
* Replace pr_warn() with dev_warn() in PowerNV hotplug driver - Bjorn
* Concurrent depth as parameter passed to __unflatten_dt_node() - Grant / Alexey
* Replace overlay with of_changeset - Grant
v5:
* Rebased to 4.1.rc6 and some unmerged patches as below:
Alexey's DDW patchset (v11);
Gavin's EEH error injection support (in mpe's next branch);
Richard's EEH cleanup patches (in mpe's next branch);
Richard's EEH support for VF (v7);
Gavin's misc EEH fixes for 4.2;
* The revision bases on skiboot corresponding patches (v7):
https://patchwork.ozlabs.org/patch/480437/
* Utilize OF overlay to update device-tree with help of newly introduced
OPAL API opal_get_overlay_dt().
* Split patches for easy review according to aik's comments.
* Fix coding style from checkpatchc.pl as pointed by aik.
* Code cleanup and misc fixup according to aik's input.
v4:
* Rebased to 4.1.RC1
* Added API to unflatten FDT blob to device node sub-tree, which is attached
the indicated parent device node. The original mechanism based on formatted
string stream has been dropped.
* The PATCH[v3 09/21] ("powerpc/eeh: Delay probing EEH device during hotplug")
was picked up sent to linux-ppc@ separately for review as Richard's "VF EEH
Support" depends on that.
v3:
* Rebased to 4.1.RC0
* PowerNV PCI infrasturcture is total refactored in order to support PCI
hotplug. The PowerNV hotplug driver is also reworked a lot because of
the changes in skiboot in order to support PCI hotplug.
Gavin Shan (45):
PCI: Add pcibios_setup_bridge()
powerpc/pci: Override pcibios_setup_bridge()
powerpc/pci: Cleanup on struct pci_controller_ops
powerpc/powernv: Cleanup on pci_controller_ops instances
powerpc/powernv: Drop phb->bdfn_to_pe()
powerpc/powernv: Reorder fields in struct pnv_phb
powerpc/powernv: Rename PE# fields in struct pnv_phb
powerpc/powernv: Fix initial IO and M32 segmap
powerpc/powernv: Simplify pnv_ioda_setup_pe_seg()
powerpc/powernv: IO and M32 mapping based on PCI device resources
powerpc/powernv: Track M64 segment consumption
powerpc/powernv: Rename M64 related functions
powerpc/powernv/ioda1: M64 support on P7IOC
powerpc/powernv/ioda1: Rename pnv_pci_ioda_setup_dma_pe()
powerpc/powernv/ioda1: Introduce PNV_IODA1_DMA32_SEGSIZE
powerpc/powernv: Remove DMA32 PE list
powerpc/powernv/ioda1: Improve DMA32 segment track
powerpc/powernv: Increase PE# capacity
powerpc/powernv: Use PE instead of number during setup and release
powerpc/powernv: Allocate PE# in reverse order
powerpc/powernv: Create PEs at PCI hot plugging time
powerpc/powernv/ioda1: Support releasing IODA1 TCE table
powerpc/powernv: Dynamically release PEs
powerpc/pci: Rename pcibios_{add,remove}_pci_devices()
powerpc/pci: Rename pcibios_find_pci_bus()
powerpc/pci: Move pci_find_bus_by_node() around
powerpc/pci: Export pci_add_device_node_info()
powerpc/pci: Introduce pci_remove_device_node_info()
powerpc/pci: Export pci_traverse_device_nodes()
powerpc/pci: Delay populating pdn
powerpc/pci: Don't scan empty slot
powerpc/pci: Update bridge windows on PCI plug
powerpc/powernv: Simplify pnv_eeh_reset()
powerpc/powernv: Exclude root bus in pnv_pci_reset_secondary_bus()
powerpc/powernv: Fundamental reset in pnv_pci_reset_secondary_bus()
powerpc/powernv: Support PCI slot ID
powerpc/powernv: Use firmware PCI slot reset infrastructure
powerpc/powernv: Functions to get/set PCI slot status
powerpc/powernv: Select OF_DYNAMIC
drivers/of: Split unflatten_dt_node()
drivers/of: Avoid recursively calling unflatten_dt_node()
drivers/of: Rename unflatten_dt_node()
drivers/of: Specify parent node in of_fdt_unflatten_tree()
drivers/of: Return allocated memory from of_fdt_unflatten_tree()
PCI/hotplug: PowerPC PowerNV PCI hotplug driver
arch/powerpc/include/asm/eeh.h | 2 +-
arch/powerpc/include/asm/opal-api.h | 17 +-
arch/powerpc/include/asm/opal.h | 8 +-
arch/powerpc/include/asm/pci-bridge.h | 25 +-
arch/powerpc/include/asm/pnv-pci.h | 7 +
arch/powerpc/include/asm/ppc-pci.h | 8 +-
arch/powerpc/kernel/eeh_dev.c | 17 +-
arch/powerpc/kernel/eeh_driver.c | 12 +-
arch/powerpc/kernel/pci-common.c | 16 +-
arch/powerpc/kernel/pci-hotplug.c | 47 +-
arch/powerpc/kernel/pci_dn.c | 89 +-
arch/powerpc/platforms/maple/pci.c | 34 +-
arch/powerpc/platforms/pasemi/pci.c | 3 -
arch/powerpc/platforms/powermac/pci.c | 38 +-
arch/powerpc/platforms/powernv/Kconfig | 1 +
arch/powerpc/platforms/powernv/eeh-powernv.c | 179 ++--
arch/powerpc/platforms/powernv/opal-wrappers.S | 4 +
arch/powerpc/platforms/powernv/pci-ioda.c | 1243 +++++++++++++++---------
arch/powerpc/platforms/powernv/pci.c | 92 +-
arch/powerpc/platforms/powernv/pci.h | 60 +-
arch/powerpc/platforms/pseries/msi.c | 4 +-
arch/powerpc/platforms/pseries/pci_dlpar.c | 32 -
arch/powerpc/platforms/pseries/setup.c | 8 +-
drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 2 +-
drivers/of/fdt.c | 372 ++++---
drivers/of/unittest.c | 2 +-
drivers/pci/hotplug/Kconfig | 12 +
drivers/pci/hotplug/Makefile | 3 +
drivers/pci/hotplug/pnv_php.c | 870 +++++++++++++++++
drivers/pci/hotplug/rpadlpar_core.c | 8 +-
drivers/pci/hotplug/rpaphp_core.c | 4 +-
drivers/pci/hotplug/rpaphp_pci.c | 4 +-
drivers/pci/setup-bus.c | 5 +
include/linux/of_fdt.h | 5 +-
include/linux/pci.h | 1 +
35 files changed, 2360 insertions(+), 874 deletions(-)
create mode 100644 drivers/pci/hotplug/pnv_php.c
--
2.1.0
Currently, PowerPC PowerNV platform utilizes ppc_md.pcibios_fixup(),
which is called for once after PCI probing and resource assignment
are completed, to allocate platform required resources for PCI devices:
PE#, IO and MMIO mapping, DMA address translation (TCE) table etc.
Obviously, it's not hotplug friendly.
This adds weak function pcibios_setup_bridge(), which is called by
pci_setup_bridge(). PowerPC PowerNV platform will reuse the function
to assign above platform required resources to newly plugged PCI devices
during PCI hotplug in subsequent patches.
Signed-off-by: Gavin Shan <redacted>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
---
drivers/pci/setup-bus.c | 5 +++++
include/linux/pci.h | 1 +
2 files changed, 6 insertions(+)
This overrides pcibios_setup_bridge() that is called to update PCI
bridge windows when PCI resource assignment is completed, to assign
PE and setup various (resource) mapping for the PE in subsequent
patches.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/include/asm/pci-bridge.h | 2 ++
arch/powerpc/kernel/pci-common.c | 8 ++++++++
2 files changed, 10 insertions(+)
Each PHB has one instance of "struct pci_controller_ops", which
includes various callbacks called by PCI subsystem. In the definition
of this struct, some callbacks have explicit names for its arguments,
but the left don't have.
This adds all explicit names of the arguments to the callbacks in
"struct pci_controller_ops" so that the code looks consistent.
Signed-off-by: Gavin Shan <redacted>
Reviewed-by: Daniel Axtens <redacted>
---
arch/powerpc/include/asm/pci-bridge.h | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
@@ -21,18 +21,19 @@ struct pci_controller_ops {void(*dma_dev_setup)(structpci_dev*dev);void(*dma_bus_setup)(structpci_bus*bus);-int(*probe_mode)(structpci_bus*);+int(*probe_mode)(structpci_bus*bus);/* Called when pci_enable_device() is called. Returns true to*allowassignment/enablingofthedevice.*/-bool(*enable_device_hook)(structpci_dev*);+bool(*enable_device_hook)(structpci_dev*dev);-void(*disable_device)(structpci_dev*);+void(*disable_device)(structpci_dev*dev);-void(*release_device)(structpci_dev*);+void(*release_device)(structpci_dev*dev);/* Called during PCI resource reassignment */-resource_size_t(*window_alignment)(structpci_bus*,unsignedlongtype);+resource_size_t(*window_alignment)(structpci_bus*bus,+unsignedlongtype);void(*setup_bridge)(structpci_bus*bus,unsignedlongtype);void(*reset_secondary_bus)(structpci_dev*dev);
This cleans up on below data struct instances to use tab instead of
space indent of statement to avoid complains from scripts/checkpatch.pl.
No logical changes introduced.
@pnv_pci_ioda_controller_ops
@pnv_npu_ioda_controller_ops
Signed-off-by: Gavin Shan <redacted>
Reviewed-by: Daniel Axtens <redacted>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 36 +++++++++++++++----------------
1 file changed, 18 insertions(+), 18 deletions(-)
This moves those fields in struct pnv_phb that are related to PE
allocation around. No logical change.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/pci.h | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
This renames the fields related to PE number in "struct pnv_phb"
for better reflecting of their usages as Alexey suggested. No
logical changes introduced.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/eeh-powernv.c | 2 +-
arch/powerpc/platforms/powernv/pci-ioda.c | 58 ++++++++++++++--------------
arch/powerpc/platforms/powernv/pci.c | 2 +-
arch/powerpc/platforms/powernv/pci.h | 4 +-
4 files changed, 33 insertions(+), 33 deletions(-)
@@ -124,7 +124,7 @@ static inline bool pnv_pci_is_mem_pref_64(unsigned long flags)staticvoidpnv_ioda_reserve_pe(structpnv_phb*phb,intpe_no){-if(!(pe_no>=0&&pe_no<phb->ioda.total_pe)){+if(!(pe_no>=0&&pe_no<phb->ioda.total_pe_num)){pr_warn("%s: Invalid PE %d on PHB#%x\n",__func__,pe_no,phb->hose->global_number);return;
@@ -144,8 +144,8 @@ static int pnv_ioda_alloc_pe(struct pnv_phb *phb)do{pe=find_next_zero_bit(phb->ioda.pe_alloc,-phb->ioda.total_pe,0);-if(pe>=phb->ioda.total_pe)+phb->ioda.total_pe_num,0);+if(pe>=phb->ioda.total_pe_num)returnIODA_INVALID_PE;}while(test_and_set_bit(pe,phb->ioda.pe_alloc));
@@ -199,13 +199,13 @@ static int pnv_ioda2_init_m64(struct pnv_phb *phb)*expectedtobe0orlastoneofPEcapabicity.*/r=&phb->hose->mem_resources[1];-if(phb->ioda.reserved_pe==0)+if(phb->ioda.reserved_pe_idx==0)r->start+=phb->ioda.m64_segsize;-elseif(phb->ioda.reserved_pe==(phb->ioda.total_pe-1))+elseif(phb->ioda.reserved_pe_idx==(phb->ioda.total_pe_num-1))r->end-=phb->ioda.m64_segsize;elsepr_warn(" Cannot strip M64 segment for reserved PE#%d\n",-phb->ioda.reserved_pe);+phb->ioda.reserved_pe_idx);return0;
@@ -274,7 +274,7 @@ static int pnv_ioda2_pick_m64_pe(struct pci_bus *bus, bool all)returnIODA_INVALID_PE;/* Allocate bitmap */-size=_ALIGN_UP(phb->ioda.total_pe/8,sizeof(unsignedlong));+size=_ALIGN_UP(phb->ioda.total_pe_num/8,sizeof(unsignedlong));pe_alloc=kzalloc(size,GFP_KERNEL);if(!pe_alloc){pr_warn("%s: Out of memory !\n",
@@ -456,7 +456,7 @@ static int pnv_ioda_get_pe_state(struct pnv_phb *phb, int pe_no)s64rc;/* Sanity check on PE number */-if(pe_no<0||pe_no>=phb->ioda.total_pe)+if(pe_no<0||pe_no>=phb->ioda.total_pe_num)returnOPAL_EEH_STOPPED_PERM_UNAVAIL;/*
@@ -3300,13 +3300,13 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,pr_err(" Failed to map registers !\n");/* Initialize more IODA stuff */-phb->ioda.total_pe=1;+phb->ioda.total_pe_num=1;prop32=of_get_property(np,"ibm,opal-num-pes",NULL);if(prop32)-phb->ioda.total_pe=be32_to_cpup(prop32);+phb->ioda.total_pe_num=be32_to_cpup(prop32);prop32=of_get_property(np,"ibm,opal-reserved-pe",NULL);if(prop32)-phb->ioda.reserved_pe=be32_to_cpup(prop32);+phb->ioda.reserved_pe_idx=be32_to_cpup(prop32);/* Parse 64-bit MMIO range */pnv_ioda_parse_m64_window(phb);
@@ -3315,29 +3315,29 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,/* FW Has already off top 64k of M32 space (MSI space) */phb->ioda.m32_size+=0x10000;-phb->ioda.m32_segsize=phb->ioda.m32_size/phb->ioda.total_pe;+phb->ioda.m32_segsize=phb->ioda.m32_size/phb->ioda.total_pe_num;phb->ioda.m32_pci_base=hose->mem_resources[0].start-hose->mem_offset[0];phb->ioda.io_size=hose->pci_io_size;-phb->ioda.io_segsize=phb->ioda.io_size/phb->ioda.total_pe;+phb->ioda.io_segsize=phb->ioda.io_size/phb->ioda.total_pe_num;phb->ioda.io_pci_base=0;/* XXX calculate this ? *//* Allocate aux data & arrays. We don't have IO ports on PHB3 */-size=_ALIGN_UP(phb->ioda.total_pe/8,sizeof(unsignedlong));+size=_ALIGN_UP(phb->ioda.total_pe_num/8,sizeof(unsignedlong));m32map_off=size;-size+=phb->ioda.total_pe*sizeof(phb->ioda.m32_segmap[0]);+size+=phb->ioda.total_pe_num*sizeof(phb->ioda.m32_segmap[0]);if(phb->type==PNV_PHB_IODA1){iomap_off=size;-size+=phb->ioda.total_pe*sizeof(phb->ioda.io_segmap[0]);+size+=phb->ioda.total_pe_num*sizeof(phb->ioda.io_segmap[0]);}pemap_off=size;-size+=phb->ioda.total_pe*sizeof(structpnv_ioda_pe);+size+=phb->ioda.total_pe_num*sizeof(structpnv_ioda_pe);aux=memblock_virt_alloc(size,0);phb->ioda.pe_alloc=aux;phb->ioda.m32_segmap=aux+m32map_off;if(phb->type==PNV_PHB_IODA1)phb->ioda.io_segmap=aux+iomap_off;phb->ioda.pe_array=aux+pemap_off;-set_bit(phb->ioda.reserved_pe,phb->ioda.pe_alloc);+set_bit(phb->ioda.reserved_pe_idx,phb->ioda.pe_alloc);INIT_LIST_HEAD(&phb->ioda.pe_dma_list);INIT_LIST_HEAD(&phb->ioda.pe_list);
There are two arrays for IO and M32 segment maps on every PHB.
The index of the arrays are segment number and the value stored
in the corresponding element is PE number, indicating the segment
is assigned to the PE. Initially, all elements in those two arrays
are zeroes, meaning all segments are assigned to PE#0. It's wrong.
This fixes the initial values in the elements of those two arrays
to IODA_INVALID_PE, meaning all segments aren't assigned to any
PE. In order to use IODA_INVALID_PE (-1) to represent invalid PE
number, the types of those two arrays are changed from "unsigned int"
to "int".
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 9 +++++++--
arch/powerpc/platforms/powernv/pci.h | 4 ++--
2 files changed, 9 insertions(+), 4 deletions(-)
The original implementation of pnv_ioda_setup_pe_seg() configures
IO and M32 segments by separate logics, which can be merged by
by caching @segmap, @seg_size, @win in advance. This shouldn't
cause any behavioural changes.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 62 ++++++++++++++-----------------
1 file changed, 28 insertions(+), 34 deletions(-)
Currently, the IO and M32 segments are mapped to the corresponding
PE based on the windows of the parent bridge of PE's primary bus.
It's not going to work when the windows of root port or upstream
port of the PCIe switch behind root port are extended to PHB's
apertures in order to support hotplug in subsequent patch.
This fixes the issue by mapping IO and M32 segments based on the
resources of the PCI devices included in the PE, instead of the
windows of the parent bridge of the PE's primary bus.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 127 +++++++++++++++++-------------
1 file changed, 71 insertions(+), 56 deletions(-)
@@ -2929,71 +2929,86 @@ truncate_iov:}#endif /* CONFIG_PCI_IOV */-/*-*ThisfunctionissupposedtobecalledonbasisofPEfromtop-*tobottomstyle.SothetheI/OorMMIOsegmentassignedto-*parentPEcouldbeoverridedbyitschildPEsifnecessary.-*/-staticvoidpnv_ioda_setup_pe_seg(structpci_controller*hose,-structpnv_ioda_pe*pe)+staticvoidpnv_ioda_setup_one_res(structpnv_ioda_pe*pe,+structresource*res){-structpnv_phb*phb=hose->private_data;+structpnv_phb*phb=pe->phb;structpci_bus_regionregion;-structresource*res;-unsignedintsegsize;-int*segmap,index,i;+unsignedintindex,segsize;+int*segmap;uint16_twin;int64_trc;-/*-*NOTE:WeonlycarePCIbusbasedPEfornow.ForPCI-*devicebasedPE,forexampleSRIOVsensitiveVFshould-*befiguredoutlater.-*/-BUG_ON(!(pe->flags&(PNV_IODA_PE_BUS|PNV_IODA_PE_BUS_ALL)));+if(!res->parent||!res->flags||res->start>res->end)+return;+if(!(res->flags&(IORESOURCE_IO|IORESOURCE_MEM))||+pnv_pci_is_mem_pref_64(res->flags))+return;-pci_bus_for_each_resource(pe->pbus,res,i){-if(!res||!res->flags||-res->start>res->end)-continue;+if(res->flags&IORESOURCE_IO){+region.start=res->start-phb->ioda.io_pci_base;+region.end=res->end-phb->ioda.io_pci_base;+segsize=phb->ioda.io_segsize;+segmap=phb->ioda.io_segmap;+win=OPAL_IO_WINDOW_TYPE;+}else{+region.start=res->start-+phb->hose->mem_offset[0]-+phb->ioda.m32_pci_base;+region.end=res->end-+phb->hose->mem_offset[0]-+phb->ioda.m32_pci_base;+segsize=phb->ioda.m32_segsize;+segmap=phb->ioda.m32_segmap;+win=OPAL_M32_WINDOW_TYPE;+}++region.start=_ALIGN_DOWN(region.start,segsize);+region.end=_ALIGN_UP(region.end,segsize);+index=region.start/segsize;+while(index<phb->ioda.total_pe_num&®ion.start<region.end){+rc=opal_pci_map_pe_mmio_window(phb->opal_id,+pe->pe_number,win,0,index);+if(rc!=OPAL_SUCCESS){+pr_warn("%s: Error %lld mapping (%d) seg#%d to PHB#%d-PE#%d\n",+__func__,rc,win,index,+phb->hose->global_number,+pe->pe_number);+return;+}-if(res->flags&IORESOURCE_IO){-region.start=res->start-phb->ioda.io_pci_base;-region.end=res->end-phb->ioda.io_pci_base;-segsize=phb->ioda.io_segsize;-segmap=phb->ioda.io_segmap;-win=OPAL_IO_WINDOW_TYPE;-}elseif((res->flags&IORESOURCE_MEM)&&-!pnv_pci_is_mem_pref_64(res->flags)){-region.start=res->start--hose->mem_offset[0]--phb->ioda.m32_pci_base;-region.end=res->end--hose->mem_offset[0]--phb->ioda.m32_pci_base;-segsize=phb->ioda.m32_segsize;-segmap=phb->ioda.m32_segmap;-win=OPAL_M32_WINDOW_TYPE;-}else{-continue;+segmap[index]=pe->pe_number;+region.start+=segsize;+index++;+}+}++staticvoidpnv_ioda_setup_pe_seg(structpnv_ioda_pe*pe)+{+structpci_dev*pdev;+structresource*res;+inti;++/* This function only works for bus dependent PE */+WARN_ON(!(pe->flags&(PNV_IODA_PE_BUS|PNV_IODA_PE_BUS_ALL)));++list_for_each_entry(pdev,&pe->pbus->devices,bus_list){+for(i=0;i<=PCI_ROM_RESOURCE;i++){+res=&pdev->resource[i];+pnv_ioda_setup_one_res(pe,res);}-index=region.start/segsize;-while(index<phb->ioda.total_pe_num&&-region.start<=region.end){-segmap[index]=pe->pe_number;-rc=opal_pci_map_pe_mmio_window(phb->opal_id,-pe->pe_number,win,0,index);-if(rc!=OPAL_SUCCESS){-pr_warn("%s: Error %lld mapping (%d) seg#%d to PHB#%d-PE#%d\n",-__func__,rc,win,index,-pe->phb->hose->global_number,-pe->pe_number);-break;-}+/*+*IfthePEcontainsallsubordinatePCIbuses,the+*windowsofthechildbridgesshouldbemappedto+*thePEaswell.+*/+if(!(pe->flags&PNV_IODA_PE_BUS_ALL&&pci_is_bridge(pdev)))+continue;-region.start+=segsize;-index++;+for(i=0;i<=PCI_BRIDGE_RESOURCE_NUM;i++){+res=&pdev->resource[PCI_BRIDGE_RESOURCES+i];+pnv_ioda_setup_one_res(pe,res);}}}
When unplugging PCI devices, their parent PEs might be offline.
The consumed M64 resource by the PEs should be released at that
time. As we track M32 segment consumption, this introduces an
array to the PHB to track the mapping between M64 segment and
PE number.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 10 ++++++++--
arch/powerpc/platforms/powernv/pci.h | 1 +
2 files changed, 9 insertions(+), 2 deletions(-)
@@ -3332,6 +3333,8 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,/* Allocate aux data & arrays. We don't have IO ports on PHB3 */size=_ALIGN_UP(phb->ioda.total_pe_num/8,sizeof(unsignedlong));+m64map_off=size;+size+=phb->ioda.total_pe_num*sizeof(phb->ioda.m64_segmap[0]);m32map_off=size;size+=phb->ioda.total_pe_num*sizeof(phb->ioda.m32_segmap[0]);if(phb->type==PNV_PHB_IODA1){
This renames those functions picking PE number based on consumed
M64 segments, mapping M64 segments to PEs as those functions are
going to be shared by IODA1/IODA2 in next patch. No logical changes
introduced.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
@@ -283,7 +283,7 @@ static int pnv_ioda2_pick_m64_pe(struct pci_bus *bus, bool all)}/* Figure out reserved PE numbers by the PE */-pnv_ioda2_reserve_m64_pe(bus,pe_alloc,all);+pnv_ioda_reserve_m64_pe(bus,pe_alloc,all);/**thecurrentbusmightnotownM64windowandthat'sall
@@ -365,8 +365,8 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)/* Use last M64 BAR to cover M64 window */phb->ioda.m64_bar_idx=15;phb->init_m64=pnv_ioda2_init_m64;-phb->reserve_m64_pe=pnv_ioda2_reserve_m64_pe;-phb->pick_m64_pe=pnv_ioda2_pick_m64_pe;+phb->reserve_m64_pe=pnv_ioda_reserve_m64_pe;+phb->pick_m64_pe=pnv_ioda_pick_m64_pe;}staticvoidpnv_ioda_freeze_pe(structpnv_phb*phb,intpe_no)
PEs are put into PHB DMA32 list (phb->ioda.pe_dma_list) according
to their DMA32 weight. The PEs on the list are iterated to setup
their TCE32 tables at system booting time. The list is used for
once and there is for keep having it.
This moves the logic calculating DMA32 weight of PHB and PE to
pnv_ioda_setup_dma() to drop PHB's DMA32 list. Also, every PE
traces the consumed DMA32 segment by @tce32_seg and @tce32_segcount
are useless and they're removed.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 168 +++++++++++++-----------------
arch/powerpc/platforms/powernv/pci.h | 19 ----
2 files changed, 75 insertions(+), 112 deletions(-)
@@ -886,44 +886,6 @@ out:return0;}-staticvoidpnv_ioda_link_pe_by_weight(structpnv_phb*phb,-structpnv_ioda_pe*pe)-{-structpnv_ioda_pe*lpe;--list_for_each_entry(lpe,&phb->ioda.pe_dma_list,dma_link){-if(lpe->dma_weight<pe->dma_weight){-list_add_tail(&pe->dma_link,&lpe->dma_link);-return;-}-}-list_add_tail(&pe->dma_link,&phb->ioda.pe_dma_list);-}--staticunsignedintpnv_ioda_dma_weight(structpci_dev*dev)-{-/* This is quite simplistic. The "base" weight of a device-*is10.0meansnoDMAistobeaccountedforit.-*/--/* If it's a bridge, no DMA */-if(dev->hdr_type!=PCI_HEADER_TYPE_NORMAL)-return0;--/* Reduce the weight of slow USB controllers */-if(dev->class==PCI_CLASS_SERIAL_USB_UHCI||-dev->class==PCI_CLASS_SERIAL_USB_OHCI||-dev->class==PCI_CLASS_SERIAL_USB_EHCI)-return3;--/* Increase the weight of RAID (includes Obsidian) */-if((dev->class>>8)==PCI_CLASS_STORAGE_RAID)-return15;--/* Default */-return10;-}-#ifdef CONFIG_PCI_IOVstaticintpnv_pci_vf_resource_shift(structpci_dev*dev,intoffset){
@@ -1044,16 +1005,6 @@ static struct pnv_ioda_pe *pnv_ioda_setup_dev_PE(struct pci_dev *dev)returnNULL;}-/* Assign a DMA weight to the device */-pe->dma_weight=pnv_ioda_dma_weight(dev);-if(pe->dma_weight!=0){-phb->ioda.dma_weight+=pe->dma_weight;-phb->ioda.dma_pe_count++;-}--/* Link the PE */-pnv_ioda_link_pe_by_weight(phb,pe);-returnpe;}
@@ -1108,10 +1058,8 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, bool all)pe->flags|=(all?PNV_IODA_PE_BUS_ALL:PNV_IODA_PE_BUS);pe->pbus=bus;pe->pdev=NULL;-pe->tce32_seg=-1;pe->mve_number=-1;pe->rid=bus->busn_res.start<<8;-pe->dma_weight=0;if(all)pe_info(pe,"Secondary bus %d..%d associated with PE#%d\n",
@@ -1133,17 +1081,6 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, bool all)/* Put PE to the list */list_add_tail(&pe->list,&phb->ioda.pe_list);--/* Account for one DMA PE if at least one DMA capable device exist-*belowthebridge-*/-if(pe->dma_weight!=0){-phb->ioda.dma_weight+=pe->dma_weight;-phb->ioda.dma_pe_count++;-}--/* Link the PE */-pnv_ioda_link_pe_by_weight(phb,pe);}staticstructpnv_ioda_pe*pnv_ioda_setup_npu_PE(structpci_dev*npu_pdev)
@@ -1184,7 +1121,6 @@ static struct pnv_ioda_pe *pnv_ioda_setup_npu_PE(struct pci_dev *npu_pdev)rid=npu_pdev->bus->number<<8|npu_pdn->devfn;npu_pdn->pcidev=npu_pdev;npu_pdn->pe_number=pe_num;-pe->dma_weight+=pnv_ioda_dma_weight(npu_pdev);phb->ioda.pe_rmap[rid]=pe->pe_number;/* Map the PE to this link */
@@ -2023,6 +1958,54 @@ static struct iommu_table_ops pnv_ioda2_iommu_ops = {.free=pnv_ioda2_table_free,};+staticintpnv_pci_ioda_dev_dma_weight(structpci_dev*dev,void*data)+{+unsignedint*weight=(unsignedint*)data;++/* This is quite simplistic. The "base" weight of a device+*is10.0meansnoDMAistobeaccountedforit.+*/+if(dev->hdr_type!=PCI_HEADER_TYPE_NORMAL)+return0;++if(dev->class==PCI_CLASS_SERIAL_USB_UHCI||+dev->class==PCI_CLASS_SERIAL_USB_OHCI||+dev->class==PCI_CLASS_SERIAL_USB_EHCI)+*weight+=3;+elseif((dev->class>>8)==PCI_CLASS_STORAGE_RAID)+*weight+=15;+else+*weight+=10;++return0;+}++staticunsignedintpnv_pci_ioda_pe_dma_weight(structpnv_ioda_pe*pe)+{+unsignedintweight=0;++if((pe->flags&PNV_IODA_PE_DEV)&&pe->pdev){+pnv_pci_ioda_dev_dma_weight(pe->pdev,&weight);+}elseif((pe->flags&PNV_IODA_PE_BUS)&&pe->pbus){+structpci_dev*pdev;++list_for_each_entry(pdev,&pe->pbus->devices,bus_list)+pnv_pci_ioda_dev_dma_weight(pdev,&weight);+}elseif((pe->flags&PNV_IODA_PE_BUS_ALL)&&pe->pbus){+pci_walk_bus(pe->pbus,pnv_pci_ioda_dev_dma_weight,&weight);+}++returnweight;+}++staticunsignedintpnv_pci_ioda_total_dma_weight(structpnv_phb*phb)+{+unsignedintweight=0;++pci_walk_bus(phb->hose->bus,pnv_pci_ioda_dev_dma_weight,&weight);+returnweight;+}+staticvoidpnv_pci_ioda1_setup_dma_pe(structpnv_phb*phb,structpnv_ioda_pe*pe,unsignedintbase,
@@ -2039,17 +2022,12 @@ static void pnv_pci_ioda1_setup_dma_pe(struct pnv_phb *phb,/* XXX FIXME: Provide 64-bit DMA facilities & non-4K TCE tables etc.. *//* XXX FIXME: Allocate multi-level tables on PHB3 */-/* We shouldn't already have a 32-bit DMA associated */-if(WARN_ON(pe->tce32_seg>=0))-return;-tbl=pnv_pci_table_alloc(phb->hose->node);iommu_register_group(&pe->table_group,phb->hose->global_number,pe->pe_number);pnv_pci_link_table_and_group(phb->hose->node,0,tbl,&pe->table_group);/* Grab a 32-bit TCE table */-pe->tce32_seg=base;pe_info(pe," Setting up 32-bit TCE table at %08x..%08x\n",base*PNV_IODA1_DMA32_SEGSIZE,(base+segs)*PNV_IODA1_DMA32_SEGSIZE-1);
@@ -2116,8 +2094,6 @@ static void pnv_pci_ioda1_setup_dma_pe(struct pnv_phb *phb,return;fail:/* XXX Failure: Try to fallback to 64-bit only ? */-if(pe->tce32_seg>=0)-pe->tce32_seg=-1;if(tce_mem)__free_pages(tce_mem,get_order(tce32_segsz*segs));if(tbl){
@@ -2528,10 +2504,6 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,{int64_trc;-/* We shouldn't already have a 32-bit DMA associated */-if(WARN_ON(pe->tce32_seg>=0))-return;-/* TVE #1 is selected by PCI address bit 59 */pe->tce_bypass_base=1ull<<59;
@@ -2539,7 +2511,6 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,pe->pe_number);/* The PE will reserve all possible 32-bits space */-pe->tce32_seg=0;pe_info(pe,"Setting up 32-bit TCE table at 0..%08x\n",phb->ioda.m32_pci_base);
@@ -2570,24 +2538,32 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,staticvoidpnv_ioda_setup_dma(structpnv_phb*phb){structpci_controller*hose=phb->hose;-unsignedintresidual,remaining,segs,tw,base;+unsignedintweight,total_weight,dma_pe_count;+unsignedintresidual,remaining,segs,base;structpnv_ioda_pe*pe;+total_weight=pnv_pci_ioda_total_dma_weight(phb);+dma_pe_count=0;+list_for_each_entry(pe,&phb->ioda.pe_list,list){+weight=pnv_pci_ioda_pe_dma_weight(pe);+if(weight>0)+dma_pe_count++;+}+/* If we have more PE# than segments available, hand out one*perPEuntilwerunoutandlettherestfail.Ifnot,*thenweassignatleastonesegmentperPE,plusmorebased*ontheamountofdevicesunderthatPE*/-if(phb->ioda.dma_pe_count>phb->ioda.tce32_count)+if(dma_pe_count>phb->ioda.tce32_count)residual=0;else-residual=phb->ioda.tce32_count--phb->ioda.dma_pe_count;+residual=phb->ioda.tce32_count-dma_pe_count;pr_info("PCI: Domain %04x has %ld available 32-bit DMA segments\n",hose->global_number,phb->ioda.tce32_count);pr_info("PCI: %d PE# for a total weight of %d\n",-phb->ioda.dma_pe_count,phb->ioda.dma_weight);+dma_pe_count,total_weight);pnv_pci_ioda_setup_opal_tce_kill(phb);
@@ -53,14 +53,7 @@ struct pnv_ioda_pe {/* PE number */unsignedintpe_number;-/* "Weight" assigned to the PE for the sake of DMA resource-*allocations-*/-unsignedintdma_weight;-/* "Base" iommu table, ie, 4K TCEs, 32-bit DMA */-inttce32_seg;-inttce32_segcount;structiommu_table_grouptable_group;/* 64-bit TCE bypass region */
@@ -78,7 +71,6 @@ struct pnv_ioda_pe {structlist_headslaves;/* Link in list of PE#s */-structlist_headdma_link;structlist_headlist;};
@@ -173,17 +165,6 @@ struct pnv_phb {/* 32-bit TCE tables allocation */unsignedlongtce32_count;-/* Total "weight" for the sake of DMA resources-*allocation-*/-unsignedintdma_weight;-unsignedintdma_pe_count;--/* Sorted list of used PE's, sorted at-*bootforresourceallocationpurposes-*/-structlist_headpe_dma_list;-/* TCE cache invalidate registers (physical and*remapped)*/
Each PHB maintains an array helping to translate 2-bytes Request
ID (RID) to PE# with the assumption that PE# takes one byte, meaning
that we can't have more than 256 PEs. However, pci_dn->pe_number
already had 4-bytes for the PE#.
This extends the PE# capacity for every PHB. After that, the PE number
is represented by 4-bytes value. Then we can reuse IODA_INVALID_PE to
check the PE# in phb->pe_rmap[] is valid or not.
Signed-off-by: Gavin Shan <redacted>
Reviewed-by: Daniel Axtens <redacted>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 6 +++++-
arch/powerpc/platforms/powernv/pci.h | 7 ++-----
2 files changed, 7 insertions(+), 6 deletions(-)
In current implementation, the PEs that are allocated or picked
from the reserved list are identified by PE number. The PE instance
has to be picked according to the PE number eventually. We have
same issue when PE is released.
For pnv_ioda_pick_m64_pe() and pnv_ioda_alloc_pe(), this returns
PE instance so that pnv_ioda_setup_bus_PE() can use the allocated
or reserved PE instance directly. Also, pnv_ioda_setup_bus_PE()
returns the reserved/allocated PE instance to be used in subsequent
patches. On the other hand, pnv_ioda_free_pe() uses PE instance
(not number) as its argument. No logical changes introduced.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 104 +++++++++++++++++-------------
arch/powerpc/platforms/powernv/pci.h | 2 +-
2 files changed, 59 insertions(+), 47 deletions(-)
@@ -119,6 +119,14 @@ static inline bool pnv_pci_is_mem_pref_64(unsigned long flags)(IORESOURCE_MEM_64|IORESOURCE_PREFETCH));}+staticstructpnv_ioda_pe*pnv_ioda_init_pe(structpnv_phb*phb,intpe_no)+{+phb->ioda.pe_array[pe_no].phb=phb;+phb->ioda.pe_array[pe_no].pe_number=pe_no;++return&phb->ioda.pe_array[pe_no];+}+staticvoidpnv_ioda_reserve_pe(structpnv_phb*phb,intpe_no){if(!(pe_no>=0&&pe_no<phb->ioda.total_pe_num)){
@@ -131,11 +139,10 @@ static void pnv_ioda_reserve_pe(struct pnv_phb *phb, int pe_no)pr_debug("%s: PE %d was reserved on PHB#%x\n",__func__,pe_no,phb->hose->global_number);-phb->ioda.pe_array[pe_no].phb=phb;-phb->ioda.pe_array[pe_no].pe_number=pe_no;+pnv_ioda_init_pe(phb,pe_no);}-staticintpnv_ioda_alloc_pe(structpnv_phb*phb)+staticstructpnv_ioda_pe*pnv_ioda_alloc_pe(structpnv_phb*phb){unsignedlongpe;
@@ -143,20 +150,20 @@ static int pnv_ioda_alloc_pe(struct pnv_phb *phb)pe=find_next_zero_bit(phb->ioda.pe_alloc,phb->ioda.total_pe_num,0);if(pe>=phb->ioda.total_pe_num)-returnIODA_INVALID_PE;+returnNULL;}while(test_and_set_bit(pe,phb->ioda.pe_alloc));-phb->ioda.pe_array[pe].phb=phb;-phb->ioda.pe_array[pe].pe_number=pe;-returnpe;+returnpnv_ioda_init_pe(phb,pe);}-staticvoidpnv_ioda_free_pe(structpnv_phb*phb,intpe)+staticvoidpnv_ioda_free_pe(structpnv_ioda_pe*pe){-WARN_ON(phb->ioda.pe_array[pe].pdev);+structpnv_phb*phb=pe->phb;-memset(&phb->ioda.pe_array[pe],0,sizeof(structpnv_ioda_pe));-clear_bit(pe,phb->ioda.pe_alloc);+WARN_ON(pe->pdev);++memset(pe,0,sizeof(structpnv_ioda_pe));+clear_bit(pe->pe_number,phb->ioda.pe_alloc);}/* The default M64 BAR is shared by all PEs */
@@ -326,7 +333,7 @@ static int pnv_ioda_pick_m64_pe(struct pci_bus *bus, bool all)/* Root bus shouldn't use M64 */if(pci_is_root_bus(bus))-returnIODA_INVALID_PE;+returnNULL;/* Allocate bitmap */size=_ALIGN_UP(phb->ioda.total_pe_num/8,sizeof(unsignedlong));
@@ -334,7 +341,7 @@ static int pnv_ioda_pick_m64_pe(struct pci_bus *bus, bool all)if(!pe_alloc){pr_warn("%s: Out of memory !\n",__func__);-returnIODA_INVALID_PE;+returnNULL;}/* Figure out reserved PE numbers by the PE */
@@ -997,8 +1002,7 @@ static struct pnv_ioda_pe *pnv_ioda_setup_dev_PE(struct pci_dev *dev)if(pnv_ioda_configure_pe(phb,pe)){/* XXX What do we do here ? */-if(pe_num)-pnv_ioda_free_pe(phb,pe_num);+pnv_ioda_free_pe(pe);pdn->pe_number=IODA_INVALID_PE;pe->pdev=NULL;pci_dev_put(dev);
@@ -1033,28 +1037,26 @@ static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe)*subordinatePCIdevicesandbuses.ThesecondtypeofPEisnormally*orgiriatedbyPCIe-to-PCIbridgeorPLXswitchdownstreamports.*/-staticvoidpnv_ioda_setup_bus_PE(structpci_bus*bus,boolall)+staticstructpnv_ioda_pe*pnv_ioda_setup_bus_PE(structpci_bus*bus,boolall){structpci_controller*hose=pci_bus_to_host(bus);structpnv_phb*phb=hose->private_data;-structpnv_ioda_pe*pe;-intpe_num=IODA_INVALID_PE;+structpnv_ioda_pe*pe=NULL;/* Check if PE is determined by M64 */if(phb->pick_m64_pe)-pe_num=phb->pick_m64_pe(bus,all);+pe=phb->pick_m64_pe(bus,all);/* The PE number isn't pinned by M64 */-if(pe_num==IODA_INVALID_PE)-pe_num=pnv_ioda_alloc_pe(phb);+if(!pe)+pe=pnv_ioda_alloc_pe(phb);-if(pe_num==IODA_INVALID_PE){+if(!pe){pr_warning("%s: Not enough PE# available for PCI bus %04x:%02x\n",__func__,pci_domain_nr(bus),bus->number);-return;+returnNULL;}-pe=&phb->ioda.pe_array[pe_num];pe->flags|=(all?PNV_IODA_PE_BUS_ALL:PNV_IODA_PE_BUS);pe->pbus=bus;pe->pdev=NULL;
@@ -1063,17 +1065,16 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, bool all)if(all)pe_info(pe,"Secondary bus %d..%d associated with PE#%d\n",-bus->busn_res.start,bus->busn_res.end,pe_num);+bus->busn_res.start,bus->busn_res.end,pe->pe_number);elsepe_info(pe,"Secondary bus %d associated with PE#%d\n",-bus->busn_res.start,pe_num);+bus->busn_res.start,pe->pe_number);if(pnv_ioda_configure_pe(phb,pe)){/* XXX What do we do here ? */-if(pe_num)-pnv_ioda_free_pe(phb,pe_num);+pnv_ioda_free_pe(pe);pe->pbus=NULL;-return;+returnNULL;}/* Associate it with all child devices */
@@ -1081,6 +1082,8 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, bool all)/* Put PE to the list */list_add_tail(&pe->list,&phb->ioda.pe_list);++returnpe;}staticstructpnv_ioda_pe*pnv_ioda_setup_npu_PE(structpci_dev*npu_pdev)
@@ -1479,8 +1486,7 @@ static void pnv_ioda_setup_vf_PE(struct pci_dev *pdev, u16 num_vfs)if(pnv_ioda_configure_pe(phb,pe)){/* XXX What do we do here ? */-if(pe_num)-pnv_ioda_free_pe(phb,pe_num);+pnv_ioda_free_pe(pe);pe->pdev=NULL;continue;}
@@ -1499,6 +1505,7 @@ int pnv_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs)structpci_bus*bus;structpci_controller*hose;structpnv_phb*phb;+structpnv_ioda_pe*pe;structpci_dn*pdn;intret;u16i;
@@ -1541,11 +1548,13 @@ int pnv_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs)/* Calculate available PE for required VFs */if(pdn->m64_single_mode){for(i=0;i<num_vfs;i++){-pdn->pe_num_map[i]=pnv_ioda_alloc_pe(phb);-if(pdn->pe_num_map[i]==IODA_INVALID_PE){+pe=pnv_ioda_alloc_pe(phb);+if(!pe){ret=-EBUSY;gotom64_failed;}++pdn->pe_num_map[i]=pe->pe_number;}}else{mutex_lock(&phb->ioda.pe_alloc_mutex);
@@ -1590,8 +1599,11 @@ int pnv_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs)m64_failed:if(pdn->m64_single_mode){for(i=0;i<num_vfs;i++){-if(pdn->pe_num_map[i]!=IODA_INVALID_PE)-pnv_ioda_free_pe(phb,pdn->pe_num_map[i]);+if(pdn->pe_num_map[i]==IODA_INVALID_PE)+continue;++pe=&phb->ioda.pe_array[pdn->pe_num_map[i]];+pnv_ioda_free_pe(pe);}}elsebitmap_clear(phb->ioda.pe_alloc,*pdn->pe_num_map,num_vfs);
PE number for one particular PE can be allocated dynamically or
reserved according to the consumed M64 (64-bits prefetchable)
segments of the PE. The M64 resources, and hence their segments
and PE number are assigned/reserved in ascending order. The PE
numbers are allocated dynamically in ascending order as well.
It's not a problem as the PE numbers are reserved and then
allocated all at once in fine order. However, it will introduce
conflicts when PCI hotplug is supported: the PE number to be
reserved for newly added PE might have been assigned.
To resolve above conflicts, this forces the PE number to be
allocated dynamically in reverse order. With this patch applied,
the PE numbers are reserved in ascending order, but allocated
dynamically in reverse order.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)
Currently, the PEs and their associated resources are assigned
in ppc_md.pcibios_fixup() except those used by SRIOV VFs. The
function is called for once after PCI probing and resources
assignment is completed. So it isn't hotplug friendly.
This creates PEs dynamically by ppc_md.pcibios_setup_bridge(), which
is called on the event during system bootup and PCI hotplug: updating
PCI bridge's windows after resource assignment/reassignment are done.
For partial hotplug case, where not all PCI devices belonging to the
PE are unplugged and plugged again, we just need unbinding/binding
the affected PCI devices with the corresponding PE without creating
new one.
As there is no upstream bridge for root bus that needs to be covered
by PE, we have to create PE for root bus in ppc_md.pcibios_setup_bridge()
before any other PEs can be created, as PE for root bus is the ancestor
to anyone else.
Also, the windows of root port or the upstream port of PCIe switch behind
root port are extended to be PHB's apertures to accommodate the additional
resources needed by newly plugged devices based on the fact: hotpluggable
slot is behind root port or downstream port of the PCIe switch behind
root port. The extension for those PCI brdiges' windows is done in
ppc_md.pcibios_setup_bridge() as well.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 294 +++++++++++++++++-------------
arch/powerpc/platforms/powernv/pci.h | 2 +
2 files changed, 168 insertions(+), 128 deletions(-)
@@ -1040,9 +1049,26 @@ static struct pnv_ioda_pe *pnv_ioda_setup_bus_PE(struct pci_bus *bus, bool all)structpci_controller*hose=pci_bus_to_host(bus);structpnv_phb*phb=hose->private_data;structpnv_ioda_pe*pe=NULL;+intpe_num;++/*+*Inpartialhotplugcase,thePEinstancemightbestillalive.+*Weshouldreuseitinsteadofallocatinganewone.+*/+pe_num=phb->ioda.pe_rmap[bus->number<<8];+if(pe_num!=IODA_INVALID_PE){+pe=&phb->ioda.pe_array[pe_num];+pnv_ioda_setup_same_PE(bus,pe);+returnNULL;+}++/* PE number for root bus should have been reserved */+if(pci_is_root_bus(bus)&&+phb->ioda.root_pe_idx!=IODA_INVALID_PE)+pe=&phb->ioda.pe_array[phb->ioda.root_pe_idx];/* Check if PE is determined by M64 */-if(phb->pick_m64_pe)+if(!pe&&phb->pick_m64_pe)pe=phb->pick_m64_pe(bus,all);/* The PE number isn't pinned by M64 */
@@ -1185,22 +1187,12 @@ static void pnv_pci_ioda_setup_PEs(void)list_for_each_entry_safe(hose,tmp,&hose_list,list_node){phb=hose->private_data;+if(phb->type!=PNV_PHB_NPU)+continue;-/* M64 layout might affect PE allocation */-if(phb->reserve_m64_pe)-phb->reserve_m64_pe(hose->bus,NULL,true);--/*-*OnNPUPHB,weexpectseparatePEsforindividualPCI-*functions.PCIbusdependentPEsarerequiredforthe-*remainingtypesofPHBs.-*/-if(phb->type==PNV_PHB_NPU){-/* PE#0 is needed for error reporting */-pnv_ioda_reserve_pe(phb,0);-pnv_ioda_setup_npu_PEs(hose->bus);-}else-pnv_ioda_setup_PEs(hose->bus);+/* PE#0 is needed for error reporting */+pnv_ioda_reserve_pe(phb,0);+pnv_ioda_setup_npu_PEs(hose->bus);}}
@@ -2552,8 +2544,13 @@ static void pnv_pci_ioda2_table_free_pages(struct iommu_table *tbl)staticvoidpnv_pci_ioda2_setup_dma_pe(structpnv_phb*phb,structpnv_ioda_pe*pe){+unsignedintweight;int64_trc;+weight=pnv_pci_ioda_pe_dma_weight(pe);+if(!weight)+return;+/* TVE #1 is selected by PCI address bit 59 */pe->tce_bypass_base=1ull<<59;
@@ -2585,49 +2582,6 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,pnv_ioda_setup_bus_dma(pe,pe->pbus);}-staticvoidpnv_ioda_setup_dma(structpnv_phb*phb)-{-structpci_controller*hose=phb->hose;-structpnv_ioda_pe*pe;-unsignedintweight;--/* If we have more PE# than segments available, hand out one-*perPEuntilwerunoutandlettherestfail.Ifnot,-*thenweassignatleastonesegmentperPE,plusmorebased-*ontheamountofdevicesunderthatPE-*/-pr_info("PCI: Domain %04x has %ld available 32-bit DMA segments\n",-hose->global_number,phb->ioda.dma32_count);--pnv_pci_ioda_setup_opal_tce_kill(phb);--/* Walk our PE list and configure their DMA segments */-list_for_each_entry(pe,&phb->ioda.pe_list,list){-weight=pnv_pci_ioda_pe_dma_weight(pe);-if(!weight)-continue;--/*-*ForIODA2compliantPHB3,weneedn'tcareabouttheweight.-*Theallavailable32-bitsDMAspacewillbeassignedto-*thespecificPE.-*/-if(phb->type==PNV_PHB_IODA1){-pnv_pci_ioda1_setup_dma_pe(phb,pe);-}elseif(phb->type==PNV_PHB_IODA2){-pe_info(pe,"Assign DMA32 space\n");-pnv_pci_ioda2_setup_dma_pe(phb,pe);-}elseif(phb->type==PNV_PHB_NPU){-/*-*WeinitialisetheDMAspaceforanNPUPHB-*aftersetupofthePHBiscompleteaswe-*pointtheNPUTVTtothethesamelocation-*asthePHB3TVT.-*/-}-}-}-#ifdef CONFIG_PCI_MSIstaticvoidpnv_ioda2_msi_eoi(structirq_data*d){
@@ -3087,39 +3041,6 @@ static void pnv_ioda_setup_pe_seg(struct pnv_ioda_pe *pe)}}-staticvoidpnv_pci_ioda_setup_seg(void)-{-structpci_controller*tmp,*hose;-structpnv_phb*phb;-structpnv_ioda_pe*pe;--list_for_each_entry_safe(hose,tmp,&hose_list,list_node){-phb=hose->private_data;--/* NPU PHB does not support IO or MMIO segmentation */-if(phb->type==PNV_PHB_NPU)-continue;--list_for_each_entry(pe,&phb->ioda.pe_list,list){-pnv_ioda_setup_pe_seg(pe);-}-}-}--staticvoidpnv_pci_ioda_setup_DMA(void)-{-structpci_controller*hose,*tmp;-structpnv_phb*phb;--list_for_each_entry_safe(hose,tmp,&hose_list,list_node){-pnv_ioda_setup_dma(hose->private_data);--/* Mark the PHB initialization done */-phb=hose->private_data;-phb->initialized=1;-}-}-staticvoidpnv_pci_ioda_create_dbgfs(void){#ifdef CONFIG_DEBUG_FS
@@ -3223,6 +3144,104 @@ static resource_size_t pnv_pci_window_alignment(struct pci_bus *bus,returnphb->ioda.io_segsize;}+/*+*Weareupdatingrootportortheupstreamportofthe+*bridgebehindtherootportwithPHB'swindowsinorder+*toaccommodatethechangesonrequiredresourcesduring+*PCI(slot)hotplug,whichisconnectedtoeitherroot+*portorthedownstreamportsofPCIeswitchbehindthe+*rootport.+*/+staticvoidpnv_pci_fixup_bridge_resources(structpci_bus*bus,+unsignedlongtype)+{+structpci_controller*hose=pci_bus_to_host(bus);+structpnv_phb*phb=hose->private_data;+structpci_dev*bridge=bus->self;+structresource*r,*w;+inti;++/* Check if we need apply fixup to the bridge's windows */+if(!pci_is_root_bus(bridge->bus)&&+!pci_is_root_bus(bridge->bus->self->bus))+return;++/* Fixup the resources */+for(i=0;i<PCI_BRIDGE_RESOURCE_NUM;i++){+r=&bridge->resource[PCI_BRIDGE_RESOURCES+i];+if(!r->flags||!r->parent)+continue;++w=NULL;+if(r->flags&type&IORESOURCE_IO)+w=&hose->io_resource;+elseif(pnv_pci_is_mem_pref_64(r->flags)&&+(type&IORESOURCE_PREFETCH)&&+phb->ioda.m64_segsize)+w=&hose->mem_resources[1];+elseif(r->flags&type&IORESOURCE_MEM)+w=&hose->mem_resources[0];++r->start=w->start;+r->end=w->end;+}+}++staticvoidpnv_pci_setup_bridge(structpci_bus*bus,+unsignedlongtype)+{+structpci_controller*hose=pci_bus_to_host(bus);+structpnv_phb*phb=hose->private_data;+structpci_dev*bridge=bus->self;+structpnv_ioda_pe*pe;+boolall=(pci_pcie_type(bridge)==PCI_EXP_TYPE_PCI_BRIDGE);++/* The PE for root bus should be realized before any one else */+if(!phb->ioda.root_pe_populated){+pe=pnv_ioda_setup_bus_PE(phb->hose->bus,false);+if(pe){+phb->ioda.root_pe_idx=pe->pe_number;+phb->ioda.root_pe_populated=true;+}+}++/* Extend bridge's windows if necessary */+pnv_pci_fixup_bridge_resources(bus,type);++/* Don't assign PE to PCI bus, which doesn't have subordinate devices */+if(list_empty(&bus->devices))+return;++/* Reserve PEs according to used M64 resources */+if(phb->reserve_m64_pe)+phb->reserve_m64_pe(bus,NULL,all);++/*+*AssignPE.Wemightrunherebecauseofpartialhotplug.+*Forthecase,wejustpickuptheexistingPEandshould+*notallocateresourcesagain.+*/+pe=pnv_ioda_setup_bus_PE(bus,all);+if(!pe)+return;++/* Setup MMIO mapping */+pnv_ioda_setup_pe_seg(pe);++/* Setup DMA */+switch(phb->type){+casePNV_PHB_IODA1:+pnv_pci_ioda1_setup_dma_pe(phb,pe);+break;+casePNV_PHB_IODA2:+pnv_pci_ioda2_setup_dma_pe(phb,pe);+break;+default:+pr_warn("%s: No DMA for PHB#%d (type %d)\n",+__func__,phb->hose->global_number,phb->type);+}+}+#ifdef CONFIG_PCI_IOVstaticresource_size_tpnv_pci_iov_resource_alignment(structpci_dev*pdev,intresno)
pnv_pci_ioda_table_free_pages() can be reused to release the IODA1
TCE table when releasing IODA1 PE in subsequent patches.
This renames the following functions to support releasing IODA1 TCE
table: pnv_pci_ioda2_table_free_pages() to pnv_pci_ioda_table_free_pages(),
pnv_pci_ioda2_table_do_free_pages() to pnv_pci_ioda_table_do_free_pages().
No logical changes introduced.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
This support releasing PEs dynamically. Firstly, this moves
pnv_pci_ioda2_release_dma_pe() around, which is called to
release DMA resource on releasing IODA2 PE. Secondly, several
functions are implemented to release the consumed resources
on releasing the PE:
* pnv_pci_ioda1_unset_window() to unset TVEs for the PE.
* pnv_pci_ioda1_release_dma_pe() to unset TVEs for the PE and
destroy the IOMMU table.
* pnv_ioda_release_pe_seg() releases the consumed IO/M32/M64
segments by the PE.
Lastly, this adds a reference count of PE, representing the number
of PCI devices associated with the PE. The reference count is
increased when PCI device joins the PE. It's decreased when PCI
device leaves the PE in pnv_pci_release_device(). When the count
becomes zero, its consumed resources are released by functions
as mentioned above. Note that the count is accessed concurrently.
So a "counter" with "int" type is enough here.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 236 ++++++++++++++++++++++++++----
arch/powerpc/platforms/powernv/pci.h | 1 +
2 files changed, 209 insertions(+), 28 deletions(-)
@@ -119,6 +119,158 @@ static inline bool pnv_pci_is_mem_pref_64(unsigned long flags)(IORESOURCE_MEM_64|IORESOURCE_PREFETCH));}+staticunsignedintpnv_pci_ioda_pe_dma_weight(structpnv_ioda_pe*pe);+staticlongpnv_pci_ioda1_unset_window(structiommu_table_group*table_group,+intnum);+staticvoidpnv_pci_ioda1_release_dma_pe(structpnv_ioda_pe*pe)+{+structiommu_table*tbl;+unsignedintweight=pnv_pci_ioda_pe_dma_weight(pe);+int64_trc;++if(!weight)+return;++tbl=pe->table_group.tables[0];+rc=pnv_pci_ioda1_unset_window(&pe->table_group,0);+if(rc)+pe_warn(pe,"OPAL error %ld release DMA window\n",rc);++if(pe->table_group.group){+iommu_group_put(pe->table_group.group);+WARN_ON(pe->table_group.group);+}++pnv_pci_ioda_table_free_pages(tbl);+iommu_free_table(tbl,"pnv");+}++staticlongpnv_pci_ioda2_unset_window(structiommu_table_group*table_group,+intnum);+staticvoidpnv_pci_ioda2_set_bypass(structpnv_ioda_pe*pe,boolenable);+staticvoidpnv_pci_ioda2_release_dma_pe(structpnv_ioda_pe*pe)+{+structiommu_table*tbl;+unsignedintweight=pnv_pci_ioda_pe_dma_weight(pe);+int64_trc;++if(!weight)+return;++tbl=pe->table_group.tables[0];+rc=pnv_pci_ioda2_unset_window(&pe->table_group,0);+if(rc)+pe_warn(pe,"OPAL error %ld release DMA window\n",rc);++pnv_pci_ioda2_set_bypass(pe,false);+if(pe->table_group.group){+iommu_group_put(pe->table_group.group);+WARN_ON(pe->table_group.group);+}++pnv_pci_ioda_table_free_pages(tbl);+iommu_free_table(tbl,"pnv");+}++staticvoidpnv_ioda_release_pe_seg(structpnv_ioda_pe*pe)+{+structpnv_phb*phb=pe->phb;+intwin,index,*segmap=NULL;+int64_trc;++for(win=OPAL_M32_WINDOW_TYPE;win<=OPAL_IO_WINDOW_TYPE;win++){+if(phb->type==PNV_PHB_IODA2&&+(win==OPAL_IO_WINDOW_TYPE||win==OPAL_M64_WINDOW_TYPE))+continue;++switch(win){+caseOPAL_IO_WINDOW_TYPE:+segmap=phb->ioda.io_segmap;+break;+caseOPAL_M32_WINDOW_TYPE:+segmap=phb->ioda.m32_segmap;+break;+caseOPAL_M64_WINDOW_TYPE:+segmap=phb->ioda.m64_segmap;+break;+}++for(index=0;index<phb->ioda.total_pe_num;index++){+if(segmap[index]!=pe->pe_number)+continue;++if(win==OPAL_M64_WINDOW_TYPE)+rc=opal_pci_map_pe_mmio_window(phb->opal_id,+phb->ioda.reserved_pe_idx,win,+index/PNV_IODA1_M64_SEGS,+index%PNV_IODA1_M64_SEGS);+else+rc=opal_pci_map_pe_mmio_window(phb->opal_id,+phb->ioda.reserved_pe_idx,win,+0,index);+if(rc!=OPAL_SUCCESS)+pe_warn(pe,"Error %ld unmapping (%d) segment#%d\n",+rc,win,index);++segmap[index]=IODA_INVALID_PE;+}+}+}++staticintpnv_ioda_deconfigure_pe(structpnv_phb*phb,+structpnv_ioda_pe*pe);+staticvoidpnv_ioda_free_pe(structpnv_ioda_pe*pe);+staticvoidpnv_ioda_release_pe(structpnv_ioda_pe*pe)+{+structpnv_phb*phb=pe->phb;+structpnv_ioda_pe*tmp,*slave;++/* Release slave PEs in compound PE */+if(pe->flags&PNV_IODA_PE_MASTER){+list_for_each_entry_safe(slave,tmp,&pe->slaves,list)+pnv_ioda_release_pe(slave);+}++/* Remove the PE from the list */+list_del(&pe->list);++/* Release DMA segments */+switch(phb->type){+casePNV_PHB_IODA1:+pnv_pci_ioda1_release_dma_pe(pe);+break;+casePNV_PHB_IODA2:+pnv_pci_ioda2_release_dma_pe(pe);+break;+default:+WARN_ON(1);+}++pnv_ioda_release_pe_seg(pe);+pnv_ioda_deconfigure_pe(pe->phb,pe);++pnv_ioda_free_pe(pe);+}++staticvoidpnv_pci_release_device(structpci_dev*pdev)+{+structpci_controller*hose=pci_bus_to_host(pdev->bus);+structpnv_phb*phb=hose->private_data;+structpci_dn*pdn=pci_get_pdn(pdev);+structpnv_ioda_pe*pe;++if(pdev->is_virtfn)+return;++if(!pdn||pdn->pe_number==IODA_INVALID_PE)+return;++pe=&phb->ioda.pe_array[pdn->pe_number];+WARN_ON(--pe->device_count<0);+if(pe->device_count==0)+pnv_ioda_release_pe(pe);+}+staticstructpnv_ioda_pe*pnv_ioda_init_pe(structpnv_phb*phb,intpe_no){phb->ioda.pe_array[pe_no].phb=phb;
@@ -715,7 +867,6 @@ static int pnv_ioda_set_peltv(struct pnv_phb *phb,return0;}-#ifdef CONFIG_PCI_IOVstaticintpnv_ioda_deconfigure_pe(structpnv_phb*phb,structpnv_ioda_pe*pe){structpci_dev*parent;
@@ -1095,9 +1250,8 @@ static struct pnv_ioda_pe *pnv_ioda_setup_bus_PE(struct pci_bus *bus, bool all)bus->busn_res.start,pe->pe_number);if(pnv_ioda_configure_pe(phb,pe)){-/* XXX What do we do here ? */-pnv_ioda_free_pe(pe);pe->pbus=NULL;+pnv_ioda_release_pe(pe);returnNULL;}
@@ -263,10 +263,10 @@ static inline struct eeh_dev *pdn_to_eeh_dev(struct pci_dn *pdn)externstructpci_bus*pcibios_find_pci_bus(structdevice_node*dn);/** Remove all of the PCI devices under this bus */-externvoidpcibios_remove_pci_devices(structpci_bus*bus);+externvoidpci_remove_pci_devices(structpci_bus*bus);/** Discover new pci devices under this bus, and add them */-externvoidpcibios_add_pci_devices(structpci_bus*bus);+externvoidpci_add_pci_devices(structpci_bus*bus);externvoidisa_bridge_find_early(structpci_controller*hose);
@@ -38,20 +38,20 @@ void pcibios_release_device(struct pci_dev *dev)}/**-*pcibios_remove_pci_devices-removealldevicesunderthisbus+*pci_remove_pci_devices-removealldevicesunderthisbus*@bus:theindicatedPCIbus**RemoveallofthePCIdevicesunderthisbusbothfromthe*linuxpcidevicetree,andfromthepowerpcEEHaddresscache.*/-voidpcibios_remove_pci_devices(structpci_bus*bus)+voidpci_remove_pci_devices(structpci_bus*bus){structpci_dev*dev,*tmp;structpci_bus*child_bus;/* First go down child busses */list_for_each_entry(child_bus,&bus->children,node)-pcibios_remove_pci_devices(child_bus);+pci_remove_pci_devices(child_bus);pr_debug("PCI: Removing devices on bus %04x:%02x\n",pci_domain_nr(bus),bus->number);
@@ -260,7 +260,7 @@ static inline struct eeh_dev *pdn_to_eeh_dev(struct pci_dn *pdn)#endif/** Find the bus corresponding to the indicated device node */-externstructpci_bus*pcibios_find_pci_bus(structdevice_node*dn);+externstructpci_bus*pci_find_bus_by_node(structdevice_node*dn);/** Remove all of the PCI devices under this bus */externvoidpci_remove_pci_devices(structpci_bus*bus);
@@ -175,7 +175,7 @@ static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)structpci_dev*dev;structpci_controller*phb;-if(pcibios_find_pci_bus(dn))+if(pci_find_bus_by_node(dn))return-EINVAL;/* Add pci bus */
@@ -212,7 +212,7 @@ static int dlpar_remove_phb(char *drc_name, struct device_node *dn)structpci_dn*pdn;intrc=0;-if(!pcibios_find_pci_bus(dn))+if(!pci_find_bus_by_node(dn))return-EINVAL;/* If pci slot is hotpluggable, use hotplug to remove it */
@@ -356,7 +356,7 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)pci_lock_rescan_remove();-bus=pcibios_find_pci_bus(dn);+bus=pci_find_bus_by_node(dn);if(!bus){ret=-EINVAL;gotoout;
@@ -93,7 +93,7 @@ int rpaphp_enable_slot(struct slot *slot)if(rc)returnrc;-bus=pcibios_find_pci_bus(slot->dn);+bus=pci_find_bus_by_node(slot->dn);if(!bus){err("%s: no pci_bus for dn %s\n",__func__,slot->dn->full_name);return-EINVAL;
This moves pci_find_bus_by_node() from arch/powerpc/platforms/
pseries/pci_dlpar.c to arch/powerpc/kernel/pci-hotplug.c so that
the function can be used by pSeries and PowerNV platform at the
same time. Also, below cleanup applied. No functional changes
introduced.
* Remove variable "busdn" in find_bus_among_children()
* Use PCI_DN() to convert device node to pci_dn
Signed-off-by: Gavin Shan <redacted>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---
arch/powerpc/kernel/pci-hotplug.c | 29 ++++++++++++++++++++++++++++
arch/powerpc/platforms/pseries/pci_dlpar.c | 31 ------------------------------
2 files changed, 29 insertions(+), 31 deletions(-)
This renames update_dn_pci_info() to pci_add_device_node_info()
with corresponding adjustment on the parameter type and exports it.
The function is used to create pdn (struct pci_dn) for the indicated
device node. Another function add_pdn(), almost wrapper of
pci_add_device_node_info(), to be used in traverse_pci_devices(). No
logical changes introduced.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/include/asm/pci-bridge.h | 3 ++-
arch/powerpc/kernel/pci_dn.c | 30 +++++++++++++++++++-----------
arch/powerpc/platforms/pseries/setup.c | 2 +-
3 files changed, 22 insertions(+), 13 deletions(-)
@@ -446,8 +455,7 @@ void pci_devs_phb_init_dynamic(struct pci_controller *phb)structpci_dn*pdn;/* PHB nodes themselves must not match */-update_dn_pci_info(dn,phb);-pdn=dn->data;+pdn=pci_add_device_node_info(phb,dn);if(pdn){pdn->devfn=pdn->busno=-1;pdn->vendor_id=pdn->device_id=pdn->class_code=0;
@@ -456,7 +464,7 @@ void pci_devs_phb_init_dynamic(struct pci_controller *phb)}/* Update dn->phb ptrs for new phb and children devices */-traverse_pci_devices(dn,update_dn_pci_info,phb);+traverse_pci_devices(dn,add_pdn,phb);}/**
This implements and exports pci_remove_device_node_info(). It's
used to remove the pdn (struct pci_dn) for the indicated device
node. The function is going to be used by PowerNV PCI hotplug
driver.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/include/asm/pci-bridge.h | 1 +
arch/powerpc/kernel/pci_dn.c | 23 +++++++++++++++++++++++
2 files changed, 24 insertions(+)
This renames traverse_pci_devices() to pci_traverse_device_nodes().
The function traverses all subordinate device nodes of the specified
one. Also, below cleanup applied to the function. No logical changes
introduced.
* Rename "pre" to "fn".
* Avoid assignment in if condition reported from checkpatch.pl.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/include/asm/ppc-pci.h | 6 +++---
arch/powerpc/kernel/pci_dn.c | 15 ++++++++++-----
arch/powerpc/platforms/pseries/msi.c | 4 ++--
3 files changed, 15 insertions(+), 10 deletions(-)
@@ -33,9 +33,9 @@ extern struct pci_dev *isa_bridge_pcidev; /* may be NULL if no ISA bus */structdevice_node;structpci_dn;-typedefvoid*(*traverse_func)(structdevice_node*me,void*data);-void*traverse_pci_devices(structdevice_node*start,traverse_funcpre,-void*data);+void*pci_traverse_device_nodes(structdevice_node*start,+void*(*fn)(structdevice_node*,void*),+void*data);void*traverse_pci_dn(structpci_dn*root,void*(*fn)(structpci_dn*,void*),void*data);
@@ -388,8 +389,11 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,if(classp)class=of_read_number(classp,1);-if(pre&&((ret=pre(dn,data))!=NULL))-returnret;+if(fn){+ret=fn(dn,data);+if(ret)+returnret;+}/* If we are a PCI bridge, go down */if(dn->child&&((class>>8)==PCI_CLASS_BRIDGE_PCI||
@@ -487,7 +492,7 @@ void pci_devs_phb_init_dynamic(struct pci_controller *phb)}/* Update dn->phb ptrs for new phb and children devices */-traverse_pci_devices(dn,add_pdn,phb);+pci_traverse_device_nodes(dn,add_pdn,phb);}/**
@@ -305,7 +305,7 @@ static int msi_quota_for_device(struct pci_dev *dev, int request)memset(&counts,0,sizeof(structmsi_counts));/* Work out how many devices we have below this PE */-traverse_pci_devices(pe_dn,count_non_bridge_devices,&counts);+pci_traverse_device_nodes(pe_dn,count_non_bridge_devices,&counts);if(counts.num_devices==0){pr_err("rtas_msi: found 0 devices under PE for %s\n",
@@ -320,7 +320,7 @@ static int msi_quota_for_device(struct pci_dev *dev, int request)/* else, we have some more calculating to do */counts.requestor=pci_device_to_OF_node(dev);counts.request=request;-traverse_pci_devices(pe_dn,count_spare_msis,&counts);+pci_traverse_device_nodes(pe_dn,count_spare_msis,&counts);/* If the quota isn't an integer multiple of the total, we can*usetheremainderasspareMSIsforanyonethatwantsthem.*/
The pdn (struct pci_dn) instances are allocated from memblock or
bootmem when creating PCI controller (hoses) in setup_arch(). PCI
hotplug, which will be supported by proceeding patches, releases
PCI device nodes and their corresponding pdn on unplugging event.
The memory chunks for pdn instances allocated from memblock or
bootmem are hard to reused after being released.
This delays creating pdn by pci_devs_phb_init() from setup_arch()
to core_initcall() so that they are allocated from slab. The memory
consumed by pdn can be released to system without problem during
PCI unplugging time. It indicates that pci_dn is unavailable in
setup_arch() and the the fixup on pdn (like AGP's) can't be carried
out that time. We have to do that in ppc_md.pcibios_root_bridge_prepare()
on maple/pasemi/powermac platforms where/when the pdn is available.
At the mean while, the EEH device is created when pdn is populated,
meaning pdn and EEH device have same life cycle. In turn, we needn't
call eeh_dev_init() to create EEH device explicitly.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/include/asm/eeh.h | 2 +-
arch/powerpc/include/asm/ppc-pci.h | 2 --
arch/powerpc/kernel/eeh_dev.c | 17 +++------------
arch/powerpc/kernel/pci_dn.c | 23 ++++++++++++++++----
arch/powerpc/platforms/maple/pci.c | 34 ++++++++++++++++++------------
arch/powerpc/platforms/pasemi/pci.c | 3 ---
arch/powerpc/platforms/powermac/pci.c | 38 +++++++++++++++++++++-------------
arch/powerpc/platforms/powernv/pci.c | 3 ---
arch/powerpc/platforms/pseries/setup.c | 6 +-----
9 files changed, 69 insertions(+), 59 deletions(-)
@@ -81,16 +80,8 @@ void *eeh_dev_init(struct pci_dn *pdn, void *data)*/voideeh_dev_phb_init_dynamic(structpci_controller*phb){-structpci_dn*root=phb->pci_data;-/* EEH PE for PHB */eeh_phb_pe_create(phb);--/* EEH device for PHB */-eeh_dev_init(root,phb);--/* EEH devices for children OF nodes */-traverse_pci_dn(root,eeh_dev_init,phb);}/**
@@ -106,8 +97,6 @@ static int __init eeh_dev_phb_init(void)list_for_each_entry_safe(phb,tmp,&hose_list,list_node)eeh_dev_phb_init_dynamic(phb);-pr_info("EEH: devices created\n");-return0;}
@@ -504,15 +515,19 @@ void pci_devs_phb_init_dynamic(struct pci_controller *phb)*pcidevicefoundunderneath.Thisroutinerunsonce,*earlyinthebootsequence.*/-void__initpci_devs_phb_init(void)+staticint__initpci_devs_phb_init(void){structpci_controller*phb,*tmp;/* This must be done first so the device nodes have valid pci info! */list_for_each_entry_safe(phb,tmp,&hose_list,list_node)pci_devs_phb_init_dynamic(phb);++return0;}+core_initcall(pci_devs_phb_init);+staticvoidpci_dev_pdn_setup(structpci_dev*pdev){structpci_dn*pdn;
@@ -568,6 +568,26 @@ void maple_pci_irq_fixup(struct pci_dev *dev)DBG(" <- maple_pci_irq_fixup\n");}+staticintmaple_pci_root_bridge_prepare(structpci_host_bridge*bridge)+{+structpci_controller*hose=pci_bus_to_host(bridge->bus);+structdevice_node*np,*child;++if(hose!=u3_agp)+return0;++/* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We+*assumethereisnoP2PbridgeontheAGPbus,whichshouldbea+*safeassumptionshopefully.+*/+np=hose->dn;+PCI_DN(np)->busno=0xf0;+for_each_child_of_node(np,child)+PCI_DN(child)->busno=0xf0;++return0;+}+void__initmaple_pci_init(void){structdevice_node*np,*root;
@@ -605,19 +625,7 @@ void __init maple_pci_init(void)if(ht&&maple_add_bridge(ht)!=0)of_node_put(ht);-/* Setup the linkage between OF nodes and PHBs */-pci_devs_phb_init();--/* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We-*assumethereisnoP2PbridgeontheAGPbus,whichshouldbea-*safeassumptionshopefully.-*/-if(u3_agp){-structdevice_node*np=u3_agp->dn;-PCI_DN(np)->busno=0xf0;-for(np=np->child;np;np=np->sibling)-PCI_DN(np)->busno=0xf0;-}+ppc_md.pcibios_root_bridge_prepare=maple_pci_root_bridge_prepare;/* Tell pci.c to not change any resource allocations. */pci_add_flags(PCI_PROBE_ONLY);
@@ -229,9 +229,6 @@ void __init pas_pci_init(void)of_node_get(np);of_node_put(root);--/* Setup the linkage between OF nodes and PHBs */-pci_devs_phb_init();}void__iomem*pasemi_pci_getcfgaddr(structpci_dev*dev,intoffset)
@@ -878,6 +878,29 @@ void pmac_pci_irq_fixup(struct pci_dev *dev)#endif /* CONFIG_PPC32 */}+#ifdef CONFIG_PPC64+staticintpmac_pci_root_bridge_prepare(structpci_host_bridge*bridge)+{+structpci_controller*hose=pci_bus_to_host(bridge->bus);+structdevice_node*np,*child;++if(hose!=u3_agp)+return0;++/* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We+*assumethereisnoP2PbridgeontheAGPbus,whichshouldbea+*safeassumptionsfornow.Weshoulddosomethingbetterinthe+*futurethough+*/+np=hose->dn;+PCI_DN(np)->busno=0xf0;+for_each_child_of_node(np,child)+PCI_DN(child)->busno=0xf0;++return0;+}+#endif /* CONFIG_PPC64 */+void__initpmac_pci_init(void){structdevice_node*np,*root;
@@ -914,20 +937,7 @@ void __init pmac_pci_init(void)if(ht&&pmac_add_bridge(ht)!=0)of_node_put(ht);-/* Setup the linkage between OF nodes and PHBs */-pci_devs_phb_init();--/* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We-*assumethereisnoP2PbridgeontheAGPbus,whichshouldbea-*safeassumptionsfornow.Weshoulddosomethingbetterinthe-*futurethough-*/-if(u3_agp){-structdevice_node*np=u3_agp->dn;-PCI_DN(np)->busno=0xf0;-for(np=np->child;np;np=np->sibling)-PCI_DN(np)->busno=0xf0;-}+ppc_md.pcibios_root_bridge_prepare=pmac_pci_root_bridge_prepare;/* pmac_check_ht_link(); */#else /* CONFIG_PPC64 */
In hotplug case, function pci_add_pci_devices() is called to rescan
the specified PCI bus, which might not have any child devices. Access
to the PCI bus's child device node will cause kernel crash without
exception.
This adds one more check to skip scanning PCI bus that doesn't have
any subordinate devices from device-tree, in order to avoid kernel
crash.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/kernel/pci-hotplug.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
On the PCI plugging event, PCI slot's subordinate devices are
scanned and their (IO and MMIO) resources are assigned. Platform
dependent resources (PE#, IO/MMIO/DMA windows) are allocated or
created on updating windows of the slot's upstream bridge.
This updates the windows of the hot plugged slot's upstream bridge
in pcibios_finish_adding_to_bus() so that the platform resources
(PE#, IO/MMIO/DMA segments) are allocated or created accordingly.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/kernel/pci-common.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
This drops unnecessary nested if statements in pnv_eeh_reset() to
improve the code readability. After the changes, the unused local
variable "ret" is dropped as well. No logical changes introduced.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/eeh-powernv.c | 67 +++++++++++++---------------
1 file changed, 31 insertions(+), 36 deletions(-)
The function pnv_pci_reset_secondary_bus() is called like below.
It's impossible for call the function on root bus. So it's safe
to remove the root bus case in the function. No functional changes
introduced.
pci_parent_bus_reset() / pci_bus_reset() / pci_try_reset_bus()
pci_reset_bridge_secondary_bus()
pcibios_reset_secondary_bus()
pnv_pci_reset_secondary_bus()
Signed-off-by: Gavin Shan <redacted>
Reviewed-by: Daniel Axtens <redacted>
---
arch/powerpc/platforms/powernv/eeh-powernv.c | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
In pnv_pci_reset_secondary_bus(), we should issue fundamental reset
if any one subordinate device of the specified bus is requesting that.
Otherwise, the device might not come up after the reset.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/eeh-powernv.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
PowerNV platforms runs on top of skiboot firmware that includes
changes to support PCI slots. PCI slots are identified by PHB's
ID or the combo of that and PCI slot ID.
This changes the EEH PowerNV backend to support PCI slots:
* Rename arguments of opal_pci_reset() and opal_pci_poll().
* One more argument (PCI slot's state) added to opal_pci_poll().
* Drop pnv_eeh_phb_poll() and introduce a enhanced similar
function pnv_pci_poll() that will be used by PowerNV hotplug
backends.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/include/asm/opal.h | 4 +--
arch/powerpc/platforms/powernv/eeh-powernv.c | 42 ++++++----------------------
arch/powerpc/platforms/powernv/pci.c | 21 ++++++++++++++
arch/powerpc/platforms/powernv/pci.h | 1 +
4 files changed, 32 insertions(+), 36 deletions(-)
@@ -717,28 +717,11 @@ static int pnv_eeh_get_state(struct eeh_pe *pe, int *delay)returnret;}-statics64pnv_eeh_phb_poll(structpnv_phb*phb)-{-s64rc=OPAL_HARDWARE;--while(1){-rc=opal_pci_poll(phb->opal_id);-if(rc<=0)-break;--if(system_state<SYSTEM_RUNNING)-udelay(1000*rc);-else-msleep(rc);-}--returnrc;-}-intpnv_eeh_phb_reset(structpci_controller*hose,intoption){structpnv_phb*phb=hose->private_data;s64rc=OPAL_HARDWARE;+intret;pr_debug("%s: Reset PHB#%x, option=%d\n",__func__,hose->global_number,option);
@@ -753,8 +736,6 @@ int pnv_eeh_phb_reset(struct pci_controller *hose, int option)rc=opal_pci_reset(phb->opal_id,OPAL_RESET_PHB_COMPLETE,OPAL_DEASSERT_RESET);-if(rc<0)-gotoout;/**PollstateofthePHBuntiltherequestisdone
@@ -762,24 +743,22 @@ int pnv_eeh_phb_reset(struct pci_controller *hose, int option)*resetfollowedbyhotresetonrootbus.Sowealso*needthePCIbussettlementdelay.*/-rc=pnv_eeh_phb_poll(phb);-if(option==EEH_RESET_DEACTIVATE){+ret=pnv_pci_poll(phb->opal_id,rc,NULL);+if(option==EEH_RESET_DEACTIVATE&&!ret){if(system_state<SYSTEM_RUNNING)udelay(1000*EEH_PE_RST_SETTLE_TIME);elsemsleep(EEH_PE_RST_SETTLE_TIME);}-out:-if(rc!=OPAL_SUCCESS)-return-EIO;-return0;+returnret;}staticintpnv_eeh_root_reset(structpci_controller*hose,intoption){structpnv_phb*phb=hose->private_data;s64rc=OPAL_HARDWARE;+intret;pr_debug("%s: Reset PHB#%x, option=%d\n",__func__,hose->global_number,option);
@@ -801,18 +780,13 @@ static int pnv_eeh_root_reset(struct pci_controller *hose, int option)rc=opal_pci_reset(phb->opal_id,OPAL_RESET_PCI_HOT,OPAL_DEASSERT_RESET);-if(rc<0)-gotoout;/* Poll state of the PHB until the request is done */-rc=pnv_eeh_phb_poll(phb);-if(option==EEH_RESET_DEACTIVATE)+ret=pnv_pci_poll(phb->opal_id,rc,NULL);+if(option==EEH_RESET_DEACTIVATE&&!ret)msleep(EEH_PE_RST_SETTLE_TIME);-out:-if(rc!=OPAL_SUCCESS)-return-EIO;-return0;+returnret;}staticintpnv_eeh_bridge_reset(structpci_dev*dev,intoption)
The skiboot firmware might provide the PCI slot reset capability
which is identified by property "ibm,reset-by-firmware" on the
PCI slot associated device node.
This checks the property. If it exists, the reset request is routed
to firmware. Otherwise, the reset is done by kernel as before.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/eeh-powernv.c | 41 +++++++++++++++++++++++++++-
1 file changed, 40 insertions(+), 1 deletion(-)
@@ -789,7 +789,7 @@ static int pnv_eeh_root_reset(struct pci_controller *hose, int option)returnret;}-staticintpnv_eeh_bridge_reset(structpci_dev*dev,intoption)+staticint__pnv_eeh_bridge_reset(structpci_dev*dev,intoption){structpci_dn*pdn=pci_get_pdn_by_devfn(dev->bus,dev->devfn);structeeh_dev*edev=pdn_to_eeh_dev(pdn);
@@ -840,6 +840,45 @@ static int pnv_eeh_bridge_reset(struct pci_dev *dev, int option)return0;}+staticintpnv_eeh_bridge_reset(structpci_dev*pdev,intoption)+{+structpci_controller*hose;+structpnv_phb*phb;+structdevice_node*dn=pdev?pci_device_to_OF_node(pdev):NULL;+uint64_tid=(0x1ul<<60);+uint8_tscope;+int64_trc;++/*+*Ifthefirmwarecan'thandleit,wewillissuehotreset+*onthesecondarybusdespitetherequestedresettype.+*/+if(!dn||!of_get_property(dn,"ibm,reset-by-firmware",NULL))+return__pnv_eeh_bridge_reset(pdev,option);++/* The firmware can handle the request */+switch(option){+caseEEH_RESET_HOT:+scope=OPAL_RESET_PCI_HOT;+break;+caseEEH_RESET_FUNDAMENTAL:+scope=OPAL_RESET_PCI_FUNDAMENTAL;+break;+caseEEH_RESET_DEACTIVATE:+return0;+default:+dev_warn(&pdev->dev,"%s: Unsupported reset %d\n",+__func__,option);+return-EINVAL;+}++hose=pci_bus_to_host(pdev->bus);+phb=hose->private_data;+id|=(pdev->bus->number<<24)|(pdev->devfn<<16)|phb->opal_id;+rc=opal_pci_reset(id,scope,OPAL_ASSERT_RESET);+returnpnv_pci_poll(id,rc,NULL);+}+staticintpnv_pci_dev_reset_type(structpci_dev*pdev,void*data){int*freset=data;
The device tree will change dynamically in PowerNV PCI hotplug
driver. This enables CONFIG_OF_DYNAMIC to support that.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/Kconfig | 1 +
1 file changed, 1 insertion(+)
The function unflatten_dt_node() is called recursively to unflatten
device nodes and properties in the FDT blob. It looks complicated
and hard to be understood.
This splits the function into 3 functions: populate_properties(),
populate_node() and unflatten_dt_node(). populate_properties(),
which is called by populate_node(), creates properties for the
indicated device node. The later one creates the device nodes
from FDT blob. populate_node() gets the offset in FDT blob for
next device nodes and then calls populate_node(). No logical
changes introduced.
Signed-off-by: Gavin Shan <redacted>
---
drivers/of/fdt.c | 249 ++++++++++++++++++++++++++++++++-----------------------
1 file changed, 147 insertions(+), 102 deletions(-)
@@ -161,39 +161,127 @@ static void *unflatten_dt_alloc(void **mem, unsigned long size,returnres;}-/**-*unflatten_dt_node-Allocandpopulateadevice_nodefromtheflattree-*@blob:Theparentdevicetreeblob-*@mem:Memorychunktouseforallocatingdevicenodesandproperties-*@poffset:pointertonodeinflattree-*@dad:Parentstructdevice_node-*@nodepp:Thedevice_nodetreecreatedbythecall-*@fpsize:Sizeofthenodepathupatthecurrentdepth.-*@dryrun:Iftrue,donotallocatedevicenodesbutstillcalculateneeded-*memorysize-*/-staticvoid*unflatten_dt_node(constvoid*blob,-void*mem,-int*poffset,-structdevice_node*dad,-structdevice_node**nodepp,-unsignedlongfpsize,+staticvoidpopulate_properties(constvoid*blob,+intoffset,+void**mem,+structdevice_node*np,+constchar*nodename,booldryrun){-const__be32*p;+structproperty*pp,**pprev=NULL;+intcur;+boolhas_name=false;++pprev=&np->properties;+for(cur=fdt_first_property_offset(blob,offset);+cur>=0;+cur=fdt_next_property_offset(blob,cur)){+const__be32*val;+constchar*pname;+u32sz;++val=fdt_getprop_by_offset(blob,cur,&pname,&sz);+if(!val){+pr_warn("%s: Cannot locate property at 0x%x\n",+__func__,cur);+continue;+}++if(!pname){+pr_warn("%s: Cannot find property name at 0x%x\n",+__func__,cur);+continue;+}++if(!strcmp(pname,"name"))+has_name=true;++pp=unflatten_dt_alloc(mem,sizeof(structproperty),+__alignof__(structproperty));+if(dryrun)+continue;++/* We accept flattened tree phandles either in+*ePAPR-style"phandle"properties,orthe+*legacy"linux,phandle"properties.Ifboth+*appearandhavedifferentvalues,things+*willgetweird.Don'tdothat.+*/+if(!strcmp(pname,"phandle")||+!strcmp(pname,"linux,phandle")){+if(!np->phandle)+np->phandle=be32_to_cpup(val);+}++/* And we process the "ibm,phandle" property+*usedinpSeriesdynamicdevicetree+*stuff+*/+if(!strcmp(pname,"ibm,phandle"))+np->phandle=be32_to_cpup(val);++pp->name=(char*)pname;+pp->length=sz;+pp->value=(__be32*)val;+*pprev=pp;+pprev=&pp->next;+}++/* With version 0x10 we may not have the name property,+*recreateitherefromtheunitnameifabsent+*/+if(!has_name){+constchar*p=nodename,*ps=p,*pa=NULL;+intlen;++while(*p){+if((*p)=='@')+pa=p;+elseif((*p)=='/')+ps=p+1;+p++;+}++if(pa<ps)+pa=p;+len=(pa-ps)+1;+pp=unflatten_dt_alloc(mem,sizeof(structproperty)+len,+__alignof__(structproperty));+if(!dryrun){+pp->name="name";+pp->length=len;+pp->value=pp+1;+*pprev=pp;+pprev=&pp->next;+memcpy(pp->value,ps,len-1);+((char*)pp->value)[len-1]=0;+pr_debug("fixed up name for %s -> %s\n",+nodename,(char*)pp->value);+}+}++if(!dryrun)+*pprev=NULL;+}++staticunsignedlongpopulate_node(constvoid*blob,+intoffset,+void**mem,+structdevice_node*dad,+unsignedlongfpsize,+structdevice_node**pnp,+booldryrun)+{structdevice_node*np;-structproperty*pp,**prev_pp=NULL;constchar*pathp;unsignedintl,allocl;-staticintdepth;-intold_depth;-intoffset;-inthas_name=0;intnew_format=0;-pathp=fdt_get_name(blob,*poffset,&l);-if(!pathp)-returnmem;+pathp=fdt_get_name(blob,offset,&l);+if(!pathp){+*pnp=NULL;+return0;+}allocl=++l;
@@ -246,89 +334,15 @@ static void * unflatten_dt_node(const void *blob,}memcpy(fn,pathp,l);-prev_pp=&np->properties;if(dad!=NULL){np->parent=dad;np->sibling=dad->child;dad->child=np;}}-/* process properties */-for(offset=fdt_first_property_offset(blob,*poffset);-(offset>=0);-(offset=fdt_next_property_offset(blob,offset))){-constchar*pname;-u32sz;-if(!(p=fdt_getprop_by_offset(blob,offset,&pname,&sz))){-offset=-FDT_ERR_INTERNAL;-break;-}--if(pname==NULL){-pr_info("Can't find property name in list !\n");-break;-}-if(strcmp(pname,"name")==0)-has_name=1;-pp=unflatten_dt_alloc(&mem,sizeof(structproperty),-__alignof__(structproperty));-if(!dryrun){-/* We accept flattened tree phandles either in-*ePAPR-style"phandle"properties,orthe-*legacy"linux,phandle"properties.Ifboth-*appearandhavedifferentvalues,things-*willgetweird.Don'tdothat.*/-if((strcmp(pname,"phandle")==0)||-(strcmp(pname,"linux,phandle")==0)){-if(np->phandle==0)-np->phandle=be32_to_cpup(p);-}-/* And we process the "ibm,phandle" property-*usedinpSeriesdynamicdevicetree-*stuff*/-if(strcmp(pname,"ibm,phandle")==0)-np->phandle=be32_to_cpup(p);-pp->name=(char*)pname;-pp->length=sz;-pp->value=(__be32*)p;-*prev_pp=pp;-prev_pp=&pp->next;-}-}-/* with version 0x10 we may not have the name property, recreate-*itherefromtheunitnameifabsent-*/-if(!has_name){-constchar*p1=pathp,*ps=pathp,*pa=NULL;-intsz;--while(*p1){-if((*p1)=='@')-pa=p1;-if((*p1)=='/')-ps=p1+1;-p1++;-}-if(pa<ps)-pa=p1;-sz=(pa-ps)+1;-pp=unflatten_dt_alloc(&mem,sizeof(structproperty)+sz,-__alignof__(structproperty));-if(!dryrun){-pp->name="name";-pp->length=sz;-pp->value=pp+1;-*prev_pp=pp;-prev_pp=&pp->next;-memcpy(pp->value,ps,sz-1);-((char*)pp->value)[sz-1]=0;-pr_debug("fixed up name for %s -> %s\n",pathp,-(char*)pp->value);-}-}+populate_properties(blob,offset,mem,np,pathp,dryrun);if(!dryrun){-*prev_pp=NULL;np->name=of_get_property(np,"name",NULL);np->type=of_get_property(np,"device_type",NULL);
In current implementation, unflatten_dt_node() is called recursively
to unflatten device nodes in FDT blob. It's stress to limited stack
capacity, especially to adopt the function to unflatten device sub-tree
that possibly has multiple root nodes. In that case, we runs out of
stack and the system can't boot up successfully.
In order to reuse the function to unflatten device sub-tree, this avoids
calling the function recursively, meaning the device nodes are unflattened
in one call on unflatten_dt_node(): two arrays are introduced to track the
parent path size and the device node of current level of depth, which will
be used by the device node on next level of depth to be unflattened. All
device nodes in more than 64 level of depth are dropped and hopefully,
the system can boot up successfully with the partial device-tree.
Also, the parameter "poffset" and "fpsize" are unused and dropped and the
parameter "dryrun" is figured out from "mem == NULL". Besides, the return
value of the function is changed to indicate the size of memory consumed by
the unflatten device tree or error code.
Signed-off-by: Gavin Shan <redacted>
---
drivers/of/fdt.c | 122 +++++++++++++++++++++++++++++++++----------------------
1 file changed, 74 insertions(+), 48 deletions(-)
@@ -453,11 +479,12 @@ static void __unflatten_device_tree(const void *blob,}/* First pass, scan for size */-start=0;-size=(unsignedlong)unflatten_dt_node(blob,NULL,&start,NULL,NULL,0,true);-size=ALIGN(size,4);+size=unflatten_dt_node(blob,NULL,NULL,NULL);+if(size<0)+return;-pr_debug(" size is %lx, allocating...\n",size);+size=ALIGN(size,4);+pr_debug(" size is %d, allocating...\n",size);/* Allocate memory for the expanded device tree */mem=dt_alloc(size+4,__alignof__(structdevice_node));
@@ -468,8 +495,7 @@ static void __unflatten_device_tree(const void *blob,pr_debug(" unflattening %p...\n",mem);/* Second pass, do actual unflattening */-start=0;-unflatten_dt_node(blob,mem,&start,NULL,mynodes,0,false);+unflatten_dt_node(blob,mem,NULL,mynodes);if(be32_to_cpup(mem+size)!=0xdeadbeef)pr_warning("End of tree marker overwritten: %08x\n",be32_to_cpup(mem+size));
This adds one more argument to of_fdt_unflatten_tree() to specify
the parent node of the FDT blob that is going to be unflattened.
In the result, the function can be used to unflatten FDT blob that
represents device sub-tree in PowerNV PCI hotplug driver.
Cc: Jyri Sarha <redacted>
Signed-off-by: Gavin Shan <redacted>
---
drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 2 +-
drivers/of/fdt.c | 14 ++++++++++----
drivers/of/unittest.c | 2 +-
include/linux/of_fdt.h | 1 +
4 files changed, 13 insertions(+), 6 deletions(-)
@@ -450,11 +450,13 @@ static int unflatten_dt_nodes(const void *blob,*pointersofthenodessothenormaldevice-treewalkingfunctions*canbeused.*@blob:Theblobtoexpand+*@dad:Parentdevicenode*@mynodes:Thedevice_nodetreecreatedbythecall*@dt_alloc:Anallocatorthatprovidesavirtualaddresstomemory*fortheresultingtree*/staticvoid__unflatten_device_tree(constvoid*blob,+structdevice_node*dad,structdevice_node**mynodes,void*(*dt_alloc)(u64size,u64align)){
@@ -479,7 +481,7 @@ static void __unflatten_device_tree(const void *blob,}/* First pass, scan for size */-size=unflatten_dt_nodes(blob,NULL,NULL,NULL);+size=unflatten_dt_nodes(blob,NULL,dad,NULL);if(size<0)return;
@@ -495,7 +497,7 @@ static void __unflatten_device_tree(const void *blob,pr_debug(" unflattening %p...\n",mem);/* Second pass, do actual unflattening */-unflatten_dt_nodes(blob,mem,NULL,mynodes);+unflatten_dt_nodes(blob,mem,dad,mynodes);if(be32_to_cpup(mem+size)!=0xdeadbeef)pr_warning("End of tree marker overwritten: %08x\n",be32_to_cpup(mem+size));
@@ -1180,7 +1186,7 @@ bool __init early_init_dt_scan(void *params)*/void__initunflatten_device_tree(void){-__unflatten_device_tree(initial_boot_params,&of_root,+__unflatten_device_tree(initial_boot_params,NULL,&of_root,early_init_dt_alloc_memory_arch);/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
@@ -921,7 +921,7 @@ static int __init unittest_data_add(void)"not running tests\n",__func__);return-ENOMEM;}-of_fdt_unflatten_tree(unittest_data,&unittest_data_node);+of_fdt_unflatten_tree(unittest_data,NULL,&unittest_data_node);if(!unittest_data_node){pr_warn("%s: No tree to attach; not running tests\n",__func__);return-ENODATA;
This returns the allocate memory chunk, storing the unflattened device
tree, from of_fdt_unflatten_tree() so that memory chunk can be released
on demand in PowerNV PCI hotplug driver.
Signed-off-by: Gavin Shan <redacted>
Acked-by: Rob Herring <robh@kernel.org>
---
drivers/of/fdt.c | 33 ++++++++++++++++++++++-----------
include/linux/of_fdt.h | 6 +++---
2 files changed, 25 insertions(+), 14 deletions(-)
From: Andrew Donnellan <hidden> Date: 2016-02-17 04:18:42
On 17/02/16 14:43, Gavin Shan wrote:
Each PHB has one instance of "struct pci_controller_ops", which
includes various callbacks called by PCI subsystem. In the definition
of this struct, some callbacks have explicit names for its arguments,
but the left don't have.
This adds all explicit names of the arguments to the callbacks in
"struct pci_controller_ops" so that the code looks consistent.
Signed-off-by: Gavin Shan <redacted>
Reviewed-by: Daniel Axtens <redacted>
Reviewed-by: Andrew Donnellan <redacted>
--
Andrew Donnellan Software Engineer, OzLabs
andrew.donnellan@au1.ibm.com Australia Development Lab, Canberra
+61 2 6201 8874 (work) IBM Australia Limited
From: Andrew Donnellan <hidden> Date: 2016-02-17 04:35:43
On 17/02/16 14:44, Gavin Shan wrote:
This drops unnecessary nested if statements in pnv_eeh_reset() to
improve the code readability. After the changes, the unused local
variable "ret" is dropped as well. No logical changes introduced.
Signed-off-by: Gavin Shan <redacted>
This looks good to me.
Reviewed-by: Andrew Donnellan <redacted>
--
Andrew Donnellan Software Engineer, OzLabs
andrew.donnellan@au1.ibm.com Australia Development Lab, Canberra
+61 2 6201 8874 (work) IBM Australia Limited
From: Andrew Donnellan <hidden> Date: 2016-02-17 04:38:32
On 17/02/16 14:43, Gavin Shan wrote:
This cleans up on below data struct instances to use tab instead of
space indent of statement to avoid complains from scripts/checkpatch.pl.
No logical changes introduced.
@pnv_pci_ioda_controller_ops
@pnv_npu_ioda_controller_ops
Signed-off-by: Gavin Shan <redacted>
Reviewed-by: Daniel Axtens <redacted>
Reviewed-by: Andrew Donnellan <redacted>
--
Andrew Donnellan Software Engineer, OzLabs
andrew.donnellan@au1.ibm.com Australia Development Lab, Canberra
+61 2 6201 8874 (work) IBM Australia Limited
From: Rob Herring <hidden> Date: 2016-02-17 14:30:42
On Tue, Feb 16, 2016 at 9:44 PM, Gavin Shan [off-list ref] wrote:
The function unflatten_dt_node() is called recursively to unflatten
device nodes and properties in the FDT blob. It looks complicated
and hard to be understood.
This splits the function into 3 functions: populate_properties(),
populate_node() and unflatten_dt_node(). populate_properties(),
which is called by populate_node(), creates properties for the
indicated device node. The later one creates the device nodes
from FDT blob. populate_node() gets the offset in FDT blob for
next device nodes and then calls populate_node(). No logical
changes introduced.
Signed-off-by: Gavin Shan <redacted>
---
drivers/of/fdt.c | 249 ++++++++++++++++++++++++++++++++-----------------------
1 file changed, 147 insertions(+), 102 deletions(-)
One nit, otherwise:
Acked-by: Rob Herring <robh@kernel.org>
[...]
+ /* And we process the "ibm,phandle" property
+ * used in pSeries dynamic device tree
+ * stuff
+ */
+ if (!strcmp(pname, "ibm,phandle"))
+ np->phandle = be32_to_cpup(val);
+
+ pp->name = (char *)pname;
+ pp->length = sz;
+ pp->value = (__be32 *)val;
From: Rob Herring <hidden> Date: 2016-02-17 14:53:51
On Tue, Feb 16, 2016 at 9:44 PM, Gavin Shan [off-list ref] wrote:
In current implementation, unflatten_dt_node() is called recursively
to unflatten device nodes in FDT blob. It's stress to limited stack
capacity, especially to adopt the function to unflatten device sub-tree
that possibly has multiple root nodes. In that case, we runs out of
stack and the system can't boot up successfully.
In order to reuse the function to unflatten device sub-tree, this avoids
calling the function recursively, meaning the device nodes are unflattened
in one call on unflatten_dt_node(): two arrays are introduced to track the
parent path size and the device node of current level of depth, which will
be used by the device node on next level of depth to be unflattened. All
device nodes in more than 64 level of depth are dropped and hopefully,
the system can boot up successfully with the partial device-tree.
Also, the parameter "poffset" and "fpsize" are unused and dropped and the
parameter "dryrun" is figured out from "mem == NULL". Besides, the return
value of the function is changed to indicate the size of memory consumed by
the unflatten device tree or error code.
Signed-off-by: Gavin Shan <redacted>
---
drivers/of/fdt.c | 122 +++++++++++++++++++++++++++++++++----------------------
1 file changed, 74 insertions(+), 48 deletions(-)
From: Rob Herring <hidden> Date: 2016-02-17 15:00:31
On Tue, Feb 16, 2016 at 9:44 PM, Gavin Shan [off-list ref] wrote:
This adds one more argument to of_fdt_unflatten_tree() to specify
the parent node of the FDT blob that is going to be unflattened.
In the result, the function can be used to unflatten FDT blob that
represents device sub-tree in PowerNV PCI hotplug driver.
Cc: Jyri Sarha <redacted>
Signed-off-by: Gavin Shan <redacted>
---
drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 2 +-
drivers/of/fdt.c | 14 ++++++++++----
drivers/of/unittest.c | 2 +-
include/linux/of_fdt.h | 1 +
4 files changed, 13 insertions(+), 6 deletions(-)
This adds one more argument to of_fdt_unflatten_tree() to specify
the parent node of the FDT blob that is going to be unflattened.
In the result, the function can be used to unflatten FDT blob that
represents device sub-tree in PowerNV PCI hotplug driver.
Cc: Jyri Sarha <redacted>
Signed-off-by: Gavin Shan <redacted>
---
drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 2 +-
@@ -450,11 +450,13 @@ static int unflatten_dt_nodes(const void *blob,*pointersofthenodessothenormaldevice-treewalkingfunctions*canbeused.*@blob:Theblobtoexpand+*@dad:Parentdevicenode*@mynodes:Thedevice_nodetreecreatedbythecall*@dt_alloc:Anallocatorthatprovidesavirtualaddresstomemory*fortheresultingtree*/staticvoid__unflatten_device_tree(constvoid*blob,+structdevice_node*dad,structdevice_node**mynodes,void*(*dt_alloc)(u64size,u64align)){
@@ -479,7 +481,7 @@ static void __unflatten_device_tree(const void *blob,}/* First pass, scan for size */-size=unflatten_dt_nodes(blob,NULL,NULL,NULL);+size=unflatten_dt_nodes(blob,NULL,dad,NULL);if(size<0)return;
@@ -495,7 +497,7 @@ static void __unflatten_device_tree(const void *blob,pr_debug(" unflattening %p...\n",mem);/* Second pass, do actual unflattening */-unflatten_dt_nodes(blob,mem,NULL,mynodes);+unflatten_dt_nodes(blob,mem,dad,mynodes);if(be32_to_cpup(mem+size)!=0xdeadbeef)pr_warning("End of tree marker overwritten: %08x\n",be32_to_cpup(mem+size));
@@ -1180,7 +1186,7 @@ bool __init early_init_dt_scan(void *params)*/void__initunflatten_device_tree(void){-__unflatten_device_tree(initial_boot_params,&of_root,+__unflatten_device_tree(initial_boot_params,NULL,&of_root,early_init_dt_alloc_memory_arch);/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
@@ -921,7 +921,7 @@ static int __init unittest_data_add(void)"not running tests\n",__func__);return-ENOMEM;}-of_fdt_unflatten_tree(unittest_data,&unittest_data_node);+of_fdt_unflatten_tree(unittest_data,NULL,&unittest_data_node);if(!unittest_data_node){pr_warn("%s: No tree to attach; not running tests\n",__func__);return-ENODATA;
This renames the fields related to PE number in "struct pnv_phb"
for better reflecting of their usages as Alexey suggested. No
logical changes introduced.
Signed-off-by: Gavin Shan <redacted>
@@ -124,7 +124,7 @@ static inline bool pnv_pci_is_mem_pref_64(unsigned long flags)staticvoidpnv_ioda_reserve_pe(structpnv_phb*phb,intpe_no){-if(!(pe_no>=0&&pe_no<phb->ioda.total_pe)){+if(!(pe_no>=0&&pe_no<phb->ioda.total_pe_num)){pr_warn("%s: Invalid PE %d on PHB#%x\n",__func__,pe_no,phb->hose->global_number);return;
@@ -144,8 +144,8 @@ static int pnv_ioda_alloc_pe(struct pnv_phb *phb)do{pe=find_next_zero_bit(phb->ioda.pe_alloc,-phb->ioda.total_pe,0);-if(pe>=phb->ioda.total_pe)+phb->ioda.total_pe_num,0);+if(pe>=phb->ioda.total_pe_num)returnIODA_INVALID_PE;}while(test_and_set_bit(pe,phb->ioda.pe_alloc));
@@ -199,13 +199,13 @@ static int pnv_ioda2_init_m64(struct pnv_phb *phb)*expectedtobe0orlastoneofPEcapabicity.*/r=&phb->hose->mem_resources[1];-if(phb->ioda.reserved_pe==0)+if(phb->ioda.reserved_pe_idx==0)r->start+=phb->ioda.m64_segsize;-elseif(phb->ioda.reserved_pe==(phb->ioda.total_pe-1))+elseif(phb->ioda.reserved_pe_idx==(phb->ioda.total_pe_num-1))r->end-=phb->ioda.m64_segsize;elsepr_warn(" Cannot strip M64 segment for reserved PE#%d\n",-phb->ioda.reserved_pe);+phb->ioda.reserved_pe_idx);return0;
@@ -274,7 +274,7 @@ static int pnv_ioda2_pick_m64_pe(struct pci_bus *bus, bool all)returnIODA_INVALID_PE;/* Allocate bitmap */-size=_ALIGN_UP(phb->ioda.total_pe/8,sizeof(unsignedlong));+size=_ALIGN_UP(phb->ioda.total_pe_num/8,sizeof(unsignedlong));pe_alloc=kzalloc(size,GFP_KERNEL);if(!pe_alloc){pr_warn("%s: Out of memory !\n",
@@ -456,7 +456,7 @@ static int pnv_ioda_get_pe_state(struct pnv_phb *phb, int pe_no)s64rc;/* Sanity check on PE number */-if(pe_no<0||pe_no>=phb->ioda.total_pe)+if(pe_no<0||pe_no>=phb->ioda.total_pe_num)returnOPAL_EEH_STOPPED_PERM_UNAVAIL;/*
@@ -3300,13 +3300,13 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,pr_err(" Failed to map registers !\n");/* Initialize more IODA stuff */-phb->ioda.total_pe=1;+phb->ioda.total_pe_num=1;prop32=of_get_property(np,"ibm,opal-num-pes",NULL);if(prop32)-phb->ioda.total_pe=be32_to_cpup(prop32);+phb->ioda.total_pe_num=be32_to_cpup(prop32);prop32=of_get_property(np,"ibm,opal-reserved-pe",NULL);if(prop32)-phb->ioda.reserved_pe=be32_to_cpup(prop32);+phb->ioda.reserved_pe_idx=be32_to_cpup(prop32);/* Parse 64-bit MMIO range */pnv_ioda_parse_m64_window(phb);
@@ -3315,29 +3315,29 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,/* FW Has already off top 64k of M32 space (MSI space) */phb->ioda.m32_size+=0x10000;-phb->ioda.m32_segsize=phb->ioda.m32_size/phb->ioda.total_pe;+phb->ioda.m32_segsize=phb->ioda.m32_size/phb->ioda.total_pe_num;phb->ioda.m32_pci_base=hose->mem_resources[0].start-hose->mem_offset[0];phb->ioda.io_size=hose->pci_io_size;-phb->ioda.io_segsize=phb->ioda.io_size/phb->ioda.total_pe;+phb->ioda.io_segsize=phb->ioda.io_size/phb->ioda.total_pe_num;phb->ioda.io_pci_base=0;/* XXX calculate this ? *//* Allocate aux data & arrays. We don't have IO ports on PHB3 */-size=_ALIGN_UP(phb->ioda.total_pe/8,sizeof(unsignedlong));+size=_ALIGN_UP(phb->ioda.total_pe_num/8,sizeof(unsignedlong));m32map_off=size;-size+=phb->ioda.total_pe*sizeof(phb->ioda.m32_segmap[0]);+size+=phb->ioda.total_pe_num*sizeof(phb->ioda.m32_segmap[0]);if(phb->type==PNV_PHB_IODA1){iomap_off=size;-size+=phb->ioda.total_pe*sizeof(phb->ioda.io_segmap[0]);+size+=phb->ioda.total_pe_num*sizeof(phb->ioda.io_segmap[0]);}pemap_off=size;-size+=phb->ioda.total_pe*sizeof(structpnv_ioda_pe);+size+=phb->ioda.total_pe_num*sizeof(structpnv_ioda_pe);aux=memblock_virt_alloc(size,0);phb->ioda.pe_alloc=aux;phb->ioda.m32_segmap=aux+m32map_off;if(phb->type==PNV_PHB_IODA1)phb->ioda.io_segmap=aux+iomap_off;phb->ioda.pe_array=aux+pemap_off;-set_bit(phb->ioda.reserved_pe,phb->ioda.pe_alloc);+set_bit(phb->ioda.reserved_pe_idx,phb->ioda.pe_alloc);INIT_LIST_HEAD(&phb->ioda.pe_dma_list);INIT_LIST_HEAD(&phb->ioda.pe_list);
There are two arrays for IO and M32 segment maps on every PHB.
The index of the arrays are segment number and the value stored
in the corresponding element is PE number, indicating the segment
is assigned to the PE. Initially, all elements in those two arrays
are zeroes, meaning all segments are assigned to PE#0. It's wrong.
>
This fixes the initial values in the elements of those two arrays
to IODA_INVALID_PE, meaning all segments aren't assigned to any
PE.
This is ok.
In order to use IODA_INVALID_PE (-1) to represent invalid PE
number, the types of those two arrays are changed from "unsigned int"
to "int".
"unsigned" can carry (-1) perfectly fine, just add a type cast to
IODA_INVALID_PE:
#define IODA_INVALID_PE (unsigned int)(-1)
Using "signed" type for indexes which cannot be negative does not make much
sense - instead of checking for the upper boundary, you have to check for
"< 0" too.
OPAL uses unsigned type for PE (uint64_t or uint32_t or uint16_t - this is
quite funny).
pnv_ioda_pe::pe_number is "unsigned" and this pe_number is the same thing
as I can see in pnv_ioda_setup_dev_PE().
Some printk() print the PE number as "%x" (which implies "unsigned").
I suggest changing the pci_dn::pe_number type from "int" to "unsigned int"
to match pnv_ioda_pe::pe_number, in a separate patch. Or do not touch types
for now.
The original implementation of pnv_ioda_setup_pe_seg() configures
IO and M32 segments by separate logics, which can be merged by
by caching @segmap, @seg_size, @win in advance. This shouldn't
cause any behavioural changes.
@@ -2958,23 +2960,9 @@ static void pnv_ioda_setup_pe_seg(struct pci_controller *hose,if(res->flags&IORESOURCE_IO){region.start=res->start-phb->ioda.io_pci_base;region.end=res->end-phb->ioda.io_pci_base;-index=region.start/phb->ioda.io_segsize;--while(index<phb->ioda.total_pe_num&&-region.start<=region.end){-phb->ioda.io_segmap[index]=pe->pe_number;-rc=opal_pci_map_pe_mmio_window(phb->opal_id,-pe->pe_number,OPAL_IO_WINDOW_TYPE,0,index);-if(rc!=OPAL_SUCCESS){-pr_err("%s: OPAL error %d when mapping IO "-"segment #%d to PE#%d\n",-__func__,rc,index,pe->pe_number);-break;-}--region.start+=phb->ioda.io_segsize;-index++;-}+segsize=phb->ioda.io_segsize;+segmap=phb->ioda.io_segmap;+win=OPAL_IO_WINDOW_TYPE;}elseif((res->flags&IORESOURCE_MEM)&&!pnv_pci_is_mem_pref_64(res->flags)){region.start=res->start-
@@ -2983,23 +2971,29 @@ static void pnv_ioda_setup_pe_seg(struct pci_controller *hose,region.end=res->end-hose->mem_offset[0]-phb->ioda.m32_pci_base;-index=region.start/phb->ioda.m32_segsize;--while(index<phb->ioda.total_pe_num&&-region.start<=region.end){-phb->ioda.m32_segmap[index]=pe->pe_number;-rc=opal_pci_map_pe_mmio_window(phb->opal_id,-pe->pe_number,OPAL_M32_WINDOW_TYPE,0,index);-if(rc!=OPAL_SUCCESS){-pr_err("%s: OPAL error %d when mapping M32 "-"segment#%d to PE#%d",-__func__,rc,index,pe->pe_number);-break;-}+segsize=phb->ioda.m32_segsize;+segmap=phb->ioda.m32_segmap;+win=OPAL_M32_WINDOW_TYPE;+}else{+continue;+}-region.start+=phb->ioda.m32_segsize;-index++;+index=region.start/segsize;+while(index<phb->ioda.total_pe_num&&+region.start<=region.end){+segmap[index]=pe->pe_number;+rc=opal_pci_map_pe_mmio_window(phb->opal_id,+pe->pe_number,win,0,index);+if(rc!=OPAL_SUCCESS){+pr_warn("%s: Error %lld mapping (%d) seg#%d to PHB#%d-PE#%d\n",+__func__,rc,win,index,+pe->phb->hose->global_number,+pe->pe_number);+break;
Please move this loop to a helper and stop caching segsize/segmap/win; this
will make the code easier to read and the next patch will look much cleaner
as it will not have to move this exact loop.
When unplugging PCI devices, their parent PEs might be offline.
The consumed M64 resource by the PEs should be released at that
time. As we track M32 segment consumption, this introduces an
array to the PHB to track the mapping between M64 segment and
PE number.
Signed-off-by: Gavin Shan <redacted>
Reviewed-by: Alexey Kardashevskiy <redacted>
but it would not hurt to mention in the commit log why M64 segment is not
tracked/setup by the existing (at this point, at least)
pnv_ioda_setup_one_res().
@@ -3332,6 +3333,8 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np,/* Allocate aux data & arrays. We don't have IO ports on PHB3 */size=_ALIGN_UP(phb->ioda.total_pe_num/8,sizeof(unsignedlong));+m64map_off=size;+size+=phb->ioda.total_pe_num*sizeof(phb->ioda.m64_segmap[0]);m32map_off=size;size+=phb->ioda.total_pe_num*sizeof(phb->ioda.m32_segmap[0]);if(phb->type==PNV_PHB_IODA1){
This series of patches rebases on powerpc/next branch, plus below additional
patches:
<This series of patches>
<Followup 3 patches from Gavin on SRIOV EEH, which aren't posted>
https://patchwork.ozlabs.org/patch/581315/ (PATCH[1/9] Richard's SRIOV EEH)
https://patchwork.ozlabs.org/patch/582639/ (PATCH[1/1] Gavin's EEH fix)
https://patchwork.ozlabs.org/patch/582093/ (PATCH[1/1] Gavin's EEH fix)
https://patchwork.ozlabs.org/patch/580626/ (PATCH[1/4] Gavin's PCI fix)
https://patchwork.ozlabs.org/patch/580153/ (PATCH[1/1] Andrew's EEH minor fix)
https://patchwork.ozlabs.org/patch/566827/ (PATCH[1/1] Russell's P5IOC2 removal)
https://patchwork.ozlabs.org/patch/534154/ (PATCH[1/7] Richard's SRIOV rework)
commit 388f7b1 ("Linux 4.5-rc3")
The series of patches intend to support PCI slot for PowerPC PowerNV platform,
which is running on top of skiboot firmware. The patchset requires corresponding
changes from skiboot firmware, which is sent to skiboot@lists.ozlabs.org
for review. The PCI slots are exposed by skiboot with device node properties,
and kernel utilizes those properties to populated PCI slots accordingly.
The original PCI infrastructure on PowerNV platform can't support hotplug
because the PE is assigned during PHB fixup time, which is called for once
during system boot time. For this, the PCI infrastructure on PowerNV platform
has been reworked for a lot. After that, the PE and its corresponding resources
(IODT, M32DT, M64 segments, DMA32 and bypass window) are assigned upon updating
PCI bridge's resources, which might decide PE# assigned to the PE (e.g. M64
resources, on P8 strictly speaking). Each PE will maintain a reference count,
which is (number of child PCI devices + 1). That indicates when last child PCI
device leaves the PE, the PE and its included resources will be relased and put
back into free pool again. With this design, the PE will be released when EEH PE
is released. PATCH[1 - 23] are related to this part.
From skiboot perspective, PCI slot is providing (hot/fundamental/complete)
resets to EEH. The kernel gets to know if skiboot supports various reset on one
particular PCI slot through device-tree node. If it does, EEH will utilize the
functionality provided by skiboot. Besides, the device-tree nodes have to change
in order to support PCI hotplug. For example, when one PCI adapter inserted to
one slot, its device-tree node should be added to the system dynamically. Conversely,
the device-tree node should be removed from the system when the PCI adapter is going
to be offline. Since pci_dn and eeh_dev have same life cyle as PCI device nodes,
they should be added/removed accordingly during PCI hotplug. PATCH[24 - 39] are
doing the related work.
The OF driver is changed to support unflattening FDT blob for sub-stree, which
is covered by PATCH[40 - 44].
The last one, PATCH[45], is the standalone PCI hotplug driver for PowerPC PowerNV
platform.
=======
Testing
=======
1. Unplug adapters behind non-empty slot, then plug them.
1.1 Check status
# cat /sys/bus/pci/slots/C10/address
0003:09:00
# cat /sys/bus/pci/slots/C10/adapter
1
# cat /sys/bus/pci/slots/C10/power
1
# lspci
0003:09:00.0 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.1 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.2 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.3 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
# lspci -t
# lspci -t
-+-[0003:00]---00.0-[01-13]----00.0-[02-13]--+-01.0-[03]----00.0
| +-08.0-[04-08]--
| +-09.0-[09]--+-00.0
| | +-00.1
| | +-00.2
| | \-00.3
| +-10.0-[0a-0e]--
| \-11.0-[0f-13]--
1.2 Unplug adapter 0003:09.00.x
# echo 0 > /sys/bus/pci/slots/C10/power
# lspci -t
-+-[0003:00]---00.0-[01-13]----00.0-[02-13]--+-01.0-[03]----00.0
| +-08.0-[04-08]--
| +-09.0-[09]--
| +-10.0-[0a-0e]--
| \-11.0-[0f-13]--
1.3 Plug adapter 0003:09.00.x
# echo 1 > /sys/bus/pci/slots/C10/power
Do I understand correctly that the adapter was not physically moved in/out
of the slot between 1.2 and 1.3?
I am confused - why is this needed to test hotplug?
# cat /sys/bus/pci/devices/0003:09:00.0/eeh_pe_config_addr
0x1
# echo 1:0:4:0:0 > /sys/kernel/debug/powerpc/PCI0003/err_injct
# lspci -ns 0003:09:00.0
# dmesg | grep EEH
EEH: Frozen PHB#3-PE#1 detected
EEH: PE location: U78C9.001.WZS00CF-P1-C10, PHB location: N/A
EEH: Detected PCI bus error on PHB#3-PE#1
EEH: This PCI device has failed 1 times in the last hour
EEH: Notify device drivers to shutdown
EEH: Collect temporary log
EEH: Reset without hotplug activity
EEH: Notify device drivers the completion of reset
EEH: Notify device driver to resume
2. Plug adapter and then unplug it. This requires hack in skiboot
to skip probing the adapters behind the target (C12 in the
testing) for once.
2.1 Check status
# cat /sys/bus/pci/slots/C12/address
0001:06
# cat /sys/bus/pci/slots/C12/power
0
# cat /sys/bus/pci/slots/C12/adapter
1
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--
2.2 Plug adapter 0001:06:00.x
# echo 1 > /sys/bus/pci/slots/C12/power
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--+-00.0
\-00.1
# lspci
0001:06:00.0 Ethernet controller: \
Broadcom Corporation NetXtreme II BCM57810 10 Gigabit Ethernet (rev 10)
0001:06:00.1 Ethernet controller: \
Broadcom Corporation NetXtreme II BCM57810 10 Gigabit Ethernet (rev 10)
2.3 Inject EEH error to adapter 0001:06:00.x, which is recovered
# cat /sys/bus/pci/devices/0001:06:00.0/eeh_pe_config_addr
0x2
# echo 2:0:4:0:0 > /sys/kernel/debug/powerpc/PCI0001/err_injct
# dmesg | grep EEH
EEH: Frozen PHB#1-PE#2 detected
EEH: PE location: U78C9.001.WZS00CF-P1-C12, PHB location: N/A
EEH: Detected PCI bus error on PHB#1-PE#2
EEH: This PCI device has failed 1 times in the last hour
EEH: Notify device drivers to shutdown
EEH: Collect temporary log
EEH: Reset without hotplug activity
EEH: Notify device drivers the completion of reset
EEH: Notify device driver to resume
2.4 Unplug adapter 0001:06:00.x
# echo 0 > /sys/bus/pci/slots/C12/power
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--
=========
Changelog
=========
v8:
* Rebased to linux-powerpc next branch.
* Resolve comments from Alexey and Daniel on PCI part
* Resolve comments from Rob on fdt.c
* Retested (refer to the "Testing section")
v7:
* Reworked revision to some extent.
* Rebased to powerpc/next repository.
* Reorder/split/merge/drop according - Alexey.
* Defined macros and use array to track IO/M32/M64/DMA32 segments - Alexey.
* Merged 3 files to one for the hotplug driver - Alexey.
* As part of OPAL API, defined macros for PCI slot power state, hotplug
message type. Defined macros for PCI slot power confirmed state in
hotplug driver.
* Misc comments from Alexey.
* Reworked unflatten_dt_node() to avoid recursive function calls.
* Use EXPORT_SYMBOL_GPL() and document function's input/output - Rob/Frank.
v6:
* Patch reorder, split, squash - Alexey.
* Minor coding style - Alexey.
* Better function names for pcibios_{add,remove}_pci_devices - Bjorn
* Replace pr_warn() with dev_warn() in PowerNV hotplug driver - Bjorn
* Concurrent depth as parameter passed to __unflatten_dt_node() - Grant / Alexey
* Replace overlay with of_changeset - Grant
v5:
* Rebased to 4.1.rc6 and some unmerged patches as below:
Alexey's DDW patchset (v11);
Gavin's EEH error injection support (in mpe's next branch);
Richard's EEH cleanup patches (in mpe's next branch);
Richard's EEH support for VF (v7);
Gavin's misc EEH fixes for 4.2;
* The revision bases on skiboot corresponding patches (v7):
https://patchwork.ozlabs.org/patch/480437/
* Utilize OF overlay to update device-tree with help of newly introduced
OPAL API opal_get_overlay_dt().
* Split patches for easy review according to aik's comments.
* Fix coding style from checkpatchc.pl as pointed by aik.
* Code cleanup and misc fixup according to aik's input.
v4:
* Rebased to 4.1.RC1
* Added API to unflatten FDT blob to device node sub-tree, which is attached
the indicated parent device node. The original mechanism based on formatted
string stream has been dropped.
* The PATCH[v3 09/21] ("powerpc/eeh: Delay probing EEH device during hotplug")
was picked up sent to linux-ppc@ separately for review as Richard's "VF EEH
Support" depends on that.
v3:
* Rebased to 4.1.RC0
* PowerNV PCI infrasturcture is total refactored in order to support PCI
hotplug. The PowerNV hotplug driver is also reworked a lot because of
the changes in skiboot in order to support PCI hotplug.
Gavin Shan (45):
PCI: Add pcibios_setup_bridge()
powerpc/pci: Override pcibios_setup_bridge()
powerpc/pci: Cleanup on struct pci_controller_ops
powerpc/powernv: Cleanup on pci_controller_ops instances
powerpc/powernv: Drop phb->bdfn_to_pe()
powerpc/powernv: Reorder fields in struct pnv_phb
powerpc/powernv: Rename PE# fields in struct pnv_phb
powerpc/powernv: Fix initial IO and M32 segmap
powerpc/powernv: Simplify pnv_ioda_setup_pe_seg()
powerpc/powernv: IO and M32 mapping based on PCI device resources
powerpc/powernv: Track M64 segment consumption
powerpc/powernv: Rename M64 related functions
powerpc/powernv/ioda1: M64 support on P7IOC
powerpc/powernv/ioda1: Rename pnv_pci_ioda_setup_dma_pe()
powerpc/powernv/ioda1: Introduce PNV_IODA1_DMA32_SEGSIZE
powerpc/powernv: Remove DMA32 PE list
powerpc/powernv/ioda1: Improve DMA32 segment track
powerpc/powernv: Increase PE# capacity
powerpc/powernv: Use PE instead of number during setup and release
powerpc/powernv: Allocate PE# in reverse order
powerpc/powernv: Create PEs at PCI hot plugging time
powerpc/powernv/ioda1: Support releasing IODA1 TCE table
powerpc/powernv: Dynamically release PEs
powerpc/pci: Rename pcibios_{add,remove}_pci_devices()
powerpc/pci: Rename pcibios_find_pci_bus()
powerpc/pci: Move pci_find_bus_by_node() around
powerpc/pci: Export pci_add_device_node_info()
powerpc/pci: Introduce pci_remove_device_node_info()
powerpc/pci: Export pci_traverse_device_nodes()
powerpc/pci: Delay populating pdn
powerpc/pci: Don't scan empty slot
powerpc/pci: Update bridge windows on PCI plug
powerpc/powernv: Simplify pnv_eeh_reset()
powerpc/powernv: Exclude root bus in pnv_pci_reset_secondary_bus()
powerpc/powernv: Fundamental reset in pnv_pci_reset_secondary_bus()
powerpc/powernv: Support PCI slot ID
powerpc/powernv: Use firmware PCI slot reset infrastructure
powerpc/powernv: Functions to get/set PCI slot status
powerpc/powernv: Select OF_DYNAMIC
drivers/of: Split unflatten_dt_node()
drivers/of: Avoid recursively calling unflatten_dt_node()
drivers/of: Rename unflatten_dt_node()
drivers/of: Specify parent node in of_fdt_unflatten_tree()
drivers/of: Return allocated memory from of_fdt_unflatten_tree()
PCI/hotplug: PowerPC PowerNV PCI hotplug driver
arch/powerpc/include/asm/eeh.h | 2 +-
arch/powerpc/include/asm/opal-api.h | 17 +-
arch/powerpc/include/asm/opal.h | 8 +-
arch/powerpc/include/asm/pci-bridge.h | 25 +-
arch/powerpc/include/asm/pnv-pci.h | 7 +
arch/powerpc/include/asm/ppc-pci.h | 8 +-
arch/powerpc/kernel/eeh_dev.c | 17 +-
arch/powerpc/kernel/eeh_driver.c | 12 +-
arch/powerpc/kernel/pci-common.c | 16 +-
arch/powerpc/kernel/pci-hotplug.c | 47 +-
arch/powerpc/kernel/pci_dn.c | 89 +-
arch/powerpc/platforms/maple/pci.c | 34 +-
arch/powerpc/platforms/pasemi/pci.c | 3 -
arch/powerpc/platforms/powermac/pci.c | 38 +-
arch/powerpc/platforms/powernv/Kconfig | 1 +
arch/powerpc/platforms/powernv/eeh-powernv.c | 179 ++--
arch/powerpc/platforms/powernv/opal-wrappers.S | 4 +
arch/powerpc/platforms/powernv/pci-ioda.c | 1243 +++++++++++++++---------
arch/powerpc/platforms/powernv/pci.c | 92 +-
arch/powerpc/platforms/powernv/pci.h | 60 +-
arch/powerpc/platforms/pseries/msi.c | 4 +-
arch/powerpc/platforms/pseries/pci_dlpar.c | 32 -
arch/powerpc/platforms/pseries/setup.c | 8 +-
drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 2 +-
drivers/of/fdt.c | 372 ++++---
drivers/of/unittest.c | 2 +-
drivers/pci/hotplug/Kconfig | 12 +
drivers/pci/hotplug/Makefile | 3 +
drivers/pci/hotplug/pnv_php.c | 870 +++++++++++++++++
drivers/pci/hotplug/rpadlpar_core.c | 8 +-
drivers/pci/hotplug/rpaphp_core.c | 4 +-
drivers/pci/hotplug/rpaphp_pci.c | 4 +-
drivers/pci/setup-bus.c | 5 +
include/linux/of_fdt.h | 5 +-
include/linux/pci.h | 1 +
35 files changed, 2360 insertions(+), 874 deletions(-)
create mode 100644 drivers/pci/hotplug/pnv_php.c
This renames pnv_pci_ioda_setup_dma_pe() to pnv_pci_ioda1_setup_dma_pe()
as it's the counter-part of IODA2's pnv_pci_ioda2_setup_dma_pe().
No logical changes introduced.
Signed-off-by: Gavin Shan <redacted>
On Wed, Apr 13, 2016 at 05:28:15PM +1000, Alexey Kardashevskiy wrote:
On 02/17/2016 02:43 PM, Gavin Shan wrote:
quoted
This series of patches rebases on powerpc/next branch, plus below additional
patches:
<This series of patches>
<Followup 3 patches from Gavin on SRIOV EEH, which aren't posted>
https://patchwork.ozlabs.org/patch/581315/ (PATCH[1/9] Richard's SRIOV EEH)
https://patchwork.ozlabs.org/patch/582639/ (PATCH[1/1] Gavin's EEH fix)
https://patchwork.ozlabs.org/patch/582093/ (PATCH[1/1] Gavin's EEH fix)
https://patchwork.ozlabs.org/patch/580626/ (PATCH[1/4] Gavin's PCI fix)
https://patchwork.ozlabs.org/patch/580153/ (PATCH[1/1] Andrew's EEH minor fix)
https://patchwork.ozlabs.org/patch/566827/ (PATCH[1/1] Russell's P5IOC2 removal)
https://patchwork.ozlabs.org/patch/534154/ (PATCH[1/7] Richard's SRIOV rework)
commit 388f7b1 ("Linux 4.5-rc3")
The series of patches intend to support PCI slot for PowerPC PowerNV platform,
which is running on top of skiboot firmware. The patchset requires corresponding
changes from skiboot firmware, which is sent to skiboot@lists.ozlabs.org
for review. The PCI slots are exposed by skiboot with device node properties,
and kernel utilizes those properties to populated PCI slots accordingly.
The original PCI infrastructure on PowerNV platform can't support hotplug
because the PE is assigned during PHB fixup time, which is called for once
during system boot time. For this, the PCI infrastructure on PowerNV platform
has been reworked for a lot. After that, the PE and its corresponding resources
(IODT, M32DT, M64 segments, DMA32 and bypass window) are assigned upon updating
PCI bridge's resources, which might decide PE# assigned to the PE (e.g. M64
resources, on P8 strictly speaking). Each PE will maintain a reference count,
which is (number of child PCI devices + 1). That indicates when last child PCI
device leaves the PE, the PE and its included resources will be relased and put
back into free pool again. With this design, the PE will be released when EEH PE
is released. PATCH[1 - 23] are related to this part.
From skiboot perspective, PCI slot is providing (hot/fundamental/complete)
resets to EEH. The kernel gets to know if skiboot supports various reset on one
particular PCI slot through device-tree node. If it does, EEH will utilize the
functionality provided by skiboot. Besides, the device-tree nodes have to change
in order to support PCI hotplug. For example, when one PCI adapter inserted to
one slot, its device-tree node should be added to the system dynamically. Conversely,
the device-tree node should be removed from the system when the PCI adapter is going
to be offline. Since pci_dn and eeh_dev have same life cyle as PCI device nodes,
they should be added/removed accordingly during PCI hotplug. PATCH[24 - 39] are
doing the related work.
The OF driver is changed to support unflattening FDT blob for sub-stree, which
is covered by PATCH[40 - 44].
The last one, PATCH[45], is the standalone PCI hotplug driver for PowerPC PowerNV
platform.
=======
Testing
=======
1. Unplug adapters behind non-empty slot, then plug them.
1.1 Check status
# cat /sys/bus/pci/slots/C10/address
0003:09:00
# cat /sys/bus/pci/slots/C10/adapter
1
# cat /sys/bus/pci/slots/C10/power
1
# lspci
0003:09:00.0 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.1 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.2 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.3 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
# lspci -t
# lspci -t
-+-[0003:00]---00.0-[01-13]----00.0-[02-13]--+-01.0-[03]----00.0
| +-08.0-[04-08]--
| +-09.0-[09]--+-00.0
| | +-00.1
| | +-00.2
| | \-00.3
| +-10.0-[0a-0e]--
| \-11.0-[0f-13]--
1.2 Unplug adapter 0003:09.00.x
# echo 0 > /sys/bus/pci/slots/C10/power
# lspci -t
-+-[0003:00]---00.0-[01-13]----00.0-[02-13]--+-01.0-[03]----00.0
| +-08.0-[04-08]--
| +-09.0-[09]--
| +-10.0-[0a-0e]--
| \-11.0-[0f-13]--
1.3 Plug adapter 0003:09.00.x
# echo 1 > /sys/bus/pci/slots/C10/power
Do I understand correctly that the adapter was not physically moved in/out of
the slot between 1.2 and 1.3?
I am confused - why is this needed to test hotplug?
Without the series, the EEH reset is always done by kenrel. With the
series applied, the EEH reset could be done in skiboot. That's the
major change introduced by the series from EEH's perspective. Also,
the EEH code was touched.
quoted
# cat /sys/bus/pci/devices/0003:09:00.0/eeh_pe_config_addr
0x1
# echo 1:0:4:0:0 > /sys/kernel/debug/powerpc/PCI0003/err_injct
# lspci -ns 0003:09:00.0
# dmesg | grep EEH
EEH: Frozen PHB#3-PE#1 detected
EEH: PE location: U78C9.001.WZS00CF-P1-C10, PHB location: N/A
EEH: Detected PCI bus error on PHB#3-PE#1
EEH: This PCI device has failed 1 times in the last hour
EEH: Notify device drivers to shutdown
EEH: Collect temporary log
EEH: Reset without hotplug activity
EEH: Notify device drivers the completion of reset
EEH: Notify device driver to resume
2. Plug adapter and then unplug it. This requires hack in skiboot
to skip probing the adapters behind the target (C12 in the
testing) for once.
2.1 Check status
# cat /sys/bus/pci/slots/C12/address
0001:06
# cat /sys/bus/pci/slots/C12/power
0
# cat /sys/bus/pci/slots/C12/adapter
1
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--
2.2 Plug adapter 0001:06:00.x
# echo 1 > /sys/bus/pci/slots/C12/power
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--+-00.0
\-00.1
# lspci
0001:06:00.0 Ethernet controller: \
Broadcom Corporation NetXtreme II BCM57810 10 Gigabit Ethernet (rev 10)
0001:06:00.1 Ethernet controller: \
Broadcom Corporation NetXtreme II BCM57810 10 Gigabit Ethernet (rev 10)
2.3 Inject EEH error to adapter 0001:06:00.x, which is recovered
# cat /sys/bus/pci/devices/0001:06:00.0/eeh_pe_config_addr
0x2
# echo 2:0:4:0:0 > /sys/kernel/debug/powerpc/PCI0001/err_injct
# dmesg | grep EEH
EEH: Frozen PHB#1-PE#2 detected
EEH: PE location: U78C9.001.WZS00CF-P1-C12, PHB location: N/A
EEH: Detected PCI bus error on PHB#1-PE#2
EEH: This PCI device has failed 1 times in the last hour
EEH: Notify device drivers to shutdown
EEH: Collect temporary log
EEH: Reset without hotplug activity
EEH: Notify device drivers the completion of reset
EEH: Notify device driver to resume
2.4 Unplug adapter 0001:06:00.x
# echo 0 > /sys/bus/pci/slots/C12/power
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--
=========
Changelog
=========
v8:
* Rebased to linux-powerpc next branch.
* Resolve comments from Alexey and Daniel on PCI part
* Resolve comments from Rob on fdt.c
* Retested (refer to the "Testing section")
v7:
* Reworked revision to some extent.
* Rebased to powerpc/next repository.
* Reorder/split/merge/drop according - Alexey.
* Defined macros and use array to track IO/M32/M64/DMA32 segments - Alexey.
* Merged 3 files to one for the hotplug driver - Alexey.
* As part of OPAL API, defined macros for PCI slot power state, hotplug
message type. Defined macros for PCI slot power confirmed state in
hotplug driver.
* Misc comments from Alexey.
* Reworked unflatten_dt_node() to avoid recursive function calls.
* Use EXPORT_SYMBOL_GPL() and document function's input/output - Rob/Frank.
v6:
* Patch reorder, split, squash - Alexey.
* Minor coding style - Alexey.
* Better function names for pcibios_{add,remove}_pci_devices - Bjorn
* Replace pr_warn() with dev_warn() in PowerNV hotplug driver - Bjorn
* Concurrent depth as parameter passed to __unflatten_dt_node() - Grant / Alexey
* Replace overlay with of_changeset - Grant
v5:
* Rebased to 4.1.rc6 and some unmerged patches as below:
Alexey's DDW patchset (v11);
Gavin's EEH error injection support (in mpe's next branch);
Richard's EEH cleanup patches (in mpe's next branch);
Richard's EEH support for VF (v7);
Gavin's misc EEH fixes for 4.2;
* The revision bases on skiboot corresponding patches (v7):
https://patchwork.ozlabs.org/patch/480437/
* Utilize OF overlay to update device-tree with help of newly introduced
OPAL API opal_get_overlay_dt().
* Split patches for easy review according to aik's comments.
* Fix coding style from checkpatchc.pl as pointed by aik.
* Code cleanup and misc fixup according to aik's input.
v4:
* Rebased to 4.1.RC1
* Added API to unflatten FDT blob to device node sub-tree, which is attached
the indicated parent device node. The original mechanism based on formatted
string stream has been dropped.
* The PATCH[v3 09/21] ("powerpc/eeh: Delay probing EEH device during hotplug")
was picked up sent to linux-ppc@ separately for review as Richard's "VF EEH
Support" depends on that.
v3:
* Rebased to 4.1.RC0
* PowerNV PCI infrasturcture is total refactored in order to support PCI
hotplug. The PowerNV hotplug driver is also reworked a lot because of
the changes in skiboot in order to support PCI hotplug.
Gavin Shan (45):
PCI: Add pcibios_setup_bridge()
powerpc/pci: Override pcibios_setup_bridge()
powerpc/pci: Cleanup on struct pci_controller_ops
powerpc/powernv: Cleanup on pci_controller_ops instances
powerpc/powernv: Drop phb->bdfn_to_pe()
powerpc/powernv: Reorder fields in struct pnv_phb
powerpc/powernv: Rename PE# fields in struct pnv_phb
powerpc/powernv: Fix initial IO and M32 segmap
powerpc/powernv: Simplify pnv_ioda_setup_pe_seg()
powerpc/powernv: IO and M32 mapping based on PCI device resources
powerpc/powernv: Track M64 segment consumption
powerpc/powernv: Rename M64 related functions
powerpc/powernv/ioda1: M64 support on P7IOC
powerpc/powernv/ioda1: Rename pnv_pci_ioda_setup_dma_pe()
powerpc/powernv/ioda1: Introduce PNV_IODA1_DMA32_SEGSIZE
powerpc/powernv: Remove DMA32 PE list
powerpc/powernv/ioda1: Improve DMA32 segment track
powerpc/powernv: Increase PE# capacity
powerpc/powernv: Use PE instead of number during setup and release
powerpc/powernv: Allocate PE# in reverse order
powerpc/powernv: Create PEs at PCI hot plugging time
powerpc/powernv/ioda1: Support releasing IODA1 TCE table
powerpc/powernv: Dynamically release PEs
powerpc/pci: Rename pcibios_{add,remove}_pci_devices()
powerpc/pci: Rename pcibios_find_pci_bus()
powerpc/pci: Move pci_find_bus_by_node() around
powerpc/pci: Export pci_add_device_node_info()
powerpc/pci: Introduce pci_remove_device_node_info()
powerpc/pci: Export pci_traverse_device_nodes()
powerpc/pci: Delay populating pdn
powerpc/pci: Don't scan empty slot
powerpc/pci: Update bridge windows on PCI plug
powerpc/powernv: Simplify pnv_eeh_reset()
powerpc/powernv: Exclude root bus in pnv_pci_reset_secondary_bus()
powerpc/powernv: Fundamental reset in pnv_pci_reset_secondary_bus()
powerpc/powernv: Support PCI slot ID
powerpc/powernv: Use firmware PCI slot reset infrastructure
powerpc/powernv: Functions to get/set PCI slot status
powerpc/powernv: Select OF_DYNAMIC
drivers/of: Split unflatten_dt_node()
drivers/of: Avoid recursively calling unflatten_dt_node()
drivers/of: Rename unflatten_dt_node()
drivers/of: Specify parent node in of_fdt_unflatten_tree()
drivers/of: Return allocated memory from of_fdt_unflatten_tree()
PCI/hotplug: PowerPC PowerNV PCI hotplug driver
arch/powerpc/include/asm/eeh.h | 2 +-
arch/powerpc/include/asm/opal-api.h | 17 +-
arch/powerpc/include/asm/opal.h | 8 +-
arch/powerpc/include/asm/pci-bridge.h | 25 +-
arch/powerpc/include/asm/pnv-pci.h | 7 +
arch/powerpc/include/asm/ppc-pci.h | 8 +-
arch/powerpc/kernel/eeh_dev.c | 17 +-
arch/powerpc/kernel/eeh_driver.c | 12 +-
arch/powerpc/kernel/pci-common.c | 16 +-
arch/powerpc/kernel/pci-hotplug.c | 47 +-
arch/powerpc/kernel/pci_dn.c | 89 +-
arch/powerpc/platforms/maple/pci.c | 34 +-
arch/powerpc/platforms/pasemi/pci.c | 3 -
arch/powerpc/platforms/powermac/pci.c | 38 +-
arch/powerpc/platforms/powernv/Kconfig | 1 +
arch/powerpc/platforms/powernv/eeh-powernv.c | 179 ++--
arch/powerpc/platforms/powernv/opal-wrappers.S | 4 +
arch/powerpc/platforms/powernv/pci-ioda.c | 1243 +++++++++++++++---------
arch/powerpc/platforms/powernv/pci.c | 92 +-
arch/powerpc/platforms/powernv/pci.h | 60 +-
arch/powerpc/platforms/pseries/msi.c | 4 +-
arch/powerpc/platforms/pseries/pci_dlpar.c | 32 -
arch/powerpc/platforms/pseries/setup.c | 8 +-
drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 2 +-
drivers/of/fdt.c | 372 ++++---
drivers/of/unittest.c | 2 +-
drivers/pci/hotplug/Kconfig | 12 +
drivers/pci/hotplug/Makefile | 3 +
drivers/pci/hotplug/pnv_php.c | 870 +++++++++++++++++
drivers/pci/hotplug/rpadlpar_core.c | 8 +-
drivers/pci/hotplug/rpaphp_core.c | 4 +-
drivers/pci/hotplug/rpaphp_pci.c | 4 +-
drivers/pci/setup-bus.c | 5 +
include/linux/of_fdt.h | 5 +-
include/linux/pci.h | 1 +
35 files changed, 2360 insertions(+), 874 deletions(-)
create mode 100644 drivers/pci/hotplug/pnv_php.c
On Wed, Apr 13, 2016 at 04:21:07PM +1000, Alexey Kardashevskiy wrote:
On 02/17/2016 02:43 PM, Gavin Shan wrote:
quoted
There are two arrays for IO and M32 segment maps on every PHB.
The index of the arrays are segment number and the value stored
in the corresponding element is PE number, indicating the segment
is assigned to the PE. Initially, all elements in those two arrays
are zeroes, meaning all segments are assigned to PE#0. It's wrong.
This fixes the initial values in the elements of those two arrays
to IODA_INVALID_PE, meaning all segments aren't assigned to any
PE.
This is ok.
quoted
In order to use IODA_INVALID_PE (-1) to represent invalid PE
number, the types of those two arrays are changed from "unsigned int"
to "int".
"unsigned" can carry (-1) perfectly fine, just add a type cast to
IODA_INVALID_PE:
#define IODA_INVALID_PE (unsigned int)(-1)
Using "signed" type for indexes which cannot be negative does not make much
sense - instead of checking for the upper boundary, you have to check for "<
0" too.
OPAL uses unsigned type for PE (uint64_t or uint32_t or uint16_t - this is
quite funny).
pnv_ioda_pe::pe_number is "unsigned" and this pe_number is the same thing as
I can see in pnv_ioda_setup_dev_PE().
Some printk() print the PE number as "%x" (which implies "unsigned").
Yes, I can simply have something like below when PE number as well as
segment index are represented by "unsigned int" values, right?
#define IODA_INVALID_PE 0xffffffff
I suggest changing the pci_dn::pe_number type from "int" to "unsigned int" to
match pnv_ioda_pe::pe_number, in a separate patch. Or do not touch types for
now.
Yes, I will have a separate patch right before this one to address it.
PEs are put into PHB DMA32 list (phb->ioda.pe_dma_list) according
to their DMA32 weight. The PEs on the list are iterated to setup
their TCE32 tables at system booting time. The list is used for
once and there is for keep having it.
"there is no need to keep it" may be?
This moves the logic calculating DMA32 weight of PHB and PE to
pnv_ioda_setup_dma() to drop PHB's DMA32 list. Also, every PE
traces the consumed DMA32 segment by @tce32_seg and @tce32_segcount
are useless and they're removed.
Signed-off-by: Gavin Shan <redacted>
Reviewed-by: Alexey Kardashevskiy <redacted>
with few comments below...
@@ -886,44 +886,6 @@ out:return0;}-staticvoidpnv_ioda_link_pe_by_weight(structpnv_phb*phb,-structpnv_ioda_pe*pe)-{-structpnv_ioda_pe*lpe;--list_for_each_entry(lpe,&phb->ioda.pe_dma_list,dma_link){-if(lpe->dma_weight<pe->dma_weight){-list_add_tail(&pe->dma_link,&lpe->dma_link);-return;-}-}-list_add_tail(&pe->dma_link,&phb->ioda.pe_dma_list);-}--staticunsignedintpnv_ioda_dma_weight(structpci_dev*dev)-{-/* This is quite simplistic. The "base" weight of a device-*is10.0meansnoDMAistobeaccountedforit.-*/--/* If it's a bridge, no DMA */-if(dev->hdr_type!=PCI_HEADER_TYPE_NORMAL)-return0;--/* Reduce the weight of slow USB controllers */-if(dev->class==PCI_CLASS_SERIAL_USB_UHCI||-dev->class==PCI_CLASS_SERIAL_USB_OHCI||-dev->class==PCI_CLASS_SERIAL_USB_EHCI)-return3;--/* Increase the weight of RAID (includes Obsidian) */-if((dev->class>>8)==PCI_CLASS_STORAGE_RAID)-return15;--/* Default */-return10;-}-#ifdef CONFIG_PCI_IOVstaticintpnv_pci_vf_resource_shift(structpci_dev*dev,intoffset){
@@ -1044,16 +1005,6 @@ static struct pnv_ioda_pe *pnv_ioda_setup_dev_PE(struct pci_dev *dev)returnNULL;}-/* Assign a DMA weight to the device */-pe->dma_weight=pnv_ioda_dma_weight(dev);-if(pe->dma_weight!=0){-phb->ioda.dma_weight+=pe->dma_weight;-phb->ioda.dma_pe_count++;-}--/* Link the PE */-pnv_ioda_link_pe_by_weight(phb,pe);-returnpe;}
@@ -1108,10 +1058,8 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, bool all)pe->flags|=(all?PNV_IODA_PE_BUS_ALL:PNV_IODA_PE_BUS);pe->pbus=bus;pe->pdev=NULL;-pe->tce32_seg=-1;pe->mve_number=-1;pe->rid=bus->busn_res.start<<8;-pe->dma_weight=0;if(all)pe_info(pe,"Secondary bus %d..%d associated with PE#%d\n",
@@ -1133,17 +1081,6 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, bool all)/* Put PE to the list */list_add_tail(&pe->list,&phb->ioda.pe_list);--/* Account for one DMA PE if at least one DMA capable device exist-*belowthebridge-*/-if(pe->dma_weight!=0){-phb->ioda.dma_weight+=pe->dma_weight;-phb->ioda.dma_pe_count++;-}--/* Link the PE */-pnv_ioda_link_pe_by_weight(phb,pe);}staticstructpnv_ioda_pe*pnv_ioda_setup_npu_PE(structpci_dev*npu_pdev)
@@ -1184,7 +1121,6 @@ static struct pnv_ioda_pe *pnv_ioda_setup_npu_PE(struct pci_dev *npu_pdev)rid=npu_pdev->bus->number<<8|npu_pdn->devfn;npu_pdn->pcidev=npu_pdev;npu_pdn->pe_number=pe_num;-pe->dma_weight+=pnv_ioda_dma_weight(npu_pdev);phb->ioda.pe_rmap[rid]=pe->pe_number;/* Map the PE to this link */
@@ -2023,6 +1958,54 @@ static struct iommu_table_ops pnv_ioda2_iommu_ops = {.free=pnv_ioda2_table_free,};+staticintpnv_pci_ioda_dev_dma_weight(structpci_dev*dev,void*data)+{+unsignedint*weight=(unsignedint*)data;++/* This is quite simplistic. The "base" weight of a device+*is10.0meansnoDMAistobeaccountedforit.+*/+if(dev->hdr_type!=PCI_HEADER_TYPE_NORMAL)+return0;++if(dev->class==PCI_CLASS_SERIAL_USB_UHCI||+dev->class==PCI_CLASS_SERIAL_USB_OHCI||+dev->class==PCI_CLASS_SERIAL_USB_EHCI)+*weight+=3;+elseif((dev->class>>8)==PCI_CLASS_STORAGE_RAID)+*weight+=15;+else+*weight+=10;++return0;+}++staticunsignedintpnv_pci_ioda_pe_dma_weight(structpnv_ioda_pe*pe)+{+unsignedintweight=0;++if((pe->flags&PNV_IODA_PE_DEV)&&pe->pdev){+pnv_pci_ioda_dev_dma_weight(pe->pdev,&weight);+}elseif((pe->flags&PNV_IODA_PE_BUS)&&pe->pbus){+structpci_dev*pdev;++list_for_each_entry(pdev,&pe->pbus->devices,bus_list)+pnv_pci_ioda_dev_dma_weight(pdev,&weight);+}elseif((pe->flags&PNV_IODA_PE_BUS_ALL)&&pe->pbus){+pci_walk_bus(pe->pbus,pnv_pci_ioda_dev_dma_weight,&weight);+}++returnweight;+}++staticunsignedintpnv_pci_ioda_total_dma_weight(structpnv_phb*phb)
s/pnv_pci_ioda_total_dma_weight/pnv_pci_ioda1_phb_dma_weight/ ? "total"
does not say much. Or just merge it into pnv_pci_ioda1_setup_dma_pe() as it
is useless for anything but IODA1.
@@ -2039,17 +2022,12 @@ static void pnv_pci_ioda1_setup_dma_pe(struct pnv_phb *phb, /* XXX FIXME: Provide 64-bit DMA facilities & non-4K TCE tables etc.. */ /* XXX FIXME: Allocate multi-level tables on PHB3 */- /* We shouldn't already have a 32-bit DMA associated */- if (WARN_ON(pe->tce32_seg >= 0))- return;- tbl = pnv_pci_table_alloc(phb->hose->node); iommu_register_group(&pe->table_group, phb->hose->global_number, pe->pe_number); pnv_pci_link_table_and_group(phb->hose->node, 0, tbl, &pe->table_group); /* Grab a 32-bit TCE table */- pe->tce32_seg = base; pe_info(pe, " Setting up 32-bit TCE table at %08x..%08x\n", base * PNV_IODA1_DMA32_SEGSIZE, (base + segs) * PNV_IODA1_DMA32_SEGSIZE - 1);
@@ -2116,8 +2094,6 @@ static void pnv_pci_ioda1_setup_dma_pe(struct pnv_phb *phb, return; fail: /* XXX Failure: Try to fallback to 64-bit only ? */- if (pe->tce32_seg >= 0)- pe->tce32_seg = -1; if (tce_mem) __free_pages(tce_mem, get_order(tce32_segsz * segs)); if (tbl) {
@@ -2528,10 +2504,6 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb, { int64_t rc;- /* We shouldn't already have a 32-bit DMA associated */- if (WARN_ON(pe->tce32_seg >= 0))- return;- /* TVE #1 is selected by PCI address bit 59 */ pe->tce_bypass_base = 1ull << 59;
@@ -2539,7 +2511,6 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb, pe->pe_number); /* The PE will reserve all possible 32-bits space */- pe->tce32_seg = 0; pe_info(pe, "Setting up 32-bit TCE table at 0..%08x\n", phb->ioda.m32_pci_base);
@@ -2555,11 +2526,8 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb, #endif rc = pnv_pci_ioda2_setup_default_config(pe);- if (rc) {- if (pe->tce32_seg >= 0)- pe->tce32_seg = -1;+ if (rc) return;- } if (pe->flags & PNV_IODA_PE_DEV) iommu_add_device(&pe->pdev->dev);
@@ -2570,24 +2538,32 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb, static void pnv_ioda_setup_dma(struct pnv_phb *phb) { struct pci_controller *hose = phb->hose;- unsigned int residual, remaining, segs, tw, base;+ unsigned int weight, total_weight, dma_pe_count;+ unsigned int residual, remaining, segs, base; struct pnv_ioda_pe *pe;+ total_weight = pnv_pci_ioda_total_dma_weight(phb);+ dma_pe_count = 0;+ list_for_each_entry(pe, &phb->ioda.pe_list, list) {+ weight = pnv_pci_ioda_pe_dma_weight(pe);+ if (weight > 0)+ dma_pe_count++;+ }+ /* If we have more PE# than segments available, hand out one * per PE until we run out and let the rest fail. If not, * then we assign at least one segment per PE, plus more based * on the amount of devices under that PE */- if (phb->ioda.dma_pe_count > phb->ioda.tce32_count)+ if (dma_pe_count > phb->ioda.tce32_count) residual = 0; else- residual = phb->ioda.tce32_count -- phb->ioda.dma_pe_count;+ residual = phb->ioda.tce32_count - dma_pe_count; pr_info("PCI: Domain %04x has %ld available 32-bit DMA segments\n", hose->global_number, phb->ioda.tce32_count); pr_info("PCI: %d PE# for a total weight of %d\n",- phb->ioda.dma_pe_count, phb->ioda.dma_weight);+ dma_pe_count, total_weight); pnv_pci_ioda_setup_opal_tce_kill(phb);
@@ -53,14 +53,7 @@ struct pnv_ioda_pe {/* PE number */unsignedintpe_number;-/* "Weight" assigned to the PE for the sake of DMA resource-*allocations-*/-unsignedintdma_weight;-/* "Base" iommu table, ie, 4K TCEs, 32-bit DMA */-inttce32_seg;-inttce32_segcount;structiommu_table_grouptable_group;/* 64-bit TCE bypass region */
@@ -78,7 +71,6 @@ struct pnv_ioda_pe {structlist_headslaves;/* Link in list of PE#s */-structlist_headdma_link;structlist_headlist;};
@@ -173,17 +165,6 @@ struct pnv_phb {/* 32-bit TCE tables allocation */unsignedlongtce32_count;-/* Total "weight" for the sake of DMA resources-*allocation-*/-unsignedintdma_weight;-unsignedintdma_pe_count;--/* Sorted list of used PE's, sorted at-*bootforresourceallocationpurposes-*/-structlist_headpe_dma_list;-/* TCE cache invalidate registers (physical and*remapped)*/
On Wed, Apr 13, 2016 at 05:28:15PM +1000, Alexey Kardashevskiy wrote:
quoted
On 02/17/2016 02:43 PM, Gavin Shan wrote:
quoted
This series of patches rebases on powerpc/next branch, plus below additional
patches:
<This series of patches>
<Followup 3 patches from Gavin on SRIOV EEH, which aren't posted>
https://patchwork.ozlabs.org/patch/581315/ (PATCH[1/9] Richard's SRIOV EEH)
https://patchwork.ozlabs.org/patch/582639/ (PATCH[1/1] Gavin's EEH fix)
https://patchwork.ozlabs.org/patch/582093/ (PATCH[1/1] Gavin's EEH fix)
https://patchwork.ozlabs.org/patch/580626/ (PATCH[1/4] Gavin's PCI fix)
https://patchwork.ozlabs.org/patch/580153/ (PATCH[1/1] Andrew's EEH minor fix)
https://patchwork.ozlabs.org/patch/566827/ (PATCH[1/1] Russell's P5IOC2 removal)
https://patchwork.ozlabs.org/patch/534154/ (PATCH[1/7] Richard's SRIOV rework)
commit 388f7b1 ("Linux 4.5-rc3")
The series of patches intend to support PCI slot for PowerPC PowerNV platform,
which is running on top of skiboot firmware. The patchset requires corresponding
changes from skiboot firmware, which is sent to skiboot@lists.ozlabs.org
for review. The PCI slots are exposed by skiboot with device node properties,
and kernel utilizes those properties to populated PCI slots accordingly.
The original PCI infrastructure on PowerNV platform can't support hotplug
because the PE is assigned during PHB fixup time, which is called for once
during system boot time. For this, the PCI infrastructure on PowerNV platform
has been reworked for a lot. After that, the PE and its corresponding resources
(IODT, M32DT, M64 segments, DMA32 and bypass window) are assigned upon updating
PCI bridge's resources, which might decide PE# assigned to the PE (e.g. M64
resources, on P8 strictly speaking). Each PE will maintain a reference count,
which is (number of child PCI devices + 1). That indicates when last child PCI
device leaves the PE, the PE and its included resources will be relased and put
back into free pool again. With this design, the PE will be released when EEH PE
is released. PATCH[1 - 23] are related to this part.
From skiboot perspective, PCI slot is providing (hot/fundamental/complete)
resets to EEH. The kernel gets to know if skiboot supports various reset on one
particular PCI slot through device-tree node. If it does, EEH will utilize the
functionality provided by skiboot. Besides, the device-tree nodes have to change
in order to support PCI hotplug. For example, when one PCI adapter inserted to
one slot, its device-tree node should be added to the system dynamically. Conversely,
the device-tree node should be removed from the system when the PCI adapter is going
to be offline. Since pci_dn and eeh_dev have same life cyle as PCI device nodes,
they should be added/removed accordingly during PCI hotplug. PATCH[24 - 39] are
doing the related work.
The OF driver is changed to support unflattening FDT blob for sub-stree, which
is covered by PATCH[40 - 44].
The last one, PATCH[45], is the standalone PCI hotplug driver for PowerPC PowerNV
platform.
=======
Testing
=======
1. Unplug adapters behind non-empty slot, then plug them.
1.1 Check status
# cat /sys/bus/pci/slots/C10/address
0003:09:00
# cat /sys/bus/pci/slots/C10/adapter
1
# cat /sys/bus/pci/slots/C10/power
1
# lspci
0003:09:00.0 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.1 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.2 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.3 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
# lspci -t
# lspci -t
-+-[0003:00]---00.0-[01-13]----00.0-[02-13]--+-01.0-[03]----00.0
| +-08.0-[04-08]--
| +-09.0-[09]--+-00.0
| | +-00.1
| | +-00.2
| | \-00.3
| +-10.0-[0a-0e]--
| \-11.0-[0f-13]--
1.2 Unplug adapter 0003:09.00.x
# echo 0 > /sys/bus/pci/slots/C10/power
# lspci -t
-+-[0003:00]---00.0-[01-13]----00.0-[02-13]--+-01.0-[03]----00.0
| +-08.0-[04-08]--
| +-09.0-[09]--
| +-10.0-[0a-0e]--
| \-11.0-[0f-13]--
1.3 Plug adapter 0003:09.00.x
# echo 1 > /sys/bus/pci/slots/C10/power
Do I understand correctly that the adapter was not physically moved in/out of
the slot between 1.2 and 1.3?
Correct.
This is not right then... Someone should try it, on both P7 and P8.
I am confused - why is this needed to test hotplug?
Without the series, the EEH reset is always done by kenrel. With the
series applied, the EEH reset could be done in skiboot.
Why exactly cannot EEH reset changes go to a smaller separate patchset
(before hotplug)?
That's the
major change introduced by the series from EEH's perspective. Also,
the EEH code was touched.
quoted
quoted
# cat /sys/bus/pci/devices/0003:09:00.0/eeh_pe_config_addr
0x1
# echo 1:0:4:0:0 > /sys/kernel/debug/powerpc/PCI0003/err_injct
# lspci -ns 0003:09:00.0
# dmesg | grep EEH
EEH: Frozen PHB#3-PE#1 detected
EEH: PE location: U78C9.001.WZS00CF-P1-C10, PHB location: N/A
EEH: Detected PCI bus error on PHB#3-PE#1
EEH: This PCI device has failed 1 times in the last hour
EEH: Notify device drivers to shutdown
EEH: Collect temporary log
EEH: Reset without hotplug activity
EEH: Notify device drivers the completion of reset
EEH: Notify device driver to resume
2. Plug adapter and then unplug it. This requires hack in skiboot
to skip probing the adapters behind the target (C12 in the
testing) for once.
2.1 Check status
# cat /sys/bus/pci/slots/C12/address
0001:06
# cat /sys/bus/pci/slots/C12/power
0
# cat /sys/bus/pci/slots/C12/adapter
1
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--
2.2 Plug adapter 0001:06:00.x
# echo 1 > /sys/bus/pci/slots/C12/power
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--+-00.0
\-00.1
# lspci
0001:06:00.0 Ethernet controller: \
Broadcom Corporation NetXtreme II BCM57810 10 Gigabit Ethernet (rev 10)
0001:06:00.1 Ethernet controller: \
Broadcom Corporation NetXtreme II BCM57810 10 Gigabit Ethernet (rev 10)
2.3 Inject EEH error to adapter 0001:06:00.x, which is recovered
# cat /sys/bus/pci/devices/0001:06:00.0/eeh_pe_config_addr
0x2
# echo 2:0:4:0:0 > /sys/kernel/debug/powerpc/PCI0001/err_injct
# dmesg | grep EEH
EEH: Frozen PHB#1-PE#2 detected
EEH: PE location: U78C9.001.WZS00CF-P1-C12, PHB location: N/A
EEH: Detected PCI bus error on PHB#1-PE#2
EEH: This PCI device has failed 1 times in the last hour
EEH: Notify device drivers to shutdown
EEH: Collect temporary log
EEH: Reset without hotplug activity
EEH: Notify device drivers the completion of reset
EEH: Notify device driver to resume
2.4 Unplug adapter 0001:06:00.x
# echo 0 > /sys/bus/pci/slots/C12/power
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--
=========
Changelog
=========
v8:
* Rebased to linux-powerpc next branch.
* Resolve comments from Alexey and Daniel on PCI part
* Resolve comments from Rob on fdt.c
* Retested (refer to the "Testing section")
v7:
* Reworked revision to some extent.
* Rebased to powerpc/next repository.
* Reorder/split/merge/drop according - Alexey.
* Defined macros and use array to track IO/M32/M64/DMA32 segments - Alexey.
* Merged 3 files to one for the hotplug driver - Alexey.
* As part of OPAL API, defined macros for PCI slot power state, hotplug
message type. Defined macros for PCI slot power confirmed state in
hotplug driver.
* Misc comments from Alexey.
* Reworked unflatten_dt_node() to avoid recursive function calls.
* Use EXPORT_SYMBOL_GPL() and document function's input/output - Rob/Frank.
v6:
* Patch reorder, split, squash - Alexey.
* Minor coding style - Alexey.
* Better function names for pcibios_{add,remove}_pci_devices - Bjorn
* Replace pr_warn() with dev_warn() in PowerNV hotplug driver - Bjorn
* Concurrent depth as parameter passed to __unflatten_dt_node() - Grant / Alexey
* Replace overlay with of_changeset - Grant
v5:
* Rebased to 4.1.rc6 and some unmerged patches as below:
Alexey's DDW patchset (v11);
Gavin's EEH error injection support (in mpe's next branch);
Richard's EEH cleanup patches (in mpe's next branch);
Richard's EEH support for VF (v7);
Gavin's misc EEH fixes for 4.2;
* The revision bases on skiboot corresponding patches (v7):
https://patchwork.ozlabs.org/patch/480437/
* Utilize OF overlay to update device-tree with help of newly introduced
OPAL API opal_get_overlay_dt().
* Split patches for easy review according to aik's comments.
* Fix coding style from checkpatchc.pl as pointed by aik.
* Code cleanup and misc fixup according to aik's input.
v4:
* Rebased to 4.1.RC1
* Added API to unflatten FDT blob to device node sub-tree, which is attached
the indicated parent device node. The original mechanism based on formatted
string stream has been dropped.
* The PATCH[v3 09/21] ("powerpc/eeh: Delay probing EEH device during hotplug")
was picked up sent to linux-ppc@ separately for review as Richard's "VF EEH
Support" depends on that.
v3:
* Rebased to 4.1.RC0
* PowerNV PCI infrasturcture is total refactored in order to support PCI
hotplug. The PowerNV hotplug driver is also reworked a lot because of
the changes in skiboot in order to support PCI hotplug.
Gavin Shan (45):
PCI: Add pcibios_setup_bridge()
powerpc/pci: Override pcibios_setup_bridge()
powerpc/pci: Cleanup on struct pci_controller_ops
powerpc/powernv: Cleanup on pci_controller_ops instances
powerpc/powernv: Drop phb->bdfn_to_pe()
powerpc/powernv: Reorder fields in struct pnv_phb
powerpc/powernv: Rename PE# fields in struct pnv_phb
powerpc/powernv: Fix initial IO and M32 segmap
powerpc/powernv: Simplify pnv_ioda_setup_pe_seg()
powerpc/powernv: IO and M32 mapping based on PCI device resources
powerpc/powernv: Track M64 segment consumption
powerpc/powernv: Rename M64 related functions
powerpc/powernv/ioda1: M64 support on P7IOC
powerpc/powernv/ioda1: Rename pnv_pci_ioda_setup_dma_pe()
powerpc/powernv/ioda1: Introduce PNV_IODA1_DMA32_SEGSIZE
powerpc/powernv: Remove DMA32 PE list
powerpc/powernv/ioda1: Improve DMA32 segment track
powerpc/powernv: Increase PE# capacity
powerpc/powernv: Use PE instead of number during setup and release
powerpc/powernv: Allocate PE# in reverse order
powerpc/powernv: Create PEs at PCI hot plugging time
powerpc/powernv/ioda1: Support releasing IODA1 TCE table
powerpc/powernv: Dynamically release PEs
powerpc/pci: Rename pcibios_{add,remove}_pci_devices()
powerpc/pci: Rename pcibios_find_pci_bus()
powerpc/pci: Move pci_find_bus_by_node() around
powerpc/pci: Export pci_add_device_node_info()
powerpc/pci: Introduce pci_remove_device_node_info()
powerpc/pci: Export pci_traverse_device_nodes()
powerpc/pci: Delay populating pdn
powerpc/pci: Don't scan empty slot
powerpc/pci: Update bridge windows on PCI plug
powerpc/powernv: Simplify pnv_eeh_reset()
powerpc/powernv: Exclude root bus in pnv_pci_reset_secondary_bus()
powerpc/powernv: Fundamental reset in pnv_pci_reset_secondary_bus()
powerpc/powernv: Support PCI slot ID
powerpc/powernv: Use firmware PCI slot reset infrastructure
powerpc/powernv: Functions to get/set PCI slot status
powerpc/powernv: Select OF_DYNAMIC
drivers/of: Split unflatten_dt_node()
drivers/of: Avoid recursively calling unflatten_dt_node()
drivers/of: Rename unflatten_dt_node()
drivers/of: Specify parent node in of_fdt_unflatten_tree()
drivers/of: Return allocated memory from of_fdt_unflatten_tree()
PCI/hotplug: PowerPC PowerNV PCI hotplug driver
arch/powerpc/include/asm/eeh.h | 2 +-
arch/powerpc/include/asm/opal-api.h | 17 +-
arch/powerpc/include/asm/opal.h | 8 +-
arch/powerpc/include/asm/pci-bridge.h | 25 +-
arch/powerpc/include/asm/pnv-pci.h | 7 +
arch/powerpc/include/asm/ppc-pci.h | 8 +-
arch/powerpc/kernel/eeh_dev.c | 17 +-
arch/powerpc/kernel/eeh_driver.c | 12 +-
arch/powerpc/kernel/pci-common.c | 16 +-
arch/powerpc/kernel/pci-hotplug.c | 47 +-
arch/powerpc/kernel/pci_dn.c | 89 +-
arch/powerpc/platforms/maple/pci.c | 34 +-
arch/powerpc/platforms/pasemi/pci.c | 3 -
arch/powerpc/platforms/powermac/pci.c | 38 +-
arch/powerpc/platforms/powernv/Kconfig | 1 +
arch/powerpc/platforms/powernv/eeh-powernv.c | 179 ++--
arch/powerpc/platforms/powernv/opal-wrappers.S | 4 +
arch/powerpc/platforms/powernv/pci-ioda.c | 1243 +++++++++++++++---------
arch/powerpc/platforms/powernv/pci.c | 92 +-
arch/powerpc/platforms/powernv/pci.h | 60 +-
arch/powerpc/platforms/pseries/msi.c | 4 +-
arch/powerpc/platforms/pseries/pci_dlpar.c | 32 -
arch/powerpc/platforms/pseries/setup.c | 8 +-
drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 2 +-
drivers/of/fdt.c | 372 ++++---
drivers/of/unittest.c | 2 +-
drivers/pci/hotplug/Kconfig | 12 +
drivers/pci/hotplug/Makefile | 3 +
drivers/pci/hotplug/pnv_php.c | 870 +++++++++++++++++
drivers/pci/hotplug/rpadlpar_core.c | 8 +-
drivers/pci/hotplug/rpaphp_core.c | 4 +-
drivers/pci/hotplug/rpaphp_pci.c | 4 +-
drivers/pci/setup-bus.c | 5 +
include/linux/of_fdt.h | 5 +-
include/linux/pci.h | 1 +
35 files changed, 2360 insertions(+), 874 deletions(-)
create mode 100644 drivers/pci/hotplug/pnv_php.c
On Wed, Apr 13, 2016 at 04:21:07PM +1000, Alexey Kardashevskiy wrote:
quoted
On 02/17/2016 02:43 PM, Gavin Shan wrote:
quoted
There are two arrays for IO and M32 segment maps on every PHB.
The index of the arrays are segment number and the value stored
in the corresponding element is PE number, indicating the segment
is assigned to the PE. Initially, all elements in those two arrays
are zeroes, meaning all segments are assigned to PE#0. It's wrong.
This fixes the initial values in the elements of those two arrays
to IODA_INVALID_PE, meaning all segments aren't assigned to any
PE.
This is ok.
quoted
In order to use IODA_INVALID_PE (-1) to represent invalid PE
number, the types of those two arrays are changed from "unsigned int"
to "int".
"unsigned" can carry (-1) perfectly fine, just add a type cast to
IODA_INVALID_PE:
#define IODA_INVALID_PE (unsigned int)(-1)
Using "signed" type for indexes which cannot be negative does not make much
sense - instead of checking for the upper boundary, you have to check for "<
0" too.
OPAL uses unsigned type for PE (uint64_t or uint32_t or uint16_t - this is
quite funny).
pnv_ioda_pe::pe_number is "unsigned" and this pe_number is the same thing as
I can see in pnv_ioda_setup_dev_PE().
Some printk() print the PE number as "%x" (which implies "unsigned").
Yes, I can simply have something like below when PE number as well as
segment index are represented by "unsigned int" values, right?
#define IODA_INVALID_PE 0xffffffff
This will work too, yes.
quoted
I suggest changing the pci_dn::pe_number type from "int" to "unsigned int" to
match pnv_ioda_pe::pe_number, in a separate patch. Or do not touch types for
now.
Yes, I will have a separate patch right before this one to address it.
On Wed, Apr 13, 2016 at 07:14:59PM +1000, Alexey Kardashevskiy wrote:
On 04/13/2016 05:42 PM, Gavin Shan wrote:
quoted
On Wed, Apr 13, 2016 at 05:28:15PM +1000, Alexey Kardashevskiy wrote:
quoted
On 02/17/2016 02:43 PM, Gavin Shan wrote:
quoted
This series of patches rebases on powerpc/next branch, plus below additional
patches:
<This series of patches>
<Followup 3 patches from Gavin on SRIOV EEH, which aren't posted>
https://patchwork.ozlabs.org/patch/581315/ (PATCH[1/9] Richard's SRIOV EEH)
https://patchwork.ozlabs.org/patch/582639/ (PATCH[1/1] Gavin's EEH fix)
https://patchwork.ozlabs.org/patch/582093/ (PATCH[1/1] Gavin's EEH fix)
https://patchwork.ozlabs.org/patch/580626/ (PATCH[1/4] Gavin's PCI fix)
https://patchwork.ozlabs.org/patch/580153/ (PATCH[1/1] Andrew's EEH minor fix)
https://patchwork.ozlabs.org/patch/566827/ (PATCH[1/1] Russell's P5IOC2 removal)
https://patchwork.ozlabs.org/patch/534154/ (PATCH[1/7] Richard's SRIOV rework)
commit 388f7b1 ("Linux 4.5-rc3")
The series of patches intend to support PCI slot for PowerPC PowerNV platform,
which is running on top of skiboot firmware. The patchset requires corresponding
changes from skiboot firmware, which is sent to skiboot@lists.ozlabs.org
for review. The PCI slots are exposed by skiboot with device node properties,
and kernel utilizes those properties to populated PCI slots accordingly.
The original PCI infrastructure on PowerNV platform can't support hotplug
because the PE is assigned during PHB fixup time, which is called for once
during system boot time. For this, the PCI infrastructure on PowerNV platform
has been reworked for a lot. After that, the PE and its corresponding resources
(IODT, M32DT, M64 segments, DMA32 and bypass window) are assigned upon updating
PCI bridge's resources, which might decide PE# assigned to the PE (e.g. M64
resources, on P8 strictly speaking). Each PE will maintain a reference count,
which is (number of child PCI devices + 1). That indicates when last child PCI
device leaves the PE, the PE and its included resources will be relased and put
back into free pool again. With this design, the PE will be released when EEH PE
is released. PATCH[1 - 23] are related to this part.
From skiboot perspective, PCI slot is providing (hot/fundamental/complete)
resets to EEH. The kernel gets to know if skiboot supports various reset on one
particular PCI slot through device-tree node. If it does, EEH will utilize the
functionality provided by skiboot. Besides, the device-tree nodes have to change
in order to support PCI hotplug. For example, when one PCI adapter inserted to
one slot, its device-tree node should be added to the system dynamically. Conversely,
the device-tree node should be removed from the system when the PCI adapter is going
to be offline. Since pci_dn and eeh_dev have same life cyle as PCI device nodes,
they should be added/removed accordingly during PCI hotplug. PATCH[24 - 39] are
doing the related work.
The OF driver is changed to support unflattening FDT blob for sub-stree, which
is covered by PATCH[40 - 44].
The last one, PATCH[45], is the standalone PCI hotplug driver for PowerPC PowerNV
platform.
=======
Testing
=======
1. Unplug adapters behind non-empty slot, then plug them.
1.1 Check status
# cat /sys/bus/pci/slots/C10/address
0003:09:00
# cat /sys/bus/pci/slots/C10/adapter
1
# cat /sys/bus/pci/slots/C10/power
1
# lspci
0003:09:00.0 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.1 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.2 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.3 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
# lspci -t
# lspci -t
-+-[0003:00]---00.0-[01-13]----00.0-[02-13]--+-01.0-[03]----00.0
| +-08.0-[04-08]--
| +-09.0-[09]--+-00.0
| | +-00.1
| | +-00.2
| | \-00.3
| +-10.0-[0a-0e]--
| \-11.0-[0f-13]--
1.2 Unplug adapter 0003:09.00.x
# echo 0 > /sys/bus/pci/slots/C10/power
# lspci -t
-+-[0003:00]---00.0-[01-13]----00.0-[02-13]--+-01.0-[03]----00.0
| +-08.0-[04-08]--
| +-09.0-[09]--
| +-10.0-[0a-0e]--
| \-11.0-[0f-13]--
1.3 Plug adapter 0003:09.00.x
# echo 1 > /sys/bus/pci/slots/C10/power
Do I understand correctly that the adapter was not physically moved in/out of
the slot between 1.2 and 1.3?
Correct.
This is not right then... Someone should try it, on both P7 and P8.
Do you mean physically pull the adapter out and insert the same
adapter back? What's the point for the test case?
I am confused - why is this needed to test hotplug?
Without the series, the EEH reset is always done by kenrel. With the
series applied, the EEH reset could be done in skiboot.
Why exactly cannot EEH reset changes go to a smaller separate patchset
(before hotplug)?
As I explained before, the patchset's order is: PCI generic part,
PowerNV PCI related, EEH related, device-tree part and hotplug driver.
The EEH reset change is included in PATCH[37/45]. There is no point
to reorder the patches.
quoted
That's the
major change introduced by the series from EEH's perspective. Also,
the EEH code was touched.
quoted
quoted
# cat /sys/bus/pci/devices/0003:09:00.0/eeh_pe_config_addr
0x1
# echo 1:0:4:0:0 > /sys/kernel/debug/powerpc/PCI0003/err_injct
# lspci -ns 0003:09:00.0
# dmesg | grep EEH
EEH: Frozen PHB#3-PE#1 detected
EEH: PE location: U78C9.001.WZS00CF-P1-C10, PHB location: N/A
EEH: Detected PCI bus error on PHB#3-PE#1
EEH: This PCI device has failed 1 times in the last hour
EEH: Notify device drivers to shutdown
EEH: Collect temporary log
EEH: Reset without hotplug activity
EEH: Notify device drivers the completion of reset
EEH: Notify device driver to resume
2. Plug adapter and then unplug it. This requires hack in skiboot
to skip probing the adapters behind the target (C12 in the
testing) for once.
2.1 Check status
# cat /sys/bus/pci/slots/C12/address
0001:06
# cat /sys/bus/pci/slots/C12/power
0
# cat /sys/bus/pci/slots/C12/adapter
1
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--
2.2 Plug adapter 0001:06:00.x
# echo 1 > /sys/bus/pci/slots/C12/power
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--+-00.0
\-00.1
# lspci
0001:06:00.0 Ethernet controller: \
Broadcom Corporation NetXtreme II BCM57810 10 Gigabit Ethernet (rev 10)
0001:06:00.1 Ethernet controller: \
Broadcom Corporation NetXtreme II BCM57810 10 Gigabit Ethernet (rev 10)
2.3 Inject EEH error to adapter 0001:06:00.x, which is recovered
# cat /sys/bus/pci/devices/0001:06:00.0/eeh_pe_config_addr
0x2
# echo 2:0:4:0:0 > /sys/kernel/debug/powerpc/PCI0001/err_injct
# dmesg | grep EEH
EEH: Frozen PHB#1-PE#2 detected
EEH: PE location: U78C9.001.WZS00CF-P1-C12, PHB location: N/A
EEH: Detected PCI bus error on PHB#1-PE#2
EEH: This PCI device has failed 1 times in the last hour
EEH: Notify device drivers to shutdown
EEH: Collect temporary log
EEH: Reset without hotplug activity
EEH: Notify device drivers the completion of reset
EEH: Notify device driver to resume
2.4 Unplug adapter 0001:06:00.x
# echo 0 > /sys/bus/pci/slots/C12/power
# lspci -t
+-[0001:00]---00.0-[01-0a]----00.0-[02-0a]--+-01.0-[03-04]----00.0-[04]----00.0
+-08.0-[05]----00.0
\-09.0-[06-0a]--
=========
Changelog
=========
v8:
* Rebased to linux-powerpc next branch.
* Resolve comments from Alexey and Daniel on PCI part
* Resolve comments from Rob on fdt.c
* Retested (refer to the "Testing section")
v7:
* Reworked revision to some extent.
* Rebased to powerpc/next repository.
* Reorder/split/merge/drop according - Alexey.
* Defined macros and use array to track IO/M32/M64/DMA32 segments - Alexey.
* Merged 3 files to one for the hotplug driver - Alexey.
* As part of OPAL API, defined macros for PCI slot power state, hotplug
message type. Defined macros for PCI slot power confirmed state in
hotplug driver.
* Misc comments from Alexey.
* Reworked unflatten_dt_node() to avoid recursive function calls.
* Use EXPORT_SYMBOL_GPL() and document function's input/output - Rob/Frank.
v6:
* Patch reorder, split, squash - Alexey.
* Minor coding style - Alexey.
* Better function names for pcibios_{add,remove}_pci_devices - Bjorn
* Replace pr_warn() with dev_warn() in PowerNV hotplug driver - Bjorn
* Concurrent depth as parameter passed to __unflatten_dt_node() - Grant / Alexey
* Replace overlay with of_changeset - Grant
v5:
* Rebased to 4.1.rc6 and some unmerged patches as below:
Alexey's DDW patchset (v11);
Gavin's EEH error injection support (in mpe's next branch);
Richard's EEH cleanup patches (in mpe's next branch);
Richard's EEH support for VF (v7);
Gavin's misc EEH fixes for 4.2;
* The revision bases on skiboot corresponding patches (v7):
https://patchwork.ozlabs.org/patch/480437/
* Utilize OF overlay to update device-tree with help of newly introduced
OPAL API opal_get_overlay_dt().
* Split patches for easy review according to aik's comments.
* Fix coding style from checkpatchc.pl as pointed by aik.
* Code cleanup and misc fixup according to aik's input.
v4:
* Rebased to 4.1.RC1
* Added API to unflatten FDT blob to device node sub-tree, which is attached
the indicated parent device node. The original mechanism based on formatted
string stream has been dropped.
* The PATCH[v3 09/21] ("powerpc/eeh: Delay probing EEH device during hotplug")
was picked up sent to linux-ppc@ separately for review as Richard's "VF EEH
Support" depends on that.
v3:
* Rebased to 4.1.RC0
* PowerNV PCI infrasturcture is total refactored in order to support PCI
hotplug. The PowerNV hotplug driver is also reworked a lot because of
the changes in skiboot in order to support PCI hotplug.
Gavin Shan (45):
PCI: Add pcibios_setup_bridge()
powerpc/pci: Override pcibios_setup_bridge()
powerpc/pci: Cleanup on struct pci_controller_ops
powerpc/powernv: Cleanup on pci_controller_ops instances
powerpc/powernv: Drop phb->bdfn_to_pe()
powerpc/powernv: Reorder fields in struct pnv_phb
powerpc/powernv: Rename PE# fields in struct pnv_phb
powerpc/powernv: Fix initial IO and M32 segmap
powerpc/powernv: Simplify pnv_ioda_setup_pe_seg()
powerpc/powernv: IO and M32 mapping based on PCI device resources
powerpc/powernv: Track M64 segment consumption
powerpc/powernv: Rename M64 related functions
powerpc/powernv/ioda1: M64 support on P7IOC
powerpc/powernv/ioda1: Rename pnv_pci_ioda_setup_dma_pe()
powerpc/powernv/ioda1: Introduce PNV_IODA1_DMA32_SEGSIZE
powerpc/powernv: Remove DMA32 PE list
powerpc/powernv/ioda1: Improve DMA32 segment track
powerpc/powernv: Increase PE# capacity
powerpc/powernv: Use PE instead of number during setup and release
powerpc/powernv: Allocate PE# in reverse order
powerpc/powernv: Create PEs at PCI hot plugging time
powerpc/powernv/ioda1: Support releasing IODA1 TCE table
powerpc/powernv: Dynamically release PEs
powerpc/pci: Rename pcibios_{add,remove}_pci_devices()
powerpc/pci: Rename pcibios_find_pci_bus()
powerpc/pci: Move pci_find_bus_by_node() around
powerpc/pci: Export pci_add_device_node_info()
powerpc/pci: Introduce pci_remove_device_node_info()
powerpc/pci: Export pci_traverse_device_nodes()
powerpc/pci: Delay populating pdn
powerpc/pci: Don't scan empty slot
powerpc/pci: Update bridge windows on PCI plug
powerpc/powernv: Simplify pnv_eeh_reset()
powerpc/powernv: Exclude root bus in pnv_pci_reset_secondary_bus()
powerpc/powernv: Fundamental reset in pnv_pci_reset_secondary_bus()
powerpc/powernv: Support PCI slot ID
powerpc/powernv: Use firmware PCI slot reset infrastructure
powerpc/powernv: Functions to get/set PCI slot status
powerpc/powernv: Select OF_DYNAMIC
drivers/of: Split unflatten_dt_node()
drivers/of: Avoid recursively calling unflatten_dt_node()
drivers/of: Rename unflatten_dt_node()
drivers/of: Specify parent node in of_fdt_unflatten_tree()
drivers/of: Return allocated memory from of_fdt_unflatten_tree()
PCI/hotplug: PowerPC PowerNV PCI hotplug driver
arch/powerpc/include/asm/eeh.h | 2 +-
arch/powerpc/include/asm/opal-api.h | 17 +-
arch/powerpc/include/asm/opal.h | 8 +-
arch/powerpc/include/asm/pci-bridge.h | 25 +-
arch/powerpc/include/asm/pnv-pci.h | 7 +
arch/powerpc/include/asm/ppc-pci.h | 8 +-
arch/powerpc/kernel/eeh_dev.c | 17 +-
arch/powerpc/kernel/eeh_driver.c | 12 +-
arch/powerpc/kernel/pci-common.c | 16 +-
arch/powerpc/kernel/pci-hotplug.c | 47 +-
arch/powerpc/kernel/pci_dn.c | 89 +-
arch/powerpc/platforms/maple/pci.c | 34 +-
arch/powerpc/platforms/pasemi/pci.c | 3 -
arch/powerpc/platforms/powermac/pci.c | 38 +-
arch/powerpc/platforms/powernv/Kconfig | 1 +
arch/powerpc/platforms/powernv/eeh-powernv.c | 179 ++--
arch/powerpc/platforms/powernv/opal-wrappers.S | 4 +
arch/powerpc/platforms/powernv/pci-ioda.c | 1243 +++++++++++++++---------
arch/powerpc/platforms/powernv/pci.c | 92 +-
arch/powerpc/platforms/powernv/pci.h | 60 +-
arch/powerpc/platforms/pseries/msi.c | 4 +-
arch/powerpc/platforms/pseries/pci_dlpar.c | 32 -
arch/powerpc/platforms/pseries/setup.c | 8 +-
drivers/gpu/drm/tilcdc/tilcdc_slave_compat.c | 2 +-
drivers/of/fdt.c | 372 ++++---
drivers/of/unittest.c | 2 +-
drivers/pci/hotplug/Kconfig | 12 +
drivers/pci/hotplug/Makefile | 3 +
drivers/pci/hotplug/pnv_php.c | 870 +++++++++++++++++
drivers/pci/hotplug/rpadlpar_core.c | 8 +-
drivers/pci/hotplug/rpaphp_core.c | 4 +-
drivers/pci/hotplug/rpaphp_pci.c | 4 +-
drivers/pci/setup-bus.c | 5 +
include/linux/of_fdt.h | 5 +-
include/linux/pci.h | 1 +
35 files changed, 2360 insertions(+), 874 deletions(-)
create mode 100644 drivers/pci/hotplug/pnv_php.c
Why exactly cannot EEH reset changes go to a smaller separate patchset
(before hotplug)?
As I explained before, the patchset's order is: PCI generic part,
PowerNV PCI related, EEH related, device-tree part and hotplug driver.
The EEH reset change is included in PATCH[37/45]. There is no point
to reorder the patches.
I don't understand all of the dependencies but if possible splitting the
series up into a set of smaller self-contained patch series makes things
easier to review and may make it easier for you to get this functionality
reviewed and accepted into upstream.
Regards,
Alistair
On Thu, Apr 14, 2016 at 09:57:32AM +1000, Alistair Popple wrote:
Hi Gavin,
<snip>
quoted
quoted
Why exactly cannot EEH reset changes go to a smaller separate patchset
(before hotplug)?
As I explained before, the patchset's order is: PCI generic part,
PowerNV PCI related, EEH related, device-tree part and hotplug driver.
The EEH reset change is included in PATCH[37/45]. There is no point
to reorder the patches.
I don't understand all of the dependencies but if possible splitting the
series up into a set of smaller self-contained patch series makes things
easier to review and may make it easier for you to get this functionality
reviewed and accepted into upstream.
Thanks, Alistair. I will move those cleanup/refactor related patches
to form a separate series which is expected to be merged first. That
will helps the reviewers to focus on the patches with complicated
changes as you suggested. Alexey, please let me know if that way is
you like to see or not.
Thanks,
Gavin
On Wed, Apr 13, 2016 at 07:14:59PM +1000, Alexey Kardashevskiy wrote:
quoted
On 04/13/2016 05:42 PM, Gavin Shan wrote:
quoted
On Wed, Apr 13, 2016 at 05:28:15PM +1000, Alexey Kardashevskiy wrote:
quoted
On 02/17/2016 02:43 PM, Gavin Shan wrote:
quoted
This series of patches rebases on powerpc/next branch, plus below additional
patches:
<This series of patches>
<Followup 3 patches from Gavin on SRIOV EEH, which aren't posted>
https://patchwork.ozlabs.org/patch/581315/ (PATCH[1/9] Richard's SRIOV EEH)
https://patchwork.ozlabs.org/patch/582639/ (PATCH[1/1] Gavin's EEH fix)
https://patchwork.ozlabs.org/patch/582093/ (PATCH[1/1] Gavin's EEH fix)
https://patchwork.ozlabs.org/patch/580626/ (PATCH[1/4] Gavin's PCI fix)
https://patchwork.ozlabs.org/patch/580153/ (PATCH[1/1] Andrew's EEH minor fix)
https://patchwork.ozlabs.org/patch/566827/ (PATCH[1/1] Russell's P5IOC2 removal)
https://patchwork.ozlabs.org/patch/534154/ (PATCH[1/7] Richard's SRIOV rework)
commit 388f7b1 ("Linux 4.5-rc3")
The series of patches intend to support PCI slot for PowerPC PowerNV platform,
which is running on top of skiboot firmware. The patchset requires corresponding
changes from skiboot firmware, which is sent to skiboot@lists.ozlabs.org
for review. The PCI slots are exposed by skiboot with device node properties,
and kernel utilizes those properties to populated PCI slots accordingly.
The original PCI infrastructure on PowerNV platform can't support hotplug
because the PE is assigned during PHB fixup time, which is called for once
during system boot time. For this, the PCI infrastructure on PowerNV platform
has been reworked for a lot. After that, the PE and its corresponding resources
(IODT, M32DT, M64 segments, DMA32 and bypass window) are assigned upon updating
PCI bridge's resources, which might decide PE# assigned to the PE (e.g. M64
resources, on P8 strictly speaking). Each PE will maintain a reference count,
which is (number of child PCI devices + 1). That indicates when last child PCI
device leaves the PE, the PE and its included resources will be relased and put
back into free pool again. With this design, the PE will be released when EEH PE
is released. PATCH[1 - 23] are related to this part.
From skiboot perspective, PCI slot is providing (hot/fundamental/complete)
resets to EEH. The kernel gets to know if skiboot supports various reset on one
particular PCI slot through device-tree node. If it does, EEH will utilize the
functionality provided by skiboot. Besides, the device-tree nodes have to change
in order to support PCI hotplug. For example, when one PCI adapter inserted to
one slot, its device-tree node should be added to the system dynamically. Conversely,
the device-tree node should be removed from the system when the PCI adapter is going
to be offline. Since pci_dn and eeh_dev have same life cyle as PCI device nodes,
they should be added/removed accordingly during PCI hotplug. PATCH[24 - 39] are
doing the related work.
The OF driver is changed to support unflattening FDT blob for sub-stree, which
is covered by PATCH[40 - 44].
The last one, PATCH[45], is the standalone PCI hotplug driver for PowerPC PowerNV
platform.
=======
Testing
=======
1. Unplug adapters behind non-empty slot, then plug them.
1.1 Check status
# cat /sys/bus/pci/slots/C10/address
0003:09:00
# cat /sys/bus/pci/slots/C10/adapter
1
# cat /sys/bus/pci/slots/C10/power
1
# lspci
0003:09:00.0 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.1 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.2 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
0003:09:00.3 Ethernet controller: \
Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)
# lspci -t
# lspci -t
-+-[0003:00]---00.0-[01-13]----00.0-[02-13]--+-01.0-[03]----00.0
| +-08.0-[04-08]--
| +-09.0-[09]--+-00.0
| | +-00.1
| | +-00.2
| | \-00.3
| +-10.0-[0a-0e]--
| \-11.0-[0f-13]--
1.2 Unplug adapter 0003:09.00.x
# echo 0 > /sys/bus/pci/slots/C10/power
# lspci -t
-+-[0003:00]---00.0-[01-13]----00.0-[02-13]--+-01.0-[03]----00.0
| +-08.0-[04-08]--
| +-09.0-[09]--
| +-10.0-[0a-0e]--
| \-11.0-[0f-13]--
1.3 Plug adapter 0003:09.00.x
# echo 1 > /sys/bus/pci/slots/C10/power
Do I understand correctly that the adapter was not physically moved in/out of
the slot between 1.2 and 1.3?
Correct.
This is not right then... Someone should try it, on both P7 and P8.
Do you mean physically pull the adapter out and insert the same
adapter back? What's the point for the test case?
Because this is what the patchset is for - to replace a physical device on
a physical machine. Powering on/off the slots via sysfs is just an
approximation (which is fine when you are debugging), something can go
wrong and require some work but you do not know it for sure.
--
Alexey
On Thu, Apr 14, 2016 at 09:57:32AM +1000, Alistair Popple wrote:
quoted
Hi Gavin,
<snip>
quoted
quoted
Why exactly cannot EEH reset changes go to a smaller separate patchset
(before hotplug)?
As I explained before, the patchset's order is: PCI generic part,
PowerNV PCI related, EEH related, device-tree part and hotplug driver.
The EEH reset change is included in PATCH[37/45]. There is no point
to reorder the patches.
I don't understand all of the dependencies but if possible splitting the
series up into a set of smaller self-contained patch series makes things
easier to review and may make it easier for you to get this functionality
reviewed and accepted into upstream.
Thanks, Alistair. I will move those cleanup/refactor related patches
to form a separate series which is expected to be merged first. That
will helps the reviewers to focus on the patches with complicated
changes as you suggested. Alexey, please let me know if that way is
you like to see or not.
I do not know yet, I have not finished reviewing this version. May be the
EEH reset patch depends on 1/45..36/45; or it only makes sense when 45/45
is applied - this all is unclear.
If 37/45 has no dependencies and good just by itself, you could have posted
it separately few months ago and it would have reached upstream by now and
this patchset would be at least one patch shorter and you would not have to
rebase all 45 patches over and over again on top of the current upstream
tree...
--
Alexey
On Thu, Apr 14, 2016 at 01:26:51PM +1000, Alexey Kardashevskiy wrote:
.../...
quoted
Do you mean physically pull the adapter out and insert the same
adapter back? What's the point for the test case?
Because this is what the patchset is for - to replace a physical device on a
physical machine. Powering on/off the slots via sysfs is just an
approximation (which is fine when you are debugging), something can go wrong
and require some work but you do not know it for sure.
Yes, It's absolutely worthy to be covered by the test cases though case (2)
covers part of that. Anyway, I'll test it through in next revision. Thanks
for your review.
From: Rob Herring <hidden> Date: 2016-04-15 16:10:21
On Wed, Apr 13, 2016 at 8:30 PM, Gavin Shan [off-list ref] wrote:
On Thu, Apr 14, 2016 at 09:57:32AM +1000, Alistair Popple wrote:
quoted
Hi Gavin,
<snip>
quoted
quoted
Why exactly cannot EEH reset changes go to a smaller separate patchset
(before hotplug)?
As I explained before, the patchset's order is: PCI generic part,
PowerNV PCI related, EEH related, device-tree part and hotplug driver.
The EEH reset change is included in PATCH[37/45]. There is no point
to reorder the patches.
I don't understand all of the dependencies but if possible splitting the
series up into a set of smaller self-contained patch series makes things
easier to review and may make it easier for you to get this functionality
reviewed and accepted into upstream.
Thanks, Alistair. I will move those cleanup/refactor related patches
to form a separate series which is expected to be merged first. That
will helps the reviewers to focus on the patches with complicated
changes as you suggested. Alexey, please let me know if that way is
you like to see or not.
As I said last cycle, I'll happily take the DT refactoring patches
separately, but you have to tell me if you want me to apply them and
it has to be well before the merge window.
Rob
Each PHB maintains an array helping to translate 2-bytes Request
ID (RID) to PE# with the assumption that PE# takes one byte, meaning
that we can't have more than 256 PEs. However, pci_dn->pe_number
already had 4-bytes for the PE#.
This extends the PE# capacity for every PHB. After that, the PE number
is represented by 4-bytes value. Then we can reuse IODA_INVALID_PE to
check the PE# in phb->pe_rmap[] is valid or not.
This should be merged into "[PATCH v8 21/45] powerpc/powernv: Create PEs at
PCI hot plugging time" as it does not make sense alone (this patch does the
initialization but only 3 patches apart this default value is analyzed ->
hard to review).
In current implementation, the PEs that are allocated or picked
from the reserved list are identified by PE number. The PE instance
has to be picked according to the PE number eventually. We have
same issue when PE is released.
For pnv_ioda_pick_m64_pe() and pnv_ioda_alloc_pe(), this returns
PE instance so that pnv_ioda_setup_bus_PE() can use the allocated
or reserved PE instance directly. Also, pnv_ioda_setup_bus_PE()
returns the reserved/allocated PE instance to be used in subsequent
patches. On the other hand, pnv_ioda_free_pe() uses PE instance
(not number) as its argument. No logical changes introduced.
Signed-off-by: Gavin Shan <redacted>
@@ -119,6 +119,14 @@ static inline bool pnv_pci_is_mem_pref_64(unsigned long flags)(IORESOURCE_MEM_64|IORESOURCE_PREFETCH));}+staticstructpnv_ioda_pe*pnv_ioda_init_pe(structpnv_phb*phb,intpe_no)+{+phb->ioda.pe_array[pe_no].phb=phb;+phb->ioda.pe_array[pe_no].pe_number=pe_no;++return&phb->ioda.pe_array[pe_no];+}+staticvoidpnv_ioda_reserve_pe(structpnv_phb*phb,intpe_no){if(!(pe_no>=0&&pe_no<phb->ioda.total_pe_num)){
@@ -131,11 +139,10 @@ static void pnv_ioda_reserve_pe(struct pnv_phb *phb, int pe_no)pr_debug("%s: PE %d was reserved on PHB#%x\n",__func__,pe_no,phb->hose->global_number);-phb->ioda.pe_array[pe_no].phb=phb;-phb->ioda.pe_array[pe_no].pe_number=pe_no;+pnv_ioda_init_pe(phb,pe_no);}-staticintpnv_ioda_alloc_pe(structpnv_phb*phb)+staticstructpnv_ioda_pe*pnv_ioda_alloc_pe(structpnv_phb*phb){unsignedlongpe;
@@ -143,20 +150,20 @@ static int pnv_ioda_alloc_pe(struct pnv_phb *phb)pe=find_next_zero_bit(phb->ioda.pe_alloc,phb->ioda.total_pe_num,0);if(pe>=phb->ioda.total_pe_num)-returnIODA_INVALID_PE;+returnNULL;}while(test_and_set_bit(pe,phb->ioda.pe_alloc));-phb->ioda.pe_array[pe].phb=phb;-phb->ioda.pe_array[pe].pe_number=pe;-returnpe;+returnpnv_ioda_init_pe(phb,pe);}-staticvoidpnv_ioda_free_pe(structpnv_phb*phb,intpe)+staticvoidpnv_ioda_free_pe(structpnv_ioda_pe*pe){-WARN_ON(phb->ioda.pe_array[pe].pdev);+structpnv_phb*phb=pe->phb;-memset(&phb->ioda.pe_array[pe],0,sizeof(structpnv_ioda_pe));-clear_bit(pe,phb->ioda.pe_alloc);+WARN_ON(pe->pdev);++memset(pe,0,sizeof(structpnv_ioda_pe));+clear_bit(pe->pe_number,phb->ioda.pe_alloc);}/* The default M64 BAR is shared by all PEs */
@@ -326,7 +333,7 @@ static int pnv_ioda_pick_m64_pe(struct pci_bus *bus, bool all)/* Root bus shouldn't use M64 */if(pci_is_root_bus(bus))-returnIODA_INVALID_PE;+returnNULL;/* Allocate bitmap */size=_ALIGN_UP(phb->ioda.total_pe_num/8,sizeof(unsignedlong));
@@ -334,7 +341,7 @@ static int pnv_ioda_pick_m64_pe(struct pci_bus *bus, bool all)if(!pe_alloc){pr_warn("%s: Out of memory !\n",__func__);-returnIODA_INVALID_PE;+returnNULL;}/* Figure out reserved PE numbers by the PE */
@@ -997,8 +1002,7 @@ static struct pnv_ioda_pe *pnv_ioda_setup_dev_PE(struct pci_dev *dev)if(pnv_ioda_configure_pe(phb,pe)){/* XXX What do we do here ? */-if(pe_num)-pnv_ioda_free_pe(phb,pe_num);+pnv_ioda_free_pe(pe);pdn->pe_number=IODA_INVALID_PE;pe->pdev=NULL;pci_dev_put(dev);
@@ -1033,28 +1037,26 @@ static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe)*subordinatePCIdevicesandbuses.ThesecondtypeofPEisnormally*orgiriatedbyPCIe-to-PCIbridgeorPLXswitchdownstreamports.*/-staticvoidpnv_ioda_setup_bus_PE(structpci_bus*bus,boolall)+staticstructpnv_ioda_pe*pnv_ioda_setup_bus_PE(structpci_bus*bus,boolall){structpci_controller*hose=pci_bus_to_host(bus);structpnv_phb*phb=hose->private_data;-structpnv_ioda_pe*pe;-intpe_num=IODA_INVALID_PE;+structpnv_ioda_pe*pe=NULL;/* Check if PE is determined by M64 */if(phb->pick_m64_pe)-pe_num=phb->pick_m64_pe(bus,all);+pe=phb->pick_m64_pe(bus,all);/* The PE number isn't pinned by M64 */-if(pe_num==IODA_INVALID_PE)-pe_num=pnv_ioda_alloc_pe(phb);+if(!pe)+pe=pnv_ioda_alloc_pe(phb);-if(pe_num==IODA_INVALID_PE){+if(!pe){pr_warning("%s: Not enough PE# available for PCI bus %04x:%02x\n",__func__,pci_domain_nr(bus),bus->number);-return;+returnNULL;}-pe=&phb->ioda.pe_array[pe_num];pe->flags|=(all?PNV_IODA_PE_BUS_ALL:PNV_IODA_PE_BUS);pe->pbus=bus;pe->pdev=NULL;
@@ -1063,17 +1065,16 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, bool all)if(all)pe_info(pe,"Secondary bus %d..%d associated with PE#%d\n",-bus->busn_res.start,bus->busn_res.end,pe_num);+bus->busn_res.start,bus->busn_res.end,pe->pe_number);elsepe_info(pe,"Secondary bus %d associated with PE#%d\n",-bus->busn_res.start,pe_num);+bus->busn_res.start,pe->pe_number);if(pnv_ioda_configure_pe(phb,pe)){/* XXX What do we do here ? */-if(pe_num)-pnv_ioda_free_pe(phb,pe_num);+pnv_ioda_free_pe(pe);pe->pbus=NULL;-return;+returnNULL;}/* Associate it with all child devices */
@@ -1081,6 +1082,8 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, bool all)/* Put PE to the list */list_add_tail(&pe->list,&phb->ioda.pe_list);++returnpe;}staticstructpnv_ioda_pe*pnv_ioda_setup_npu_PE(structpci_dev*npu_pdev)
@@ -1479,8 +1486,7 @@ static void pnv_ioda_setup_vf_PE(struct pci_dev *pdev, u16 num_vfs)if(pnv_ioda_configure_pe(phb,pe)){/* XXX What do we do here ? */-if(pe_num)-pnv_ioda_free_pe(phb,pe_num);+pnv_ioda_free_pe(pe);pe->pdev=NULL;continue;}
@@ -1499,6 +1505,7 @@ int pnv_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs)structpci_bus*bus;structpci_controller*hose;structpnv_phb*phb;+structpnv_ioda_pe*pe;structpci_dn*pdn;intret;u16i;
@@ -1541,11 +1548,13 @@ int pnv_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs)/* Calculate available PE for required VFs */if(pdn->m64_single_mode){for(i=0;i<num_vfs;i++){-pdn->pe_num_map[i]=pnv_ioda_alloc_pe(phb);-if(pdn->pe_num_map[i]==IODA_INVALID_PE){+pe=pnv_ioda_alloc_pe(phb);+if(!pe){ret=-EBUSY;gotom64_failed;}++pdn->pe_num_map[i]=pe->pe_number;}}else{mutex_lock(&phb->ioda.pe_alloc_mutex);
@@ -1590,8 +1599,11 @@ int pnv_pci_sriov_enable(struct pci_dev *pdev, u16 num_vfs)m64_failed:if(pdn->m64_single_mode){for(i=0;i<num_vfs;i++){-if(pdn->pe_num_map[i]!=IODA_INVALID_PE)-pnv_ioda_free_pe(phb,pdn->pe_num_map[i]);+if(pdn->pe_num_map[i]==IODA_INVALID_PE)+continue;++pe=&phb->ioda.pe_array[pdn->pe_num_map[i]];+pnv_ioda_free_pe(pe);}}elsebitmap_clear(phb->ioda.pe_alloc,*pdn->pe_num_map,num_vfs);
PE number for one particular PE can be allocated dynamically or
reserved according to the consumed M64 (64-bits prefetchable)
segments of the PE. The M64 resources, and hence their segments
and PE number are assigned/reserved in ascending order. The PE
numbers are allocated dynamically in ascending order as well.
It's not a problem as the PE numbers are reserved and then
allocated all at once in fine order. However, it will introduce
conflicts when PCI hotplug is supported: the PE number to be
reserved for newly added PE might have been assigned.
To resolve above conflicts, this forces the PE number to be
allocated dynamically in reverse order. With this patch applied,
the PE numbers are reserved in ascending order, but allocated
dynamically in reverse order.
The patch is probably is ok, the commit log is not - I do not follow it.
Some PEs are reserved (for what? why does the absolute PE number matter?
put it in the commit log), that means that the corresponding bits in
pe_alloc[] should be set so when you will be allocating PEs for a just
plugged device, you won't pick them and you will pick free ones, and the
order should not matter. I would think that "reservation" happens once at
the boot time so you set "used" bits for the reserved PEs then and after
that the dynamic allocator will skip them.
Currently, the PEs and their associated resources are assigned
in ppc_md.pcibios_fixup() except those used by SRIOV VFs.
But this new code does not affect IOV and VF's PEs will still be created
somewhere else rather than pnv_pci_setup_bridge()?
The
function is called for once after PCI probing and resources
assignment is completed. So it isn't hotplug friendly.
This creates PEs dynamically by ppc_md.pcibios_setup_bridge(), which
is called on the event during system bootup and PCI hotplug: updating
PCI bridge's windows after resource assignment/reassignment are done.
For partial hotplug case, where not all PCI devices belonging to the
PE are unplugged and plugged again, we just need unbinding/binding
the affected PCI devices with the corresponding PE without creating
new one.
As there is no upstream bridge for root bus that needs to be covered
by PE, we have to create PE for root bus in ppc_md.pcibios_setup_bridge()
before any other PEs can be created, as PE for root bus is the ancestor
to anyone else.
We did not need a root bus PE before? What is the other PE reserved for?
Comments only say "reserved"...
Also, the windows of root port or the upstream port of PCIe switch behind
root port are extended to be PHB's apertures to accommodate the additional
resources needed by newly plugged devices based on the fact: hotpluggable
slot is behind root port or downstream port of the PCIe switch behind
root port. The extension for those PCI brdiges' windows is done in
ppc_md.pcibios_setup_bridge() as well.
This patch seems to be doing way too many things, hard to follow.
Could you please split the patch into smaller chunks? For example (you can
do it totally different):
- move pnv_pci_ioda_setup_opal_tce_kill()
- move PE creation from pnv_pci_ioda_fixup() to pnv_pci_setup_bridge();
- add pnv_pci_fixup_bridge_resources()
- add an extra reserved PE for the root bus (and all this magic with
root_pe_idx/root_pe_populated)
- ...
--
Alexey
pnv_pci_ioda_table_free_pages() can be reused to release the IODA1
TCE table when releasing IODA1 PE in subsequent patches.
This renames the following functions to support releasing IODA1 TCE
table: pnv_pci_ioda2_table_free_pages() to pnv_pci_ioda_table_free_pages(),
pnv_pci_ioda2_table_do_free_pages() to pnv_pci_ioda_table_do_free_pages().
No logical changes introduced.
I can only see renaming here but it seems (from
IODA_architecture_04-14-2008.pdf) that IODA1 does not support multi-level
TCE tables in the way IODA2 does.
This support releasing PEs dynamically. Firstly, this moves
pnv_pci_ioda2_release_dma_pe() around, which is called to
release DMA resource on releasing IODA2 PE.
imho move would only make sense if we could get rid of the forward
declarations but this is not the case.
quoted hunk
Secondly, several
functions are implemented to release the consumed resources
on releasing the PE:
* pnv_pci_ioda1_unset_window() to unset TVEs for the PE.
* pnv_pci_ioda1_release_dma_pe() to unset TVEs for the PE and
destroy the IOMMU table.
* pnv_ioda_release_pe_seg() releases the consumed IO/M32/M64
segments by the PE.
Lastly, this adds a reference count of PE, representing the number
of PCI devices associated with the PE. The reference count is
increased when PCI device joins the PE. It's decreased when PCI
device leaves the PE in pnv_pci_release_device(). When the count
becomes zero, its consumed resources are released by functions
as mentioned above. Note that the count is accessed concurrently.
So a "counter" with "int" type is enough here.
Signed-off-by: Gavin Shan <redacted>
---
arch/powerpc/platforms/powernv/pci-ioda.c | 236 ++++++++++++++++++++++++++----
arch/powerpc/platforms/powernv/pci.h | 1 +
2 files changed, 209 insertions(+), 28 deletions(-)
If you left this code in its old location, it would be lot more obvious
what you silently changed in this function (checking for weight). Please
either do not move the code (this is preferred as I am hacking same chunk
in "[PATCH kernel 0/2] powerpc/powernv: Fix crash on PF unbind when VF is
passed" and I'd like to reduce conflicts) or split it to a separate patch.
@@ -263,10 +263,10 @@ static inline struct eeh_dev *pdn_to_eeh_dev(struct pci_dn *pdn)externstructpci_bus*pcibios_find_pci_bus(structdevice_node*dn);/** Remove all of the PCI devices under this bus */-externvoidpcibios_remove_pci_devices(structpci_bus*bus);+externvoidpci_remove_pci_devices(structpci_bus*bus);
pci_lala_pci_lala() ("pci" is used twice) looks weird, if the prefix is
"pci", what other device types can they handle?...
May be pcihp_add_devices(), pcihp_remove_devices() as these as defined in
pci-hotplug.c?
quoted hunk
/** Discover new pci devices under this bus, and add them */
-extern void pcibios_add_pci_devices(struct pci_bus *bus);
+extern void pci_add_pci_devices(struct pci_bus *bus);
extern void isa_bridge_find_early(struct pci_controller *hose);
@@ -38,20 +38,20 @@ void pcibios_release_device(struct pci_dev *dev)}/**-*pcibios_remove_pci_devices-removealldevicesunderthisbus+*pci_remove_pci_devices-removealldevicesunderthisbus*@bus:theindicatedPCIbus**RemoveallofthePCIdevicesunderthisbusbothfromthe*linuxpcidevicetree,andfromthepowerpcEEHaddresscache.*/-voidpcibios_remove_pci_devices(structpci_bus*bus)+voidpci_remove_pci_devices(structpci_bus*bus){structpci_dev*dev,*tmp;structpci_bus*child_bus;/* First go down child busses */list_for_each_entry(child_bus,&bus->children,node)-pcibios_remove_pci_devices(child_bus);+pci_remove_pci_devices(child_bus);pr_debug("PCI: Removing devices on bus %04x:%02x\n",pci_domain_nr(bus),bus->number);
This renames pcibios_find_pci_bus() to pci_find_bus_by_node() to
avoid conflicts with those PCI subsystem weak function names, which
have prefix "pcibios". No logical changes introduced.
Signed-off-by: Gavin Shan <redacted>
@@ -260,7 +260,7 @@ static inline struct eeh_dev *pdn_to_eeh_dev(struct pci_dn *pdn)#endif/** Find the bus corresponding to the indicated device node */-externstructpci_bus*pcibios_find_pci_bus(structdevice_node*dn);+externstructpci_bus*pci_find_bus_by_node(structdevice_node*dn);/** Remove all of the PCI devices under this bus */externvoidpci_remove_pci_devices(structpci_bus*bus);
@@ -175,7 +175,7 @@ static int dlpar_add_pci_slot(char *drc_name, struct device_node *dn)structpci_dev*dev;structpci_controller*phb;-if(pcibios_find_pci_bus(dn))+if(pci_find_bus_by_node(dn))return-EINVAL;/* Add pci bus */
@@ -212,7 +212,7 @@ static int dlpar_remove_phb(char *drc_name, struct device_node *dn)structpci_dn*pdn;intrc=0;-if(!pcibios_find_pci_bus(dn))+if(!pci_find_bus_by_node(dn))return-EINVAL;/* If pci slot is hotpluggable, use hotplug to remove it */
@@ -356,7 +356,7 @@ int dlpar_remove_pci_slot(char *drc_name, struct device_node *dn)pci_lock_rescan_remove();-bus=pcibios_find_pci_bus(dn);+bus=pci_find_bus_by_node(dn);if(!bus){ret=-EINVAL;gotoout;
@@ -93,7 +93,7 @@ int rpaphp_enable_slot(struct slot *slot)if(rc)returnrc;-bus=pcibios_find_pci_bus(slot->dn);+bus=pci_find_bus_by_node(slot->dn);if(!bus){err("%s: no pci_bus for dn %s\n",__func__,slot->dn->full_name);return-EINVAL;
This renames update_dn_pci_info() to pci_add_device_node_info()
with corresponding adjustment on the parameter type and exports it.
The function is used to create pdn (struct pci_dn) for the indicated
device node. Another function add_pdn(), almost wrapper of
pci_add_device_node_info(), to be used in traverse_pci_devices(). No
logical changes introduced.
Signed-off-by: Gavin Shan <redacted>
@@ -446,8 +455,7 @@ void pci_devs_phb_init_dynamic(struct pci_controller *phb)structpci_dn*pdn;/* PHB nodes themselves must not match */-update_dn_pci_info(dn,phb);-pdn=dn->data;+pdn=pci_add_device_node_info(phb,dn);if(pdn){pdn->devfn=pdn->busno=-1;pdn->vendor_id=pdn->device_id=pdn->class_code=0;
@@ -456,7 +464,7 @@ void pci_devs_phb_init_dynamic(struct pci_controller *phb)}/* Update dn->phb ptrs for new phb and children devices */-traverse_pci_devices(dn,update_dn_pci_info,phb);+traverse_pci_devices(dn,add_pdn,phb);}/**
This implements and exports pci_remove_device_node_info(). It's
used to remove the pdn (struct pci_dn) for the indicated device
node. The function is going to be used by PowerNV PCI hotplug
driver.
Signed-off-by: Gavin Shan <redacted>
Kind of strange that there is no such helper for pseries, is there?
Reviewed-by: Alexey Kardashevskiy <redacted>