From: James Hogan <james.hogan@mips.com>
To: David Daney <david.daney@cavium.com>
Cc: <linux-mips@linux-mips.org>, <ralf@linux-mips.org>,
<netdev@vger.kernel.org>, "David S. Miller" <davem@davemloft.net>,
"Rob Herring" <robh+dt@kernel.org>,
Mark Rutland <mark.rutland@arm.com>, <devel@driverdev.osuosl.org>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
<linux-kernel@vger.kernel.org>,
"Steven J. Hill" <steven.hill@cavium.com>,
<devicetree@vger.kernel.org>, Andrew Lunn <andrew@lunn.ch>,
Florian Fainelli <f.fainelli@gmail.com>,
Carlos Munoz <cmunoz@cavium.com>
Subject: Re: [PATCH v4 3/8] MIPS: Octeon: Add a global resource manager.
Date: Thu, 30 Nov 2017 22:53:33 +0000 [thread overview]
Message-ID: <20171130225333.GI27409@jhogan-linux.mipstec.com> (raw)
In-Reply-To: <20171129005540.28829-4-david.daney@cavium.com>
[-- Attachment #1: Type: text/plain, Size: 14103 bytes --]
On Tue, Nov 28, 2017 at 04:55:35PM -0800, David Daney wrote:
> From: Carlos Munoz <cmunoz@cavium.com>
>
> Add a global resource manager to manage tagged pointers within
> bootmem allocated memory. This is used by various functional
> blocks in the Octeon core like the FPA, Ethernet nexus, etc.
>
> Signed-off-by: Carlos Munoz <cmunoz@cavium.com>
> Signed-off-by: Steven J. Hill <Steven.Hill@cavium.com>
> Signed-off-by: David Daney <david.daney@cavium.com>
> ---
> arch/mips/cavium-octeon/Makefile | 3 +-
> arch/mips/cavium-octeon/resource-mgr.c | 371 +++++++++++++++++++++++++++++++++
> arch/mips/include/asm/octeon/octeon.h | 18 ++
> 3 files changed, 391 insertions(+), 1 deletion(-)
> create mode 100644 arch/mips/cavium-octeon/resource-mgr.c
>
> diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
> index 7c02e542959a..0a299ab8719f 100644
> --- a/arch/mips/cavium-octeon/Makefile
> +++ b/arch/mips/cavium-octeon/Makefile
> @@ -9,7 +9,8 @@
> # Copyright (C) 2005-2009 Cavium Networks
> #
>
> -obj-y := cpu.o setup.o octeon-platform.o octeon-irq.o csrc-octeon.o
> +obj-y := cpu.o setup.o octeon-platform.o octeon-irq.o csrc-octeon.o \
> + resource-mgr.o
Maybe put that on a separate line like below.
> obj-y += dma-octeon.o
> obj-y += octeon-memcpy.o
> obj-y += executive/
> diff --git a/arch/mips/cavium-octeon/resource-mgr.c b/arch/mips/cavium-octeon/resource-mgr.c
> new file mode 100644
> index 000000000000..ca25fa953402
> --- /dev/null
> +++ b/arch/mips/cavium-octeon/resource-mgr.c
> @@ -0,0 +1,371 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Resource manager for Octeon.
> + *
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License. See the file "COPYING" in the main directory of this archive
> + * for more details.
> + *
> + * Copyright (C) 2017 Cavium, Inc.
> + */
> +#include <linux/module.h>
> +
> +#include <asm/octeon/octeon.h>
> +#include <asm/octeon/cvmx-bootmem.h>
> +
> +#define RESOURCE_MGR_BLOCK_NAME "cvmx-global-resources"
> +#define MAX_RESOURCES 128
> +#define INST_AVAILABLE -88
> +#define OWNER 0xbadc0de
> +
> +struct global_resource_entry {
> + struct global_resource_tag tag;
> + u64 phys_addr;
> + u64 size;
> +};
> +
> +struct global_resources {
> +#ifdef __LITTLE_ENDIAN_BITFIELD
> + u32 rlock;
> + u32 pad;
> +#else
> + u32 pad;
> + u32 rlock;
> +#endif
> + u64 entry_cnt;
> + struct global_resource_entry resource_entry[];
> +};
> +
> +static struct global_resources *res_mgr_info;
> +
> +
> +/*
> + * The resource manager interacts with software running outside of the
> + * Linux kernel, which necessitates locking to maintain data structure
> + * consistency. These custom locking functions implement the locking
> + * protocol, and cannot be replaced by kernel locking functions that
> + * may use different in-memory structures.
> + */
> +
> +static void res_mgr_lock(void)
> +{
> + unsigned int tmp;
> + u64 lock = (u64)&res_mgr_info->rlock;
presumably this could be a u32 *, avoid the cast to u64, and still work
just fine below.
> +
> + __asm__ __volatile__(
> + ".set noreorder\n"
> + "1: ll %[tmp], 0(%[addr])\n"
> + " bnez %[tmp], 1b\n"
> + " li %[tmp], 1\n"
I believe the convention for .S files is for instructions in branch
delay slots to be indented an additional space for readability. Maybe
that would be worthwhile here.
> + " sc %[tmp], 0(%[addr])\n"
> + " beqz %[tmp], 1b\n"
> + " nop\n"
and here also.
> + ".set reorder\n" :
nit: strictly speaking there's no need for \n on the last line.
> + [tmp] "=&r"(tmp) :
> + [addr] "r"(lock) :
> + "memory");
minor style thing: its far more common to have : at the beginning of the
line rather than the end.
> +}
> +
> +static void res_mgr_unlock(void)
> +{
> + u64 lock = (u64)&res_mgr_info->rlock;
same again
> +
> + /* Wait until all resource operations finish before unlocking. */
> + mb();
> + __asm__ __volatile__(
> + "sw $0, 0(%[addr])\n" : :
> + [addr] "r"(lock) :
> + "memory");
> +
> + /* Force a write buffer flush. */
> + mb();
> +}
> +
> +static int res_mgr_find_resource(struct global_resource_tag tag)
> +{
> + struct global_resource_entry *res_entry;
> + int i;
> +
> + for (i = 0; i < res_mgr_info->entry_cnt; i++) {
> + res_entry = &res_mgr_info->resource_entry[i];
> + if (res_entry->tag.lo == tag.lo && res_entry->tag.hi == tag.hi)
> + return i;
> + }
> + return -1;
> +}
> +
> +/**
> + * res_mgr_create_resource - Create a resource.
> + * @tag: Identifies the resource.
> + * @inst_cnt: Number of resource instances to create.
> + *
> + * Returns 0 if the source was created successfully.
> + * Returns <0 for error codes.
Only -1 seems to be returned. Is it worth returning some standard Linux
error codes instead?
> + */
> +int res_mgr_create_resource(struct global_resource_tag tag, int inst_cnt)
> +{
> + struct global_resource_entry *res_entry;
> + u64 size;
> + u64 *res_addr;
> + int res_index, i, rc = 0;
> +
> + res_mgr_lock();
> +
> + /* Make sure resource doesn't already exist. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index >= 0) {
> + rc = -1;
> + goto err;
> + }
> +
> + if (res_mgr_info->entry_cnt >= MAX_RESOURCES) {
> + pr_err("Resource max limit reached, not created\n");
> + rc = -1;
> + goto err;
> + }
> +
> + /*
> + * Each instance is kept in an array of u64s. The first array element
> + * holds the number of allocated instances.
> + */
> + size = sizeof(u64) * (inst_cnt + 1);
> + res_addr = cvmx_bootmem_alloc_range(size, CVMX_CACHE_LINE_SIZE, 0, 0);
> + if (!res_addr) {
> + pr_err("Failed to allocate resource. not created\n");
> + rc = -1;
> + goto err;
> + }
> +
> + /* Initialize the newly created resource. */
> + *res_addr = inst_cnt;
> + for (i = 1; i < inst_cnt + 1; i++)
or "i <= inst_cnt"?
> + *(res_addr + i) = INST_AVAILABLE;
Nit: IMO res_addr[i] is marginally more readable
> +
> + res_index = res_mgr_info->entry_cnt;
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_entry->tag.lo = tag.lo;
> + res_entry->tag.hi = tag.hi;
or res_entry->tag = tag;?
> + res_entry->phys_addr = virt_to_phys(res_addr);
> + res_entry->size = size;
> + res_mgr_info->entry_cnt++;
> +
> +err:
> + res_mgr_unlock();
> +
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_create_resource);
> +
> +/**
> + * res_mgr_alloc_range - Allocate a range of resource instances.
I don't know how strict kerndoc is on this, but I think it should be
res_mgr_alloc_range() here. Same elsewhere.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested start of instance range to allocate.
> + * Range instances are guaranteed to be sequential
> + * (-1 for don't care).
> + * @req_cnt: Number of instances to allocate.
> + * @use_last_avail: Set to request the last available instance.
> + * @inst: Updated with the allocated instances.
> + *
> + * Returns 0 if the source was created successfully.
> + * Returns <0 for error codes.
> + */
> +int res_mgr_alloc_range(struct global_resource_tag tag, int req_inst,
> + int req_cnt, bool use_last_avail, int *inst)
> +{
> + struct global_resource_entry *res_entry;
> + int res_index;
> + u64 *res_addr;
> + u64 inst_cnt;
> + int alloc_cnt, i, rc = -1;
> +
> + /* Start with no instances allocated. */
> + for (i = 0; i < req_cnt; i++)
> + inst[i] = INST_AVAILABLE;
> +
> + res_mgr_lock();
> +
> + /* Find the resource. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index < 0) {
> + pr_err("Resource not found, can't allocate instance\n");
> + goto err;
> + }
> +
> + /* Get resource data. */
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_addr = phys_to_virt(res_entry->phys_addr);
> + inst_cnt = *res_addr;
> +
> + /* Allocate the requested instances. */
> + if (req_inst >= 0) {
> + /* Specific instance range requested. */
> + if (req_inst + req_cnt >= inst_cnt) {
> + pr_err("Requested instance out of range\n");
> + goto err;
> + }
> +
> + for (i = 0; i < req_cnt; i++) {
> + if (*(res_addr + req_inst + 1 + i) == INST_AVAILABLE)
> + inst[i] = req_inst + i;
> + else {
braces on all branches if on any.
> + inst[0] = INST_AVAILABLE;
> + break;
> + }
> + }
> + } else if (use_last_avail) {
> + /* Last available instance requested. */
> + alloc_cnt = 0;
> + for (i = inst_cnt; i > 0; i--) {
> + if (*(res_addr + i) == INST_AVAILABLE) {
> + /*
> + * Instance off by 1 (first element holds the
> + * count).
> + */
> + inst[alloc_cnt] = i - 1;
> +
> + alloc_cnt++;
> + if (alloc_cnt == req_cnt)
> + break;
> + }
> + }
> +
> + if (i == 0)
> + inst[0] = INST_AVAILABLE;
> + } else {
> + /* Next available instance requested. */
> + alloc_cnt = 0;
> + for (i = 1; i <= inst_cnt; i++) {
> + if (*(res_addr + i) == INST_AVAILABLE) {
> + /*
> + * Instance off by 1 (first element holds the
> + * count).
> + */
> + inst[alloc_cnt] = i - 1;
> +
> + alloc_cnt++;
> + if (alloc_cnt == req_cnt)
> + break;
> + }
> + }
> +
> + if (i > inst_cnt)
> + inst[0] = INST_AVAILABLE;
> + }
> +
> + if (inst[0] != INST_AVAILABLE) {
> + for (i = 0; i < req_cnt; i++)
> + *(res_addr + inst[i] + 1) = OWNER;
> + rc = 0;
> + }
> +
> +err:
> + res_mgr_unlock();
> +
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_alloc_range);
> +
> +/**
> + * res_mgr_alloc - Allocate a resource instance.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to allocate (-1 for don't care).
> + * @use_last_avail: Set to request the last available instance.
> + *
> + * Returns: Allocated resource instance if successful.
> + * Returns <0 for error codes.
> + */
> +int res_mgr_alloc(struct global_resource_tag tag, int req_inst, bool use_last_avail)
> +{
> + int inst, rc;
> +
> + rc = res_mgr_alloc_range(tag, req_inst, 1, use_last_avail, &inst);
> + if (!rc)
> + return inst;
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_alloc);
> +
> +/**
> + * res_mgr_free_range - Free a resource instance range.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to free.
the parameter is called inst.
Other than these minor / style comments, it doesn't look unreasonable to
me.
Cheers
James
> + * @req_cnt: Number of instances to free.
> + */
> +void res_mgr_free_range(struct global_resource_tag tag, const int *inst, int req_cnt)
> +{
> + struct global_resource_entry *res_entry;
> + int res_index, i;
> + u64 *res_addr;
> +
> + res_mgr_lock();
> +
> + /* Find the resource. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index < 0) {
> + pr_err("Resource not found, can't free instance\n");
> + goto err;
> + }
> +
> + /* Get the resource data. */
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_addr = phys_to_virt(res_entry->phys_addr);
> +
> + /* Free the resource instances. */
> + for (i = 0; i < req_cnt; i++) {
> + /* Instance off by 1 (first element holds the count). */
> + *(res_addr + inst[i] + 1) = INST_AVAILABLE;
> + }
> +
> +err:
> + res_mgr_unlock();
> +}
> +EXPORT_SYMBOL(res_mgr_free_range);
> +
> +/**
> + * res_mgr_free - Free a resource instance.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to free.
> + */
> +void res_mgr_free(struct global_resource_tag tag, int inst)
> +{
> + res_mgr_free_range(tag, &inst, 1);
> +}
> +EXPORT_SYMBOL(res_mgr_free);
> +
> +static int __init res_mgr_init(void)
> +{
> + struct cvmx_bootmem_named_block_desc *block;
> + int block_size;
> + u64 addr;
> +
> + cvmx_bootmem_lock();
> +
> + /* Search for the resource manager data in boot memory. */
> + block = cvmx_bootmem_phy_named_block_find(RESOURCE_MGR_BLOCK_NAME, CVMX_BOOTMEM_FLAG_NO_LOCKING);
> + if (block) {
> + /* Found. */
> + res_mgr_info = phys_to_virt(block->base_addr);
> + } else {
> + /* Create it. */
> + block_size = sizeof(struct global_resources) +
> + sizeof(struct global_resource_entry) * MAX_RESOURCES;
> + addr = cvmx_bootmem_phy_named_block_alloc(block_size, 0, 0,
> + CVMX_CACHE_LINE_SIZE, RESOURCE_MGR_BLOCK_NAME,
> + CVMX_BOOTMEM_FLAG_NO_LOCKING);
> + if (!addr) {
> + pr_err("Failed to allocate name block %s\n",
> + RESOURCE_MGR_BLOCK_NAME);
> + } else {
> + res_mgr_info = phys_to_virt(addr);
> + memset(res_mgr_info, 0, block_size);
> + }
> + }
> +
> + cvmx_bootmem_unlock();
> +
> + return 0;
> +}
> +device_initcall(res_mgr_init);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cavium, Inc. Octeon resource manager");
> diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h
> index 92a17d67c1fa..0411efdb465c 100644
> --- a/arch/mips/include/asm/octeon/octeon.h
> +++ b/arch/mips/include/asm/octeon/octeon.h
> @@ -346,6 +346,24 @@ void octeon_mult_restore3_end(void);
> void octeon_mult_restore2(void);
> void octeon_mult_restore2_end(void);
>
> +/*
> + * This definition must be kept in sync with the one in
> + * cvmx-global-resources.c
> + */
> +struct global_resource_tag {
> + uint64_t lo;
> + uint64_t hi;
> +};
> +
> +void res_mgr_free(struct global_resource_tag tag, int inst);
> +void res_mgr_free_range(struct global_resource_tag tag, const int *inst,
> + int req_cnt);
> +int res_mgr_alloc(struct global_resource_tag tag, int req_inst,
> + bool use_last_avail);
> +int res_mgr_alloc_range(struct global_resource_tag tag, int req_inst,
> + int req_cnt, bool use_last_avail, int *inst);
> +int res_mgr_create_resource(struct global_resource_tag tag, int inst_cnt);
> +
> /**
> * Read a 32bit value from the Octeon NPI register space
> *
> --
> 2.14.3
>
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
WARNING: multiple messages have this Message-ID (diff)
From: James Hogan <james.hogan@mips.com>
To: David Daney <david.daney@cavium.com>
Cc: linux-mips@linux-mips.org, ralf@linux-mips.org,
netdev@vger.kernel.org, "David S. Miller" <davem@davemloft.net>,
Rob Herring <robh+dt@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
devel@driverdev.osuosl.org,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
linux-kernel@vger.kernel.org,
"Steven J. Hill" <steven.hill@cavium.com>,
devicetree@vger.kernel.org, Andrew Lunn <andrew@lunn.ch>,
Florian Fainelli <f.fainelli@gmail.com>,
Carlos Munoz <cmunoz@cavium.com>
Subject: Re: [PATCH v4 3/8] MIPS: Octeon: Add a global resource manager.
Date: Thu, 30 Nov 2017 22:53:33 +0000 [thread overview]
Message-ID: <20171130225333.GI27409@jhogan-linux.mipstec.com> (raw)
Message-ID: <20171130225333.YVVyYH5pzvfM0wloUnwh2Fd9ZXC1cwWLUNZmuqTmKLA@z> (raw)
In-Reply-To: <20171129005540.28829-4-david.daney@cavium.com>
[-- Attachment #1: Type: text/plain, Size: 14103 bytes --]
On Tue, Nov 28, 2017 at 04:55:35PM -0800, David Daney wrote:
> From: Carlos Munoz <cmunoz@cavium.com>
>
> Add a global resource manager to manage tagged pointers within
> bootmem allocated memory. This is used by various functional
> blocks in the Octeon core like the FPA, Ethernet nexus, etc.
>
> Signed-off-by: Carlos Munoz <cmunoz@cavium.com>
> Signed-off-by: Steven J. Hill <Steven.Hill@cavium.com>
> Signed-off-by: David Daney <david.daney@cavium.com>
> ---
> arch/mips/cavium-octeon/Makefile | 3 +-
> arch/mips/cavium-octeon/resource-mgr.c | 371 +++++++++++++++++++++++++++++++++
> arch/mips/include/asm/octeon/octeon.h | 18 ++
> 3 files changed, 391 insertions(+), 1 deletion(-)
> create mode 100644 arch/mips/cavium-octeon/resource-mgr.c
>
> diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
> index 7c02e542959a..0a299ab8719f 100644
> --- a/arch/mips/cavium-octeon/Makefile
> +++ b/arch/mips/cavium-octeon/Makefile
> @@ -9,7 +9,8 @@
> # Copyright (C) 2005-2009 Cavium Networks
> #
>
> -obj-y := cpu.o setup.o octeon-platform.o octeon-irq.o csrc-octeon.o
> +obj-y := cpu.o setup.o octeon-platform.o octeon-irq.o csrc-octeon.o \
> + resource-mgr.o
Maybe put that on a separate line like below.
> obj-y += dma-octeon.o
> obj-y += octeon-memcpy.o
> obj-y += executive/
> diff --git a/arch/mips/cavium-octeon/resource-mgr.c b/arch/mips/cavium-octeon/resource-mgr.c
> new file mode 100644
> index 000000000000..ca25fa953402
> --- /dev/null
> +++ b/arch/mips/cavium-octeon/resource-mgr.c
> @@ -0,0 +1,371 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Resource manager for Octeon.
> + *
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License. See the file "COPYING" in the main directory of this archive
> + * for more details.
> + *
> + * Copyright (C) 2017 Cavium, Inc.
> + */
> +#include <linux/module.h>
> +
> +#include <asm/octeon/octeon.h>
> +#include <asm/octeon/cvmx-bootmem.h>
> +
> +#define RESOURCE_MGR_BLOCK_NAME "cvmx-global-resources"
> +#define MAX_RESOURCES 128
> +#define INST_AVAILABLE -88
> +#define OWNER 0xbadc0de
> +
> +struct global_resource_entry {
> + struct global_resource_tag tag;
> + u64 phys_addr;
> + u64 size;
> +};
> +
> +struct global_resources {
> +#ifdef __LITTLE_ENDIAN_BITFIELD
> + u32 rlock;
> + u32 pad;
> +#else
> + u32 pad;
> + u32 rlock;
> +#endif
> + u64 entry_cnt;
> + struct global_resource_entry resource_entry[];
> +};
> +
> +static struct global_resources *res_mgr_info;
> +
> +
> +/*
> + * The resource manager interacts with software running outside of the
> + * Linux kernel, which necessitates locking to maintain data structure
> + * consistency. These custom locking functions implement the locking
> + * protocol, and cannot be replaced by kernel locking functions that
> + * may use different in-memory structures.
> + */
> +
> +static void res_mgr_lock(void)
> +{
> + unsigned int tmp;
> + u64 lock = (u64)&res_mgr_info->rlock;
presumably this could be a u32 *, avoid the cast to u64, and still work
just fine below.
> +
> + __asm__ __volatile__(
> + ".set noreorder\n"
> + "1: ll %[tmp], 0(%[addr])\n"
> + " bnez %[tmp], 1b\n"
> + " li %[tmp], 1\n"
I believe the convention for .S files is for instructions in branch
delay slots to be indented an additional space for readability. Maybe
that would be worthwhile here.
> + " sc %[tmp], 0(%[addr])\n"
> + " beqz %[tmp], 1b\n"
> + " nop\n"
and here also.
> + ".set reorder\n" :
nit: strictly speaking there's no need for \n on the last line.
> + [tmp] "=&r"(tmp) :
> + [addr] "r"(lock) :
> + "memory");
minor style thing: its far more common to have : at the beginning of the
line rather than the end.
> +}
> +
> +static void res_mgr_unlock(void)
> +{
> + u64 lock = (u64)&res_mgr_info->rlock;
same again
> +
> + /* Wait until all resource operations finish before unlocking. */
> + mb();
> + __asm__ __volatile__(
> + "sw $0, 0(%[addr])\n" : :
> + [addr] "r"(lock) :
> + "memory");
> +
> + /* Force a write buffer flush. */
> + mb();
> +}
> +
> +static int res_mgr_find_resource(struct global_resource_tag tag)
> +{
> + struct global_resource_entry *res_entry;
> + int i;
> +
> + for (i = 0; i < res_mgr_info->entry_cnt; i++) {
> + res_entry = &res_mgr_info->resource_entry[i];
> + if (res_entry->tag.lo == tag.lo && res_entry->tag.hi == tag.hi)
> + return i;
> + }
> + return -1;
> +}
> +
> +/**
> + * res_mgr_create_resource - Create a resource.
> + * @tag: Identifies the resource.
> + * @inst_cnt: Number of resource instances to create.
> + *
> + * Returns 0 if the source was created successfully.
> + * Returns <0 for error codes.
Only -1 seems to be returned. Is it worth returning some standard Linux
error codes instead?
> + */
> +int res_mgr_create_resource(struct global_resource_tag tag, int inst_cnt)
> +{
> + struct global_resource_entry *res_entry;
> + u64 size;
> + u64 *res_addr;
> + int res_index, i, rc = 0;
> +
> + res_mgr_lock();
> +
> + /* Make sure resource doesn't already exist. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index >= 0) {
> + rc = -1;
> + goto err;
> + }
> +
> + if (res_mgr_info->entry_cnt >= MAX_RESOURCES) {
> + pr_err("Resource max limit reached, not created\n");
> + rc = -1;
> + goto err;
> + }
> +
> + /*
> + * Each instance is kept in an array of u64s. The first array element
> + * holds the number of allocated instances.
> + */
> + size = sizeof(u64) * (inst_cnt + 1);
> + res_addr = cvmx_bootmem_alloc_range(size, CVMX_CACHE_LINE_SIZE, 0, 0);
> + if (!res_addr) {
> + pr_err("Failed to allocate resource. not created\n");
> + rc = -1;
> + goto err;
> + }
> +
> + /* Initialize the newly created resource. */
> + *res_addr = inst_cnt;
> + for (i = 1; i < inst_cnt + 1; i++)
or "i <= inst_cnt"?
> + *(res_addr + i) = INST_AVAILABLE;
Nit: IMO res_addr[i] is marginally more readable
> +
> + res_index = res_mgr_info->entry_cnt;
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_entry->tag.lo = tag.lo;
> + res_entry->tag.hi = tag.hi;
or res_entry->tag = tag;?
> + res_entry->phys_addr = virt_to_phys(res_addr);
> + res_entry->size = size;
> + res_mgr_info->entry_cnt++;
> +
> +err:
> + res_mgr_unlock();
> +
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_create_resource);
> +
> +/**
> + * res_mgr_alloc_range - Allocate a range of resource instances.
I don't know how strict kerndoc is on this, but I think it should be
res_mgr_alloc_range() here. Same elsewhere.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested start of instance range to allocate.
> + * Range instances are guaranteed to be sequential
> + * (-1 for don't care).
> + * @req_cnt: Number of instances to allocate.
> + * @use_last_avail: Set to request the last available instance.
> + * @inst: Updated with the allocated instances.
> + *
> + * Returns 0 if the source was created successfully.
> + * Returns <0 for error codes.
> + */
> +int res_mgr_alloc_range(struct global_resource_tag tag, int req_inst,
> + int req_cnt, bool use_last_avail, int *inst)
> +{
> + struct global_resource_entry *res_entry;
> + int res_index;
> + u64 *res_addr;
> + u64 inst_cnt;
> + int alloc_cnt, i, rc = -1;
> +
> + /* Start with no instances allocated. */
> + for (i = 0; i < req_cnt; i++)
> + inst[i] = INST_AVAILABLE;
> +
> + res_mgr_lock();
> +
> + /* Find the resource. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index < 0) {
> + pr_err("Resource not found, can't allocate instance\n");
> + goto err;
> + }
> +
> + /* Get resource data. */
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_addr = phys_to_virt(res_entry->phys_addr);
> + inst_cnt = *res_addr;
> +
> + /* Allocate the requested instances. */
> + if (req_inst >= 0) {
> + /* Specific instance range requested. */
> + if (req_inst + req_cnt >= inst_cnt) {
> + pr_err("Requested instance out of range\n");
> + goto err;
> + }
> +
> + for (i = 0; i < req_cnt; i++) {
> + if (*(res_addr + req_inst + 1 + i) == INST_AVAILABLE)
> + inst[i] = req_inst + i;
> + else {
braces on all branches if on any.
> + inst[0] = INST_AVAILABLE;
> + break;
> + }
> + }
> + } else if (use_last_avail) {
> + /* Last available instance requested. */
> + alloc_cnt = 0;
> + for (i = inst_cnt; i > 0; i--) {
> + if (*(res_addr + i) == INST_AVAILABLE) {
> + /*
> + * Instance off by 1 (first element holds the
> + * count).
> + */
> + inst[alloc_cnt] = i - 1;
> +
> + alloc_cnt++;
> + if (alloc_cnt == req_cnt)
> + break;
> + }
> + }
> +
> + if (i == 0)
> + inst[0] = INST_AVAILABLE;
> + } else {
> + /* Next available instance requested. */
> + alloc_cnt = 0;
> + for (i = 1; i <= inst_cnt; i++) {
> + if (*(res_addr + i) == INST_AVAILABLE) {
> + /*
> + * Instance off by 1 (first element holds the
> + * count).
> + */
> + inst[alloc_cnt] = i - 1;
> +
> + alloc_cnt++;
> + if (alloc_cnt == req_cnt)
> + break;
> + }
> + }
> +
> + if (i > inst_cnt)
> + inst[0] = INST_AVAILABLE;
> + }
> +
> + if (inst[0] != INST_AVAILABLE) {
> + for (i = 0; i < req_cnt; i++)
> + *(res_addr + inst[i] + 1) = OWNER;
> + rc = 0;
> + }
> +
> +err:
> + res_mgr_unlock();
> +
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_alloc_range);
> +
> +/**
> + * res_mgr_alloc - Allocate a resource instance.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to allocate (-1 for don't care).
> + * @use_last_avail: Set to request the last available instance.
> + *
> + * Returns: Allocated resource instance if successful.
> + * Returns <0 for error codes.
> + */
> +int res_mgr_alloc(struct global_resource_tag tag, int req_inst, bool use_last_avail)
> +{
> + int inst, rc;
> +
> + rc = res_mgr_alloc_range(tag, req_inst, 1, use_last_avail, &inst);
> + if (!rc)
> + return inst;
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_alloc);
> +
> +/**
> + * res_mgr_free_range - Free a resource instance range.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to free.
the parameter is called inst.
Other than these minor / style comments, it doesn't look unreasonable to
me.
Cheers
James
> + * @req_cnt: Number of instances to free.
> + */
> +void res_mgr_free_range(struct global_resource_tag tag, const int *inst, int req_cnt)
> +{
> + struct global_resource_entry *res_entry;
> + int res_index, i;
> + u64 *res_addr;
> +
> + res_mgr_lock();
> +
> + /* Find the resource. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index < 0) {
> + pr_err("Resource not found, can't free instance\n");
> + goto err;
> + }
> +
> + /* Get the resource data. */
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_addr = phys_to_virt(res_entry->phys_addr);
> +
> + /* Free the resource instances. */
> + for (i = 0; i < req_cnt; i++) {
> + /* Instance off by 1 (first element holds the count). */
> + *(res_addr + inst[i] + 1) = INST_AVAILABLE;
> + }
> +
> +err:
> + res_mgr_unlock();
> +}
> +EXPORT_SYMBOL(res_mgr_free_range);
> +
> +/**
> + * res_mgr_free - Free a resource instance.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to free.
> + */
> +void res_mgr_free(struct global_resource_tag tag, int inst)
> +{
> + res_mgr_free_range(tag, &inst, 1);
> +}
> +EXPORT_SYMBOL(res_mgr_free);
> +
> +static int __init res_mgr_init(void)
> +{
> + struct cvmx_bootmem_named_block_desc *block;
> + int block_size;
> + u64 addr;
> +
> + cvmx_bootmem_lock();
> +
> + /* Search for the resource manager data in boot memory. */
> + block = cvmx_bootmem_phy_named_block_find(RESOURCE_MGR_BLOCK_NAME, CVMX_BOOTMEM_FLAG_NO_LOCKING);
> + if (block) {
> + /* Found. */
> + res_mgr_info = phys_to_virt(block->base_addr);
> + } else {
> + /* Create it. */
> + block_size = sizeof(struct global_resources) +
> + sizeof(struct global_resource_entry) * MAX_RESOURCES;
> + addr = cvmx_bootmem_phy_named_block_alloc(block_size, 0, 0,
> + CVMX_CACHE_LINE_SIZE, RESOURCE_MGR_BLOCK_NAME,
> + CVMX_BOOTMEM_FLAG_NO_LOCKING);
> + if (!addr) {
> + pr_err("Failed to allocate name block %s\n",
> + RESOURCE_MGR_BLOCK_NAME);
> + } else {
> + res_mgr_info = phys_to_virt(addr);
> + memset(res_mgr_info, 0, block_size);
> + }
> + }
> +
> + cvmx_bootmem_unlock();
> +
> + return 0;
> +}
> +device_initcall(res_mgr_init);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cavium, Inc. Octeon resource manager");
> diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h
> index 92a17d67c1fa..0411efdb465c 100644
> --- a/arch/mips/include/asm/octeon/octeon.h
> +++ b/arch/mips/include/asm/octeon/octeon.h
> @@ -346,6 +346,24 @@ void octeon_mult_restore3_end(void);
> void octeon_mult_restore2(void);
> void octeon_mult_restore2_end(void);
>
> +/*
> + * This definition must be kept in sync with the one in
> + * cvmx-global-resources.c
> + */
> +struct global_resource_tag {
> + uint64_t lo;
> + uint64_t hi;
> +};
> +
> +void res_mgr_free(struct global_resource_tag tag, int inst);
> +void res_mgr_free_range(struct global_resource_tag tag, const int *inst,
> + int req_cnt);
> +int res_mgr_alloc(struct global_resource_tag tag, int req_inst,
> + bool use_last_avail);
> +int res_mgr_alloc_range(struct global_resource_tag tag, int req_inst,
> + int req_cnt, bool use_last_avail, int *inst);
> +int res_mgr_create_resource(struct global_resource_tag tag, int inst_cnt);
> +
> /**
> * Read a 32bit value from the Octeon NPI register space
> *
> --
> 2.14.3
>
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
WARNING: multiple messages have this Message-ID (diff)
From: James Hogan <james.hogan-8NJIiSa5LzA@public.gmane.org>
To: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
Cc: linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org,
ralf-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org,
netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
"David S. Miller" <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>,
Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>,
devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b@public.gmane.org,
Greg Kroah-Hartman
<gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
"Steven J. Hill"
<steven.hill-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>,
Florian Fainelli
<f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
Carlos Munoz <cmunoz-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
Subject: Re: [PATCH v4 3/8] MIPS: Octeon: Add a global resource manager.
Date: Thu, 30 Nov 2017 22:53:33 +0000 [thread overview]
Message-ID: <20171130225333.GI27409@jhogan-linux.mipstec.com> (raw)
In-Reply-To: <20171129005540.28829-4-david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 14219 bytes --]
On Tue, Nov 28, 2017 at 04:55:35PM -0800, David Daney wrote:
> From: Carlos Munoz <cmunoz-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>
> Add a global resource manager to manage tagged pointers within
> bootmem allocated memory. This is used by various functional
> blocks in the Octeon core like the FPA, Ethernet nexus, etc.
>
> Signed-off-by: Carlos Munoz <cmunoz-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Steven J. Hill <Steven.Hill-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> Signed-off-by: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> ---
> arch/mips/cavium-octeon/Makefile | 3 +-
> arch/mips/cavium-octeon/resource-mgr.c | 371 +++++++++++++++++++++++++++++++++
> arch/mips/include/asm/octeon/octeon.h | 18 ++
> 3 files changed, 391 insertions(+), 1 deletion(-)
> create mode 100644 arch/mips/cavium-octeon/resource-mgr.c
>
> diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
> index 7c02e542959a..0a299ab8719f 100644
> --- a/arch/mips/cavium-octeon/Makefile
> +++ b/arch/mips/cavium-octeon/Makefile
> @@ -9,7 +9,8 @@
> # Copyright (C) 2005-2009 Cavium Networks
> #
>
> -obj-y := cpu.o setup.o octeon-platform.o octeon-irq.o csrc-octeon.o
> +obj-y := cpu.o setup.o octeon-platform.o octeon-irq.o csrc-octeon.o \
> + resource-mgr.o
Maybe put that on a separate line like below.
> obj-y += dma-octeon.o
> obj-y += octeon-memcpy.o
> obj-y += executive/
> diff --git a/arch/mips/cavium-octeon/resource-mgr.c b/arch/mips/cavium-octeon/resource-mgr.c
> new file mode 100644
> index 000000000000..ca25fa953402
> --- /dev/null
> +++ b/arch/mips/cavium-octeon/resource-mgr.c
> @@ -0,0 +1,371 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Resource manager for Octeon.
> + *
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License. See the file "COPYING" in the main directory of this archive
> + * for more details.
> + *
> + * Copyright (C) 2017 Cavium, Inc.
> + */
> +#include <linux/module.h>
> +
> +#include <asm/octeon/octeon.h>
> +#include <asm/octeon/cvmx-bootmem.h>
> +
> +#define RESOURCE_MGR_BLOCK_NAME "cvmx-global-resources"
> +#define MAX_RESOURCES 128
> +#define INST_AVAILABLE -88
> +#define OWNER 0xbadc0de
> +
> +struct global_resource_entry {
> + struct global_resource_tag tag;
> + u64 phys_addr;
> + u64 size;
> +};
> +
> +struct global_resources {
> +#ifdef __LITTLE_ENDIAN_BITFIELD
> + u32 rlock;
> + u32 pad;
> +#else
> + u32 pad;
> + u32 rlock;
> +#endif
> + u64 entry_cnt;
> + struct global_resource_entry resource_entry[];
> +};
> +
> +static struct global_resources *res_mgr_info;
> +
> +
> +/*
> + * The resource manager interacts with software running outside of the
> + * Linux kernel, which necessitates locking to maintain data structure
> + * consistency. These custom locking functions implement the locking
> + * protocol, and cannot be replaced by kernel locking functions that
> + * may use different in-memory structures.
> + */
> +
> +static void res_mgr_lock(void)
> +{
> + unsigned int tmp;
> + u64 lock = (u64)&res_mgr_info->rlock;
presumably this could be a u32 *, avoid the cast to u64, and still work
just fine below.
> +
> + __asm__ __volatile__(
> + ".set noreorder\n"
> + "1: ll %[tmp], 0(%[addr])\n"
> + " bnez %[tmp], 1b\n"
> + " li %[tmp], 1\n"
I believe the convention for .S files is for instructions in branch
delay slots to be indented an additional space for readability. Maybe
that would be worthwhile here.
> + " sc %[tmp], 0(%[addr])\n"
> + " beqz %[tmp], 1b\n"
> + " nop\n"
and here also.
> + ".set reorder\n" :
nit: strictly speaking there's no need for \n on the last line.
> + [tmp] "=&r"(tmp) :
> + [addr] "r"(lock) :
> + "memory");
minor style thing: its far more common to have : at the beginning of the
line rather than the end.
> +}
> +
> +static void res_mgr_unlock(void)
> +{
> + u64 lock = (u64)&res_mgr_info->rlock;
same again
> +
> + /* Wait until all resource operations finish before unlocking. */
> + mb();
> + __asm__ __volatile__(
> + "sw $0, 0(%[addr])\n" : :
> + [addr] "r"(lock) :
> + "memory");
> +
> + /* Force a write buffer flush. */
> + mb();
> +}
> +
> +static int res_mgr_find_resource(struct global_resource_tag tag)
> +{
> + struct global_resource_entry *res_entry;
> + int i;
> +
> + for (i = 0; i < res_mgr_info->entry_cnt; i++) {
> + res_entry = &res_mgr_info->resource_entry[i];
> + if (res_entry->tag.lo == tag.lo && res_entry->tag.hi == tag.hi)
> + return i;
> + }
> + return -1;
> +}
> +
> +/**
> + * res_mgr_create_resource - Create a resource.
> + * @tag: Identifies the resource.
> + * @inst_cnt: Number of resource instances to create.
> + *
> + * Returns 0 if the source was created successfully.
> + * Returns <0 for error codes.
Only -1 seems to be returned. Is it worth returning some standard Linux
error codes instead?
> + */
> +int res_mgr_create_resource(struct global_resource_tag tag, int inst_cnt)
> +{
> + struct global_resource_entry *res_entry;
> + u64 size;
> + u64 *res_addr;
> + int res_index, i, rc = 0;
> +
> + res_mgr_lock();
> +
> + /* Make sure resource doesn't already exist. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index >= 0) {
> + rc = -1;
> + goto err;
> + }
> +
> + if (res_mgr_info->entry_cnt >= MAX_RESOURCES) {
> + pr_err("Resource max limit reached, not created\n");
> + rc = -1;
> + goto err;
> + }
> +
> + /*
> + * Each instance is kept in an array of u64s. The first array element
> + * holds the number of allocated instances.
> + */
> + size = sizeof(u64) * (inst_cnt + 1);
> + res_addr = cvmx_bootmem_alloc_range(size, CVMX_CACHE_LINE_SIZE, 0, 0);
> + if (!res_addr) {
> + pr_err("Failed to allocate resource. not created\n");
> + rc = -1;
> + goto err;
> + }
> +
> + /* Initialize the newly created resource. */
> + *res_addr = inst_cnt;
> + for (i = 1; i < inst_cnt + 1; i++)
or "i <= inst_cnt"?
> + *(res_addr + i) = INST_AVAILABLE;
Nit: IMO res_addr[i] is marginally more readable
> +
> + res_index = res_mgr_info->entry_cnt;
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_entry->tag.lo = tag.lo;
> + res_entry->tag.hi = tag.hi;
or res_entry->tag = tag;?
> + res_entry->phys_addr = virt_to_phys(res_addr);
> + res_entry->size = size;
> + res_mgr_info->entry_cnt++;
> +
> +err:
> + res_mgr_unlock();
> +
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_create_resource);
> +
> +/**
> + * res_mgr_alloc_range - Allocate a range of resource instances.
I don't know how strict kerndoc is on this, but I think it should be
res_mgr_alloc_range() here. Same elsewhere.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested start of instance range to allocate.
> + * Range instances are guaranteed to be sequential
> + * (-1 for don't care).
> + * @req_cnt: Number of instances to allocate.
> + * @use_last_avail: Set to request the last available instance.
> + * @inst: Updated with the allocated instances.
> + *
> + * Returns 0 if the source was created successfully.
> + * Returns <0 for error codes.
> + */
> +int res_mgr_alloc_range(struct global_resource_tag tag, int req_inst,
> + int req_cnt, bool use_last_avail, int *inst)
> +{
> + struct global_resource_entry *res_entry;
> + int res_index;
> + u64 *res_addr;
> + u64 inst_cnt;
> + int alloc_cnt, i, rc = -1;
> +
> + /* Start with no instances allocated. */
> + for (i = 0; i < req_cnt; i++)
> + inst[i] = INST_AVAILABLE;
> +
> + res_mgr_lock();
> +
> + /* Find the resource. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index < 0) {
> + pr_err("Resource not found, can't allocate instance\n");
> + goto err;
> + }
> +
> + /* Get resource data. */
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_addr = phys_to_virt(res_entry->phys_addr);
> + inst_cnt = *res_addr;
> +
> + /* Allocate the requested instances. */
> + if (req_inst >= 0) {
> + /* Specific instance range requested. */
> + if (req_inst + req_cnt >= inst_cnt) {
> + pr_err("Requested instance out of range\n");
> + goto err;
> + }
> +
> + for (i = 0; i < req_cnt; i++) {
> + if (*(res_addr + req_inst + 1 + i) == INST_AVAILABLE)
> + inst[i] = req_inst + i;
> + else {
braces on all branches if on any.
> + inst[0] = INST_AVAILABLE;
> + break;
> + }
> + }
> + } else if (use_last_avail) {
> + /* Last available instance requested. */
> + alloc_cnt = 0;
> + for (i = inst_cnt; i > 0; i--) {
> + if (*(res_addr + i) == INST_AVAILABLE) {
> + /*
> + * Instance off by 1 (first element holds the
> + * count).
> + */
> + inst[alloc_cnt] = i - 1;
> +
> + alloc_cnt++;
> + if (alloc_cnt == req_cnt)
> + break;
> + }
> + }
> +
> + if (i == 0)
> + inst[0] = INST_AVAILABLE;
> + } else {
> + /* Next available instance requested. */
> + alloc_cnt = 0;
> + for (i = 1; i <= inst_cnt; i++) {
> + if (*(res_addr + i) == INST_AVAILABLE) {
> + /*
> + * Instance off by 1 (first element holds the
> + * count).
> + */
> + inst[alloc_cnt] = i - 1;
> +
> + alloc_cnt++;
> + if (alloc_cnt == req_cnt)
> + break;
> + }
> + }
> +
> + if (i > inst_cnt)
> + inst[0] = INST_AVAILABLE;
> + }
> +
> + if (inst[0] != INST_AVAILABLE) {
> + for (i = 0; i < req_cnt; i++)
> + *(res_addr + inst[i] + 1) = OWNER;
> + rc = 0;
> + }
> +
> +err:
> + res_mgr_unlock();
> +
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_alloc_range);
> +
> +/**
> + * res_mgr_alloc - Allocate a resource instance.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to allocate (-1 for don't care).
> + * @use_last_avail: Set to request the last available instance.
> + *
> + * Returns: Allocated resource instance if successful.
> + * Returns <0 for error codes.
> + */
> +int res_mgr_alloc(struct global_resource_tag tag, int req_inst, bool use_last_avail)
> +{
> + int inst, rc;
> +
> + rc = res_mgr_alloc_range(tag, req_inst, 1, use_last_avail, &inst);
> + if (!rc)
> + return inst;
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_alloc);
> +
> +/**
> + * res_mgr_free_range - Free a resource instance range.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to free.
the parameter is called inst.
Other than these minor / style comments, it doesn't look unreasonable to
me.
Cheers
James
> + * @req_cnt: Number of instances to free.
> + */
> +void res_mgr_free_range(struct global_resource_tag tag, const int *inst, int req_cnt)
> +{
> + struct global_resource_entry *res_entry;
> + int res_index, i;
> + u64 *res_addr;
> +
> + res_mgr_lock();
> +
> + /* Find the resource. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index < 0) {
> + pr_err("Resource not found, can't free instance\n");
> + goto err;
> + }
> +
> + /* Get the resource data. */
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_addr = phys_to_virt(res_entry->phys_addr);
> +
> + /* Free the resource instances. */
> + for (i = 0; i < req_cnt; i++) {
> + /* Instance off by 1 (first element holds the count). */
> + *(res_addr + inst[i] + 1) = INST_AVAILABLE;
> + }
> +
> +err:
> + res_mgr_unlock();
> +}
> +EXPORT_SYMBOL(res_mgr_free_range);
> +
> +/**
> + * res_mgr_free - Free a resource instance.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to free.
> + */
> +void res_mgr_free(struct global_resource_tag tag, int inst)
> +{
> + res_mgr_free_range(tag, &inst, 1);
> +}
> +EXPORT_SYMBOL(res_mgr_free);
> +
> +static int __init res_mgr_init(void)
> +{
> + struct cvmx_bootmem_named_block_desc *block;
> + int block_size;
> + u64 addr;
> +
> + cvmx_bootmem_lock();
> +
> + /* Search for the resource manager data in boot memory. */
> + block = cvmx_bootmem_phy_named_block_find(RESOURCE_MGR_BLOCK_NAME, CVMX_BOOTMEM_FLAG_NO_LOCKING);
> + if (block) {
> + /* Found. */
> + res_mgr_info = phys_to_virt(block->base_addr);
> + } else {
> + /* Create it. */
> + block_size = sizeof(struct global_resources) +
> + sizeof(struct global_resource_entry) * MAX_RESOURCES;
> + addr = cvmx_bootmem_phy_named_block_alloc(block_size, 0, 0,
> + CVMX_CACHE_LINE_SIZE, RESOURCE_MGR_BLOCK_NAME,
> + CVMX_BOOTMEM_FLAG_NO_LOCKING);
> + if (!addr) {
> + pr_err("Failed to allocate name block %s\n",
> + RESOURCE_MGR_BLOCK_NAME);
> + } else {
> + res_mgr_info = phys_to_virt(addr);
> + memset(res_mgr_info, 0, block_size);
> + }
> + }
> +
> + cvmx_bootmem_unlock();
> +
> + return 0;
> +}
> +device_initcall(res_mgr_init);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cavium, Inc. Octeon resource manager");
> diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h
> index 92a17d67c1fa..0411efdb465c 100644
> --- a/arch/mips/include/asm/octeon/octeon.h
> +++ b/arch/mips/include/asm/octeon/octeon.h
> @@ -346,6 +346,24 @@ void octeon_mult_restore3_end(void);
> void octeon_mult_restore2(void);
> void octeon_mult_restore2_end(void);
>
> +/*
> + * This definition must be kept in sync with the one in
> + * cvmx-global-resources.c
> + */
> +struct global_resource_tag {
> + uint64_t lo;
> + uint64_t hi;
> +};
> +
> +void res_mgr_free(struct global_resource_tag tag, int inst);
> +void res_mgr_free_range(struct global_resource_tag tag, const int *inst,
> + int req_cnt);
> +int res_mgr_alloc(struct global_resource_tag tag, int req_inst,
> + bool use_last_avail);
> +int res_mgr_alloc_range(struct global_resource_tag tag, int req_inst,
> + int req_cnt, bool use_last_avail, int *inst);
> +int res_mgr_create_resource(struct global_resource_tag tag, int inst_cnt);
> +
> /**
> * Read a 32bit value from the Octeon NPI register space
> *
> --
> 2.14.3
>
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
WARNING: multiple messages have this Message-ID (diff)
From: James Hogan <james.hogan-8NJIiSa5LzA@public.gmane.org>
To: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
Cc: <linux-mips-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org>,
<ralf-6z/3iImG2C8G8FEW9MqTrA@public.gmane.org>,
<netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
"David S. Miller" <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>,
"Rob Herring" <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>,
<devel-gWbeCf7V1WCQmaza687I9mD2FQJk+8+b@public.gmane.org>,
Greg Kroah-Hartman
<gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>,
<linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
"Steven J. Hill"
<steven.hill-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>,
<devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org>,
Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>,
Florian Fainelli
<f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>,
Carlos Munoz <cmunoz-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
Subject: Re: [PATCH v4 3/8] MIPS: Octeon: Add a global resource manager.
Date: Thu, 30 Nov 2017 22:53:33 +0000 [thread overview]
Message-ID: <20171130225333.GI27409@jhogan-linux.mipstec.com> (raw)
In-Reply-To: <20171129005540.28829-4-david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 14219 bytes --]
On Tue, Nov 28, 2017 at 04:55:35PM -0800, David Daney wrote:
> From: Carlos Munoz <cmunoz-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>
> Add a global resource manager to manage tagged pointers within
> bootmem allocated memory. This is used by various functional
> blocks in the Octeon core like the FPA, Ethernet nexus, etc.
>
> Signed-off-by: Carlos Munoz <cmunoz-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Steven J. Hill <Steven.Hill-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> Signed-off-by: David Daney <david.daney-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> ---
> arch/mips/cavium-octeon/Makefile | 3 +-
> arch/mips/cavium-octeon/resource-mgr.c | 371 +++++++++++++++++++++++++++++++++
> arch/mips/include/asm/octeon/octeon.h | 18 ++
> 3 files changed, 391 insertions(+), 1 deletion(-)
> create mode 100644 arch/mips/cavium-octeon/resource-mgr.c
>
> diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
> index 7c02e542959a..0a299ab8719f 100644
> --- a/arch/mips/cavium-octeon/Makefile
> +++ b/arch/mips/cavium-octeon/Makefile
> @@ -9,7 +9,8 @@
> # Copyright (C) 2005-2009 Cavium Networks
> #
>
> -obj-y := cpu.o setup.o octeon-platform.o octeon-irq.o csrc-octeon.o
> +obj-y := cpu.o setup.o octeon-platform.o octeon-irq.o csrc-octeon.o \
> + resource-mgr.o
Maybe put that on a separate line like below.
> obj-y += dma-octeon.o
> obj-y += octeon-memcpy.o
> obj-y += executive/
> diff --git a/arch/mips/cavium-octeon/resource-mgr.c b/arch/mips/cavium-octeon/resource-mgr.c
> new file mode 100644
> index 000000000000..ca25fa953402
> --- /dev/null
> +++ b/arch/mips/cavium-octeon/resource-mgr.c
> @@ -0,0 +1,371 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Resource manager for Octeon.
> + *
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License. See the file "COPYING" in the main directory of this archive
> + * for more details.
> + *
> + * Copyright (C) 2017 Cavium, Inc.
> + */
> +#include <linux/module.h>
> +
> +#include <asm/octeon/octeon.h>
> +#include <asm/octeon/cvmx-bootmem.h>
> +
> +#define RESOURCE_MGR_BLOCK_NAME "cvmx-global-resources"
> +#define MAX_RESOURCES 128
> +#define INST_AVAILABLE -88
> +#define OWNER 0xbadc0de
> +
> +struct global_resource_entry {
> + struct global_resource_tag tag;
> + u64 phys_addr;
> + u64 size;
> +};
> +
> +struct global_resources {
> +#ifdef __LITTLE_ENDIAN_BITFIELD
> + u32 rlock;
> + u32 pad;
> +#else
> + u32 pad;
> + u32 rlock;
> +#endif
> + u64 entry_cnt;
> + struct global_resource_entry resource_entry[];
> +};
> +
> +static struct global_resources *res_mgr_info;
> +
> +
> +/*
> + * The resource manager interacts with software running outside of the
> + * Linux kernel, which necessitates locking to maintain data structure
> + * consistency. These custom locking functions implement the locking
> + * protocol, and cannot be replaced by kernel locking functions that
> + * may use different in-memory structures.
> + */
> +
> +static void res_mgr_lock(void)
> +{
> + unsigned int tmp;
> + u64 lock = (u64)&res_mgr_info->rlock;
presumably this could be a u32 *, avoid the cast to u64, and still work
just fine below.
> +
> + __asm__ __volatile__(
> + ".set noreorder\n"
> + "1: ll %[tmp], 0(%[addr])\n"
> + " bnez %[tmp], 1b\n"
> + " li %[tmp], 1\n"
I believe the convention for .S files is for instructions in branch
delay slots to be indented an additional space for readability. Maybe
that would be worthwhile here.
> + " sc %[tmp], 0(%[addr])\n"
> + " beqz %[tmp], 1b\n"
> + " nop\n"
and here also.
> + ".set reorder\n" :
nit: strictly speaking there's no need for \n on the last line.
> + [tmp] "=&r"(tmp) :
> + [addr] "r"(lock) :
> + "memory");
minor style thing: its far more common to have : at the beginning of the
line rather than the end.
> +}
> +
> +static void res_mgr_unlock(void)
> +{
> + u64 lock = (u64)&res_mgr_info->rlock;
same again
> +
> + /* Wait until all resource operations finish before unlocking. */
> + mb();
> + __asm__ __volatile__(
> + "sw $0, 0(%[addr])\n" : :
> + [addr] "r"(lock) :
> + "memory");
> +
> + /* Force a write buffer flush. */
> + mb();
> +}
> +
> +static int res_mgr_find_resource(struct global_resource_tag tag)
> +{
> + struct global_resource_entry *res_entry;
> + int i;
> +
> + for (i = 0; i < res_mgr_info->entry_cnt; i++) {
> + res_entry = &res_mgr_info->resource_entry[i];
> + if (res_entry->tag.lo == tag.lo && res_entry->tag.hi == tag.hi)
> + return i;
> + }
> + return -1;
> +}
> +
> +/**
> + * res_mgr_create_resource - Create a resource.
> + * @tag: Identifies the resource.
> + * @inst_cnt: Number of resource instances to create.
> + *
> + * Returns 0 if the source was created successfully.
> + * Returns <0 for error codes.
Only -1 seems to be returned. Is it worth returning some standard Linux
error codes instead?
> + */
> +int res_mgr_create_resource(struct global_resource_tag tag, int inst_cnt)
> +{
> + struct global_resource_entry *res_entry;
> + u64 size;
> + u64 *res_addr;
> + int res_index, i, rc = 0;
> +
> + res_mgr_lock();
> +
> + /* Make sure resource doesn't already exist. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index >= 0) {
> + rc = -1;
> + goto err;
> + }
> +
> + if (res_mgr_info->entry_cnt >= MAX_RESOURCES) {
> + pr_err("Resource max limit reached, not created\n");
> + rc = -1;
> + goto err;
> + }
> +
> + /*
> + * Each instance is kept in an array of u64s. The first array element
> + * holds the number of allocated instances.
> + */
> + size = sizeof(u64) * (inst_cnt + 1);
> + res_addr = cvmx_bootmem_alloc_range(size, CVMX_CACHE_LINE_SIZE, 0, 0);
> + if (!res_addr) {
> + pr_err("Failed to allocate resource. not created\n");
> + rc = -1;
> + goto err;
> + }
> +
> + /* Initialize the newly created resource. */
> + *res_addr = inst_cnt;
> + for (i = 1; i < inst_cnt + 1; i++)
or "i <= inst_cnt"?
> + *(res_addr + i) = INST_AVAILABLE;
Nit: IMO res_addr[i] is marginally more readable
> +
> + res_index = res_mgr_info->entry_cnt;
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_entry->tag.lo = tag.lo;
> + res_entry->tag.hi = tag.hi;
or res_entry->tag = tag;?
> + res_entry->phys_addr = virt_to_phys(res_addr);
> + res_entry->size = size;
> + res_mgr_info->entry_cnt++;
> +
> +err:
> + res_mgr_unlock();
> +
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_create_resource);
> +
> +/**
> + * res_mgr_alloc_range - Allocate a range of resource instances.
I don't know how strict kerndoc is on this, but I think it should be
res_mgr_alloc_range() here. Same elsewhere.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested start of instance range to allocate.
> + * Range instances are guaranteed to be sequential
> + * (-1 for don't care).
> + * @req_cnt: Number of instances to allocate.
> + * @use_last_avail: Set to request the last available instance.
> + * @inst: Updated with the allocated instances.
> + *
> + * Returns 0 if the source was created successfully.
> + * Returns <0 for error codes.
> + */
> +int res_mgr_alloc_range(struct global_resource_tag tag, int req_inst,
> + int req_cnt, bool use_last_avail, int *inst)
> +{
> + struct global_resource_entry *res_entry;
> + int res_index;
> + u64 *res_addr;
> + u64 inst_cnt;
> + int alloc_cnt, i, rc = -1;
> +
> + /* Start with no instances allocated. */
> + for (i = 0; i < req_cnt; i++)
> + inst[i] = INST_AVAILABLE;
> +
> + res_mgr_lock();
> +
> + /* Find the resource. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index < 0) {
> + pr_err("Resource not found, can't allocate instance\n");
> + goto err;
> + }
> +
> + /* Get resource data. */
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_addr = phys_to_virt(res_entry->phys_addr);
> + inst_cnt = *res_addr;
> +
> + /* Allocate the requested instances. */
> + if (req_inst >= 0) {
> + /* Specific instance range requested. */
> + if (req_inst + req_cnt >= inst_cnt) {
> + pr_err("Requested instance out of range\n");
> + goto err;
> + }
> +
> + for (i = 0; i < req_cnt; i++) {
> + if (*(res_addr + req_inst + 1 + i) == INST_AVAILABLE)
> + inst[i] = req_inst + i;
> + else {
braces on all branches if on any.
> + inst[0] = INST_AVAILABLE;
> + break;
> + }
> + }
> + } else if (use_last_avail) {
> + /* Last available instance requested. */
> + alloc_cnt = 0;
> + for (i = inst_cnt; i > 0; i--) {
> + if (*(res_addr + i) == INST_AVAILABLE) {
> + /*
> + * Instance off by 1 (first element holds the
> + * count).
> + */
> + inst[alloc_cnt] = i - 1;
> +
> + alloc_cnt++;
> + if (alloc_cnt == req_cnt)
> + break;
> + }
> + }
> +
> + if (i == 0)
> + inst[0] = INST_AVAILABLE;
> + } else {
> + /* Next available instance requested. */
> + alloc_cnt = 0;
> + for (i = 1; i <= inst_cnt; i++) {
> + if (*(res_addr + i) == INST_AVAILABLE) {
> + /*
> + * Instance off by 1 (first element holds the
> + * count).
> + */
> + inst[alloc_cnt] = i - 1;
> +
> + alloc_cnt++;
> + if (alloc_cnt == req_cnt)
> + break;
> + }
> + }
> +
> + if (i > inst_cnt)
> + inst[0] = INST_AVAILABLE;
> + }
> +
> + if (inst[0] != INST_AVAILABLE) {
> + for (i = 0; i < req_cnt; i++)
> + *(res_addr + inst[i] + 1) = OWNER;
> + rc = 0;
> + }
> +
> +err:
> + res_mgr_unlock();
> +
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_alloc_range);
> +
> +/**
> + * res_mgr_alloc - Allocate a resource instance.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to allocate (-1 for don't care).
> + * @use_last_avail: Set to request the last available instance.
> + *
> + * Returns: Allocated resource instance if successful.
> + * Returns <0 for error codes.
> + */
> +int res_mgr_alloc(struct global_resource_tag tag, int req_inst, bool use_last_avail)
> +{
> + int inst, rc;
> +
> + rc = res_mgr_alloc_range(tag, req_inst, 1, use_last_avail, &inst);
> + if (!rc)
> + return inst;
> + return rc;
> +}
> +EXPORT_SYMBOL(res_mgr_alloc);
> +
> +/**
> + * res_mgr_free_range - Free a resource instance range.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to free.
the parameter is called inst.
Other than these minor / style comments, it doesn't look unreasonable to
me.
Cheers
James
> + * @req_cnt: Number of instances to free.
> + */
> +void res_mgr_free_range(struct global_resource_tag tag, const int *inst, int req_cnt)
> +{
> + struct global_resource_entry *res_entry;
> + int res_index, i;
> + u64 *res_addr;
> +
> + res_mgr_lock();
> +
> + /* Find the resource. */
> + res_index = res_mgr_find_resource(tag);
> + if (res_index < 0) {
> + pr_err("Resource not found, can't free instance\n");
> + goto err;
> + }
> +
> + /* Get the resource data. */
> + res_entry = &res_mgr_info->resource_entry[res_index];
> + res_addr = phys_to_virt(res_entry->phys_addr);
> +
> + /* Free the resource instances. */
> + for (i = 0; i < req_cnt; i++) {
> + /* Instance off by 1 (first element holds the count). */
> + *(res_addr + inst[i] + 1) = INST_AVAILABLE;
> + }
> +
> +err:
> + res_mgr_unlock();
> +}
> +EXPORT_SYMBOL(res_mgr_free_range);
> +
> +/**
> + * res_mgr_free - Free a resource instance.
> + * @tag: Identifies the resource.
> + * @req_inst: Requested instance to free.
> + */
> +void res_mgr_free(struct global_resource_tag tag, int inst)
> +{
> + res_mgr_free_range(tag, &inst, 1);
> +}
> +EXPORT_SYMBOL(res_mgr_free);
> +
> +static int __init res_mgr_init(void)
> +{
> + struct cvmx_bootmem_named_block_desc *block;
> + int block_size;
> + u64 addr;
> +
> + cvmx_bootmem_lock();
> +
> + /* Search for the resource manager data in boot memory. */
> + block = cvmx_bootmem_phy_named_block_find(RESOURCE_MGR_BLOCK_NAME, CVMX_BOOTMEM_FLAG_NO_LOCKING);
> + if (block) {
> + /* Found. */
> + res_mgr_info = phys_to_virt(block->base_addr);
> + } else {
> + /* Create it. */
> + block_size = sizeof(struct global_resources) +
> + sizeof(struct global_resource_entry) * MAX_RESOURCES;
> + addr = cvmx_bootmem_phy_named_block_alloc(block_size, 0, 0,
> + CVMX_CACHE_LINE_SIZE, RESOURCE_MGR_BLOCK_NAME,
> + CVMX_BOOTMEM_FLAG_NO_LOCKING);
> + if (!addr) {
> + pr_err("Failed to allocate name block %s\n",
> + RESOURCE_MGR_BLOCK_NAME);
> + } else {
> + res_mgr_info = phys_to_virt(addr);
> + memset(res_mgr_info, 0, block_size);
> + }
> + }
> +
> + cvmx_bootmem_unlock();
> +
> + return 0;
> +}
> +device_initcall(res_mgr_init);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("Cavium, Inc. Octeon resource manager");
> diff --git a/arch/mips/include/asm/octeon/octeon.h b/arch/mips/include/asm/octeon/octeon.h
> index 92a17d67c1fa..0411efdb465c 100644
> --- a/arch/mips/include/asm/octeon/octeon.h
> +++ b/arch/mips/include/asm/octeon/octeon.h
> @@ -346,6 +346,24 @@ void octeon_mult_restore3_end(void);
> void octeon_mult_restore2(void);
> void octeon_mult_restore2_end(void);
>
> +/*
> + * This definition must be kept in sync with the one in
> + * cvmx-global-resources.c
> + */
> +struct global_resource_tag {
> + uint64_t lo;
> + uint64_t hi;
> +};
> +
> +void res_mgr_free(struct global_resource_tag tag, int inst);
> +void res_mgr_free_range(struct global_resource_tag tag, const int *inst,
> + int req_cnt);
> +int res_mgr_alloc(struct global_resource_tag tag, int req_inst,
> + bool use_last_avail);
> +int res_mgr_alloc_range(struct global_resource_tag tag, int req_inst,
> + int req_cnt, bool use_last_avail, int *inst);
> +int res_mgr_create_resource(struct global_resource_tag tag, int inst_cnt);
> +
> /**
> * Read a 32bit value from the Octeon NPI register space
> *
> --
> 2.14.3
>
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
next prev parent reply other threads:[~2017-11-30 22:54 UTC|newest]
Thread overview: 69+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-11-29 0:55 [PATCH v4 0/8] Cavium OCTEON-III network driver David Daney
2017-11-29 0:55 ` David Daney
2017-11-29 0:55 ` [PATCH v4 1/8] dt-bindings: Add Cavium Octeon Common Ethernet Interface David Daney
2017-11-29 0:55 ` David Daney
2017-11-29 2:01 ` Andrew Lunn
2017-11-29 2:01 ` Andrew Lunn
2017-11-29 2:54 ` David Daney
2017-11-29 0:55 ` [PATCH v4 2/8] MIPS: Octeon: Enable LMTDMA/LMTST operations David Daney
2017-11-29 0:55 ` David Daney
2017-11-30 21:36 ` James Hogan
2017-11-30 21:36 ` James Hogan
2017-11-30 21:36 ` James Hogan
2017-11-30 21:49 ` David Daney
2017-11-30 21:49 ` David Daney
2017-11-30 22:56 ` James Hogan
2017-11-30 22:56 ` James Hogan
2017-11-30 23:09 ` David Daney
2017-11-30 23:09 ` David Daney
2017-11-30 23:12 ` James Hogan
2017-11-30 23:12 ` James Hogan
2017-11-30 23:12 ` James Hogan
2017-11-30 23:12 ` James Hogan
2017-11-29 0:55 ` [PATCH v4 3/8] MIPS: Octeon: Add a global resource manager David Daney
2017-11-30 22:53 ` James Hogan [this message]
2017-11-30 22:53 ` James Hogan
2017-11-30 22:53 ` James Hogan
2017-11-30 22:53 ` James Hogan
2017-12-01 1:51 ` David Daney
2017-12-01 1:51 ` David Daney
2017-12-01 7:53 ` Philippe Ombredanne
2017-12-01 17:42 ` David Daney
2017-12-01 19:49 ` Philippe Ombredanne
2017-12-01 20:01 ` David Daney
2017-12-01 20:41 ` Philippe Ombredanne
2017-12-01 20:56 ` David Daney
2017-12-01 20:56 ` David Daney
2017-12-01 23:33 ` Philippe Ombredanne
2017-12-01 23:33 ` Philippe Ombredanne
2017-11-29 0:55 ` [PATCH v4 4/8] MIPS: Octeon: Add Free Pointer Unit (FPA) support David Daney
2017-11-29 0:55 ` David Daney
2017-11-29 0:55 ` David Daney
2017-11-29 0:55 ` [PATCH v4 5/8] MIPS: Octeon: Automatically provision CVMSEG space David Daney
2017-11-29 0:55 ` David Daney
2017-11-29 0:55 ` [PATCH v4 6/8] staging: octeon: Remove USE_ASYNC_IOBDMA macro David Daney
2017-11-29 0:55 ` David Daney
2017-12-07 14:28 ` Greg Kroah-Hartman
2017-12-07 14:28 ` Greg Kroah-Hartman
2017-11-29 0:55 ` [PATCH v4 7/8] netdev: octeon-ethernet: Add Cavium Octeon III support David Daney
2017-11-29 10:30 ` Souptick Joarder
2017-11-29 10:30 ` Souptick Joarder
2017-11-29 13:47 ` Andrew Lunn
2017-11-29 13:47 ` Andrew Lunn
2017-11-29 16:07 ` Souptick Joarder
2017-11-29 16:07 ` Souptick Joarder
2017-11-29 19:11 ` Dan Carpenter
2017-11-29 19:11 ` Dan Carpenter
2017-11-29 22:16 ` Andrew Lunn
2017-11-29 22:16 ` Andrew Lunn
2017-11-29 19:20 ` David Daney
2017-11-29 19:20 ` David Daney
2017-11-30 7:12 ` Souptick Joarder
2017-11-29 22:56 ` Andrew Lunn
2017-11-29 22:56 ` Andrew Lunn
2017-11-29 23:04 ` David Daney
2017-11-29 23:04 ` David Daney
2017-11-29 0:55 ` [PATCH v4 8/8] MAINTAINERS: Add entry for drivers/net/ethernet/cavium/octeon/octeon3-* David Daney
2017-11-29 0:55 ` David Daney
2017-11-29 14:18 ` [PATCH v4 0/8] Cavium OCTEON-III network driver David Miller
2017-11-29 14:18 ` David Miller
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20171130225333.GI27409@jhogan-linux.mipstec.com \
--to=james.hogan@mips.com \
--cc=andrew@lunn.ch \
--cc=cmunoz@cavium.com \
--cc=davem@davemloft.net \
--cc=david.daney@cavium.com \
--cc=devel@driverdev.osuosl.org \
--cc=devicetree@vger.kernel.org \
--cc=f.fainelli@gmail.com \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mips@linux-mips.org \
--cc=mark.rutland@arm.com \
--cc=netdev@vger.kernel.org \
--cc=ralf@linux-mips.org \
--cc=robh+dt@kernel.org \
--cc=steven.hill@cavium.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.