From 8fc1f5d7eff9a4ed0cdb7215e7ca4b82b931d6d7 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 20 May 2013 17:23:22 +0000 Subject: powerpc: Fix TLB cleanup at boot on POWER8 The TLB has 512 congruence classes (2048 entries 4 way set associative) while P7 had 128 Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/cpu_setup_power.S | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'arch') diff --git a/arch/powerpc/kernel/cpu_setup_power.S b/arch/powerpc/kernel/cpu_setup_power.S index a283b6442b26..18b5b9cf8e37 100644 --- a/arch/powerpc/kernel/cpu_setup_power.S +++ b/arch/powerpc/kernel/cpu_setup_power.S @@ -135,8 +135,12 @@ __init_HFSCR: blr __init_TLB: - /* Clear the TLB */ - li r6,128 + /* + * Clear the TLB using the "IS 3" form of tlbiel instruction + * (invalidate by congruence class). P7 has 128 CCs, P8 has 512 + * so we just always do 512 + */ + li r6,512 mtctr r6 li r7,0xc00 /* IS field = 0b11 */ ptesync -- cgit v1.2.2 From bee7dd9c5fd5ab944e2e0ef3b92905fcbc993768 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 20 May 2013 17:24:39 +0000 Subject: powerpc/pci: Fix bogus message at boot about empty memory resources The message is only meant to be displayed if resource 0 is empty, but was displayed if any is. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/pci-common.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 6053f037ef0a..e9acf50dd5b2 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1520,9 +1520,10 @@ static void pcibios_setup_phb_resources(struct pci_controller *hose, for (i = 0; i < 3; ++i) { res = &hose->mem_resources[i]; if (!res->flags) { - printk(KERN_ERR "PCI: Memory resource 0 not set for " - "host bridge %s (domain %d)\n", - hose->dn->full_name, hose->global_number); + if (i == 0) + printk(KERN_ERR "PCI: Memory resource 0 not set for " + "host bridge %s (domain %d)\n", + hose->dn->full_name, hose->global_number); continue; } offset = hose->mem_offset[i]; -- cgit v1.2.2 From 605e44d6e6f9b0c9ca8842dc0eb3ad032a463bdb Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Mon, 20 May 2013 17:25:15 +0000 Subject: powerpc/powernv: Fix condition for when to invalidate the TCE cache We use two flags, one to indicate an invalidation is needed after creating a new entry and one to indicate an invalidation is needed after removing an entry. However we were testing the wrong flag in the remove case. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 163bd7422f1c..098d3573315c 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -367,7 +367,7 @@ static void pnv_tce_free(struct iommu_table *tbl, long index, long npages) while (npages--) *(tcep++) = 0; - if (tbl->it_type & TCE_PCI_SWINV_CREATE) + if (tbl->it_type & TCE_PCI_SWINV_FREE) pnv_pci_ioda_tce_invalidate(tbl, tces, tcep - 1); } -- cgit v1.2.2 From 59affcd3e460b97492bc1aa2b843bafe7c54f596 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 21 May 2013 16:31:12 +0000 Subject: powerpc: Context switch more PMU related SPRs In commit 9353374 "Context switch the new EBB SPRs" we added support for context switching some new EBB SPRs. However despite four of us signing off on that patch we missed some. To be fair these are not actually new SPRs, but they are now potentially user accessible so need to be context switched. Signed-off-by: Michael Ellerman Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/processor.h | 6 ++++++ arch/powerpc/kernel/asm-offsets.c | 6 ++++++ arch/powerpc/kernel/entry_64.S | 28 ++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) (limited to 'arch') diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index d7e67ca8b4a6..594db6bc093c 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -284,6 +284,12 @@ struct thread_struct { unsigned long ebbrr; unsigned long ebbhr; unsigned long bescr; + unsigned long siar; + unsigned long sdar; + unsigned long sier; + unsigned long mmcr0; + unsigned long mmcr2; + unsigned long mmcra; #endif }; diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index b51a97cfedf8..6f16ffafa6f0 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -127,6 +127,12 @@ int main(void) DEFINE(THREAD_BESCR, offsetof(struct thread_struct, bescr)); DEFINE(THREAD_EBBHR, offsetof(struct thread_struct, ebbhr)); DEFINE(THREAD_EBBRR, offsetof(struct thread_struct, ebbrr)); + DEFINE(THREAD_SIAR, offsetof(struct thread_struct, siar)); + DEFINE(THREAD_SDAR, offsetof(struct thread_struct, sdar)); + DEFINE(THREAD_SIER, offsetof(struct thread_struct, sier)); + DEFINE(THREAD_MMCR0, offsetof(struct thread_struct, mmcr0)); + DEFINE(THREAD_MMCR2, offsetof(struct thread_struct, mmcr2)); + DEFINE(THREAD_MMCRA, offsetof(struct thread_struct, mmcra)); #endif #ifdef CONFIG_PPC_TRANSACTIONAL_MEM DEFINE(PACATMSCRATCH, offsetof(struct paca_struct, tm_scratch)); diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 51cfb8fc301f..0e9095e47b5b 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -465,6 +465,20 @@ BEGIN_FTR_SECTION std r0, THREAD_EBBHR(r3) mfspr r0, SPRN_EBBRR std r0, THREAD_EBBRR(r3) + + /* PMU registers made user read/(write) by EBB */ + mfspr r0, SPRN_SIAR + std r0, THREAD_SIAR(r3) + mfspr r0, SPRN_SDAR + std r0, THREAD_SDAR(r3) + mfspr r0, SPRN_SIER + std r0, THREAD_SIER(r3) + mfspr r0, SPRN_MMCR0 + std r0, THREAD_MMCR0(r3) + mfspr r0, SPRN_MMCR2 + std r0, THREAD_MMCR2(r3) + mfspr r0, SPRN_MMCRA + std r0, THREAD_MMCRA(r3) END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) #endif @@ -560,6 +574,20 @@ BEGIN_FTR_SECTION ld r0, THREAD_EBBRR(r4) mtspr SPRN_EBBRR, r0 + /* PMU registers made user read/(write) by EBB */ + ld r0, THREAD_SIAR(r4) + mtspr SPRN_SIAR, r0 + ld r0, THREAD_SDAR(r4) + mtspr SPRN_SDAR, r0 + ld r0, THREAD_SIER(r4) + mtspr SPRN_SIER, r0 + ld r0, THREAD_MMCR0(r4) + mtspr SPRN_MMCR0, r0 + ld r0, THREAD_MMCR2(r4) + mtspr SPRN_MMCR2, r0 + ld r0, THREAD_MMCRA(r4) + mtspr SPRN_MMCRA, r0 + ld r0,THREAD_TAR(r4) mtspr SPRN_TAR,r0 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S) -- cgit v1.2.2 From b72c1f651491e4cd33ddec79c504a49071a512f0 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 21 May 2013 22:58:21 +0000 Subject: powerpc: Make radeon 32-bit MSI quirk work on powernv This moves the quirk itself to pci_64.c as to get built on all ppc64 platforms (the only ones with a pci_dn), factors the two implementations of get_pdn() into a single pci_get_dn() and use the quirk to do 32-bit MSIs on IODA based powernv platforms. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/pci-bridge.h | 2 ++ arch/powerpc/kernel/pci_64.c | 10 +++++++++ arch/powerpc/kernel/pci_dn.c | 8 +++++++ arch/powerpc/platforms/powernv/pci-ioda.c | 27 ++++++++++-------------- arch/powerpc/platforms/powernv/pci.c | 4 ++++ arch/powerpc/platforms/pseries/msi.c | 35 +++---------------------------- 6 files changed, 38 insertions(+), 48 deletions(-) (limited to 'arch') diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index 8b11b5bd9938..2c1d8cb9b265 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h @@ -174,6 +174,8 @@ struct pci_dn { /* Get the pointer to a device_node's pci_dn */ #define PCI_DN(dn) ((struct pci_dn *) (dn)->data) +extern struct pci_dn *pci_get_pdn(struct pci_dev *pdev); + extern void * update_dn_pci_info(struct device_node *dn, void *data); static inline int pci_device_from_OF_node(struct device_node *np, diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 873050d26840..2e8629654ca8 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -266,3 +266,13 @@ int pcibus_to_node(struct pci_bus *bus) } EXPORT_SYMBOL(pcibus_to_node); #endif + +static void quirk_radeon_32bit_msi(struct pci_dev *dev) +{ + struct pci_dn *pdn = pci_get_pdn(dev); + + if (pdn) + pdn->force_32bit_msi = 1; +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x68f2, quirk_radeon_32bit_msi); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0xaa68, quirk_radeon_32bit_msi); diff --git a/arch/powerpc/kernel/pci_dn.c b/arch/powerpc/kernel/pci_dn.c index e7af165f8b9d..df038442548a 100644 --- a/arch/powerpc/kernel/pci_dn.c +++ b/arch/powerpc/kernel/pci_dn.c @@ -32,6 +32,14 @@ #include #include +struct pci_dn *pci_get_pdn(struct pci_dev *pdev) +{ + struct device_node *dn = pci_device_to_OF_node(pdev); + if (!dn) + return NULL; + return PCI_DN(dn); +} + /* * Traverse_func that inits the PCI fields of the device node. * NOTE: this *must* be done before read/write config to the device. diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 3937aaae5bc4..9c9d15e4cdf2 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -68,16 +68,6 @@ define_pe_printk_level(pe_err, KERN_ERR); define_pe_printk_level(pe_warn, KERN_WARNING); define_pe_printk_level(pe_info, KERN_INFO); -static struct pci_dn *pnv_ioda_get_pdn(struct pci_dev *dev) -{ - struct device_node *np; - - np = pci_device_to_OF_node(dev); - if (!np) - return NULL; - return PCI_DN(np); -} - static int pnv_ioda_alloc_pe(struct pnv_phb *phb) { unsigned long pe; @@ -110,7 +100,7 @@ static struct pnv_ioda_pe *pnv_ioda_get_pe(struct pci_dev *dev) { struct pci_controller *hose = pci_bus_to_host(dev->bus); struct pnv_phb *phb = hose->private_data; - struct pci_dn *pdn = pnv_ioda_get_pdn(dev); + struct pci_dn *pdn = pci_get_pdn(dev); if (!pdn) return NULL; @@ -173,7 +163,7 @@ static int pnv_ioda_configure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe) /* Add to all parents PELT-V */ while (parent) { - struct pci_dn *pdn = pnv_ioda_get_pdn(parent); + struct pci_dn *pdn = pci_get_pdn(parent); if (pdn && pdn->pe_number != IODA_INVALID_PE) { rc = opal_pci_set_peltv(phb->opal_id, pdn->pe_number, pe->pe_number, OPAL_ADD_PE_TO_DOMAIN); @@ -252,7 +242,7 @@ static struct pnv_ioda_pe *pnv_ioda_setup_dev_PE(struct pci_dev *dev) { struct pci_controller *hose = pci_bus_to_host(dev->bus); struct pnv_phb *phb = hose->private_data; - struct pci_dn *pdn = pnv_ioda_get_pdn(dev); + struct pci_dn *pdn = pci_get_pdn(dev); struct pnv_ioda_pe *pe; int pe_num; @@ -323,7 +313,7 @@ static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe) struct pci_dev *dev; list_for_each_entry(dev, &bus->devices, bus_list) { - struct pci_dn *pdn = pnv_ioda_get_pdn(dev); + struct pci_dn *pdn = pci_get_pdn(dev); if (pdn == NULL) { pr_warn("%s: No device node associated with device !\n", @@ -436,7 +426,7 @@ static void pnv_pci_ioda_setup_PEs(void) static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev) { - struct pci_dn *pdn = pnv_ioda_get_pdn(pdev); + struct pci_dn *pdn = pci_get_pdn(pdev); struct pnv_ioda_pe *pe; /* @@ -768,6 +758,7 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, unsigned int is_64, struct msi_msg *msg) { struct pnv_ioda_pe *pe = pnv_ioda_get_pe(dev); + struct pci_dn *pdn = pci_get_pdn(dev); struct irq_data *idata; struct irq_chip *ichip; unsigned int xive_num = hwirq - phb->msi_base; @@ -783,6 +774,10 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, if (pe->mve_number < 0) return -ENXIO; + /* Force 32-bit MSI on some broken devices */ + if (pdn && pdn->force_32bit_msi) + is_64 = 0; + /* Assign XIVE to PE */ rc = opal_pci_set_xive_pe(phb->opal_id, pe->pe_number, xive_num); if (rc) { @@ -1035,7 +1030,7 @@ static int pnv_pci_enable_device_hook(struct pci_dev *dev) if (!phb->initialized) return 0; - pdn = pnv_ioda_get_pdn(dev); + pdn = pci_get_pdn(dev); if (!pdn || pdn->pe_number == IODA_INVALID_PE) return -EINVAL; diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index 098d3573315c..277343cc6a3d 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -47,6 +47,10 @@ static int pnv_msi_check_device(struct pci_dev* pdev, int nvec, int type) { struct pci_controller *hose = pci_bus_to_host(pdev->bus); struct pnv_phb *phb = hose->private_data; + struct pci_dn *pdn = pci_get_pdn(pdev); + + if (pdn && pdn->force_32bit_msi && !phb->msi32_support) + return -ENODEV; return (phb && phb->msi_bmp.bitmap) ? 0 : -ENODEV; } diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 420524e6f8c9..d34f4ffdb796 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -26,26 +26,6 @@ static int query_token, change_token; #define RTAS_CHANGE_MSIX_FN 4 #define RTAS_CHANGE_32MSI_FN 5 -static struct pci_dn *get_pdn(struct pci_dev *pdev) -{ - struct device_node *dn; - struct pci_dn *pdn; - - dn = pci_device_to_OF_node(pdev); - if (!dn) { - dev_dbg(&pdev->dev, "rtas_msi: No OF device node\n"); - return NULL; - } - - pdn = PCI_DN(dn); - if (!pdn) { - dev_dbg(&pdev->dev, "rtas_msi: No PCI DN\n"); - return NULL; - } - - return pdn; -} - /* RTAS Helpers */ static int rtas_change_msi(struct pci_dn *pdn, u32 func, u32 num_irqs) @@ -91,7 +71,7 @@ static void rtas_disable_msi(struct pci_dev *pdev) { struct pci_dn *pdn; - pdn = get_pdn(pdev); + pdn = pci_get_pdn(pdev); if (!pdn) return; @@ -152,7 +132,7 @@ static int check_req(struct pci_dev *pdev, int nvec, char *prop_name) struct pci_dn *pdn; const u32 *req_msi; - pdn = get_pdn(pdev); + pdn = pci_get_pdn(pdev); if (!pdn) return -ENODEV; @@ -402,7 +382,7 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) struct msi_msg msg; int nvec = nvec_in; - pdn = get_pdn(pdev); + pdn = pci_get_pdn(pdev); if (!pdn) return -ENODEV; @@ -518,12 +498,3 @@ static int rtas_msi_init(void) } arch_initcall(rtas_msi_init); -static void quirk_radeon(struct pci_dev *dev) -{ - struct pci_dn *pdn = get_pdn(dev); - - if (pdn) - pdn->force_32bit_msi = 1; -} -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x68f2, quirk_radeon); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0xaa68, quirk_radeon); -- cgit v1.2.2 From 83920c498ebb51cbd62f26f72e87c04a2a46dec9 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 21 May 2013 23:00:22 +0000 Subject: powerpc/powernv: Build a zImage.epapr The zImage.epapr wrapper allows to use zImages when booting via a flat device-tree which can be used on powernv. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/powernv/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig index d3e840d643af..c24684c818ab 100644 --- a/arch/powerpc/platforms/powernv/Kconfig +++ b/arch/powerpc/platforms/powernv/Kconfig @@ -6,6 +6,7 @@ config PPC_POWERNV select PPC_ICP_NATIVE select PPC_P7_NAP select PPC_PCI_CHOICE if EMBEDDED + select EPAPR_BOOT default y config POWERNV_MSI -- cgit v1.2.2 From f1dd153121dcb872ae6cba8d52bec97519eb7d97 Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 22 May 2013 11:07:46 +0000 Subject: powerpc/pseries: Make 32-bit MSI quirk work on systems lacking firmware support Recent commit e61133dda480062d221f09e4fc18f66763f8ecd0 added support for a new firmware feature to force an adapter to use 32 bit MSIs. However, this firmware is not available for all systems. The hack below allows devices needing 32 bit MSIs to work on these systems as well. It is careful to only enable this on Gen2 slots, which should limit this to configurations where this hack is needed and tested to work. [Small change to factor out the hack into a separate function -- BenH] Signed-off-by: Brian King Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/platforms/pseries/msi.c | 40 +++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) (limited to 'arch') diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index d34f4ffdb796..6d2f0abce6fa 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c @@ -374,6 +374,23 @@ static int check_msix_entries(struct pci_dev *pdev) return 0; } +static void rtas_hack_32bit_msi_gen2(struct pci_dev *pdev) +{ + u32 addr_hi, addr_lo; + + /* + * We should only get in here for IODA1 configs. This is based on the + * fact that we using RTAS for MSIs, we don't have the 32 bit MSI RTAS + * support, and we are in a PCIe Gen2 slot. + */ + dev_info(&pdev->dev, + "rtas_msi: No 32 bit MSI firmware support, forcing 32 bit MSI\n"); + pci_read_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_HI, &addr_hi); + addr_lo = 0xffff0000 | ((addr_hi >> (48 - 32)) << 4); + pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_LO, addr_lo); + pci_write_config_dword(pdev, pdev->msi_cap + PCI_MSI_ADDRESS_HI, 0); +} + static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) { struct pci_dn *pdn; @@ -381,6 +398,7 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) struct msi_desc *entry; struct msi_msg msg; int nvec = nvec_in; + int use_32bit_msi_hack = 0; pdn = pci_get_pdn(pdev); if (!pdn) @@ -408,15 +426,31 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) */ again: if (type == PCI_CAP_ID_MSI) { - if (pdn->force_32bit_msi) + if (pdn->force_32bit_msi) { rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSI_FN, nvec); - else + if (rc < 0) { + /* + * We only want to run the 32 bit MSI hack below if + * the max bus speed is Gen2 speed + */ + if (pdev->bus->max_bus_speed != PCIE_SPEED_5_0GT) + return rc; + + use_32bit_msi_hack = 1; + } + } else + rc = -1; + + if (rc < 0) rc = rtas_change_msi(pdn, RTAS_CHANGE_MSI_FN, nvec); - if (rc < 0 && !pdn->force_32bit_msi) { + if (rc < 0) { pr_debug("rtas_msi: trying the old firmware call.\n"); rc = rtas_change_msi(pdn, RTAS_CHANGE_FN, nvec); } + + if (use_32bit_msi_hack && rc > 0) + rtas_hack_32bit_msi_gen2(pdev); } else rc = rtas_change_msi(pdn, RTAS_CHANGE_MSIX_FN, nvec); -- cgit v1.2.2