* [PATCH v7 3/5] PCI: designware: enhance dw_pcie_host_init() to support v3.65 DW hardware
From: Murali Karicheri @ 2014-07-21 16:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405961925-27248-1-git-send-email-m-karicheri2@ti.com>
keystone PCI controller is based on v3.65 designware hardware. This
version differs from newer versions of the hardware in few functional
areas discussed below that makes it necessary to change dw_pcie_host_init()
to support v3.65 based PCI controller.
1. No support for ATU port. So any ATU specific resource handling code
is to be bypassed for v3.65 h/w.
2. MSI controller uses Application space to implement MSI and 32 MSI
interrupts are multiplexed over 8 IRQs to the host. Hence the code
to process MSI IRQ needs to be different. This patch allows platform
driver to provide its own irq_domain_ops ptr to irq_domain_add_linear()
through an API callback from the designware core driver.
3. MSI interrupt generation requires EP to write to the RC's application
register. So enhance the driver to allow setup of inbound access to
MSI irq register as a post scan bus API callback.
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Reviewed-by: Pratyush Anand <pratyush.anand@st.com>
Acked-by: Mohit KUMAR <mohit.kumar@st.com>
CC: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org>
---
drivers/pci/host/pcie-designware.c | 54 +++++++++++++++++++++++-------------
drivers/pci/host/pcie-designware.h | 2 ++
2 files changed, 36 insertions(+), 20 deletions(-)
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 905941c..35bb4af 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -420,8 +420,8 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
struct device_node *np = pp->dev->of_node;
struct of_pci_range range;
struct of_pci_range_parser parser;
+ int i, ret;
u32 val;
- int i;
if (of_pci_range_parser_init(&parser, np)) {
dev_err(pp->dev, "missing ranges property\n");
@@ -467,21 +467,26 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
}
}
- pp->cfg0_base = pp->cfg.start;
- pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
pp->mem_base = pp->mem.start;
- pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
- pp->config.cfg0_size);
if (!pp->va_cfg0_base) {
- dev_err(pp->dev, "error with ioremap in function\n");
- return -ENOMEM;
+ pp->cfg0_base = pp->cfg.start;
+ pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
+ pp->config.cfg0_size);
+ if (!pp->va_cfg0_base) {
+ dev_err(pp->dev, "error with ioremap in function\n");
+ return -ENOMEM;
+ }
}
- pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
- pp->config.cfg1_size);
+
if (!pp->va_cfg1_base) {
- dev_err(pp->dev, "error with ioremap\n");
- return -ENOMEM;
+ pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
+ pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
+ pp->config.cfg1_size);
+ if (!pp->va_cfg1_base) {
+ dev_err(pp->dev, "error with ioremap\n");
+ return -ENOMEM;
+ }
}
if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
@@ -490,16 +495,22 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
}
if (IS_ENABLED(CONFIG_PCI_MSI)) {
- pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
- MAX_MSI_IRQS, &msi_domain_ops,
- &dw_pcie_msi_chip);
- if (!pp->irq_domain) {
- dev_err(pp->dev, "irq domain init failed\n");
- return -ENXIO;
- }
+ if (!pp->ops->msi_host_init) {
+ pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
+ MAX_MSI_IRQS, &msi_domain_ops,
+ &dw_pcie_msi_chip);
+ if (!pp->irq_domain) {
+ dev_err(pp->dev, "irq domain init failed\n");
+ return -ENXIO;
+ }
- for (i = 0; i < MAX_MSI_IRQS; i++)
- irq_create_mapping(pp->irq_domain, i);
+ for (i = 0; i < MAX_MSI_IRQS; i++)
+ irq_create_mapping(pp->irq_domain, i);
+ } else {
+ ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
+ if (ret < 0)
+ return ret;
+ }
}
if (pp->ops->host_init)
@@ -759,6 +770,9 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
BUG();
}
+ if (bus && pp->ops->scan_bus)
+ pp->ops->scan_bus(pp);
+
return bus;
}
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 387f69e..080c649 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -70,6 +70,8 @@ struct pcie_host_ops {
void (*msi_set_irq)(struct pcie_port *pp, int irq);
void (*msi_clear_irq)(struct pcie_port *pp, int irq);
u32 (*get_msi_data)(struct pcie_port *pp);
+ void (*scan_bus)(struct pcie_port *pp);
+ int (*msi_host_init)(struct pcie_port *pp, struct msi_chip *chip);
};
int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
--
1.7.9.5
^ permalink raw reply related
* [PATCH v7 2/5] PCI: designware: refactor MSI code to work with v3.65 dw hardware
From: Murali Karicheri @ 2014-07-21 16:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405961925-27248-1-git-send-email-m-karicheri2@ti.com>
Keystone PCI controller is based on v3.65 version of the DW
PCI h/w that implements MSI controller registers in application
space compared to the newer version. This requires updates to
the DW core API to support the PCI controller driver based on
this old DW hardware. Add msi_irq_set()/clear() API functions to
allow Set/Clear MSI IRQ enable bit in the application register.
Also the old h/w uses MSI_IRQ register in application register
space to raise MSI IRQ to the RC from EP. Current code uses the
standard mechanism as per PCI spec. So add another API get_msi_data()
to get the address of this register so that common code can be
re-used on old h/w.
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Reviewed-by: Pratyush Anand <pratyush.anand@st.com>
Acked-by: Mohit Kumar <mohit.kumar@st.com>
Acked-by: Jingoo Han <jg1.han@samsung.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org>
---
drivers/pci/host/pcie-designware.c | 50 ++++++++++++++++++++++++++----------
drivers/pci/host/pcie-designware.h | 3 +++
2 files changed, 39 insertions(+), 14 deletions(-)
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index d8f3af7..905941c 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -217,27 +217,47 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
return 0;
}
+static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
+{
+ unsigned int res, bit, val;
+
+ res = (irq / 32) * 12;
+ bit = irq % 32;
+ dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+ val &= ~(1 << bit);
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
unsigned int nvec, unsigned int pos)
{
- unsigned int i, res, bit, val;
+ unsigned int i;
for (i = 0; i < nvec; i++) {
irq_set_msi_desc_off(irq_base, i, NULL);
clear_bit(pos + i, pp->msi_irq_in_use);
/* Disable corresponding interrupt on MSI controller */
- res = ((pos + i) / 32) * 12;
- bit = (pos + i) % 32;
- dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
- val &= ~(1 << bit);
- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+ if (pp->ops->msi_clear_irq)
+ pp->ops->msi_clear_irq(pp, pos + i);
+ else
+ dw_pcie_msi_clear_irq(pp, pos + i);
}
}
+static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
+{
+ unsigned int res, bit, val;
+
+ res = (irq / 32) * 12;
+ bit = irq % 32;
+ dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
+ val |= 1 << bit;
+ dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+}
+
static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
{
- int res, bit, irq, pos0, pos1, i;
- u32 val;
+ int irq, pos0, pos1, i;
struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
if (!pp) {
@@ -281,11 +301,10 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
}
set_bit(pos0 + i, pp->msi_irq_in_use);
/*Enable corresponding interrupt in MSI interrupt controller */
- res = ((pos0 + i) / 32) * 12;
- bit = (pos0 + i) % 32;
- dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
- val |= 1 << bit;
- dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
+ if (pp->ops->msi_set_irq)
+ pp->ops->msi_set_irq(pp, pos0 + i);
+ else
+ dw_pcie_msi_set_irq(pp, pos0 + i);
}
*pos = pos0;
@@ -353,7 +372,10 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
*/
desc->msi_attrib.multiple = msgvec;
- msg.address_lo = virt_to_phys((void *)pp->msi_data);
+ if (pp->ops->get_msi_data)
+ msg.address_lo = pp->ops->get_msi_data(pp);
+ else
+ msg.address_lo = virt_to_phys((void *)pp->msi_data);
msg.address_hi = 0x0;
msg.data = pos;
write_msi_msg(irq, &msg);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 8121901..387f69e 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -67,6 +67,9 @@ struct pcie_host_ops {
unsigned int devfn, int where, int size, u32 val);
int (*link_up)(struct pcie_port *pp);
void (*host_init)(struct pcie_port *pp);
+ void (*msi_set_irq)(struct pcie_port *pp, int irq);
+ void (*msi_clear_irq)(struct pcie_port *pp, int irq);
+ u32 (*get_msi_data)(struct pcie_port *pp);
};
int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
--
1.7.9.5
^ permalink raw reply related
* [PATCH v7 1/5] PCI: designware: add rd[wr]_other_conf API
From: Murali Karicheri @ 2014-07-21 16:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405961925-27248-1-git-send-email-m-karicheri2@ti.com>
v3.65 version of the designware h/w, requires application space
registers to be configured to access the remote EP config space.
To support this, add rd[wr]_other_conf API in the pcie_host_opts
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
Reviewed-by: Pratyush Anand <pratyush.anand@st.com>
Acked-by: Mohit Kumar <mohit.kumar@st.com>
Acked-by: Jingoo Han <jg1.han@samsung.com>
Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org>
---
drivers/pci/host/pcie-designware.c | 12 ++++++++++--
drivers/pci/host/pcie-designware.h | 4 ++++
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 1eaf4df..d8f3af7 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -656,7 +656,11 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
}
if (bus->number != pp->root_bus_nr)
- ret = dw_pcie_rd_other_conf(pp, bus, devfn,
+ if (pp->ops->rd_other_conf)
+ ret = pp->ops->rd_other_conf(pp, bus, devfn,
+ where, size, val);
+ else
+ ret = dw_pcie_rd_other_conf(pp, bus, devfn,
where, size, val);
else
ret = dw_pcie_rd_own_conf(pp, where, size, val);
@@ -679,7 +683,11 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
return PCIBIOS_DEVICE_NOT_FOUND;
if (bus->number != pp->root_bus_nr)
- ret = dw_pcie_wr_other_conf(pp, bus, devfn,
+ if (pp->ops->wr_other_conf)
+ ret = pp->ops->wr_other_conf(pp, bus, devfn,
+ where, size, val);
+ else
+ ret = dw_pcie_wr_other_conf(pp, bus, devfn,
where, size, val);
else
ret = dw_pcie_wr_own_conf(pp, where, size, val);
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 77f592f..8121901 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -61,6 +61,10 @@ struct pcie_host_ops {
u32 val, void __iomem *dbi_base);
int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
+ int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 *val);
+ int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
+ unsigned int devfn, int where, int size, u32 val);
int (*link_up)(struct pcie_port *pp);
void (*host_init)(struct pcie_port *pp);
};
--
1.7.9.5
^ permalink raw reply related
* [PATCH v7 0/5] Add Keystone PCIe controller driver
From: Murali Karicheri @ 2014-07-21 16:58 UTC (permalink / raw)
To: linux-arm-kernel
This patch series add PCIe controller driver for keystone SoCs. This is
based on v4 of the series posted to the mailing list. Keystone PCI controller
is based on version 3.65 of the DW hardware. This driver uses the DW core
functions to implement the PCI controller driver for keystone.
Testing:
=======
Testing of the driver is done on TI's K2HK EVM inserted to a Elma blu!eco
MicroTCA chassis AMC slot with JumpGen SEM-200 AMC SATA Storage and Dual
Ethernet Card Express inserted on another AMC slot. The e1000e driver available
on intel's website is patched to the kernel source tree and build. e1000e.ko
is dynamically loaded and executed ping and iperf tests to test the
functionality.
Thanks to all of you who have contributed by reviewing and offering valuable
comments. If you want me to add your "Reviewed-by", please let me know so that
I can add it to the commit log and re-send. Patch 1-3 has Acks from maintainers
and I believe this can be merged to upstream branch. Patch 4 is waiting for
Ack from DT maintainer. Please provide the same at the earliest.
Thanks
Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
CC: Russell King <linux@arm.linux.org.uk>
CC: Grant Likely <grant.likely@linaro.org>
CC: Rob Herring <robh+dt@kernel.org>
CC: Mohit Kumar <mohit.kumar@st.com>
CC: Jingoo Han <jg1.han@samsung.com>
CC: Bjorn Helgaas <bhelgaas@google.com>
CC: Pratyush Anand <pratyush.anand@st.com>
CC: Richard Zhu <r65037@freescale.com>
CC: Kishon Vijay Abraham I <kishon@ti.com>
CC: Marek Vasut <marex@denx.de>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Pawel Moll <pawel.moll@arm.com>
CC: Mark Rutland <mark.rutland@arm.com>
CC: Ian Campbell <ijc+devicetree@hellion.org.uk>
CC: Kumar Gala <galak@codeaurora.org>
CC: Randy Dunlap <rdunlap@infradead.org>
CC: Grant Likely <grant.likely@linaro.org>
Changelog:
v7
- Removed ti,enable_linktrain DT property. The driver now check if
the link is up and then retrain the link if not already up. This
is as per comment from DT maintainer.
- Rebased to upstream kernel v3.16-rc6
v6
- Added Ack from Maintainer for patch 3. Patch 1-3 now have the
Acks from maintainer and can be merged to upstream branch.
Patch 4 is waiting ack from DT maintainer.
v5
- Rebased to upstream kernel v3.16-rc5
- Reworked Patch 3/6 and 4/6 into a single patch based on
maintainer comment to use a API callback model to support
the v3.65 h/w.
v4
- Addressed comments against 5/5.
- Added a patch 6/6 for Maintainer information
- Added couple of Acked-By:
- Rebased to latest Linux 3.16-rc4
v3
- DW application register handling code is now part of
Keystone PCI driver. RFC had this code part of Keystone
PCI driver, then V1 moved this to a separate file to
re-use on other platforms that uses this version of the
DW h/w. Then based on comments against v2, this is moved
back to Keystone driver.
- Keystone SerDes phy driver is removed from this series so that
this can be merged independent of that patch
- added msi_set_irq()/clear_irq() API's to support Keystone
V2
- Split the designware pcie enhancement patch to multiple
patches based on functionality added
- Remove the quirk code and add a patch to fix mps/mrss
tuning for ARM. Use kernel command line parameter
pci=pcie_bus_perf to work with Keystone PCI Controller.
Following patch addressed this.
[PATCH v1] ARM: pci: add call to pcie_bus_configure_settings()
- Add documentation for device tree bindings
- Add separate interrupt controller nodes for MSI and Legacy
IRQs and use irq map for legacy IRQ
- Use compatibility to identify v3.65 version of the DW hardware
and use it to customize the designware common code.
- Use reg property for configuration space instead of range
- Other minor updates based on code inspection.
V1
- Add an interrupt controller node for Legacy irq chip and use
interrupt map/map-mask property to map legacy IRQs A/B/C/D
- Add a Phy driver to replace the original serdes driver
- Move common application register handling code to a separate
file to allow re-use across other platforms that use older
DW PCIe h/w
- PCI quirk for maximum read request size. Check and override only
if the maximum is higher than what controller can handle.
- Converted to a module platform driver.
Murali Karicheri (5):
PCI: designware: add rd[wr]_other_conf API
PCI: designware: refactor MSI code to work with v3.65 dw hardware
PCI: designware: enhance dw_pcie_host_init() to support v3.65 DW
hardware
PCI: add PCI controller for keystone PCIe h/w
PCI: keystone: Update maintainer information
.../devicetree/bindings/pci/pci-keystone.txt | 68 +++
MAINTAINERS | 7 +
drivers/pci/host/Kconfig | 5 +
drivers/pci/host/Makefile | 1 +
drivers/pci/host/pci-keystone-dw.c | 521 ++++++++++++++++++++
drivers/pci/host/pci-keystone.c | 386 +++++++++++++++
drivers/pci/host/pci-keystone.h | 58 +++
drivers/pci/host/pcie-designware.c | 116 +++--
drivers/pci/host/pcie-designware.h | 9 +
9 files changed, 1135 insertions(+), 36 deletions(-)
create mode 100644 Documentation/devicetree/bindings/pci/pci-keystone.txt
create mode 100644 drivers/pci/host/pci-keystone-dw.c
create mode 100644 drivers/pci/host/pci-keystone.c
create mode 100644 drivers/pci/host/pci-keystone.h
--
1.7.9.5
^ permalink raw reply
* [PATCH 6/6] ARM: mvebu: Add missing MDIO clock in Armada 375
From: Ezequiel Garcia @ 2014-07-21 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405961296-5846-1-git-send-email-ezequiel.garcia@free-electrons.com>
In Armada 375 SoCs, the MDIO is handled by a separate orion-mdio driver,
despite the register is contained within the "LMS" block of the network
controller.
Therefore we need to add the clock to the MDIO devicetree to prevent the
controller from being accesed with its clock gated. This is needed, for
instance, to be able to load the MDIO driver before the network driver.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
arch/arm/boot/dts/armada-375.dtsi | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm/boot/dts/armada-375.dtsi b/arch/arm/boot/dts/armada-375.dtsi
index bfcbe58..c1e49e7 100644
--- a/arch/arm/boot/dts/armada-375.dtsi
+++ b/arch/arm/boot/dts/armada-375.dtsi
@@ -158,6 +158,7 @@
#size-cells = <0>;
compatible = "marvell,orion-mdio";
reg = <0xc0054 0x4>;
+ clocks = <&gateclk 19>;
};
/* Network controller */
--
2.0.1
^ permalink raw reply related
* [PATCH 5/6] ARM: mvebu: Add ethernet aliases required by U-Boot
From: Ezequiel Garcia @ 2014-07-21 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405961296-5846-1-git-send-email-ezequiel.garcia@free-electrons.com>
From: Marcin Wojtas <mw@semihalf.com>
The vendor bootloader provided for Armada 375 boards expect an
alias for the ethernet nodes, which is used to fixup the MAC address.
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
arch/arm/boot/dts/armada-375.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/boot/dts/armada-375.dtsi b/arch/arm/boot/dts/armada-375.dtsi
index d4619ad..bfcbe58 100644
--- a/arch/arm/boot/dts/armada-375.dtsi
+++ b/arch/arm/boot/dts/armada-375.dtsi
@@ -25,6 +25,8 @@
gpio0 = &gpio0;
gpio1 = &gpio1;
gpio2 = &gpio2;
+ ethernet0 = ð0;
+ ethernet1 = ð1;
};
clocks {
--
2.0.1
^ permalink raw reply related
* [PATCH 4/6] net: mvpp2: Simplify BM pool buffers freeing
From: Ezequiel Garcia @ 2014-07-21 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405961296-5846-1-git-send-email-ezequiel.garcia@free-electrons.com>
Now that all the users of mvpp2_bm_bufs_free() have been fixed, we can safely
clean the function prototype.
The function is always called to release all the buffers in a BM pool, and
the number of buffers freed is not needed. Therefore, we change the return
to a void, and remove the "num" parameter. This is a cosmetic change, to
make the code slightly cleaner.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 19 ++++++-------------
1 file changed, 6 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 43d3391..b009eee 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -3385,17 +3385,12 @@ static void mvpp2_bm_pool_bufsize_set(struct mvpp2 *priv,
mvpp2_write(priv, MVPP2_POOL_BUF_SIZE_REG(bm_pool->id), val);
}
-/* Free "num" buffers from the pool */
-static int mvpp2_bm_bufs_free(struct mvpp2 *priv,
- struct mvpp2_bm_pool *bm_pool, int num)
+/* Free all buffers from the pool */
+static void mvpp2_bm_bufs_free(struct mvpp2 *priv, struct mvpp2_bm_pool *bm_pool)
{
int i;
- if (num >= bm_pool->buf_num)
- /* Free all buffers from the pool */
- num = bm_pool->buf_num;
-
- for (i = 0; i < num; i++) {
+ for (i = 0; i < bm_pool->buf_num; i++) {
u32 vaddr;
/* Get buffer virtual adress (indirect access) */
@@ -3408,7 +3403,6 @@ static int mvpp2_bm_bufs_free(struct mvpp2 *priv,
/* Update BM driver with number of buffers removed from pool */
bm_pool->buf_num -= i;
- return i;
}
/* Cleanup pool */
@@ -3416,10 +3410,9 @@ static int mvpp2_bm_pool_destroy(struct platform_device *pdev,
struct mvpp2 *priv,
struct mvpp2_bm_pool *bm_pool)
{
- int num;
u32 val;
- num = mvpp2_bm_bufs_free(priv, bm_pool, bm_pool->buf_num);
+ mvpp2_bm_bufs_free(priv, bm_pool);
if (bm_pool->buf_num) {
WARN(1, "cannot free all buffers in pool %d\n", bm_pool->id);
return 0;
@@ -3675,7 +3668,7 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
MVPP2_BM_LONG_BUF_NUM :
MVPP2_BM_SHORT_BUF_NUM;
else
- mvpp2_bm_bufs_free(port->priv, new_pool, pkts_num);
+ mvpp2_bm_bufs_free(port->priv, new_pool);
new_pool->pkt_size = pkt_size;
@@ -3748,7 +3741,7 @@ static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu)
int pkt_size = MVPP2_RX_PKT_SIZE(mtu);
/* Update BM pool with new buffer size */
- mvpp2_bm_bufs_free(port->priv, port_pool, pkts_num);
+ mvpp2_bm_bufs_free(port->priv, port_pool);
if (port_pool->buf_num) {
WARN(1, "cannot free all buffers in pool %d\n", port_pool->id);
return -EIO;
--
2.0.1
^ permalink raw reply related
* [PATCH 3/6] net: mvpp2: Fix the BM pool buffer release check
From: Ezequiel Garcia @ 2014-07-21 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405961296-5846-1-git-send-email-ezequiel.garcia@free-electrons.com>
After a call to mvpp2_bm_bufs_free(), the caller usually wants to know
if the function successfully freed the requested number. However, this
cannot be done by looking into the BM pool count, because the current
buffer count was updated by mvpp2_bm_bufs_free().
In fact, the current callers of mvpp2_bm_bufs_free() use it to release
all the buffers in the pool, so we can fix this by simply checking
if the pool is not empty.
Signed-off-by: Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index aa139df..43d3391 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -3420,7 +3420,7 @@ static int mvpp2_bm_pool_destroy(struct platform_device *pdev,
u32 val;
num = mvpp2_bm_bufs_free(priv, bm_pool, bm_pool->buf_num);
- if (num != bm_pool->buf_num) {
+ if (bm_pool->buf_num) {
WARN(1, "cannot free all buffers in pool %d\n", bm_pool->id);
return 0;
}
@@ -3748,8 +3748,8 @@ static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu)
int pkt_size = MVPP2_RX_PKT_SIZE(mtu);
/* Update BM pool with new buffer size */
- num = mvpp2_bm_bufs_free(port->priv, port_pool, pkts_num);
- if (num != pkts_num) {
+ mvpp2_bm_bufs_free(port->priv, port_pool, pkts_num);
+ if (port_pool->buf_num) {
WARN(1, "cannot free all buffers in pool %d\n", port_pool->id);
return -EIO;
}
--
2.0.1
^ permalink raw reply related
* [PATCH 2/6] net: mvpp2: Enable proper PHY polling and fix port functionality
From: Ezequiel Garcia @ 2014-07-21 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405961296-5846-1-git-send-email-ezequiel.garcia@free-electrons.com>
From: Marcin Wojtas <mw@semihalf.com>
Currently, the network interfaces that are not configured by the bootloader
(using e.g. tftp or ping) can detect the link status but are unable to
transmit data.
The network controller has a functionality that allows the hardware to
continuously poll the PHY and directly update the MAC configuration accordingly
(speed, duplex, etc.). However, this doesn't work well with phylib's
software-based polling and updating MAC configuration in the driver's callback.
This commit fixes this issue by:
1. Setting MVPP2_PHY_AN_STOP_SMI0_MASK in MVPP2_PHY_AN_CFG0_REG in
mvpp2_init(), which disables the harware polling feature.
2. Disabling MVPP2_GMAC_PCS_ENABLE_MASK bit in MVPP2_GMAC_CTRL_2_REG in
mvpp2_port_mii_set() for port types other than SGMII.
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 40 ++++++++++++++++++++++++++++--------
1 file changed, 32 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index 8eac438..aa139df 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -248,6 +248,8 @@
/* LMS registers */
#define MVPP2_SRC_ADDR_MIDDLE 0x24
#define MVPP2_SRC_ADDR_HIGH 0x28
+#define MVPP2_PHY_AN_CFG0_REG 0x34
+#define MVPP2_PHY_AN_STOP_SMI0_MASK BIT(7)
#define MVPP2_MIB_COUNTERS_BASE(port) (0x1000 + ((port) >> 1) * \
0x400 + (port) * 0x400)
#define MVPP2_MIB_LATE_COLLISION 0x7c
@@ -278,6 +280,7 @@
#define MVPP2_GMAC_CONFIG_MII_SPEED BIT(5)
#define MVPP2_GMAC_CONFIG_GMII_SPEED BIT(6)
#define MVPP2_GMAC_AN_SPEED_EN BIT(7)
+#define MVPP2_GMAC_FC_ADV_EN BIT(9)
#define MVPP2_GMAC_CONFIG_FULL_DUPLEX BIT(12)
#define MVPP2_GMAC_AN_DUPLEX_EN BIT(13)
#define MVPP2_GMAC_PORT_FIFO_CFG_1_REG 0x1c
@@ -3809,16 +3812,30 @@ static void mvpp2_interrupts_unmask(void *arg)
static void mvpp2_port_mii_set(struct mvpp2_port *port)
{
- u32 reg, val = 0;
+ u32 val;
- if (port->phy_interface == PHY_INTERFACE_MODE_SGMII)
- val = MVPP2_GMAC_PCS_ENABLE_MASK |
- MVPP2_GMAC_INBAND_AN_MASK;
- else if (port->phy_interface == PHY_INTERFACE_MODE_RGMII)
- val = MVPP2_GMAC_PORT_RGMII_MASK;
+ val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
+
+ switch (port->phy_interface) {
+ case PHY_INTERFACE_MODE_SGMII:
+ val |= MVPP2_GMAC_INBAND_AN_MASK;
+ break;
+ case PHY_INTERFACE_MODE_RGMII:
+ val |= MVPP2_GMAC_PORT_RGMII_MASK;
+ default:
+ val &= ~MVPP2_GMAC_PCS_ENABLE_MASK;
+ }
+
+ writel(val, port->base + MVPP2_GMAC_CTRL_2_REG);
+}
- reg = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
- writel(reg | val, port->base + MVPP2_GMAC_CTRL_2_REG);
+static void mvpp2_port_fc_adv_enable(struct mvpp2_port *port)
+{
+ u32 val;
+
+ val = readl(port->base + MVPP2_GMAC_AUTONEG_CONFIG);
+ val |= MVPP2_GMAC_FC_ADV_EN;
+ writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG);
}
static void mvpp2_port_enable(struct mvpp2_port *port)
@@ -5877,6 +5894,7 @@ static void mvpp2_port_power_up(struct mvpp2_port *port)
{
mvpp2_port_mii_set(port);
mvpp2_port_periodic_xon_disable(port);
+ mvpp2_port_fc_adv_enable(port);
mvpp2_port_reset(port);
}
@@ -6198,6 +6216,7 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
{
const struct mbus_dram_target_info *dram_target_info;
int err, i;
+ u32 val;
/* Checks for hardware constraints */
if (rxq_number % 4 || (rxq_number > MVPP2_MAX_RXQ) ||
@@ -6211,6 +6230,11 @@ static int mvpp2_init(struct platform_device *pdev, struct mvpp2 *priv)
if (dram_target_info)
mvpp2_conf_mbus_windows(dram_target_info, priv);
+ /* Disable HW PHY polling */
+ val = readl(priv->lms_base + MVPP2_PHY_AN_CFG0_REG);
+ val |= MVPP2_PHY_AN_STOP_SMI0_MASK;
+ writel(val, priv->lms_base + MVPP2_PHY_AN_CFG0_REG);
+
/* Allocate and initialize aggregated TXQs */
priv->aggr_txqs = devm_kcalloc(&pdev->dev, num_present_cpus(),
sizeof(struct mvpp2_tx_queue),
--
2.0.1
^ permalink raw reply related
* [PATCH 1/6] net: mvpp2: Fix the periodic XON enable bit
From: Ezequiel Garcia @ 2014-07-21 16:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405961296-5846-1-git-send-email-ezequiel.garcia@free-electrons.com>
From: Marcin Wojtas <mw@semihalf.com>
This bit was originally wrong, the correct value is BIT(1), so fix it.
Signed-off-by: Marcin Wojtas <mw@semihalf.com>
---
drivers/net/ethernet/marvell/mvpp2.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index f4de2a9..8eac438 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -262,7 +262,7 @@
#define MVPP2_GMAC_MAX_RX_SIZE_MASK 0x7ffc
#define MVPP2_GMAC_MIB_CNTR_EN_MASK BIT(15)
#define MVPP2_GMAC_CTRL_1_REG 0x4
-#define MVPP2_GMAC_PERIODIC_XON_EN_MASK BIT(0)
+#define MVPP2_GMAC_PERIODIC_XON_EN_MASK BIT(1)
#define MVPP2_GMAC_GMII_LB_EN_MASK BIT(5)
#define MVPP2_GMAC_PCS_LB_EN_BIT 6
#define MVPP2_GMAC_PCS_LB_EN_MASK BIT(6)
--
2.0.1
^ permalink raw reply related
* [PATCH 0/6] net: mvpp2: Assorted fixes
From: Ezequiel Garcia @ 2014-07-21 16:48 UTC (permalink / raw)
To: linux-arm-kernel
This patchset contains a set of fixes for issues found while doing some
more intensive tests on the recently accepted mvpp2 ethernet driver.
David: if we are still in time, we'd like to get the driver fixes merged
for v3.17-rc1.
For the devicetree changes, it's already too late for that, since Jason
Cooper has already posted the PRs for v3.17. I'll re-post them when
v3.17-rc1 is released.
As usual, feedback is welcome.
Ezequiel Garcia (3):
net: mvpp2: Fix the BM pool buffer release check
net: mvpp2: Simplify BM pool buffers freeing
ARM: mvebu: Add missing MDIO clock in Armada 375
Marcin Wojtas (3):
net: mvpp2: Fix the periodic XON enable bit
net: mvpp2: Enable proper PHY polling and fix port functionality
ARM: mvebu: Add ethernet aliases required by U-Boot
arch/arm/boot/dts/armada-375.dtsi | 3 ++
drivers/net/ethernet/marvell/mvpp2.c | 65 +++++++++++++++++++++++-------------
2 files changed, 44 insertions(+), 24 deletions(-)
--
2.0.1
^ permalink raw reply
* [PATCH RFC 5/9] ARM: Add L1 PTE non-secure mapping
From: Russell King - ARM Linux @ 2014-07-21 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405954040-30399-6-git-send-email-daniel.thompson@linaro.org>
On Mon, Jul 21, 2014 at 03:47:16PM +0100, Daniel Thompson wrote:
> From: Marek Vasut <marex@denx.de>
>
> Add new device type, MT_DEVICE_NS. This type sets the NS bit in L1 PTE [1].
> Accesses to a memory region which is mapped this way generate non-secure
> access to that memory area. One must be careful here, since the NS bit is
> only available in L1 PTE, therefore when creating the mapping, the mapping
> must be at least 1 MiB big and must be aligned to 1 MiB. If that condition
> was false, the kernel would use regular L2 page mapping for this area instead
> and the NS bit setting would be ineffective.
Right, so this says that PTE mappings are not permissible.
> + [MT_DEVICE_NS] = { /* Non-secure accesses from secure mode */
> + .prot_pte = PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED |
> + L_PTE_SHARED,
> + .prot_l1 = PMD_TYPE_TABLE,
However, by filling in prot_pte and prot_l1, you're telling the code that
it /can/ setup such a mapping. This is screwed.
If you want to deny anything but section mappings (because they don't work)
then you omit prot_pte and prot_l1. With those omitted, if someone tries
to abuse this mapping type, then this check in create_mapping() will
trigger:
if (type->prot_l1 == 0 && ((addr | phys | length) & ~SECTION_MASK)) {
printk(KERN_WARNING "BUG: map for 0x%08llx at 0x%08lx can not "
"be mapped using pages, ignoring.\n",
(long long)__pfn_to_phys(md->pfn), addr);
return;
}
ioremap doesn't have that check; it assumes that it will always be setting
up PTE mappings via ioremap_page_range(). In fact, on many platforms
that's the only option.
So making this interface available via ioremap() seems pointless - but
more importantly it's extremely error-prone. So, MT_DEVICE_NS shouldn't
be using 4 at all, shouldn't be in asm/io.h, but should be with the
private MT_* definitions in map.h.
--
FTTC broadband for 0.8mile line: currently at 9.5Mbps down 400kbps up
according to speedtest.net.
^ permalink raw reply
* [GIT PULL 2/3] ARM: tegra: move fuse code out of arch/arm
From: Olof Johansson @ 2014-07-21 16:46 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <53CD4201.5070705@wwwdotorg.org>
On Mon, Jul 21, 2014 at 9:38 AM, Stephen Warren <swarren@wwwdotorg.org> wrote:
> On 07/21/2014 09:54 AM, Catalin Marinas wrote:
>> On Mon, Jul 21, 2014 at 09:06:00AM -0600, Stephen Warren wrote:
>>> On 07/17/2014 11:33 PM, Olof Johansson wrote:
>>>> On Thu, Jul 17, 2014 at 7:45 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>>> On 07/08/2014 11:47 AM, Olof Johansson wrote:
>>>>>> On Tue, Jul 8, 2014 at 6:43 AM, Peter De Schrijver
>>>>>> <pdeschrijver@nvidia.com> wrote:
>>>>>>> On Mon, Jul 07, 2014 at 02:44:17AM +0200, Olof Johansson wrote:
>>>>>>>> On Mon, Jun 23, 2014 at 03:23:45PM -0600, Stephen Warren wrote:
>>>>>>>>> This branch moves code related to the Tegra fuses out of arch/arm and
>>>>>>>>> into a centralized location which could be shared with ARM64. It also
>>>>>>>>> adds support for reading the fuse data through sysfs.
>>>>>>>>
>>>>>>>> The new/moved misc driver isn't acked by any misc maintainer, so I can't
>>>>>>>> take this branch.
>>>>>>>>
>>>>>>>> I saw no indication from searching the mailing list of that either,
>>>>>>>> so it wasn't just a missed acked-by.
>>>>>>>>
>>>>>>>> I wonder if this code should go under drivers/soc/ instead?
>>>>>>>
>>>>>>> It's modelled after sunxi_sid.c which lives in drivers/misc/eeprom/.
>>>>>>> Originally this driver was also in drivers/misc/eeprom/, but Stephen objected
>>>>>>> and therefore it was moved to drivers/misc/fuse. I think that's the right
>>>>>>> place still.
>>>>>>
>>>>>> I disagree, I think this belongs under drivers/soc. Especially since
>>>>>> you're adding dependencies on this misc driver from other parts of the
>>>>>> kernel / other drivers.
>>>>>>
>>>>>> I also don't like seeing init calls form platform code down into
>>>>>> drivers/misc like you're adding here. Can you please look at doing
>>>>>> that as a regular init call setup?
>>>>>
>>>>> I strongly disagree with using init calls for this kind of thing. There
>>>>> are ordering dependencies between the initialization code that can only
>>>>> be sanely managed by explicitly calling functions in a particular order;
>>>>> there's simply no way to manage this using initcalls. This is exactly
>>>>> why the hooks in the ARM machine descriptors exist...
>>>>
>>>> Right, but there are non on 64-bit, so you need to solve it for there
>>>> anyway. And once it's solved there, you might as well keep it common
>>>> with 32-bit.
>>>
>>> My assertion is that we should just do it directly on 64-bit too.
>>> There's no reason for arm64 to deviate from what arch/arm does already.
>>
>> On arm64, I really want to get away from any SoC specific early
>> initcall. One of the main reason is for things like SCU, interconnects,
>> system cache configurations (even certain clocks) to be enabled in
>> firmware before Linux starts (it's an education process but that's a way
>> for example to prevent people sending patches to enable SoC coherency
>> because they haven't thought about it before upstreaming).
>>
>> It would be nice to be able to initialise SoC stuff at device_initcall()
>> level (and even keep such code as modules in initramfs) but one of the
>> problems we have is dependency on clocks (and the clock model which
>> doesn't follow the device/driver model). The of_platform_populate() is
>> called at arch_initcall_sync (after arch_initcall to still allow some
>> SoC code, if needed, to run at arch_initcall).
>
> The main thing I want to avoid is a ton of separate drivers that all
> rely on each-other getting resolved by deferred probe. While that might
> work out, it seems pointless to make the kernel try and probe a bunch of
> stuff just to have it fail and get repeated, when we know exactly which
> order everything should get initialized in.
>
> Another issue is that we have SoCs which only differ in the CPU. I want
> the code to work identically on both SoCs so the CPU has limited affect
> on the low-level IO code. If we're going to enforce a "no machine
> descriptors" rule on arch/arm64, I think we should do the same thing in
> arch/arm for consistency.
>
>> We have a similar issue with arm64 vexpress (well, just on the model)
>> where vexpress_sysreg_init() is a core_initcall (should be fine as
>> arch_initcall) as it needs to be done before of_platform_populate().
>> Pawel on cc should know more of the history here.
>>
>> I recall there were also some discussions about a SoC driver model which
>> hangs off the top compatible string in the DT (e.g. "arm,vexpress") and
>> allow (minimal) code to be run slightly earlier, though still not
>> earlier than arch_initcall.
>
> I guess that would work out OK; if we force the driver that binds to a
> top-level compatible value of "nvidia,tegraNNN" to probe first, and it
> then calls out to all the low-level init code in a sane order, that
> would solve the problem. I'm not sure that's any better than having a
> machine descriptor with an "init" function though; wrapping all this in
> a driver just seems like overhead, but it would work out OK.
This is exactly the same as having a machine descriptor, but the
arch/arm64 maintainers don't have to look at it so they don't think it
is one.
So now we need to find a place for machine descriptors somewhere under
drivers/* too. Sigh. Agreed, this is nothing but overhead and
overabstraction.
-Olof
^ permalink raw reply
* [PATCH v6 4/5] PCI: add PCI controller for keystone PCIe h/w
From: Murali Karicheri @ 2014-07-21 16:39 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <006001cfa485$4f4fcff0$edef6fd0$%han@samsung.com>
On 07/20/2014 09:44 PM, Jingoo Han wrote:
> On Saturday, July 19, 2014 5:29 AM, Murali Karicheri wrote:
>> On 07/18/2014 03:31 PM, Rob Herring wrote:
>>> On Fri, Jul 18, 2014 at 10:14 AM, Murali Karicheri<m-karicheri2@ti.com> wrote:
>> --- Cut ---
>>>> +
>>>> +Optional properties:-
>>>> + phys: phandle to Generic Keystone SerDes phy for PCI
>>>> + phy-names: name of the Generic Keystine SerDes phy for PCI
>>>> + - If boot loader already does PCI link establishment, then phys and
>>>> + phy-names shouldn't be present.
>>>> + ti,enable-linktrain - Enable Link training.
>>>> + - If boot loader already does PCI link establishment, then this
>>>> + shouldn't be present.
>>>
>>> Can't you read from the h/w if the link is trained?
>
> I agree with Rob Herring's suggestion.
>
>>
>> Yes.
>>
>> There are customers who use this driver with PCI Link setup done in the
>> boot loader. This property tells the driver to bypass Link setup
>> procedure in that case. Is this undesirable and if so. how other
>> platforms handle it? Check first if link is trained or start the link
>> setup procedure? Let me know. If this is fine, please provide your Ack.
>
> Please, check the following code of Exynos PCIe diver.
>
> ./drivers/pci/host/pci-exynos.c
>
> static int exynos_pcie_establish_link(struct pcie_port *pp)
> {
> struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
> void __iomem *elbi_base = exynos_pcie->elbi_base;
> void __iomem *pmu_base = exynos_pcie->pmu_base;
>
> if (dw_pcie_link_up(pp)) {
> dev_err(pp->dev, "Link already up\n");
> return 0;
> }
> .....
>
> In the case of Exynos PCIe, the Exynos PCIe driver checks the
> h/w bit such as PCIE_ELBI_LTSSM_ENABLE bit of PCIE_ELBI_RDLH_LINKUP
> offset register.
>
> If the link is already set up by the boot loader or other reasons,
> the driver will skip some initialization codes.
>
> The first step is that you find such h/w bit for checking link up.
> If so, please add the code for skipping, when the link is already
> set up.
>
Rob, Jingoo,
We have similar bit to check for Link status and I have removed the DT
property and skip Link retrain if PCIe Link is already Up. I will be
resending the series with Patch 4/5 updated.
Thanks.
Murali
> Best regards,
> Jingoo Han
>
^ permalink raw reply
* [GIT PULL 2/3] ARM: tegra: move fuse code out of arch/arm
From: Stephen Warren @ 2014-07-21 16:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140721155451.GF32578@arm.com>
On 07/21/2014 09:54 AM, Catalin Marinas wrote:
> On Mon, Jul 21, 2014 at 09:06:00AM -0600, Stephen Warren wrote:
>> On 07/17/2014 11:33 PM, Olof Johansson wrote:
>>> On Thu, Jul 17, 2014 at 7:45 PM, Stephen Warren <swarren@wwwdotorg.org> wrote:
>>>> On 07/08/2014 11:47 AM, Olof Johansson wrote:
>>>>> On Tue, Jul 8, 2014 at 6:43 AM, Peter De Schrijver
>>>>> <pdeschrijver@nvidia.com> wrote:
>>>>>> On Mon, Jul 07, 2014 at 02:44:17AM +0200, Olof Johansson wrote:
>>>>>>> On Mon, Jun 23, 2014 at 03:23:45PM -0600, Stephen Warren wrote:
>>>>>>>> This branch moves code related to the Tegra fuses out of arch/arm and
>>>>>>>> into a centralized location which could be shared with ARM64. It also
>>>>>>>> adds support for reading the fuse data through sysfs.
>>>>>>>
>>>>>>> The new/moved misc driver isn't acked by any misc maintainer, so I can't
>>>>>>> take this branch.
>>>>>>>
>>>>>>> I saw no indication from searching the mailing list of that either,
>>>>>>> so it wasn't just a missed acked-by.
>>>>>>>
>>>>>>> I wonder if this code should go under drivers/soc/ instead?
>>>>>>
>>>>>> It's modelled after sunxi_sid.c which lives in drivers/misc/eeprom/.
>>>>>> Originally this driver was also in drivers/misc/eeprom/, but Stephen objected
>>>>>> and therefore it was moved to drivers/misc/fuse. I think that's the right
>>>>>> place still.
>>>>>
>>>>> I disagree, I think this belongs under drivers/soc. Especially since
>>>>> you're adding dependencies on this misc driver from other parts of the
>>>>> kernel / other drivers.
>>>>>
>>>>> I also don't like seeing init calls form platform code down into
>>>>> drivers/misc like you're adding here. Can you please look at doing
>>>>> that as a regular init call setup?
>>>>
>>>> I strongly disagree with using init calls for this kind of thing. There
>>>> are ordering dependencies between the initialization code that can only
>>>> be sanely managed by explicitly calling functions in a particular order;
>>>> there's simply no way to manage this using initcalls. This is exactly
>>>> why the hooks in the ARM machine descriptors exist...
>>>
>>> Right, but there are non on 64-bit, so you need to solve it for there
>>> anyway. And once it's solved there, you might as well keep it common
>>> with 32-bit.
>>
>> My assertion is that we should just do it directly on 64-bit too.
>> There's no reason for arm64 to deviate from what arch/arm does already.
>
> On arm64, I really want to get away from any SoC specific early
> initcall. One of the main reason is for things like SCU, interconnects,
> system cache configurations (even certain clocks) to be enabled in
> firmware before Linux starts (it's an education process but that's a way
> for example to prevent people sending patches to enable SoC coherency
> because they haven't thought about it before upstreaming).
>
> It would be nice to be able to initialise SoC stuff at device_initcall()
> level (and even keep such code as modules in initramfs) but one of the
> problems we have is dependency on clocks (and the clock model which
> doesn't follow the device/driver model). The of_platform_populate() is
> called at arch_initcall_sync (after arch_initcall to still allow some
> SoC code, if needed, to run at arch_initcall).
The main thing I want to avoid is a ton of separate drivers that all
rely on each-other getting resolved by deferred probe. While that might
work out, it seems pointless to make the kernel try and probe a bunch of
stuff just to have it fail and get repeated, when we know exactly which
order everything should get initialized in.
Another issue is that we have SoCs which only differ in the CPU. I want
the code to work identically on both SoCs so the CPU has limited affect
on the low-level IO code. If we're going to enforce a "no machine
descriptors" rule on arch/arm64, I think we should do the same thing in
arch/arm for consistency.
> We have a similar issue with arm64 vexpress (well, just on the model)
> where vexpress_sysreg_init() is a core_initcall (should be fine as
> arch_initcall) as it needs to be done before of_platform_populate().
> Pawel on cc should know more of the history here.
>
> I recall there were also some discussions about a SoC driver model which
> hangs off the top compatible string in the DT (e.g. "arm,vexpress") and
> allow (minimal) code to be run slightly earlier, though still not
> earlier than arch_initcall.
I guess that would work out OK; if we force the driver that binds to a
top-level compatible value of "nvidia,tegraNNN" to probe first, and it
then calls out to all the low-level init code in a sane order, that
would solve the problem. I'm not sure that's any better than having a
machine descriptor with an "init" function though; wrapping all this in
a driver just seems like overhead, but it would work out OK.
^ permalink raw reply
* [PATCH v2] arm64/efi: efistub: jump to 'stext' directly, not through the header
From: Ard Biesheuvel @ 2014-07-21 16:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405606141.25580.108.camel@deneb.redhat.com>
On 17 July 2014 16:09, Mark Salter <msalter@redhat.com> wrote:
> On Wed, 2014-07-16 at 23:13 +0200, Ard Biesheuvel wrote:
>> On 16 July 2014 23:03, Mark Salter <msalter@redhat.com> wrote:
>> > On Wed, 2014-07-16 at 22:38 +0200, Ard Biesheuvel wrote:
>> >> On 16 July 2014 21:45, Mark Salter <msalter@redhat.com> wrote:
>> >> > On Wed, 2014-07-16 at 16:53 +0100, Mark Rutland wrote:
>> >> >> On Wed, Jul 16, 2014 at 03:51:37PM +0100, Mark Salter wrote:
>> >> >> > On Tue, 2014-07-15 at 12:58 +0200, Ard Biesheuvel wrote:
>> >> >> > > After the EFI stub has done its business, it jumps into the kernel by branching
>> >> >> > > to offset #0 of the loaded Image, which is where it expects to find the header
>> >> >> > > containing a 'branch to stext' instruction.
>> >> >> > >
>> >> >> > > However, the header is not covered by any PE/COFF section, so the header may
>> >> >> > > not actually be loaded at the expected offset. So instead, jump to 'stext'
>> >> >> > > directly, which is at the base of the PE/COFF .text section, by supplying a
>> >> >> > > symbol 'stext_offset' to efi-entry.o which contains the relative offset of
>> >> >> > > stext into the Image. Also replace other open coded calculations of the same
>> >> >> > > value with a reference to 'stext_offset'
>> >> >> >
>> >> >> > Have you actually seen a situation where the header isn't there?
>> >> >> > Isn't the kernel header actually part of the pe/coff file and
>> >> >> > firmware loads the whole file into RAM?
>> >> >>
>> >> >> From my understanding of Ard's earlier comments, this part isn't
>> >> >> guaranteed per the UEFI spec.
>> >> >>
>> >> >> I would rather we weren't relying on implementation details.
>> >> >>
>> >> >
>> >> > Could be. I didn't see anything about it in the UEFI spec, but I
>> >> > probably wasn't exhaustive in my search. In any case, there's at
>> >> > least one other place broken if the kernel header isn't included
>> >> > in the loaded image.
>> >> >
>> >>
>> >> I have not been able to find anything in the PE/COFF documents that
>> >> tells you what to put in memory areas that are not covered by a
>> >> section. Expecting the header to be there is indeed relying on an
>> >> implementation detail, which seems risky.
>> >> And indeed, if there are any other (non EFI related) uses of header
>> >> fields in the kernel, it would be good to have a look at those well,
>> >
>> > I think we need to come up with a loader which does load an image
>> > without kernel header so that we can test. Otherwise, we'll probably
>> > end up with buggy code anyway. The stub code assumes the the loaded
>> > image pointed to by the system table is the whole image. Seems like
>> > we'd need to add code to determine if it is whole kernel image or
>> > image without initial header. Stub would have to handle both cases.
>> > For instance, one case would want image placed at 2MiB+TEXT_OFFSET,
>> > other case would want 2MiB+TEXT_OFFSET+sizeof(kernel header).
>> >
>>
>> No, this has nothing to do with misaligned data.
>>
>> The PE/COFF .text section does not start at virtual offset #0 but at
>> virtual offset 'stext - efi_head'.
>> In other words, there is a hole in the virtual image where the header
>> is supposed to be.
>> So if there is no PE/COFF section describing what data should be put
>> at offset #0 by the loader, we can't assume the header is there, even
>> if ImageBase does start at #0
>
> I get that. You're supposing UEFI will always allocate memory for the
> full image, but only sometimes copy the PE/COFF headers. I can see your
> point from a PE/COFF perspective, but not so much from the UEFI spec
> perspective where the language leads me to think it treats the PE/COFF
> images as one unit wrt loading. In any case, it really isn't worth
> arguing about. I don't have any objection to the patch since it won't
> break anything from my perspective and it'll protect against breakage
> which could possibly occur with some firmware implementations.
>
OK, thanks.
--
Ard.
^ permalink raw reply
* [PATCH 2/2] iio: exynos-adc: add experimental touchscreen support
From: Dmitry Torokhov @ 2014-07-21 16:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6569004.FG0IRy8WyL@wuerfel>
On Mon, Jul 21, 2014 at 05:11:27PM +0200, Arnd Bergmann wrote:
> On Monday 21 July 2014 07:44:42 Dmitry Torokhov wrote:
> > > >
> > > > It would be nice to actually close the device even if someone is
> > > > touching screen. Please implement open/close methods and have them set a
> > > > flag that you would check here.
> > >
> > > Ok. I think it's even better to move the request_irq() into the open function,
> > > which will avoid the flag and defer the error handling into the actual opening,
> > > as well as syncing the running irq with the close function.
> >
> > I do not quite like acquiring resources needed in open. I think drivers should
> > do all resource acquisition in probe() and leave open()/close() to
> > activate/quiesce devices.
>
> Ok, I'll move it back then. I'm not sure what I'm supposed to do
> in open/close then. Isn't it enough to check info->input->users
> like this?
>
> static irqreturn_t exynos_ts_isr(int irq, void *dev_id)
> {
> struct exynos_adc *info = dev_id;
> struct iio_dev *dev = dev_get_drvdata(info->dev);
> u32 x, y;
> bool pressed;
> int ret;
>
> while (info->input->users) {
> ret = exynos_read_s3c64xx_ts(dev, &x, &y);
> if (ret == -ETIMEDOUT)
> break;
>
> pressed = x & y & ADC_DATX_PRESSED;
> if (!pressed) {
> input_report_key(info->input, BTN_TOUCH, 0);
> input_sync(info->input);
> break;
> }
>
> input_report_abs(info->input, ABS_X, x & ADC_DATX_MASK);
> input_report_abs(info->input, ABS_Y, y & ADC_DATY_MASK);
> input_report_key(info->input, BTN_TOUCH, 1);
> input_sync(info->input);
>
> msleep(1);
> };
>
> writel(0, ADC_V1_CLRINTPNDNUP(info->regs));
>
> return IRQ_HANDLED;
> }
>
> I could do enable_irq()/disable_irq(), but that leaves a small
> race at startup where we request the irq line and then immediately
> disable it again.
I think the above (or a separate flag in driver structure) coupled with
enable/disable IRQ is fine - input core can deal with calls to input_report_*
on devices that have been properly allocated but have not been registered yet.
drivers/input/keyboard/samsung-keypad.c does similar handling.
Thanks.
--
Dmitry
^ permalink raw reply
* [PATCH RFC 9/9] arm: imx: non-secure aliased mapping of GIC registers
From: Marek Vasut @ 2014-07-21 16:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405954040-30399-10-git-send-email-daniel.thompson@linaro.org>
On Monday, July 21, 2014 at 04:47:20 PM, Daniel Thompson wrote:
> Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
> ---
> arch/arm/mach-imx/mach-imx6q.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/arch/arm/mach-imx/mach-imx6q.c
> b/arch/arm/mach-imx/mach-imx6q.c index e60456d..192d268 100644
> --- a/arch/arm/mach-imx/mach-imx6q.c
> +++ b/arch/arm/mach-imx/mach-imx6q.c
> @@ -381,10 +381,21 @@ static void __init imx6q_init_late(void)
> }
> }
>
> +static struct map_desc gic_cpu_io_desc __initdata = {
> + .virtual = 0xff000000,
> + .pfn = __phys_to_pfn(0x00a00000),
> + .length = SZ_1M,
> + .type = MT_DEVICE_NS,
> +};
> +
> static void __init imx6q_map_io(void)
> {
> debug_ll_io_init();
> imx_scu_map_io();
> + /* TODO: Need to check we are running without a secure monitor before
> + * setting up this mapping.
> + */
> + iotable_init(&gic_cpu_io_desc, 1);
> }
Is there no way to add ioremap_nonsecure() so the gic can allocate the mapping
itself instead of adding a static one ? Also, can you add a flag to the
MT_DEVICE_NS that says the mapping can only ever be in L1 and never in "lower"
levels of the page table ?
Best regards,
Marek Vasut
^ permalink raw reply
* [GIT PULL 2/3] ARM: tegra: move fuse code out of arch/arm
From: Pawel Moll @ 2014-07-21 16:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20140721155451.GF32578@arm.com>
On Mon, 2014-07-21 at 16:54 +0100, Catalin Marinas wrote:
> We have a similar issue with arm64 vexpress (well, just on the model)
> where vexpress_sysreg_init() is a core_initcall (should be fine as
> arch_initcall) as it needs to be done before of_platform_populate().
> Pawel on cc should know more of the history here.
In case of vexpress the trick was to squeeze everything into the device
model. Once this was done, there was enough initcall levels to get all
dependencies sorted. The device model is good. We seemed to have learned
to abuse it claiming that "things must be initialised early", while in 9
out of 10 cases they don't have to be "that early"...
> I recall there were also some discussions about a SoC driver model which
> hangs off the top compatible string in the DT (e.g. "arm,vexpress") and
> allow (minimal) code to be run slightly earlier, though still not
> earlier than arch_initcall.
This was just a loose idea:
http://thread.gmane.org/gmane.linux.ports.arm.kernel/204361/focus=204843
I still like it, and it seems logical to me. We've got a platform. It's
got a compatible string. We can write a driver for this platform that
does all magic at appropriate initcall level.
Pawe?
^ permalink raw reply
* [PATCH] exynos: boot serial endian fix
From: Mark Brown @ 2014-07-21 16:11 UTC (permalink / raw)
To: linux-arm-kernel
From: Victor Kamensky <victor.kamensky@linaro.org>
In order to support booting a big endian kernel the uncompress serial
line write utils need to use endian neutral functions to read h/w
register. Fix uart_rd, uart_wr and serial chip fifo related macros to do
this.
Signed-off-by: Victor Kamensky <victor.kamensky@linaro.org>
Signed-off-by: Mark Brown <broonie@linaro.org>
---
arch/arm/include/debug/samsung.S | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/arch/arm/include/debug/samsung.S b/arch/arm/include/debug/samsung.S
index 8d8d922e5e44..dc62d4ae04d0 100644
--- a/arch/arm/include/debug/samsung.S
+++ b/arch/arm/include/debug/samsung.S
@@ -9,17 +9,20 @@
* published by the Free Software Foundation.
*/
+#include <asm/assembler.h>
#include <linux/serial_s3c.h>
/* The S5PV210/S5PC110 implementations are as belows. */
.macro fifo_level_s5pv210 rd, rx
ldr \rd, [\rx, # S3C2410_UFSTAT]
+ ARM_BE8(rev \rd, \rd)
and \rd, \rd, #S5PV210_UFSTAT_TXMASK
.endm
.macro fifo_full_s5pv210 rd, rx
ldr \rd, [\rx, # S3C2410_UFSTAT]
+ ARM_BE8(rev \rd, \rd)
tst \rd, #S5PV210_UFSTAT_TXFULL
.endm
@@ -28,6 +31,7 @@
.macro fifo_level_s3c2440 rd, rx
ldr \rd, [\rx, # S3C2410_UFSTAT]
+ ARM_BE8(rev \rd, \rd)
and \rd, \rd, #S3C2440_UFSTAT_TXMASK
.endm
@@ -37,6 +41,7 @@
.macro fifo_full_s3c2440 rd, rx
ldr \rd, [\rx, # S3C2410_UFSTAT]
+ ARM_BE8(rev \rd, \rd)
tst \rd, #S3C2440_UFSTAT_TXFULL
.endm
@@ -50,6 +55,7 @@
.macro busyuart, rd, rx
ldr \rd, [\rx, # S3C2410_UFCON]
+ ARM_BE8(rev \rd, \rd)
tst \rd, #S3C2410_UFCON_FIFOMODE @ fifo enabled?
beq 1001f @
@ FIFO enabled...
@@ -61,6 +67,7 @@
1001:
@ busy waiting for non fifo
ldr \rd, [\rx, # S3C2410_UTRSTAT]
+ ARM_BE8(rev \rd, \rd)
tst \rd, #S3C2410_UTRSTAT_TXFE
beq 1001b
@@ -69,6 +76,7 @@
.macro waituart,rd,rx
ldr \rd, [\rx, # S3C2410_UFCON]
+ ARM_BE8(rev \rd, \rd)
tst \rd, #S3C2410_UFCON_FIFOMODE @ fifo enabled?
beq 1001f @
@ FIFO enabled...
@@ -80,6 +88,7 @@
1001:
@ idle waiting for non fifo
ldr \rd, [\rx, # S3C2410_UTRSTAT]
+ ARM_BE8(rev \rd, \rd)
tst \rd, #S3C2410_UTRSTAT_TXFE
beq 1001b
--
2.0.1
^ permalink raw reply related
* [PATCH RFC 1/9] irqchip: gic: Provide support for interrupt grouping
From: Marek Vasut @ 2014-07-21 16:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405954040-30399-2-git-send-email-daniel.thompson@linaro.org>
On Monday, July 21, 2014 at 04:47:12 PM, Daniel Thompson wrote:
> All GIC hardware except GICv1-without-TrustZone support provides a means
> to group exceptions into group 0 (which can optionally be signally using
> use FIQ) and group 1. The kernel currently provides no means to exploit
> this. This patch alters the initialization of the GIC to place all
> interrupts into group 1 which is the foundational requirement to
> meaningfully use FIQ.
[...]
> @@ -670,7 +753,11 @@ static void gic_raise_softirq(const struct cpumask
> *mask, unsigned int irq) dmb(ishst);
>
> /* this always happens on GIC0 */
> - writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) +
> GIC_DIST_SOFTINT); + softint = map << 16 | irq;
> + if (gic_data_fiq_enable(&gic_data[0]))
> + softint |= 0x8000;
These magic bits here could use some clarification, possibly a comment.
> + writel_relaxed(softint,
> + gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
>
> raw_spin_unlock_irqrestore(&irq_controller_lock, flags);
> }
[...]
Best regards,
Marek Vasut
^ permalink raw reply
* [PATCH v6 7/7] drivers: cpuidle: initialize Exynos driver through DT
From: Lorenzo Pieralisi @ 2014-07-21 16:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405958786-17243-1-git-send-email-lorenzo.pieralisi@arm.com>
With the introduction of DT based idle states, CPUidle drivers for
ARM can now initialize idle states data through properties in the device
tree.
This patch adds code to the Exynos CPUidle driver to dynamically
initialize idle states data through the updated device tree source
files.
Cc: Chander Kashyap <chander.kashyap@linaro.org>
Cc: Kukjin Kim <kgene.kim@samsung.com>
Cc: Tomasz Figa <t.figa@samsung.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
---
arch/arm/boot/dts/exynos4210.dtsi | 11 +++++++++++
arch/arm/boot/dts/exynos5250.dtsi | 11 +++++++++++
drivers/cpuidle/Kconfig.arm | 1 +
drivers/cpuidle/cpuidle-exynos.c | 37 ++++++++++++++++++++++++-------------
4 files changed, 47 insertions(+), 13 deletions(-)
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
index bc2b444..0270100 100644
--- a/arch/arm/boot/dts/exynos4210.dtsi
+++ b/arch/arm/boot/dts/exynos4210.dtsi
@@ -39,12 +39,23 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0x900>;
+ cpu-idle-states = <&CLUSTER_SLEEP_0>;
};
cpu at 901 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0x901>;
+ cpu-idle-states = <&CLUSTER_SLEEP_0>;
+ };
+
+ idle-states {
+ CLUSTER_SLEEP_0: cluster-sleep-0 {
+ compatible = "arm,idle-state";
+ entry-latency-us = <1000>;
+ exit-latency-us = <300>;
+ min-residency-us = <100000>;
+ };
};
};
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index 834fb5a..631906e 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -63,12 +63,23 @@
compatible = "arm,cortex-a15";
reg = <0>;
clock-frequency = <1700000000>;
+ cpu-idle-states = <&CLUSTER_SLEEP_0>;
};
cpu at 1 {
device_type = "cpu";
compatible = "arm,cortex-a15";
reg = <1>;
clock-frequency = <1700000000>;
+ cpu-idle-states = <&CLUSTER_SLEEP_0>;
+ };
+
+ idle-states {
+ CLUSTER_SLEEP_0: cluster-sleep-0 {
+ compatible = "arm,idle-state";
+ entry-latency-us = <1000>;
+ exit-latency-us = <300>;
+ min-residency-us = <100000>;
+ };
};
};
diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm
index a9b089c..d8a9cd2 100644
--- a/drivers/cpuidle/Kconfig.arm
+++ b/drivers/cpuidle/Kconfig.arm
@@ -60,5 +60,6 @@ config ARM_AT91_CPUIDLE
config ARM_EXYNOS_CPUIDLE
bool "Cpu Idle Driver for the Exynos processors"
depends on ARCH_EXYNOS
+ select DT_IDLE_STATES
help
Select this to enable cpuidle for Exynos processors
diff --git a/drivers/cpuidle/cpuidle-exynos.c b/drivers/cpuidle/cpuidle-exynos.c
index 7c01512..097c21d 100644
--- a/drivers/cpuidle/cpuidle-exynos.c
+++ b/drivers/cpuidle/cpuidle-exynos.c
@@ -13,11 +13,14 @@
#include <linux/export.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <asm/proc-fns.h>
#include <asm/suspend.h>
#include <asm/cpuidle.h>
+#include "dt_idle_states.h"
+
static void (*exynos_enter_aftr)(void);
static int idle_finisher(unsigned long flags)
@@ -60,32 +63,40 @@ static struct cpuidle_driver exynos_idle_driver = {
.owner = THIS_MODULE,
.states = {
[0] = ARM_CPUIDLE_WFI_STATE,
- [1] = {
- .enter = exynos_enter_lowpower,
- .exit_latency = 300,
- .target_residency = 100000,
- .flags = CPUIDLE_FLAG_TIME_VALID,
- .name = "C1",
- .desc = "ARM power down",
- },
},
- .state_count = 2,
- .safe_state_index = 0,
};
static int exynos_cpuidle_probe(struct platform_device *pdev)
{
- int ret;
+ int ret, i;
+ struct cpuidle_driver *drv = &exynos_idle_driver;
exynos_enter_aftr = (void *)(pdev->dev.platform_data);
- ret = cpuidle_register(&exynos_idle_driver, NULL);
+ drv->cpumask = kzalloc(cpumask_size(), GFP_KERNEL);
+ if (!drv->cpumask)
+ return -ENOMEM;
+
+ /* Start at index 1, index 0 standard WFI */
+ ret = dt_init_idle_driver(drv, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to initialize idle states\n");
+ goto free_mem;
+ }
+
+ for (i = 1; i < drv->state_count; i++)
+ drv->states[i].enter = exynos_enter_lowpower;
+
+ ret = cpuidle_register(drv, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to register cpuidle driver\n");
- return ret;
+ goto free_mem;
}
return 0;
+free_mem:
+ kfree(drv->cpumask);
+ return ret;
}
static struct platform_driver exynos_cpuidle_driver = {
--
1.9.1
^ permalink raw reply related
* [PATCH v6 6/7] drivers: cpuidle: initialize big.LITTLE driver through DT
From: Lorenzo Pieralisi @ 2014-07-21 16:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405958786-17243-1-git-send-email-lorenzo.pieralisi@arm.com>
With the introduction of DT based idle states, CPUidle drivers for ARM
can now initialize idle states data through properties in the device tree.
This patch adds code to the big.LITTLE CPUidle driver to dynamically
initialize idle states data through the updated device tree source file.
Cc: Chander Kashyap <chander.kashyap@linaro.org>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
---
arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts | 23 ++++++++++++++++
drivers/cpuidle/Kconfig.arm | 1 +
drivers/cpuidle/cpuidle-big_little.c | 43 +++++++++++++++---------------
3 files changed, 46 insertions(+), 21 deletions(-)
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
index a25c262..d61da86 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
@@ -38,6 +38,7 @@
compatible = "arm,cortex-a15";
reg = <0>;
cci-control-port = <&cci_control1>;
+ cpu-idle-states = <&CLUSTER_SLEEP_BIG>;
};
cpu1: cpu at 1 {
@@ -45,6 +46,7 @@
compatible = "arm,cortex-a15";
reg = <1>;
cci-control-port = <&cci_control1>;
+ cpu-idle-states = <&CLUSTER_SLEEP_BIG>;
};
cpu2: cpu at 2 {
@@ -52,6 +54,7 @@
compatible = "arm,cortex-a7";
reg = <0x100>;
cci-control-port = <&cci_control2>;
+ cpu-idle-states = <&CLUSTER_SLEEP_LITTLE>;
};
cpu3: cpu at 3 {
@@ -59,6 +62,7 @@
compatible = "arm,cortex-a7";
reg = <0x101>;
cci-control-port = <&cci_control2>;
+ cpu-idle-states = <&CLUSTER_SLEEP_LITTLE>;
};
cpu4: cpu at 4 {
@@ -66,6 +70,25 @@
compatible = "arm,cortex-a7";
reg = <0x102>;
cci-control-port = <&cci_control2>;
+ cpu-idle-states = <&CLUSTER_SLEEP_LITTLE>;
+ };
+
+ idle-states {
+ CLUSTER_SLEEP_BIG: cluster-sleep-big {
+ compatible = "arm,idle-state";
+ local-timer-stop;
+ entry-latency-us = <1000>;
+ exit-latency-us = <700>;
+ min-residency-us = <3500>;
+ };
+
+ CLUSTER_SLEEP_LITTLE: cluster-sleep-little {
+ compatible = "arm,idle-state";
+ local-timer-stop;
+ entry-latency-us = <1000>;
+ exit-latency-us = <500>;
+ min-residency-us = <3000>;
+ };
};
};
diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm
index b6d69e8..a9b089c 100644
--- a/drivers/cpuidle/Kconfig.arm
+++ b/drivers/cpuidle/Kconfig.arm
@@ -12,6 +12,7 @@ config ARM_BIG_LITTLE_CPUIDLE
depends on ARCH_VEXPRESS_TC2_PM
select ARM_CPU_SUSPEND
select CPU_IDLE_MULTIPLE_DRIVERS
+ select DT_IDLE_STATES
help
Select this option to enable CPU idle driver for big.LITTLE based
ARM systems. Driver manages CPUs coordination through MCPM and
diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c
index b45fc62..0a88480 100644
--- a/drivers/cpuidle/cpuidle-big_little.c
+++ b/drivers/cpuidle/cpuidle-big_little.c
@@ -24,6 +24,8 @@
#include <asm/smp_plat.h>
#include <asm/suspend.h>
+#include "dt_idle_states.h"
+
static int bl_enter_powerdown(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int idx);
@@ -61,32 +63,12 @@ static struct cpuidle_driver bl_idle_little_driver = {
.name = "little_idle",
.owner = THIS_MODULE,
.states[0] = ARM_CPUIDLE_WFI_STATE,
- .states[1] = {
- .enter = bl_enter_powerdown,
- .exit_latency = 700,
- .target_residency = 2500,
- .flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_TIMER_STOP,
- .name = "C1",
- .desc = "ARM little-cluster power down",
- },
- .state_count = 2,
};
static struct cpuidle_driver bl_idle_big_driver = {
.name = "big_idle",
.owner = THIS_MODULE,
.states[0] = ARM_CPUIDLE_WFI_STATE,
- .states[1] = {
- .enter = bl_enter_powerdown,
- .exit_latency = 500,
- .target_residency = 2000,
- .flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_TIMER_STOP,
- .name = "C1",
- .desc = "ARM big-cluster power down",
- },
- .state_count = 2,
};
/*
@@ -165,7 +147,8 @@ static int __init bl_idle_driver_init(struct cpuidle_driver *drv, int cpu_id)
static int __init bl_idle_init(void)
{
- int ret;
+ int ret, i;
+ struct cpuidle_driver *drv;
/*
* Initialize the driver just for a compliant set of machines
@@ -187,6 +170,24 @@ static int __init bl_idle_init(void)
if (ret)
goto out_uninit_little;
+ /* Start at index 1, index 0 standard WFI */
+ ret = dt_init_idle_driver(&bl_idle_big_driver, 1);
+ if (ret)
+ goto out_uninit_big;
+
+ /* Start at index 1, index 0 standard WFI */
+ ret = dt_init_idle_driver(&bl_idle_little_driver, 1);
+ if (ret)
+ goto out_uninit_big;
+
+ drv = &bl_idle_big_driver;
+ for (i = 1; i < drv->state_count; i++)
+ drv->states[i].enter = bl_enter_powerdown;
+
+ drv = &bl_idle_little_driver;
+ for (i = 1; i < drv->state_count; i++)
+ drv->states[i].enter = bl_enter_powerdown;
+
ret = cpuidle_register(&bl_idle_little_driver, NULL);
if (ret)
goto out_uninit_big;
--
1.9.1
^ permalink raw reply related
* [PATCH v6 5/7] drivers: cpuidle: CPU idle ARM64 driver
From: Lorenzo Pieralisi @ 2014-07-21 16:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405958786-17243-1-git-send-email-lorenzo.pieralisi@arm.com>
This patch implements a generic CPU idle driver for ARM64 machines.
It relies on the DT idle states infrastructure to initialize idle
states count and respective parameters. Current code assumes the driver
is managing idle states on all possible CPUs but can be easily
generalized to support heterogenous systems and build cpumasks at
runtime using MIDRs or DT cpu nodes compatible properties.
The driver relies on the arm64 CPU operations to call the idle
initialization hook used to parse and save suspend back-end specific
idle states information upon probing.
Idle state index 0 is always initialized as a simple wfi state, ie always
considered present and functional on all ARM64 platforms.
Idle state indices higher than 0 trigger idle state entry by calling
the cpu_suspend function, that does save the CPU context and executes
the CPU operations suspend back-end hook. cpu_suspend passes the idle
state index as a parameter so that the CPU operations suspend back-end
can retrieve the required idle state data by using the idle state
index to execute a look-up on its internal data structures.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
---
drivers/cpuidle/Kconfig | 5 ++
drivers/cpuidle/Kconfig.arm64 | 14 +++++
drivers/cpuidle/Makefile | 4 ++
drivers/cpuidle/cpuidle-arm64.c | 128 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 151 insertions(+)
create mode 100644 drivers/cpuidle/Kconfig.arm64
create mode 100644 drivers/cpuidle/cpuidle-arm64.c
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index 414e7a96..ebf0c2e 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -43,6 +43,11 @@ depends on ARM
source "drivers/cpuidle/Kconfig.arm"
endmenu
+menu "ARM64 CPU Idle Drivers"
+depends on ARM64
+source "drivers/cpuidle/Kconfig.arm64"
+endmenu
+
menu "MIPS CPU Idle Drivers"
depends on MIPS
source "drivers/cpuidle/Kconfig.mips"
diff --git a/drivers/cpuidle/Kconfig.arm64 b/drivers/cpuidle/Kconfig.arm64
new file mode 100644
index 0000000..d0a08ed
--- /dev/null
+++ b/drivers/cpuidle/Kconfig.arm64
@@ -0,0 +1,14 @@
+#
+# ARM64 CPU Idle drivers
+#
+
+config ARM64_CPUIDLE
+ bool "Generic ARM64 CPU idle Driver"
+ select ARM64_CPU_SUSPEND
+ select DT_IDLE_STATES
+ help
+ Select this to enable generic cpuidle driver for ARM64.
+ It provides a generic idle driver whose idle states are configured
+ at run-time through DT nodes. The CPUidle suspend backend is
+ initialized by calling the CPU operations init idle hook
+ provided by architecture code.
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index b27a062..706cb7f 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -23,6 +23,10 @@ obj-$(CONFIG_ARM_EXYNOS_CPUIDLE) += cpuidle-exynos.o
obj-$(CONFIG_MIPS_CPS_CPUIDLE) += cpuidle-cps.o
###############################################################################
+# ARM64 drivers
+obj-$(CONFIG_ARM64_CPUIDLE) += cpuidle-arm64.o
+
+###############################################################################
# POWERPC drivers
obj-$(CONFIG_PSERIES_CPUIDLE) += cpuidle-pseries.o
obj-$(CONFIG_POWERNV_CPUIDLE) += cpuidle-powernv.o
diff --git a/drivers/cpuidle/cpuidle-arm64.c b/drivers/cpuidle/cpuidle-arm64.c
new file mode 100644
index 0000000..1aeb426
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-arm64.c
@@ -0,0 +1,128 @@
+/*
+ * ARM64 generic CPU idle driver.
+ *
+ * Copyright (C) 2014 ARM Ltd.
+ * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define pr_fmt(fmt) "CPUidle arm64: " fmt
+
+#include <linux/cpuidle.h>
+#include <linux/cpumask.h>
+#include <linux/cpu_pm.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include <asm/cpuidle.h>
+#include <asm/suspend.h>
+
+#include "dt_idle_states.h"
+
+/*
+ * arm_enter_idle_state - Programs CPU to enter the specified state
+ *
+ * dev: cpuidle device
+ * drv: cpuidle driver
+ * idx: state index
+ *
+ * Called from the CPUidle framework to program the device to the
+ * specified target state selected by the governor.
+ */
+static int arm_enter_idle_state(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int idx)
+{
+ int ret;
+
+ if (!idx) {
+ cpu_do_idle();
+ return idx;
+ }
+
+ ret = cpu_pm_enter();
+ if (!ret) {
+ /*
+ * Pass idle state index to cpu_suspend which in turn will
+ * call the CPU ops suspend protocol with idle index as a
+ * parameter.
+ */
+ ret = cpu_suspend(idx);
+
+ cpu_pm_exit();
+ }
+
+ return ret ? -1 : idx;
+}
+
+struct cpuidle_driver arm64_idle_driver = {
+ .name = "arm64_idle",
+ .owner = THIS_MODULE,
+ /*
+ * State at index 0 is standby wfi and considered standard
+ * on all ARM platforms. If in some platforms simple wfi
+ * can't be used as "state 0", DT bindings must be implemented
+ * to work around this issue and allow installing a special
+ * handler for idle state index 0.
+ */
+ .states[0] = {
+ .enter = arm_enter_idle_state,
+ .exit_latency = 1,
+ .target_residency = 1,
+ .power_usage = UINT_MAX,
+ .flags = CPUIDLE_FLAG_TIME_VALID,
+ .name = "WFI",
+ .desc = "ARM64 WFI",
+ }
+};
+
+/*
+ * arm64_idle_init
+ *
+ * Registers the arm64 specific cpuidle driver with the cpuidle
+ * framework. It relies on core code to parse the idle states
+ * and initialize them using driver data structures accordingly.
+ */
+static int __init arm64_idle_init(void)
+{
+ int i, ret;
+ struct cpuidle_driver *drv = &arm64_idle_driver;
+
+ drv->cpumask = kzalloc(cpumask_size(), GFP_KERNEL);
+ if (!drv->cpumask)
+ return -ENOMEM;
+
+ cpumask_copy(drv->cpumask, cpu_possible_mask);
+ /*
+ * Start at index 1, request idle state nodes to be filled
+ */
+ ret = dt_init_idle_driver(drv, 1);
+ if (ret)
+ goto free_mem;
+ /*
+ * Call arch CPU operations in order to initialize
+ * idle states suspend back-end specific data
+ */
+ for_each_cpu(i, drv->cpumask) {
+ ret = cpu_init_idle(i);
+ if (ret)
+ goto free_mem;
+ }
+
+ for (i = 1; i < drv->state_count; i++)
+ drv->states[i].enter = arm_enter_idle_state;
+
+ ret = cpuidle_register(drv, NULL);
+ if (ret)
+ goto free_mem;
+
+ return 0;
+free_mem:
+ kfree(drv->cpumask);
+ return ret;
+}
+device_initcall(arm64_idle_init);
--
1.9.1
^ permalink raw reply related
* [PATCH v6 4/7] arm64: add PSCI CPU_SUSPEND based cpu_suspend support
From: Lorenzo Pieralisi @ 2014-07-21 16:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1405958786-17243-1-git-send-email-lorenzo.pieralisi@arm.com>
This patch implements the cpu_suspend cpu operations method through
the PSCI CPU SUSPEND API. The PSCI implementation translates the idle state
index passed by the cpu_suspend core call into a valid PSCI state according to
the PSCI states initialized at boot through the cpu_init_idle() CPU
operations hook.
Entry point is set to cpu_resume physical address, that represents the
default kernel execution address following a CPU reset; for standby
states the entry point address is useless and will therefore be ignored
by the PSCI implementation.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
---
arch/arm64/kernel/psci.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 89 insertions(+)
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index a623c44..bbdf41d 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -21,6 +21,7 @@
#include <linux/reboot.h>
#include <linux/pm.h>
#include <linux/delay.h>
+#include <linux/slab.h>
#include <uapi/linux/psci.h>
#include <asm/compiler.h>
@@ -28,6 +29,7 @@
#include <asm/errno.h>
#include <asm/psci.h>
#include <asm/smp_plat.h>
+#include <asm/suspend.h>
#include <asm/system_misc.h>
#define PSCI_POWER_STATE_TYPE_STANDBY 0
@@ -65,6 +67,8 @@ enum psci_function {
PSCI_FN_MAX,
};
+static DEFINE_PER_CPU_READ_MOSTLY(struct psci_power_state *, psci_power_state);
+
static u32 psci_function_id[PSCI_FN_MAX];
static int psci_to_linux_errno(int errno)
@@ -93,6 +97,18 @@ static u32 psci_power_state_pack(struct psci_power_state state)
& PSCI_0_2_POWER_STATE_AFFL_MASK);
}
+static void psci_power_state_unpack(u32 power_state,
+ struct psci_power_state *state)
+{
+ state->id = (power_state & PSCI_0_2_POWER_STATE_ID_MASK) >>
+ PSCI_0_2_POWER_STATE_ID_SHIFT;
+ state->type = (power_state & PSCI_0_2_POWER_STATE_TYPE_MASK) >>
+ PSCI_0_2_POWER_STATE_TYPE_SHIFT;
+ state->affinity_level =
+ (power_state & PSCI_0_2_POWER_STATE_AFFL_MASK) >>
+ PSCI_0_2_POWER_STATE_AFFL_SHIFT;
+}
+
/*
* The following two functions are invoked via the invoke_psci_fn pointer
* and will not be inlined, allowing us to piggyback on the AAPCS.
@@ -199,6 +215,61 @@ static int psci_migrate_info_type(void)
return err;
}
+static int cpu_psci_cpu_init_idle(struct device_node *cpu_node,
+ unsigned int cpu)
+{
+ int i, ret, count = 0;
+ struct psci_power_state *psci_states;
+ struct device_node *state_node;
+
+ /*
+ * If the PSCI cpu_suspend function hook has not been initialized
+ * idle states must not be enabled, so bail out
+ */
+ if (!psci_ops.cpu_suspend)
+ return -EOPNOTSUPP;
+
+ /* Count idle states */
+ while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states",
+ count)))
+ count++;
+
+ if (!count)
+ return -ENODEV;
+
+ psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
+ if (!psci_states) {
+ pr_warn("idle state psci_state allocation failed\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < count; i++) {
+ u32 psci_power_state;
+
+ state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
+
+ ret = of_property_read_u32(state_node,
+ "arm,psci-suspend-param",
+ &psci_power_state);
+ if (ret) {
+ pr_warn(" * %s missing arm,psci-suspend-param property\n",
+ state_node->full_name);
+ goto free_mem;
+ }
+
+ pr_debug("psci-power-state %#x index %d\n", psci_power_state,
+ i);
+ psci_power_state_unpack(psci_power_state, &psci_states[i]);
+ }
+ /* Idle states parsed correctly, initialize per-cpu pointer */
+ per_cpu(psci_power_state, cpu) = psci_states;
+ return 0;
+
+free_mem:
+ kfree(psci_states);
+ return ret;
+}
+
static int get_set_conduit_method(struct device_node *np)
{
const char *method;
@@ -436,8 +507,23 @@ static int cpu_psci_cpu_kill(unsigned int cpu)
#endif
#endif
+static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index)
+{
+ struct psci_power_state *state = __get_cpu_var(psci_power_state);
+ /*
+ * idle state index 0 corresponds to wfi, should never be called
+ * from the cpu_suspend operations
+ */
+ if (WARN_ON_ONCE(!index))
+ return -EINVAL;
+
+ return psci_ops.cpu_suspend(state[index - 1],
+ virt_to_phys(cpu_resume));
+}
+
const struct cpu_operations cpu_psci_ops = {
.name = "psci",
+ .cpu_init_idle = cpu_psci_cpu_init_idle,
#ifdef CONFIG_SMP
.cpu_init = cpu_psci_cpu_init,
.cpu_prepare = cpu_psci_cpu_prepare,
@@ -448,5 +534,8 @@ const struct cpu_operations cpu_psci_ops = {
.cpu_kill = cpu_psci_cpu_kill,
#endif
#endif
+#ifdef CONFIG_ARM64_CPU_SUSPEND
+ .cpu_suspend = cpu_psci_cpu_suspend,
+#endif
};
--
1.9.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox