* [PATCH v2 1/3] powerpc/fsl_soc.c: remove FSL USB platform code
From: Anatolij Gustschin @ 2010-09-28 9:36 UTC (permalink / raw)
To: linux-usb
Cc: David Brownell, Wolfgang Denk, Detlev Zundel, Greg Kroah-Hartman,
linuxppc-dev, Anatolij Gustschin
In-Reply-To: <1285666594-21150-1-git-send-email-agust@denx.de>
This removed code will be replaced by simple of_platform
driver for creation of FSL USB platform devices which is
added by next patch of the series.
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Kumar Gala <galak@kernel.crashing.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
arch/powerpc/sysdev/fsl_soc.c | 163 -----------------------------------------
1 files changed, 0 insertions(+), 163 deletions(-)
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index b91f7ac..49a51f1 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -209,169 +209,6 @@ static int __init of_add_fixed_phys(void)
arch_initcall(of_add_fixed_phys);
#endif /* CONFIG_FIXED_PHY */
-static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
-{
- if (!phy_type)
- return FSL_USB2_PHY_NONE;
- if (!strcasecmp(phy_type, "ulpi"))
- return FSL_USB2_PHY_ULPI;
- if (!strcasecmp(phy_type, "utmi"))
- return FSL_USB2_PHY_UTMI;
- if (!strcasecmp(phy_type, "utmi_wide"))
- return FSL_USB2_PHY_UTMI_WIDE;
- if (!strcasecmp(phy_type, "serial"))
- return FSL_USB2_PHY_SERIAL;
-
- return FSL_USB2_PHY_NONE;
-}
-
-static int __init fsl_usb_of_init(void)
-{
- struct device_node *np;
- unsigned int i = 0;
- struct platform_device *usb_dev_mph = NULL, *usb_dev_dr_host = NULL,
- *usb_dev_dr_client = NULL;
- int ret;
-
- for_each_compatible_node(np, NULL, "fsl-usb2-mph") {
- struct resource r[2];
- struct fsl_usb2_platform_data usb_data;
- const unsigned char *prop = NULL;
-
- memset(&r, 0, sizeof(r));
- memset(&usb_data, 0, sizeof(usb_data));
-
- ret = of_address_to_resource(np, 0, &r[0]);
- if (ret)
- goto err;
-
- of_irq_to_resource(np, 0, &r[1]);
-
- usb_dev_mph =
- platform_device_register_simple("fsl-ehci", i, r, 2);
- if (IS_ERR(usb_dev_mph)) {
- ret = PTR_ERR(usb_dev_mph);
- goto err;
- }
-
- usb_dev_mph->dev.coherent_dma_mask = 0xffffffffUL;
- usb_dev_mph->dev.dma_mask = &usb_dev_mph->dev.coherent_dma_mask;
-
- usb_data.operating_mode = FSL_USB2_MPH_HOST;
-
- prop = of_get_property(np, "port0", NULL);
- if (prop)
- usb_data.port_enables |= FSL_USB2_PORT0_ENABLED;
-
- prop = of_get_property(np, "port1", NULL);
- if (prop)
- usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
-
- prop = of_get_property(np, "phy_type", NULL);
- usb_data.phy_mode = determine_usb_phy(prop);
-
- ret =
- platform_device_add_data(usb_dev_mph, &usb_data,
- sizeof(struct
- fsl_usb2_platform_data));
- if (ret)
- goto unreg_mph;
- i++;
- }
-
- for_each_compatible_node(np, NULL, "fsl-usb2-dr") {
- struct resource r[2];
- struct fsl_usb2_platform_data usb_data;
- const unsigned char *prop = NULL;
-
- if (!of_device_is_available(np))
- continue;
-
- memset(&r, 0, sizeof(r));
- memset(&usb_data, 0, sizeof(usb_data));
-
- ret = of_address_to_resource(np, 0, &r[0]);
- if (ret)
- goto unreg_mph;
-
- of_irq_to_resource(np, 0, &r[1]);
-
- prop = of_get_property(np, "dr_mode", NULL);
-
- if (!prop || !strcmp(prop, "host")) {
- usb_data.operating_mode = FSL_USB2_DR_HOST;
- usb_dev_dr_host = platform_device_register_simple(
- "fsl-ehci", i, r, 2);
- if (IS_ERR(usb_dev_dr_host)) {
- ret = PTR_ERR(usb_dev_dr_host);
- goto err;
- }
- } else if (prop && !strcmp(prop, "peripheral")) {
- usb_data.operating_mode = FSL_USB2_DR_DEVICE;
- usb_dev_dr_client = platform_device_register_simple(
- "fsl-usb2-udc", i, r, 2);
- if (IS_ERR(usb_dev_dr_client)) {
- ret = PTR_ERR(usb_dev_dr_client);
- goto err;
- }
- } else if (prop && !strcmp(prop, "otg")) {
- usb_data.operating_mode = FSL_USB2_DR_OTG;
- usb_dev_dr_host = platform_device_register_simple(
- "fsl-ehci", i, r, 2);
- if (IS_ERR(usb_dev_dr_host)) {
- ret = PTR_ERR(usb_dev_dr_host);
- goto err;
- }
- usb_dev_dr_client = platform_device_register_simple(
- "fsl-usb2-udc", i, r, 2);
- if (IS_ERR(usb_dev_dr_client)) {
- ret = PTR_ERR(usb_dev_dr_client);
- goto err;
- }
- } else {
- ret = -EINVAL;
- goto err;
- }
-
- prop = of_get_property(np, "phy_type", NULL);
- usb_data.phy_mode = determine_usb_phy(prop);
-
- if (usb_dev_dr_host) {
- usb_dev_dr_host->dev.coherent_dma_mask = 0xffffffffUL;
- usb_dev_dr_host->dev.dma_mask = &usb_dev_dr_host->
- dev.coherent_dma_mask;
- if ((ret = platform_device_add_data(usb_dev_dr_host,
- &usb_data, sizeof(struct
- fsl_usb2_platform_data))))
- goto unreg_dr;
- }
- if (usb_dev_dr_client) {
- usb_dev_dr_client->dev.coherent_dma_mask = 0xffffffffUL;
- usb_dev_dr_client->dev.dma_mask = &usb_dev_dr_client->
- dev.coherent_dma_mask;
- if ((ret = platform_device_add_data(usb_dev_dr_client,
- &usb_data, sizeof(struct
- fsl_usb2_platform_data))))
- goto unreg_dr;
- }
- i++;
- }
- return 0;
-
-unreg_dr:
- if (usb_dev_dr_host)
- platform_device_unregister(usb_dev_dr_host);
- if (usb_dev_dr_client)
- platform_device_unregister(usb_dev_dr_client);
-unreg_mph:
- if (usb_dev_mph)
- platform_device_unregister(usb_dev_mph);
-err:
- return ret;
-}
-
-arch_initcall(fsl_usb_of_init);
-
#if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
static __be32 __iomem *rstcr;
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 0/3] Add USB Host support for MPC5121 SoC
From: Anatolij Gustschin @ 2010-09-28 9:36 UTC (permalink / raw)
To: linux-usb
Cc: David Brownell, Wolfgang Denk, Detlev Zundel, Greg Kroah-Hartman,
linuxppc-dev, Anatolij Gustschin
This is version 2 of patches to add MPC512x USB support in
mainline kernel. USB OTG support is not included in this
patch series, it will be submitted later.
The patches have been rebased on current linux-next tree
and reworked to address comments from Grant.
Anatolij Gustschin (3):
powerpc/fsl_soc.c: remove FSL USB platform code
USB: add of_platform glue driver for FSL USB DR controller
USB: add USB EHCI support for MPC5121 SoC
Documentation/powerpc/dts-bindings/fsl/usb.txt | 22 ++
arch/powerpc/sysdev/fsl_soc.c | 163 -------------
drivers/usb/Kconfig | 1 +
drivers/usb/gadget/Kconfig | 1 +
drivers/usb/host/Kconfig | 10 +-
drivers/usb/host/Makefile | 1 +
drivers/usb/host/ehci-fsl.c | 99 ++++++---
drivers/usb/host/ehci-fsl.h | 13 +-
drivers/usb/host/ehci-mem.c | 2 +-
drivers/usb/host/fsl-mph-dr-of.c | 302 ++++++++++++++++++++++++
include/linux/fsl_devices.h | 15 ++
11 files changed, 434 insertions(+), 195 deletions(-)
create mode 100644 drivers/usb/host/fsl-mph-dr-of.c
^ permalink raw reply
* Re: [PATCH 6/8] v2 Update node sysfs code
From: Robin Holt @ 2010-09-28 9:29 UTC (permalink / raw)
To: Nathan Fontenot
Cc: linuxppc-dev, Greg KH, linux-kernel, Dave Hansen, linux-mm,
KAMEZAWA Hiroyuki
In-Reply-To: <4CA0F00D.9000702@austin.ibm.com>
This patch may work, but it appears it is lacking in, at least the
link_mem_sections() function. Assuming you have a memory block covering
2GB and a section size of 128MB (some values we are toying with for
large SGI machines), you end up calling register_mem_sect_under_node()
16 times which then takes the same steps.
I think you also need:
Index: linux-2.6.32/drivers/base/node.c
===================================================================
--- linux-2.6.32.orig/drivers/base/node.c 2010-09-28 04:18:53.848448349 -0500
+++ linux-2.6.32/drivers/base/node.c 2010-09-28 04:21:35.169446261 -0500
@@ -342,6 +342,7 @@
if (!err)
err = ret;
+ pfn = section_nr_to_pfn(mem_blk->end_phys_index);
/* discard ref obtained in find_memory_block() */
kobject_put(&mem_blk->sysdev.kobj);
}
Also, I don't think I much care for the weirdness that occurs if a
memory block spans two nodes. I have not thought through how possible
(or likely) this is, but the code certainly permits it. If that were
the case, how would we know which sections need to be taken offline, etc?
I wonder how much this will muddy up the information available in sysfs.
Thanks,
Robin
On Mon, Sep 27, 2010 at 02:27:09PM -0500, Nathan Fontenot wrote:
> Update the node sysfs code to be aware of the new capability for a memory
> block to contain multiple memory sections. This requires an additional
> parameter to unregister_mem_sect_under_nodes so that we know which memory
> section of the memory block to unregister.
>
> Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
>
> ---
> drivers/base/memory.c | 2 +-
> drivers/base/node.c | 12 ++++++++----
> include/linux/node.h | 6 ++++--
> 3 files changed, 13 insertions(+), 7 deletions(-)
>
> Index: linux-next/drivers/base/node.c
> ===================================================================
> --- linux-next.orig/drivers/base/node.c 2010-09-27 13:49:36.000000000 -0500
> +++ linux-next/drivers/base/node.c 2010-09-27 13:50:43.000000000 -0500
> @@ -346,8 +346,10 @@
> return -EFAULT;
> if (!node_online(nid))
> return 0;
> - sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
> - sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
> +
> + sect_start_pfn = section_nr_to_pfn(mem_blk->start_phys_index);
> + sect_end_pfn = section_nr_to_pfn(mem_blk->end_phys_index);
> + sect_end_pfn += PAGES_PER_SECTION - 1;
> for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
> int page_nid;
>
> @@ -371,7 +373,8 @@
> }
>
> /* unregister memory section under all nodes that it spans */
> -int unregister_mem_sect_under_nodes(struct memory_block *mem_blk)
> +int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
> + unsigned long phys_index)
> {
> NODEMASK_ALLOC(nodemask_t, unlinked_nodes, GFP_KERNEL);
> unsigned long pfn, sect_start_pfn, sect_end_pfn;
> @@ -383,7 +386,8 @@
> if (!unlinked_nodes)
> return -ENOMEM;
> nodes_clear(*unlinked_nodes);
> - sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
> +
> + sect_start_pfn = section_nr_to_pfn(phys_index);
> sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
> for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
> int nid;
> Index: linux-next/drivers/base/memory.c
> ===================================================================
> --- linux-next.orig/drivers/base/memory.c 2010-09-27 13:50:38.000000000 -0500
> +++ linux-next/drivers/base/memory.c 2010-09-27 13:50:43.000000000 -0500
> @@ -587,9 +587,9 @@
>
> mutex_lock(&mem_sysfs_mutex);
> mem = find_memory_block(section);
> + unregister_mem_sect_under_nodes(mem, __section_nr(section));
>
> if (atomic_dec_and_test(&mem->section_count)) {
> - unregister_mem_sect_under_nodes(mem);
> mem_remove_simple_file(mem, phys_index);
> mem_remove_simple_file(mem, end_phys_index);
> mem_remove_simple_file(mem, state);
> Index: linux-next/include/linux/node.h
> ===================================================================
> --- linux-next.orig/include/linux/node.h 2010-09-27 13:49:36.000000000 -0500
> +++ linux-next/include/linux/node.h 2010-09-27 13:50:43.000000000 -0500
> @@ -44,7 +44,8 @@
> extern int unregister_cpu_under_node(unsigned int cpu, unsigned int nid);
> extern int register_mem_sect_under_node(struct memory_block *mem_blk,
> int nid);
> -extern int unregister_mem_sect_under_nodes(struct memory_block *mem_blk);
> +extern int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
> + unsigned long phys_index);
>
> #ifdef CONFIG_HUGETLBFS
> extern void register_hugetlbfs_with_node(node_registration_func_t doregister,
> @@ -72,7 +73,8 @@
> {
> return 0;
> }
> -static inline int unregister_mem_sect_under_nodes(struct memory_block *mem_blk)
> +static inline int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
> + unsigned long phys_index)
> {
> return 0;
> }
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
^ permalink raw reply
* Re: [PATCH RFCv2 1/2] dmaengine: add support for scatterlist to scatterlist transfers
From: Per Förlin @ 2010-09-28 7:13 UTC (permalink / raw)
To: Ira W. Snyder
Cc: Linus Walleij, Dan Williams, linuxppc-dev@lists.ozlabs.org,
linux-kernel@vger.kernel.org
In-Reply-To: <20100927172356.GA805@ovro.caltech.edu>
> On Mon, Sep 27, 2010 at 05:23:34PM +0200, Linus Walleij wrote:
>> 2010/9/25 Ira W. Snyder <iws@ovro.caltech.edu>:
>>
>>> This adds support for scatterlist to scatterlist DMA transfers.
>>
>> This is a good idea, we have a local function to do this in DMA40 already,
>> stedma40_memcpy_sg().
>>
>
> I think that having two devices that want to implement this
> functionality as part of the DMAEngine API is a good argument for making
> it available as part of the core API. I think it would be good to add
> this to struct dma_device, and add a capability (DMA_SG?) for it as
> well.
>
> I have looked at the stedma40_memcpy_sg() function, and I think we would
> want to extend it slightly for the generic API. Is there any good reason
> to prohibit scatterlists with different numbers of elements?
No
/Per
^ permalink raw reply
* Re: [PATCH v6 0/8] ptp: IEEE 1588 hardware clock support
From: Richard Cochran @ 2010-09-28 6:47 UTC (permalink / raw)
To: Alan Cox
Cc: John Stultz, Rodolfo Giometti, Arnd Bergmann, Peter Zijlstra,
linux-api, devicetree-discuss, linux-kernel, Thomas Gleixner,
netdev, Christoph Lameter, linuxppc-dev, David Miller,
linux-arm-kernel, Krzysztof Halasa
In-Reply-To: <20100927180558.52817d5f@lxorguk.ukuu.org.uk>
On Mon, Sep 27, 2010 at 06:05:58PM +0100, Alan Cox wrote:
> On Mon, 27 Sep 2010 10:56:09 -0500 (CDT)
> Christoph Lameter <cl@linux.com> wrote:
>
> >
> > On Fri, 24 Sep 2010, Alan Cox wrote:
> >
> > > Whether you add new syscalls or do the fd passing using flags and hide
> > > the ugly bits in glibc is another question.
> >
> > Use device specific ioctls instead of syscalls?
>
> Some of the ioctls are probably not device specific, the job of the OS in
> part is to present a unified interface. We already have a mess of HPET
> and RTC driver ioctls.
Yes, and the whole point of introducing a PTP hardare clock API was to
avoid each new clock driver introducing yet another ioctl interface.
I had proposed a standard ioctl interface for PTP hardware clocks, but
that interface was rightly criticized for duplicating the posix clock
API. It does not make sense to have multiple interfaces with the exact
same functionality.
It is impossible to support every last feature of every possible
hardware clock with a generic interface, so there will always need to
be special ioctls for such features.
However, some clock functions *are* completely generic and apply to
every clock:
- set time
- get time
- adjust the frequency by N ppb
- shift the time by a given offset
The first two are provided by the posix clock interface, the third by
the NTP adjtimex call, which also can support (by a single mode
extension) the last item.
Richard
^ permalink raw reply
* Re: [PATCH v6 0/8] ptp: IEEE 1588 hardware clock support
From: Richard Cochran @ 2010-09-28 6:34 UTC (permalink / raw)
To: M. Warner Losh
Cc: peterz, johnstul, devicetree-discuss, linuxppc-dev, linux-kernel,
netdev, tglx, linux-api, cl, giometti, davem, linux-arm-kernel,
khc
In-Reply-To: <20100927.101423.702773873740300798.imp@bsdimp.com>
On Mon, Sep 27, 2010 at 10:14:23AM -0600, M. Warner Losh wrote:
>
> This is a common error that I've seen repeated in this thread. The
> only reason that it has historically been important is because when
> you are doing timestamping in software based on an interrupt, that
> stuff does matter.
Yes, thanks for your helpful explanation.
To further illustrate how small the effect of running the servo in
user space is, consider the following.
It is true that delays and jitter in the time to process the received
packet negatively affect the clock servo loop. However, the effect in
our case will be quite small.
John Eidson's book [1] presents a rigorous servo model that includes
an analysis of the delay from the time the samples (timestamps) are
taken until the corrective action is performed by the PTP software.
For PTP, the sample time is at the sender (the remote host, the master
clock). The master sends *two* packets, where the second one (the so
called follow-up packet) contains the hardware time stamp of the first
one. So, the computational delay includes the time spent by the sender
in its PTP stack preparing the second packet, the time the packet
spends in transit, and the time in the receiver's PTP stack and servo.
According to Eidson's analysis, a delay of up to 10 milliseconds would
be acceptable, even with a sample rate of 10 Hz. Therefore, saving a
few dozen microseconds by placing the servo (and PTP stack) into the
kernel is not worth the effort.
Richard
[1] title = {Measurement, control, and communication using IEEE 1588},
author = {J. C. Eidson},
year = 2006,
publisher = {Springer-Verlag},
^ permalink raw reply
* [PATCH 2/3 RESEND] powerpc: remove cast from void*
From: matt mooney @ 2010-09-28 2:04 UTC (permalink / raw)
To: Jiri Kosina; +Cc: kernel-janitors, Paul Mackerras, linuxppc-dev
In-Reply-To: <cover.1285638395.git.mfm@muteddisk.com>
Unnecessary cast from void* in assignment.
Signed-off-by: matt mooney <mfm@muteddisk.com>
---
arch/powerpc/platforms/pseries/hvCall_inst.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c
index e19ff02..f106662 100644
--- a/arch/powerpc/platforms/pseries/hvCall_inst.c
+++ b/arch/powerpc/platforms/pseries/hvCall_inst.c
@@ -55,7 +55,7 @@ static void hc_stop(struct seq_file *m, void *p)
static int hc_show(struct seq_file *m, void *p)
{
unsigned long h_num = (unsigned long)p;
- struct hcall_stats *hs = (struct hcall_stats *)m->private;
+ struct hcall_stats *hs = m->private;
if (hs[h_num].num_calls) {
if (cpu_has_feature(CPU_FTR_PURR))
--
1.7.2.1
^ permalink raw reply related
* Re: Oops in trace_hardirqs_on (powerpc)
From: Steven Rostedt @ 2010-09-28 1:58 UTC (permalink / raw)
To: Jörg Sommer
Cc: Frederic Weisbecker, Ingo Molnar, linux-kernel, linuxppc-dev
In-Reply-To: <20100927125037.GA4497@alea.gnuu.de>
On Mon, 2010-09-27 at 14:50 +0200, Jörg Sommer wrote:
> Hello Steven,
>
> Steven Rostedt hat am Wed 22. Sep, 15:44 (-0400) geschrieben:
> > Sorry for the late reply, but I was on vacation when you sent this, and
> > I missed it while going through email.
> >
> > Do you still have this issue?
>
> No. I've rebuild my kernel without TRACE_IRQFLAGS and the problem
> vanished, as expected. The problem is, that in some cases the stack is
> only two frames deep, which causes the macro CALLER_ADDR1 makes an
> invalid access. Someone told me, there a workaround for the problem on
> i386, too.
>
> % sed -n 2p arch/x86/lib/thunk_32.S
> * Trampoline to trace irqs off. (otherwise CALLER_ADDR1 might crash)
Yes, I remember that problem. When I get back from Tokyo, I'll tried to
remember to fix it.
Thanks!
-- Steve
^ permalink raw reply
* Re: [PATCH 4/8] v2 Allow memory block to span multiple memory sections
From: Dave Hansen @ 2010-09-27 23:55 UTC (permalink / raw)
To: Nathan Fontenot
Cc: linux-mm, Greg KH, linux-kernel, KAMEZAWA Hiroyuki, linuxppc-dev
In-Reply-To: <4CA0EFAA.8050000@austin.ibm.com>
On Mon, 2010-09-27 at 14:25 -0500, Nathan Fontenot wrote:
> +static inline int base_memory_block_id(int section_nr)
> +{
> + return section_nr / sections_per_block;
> +}
...
> - mutex_lock(&mem_sysfs_mutex);
> -
> - mem->phys_index = __section_nr(section);
> + scn_nr = __section_nr(section);
> + mem->phys_index = base_memory_block_id(scn_nr) * sections_per_block;
I'm really regretting giving this variable such a horrid name. I suck.
I think this is correct now:
mem->phys_index = base_memory_block_id(scn_nr) * sections_per_block;
mem->phys_index = section_nr / sections_per_block * sections_per_block;
mem->phys_index = section_nr
Since it gets exported to userspace this way:
> +static ssize_t show_mem_start_phys_index(struct sys_device *dev,
> struct sysdev_attribute *attr, char *buf)
> {
> struct memory_block *mem =
> container_of(dev, struct memory_block, sysdev);
> - return sprintf(buf, "%08lx\n", mem->phys_index / sections_per_block);
> + unsigned long phys_index;
> +
> + phys_index = mem->start_phys_index / sections_per_block;
> + return sprintf(buf, "%08lx\n", phys_index);
> +}
The only other thing I'd say is that we need to put phys_index out of
its misery and call it what it is now: a section number. I think it's
OK to call them "start/end_section_nr", at least inside the kernel. I
intentionally used "phys_index" terminology in sysfs so that we _could_
eventually do this stuff and break the relationship between sections and
the sysfs dirs, but I think keeping the terminology around inside the
kernel is confusing now.
-- Dave
^ permalink raw reply
* [RFC PATCH 0/2] Fix IRQ round-robing w/o irqbalance on pseries
From: Nishanth Aravamudan @ 2010-09-27 23:17 UTC (permalink / raw)
To: nacc; +Cc: linuxppc-dev, linux-kernel, miltonm
We have received reports on power systems not running irqbalance where
all interrupts are being routed to CPU0 rather than being interleaved by
default across the system. Current firmware only allows either sending
interrupts to all CPUs or sending them to one CPU. The following two
patches address this issue by fixing the mask used in generic code and
by fixing the check for the "all" setting in the pseries code.
Nishanth Aravamudan (2):
IRQ: use cpu_possible_mask rather than online_mask in setup_affinity
pseries/xics: use cpu_possible_mask rather than cpu_all_mask
arch/powerpc/platforms/pseries/xics.c | 2 +-
kernel/irq/manage.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
Cc: linuxppc-dev@lists.ozlabs.org
Cc: linux-kernel@vger.kernel.org
^ permalink raw reply
* [RFC PATCH 2/2] pseries/xics: use cpu_possible_mask rather than cpu_all_mask
From: Nishanth Aravamudan @ 2010-09-27 23:17 UTC (permalink / raw)
To: nacc
Cc: Mark Nelson, linux-kernel, miltonm, Paul Mackerras,
Anton Blanchard, Thomas Gleixner, linuxppc-dev
In-Reply-To: <1285629463-27699-1-git-send-email-nacc@us.ibm.com>
Current firmware only allows us to send IRQs to the first processor or
all processors. We currently check to see if the passed in mask is equal
to the all_mask, but the firmware is only considering whether the
request is for the equivalent of the possible_mask. Thus, we think the
request is for some subset of CPUs and only assign IRQs to the first CPU
(on systems without irqbalance running) as evidenced by
/proc/interrupts. By using possible_mask instead, we account for this
and proper interleaving of interrupts occurs. Without this change and
"pseries/xics: use cpu_possible_mask rather than cpu_all_mask", IRQs are
all routed to CPU0 on power machines not running irqbalance.
Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
---
arch/powerpc/platforms/pseries/xics.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index 93834b0..7c1e342 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -178,7 +178,7 @@ static int get_irq_server(unsigned int virq, const struct cpumask *cpumask,
if (!distribute_irqs)
return default_server;
- if (!cpumask_equal(cpumask, cpu_all_mask)) {
+ if (!cpumask_subset(cpu_possible_mask, cpumask)) {
int server = cpumask_first_and(cpu_online_mask, cpumask);
if (server < nr_cpu_ids)
--
1.7.0.4
^ permalink raw reply related
* [PATCH 3/4] fsldma: remove DMA_SLAVE support
From: Ira W. Snyder @ 2010-09-27 22:57 UTC (permalink / raw)
To: linux-kernel; +Cc: Dan Williams, linuxppc-dev
In-Reply-To: <1285628277-26894-1-git-send-email-iws@ovro.caltech.edu>
Now that the generic DMAEngine API has support for scatterlist to
scatterlist copying, this implementation of the DMA_SLAVE API is no
longer necessary.
In order to let device_control() continue to function, a stub
device_prep_slave_sg() function is provided. This allows custom device
configuration, such as enabling external control.
Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
arch/powerpc/include/asm/fsldma.h | 115 ++------------------
drivers/dma/fsldma.c | 219 +++++++------------------------------
2 files changed, 48 insertions(+), 286 deletions(-)
diff --git a/arch/powerpc/include/asm/fsldma.h b/arch/powerpc/include/asm/fsldma.h
index debc5ed..dc0bd27 100644
--- a/arch/powerpc/include/asm/fsldma.h
+++ b/arch/powerpc/include/asm/fsldma.h
@@ -1,7 +1,7 @@
/*
* Freescale MPC83XX / MPC85XX DMA Controller
*
- * Copyright (c) 2009 Ira W. Snyder <iws@ovro.caltech.edu>
+ * Copyright (c) 2009-2010 Ira W. Snyder <iws@ovro.caltech.edu>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
@@ -11,127 +11,32 @@
#ifndef __ARCH_POWERPC_ASM_FSLDMA_H__
#define __ARCH_POWERPC_ASM_FSLDMA_H__
-#include <linux/slab.h>
#include <linux/dmaengine.h>
/*
- * Definitions for the Freescale DMA controller's DMA_SLAVE implemention
+ * The Freescale DMA controller has several features that are not accomodated
+ * in the Linux DMAEngine API. Therefore, the generic structure is expanded
+ * to allow drivers to use these features.
*
- * The Freescale DMA_SLAVE implementation was designed to handle many-to-many
- * transfers. An example usage would be an accelerated copy between two
- * scatterlists. Another example use would be an accelerated copy from
- * multiple non-contiguous device buffers into a single scatterlist.
+ * This structure should be passed into the DMAEngine routine device_control()
+ * as in this example:
*
- * A DMA_SLAVE transaction is defined by a struct fsl_dma_slave. This
- * structure contains a list of hardware addresses that should be copied
- * to/from the scatterlist passed into device_prep_slave_sg(). The structure
- * also has some fields to enable hardware-specific features.
+ * chan->device->device_control(chan, DMA_SLAVE_CONFIG, (unsigned long)cfg);
*/
/**
- * struct fsl_dma_hw_addr
- * @entry: linked list entry
- * @address: the hardware address
- * @length: length to transfer
- *
- * Holds a single physical hardware address / length pair for use
- * with the DMAEngine DMA_SLAVE API.
- */
-struct fsl_dma_hw_addr {
- struct list_head entry;
-
- dma_addr_t address;
- size_t length;
-};
-
-/**
* struct fsl_dma_slave
- * @addresses: a linked list of struct fsl_dma_hw_addr structures
+ * @config: the standard Linux DMAEngine API DMA_SLAVE configuration
* @request_count: value for DMA request count
- * @src_loop_size: setup and enable constant source-address DMA transfers
- * @dst_loop_size: setup and enable constant destination address DMA transfers
* @external_start: enable externally started DMA transfers
* @external_pause: enable externally paused DMA transfers
- *
- * Holds a list of address / length pairs for use with the DMAEngine
- * DMA_SLAVE API implementation for the Freescale DMA controller.
*/
-struct fsl_dma_slave {
+struct fsldma_slave_config {
+ struct dma_slave_config config;
- /* List of hardware address/length pairs */
- struct list_head addresses;
-
- /* Support for extra controller features */
unsigned int request_count;
- unsigned int src_loop_size;
- unsigned int dst_loop_size;
bool external_start;
bool external_pause;
};
-/**
- * fsl_dma_slave_append - add an address/length pair to a struct fsl_dma_slave
- * @slave: the &struct fsl_dma_slave to add to
- * @address: the hardware address to add
- * @length: the length of bytes to transfer from @address
- *
- * Add a hardware address/length pair to a struct fsl_dma_slave. Returns 0 on
- * success, -ERRNO otherwise.
- */
-static inline int fsl_dma_slave_append(struct fsl_dma_slave *slave,
- dma_addr_t address, size_t length)
-{
- struct fsl_dma_hw_addr *addr;
-
- addr = kzalloc(sizeof(*addr), GFP_ATOMIC);
- if (!addr)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&addr->entry);
- addr->address = address;
- addr->length = length;
-
- list_add_tail(&addr->entry, &slave->addresses);
- return 0;
-}
-
-/**
- * fsl_dma_slave_free - free a struct fsl_dma_slave
- * @slave: the struct fsl_dma_slave to free
- *
- * Free a struct fsl_dma_slave and all associated address/length pairs
- */
-static inline void fsl_dma_slave_free(struct fsl_dma_slave *slave)
-{
- struct fsl_dma_hw_addr *addr, *tmp;
-
- if (slave) {
- list_for_each_entry_safe(addr, tmp, &slave->addresses, entry) {
- list_del(&addr->entry);
- kfree(addr);
- }
-
- kfree(slave);
- }
-}
-
-/**
- * fsl_dma_slave_alloc - allocate a struct fsl_dma_slave
- * @gfp: the flags to pass to kmalloc when allocating this structure
- *
- * Allocate a struct fsl_dma_slave for use by the DMA_SLAVE API. Returns a new
- * struct fsl_dma_slave on success, or NULL on failure.
- */
-static inline struct fsl_dma_slave *fsl_dma_slave_alloc(gfp_t gfp)
-{
- struct fsl_dma_slave *slave;
-
- slave = kzalloc(sizeof(*slave), gfp);
- if (!slave)
- return NULL;
-
- INIT_LIST_HEAD(&slave->addresses);
- return slave;
-}
-
#endif /* __ARCH_POWERPC_ASM_FSLDMA_H__ */
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 1ed29d1..d3ce25b 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -719,207 +719,64 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
enum dma_data_direction direction, unsigned long flags)
{
- struct fsldma_chan *chan;
- struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL;
- struct fsl_dma_slave *slave;
- size_t copy;
-
- int i;
- struct scatterlist *sg;
- size_t sg_used;
- size_t hw_used;
- struct fsl_dma_hw_addr *hw;
- dma_addr_t dma_dst, dma_src;
-
- if (!dchan)
- return NULL;
-
- if (!dchan->private)
- return NULL;
-
- chan = to_fsl_chan(dchan);
- slave = dchan->private;
-
- if (list_empty(&slave->addresses))
- return NULL;
-
- hw = list_first_entry(&slave->addresses, struct fsl_dma_hw_addr, entry);
- hw_used = 0;
-
/*
- * Build the hardware transaction to copy from the scatterlist to
- * the hardware, or from the hardware to the scatterlist
- *
- * If you are copying from the hardware to the scatterlist and it
- * takes two hardware entries to fill an entire page, then both
- * hardware entries will be coalesced into the same page
+ * This operation is not supported on the Freescale DMA controller
*
- * If you are copying from the scatterlist to the hardware and a
- * single page can fill two hardware entries, then the data will
- * be read out of the page into the first hardware entry, and so on
+ * However, we need to provide the function pointer to allow the
+ * device_control() method to work.
*/
- for_each_sg(sgl, sg, sg_len, i) {
- sg_used = 0;
-
- /* Loop until the entire scatterlist entry is used */
- while (sg_used < sg_dma_len(sg)) {
-
- /*
- * If we've used up the current hardware address/length
- * pair, we need to load a new one
- *
- * This is done in a while loop so that descriptors with
- * length == 0 will be skipped
- */
- while (hw_used >= hw->length) {
-
- /*
- * If the current hardware entry is the last
- * entry in the list, we're finished
- */
- if (list_is_last(&hw->entry, &slave->addresses))
- goto finished;
-
- /* Get the next hardware address/length pair */
- hw = list_entry(hw->entry.next,
- struct fsl_dma_hw_addr, entry);
- hw_used = 0;
- }
-
- /* Allocate the link descriptor from DMA pool */
- new = fsl_dma_alloc_descriptor(chan);
- if (!new) {
- dev_err(chan->dev, "No free memory for "
- "link descriptor\n");
- goto fail;
- }
-#ifdef FSL_DMA_LD_DEBUG
- dev_dbg(chan->dev, "new link desc alloc %p\n", new);
-#endif
-
- /*
- * Calculate the maximum number of bytes to transfer,
- * making sure it is less than the DMA controller limit
- */
- copy = min_t(size_t, sg_dma_len(sg) - sg_used,
- hw->length - hw_used);
- copy = min_t(size_t, copy, FSL_DMA_BCR_MAX_CNT);
-
- /*
- * DMA_FROM_DEVICE
- * from the hardware to the scatterlist
- *
- * DMA_TO_DEVICE
- * from the scatterlist to the hardware
- */
- if (direction == DMA_FROM_DEVICE) {
- dma_src = hw->address + hw_used;
- dma_dst = sg_dma_address(sg) + sg_used;
- } else {
- dma_src = sg_dma_address(sg) + sg_used;
- dma_dst = hw->address + hw_used;
- }
-
- /* Fill in the descriptor */
- set_desc_cnt(chan, &new->hw, copy);
- set_desc_src(chan, &new->hw, dma_src);
- set_desc_dst(chan, &new->hw, dma_dst);
-
- /*
- * If this is not the first descriptor, chain the
- * current descriptor after the previous descriptor
- */
- if (!first) {
- first = new;
- } else {
- set_desc_next(chan, &prev->hw,
- new->async_tx.phys);
- }
-
- new->async_tx.cookie = 0;
- async_tx_ack(&new->async_tx);
-
- prev = new;
- sg_used += copy;
- hw_used += copy;
-
- /* Insert the link descriptor into the LD ring */
- list_add_tail(&new->node, &first->tx_list);
- }
- }
-
-finished:
-
- /* All of the hardware address/length pairs had length == 0 */
- if (!first || !new)
- return NULL;
-
- new->async_tx.flags = flags;
- new->async_tx.cookie = -EBUSY;
-
- /* Set End-of-link to the last link descriptor of new list */
- set_ld_eol(chan, new);
-
- /* Enable extra controller features */
- if (chan->set_src_loop_size)
- chan->set_src_loop_size(chan, slave->src_loop_size);
-
- if (chan->set_dst_loop_size)
- chan->set_dst_loop_size(chan, slave->dst_loop_size);
-
- if (chan->toggle_ext_start)
- chan->toggle_ext_start(chan, slave->external_start);
-
- if (chan->toggle_ext_pause)
- chan->toggle_ext_pause(chan, slave->external_pause);
-
- if (chan->set_request_count)
- chan->set_request_count(chan, slave->request_count);
-
- return &first->async_tx;
-
-fail:
- /* If first was not set, then we failed to allocate the very first
- * descriptor, and we're done */
- if (!first)
- return NULL;
-
- /*
- * First is set, so all of the descriptors we allocated have been added
- * to first->tx_list, INCLUDING "first" itself. Therefore we
- * must traverse the list backwards freeing each descriptor in turn
- *
- * We're re-using variables for the loop, oh well
- */
- fsldma_free_desc_list_reverse(chan, &first->tx_list);
return NULL;
}
static int fsl_dma_device_control(struct dma_chan *dchan,
enum dma_ctrl_cmd cmd, unsigned long arg)
{
+ struct fsldma_slave_config *cfg;
struct fsldma_chan *chan;
unsigned long flags;
- /* Only supports DMA_TERMINATE_ALL */
- if (cmd != DMA_TERMINATE_ALL)
- return -ENXIO;
-
if (!dchan)
return -EINVAL;
chan = to_fsl_chan(dchan);
- /* Halt the DMA engine */
- dma_halt(chan);
+ switch (cmd) {
+ case DMA_TERMINATE_ALL:
+ /* Halt the DMA engine */
+ dma_halt(chan);
- spin_lock_irqsave(&chan->desc_lock, flags);
+ spin_lock_irqsave(&chan->desc_lock, flags);
- /* Remove and free all of the descriptors in the LD queue */
- fsldma_free_desc_list(chan, &chan->ld_pending);
- fsldma_free_desc_list(chan, &chan->ld_running);
+ /* Remove and free all of the descriptors in the LD queue */
+ fsldma_free_desc_list(chan, &chan->ld_pending);
+ fsldma_free_desc_list(chan, &chan->ld_running);
- spin_unlock_irqrestore(&chan->desc_lock, flags);
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
+ return 0;
+
+ case DMA_SLAVE_CONFIG:
+
+ cfg = (struct fsldma_slave_config *)arg;
+ if (chan->set_request_count)
+ chan->set_request_count(chan, cfg->request_count);
+
+ if (chan->toggle_ext_start)
+ chan->toggle_ext_start(chan, cfg->external_start);
+
+ if (chan->toggle_ext_pause)
+ chan->toggle_ext_pause(chan, cfg->external_pause);
+
+ /*
+ * TODO: add other features
+ *
+ * I'm not sure how to use the members dma_slave_config to
+ * control the src/dst address hold features.
+ */
+ return 0;
+
+ default:
+ return -ENXIO;
+ }
return 0;
}
--
1.7.1
^ permalink raw reply related
* [PATCH 1/4] dma: add support for scatterlist to scatterlist copy
From: Ira W. Snyder @ 2010-09-27 22:57 UTC (permalink / raw)
To: linux-kernel; +Cc: Dan Williams, linuxppc-dev
In-Reply-To: <1285628277-26894-1-git-send-email-iws@ovro.caltech.edu>
This adds support for scatterlist to scatterlist DMA transfers. A
similar interface is exposed by the fsldma driver (through the DMA_SLAVE
API) and by the ste_dma40 driver (through an exported function).
This patch paves the way for making this type of copy operation a part
of the generic DMAEngine API. Futher patches will add support in
individual drivers.
Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
drivers/dma/dmaengine.c | 2 ++
include/linux/dmaengine.h | 6 ++++++
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 9d31d5e..db403b8 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -690,6 +690,8 @@ int dma_async_device_register(struct dma_device *device)
!device->device_prep_dma_memset);
BUG_ON(dma_has_cap(DMA_INTERRUPT, device->cap_mask) &&
!device->device_prep_dma_interrupt);
+ BUG_ON(dma_has_cap(DMA_SG, device->cap_mask) &&
+ !device->device_prep_dma_sg);
BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
!device->device_prep_slave_sg);
BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index c61d4ca..7c44620 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -64,6 +64,7 @@ enum dma_transaction_type {
DMA_PQ_VAL,
DMA_MEMSET,
DMA_INTERRUPT,
+ DMA_SG,
DMA_PRIVATE,
DMA_ASYNC_TX,
DMA_SLAVE,
@@ -473,6 +474,11 @@ struct dma_device {
unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)(
struct dma_chan *chan, unsigned long flags);
+ struct dma_async_tx_descriptor *(*device_prep_dma_sg)(
+ struct dma_chan *chan,
+ struct scatterlist *dst_sg, unsigned int dst_nents,
+ struct scatterlist *src_sg, unsigned int src_nents,
+ unsigned long flags);
struct dma_async_tx_descriptor *(*device_prep_slave_sg)(
struct dma_chan *chan, struct scatterlist *sgl,
--
1.7.1
^ permalink raw reply related
* [PATCH 4/4] ste_dma40: implement support for scatterlist to scatterlist copy
From: Ira W. Snyder @ 2010-09-27 22:57 UTC (permalink / raw)
To: linux-kernel; +Cc: Per Fridén, Linus Walleij, Dan Williams, linuxppc-dev
In-Reply-To: <1285628277-26894-1-git-send-email-iws@ovro.caltech.edu>
Now that the DMAEngine API has support for scatterlist to scatterlist
copy, implement support for the STE DMA40 DMA controller.
Cc: Linus Walleij <linus.ml.walleij@gmail.com>
Cc: Per Fridén <per.friden@stericsson.com>
Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
drivers/dma/ste_dma40.c | 17 +++++++++++++++++
1 files changed, 17 insertions(+), 0 deletions(-)
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 17e2600..cd48859 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -1857,6 +1857,18 @@ err:
return NULL;
}
+static struct dma_async_tx_descriptor *
+d40_prep_sg(struct dma_chan *chan,
+ struct scatterlist *dst_sg, unsigned int dst_nents,
+ struct scatterlist *src_sg, unsigned int src_nents,
+ unsigned long dma_flags)
+{
+ if (dst_nents != src_nents)
+ return -EINVAL;
+
+ return stedma40_memcpy_sg(chan, dst_sg, src_sg, dst_nents, dma_flags);
+}
+
static int d40_prep_slave_sg_log(struct d40_desc *d40d,
struct d40_chan *d40c,
struct scatterlist *sgl,
@@ -2281,6 +2293,7 @@ static int __init d40_dmaengine_init(struct d40_base *base,
base->dma_slave.device_alloc_chan_resources = d40_alloc_chan_resources;
base->dma_slave.device_free_chan_resources = d40_free_chan_resources;
base->dma_slave.device_prep_dma_memcpy = d40_prep_memcpy;
+ base->dma_slave.device_prep_dma_sg = d40_prep_sg;
base->dma_slave.device_prep_slave_sg = d40_prep_slave_sg;
base->dma_slave.device_tx_status = d40_tx_status;
base->dma_slave.device_issue_pending = d40_issue_pending;
@@ -2301,10 +2314,12 @@ static int __init d40_dmaengine_init(struct d40_base *base,
dma_cap_zero(base->dma_memcpy.cap_mask);
dma_cap_set(DMA_MEMCPY, base->dma_memcpy.cap_mask);
+ dma_cap_set(DMA_SG, base->dma_slave.cap_mask);
base->dma_memcpy.device_alloc_chan_resources = d40_alloc_chan_resources;
base->dma_memcpy.device_free_chan_resources = d40_free_chan_resources;
base->dma_memcpy.device_prep_dma_memcpy = d40_prep_memcpy;
+ base->dma_slave.device_prep_dma_sg = d40_prep_sg;
base->dma_memcpy.device_prep_slave_sg = d40_prep_slave_sg;
base->dma_memcpy.device_tx_status = d40_tx_status;
base->dma_memcpy.device_issue_pending = d40_issue_pending;
@@ -2331,10 +2346,12 @@ static int __init d40_dmaengine_init(struct d40_base *base,
dma_cap_zero(base->dma_both.cap_mask);
dma_cap_set(DMA_SLAVE, base->dma_both.cap_mask);
dma_cap_set(DMA_MEMCPY, base->dma_both.cap_mask);
+ dma_cap_set(DMA_SG, base->dma_slave.cap_mask);
base->dma_both.device_alloc_chan_resources = d40_alloc_chan_resources;
base->dma_both.device_free_chan_resources = d40_free_chan_resources;
base->dma_both.device_prep_dma_memcpy = d40_prep_memcpy;
+ base->dma_slave.device_prep_dma_sg = d40_prep_sg;
base->dma_both.device_prep_slave_sg = d40_prep_slave_sg;
base->dma_both.device_tx_status = d40_tx_status;
base->dma_both.device_issue_pending = d40_issue_pending;
--
1.7.1
^ permalink raw reply related
* [PATCH 2/4] fsldma: implement support for scatterlist to scatterlist copy
From: Ira W. Snyder @ 2010-09-27 22:57 UTC (permalink / raw)
To: linux-kernel; +Cc: Dan Williams, linuxppc-dev
In-Reply-To: <1285628277-26894-1-git-send-email-iws@ovro.caltech.edu>
Now that the DMAEngine API has support for scatterlist to scatterlist
copy, implement support for the Freescale DMA controller.
Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
drivers/dma/fsldma.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 125 insertions(+), 3 deletions(-)
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index cea08be..1ed29d1 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -38,6 +38,8 @@
#include <asm/fsldma.h>
#include "fsldma.h"
+static const char msg_ld_oom[] = "No free memory for link descriptor\n";
+
static void dma_init(struct fsldma_chan *chan)
{
/* Reset the channel */
@@ -499,7 +501,7 @@ fsl_dma_prep_interrupt(struct dma_chan *dchan, unsigned long flags)
new = fsl_dma_alloc_descriptor(chan);
if (!new) {
- dev_err(chan->dev, "No free memory for link descriptor\n");
+ dev_err(chan->dev, msg_ld_oom);
return NULL;
}
@@ -536,8 +538,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
/* Allocate the link descriptor from DMA pool */
new = fsl_dma_alloc_descriptor(chan);
if (!new) {
- dev_err(chan->dev,
- "No free memory for link descriptor\n");
+ dev_err(chan->dev, msg_ld_oom);
goto fail;
}
#ifdef FSL_DMA_LD_DEBUG
@@ -583,6 +584,125 @@ fail:
return NULL;
}
+static struct dma_async_tx_descriptor *fsl_dma_prep_sg(struct dma_chan *dchan,
+ struct scatterlist *dst_sg, unsigned int dst_nents,
+ struct scatterlist *src_sg, unsigned int src_nents,
+ unsigned long flags)
+{
+ struct fsl_desc_sw *first = NULL, *prev = NULL, *new = NULL;
+ struct fsldma_chan *chan = to_fsl_chan(dchan);
+ size_t dst_avail, src_avail;
+ dma_addr_t dst, src;
+ size_t len;
+
+ /* basic sanity checks */
+ if (dst_nents == 0 || src_nents == 0)
+ return NULL;
+
+ if (dst_sg == NULL || src_sg == NULL)
+ return NULL;
+
+ /*
+ * TODO: should we check that both scatterlists have the same
+ * TODO: number of bytes in total? Is that really an error?
+ */
+
+ /* get prepared for the loop */
+ dst_avail = sg_dma_len(dst_sg);
+ src_avail = sg_dma_len(src_sg);
+
+ /* run until we are out of scatterlist entries */
+ while (true) {
+
+ /* create the largest transaction possible */
+ len = min_t(size_t, src_avail, dst_avail);
+ len = min_t(size_t, len, FSL_DMA_BCR_MAX_CNT);
+ if (len == 0)
+ goto fetch;
+
+ dst = sg_dma_address(dst_sg) + sg_dma_len(dst_sg) - dst_avail;
+ src = sg_dma_address(src_sg) + sg_dma_len(src_sg) - src_avail;
+
+ /* allocate and populate the descriptor */
+ new = fsl_dma_alloc_descriptor(chan);
+ if (!new) {
+ dev_err(chan->dev, msg_ld_oom);
+ goto fail;
+ }
+#ifdef FSL_DMA_LD_DEBUG
+ dev_dbg(chan->dev, "new link desc alloc %p\n", new);
+#endif
+
+ set_desc_cnt(chan, &new->hw, len);
+ set_desc_src(chan, &new->hw, src);
+ set_desc_dst(chan, &new->hw, dst);
+
+ if (!first)
+ first = new;
+ else
+ set_desc_next(chan, &prev->hw, new->async_tx.phys);
+
+ new->async_tx.cookie = 0;
+ async_tx_ack(&new->async_tx);
+ prev = new;
+
+ /* Insert the link descriptor to the LD ring */
+ list_add_tail(&new->node, &first->tx_list);
+
+ /* update metadata */
+ dst_avail -= len;
+ src_avail -= len;
+
+fetch:
+ /* fetch the next dst scatterlist entry */
+ if (dst_avail == 0) {
+
+ /* no more entries: we're done */
+ if (dst_nents == 0)
+ break;
+
+ /* fetch the next entry: if there are no more: done */
+ dst_sg = sg_next(dst_sg);
+ if (dst_sg == NULL)
+ break;
+
+ dst_nents--;
+ dst_avail = sg_dma_len(dst_sg);
+ }
+
+ /* fetch the next src scatterlist entry */
+ if (src_avail == 0) {
+
+ /* no more entries: we're done */
+ if (src_nents == 0)
+ break;
+
+ /* fetch the next entry: if there are no more: done */
+ src_sg = sg_next(src_sg);
+ if (src_sg == NULL)
+ break;
+
+ src_nents--;
+ src_avail = sg_dma_len(src_sg);
+ }
+ }
+
+ new->async_tx.flags = flags; /* client is in control of this ack */
+ new->async_tx.cookie = -EBUSY;
+
+ /* Set End-of-link to the last link descriptor of new list */
+ set_ld_eol(chan, new);
+
+ return &first->async_tx;
+
+fail:
+ if (!first)
+ return NULL;
+
+ fsldma_free_desc_list_reverse(chan, &first->tx_list);
+ return NULL;
+}
+
/**
* fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
* @chan: DMA channel
@@ -1327,11 +1447,13 @@ static int __devinit fsldma_of_probe(struct platform_device *op,
dma_cap_set(DMA_MEMCPY, fdev->common.cap_mask);
dma_cap_set(DMA_INTERRUPT, fdev->common.cap_mask);
+ dma_cap_set(DMA_SG, fdev->common.cap_mask);
dma_cap_set(DMA_SLAVE, fdev->common.cap_mask);
fdev->common.device_alloc_chan_resources = fsl_dma_alloc_chan_resources;
fdev->common.device_free_chan_resources = fsl_dma_free_chan_resources;
fdev->common.device_prep_dma_interrupt = fsl_dma_prep_interrupt;
fdev->common.device_prep_dma_memcpy = fsl_dma_prep_memcpy;
+ fdev->common.device_prep_dma_sg = fsl_dma_prep_sg;
fdev->common.device_tx_status = fsl_tx_status;
fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending;
fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg;
--
1.7.1
^ permalink raw reply related
* [PATCH RFCv3 0/4] dma: add support for scatterlist to scatterlist copy
From: Ira W. Snyder @ 2010-09-27 22:57 UTC (permalink / raw)
To: linux-kernel; +Cc: Dan Williams, linuxppc-dev
This series adds support for scatterlist to scatterlist copies to the
generic DMAEngine API. Both the fsldma and ste_dma40 drivers currently
implement a similar API using different, non-generic methods. This series
converts both of them to the new, standardized API.
By doing this as part of the core DMAEngine API, the individual drivers
have control over how to chain their descriptors together. This is
different to the previous implementation, which called
device_prep_dma_memcpy() multiple times.
Neither implementation has been tested on real hardware. I attempted a
conversion of the ste_dma40 driver which should do the right thing, but the
authors should check and make sure.
Ira W. Snyder (4):
dma: add support for scatterlist to scatterlist copy
fsldma: implement support for scatterlist to scatterlist copy
fsldma: remove DMA_SLAVE support
ste_dma40: implement support for scatterlist to scatterlist copy
arch/powerpc/include/asm/fsldma.h | 115 ++------------
drivers/dma/dmaengine.c | 2 +
drivers/dma/fsldma.c | 321 +++++++++++++++++--------------------
drivers/dma/ste_dma40.c | 17 ++
include/linux/dmaengine.h | 6 +
5 files changed, 185 insertions(+), 276 deletions(-)
^ permalink raw reply
* [PATCH 1/2] v2 476: Set CCR2[DSTI] to prevent isync from flushing shadow TLB
From: Dave Kleikamp @ 2010-09-27 21:56 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list
In-Reply-To: <1285622128.17411.29.camel@shaggy-w500>
When the DSTI (Disable Shadow TLB Invalidate) bit is set in the CCR2
register, the isync command does not flush the shadow TLB (iTLB & dTLB).
However, since the shadow TLB does not contain context information, we
want the shadow TLB flushed in situations where we are switching context.
In those situations, we explicitly clear the DSTI bit before performing
isync, and set it again afterward. We also need to do the same when we
perform isync after explicitly flushing the TLB.
Signed-off-by: Dave Kleikamp <shaggy@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/reg_booke.h | 4 ++++
arch/powerpc/kernel/head_44x.S | 25 +++++++++++++++++++++++++
arch/powerpc/mm/tlb_nohash_low.S | 14 +++++++++++++-
arch/powerpc/platforms/44x/misc_44x.S | 26 ++++++++++++++++++++++++++
4 files changed, 68 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index 667a498..a7ecbfe 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -120,6 +120,7 @@
#define SPRN_TLB3CFG 0x2B3 /* TLB 3 Config Register */
#define SPRN_EPR 0x2BE /* External Proxy Register */
#define SPRN_CCR1 0x378 /* Core Configuration Register 1 */
+#define SPRN_CCR2_476 0x379 /* Core Configuration Register 2 (476)*/
#define SPRN_ZPR 0x3B0 /* Zone Protection Register (40x) */
#define SPRN_MAS7 0x3B0 /* MMU Assist Register 7 */
#define SPRN_MMUCR 0x3B2 /* MMU Control Register */
@@ -188,6 +189,9 @@
#define CCR1_DPC 0x00000100 /* Disable L1 I-Cache/D-Cache parity checking */
#define CCR1_TCS 0x00000080 /* Timer Clock Select */
+/* Bit definitions for CCR2. */
+#define CCR2_476_DSTI 0x08000000 /* Disable Shadow TLB Invalidate */
+
/* Bit definitions for the MCSR. */
#define MCSR_MCS 0x80000000 /* Machine Check Summary */
#define MCSR_IB 0x40000000 /* Instruction PLB Error */
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index 562305b..cd34afb 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -38,6 +38,7 @@
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>
#include <asm/synch.h>
+#include <asm/bug.h>
#include "head_booke.h"
@@ -703,8 +704,23 @@ _GLOBAL(set_context)
stw r4, 0x4(r5)
#endif
mtspr SPRN_PID,r3
+BEGIN_MMU_FTR_SECTION
+ b 1f
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
isync /* Force context change */
blr
+1:
+#ifdef CONFIG_PPC_47x
+ mfspr r10,SPRN_CCR2_476
+ rlwinm r11,r10,0,~CCR2_476_DSTI
+ mtspr SPRN_CCR2_476,r11
+ isync /* Force context change */
+ mtspr SPRN_CCR2_476,r10
+#else /* CONFIG_PPC_47x */
+2: trap
+ EMIT_BUG_ENTRY 2b,__FILE__,__LINE__,0;
+#endif /* CONFIG_PPC_47x */
+ blr
/*
* Init CPU state. This is called at boot time or for secondary CPUs
@@ -861,6 +877,15 @@ skpinv: addi r4,r4,1 /* Increment */
isync
#endif /* CONFIG_PPC_EARLY_DEBUG_44x */
+BEGIN_MMU_FTR_SECTION
+ mfspr r3,SPRN_CCR2_476
+ /* With CCR2(DSTI) set, isync does not invalidate the shadow TLB */
+ oris r3,r3,CCR2_476_DSTI@h
+ rlwinm r3,r3,0,~CCR2_476_DSTI
+ mtspr SPRN_CCR2_476,r3
+ isync
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
+
/* Establish the interrupt vector offsets */
SET_IVOR(0, CriticalInput);
SET_IVOR(1, MachineCheck);
diff --git a/arch/powerpc/mm/tlb_nohash_low.S b/arch/powerpc/mm/tlb_nohash_low.S
index b9d9fed..f28fb52 100644
--- a/arch/powerpc/mm/tlb_nohash_low.S
+++ b/arch/powerpc/mm/tlb_nohash_low.S
@@ -112,7 +112,11 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
clrrwi r4,r3,12 /* get an EPN for the hashing with V = 0 */
ori r4,r4,PPC47x_TLBE_SIZE
tlbwe r4,r7,0 /* write it */
+ mfspr r8,SPRN_CCR2_476
+ rlwinm r9,r8,0,~CCR2_476_DSTI
+ mtspr SPRN_CCR2_476,r9
isync
+ mtspr SPRN_CCR2_476,r8
wrtee r10
blr
#else /* CONFIG_PPC_47x */
@@ -180,7 +184,11 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
lwz r8,0(r10) /* Load boltmap entry */
addi r10,r10,4 /* Next word */
b 1b /* Then loop */
-1: isync /* Sync shadows */
+1: mfspr r9,SPRN_CCR2_476
+ rlwinm r10,r9,0,~CCR2_476_DSTI
+ mtspr SPRN_CCR2_476,r10
+ isync /* Sync shadows */
+ mtspr SPRN_CCR2_476,r9
wrtee r11
#else /* CONFIG_PPC_47x */
1: trap
@@ -203,7 +211,11 @@ _GLOBAL(_tlbivax_bcast)
isync
/* tlbivax 0,r3 - use .long to avoid binutils deps */
.long 0x7c000624 | (r3 << 11)
+ mfspr r8,SPRN_CCR2_476
+ rlwinm r9,r8,0,~CCR2_476_DSTI
+ mtspr SPRN_CCR2_476,r9
isync
+ mtspr SPRN_CCR2_476,r8
eieio
tlbsync
sync
diff --git a/arch/powerpc/platforms/44x/misc_44x.S b/arch/powerpc/platforms/44x/misc_44x.S
index dc12b80..a635312 100644
--- a/arch/powerpc/platforms/44x/misc_44x.S
+++ b/arch/powerpc/platforms/44x/misc_44x.S
@@ -9,15 +9,38 @@
*
*/
+#include <asm/mmu.h>
#include <asm/reg.h>
#include <asm/ppc_asm.h>
.text
+#ifdef CONFIG_PPC_47x
+
+#define LOAD_CLEAR_CCR2_DSTI(REG1, REG2) \
+BEGIN_MMU_FTR_SECTION \
+ mfspr REG1,SPRN_CCR2_476; \
+ rlwinm REG2,REG1,0,~CCR2_476_DSTI; \
+ mtspr SPRN_CCR2_476,REG2; \
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
+
+#define RESTORE_CCR2_DSTI(REG) \
+BEGIN_MMU_FTR_SECTION \
+ mtspr SPRN_CCR2_476,REG; \
+END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_47x)
+
+#else /* CONFIG_PPC_47x */
+
+#define LOAD_CLEAR_CCR2_DSTI(REG1, REG2)
+#define RESTORE_CCR2_DSTI(REG)
+
+#endif /* CONFIG_PPC_47x */
+
/*
* Do an IO access in AS1
*/
_GLOBAL(as1_readb)
+ LOAD_CLEAR_CCR2_DSTI(r8, r9)
mfmsr r7
ori r0,r7,MSR_DS
sync
@@ -29,9 +52,11 @@ _GLOBAL(as1_readb)
mtmsr r7
sync
isync
+ RESTORE_CCR2_DSTI(r8)
blr
_GLOBAL(as1_writeb)
+ LOAD_CLEAR_CCR2_DSTI(r8, r9)
mfmsr r7
ori r0,r7,MSR_DS
sync
@@ -43,4 +68,5 @@ _GLOBAL(as1_writeb)
mtmsr r7
sync
isync
+ RESTORE_CCR2_DSTI(r8)
blr
--
1.7.2.2
--
Dave Kleikamp
IBM Linux Technology Center
^ permalink raw reply related
* Re: [PATCH 1/2] 476: Set CCR2[DSTI] to prevent isync from flushing shadow TLB
From: Dave Kleikamp @ 2010-09-27 21:15 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev list
In-Reply-To: <1285621852.14081.62.camel@pasglop>
On Tue, 2010-09-28 at 07:10 +1000, Benjamin Herrenschmidt wrote:
> On Mon, 2010-09-27 at 10:26 -0500, Dave Kleikamp wrote:
> > I think I made it a config option at Ben's request when I first started
> > this work last year, before being sidetracked by other priorities. I
> > could either remove the option, or default it to 'n'. It might be best
> > to just hard-code the behavior to make sure it's exercised, since
> > there's no 47x hardware in production yet, but we can give Ben a chance
> > to weigh in with his opinion.
>
> You can remove the option I suppose. It was useful to have it during
> early bringup but probably not anymore.
Thanks, Ben. I'll resend it without the config option.
Shaggy
--
Dave Kleikamp
IBM Linux Technology Center
^ permalink raw reply
* Re: [PATCH 1/2] 476: Set CCR2[DSTI] to prevent isync from flushing shadow TLB
From: Benjamin Herrenschmidt @ 2010-09-27 21:10 UTC (permalink / raw)
To: Dave Kleikamp; +Cc: linuxppc-dev list
In-Reply-To: <1285601205.17411.23.camel@shaggy-w500>
On Mon, 2010-09-27 at 10:26 -0500, Dave Kleikamp wrote:
> I think I made it a config option at Ben's request when I first started
> this work last year, before being sidetracked by other priorities. I
> could either remove the option, or default it to 'n'. It might be best
> to just hard-code the behavior to make sure it's exercised, since
> there's no 47x hardware in production yet, but we can give Ben a chance
> to weigh in with his opinion.
You can remove the option I suppose. It was useful to have it during
early bringup but probably not anymore.
Cheers,
Ben.
^ permalink raw reply
* Re: [PATCH 1/1] Add config option for batched hcalls
From: Will Schmidt @ 2010-09-27 20:06 UTC (permalink / raw)
To: Olof Johansson; +Cc: linuxppc-dev, Anton Blanchard
In-Reply-To: <20100926034903.GA5473@lixom.net>
On Sat, 2010-09-25 at 22:49 -0500, Olof Johansson wrote:
> On Fri, Sep 24, 2010 at 04:44:15PM -0500, Will Schmidt wrote:
> >
> > Add a config option for the (batched) MULTITCE and BULK_REMOVE h-calls.
> >
> > By default, these options are on and are beneficial for performance and
> > throughput reasons. If disabled, the code will fall back to using less
> > optimal TCE and REMOVE hcalls. The ability to easily disable these
> > options is useful for some of the PREEMPT_RT related investigation and
> > work occurring on Power.
>
> Hi,
>
> I can see why it's useful to enable and disable, but these are all
> runtime-checked, wouldn't it be more useful to add a bootarg to handle
> it instead of adding some new config options that pretty much everyone
> will always go with the defaults on?
>
> The bits are set early, but from looking at where they're used, there
> doesn't seem to be any harm in disabling them later on when a bootarg
> is convenient to parse and deal with?
>
> It has the benefit of easier on/off testing, if that has any value for
> production debug down the road.
Hi Olof,
Thats a good idea, let me poke at this a bit more, see if I can get
bootargs for this.
Thanks,
-Will
>
>
> -Olof
>
^ permalink raw reply
* [PATCH 8/8] v2 Update memory hotplug documentation
From: Nathan Fontenot @ 2010-09-27 19:28 UTC (permalink / raw)
To: linux-kernel, linux-mm, linuxppc-dev
Cc: Greg KH, KAMEZAWA Hiroyuki, Dave Hansen
In-Reply-To: <4CA0EBEB.1030204@austin.ibm.com>
Update the memory hotplug documentation to reflect the new behaviors of
memory blocks reflected in sysfs.
Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
---
Documentation/memory-hotplug.txt | 46 +++++++++++++++++++++++++--------------
1 file changed, 30 insertions(+), 16 deletions(-)
Index: linux-next/Documentation/memory-hotplug.txt
===================================================================
--- linux-next.orig/Documentation/memory-hotplug.txt 2010-09-27 13:49:33.000000000 -0500
+++ linux-next/Documentation/memory-hotplug.txt 2010-09-27 13:50:48.000000000 -0500
@@ -126,36 +126,50 @@
--------------------------------
4 sysfs files for memory hotplug
--------------------------------
-All sections have their device information under /sys/devices/system/memory as
+All sections have their device information in sysfs. Each section is part of
+a memory block under /sys/devices/system/memory as
/sys/devices/system/memory/memoryXXX
-(XXX is section id.)
+(XXX is the section id.)
-Now, XXX is defined as start_address_of_section / section_size.
+Now, XXX is defined as (start_address_of_section / section_size) of the first
+section contained in the memory block. The files 'phys_index' and
+'end_phys_index' under each directory report the beginning and end section id's
+for the memory block covered by the sysfs directory. It is expected that all
+memory sections in this range are present and no memory holes exist in the
+range. Currently there is no way to determine if there is a memory hole, but
+the existence of one should not affect the hotplug capabilities of the memory
+block.
For example, assume 1GiB section size. A device for a memory starting at
0x100000000 is /sys/device/system/memory/memory4
(0x100000000 / 1Gib = 4)
This device covers address range [0x100000000 ... 0x140000000)
-Under each section, you can see 4 files.
+Under each section, you can see 5 files.
-/sys/devices/system/memory/memoryXXX/phys_index
+/sys/devices/system/memory/memoryXXX/start_phys_index
+/sys/devices/system/memory/memoryXXX/end_phys_index
/sys/devices/system/memory/memoryXXX/phys_device
/sys/devices/system/memory/memoryXXX/state
/sys/devices/system/memory/memoryXXX/removable
-'phys_index' : read-only and contains section id, same as XXX.
-'state' : read-write
- at read: contains online/offline state of memory.
- at write: user can specify "online", "offline" command
-'phys_device': read-only: designed to show the name of physical memory device.
- This is not well implemented now.
-'removable' : read-only: contains an integer value indicating
- whether the memory section is removable or not
- removable. A value of 1 indicates that the memory
- section is removable and a value of 0 indicates that
- it is not removable.
+'phys_index' : read-only and contains section id of the first section
+ in the memory block, same as XXX.
+'end_phys_index' : read-only and contains section id of the last section
+ in the memory block.
+'state' : read-write
+ at read: contains online/offline state of memory.
+ at write: user can specify "online", "offline" command
+ which will be performed on al sections in the block.
+'phys_device' : read-only: designed to show the name of physical memory
+ device. This is not well implemented now.
+'removable' : read-only: contains an integer value indicating
+ whether the memory block is removable or not
+ removable. A value of 1 indicates that the memory
+ block is removable and a value of 0 indicates that
+ it is not removable. A memory block is removable only if
+ every section in the block is removable.
NOTE:
These directories/files appear after physical memory hotplug phase.
^ permalink raw reply
* [PATCH 7/8] v2 Define memory_block_size_bytes() for powerpc/pseries
From: Nathan Fontenot @ 2010-09-27 19:28 UTC (permalink / raw)
To: linux-kernel, linux-mm, linuxppc-dev
Cc: Greg KH, KAMEZAWA Hiroyuki, Dave Hansen
In-Reply-To: <4CA0EBEB.1030204@austin.ibm.com>
Define a version of memory_block_size_bytes() for powerpc/pseries such that
a memory block spans an entire lmb.
Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
---
arch/powerpc/platforms/pseries/hotplug-memory.c | 66 +++++++++++++++++++-----
1 file changed, 53 insertions(+), 13 deletions(-)
Index: linux-next/arch/powerpc/platforms/pseries/hotplug-memory.c
===================================================================
--- linux-next.orig/arch/powerpc/platforms/pseries/hotplug-memory.c 2010-09-27 13:49:34.000000000 -0500
+++ linux-next/arch/powerpc/platforms/pseries/hotplug-memory.c 2010-09-27 13:50:45.000000000 -0500
@@ -17,6 +17,54 @@
#include <asm/pSeries_reconfig.h>
#include <asm/sparsemem.h>
+static u32 get_memblock_size(void)
+{
+ struct device_node *np;
+ unsigned int memblock_size = 0;
+
+ np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+ if (np) {
+ const unsigned long *size;
+
+ size = of_get_property(np, "ibm,lmb-size", NULL);
+ memblock_size = size ? *size : 0;
+
+ of_node_put(np);
+ } else {
+ unsigned int memzero_size = 0;
+ const unsigned int *regs;
+
+ np = of_find_node_by_path("/memory@0");
+ if (np) {
+ regs = of_get_property(np, "reg", NULL);
+ memzero_size = regs ? regs[3] : 0;
+ of_node_put(np);
+ }
+
+ if (memzero_size) {
+ /* We now know the size of memory@0, use this to find
+ * the first memoryblock and get its size.
+ */
+ char buf[64];
+
+ sprintf(buf, "/memory@%x", memzero_size);
+ np = of_find_node_by_path(buf);
+ if (np) {
+ regs = of_get_property(np, "reg", NULL);
+ memblock_size = regs ? regs[3] : 0;
+ of_node_put(np);
+ }
+ }
+ }
+
+ return memblock_size;
+}
+
+u32 memory_block_size_bytes(void)
+{
+ return get_memblock_size();
+}
+
static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size)
{
unsigned long start, start_pfn;
@@ -127,30 +175,22 @@
static int pseries_drconf_memory(unsigned long *base, unsigned int action)
{
- struct device_node *np;
- const unsigned long *lmb_size;
+ unsigned long memblock_size;
int rc;
- np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
- if (!np)
+ memblock_size = get_memblock_size();
+ if (!memblock_size)
return -EINVAL;
- lmb_size = of_get_property(np, "ibm,lmb-size", NULL);
- if (!lmb_size) {
- of_node_put(np);
- return -EINVAL;
- }
-
if (action == PSERIES_DRCONF_MEM_ADD) {
- rc = memblock_add(*base, *lmb_size);
+ rc = memblock_add(*base, memblock_size);
rc = (rc < 0) ? -EINVAL : 0;
} else if (action == PSERIES_DRCONF_MEM_REMOVE) {
- rc = pseries_remove_memblock(*base, *lmb_size);
+ rc = pseries_remove_memblock(*base, memblock_size);
} else {
rc = -EINVAL;
}
- of_node_put(np);
return rc;
}
^ permalink raw reply
* [PATCH 6/8] v2 Update node sysfs code
From: Nathan Fontenot @ 2010-09-27 19:27 UTC (permalink / raw)
To: linux-kernel, linux-mm, linuxppc-dev
Cc: Greg KH, KAMEZAWA Hiroyuki, Dave Hansen
In-Reply-To: <4CA0EBEB.1030204@austin.ibm.com>
Update the node sysfs code to be aware of the new capability for a memory
block to contain multiple memory sections. This requires an additional
parameter to unregister_mem_sect_under_nodes so that we know which memory
section of the memory block to unregister.
Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
---
drivers/base/memory.c | 2 +-
drivers/base/node.c | 12 ++++++++----
include/linux/node.h | 6 ++++--
3 files changed, 13 insertions(+), 7 deletions(-)
Index: linux-next/drivers/base/node.c
===================================================================
--- linux-next.orig/drivers/base/node.c 2010-09-27 13:49:36.000000000 -0500
+++ linux-next/drivers/base/node.c 2010-09-27 13:50:43.000000000 -0500
@@ -346,8 +346,10 @@
return -EFAULT;
if (!node_online(nid))
return 0;
- sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
- sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
+
+ sect_start_pfn = section_nr_to_pfn(mem_blk->start_phys_index);
+ sect_end_pfn = section_nr_to_pfn(mem_blk->end_phys_index);
+ sect_end_pfn += PAGES_PER_SECTION - 1;
for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
int page_nid;
@@ -371,7 +373,8 @@
}
/* unregister memory section under all nodes that it spans */
-int unregister_mem_sect_under_nodes(struct memory_block *mem_blk)
+int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
+ unsigned long phys_index)
{
NODEMASK_ALLOC(nodemask_t, unlinked_nodes, GFP_KERNEL);
unsigned long pfn, sect_start_pfn, sect_end_pfn;
@@ -383,7 +386,8 @@
if (!unlinked_nodes)
return -ENOMEM;
nodes_clear(*unlinked_nodes);
- sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
+
+ sect_start_pfn = section_nr_to_pfn(phys_index);
sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
int nid;
Index: linux-next/drivers/base/memory.c
===================================================================
--- linux-next.orig/drivers/base/memory.c 2010-09-27 13:50:38.000000000 -0500
+++ linux-next/drivers/base/memory.c 2010-09-27 13:50:43.000000000 -0500
@@ -587,9 +587,9 @@
mutex_lock(&mem_sysfs_mutex);
mem = find_memory_block(section);
+ unregister_mem_sect_under_nodes(mem, __section_nr(section));
if (atomic_dec_and_test(&mem->section_count)) {
- unregister_mem_sect_under_nodes(mem);
mem_remove_simple_file(mem, phys_index);
mem_remove_simple_file(mem, end_phys_index);
mem_remove_simple_file(mem, state);
Index: linux-next/include/linux/node.h
===================================================================
--- linux-next.orig/include/linux/node.h 2010-09-27 13:49:36.000000000 -0500
+++ linux-next/include/linux/node.h 2010-09-27 13:50:43.000000000 -0500
@@ -44,7 +44,8 @@
extern int unregister_cpu_under_node(unsigned int cpu, unsigned int nid);
extern int register_mem_sect_under_node(struct memory_block *mem_blk,
int nid);
-extern int unregister_mem_sect_under_nodes(struct memory_block *mem_blk);
+extern int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
+ unsigned long phys_index);
#ifdef CONFIG_HUGETLBFS
extern void register_hugetlbfs_with_node(node_registration_func_t doregister,
@@ -72,7 +73,8 @@
{
return 0;
}
-static inline int unregister_mem_sect_under_nodes(struct memory_block *mem_blk)
+static inline int unregister_mem_sect_under_nodes(struct memory_block *mem_blk,
+ unsigned long phys_index)
{
return 0;
}
^ permalink raw reply
* [PATCH 5/8] v2 Add end_phys_index file
From: Nathan Fontenot @ 2010-09-27 19:26 UTC (permalink / raw)
To: linux-kernel, linux-mm, linuxppc-dev
Cc: Greg KH, KAMEZAWA Hiroyuki, Dave Hansen
In-Reply-To: <4CA0EBEB.1030204@austin.ibm.com>
Update the 'phys_index' properties of a memory block to include a
'start_phys_index' which is the same as the current 'phys_index' property.
The property still appears as 'phys_index' in sysfs but the memory_block
struct name is updated to indicate the start and end values.
This also adds an 'end_phys_index' property to indicate the id of the
last section in th memory block.
Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
---
drivers/base/memory.c | 39 ++++++++++++++++++++++++++++++---------
include/linux/memory.h | 3 ++-
2 files changed, 32 insertions(+), 10 deletions(-)
Index: linux-next/drivers/base/memory.c
===================================================================
--- linux-next.orig/drivers/base/memory.c 2010-09-27 13:50:18.000000000 -0500
+++ linux-next/drivers/base/memory.c 2010-09-27 13:50:38.000000000 -0500
@@ -97,7 +97,7 @@
int error;
memory->sysdev.cls = &memory_sysdev_class;
- memory->sysdev.id = memory->phys_index / sections_per_block;
+ memory->sysdev.id = memory->start_phys_index / sections_per_block;
error = sysdev_register(&memory->sysdev);
return error;
@@ -138,12 +138,26 @@
* uses.
*/
-static ssize_t show_mem_phys_index(struct sys_device *dev,
+static ssize_t show_mem_start_phys_index(struct sys_device *dev,
struct sysdev_attribute *attr, char *buf)
{
struct memory_block *mem =
container_of(dev, struct memory_block, sysdev);
- return sprintf(buf, "%08lx\n", mem->phys_index / sections_per_block);
+ unsigned long phys_index;
+
+ phys_index = mem->start_phys_index / sections_per_block;
+ return sprintf(buf, "%08lx\n", phys_index);
+}
+
+static ssize_t show_mem_end_phys_index(struct sys_device *dev,
+ struct sysdev_attribute *attr, char *buf)
+{
+ struct memory_block *mem =
+ container_of(dev, struct memory_block, sysdev);
+ unsigned long phys_index;
+
+ phys_index = mem->end_phys_index / sections_per_block;
+ return sprintf(buf, "%08lx\n", phys_index);
}
/*
@@ -158,7 +172,7 @@
container_of(dev, struct memory_block, sysdev);
for (i = 0; i < sections_per_block; i++) {
- pfn = section_nr_to_pfn(mem->phys_index + i);
+ pfn = section_nr_to_pfn(mem->start_phys_index + i);
ret &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
}
@@ -275,14 +289,15 @@
mem->state = MEM_GOING_OFFLINE;
for (i = 0; i < sections_per_block; i++) {
- ret = memory_section_action(mem->phys_index + i, to_state);
+ ret = memory_section_action(mem->start_phys_index + i,
+ to_state);
if (ret)
break;
}
if (ret) {
for (i = 0; i < sections_per_block; i++)
- memory_section_action(mem->phys_index + i,
+ memory_section_action(mem->start_phys_index + i,
from_state_req);
mem->state = from_state_req;
@@ -330,7 +345,8 @@
return sprintf(buf, "%d\n", mem->phys_device);
}
-static SYSDEV_ATTR(phys_index, 0444, show_mem_phys_index, NULL);
+static SYSDEV_ATTR(phys_index, 0444, show_mem_start_phys_index, NULL);
+static SYSDEV_ATTR(end_phys_index, 0444, show_mem_end_phys_index, NULL);
static SYSDEV_ATTR(state, 0644, show_mem_state, store_mem_state);
static SYSDEV_ATTR(phys_device, 0444, show_phys_device, NULL);
static SYSDEV_ATTR(removable, 0444, show_mem_removable, NULL);
@@ -514,17 +530,21 @@
return -ENOMEM;
scn_nr = __section_nr(section);
- mem->phys_index = base_memory_block_id(scn_nr) * sections_per_block;
+ mem->start_phys_index =
+ base_memory_block_id(scn_nr) * sections_per_block;
+ mem->end_phys_index = mem->start_phys_index + sections_per_block - 1;
mem->state = state;
atomic_inc(&mem->section_count);
mutex_init(&mem->state_mutex);
- start_pfn = section_nr_to_pfn(mem->phys_index);
+ start_pfn = section_nr_to_pfn(mem->start_phys_index);
mem->phys_device = arch_get_memory_phys_device(start_pfn);
ret = register_memory(mem);
if (!ret)
ret = mem_create_simple_file(mem, phys_index);
if (!ret)
+ ret = mem_create_simple_file(mem, end_phys_index);
+ if (!ret)
ret = mem_create_simple_file(mem, state);
if (!ret)
ret = mem_create_simple_file(mem, phys_device);
@@ -571,6 +591,7 @@
if (atomic_dec_and_test(&mem->section_count)) {
unregister_mem_sect_under_nodes(mem);
mem_remove_simple_file(mem, phys_index);
+ mem_remove_simple_file(mem, end_phys_index);
mem_remove_simple_file(mem, state);
mem_remove_simple_file(mem, phys_device);
mem_remove_simple_file(mem, removable);
Index: linux-next/include/linux/memory.h
===================================================================
--- linux-next.orig/include/linux/memory.h 2010-09-27 13:49:37.000000000 -0500
+++ linux-next/include/linux/memory.h 2010-09-27 13:50:38.000000000 -0500
@@ -22,7 +22,8 @@
#include <asm/atomic.h>
struct memory_block {
- unsigned long phys_index;
+ unsigned long start_phys_index;
+ unsigned long end_phys_index;
unsigned long state;
atomic_t section_count;
^ permalink raw reply
* [PATCH 4/8] v2 Allow memory block to span multiple memory sections
From: Nathan Fontenot @ 2010-09-27 19:25 UTC (permalink / raw)
To: linux-kernel, linux-mm, linuxppc-dev
Cc: Greg KH, KAMEZAWA Hiroyuki, Dave Hansen
In-Reply-To: <4CA0EBEB.1030204@austin.ibm.com>
Update the memory sysfs code such that each sysfs memory directory is now
considered a memory block that can span multiple memory sections per
memory block. The default size of each memory block is SECTION_SIZE_BITS
to maintain the current behavior of having a single memory section per
memory block (i.e. one sysfs directory per memory section).
For architectures that want to have memory blocks span multiple
memory sections they need only define their own memory_block_size_bytes()
routine.
Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com>
---
drivers/base/memory.c | 155 ++++++++++++++++++++++++++++++++++----------------
1 file changed, 108 insertions(+), 47 deletions(-)
Index: linux-next/drivers/base/memory.c
===================================================================
--- linux-next.orig/drivers/base/memory.c 2010-09-27 09:31:57.000000000 -0500
+++ linux-next/drivers/base/memory.c 2010-09-27 13:50:18.000000000 -0500
@@ -30,6 +30,14 @@
static DEFINE_MUTEX(mem_sysfs_mutex);
#define MEMORY_CLASS_NAME "memory"
+#define MIN_MEMORY_BLOCK_SIZE (1 << SECTION_SIZE_BITS)
+
+static int sections_per_block;
+
+static inline int base_memory_block_id(int section_nr)
+{
+ return section_nr / sections_per_block;
+}
static struct sysdev_class memory_sysdev_class = {
.name = MEMORY_CLASS_NAME,
@@ -84,28 +92,47 @@
* register_memory - Setup a sysfs device for a memory block
*/
static
-int register_memory(struct memory_block *memory, struct mem_section *section)
+int register_memory(struct memory_block *memory)
{
int error;
memory->sysdev.cls = &memory_sysdev_class;
- memory->sysdev.id = __section_nr(section);
+ memory->sysdev.id = memory->phys_index / sections_per_block;
error = sysdev_register(&memory->sysdev);
return error;
}
static void
-unregister_memory(struct memory_block *memory, struct mem_section *section)
+unregister_memory(struct memory_block *memory)
{
BUG_ON(memory->sysdev.cls != &memory_sysdev_class);
- BUG_ON(memory->sysdev.id != __section_nr(section));
/* drop the ref. we got in remove_memory_block() */
kobject_put(&memory->sysdev.kobj);
sysdev_unregister(&memory->sysdev);
}
+u32 __weak memory_block_size_bytes(void)
+{
+ return MIN_MEMORY_BLOCK_SIZE;
+}
+
+static u32 get_memory_block_size(void)
+{
+ u32 block_sz;
+
+ block_sz = memory_block_size_bytes();
+
+ /* Validate blk_sz is a power of 2 and not less than section size */
+ if ((block_sz & (block_sz - 1)) || (block_sz < MIN_MEMORY_BLOCK_SIZE)) {
+ WARN_ON(1);
+ block_sz = MIN_MEMORY_BLOCK_SIZE;
+ }
+
+ return block_sz;
+}
+
/*
* use this as the physical section index that this memsection
* uses.
@@ -116,7 +143,7 @@
{
struct memory_block *mem =
container_of(dev, struct memory_block, sysdev);
- return sprintf(buf, "%08lx\n", mem->phys_index);
+ return sprintf(buf, "%08lx\n", mem->phys_index / sections_per_block);
}
/*
@@ -125,13 +152,16 @@
static ssize_t show_mem_removable(struct sys_device *dev,
struct sysdev_attribute *attr, char *buf)
{
- unsigned long start_pfn;
- int ret;
+ unsigned long i, pfn;
+ int ret = 1;
struct memory_block *mem =
container_of(dev, struct memory_block, sysdev);
- start_pfn = section_nr_to_pfn(mem->phys_index);
- ret = is_mem_section_removable(start_pfn, PAGES_PER_SECTION);
+ for (i = 0; i < sections_per_block; i++) {
+ pfn = section_nr_to_pfn(mem->phys_index + i);
+ ret &= is_mem_section_removable(pfn, PAGES_PER_SECTION);
+ }
+
return sprintf(buf, "%d\n", ret);
}
@@ -184,17 +214,14 @@
* OK to have direct references to sparsemem variables in here.
*/
static int
-memory_block_action(struct memory_block *mem, unsigned long action)
+memory_section_action(unsigned long phys_index, unsigned long action)
{
int i;
- unsigned long psection;
unsigned long start_pfn, start_paddr;
struct page *first_page;
int ret;
- int old_state = mem->state;
- psection = mem->phys_index;
- first_page = pfn_to_page(psection << PFN_SECTION_SHIFT);
+ first_page = pfn_to_page(phys_index << PFN_SECTION_SHIFT);
/*
* The probe routines leave the pages reserved, just
@@ -207,8 +234,8 @@
continue;
printk(KERN_WARNING "section number %ld page number %d "
- "not reserved, was it already online? \n",
- psection, i);
+ "not reserved, was it already online?\n",
+ phys_index, i);
return -EBUSY;
}
}
@@ -219,18 +246,13 @@
ret = online_pages(start_pfn, PAGES_PER_SECTION);
break;
case MEM_OFFLINE:
- mem->state = MEM_GOING_OFFLINE;
start_paddr = page_to_pfn(first_page) << PAGE_SHIFT;
ret = remove_memory(start_paddr,
PAGES_PER_SECTION << PAGE_SHIFT);
- if (ret) {
- mem->state = old_state;
- break;
- }
break;
default:
- WARN(1, KERN_WARNING "%s(%p, %ld) unknown action: %ld\n",
- __func__, mem, action, action);
+ WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: "
+ "%ld\n", __func__, phys_index, action, action);
ret = -EINVAL;
}
@@ -240,7 +262,8 @@
static int memory_block_change_state(struct memory_block *mem,
unsigned long to_state, unsigned long from_state_req)
{
- int ret = 0;
+ int i, ret = 0;
+
mutex_lock(&mem->state_mutex);
if (mem->state != from_state_req) {
@@ -248,8 +271,22 @@
goto out;
}
- ret = memory_block_action(mem, to_state);
- if (!ret)
+ if (to_state == MEM_OFFLINE)
+ mem->state = MEM_GOING_OFFLINE;
+
+ for (i = 0; i < sections_per_block; i++) {
+ ret = memory_section_action(mem->phys_index + i, to_state);
+ if (ret)
+ break;
+ }
+
+ if (ret) {
+ for (i = 0; i < sections_per_block; i++)
+ memory_section_action(mem->phys_index + i,
+ from_state_req);
+
+ mem->state = from_state_req;
+ } else
mem->state = to_state;
out:
@@ -262,20 +299,15 @@
struct sysdev_attribute *attr, const char *buf, size_t count)
{
struct memory_block *mem;
- unsigned int phys_section_nr;
int ret = -EINVAL;
mem = container_of(dev, struct memory_block, sysdev);
- phys_section_nr = mem->phys_index;
-
- if (!present_section_nr(phys_section_nr))
- goto out;
if (!strncmp(buf, "online", min((int)count, 6)))
ret = memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE);
else if(!strncmp(buf, "offline", min((int)count, 7)))
ret = memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE);
-out:
+
if (ret)
return ret;
return count;
@@ -315,7 +347,7 @@
print_block_size(struct sysdev_class *class, struct sysdev_class_attribute *attr,
char *buf)
{
- return sprintf(buf, "%lx\n", (unsigned long)PAGES_PER_SECTION * PAGE_SIZE);
+ return sprintf(buf, "%x\n", get_memory_block_size());
}
static SYSDEV_CLASS_ATTR(block_size_bytes, 0444, print_block_size, NULL);
@@ -451,12 +483,13 @@
struct sys_device *sysdev;
struct memory_block *mem;
char name[sizeof(MEMORY_CLASS_NAME) + 9 + 1];
+ int block_id = base_memory_block_id(__section_nr(section));
/*
* This only works because we know that section == sysdev->id
* slightly redundant with sysdev_register()
*/
- sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, __section_nr(section));
+ sprintf(&name[0], "%s%d", MEMORY_CLASS_NAME, block_id);
kobj = kset_find_obj(&memory_sysdev_class.kset, name);
if (!kobj)
@@ -468,26 +501,27 @@
return mem;
}
-static int add_memory_block(int nid, struct mem_section *section,
- unsigned long state, enum mem_add_context context)
+static int init_memory_block(struct memory_block **memory,
+ struct mem_section *section, unsigned long state)
{
- struct memory_block *mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ struct memory_block *mem;
unsigned long start_pfn;
+ int scn_nr;
int ret = 0;
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
if (!mem)
return -ENOMEM;
- mutex_lock(&mem_sysfs_mutex);
-
- mem->phys_index = __section_nr(section);
+ scn_nr = __section_nr(section);
+ mem->phys_index = base_memory_block_id(scn_nr) * sections_per_block;
mem->state = state;
atomic_inc(&mem->section_count);
mutex_init(&mem->state_mutex);
start_pfn = section_nr_to_pfn(mem->phys_index);
mem->phys_device = arch_get_memory_phys_device(start_pfn);
- ret = register_memory(mem, section);
+ ret = register_memory(mem);
if (!ret)
ret = mem_create_simple_file(mem, phys_index);
if (!ret)
@@ -496,8 +530,29 @@
ret = mem_create_simple_file(mem, phys_device);
if (!ret)
ret = mem_create_simple_file(mem, removable);
+
+ *memory = mem;
+ return ret;
+}
+
+static int add_memory_section(int nid, struct mem_section *section,
+ unsigned long state, enum mem_add_context context)
+{
+ struct memory_block *mem;
+ int ret = 0;
+
+ mutex_lock(&mem_sysfs_mutex);
+
+ mem = find_memory_block(section);
+ if (mem) {
+ atomic_inc(&mem->section_count);
+ kobject_put(&mem->sysdev.kobj);
+ } else
+ ret = init_memory_block(&mem, section, state);
+
if (!ret) {
- if (context == HOTPLUG)
+ if (context == HOTPLUG &&
+ atomic_read(&mem->section_count) == sections_per_block)
ret = register_mem_sect_under_node(mem, nid);
}
@@ -519,8 +574,10 @@
mem_remove_simple_file(mem, state);
mem_remove_simple_file(mem, phys_device);
mem_remove_simple_file(mem, removable);
- unregister_memory(mem, section);
- }
+ unregister_memory(mem);
+ kfree(mem);
+ } else
+ kobject_put(&mem->sysdev.kobj);
mutex_unlock(&mem_sysfs_mutex);
return 0;
@@ -532,7 +589,7 @@
*/
int register_new_memory(int nid, struct mem_section *section)
{
- return add_memory_block(nid, section, MEM_OFFLINE, HOTPLUG);
+ return add_memory_section(nid, section, MEM_OFFLINE, HOTPLUG);
}
int unregister_memory_section(struct mem_section *section)
@@ -551,12 +608,16 @@
unsigned int i;
int ret;
int err;
+ int block_sz;
memory_sysdev_class.kset.uevent_ops = &memory_uevent_ops;
ret = sysdev_class_register(&memory_sysdev_class);
if (ret)
goto out;
+ block_sz = get_memory_block_size();
+ sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
+
/*
* Create entries for memory sections that were found
* during boot and have been initialized
@@ -564,8 +625,8 @@
for (i = 0; i < NR_MEM_SECTIONS; i++) {
if (!present_section_nr(i))
continue;
- err = add_memory_block(0, __nr_to_section(i), MEM_ONLINE,
- BOOT);
+ err = add_memory_section(0, __nr_to_section(i), MEM_ONLINE,
+ BOOT);
if (!ret)
ret = err;
}
^ permalink raw reply
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