From: Robert Jennings <hidden> Date: 2008-06-12 21:54:46
Cooperative Memory Overcommitment (CMO) is a pSeries platform feature
that enables the allocation of more memory to a set logical partitions
than is physically present. For example, a system with 16Gb of memory
can be configured to simultaneously run 3 logical partitions each with
8Gb of memory allocated to them.
The system firmware can page out memory as needed to meet the needs
of each partition. To minimize the effects of firmware paging memory,
the Collaborative Memory Manager (CMM) driver acts as a balloon driver
to work with firmware to provide memory ahead of any paging needs.
The OS is provided with an entitlement of IO memory for device drivers
to map. This amount varies with the number of virtual IO adapters
present and can change as devices are hot-plugged. The VIO bus code
distributes this memory to devices. Logical partitions supporting CMO
may only have virtual IO devices, physical devices are not supported.
Above the entitled level, IO mappings can fail and the IOMMU needed be
updated to handle this change.
Virtual IO adapters have been updated to handle DMA mapping failures and
to size their entitlement needs.
Platform support for for CMM and hot-plug entitlement events are also
included in the following patches.
The changes should have minimal impact to non-CMO enabled environments.
This patch set has been written against 2.6.26-rc5 and has been tested
at that level.
Regards,
Robert Jennings
@@ -167,7 +167,8 @@ static unsigned int h_get_ppp(unsigned lreturnrc;}
=20
-static void h_pic(unsigned long *pool_idle_time, unsigned long *num_procs)
+static unsigned int h_pic(unsigned long *pool_idle_time,
+ unsigned long *num_procs)
{
unsigned long rc;
unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
@@ -176,6 +177,53 @@ static void h_pic(unsigned long *pool_id
This changes a user visible interface by removing the above. I don't
know if this matters (probably not), but it should be mentioned in the
changelog.
+ if (new_entitled)
+ *new_weight = current_weight;
+
+ if (new_weight)
+ *new_entitled = current_entitled;
These look fishy - checking one pointer for NULL and then updating via
the other pointer.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
This changes a user visible interface by removing the above. I don't
know if this matters (probably not), but it should be mentioned in the
changelog.
You're right this should have been mentioned. The values it is printing
out are the raw values returned from the H_GET_PPP hcall. The values
were then parsed and pretty printed afterwards. I don't see a need to
print these values out twice.
quoted
+ if (new_entitled)
+ *new_weight = current_weight;
+
+ if (new_weight)
+ *new_entitled = current_entitled;
These look fishy - checking one pointer for NULL and then updating via
the other pointer.
I thought something about this looked strange...
Unfortunately this code gets slightly updated again in patch 3/19 of
this patch series. The point you make is valid though, should not be
de-referencing the pointers without validating them.
I'll update this patch with a new changelog and pull the change from
patch 3/19 into this pach where it belongs.
-Nathan
------------------------------------------------------------------------
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev
Split the retrieval and setting of processor entitlement and weight into
helper routines. This also removes the printing of the raw values
returned from h_get_ppp, the values are already parsed and printed.
Signed-off-by: Nathan Fontenot <redacted>
---
arch/powerpc/kernel/lparcfg.c | 163
++++++++++++++++++++++--------------------
1 file changed, 86 insertions(+), 77 deletions(-)
Index: linux-2.6.git/arch/powerpc/kernel/lparcfg.c
===================================================================
@@ -167,7 +167,8 @@ return rc; }-static void h_pic(unsigned long *pool_idle_time, unsigned long *num_procs)+static unsigned int h_pic(unsigned long *pool_idle_time,+ unsigned long *num_procs) { unsigned long rc; unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
@@ -176,6 +177,53 @@ *pool_idle_time = retbuf[0]; *num_procs = retbuf[1];++ return rc;+}++/*+ * parse_ppp_data+ * Parse out the data returned from h_get_ppp and h_pic+ */+static void parse_ppp_data(struct seq_file *m)+{+ unsigned long h_entitled, h_unallocated;+ unsigned long h_aggregation, h_resource;+ int rc;++ rc = h_get_ppp(&h_entitled, &h_unallocated, &h_aggregation,+ &h_resource);+ if (rc)+ return;++ seq_printf(m, "partition_entitled_capacity=%ld\n", h_entitled);+ seq_printf(m, "group=%ld\n", (h_aggregation >> 2 * 8) & 0xffff);+ seq_printf(m, "system_active_processors=%ld\n",+ (h_resource >> 0 * 8) & 0xffff);++ /* pool related entries are apropriate for shared configs */+ if (lppaca[0].shared_proc) {+ unsigned long pool_idle_time, pool_procs;++ seq_printf(m, "pool=%ld\n", (h_aggregation >> 0 * 8) & 0xffff);++ /* report pool_capacity in percentage */+ seq_printf(m, "pool_capacity=%ld\n",+ ((h_resource >> 2 * 8) & 0xffff) * 100);++ rc = h_pic(&pool_idle_time, &pool_procs);+ if (! rc) {+ seq_printf(m, "pool_idle_time=%ld\n", pool_idle_time);+ seq_printf(m, "pool_num_procs=%ld\n", pool_procs);+ }+ }++ seq_printf(m, "unallocated_capacity_weight=%ld\n",+ (h_resource >> 4 * 8) & 0xFF);++ seq_printf(m, "capacity_weight=%ld\n", (h_resource >> 5 * 8) & 0xFF);+ seq_printf(m, "capped=%ld\n", (h_resource >> 6 * 8) & 0x01);+ seq_printf(m, "unallocated_capacity=%ld\n", h_unallocated); } #define SPLPAR_CHARACTERISTICS_TOKEN 20
@@ -353,6 +420,7 @@ static int pseries_lparcfg_data(struct s /* this call handles the ibm,get-system-parameter contents */ parse_system_parameter_string(m); parse_ppp_data(m);+ parse_mpp_data(m);
This patch has been updated to remove a piece that is now included
in patch 2/19 of this series where it should be.
-Nathan
Update /proc/ppc64/lparcfg to enable displaying of Cooperative Memory
Overcommitment statistics as reported by the H_GET_MPP hcall. This also
updates the lparcfg interface to allow setting memory entitlement and
weight.
Signed-off-by: Nathan Fontenot <redacted>
---
arch/powerpc/kernel/lparcfg.c | 139
+++++++++++++++++++++++++++++++++++++++---
include/asm-powerpc/hvcall.h | 18 +++++
2 files changed, 147 insertions(+), 10 deletions(-)
Index: linux-2.6.git/arch/powerpc/kernel/lparcfg.c
===================================================================
@@ -129,6 +129,35 @@ /* * Methods used to fetch LPAR data when running on a pSeries platform. */+/**+ * h_get_mpp+ * H_GET_MPP hcall returns info in 7 parms+ */+int h_get_mpp(struct hvcall_mpp_data *mpp_data)+{+ int rc;+ unsigned long retbuf[PLPAR_HCALL_BUFSIZE];++ rc = plpar_hcall(H_GET_MPP, retbuf);++ mpp_data->entitled_mem = retbuf[0];+ mpp_data->mapped_mem = retbuf[1];++ mpp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff;+ mpp_data->pool_num = retbuf[2] & 0xffff;++ mpp_data->mem_weight = (retbuf[3] >> 7 * 8) & 0xff;+ mpp_data->unallocated_mem_weight = (retbuf[3] >> 6 * 8) & 0xff;+ mpp_data->unallocated_entitlement = retbuf[3] & 0xffffffffffff;++ mpp_data->pool_size = retbuf[4];+ mpp_data->loan_request = retbuf[5];+ mpp_data->backing_mem = retbuf[6];++ return rc;+}+EXPORT_SYMBOL(h_get_mpp);+ /* * H_GET_PPP hcall returns info in 4 parms. * entitled_capacity,unallocated_capacity,
@@ -226,6 +255,44 @@ seq_printf(m, "unallocated_capacity=%ld\n", h_unallocated); }+/**+ * parse_mpp_data+ * Parse out data returned from h_get_mpp+ */+static void parse_mpp_data(struct seq_file *m)+{+ struct hvcall_mpp_data mpp_data;+ int rc;++ rc = h_get_mpp(&mpp_data);+ if (rc)+ return;++ seq_printf(m, "entitled_memory=%ld\n", mpp_data.entitled_mem);++ if (mpp_data.mapped_mem != -1)+ seq_printf(m, "mapped_entitled_memory=%ld\n",+ mpp_data.mapped_mem);++ seq_printf(m, "entitled_memory_group_number=%d\n", mpp_data.group_num);+ seq_printf(m, "entitled_memory_pool_number=%d\n", mpp_data.pool_num);++ seq_printf(m, "entitled_memory_weight=%d\n", mpp_data.mem_weight);+ seq_printf(m, "unallocated_entitled_memory_weight=%d\n",+ mpp_data.unallocated_mem_weight);+ seq_printf(m, "unallocated_io_mapping_entitlement=%ld\n",+ mpp_data.unallocated_entitlement);++ if (mpp_data.pool_size != -1)+ seq_printf(m, "entitled_memory_pool_size=%ld bytes\n",+ mpp_data.pool_size);++ seq_printf(m, "entitled_memory_loan_request=%ld\n",+ mpp_data.loan_request);++ seq_printf(m, "backing_memory=%ld bytes\n", mpp_data.backing_mem);+}+ #define SPLPAR_CHARACTERISTICS_TOKEN 20 #define SPLPAR_MAXLENGTH 1026*(sizeof(char))
@@ -353,6 +420,7 @@ /* this call handles the ibm,get-system-parameter contents */ parse_system_parameter_string(m); parse_ppp_data(m);+ parse_mpp_data(m); seq_printf(m, "purr=%ld\n", get_purr());
@@ -417,6 +485,43 @@ return retval; }+/**+ * update_mpp+ *+ * Update the memory entitlement and weight for the partition. Caller must+ * spercify either a new entitlement or weight, not both, to be updated+ * since the h_set_mpp call takes both entitlement and weight as
Version 3 of the patch, small update to use the correct plpar_hcall
for H_GET_MPP.
-------------------
Update /proc/ppc64/lparcfg to enable displaying of Cooperative Memory
Overcommitment statistics as reported by the H_GET_MPP hcall. This also
updates the lparcfg interface to allow setting memory entitlement and
weight.
Signed-off-by: Nathan Fontenot <redacted>
---
arch/powerpc/kernel/lparcfg.c | 139
+++++++++++++++++++++++++++++++++++++++---
include/asm-powerpc/hvcall.h | 18 +++++
2 files changed, 147 insertions(+), 10 deletions(-)
Index: linux-2.6.git/arch/powerpc/kernel/lparcfg.c
===================================================================
@@ -129,6 +129,35 @@ /* * Methods used to fetch LPAR data when running on a pSeries platform. */+/**+ * h_get_mpp+ * H_GET_MPP hcall returns info in 7 parms+ */+int h_get_mpp(struct hvcall_mpp_data *mpp_data)+{+ int rc;+ unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];++ rc = plpar_hcall9(H_GET_MPP, retbuf);++ mpp_data->entitled_mem = retbuf[0];+ mpp_data->mapped_mem = retbuf[1];++ mpp_data->group_num = (retbuf[2] >> 2 * 8) & 0xffff;+ mpp_data->pool_num = retbuf[2] & 0xffff;++ mpp_data->mem_weight = (retbuf[3] >> 7 * 8) & 0xff;+ mpp_data->unallocated_mem_weight = (retbuf[3] >> 6 * 8) & 0xff;+ mpp_data->unallocated_entitlement = retbuf[3] & 0xffffffffffff;++ mpp_data->pool_size = retbuf[4];+ mpp_data->loan_request = retbuf[5];+ mpp_data->backing_mem = retbuf[6];++ return rc;+}+EXPORT_SYMBOL(h_get_mpp);+ /* * H_GET_PPP hcall returns info in 4 parms. * entitled_capacity,unallocated_capacity,
@@ -226,6 +255,44 @@ seq_printf(m, "unallocated_capacity=%ld\n", h_unallocated); }+/**+ * parse_mpp_data+ * Parse out data returned from h_get_mpp+ */+static void parse_mpp_data(struct seq_file *m)+{+ struct hvcall_mpp_data mpp_data;+ int rc;++ rc = h_get_mpp(&mpp_data);+ if (rc)+ return;++ seq_printf(m, "entitled_memory=%ld\n", mpp_data.entitled_mem);++ if (mpp_data.mapped_mem != -1)+ seq_printf(m, "mapped_entitled_memory=%ld\n",+ mpp_data.mapped_mem);++ seq_printf(m, "entitled_memory_group_number=%d\n", mpp_data.group_num);+ seq_printf(m, "entitled_memory_pool_number=%d\n", mpp_data.pool_num);++ seq_printf(m, "entitled_memory_weight=%d\n", mpp_data.mem_weight);+ seq_printf(m, "unallocated_entitled_memory_weight=%d\n",+ mpp_data.unallocated_mem_weight);+ seq_printf(m, "unallocated_io_mapping_entitlement=%ld\n",+ mpp_data.unallocated_entitlement);++ if (mpp_data.pool_size != -1)+ seq_printf(m, "entitled_memory_pool_size=%ld bytes\n",+ mpp_data.pool_size);++ seq_printf(m, "entitled_memory_loan_request=%ld\n",+ mpp_data.loan_request);++ seq_printf(m, "backing_memory=%ld bytes\n", mpp_data.backing_mem);+}+ #define SPLPAR_CHARACTERISTICS_TOKEN 20 #define SPLPAR_MAXLENGTH 1026*(sizeof(char))
@@ -353,6 +420,7 @@ /* this call handles the ibm,get-system-parameter contents */ parse_system_parameter_string(m); parse_ppp_data(m);+ parse_mpp_data(m); seq_printf(m, "purr=%ld\n", get_purr());
@@ -417,6 +485,43 @@ return retval; }+/**+ * update_mpp+ *+ * Update the memory entitlement and weight for the partition. Caller must+ * spercify either a new entitlement or weight, not both, to be updated+ * since the h_set_mpp call takes both entitlement and weight as
From: Brian King <hidden> Date: 2008-06-24 14:24:48
Just a few minor nits.
+/**
+ * h_get_mpp
+ * H_GET_MPP hcall returns info in 7 parms
+ */
+int h_get_mpp(struct hvcall_mpp_data *mpp_data)
+{
+ int rc;
+ unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
^^^^
Should be tabs instead of spaces in this function and a few others
in this patch file.
+/**
+ * parse_mpp_data
+ * Parse out data returned from h_get_mpp
+ */
+static void parse_mpp_data(struct seq_file *m)
+{
+ struct hvcall_mpp_data mpp_data;
+ int rc;
Same here.
+/**
+ * update_mpp
+ *
+ * Update the memory entitlement and weight for the partition. Caller
must
+ * spercify either a new entitlement or weight, not both, to be updated
^^^^^^^^
+ * since the h_set_mpp call takes both entitlement and weight as
parameters.
+ */
+static ssize_t update_mpp(u64 *entitlement, u8 *weight)
+{
+ struct hvcall_mpp_data mpp_data;
Tab/spacing here.
quoted hunk
@@ -270,6 +272,20 @@ }; #define HCALL_STAT_ARRAY_SIZE ((MAX_HCALL_OPCODE >> 2) + 1)+struct hvcall_mpp_data {+ unsigned long entitled_mem;+ unsigned long mapped_mem;+ unsigned short group_num;+ unsigned short pool_num;+ unsigned char mem_weight;+ unsigned char unallocated_mem_weight;+ unsigned long unallocated_entitlement; /* value in bytes */+ unsigned long pool_size;+ long loan_request;
Might as well be specific here and call this a signed long.
Tab/spacing issue here as well.
--
Brian King
Linux on Power Virtualization
IBM Linux Technology Center
v4 of this patch, updates to correct whitespace, spelling issues pointed out by
Brian King. Also made the long a signed long per Brian's suggestion.
Update /proc/ppc64/lparcfg to enable displaying of Cooperative Memory
Overcommitment statistics as reported by the H_GET_MPP hcall. This also
updates the lparcfg interface to allow setting memory entitlement and
weight.
Signed-off-by: Nathan Fontenot <redacted>
Signed-off-by: Robert Jennings <redacted>
---
arch/powerpc/kernel/lparcfg.c | 119 ++++++++++++++++++++++++++++++++++++++++++
include/asm-powerpc/hvcall.h | 18 ++++++
2 files changed, 136 insertions(+), 1 deletion(-)
Index: b/arch/powerpc/kernel/lparcfg.c
===================================================================
@@ -353,6 +420,7 @@ static int pseries_lparcfg_data(struct s/* this call handles the ibm,get-system-parameter contents */parse_system_parameter_string(m);parse_ppp_data(m);+parse_mpp_data(m);seq_printf(m,"purr=%ld\n",get_purr());}else{/* non SPLPAR case */
From: Robert Jennings <hidden> Date: 2008-06-12 22:12:45
=46rom: Nathan Fontenot [off-list ref]
Split the retrieval of processor entitlement data returned in the H_GET_PPP
hcall into its own helper routine.
Signed-off-by: Nathan Fontenot <redacted>
---
arch/powerpc/kernel/lparcfg.c | 80 ++++++++++++++++++++++++-------------=
-----
1 file changed, 45 insertions(+), 35 deletions(-)
Index: b/arch/powerpc/kernel/lparcfg.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
@@ -178,20 +190,24 @@ EXPORT_SYMBOL(h_get_mpp); * XXXX - Active processors in Physical Processor Pool. * XXXX - Processors active on platform. */-static unsigned int h_get_ppp(unsigned long *entitled,- unsigned long *unallocated,- unsigned long *aggregation,- unsigned long *resource)+static unsigned int h_get_ppp(struct hvcall_ppp_data *ppp_data) { unsigned long rc; unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
From: Robert Jennings <hidden> Date: 2008-06-12 22:13:09
=46rom: Robert Jennings [off-list ref]
For Cooperative Memory Overcommitment (CMO), set the FW_FEATURE_CMO
flag in powerpc_firmware_features from the rtas ibm,get-system-parameters
table prior to calling iommu_init_early_pSeries.
With this, any CMO specific functionality can be controlled by checking:
firmware_has_feature(FW_FEATURE_CMO)
Signed-off-by: Robert Jennings <redacted>
---
arch/powerpc/platforms/pseries/setup.c | 71 ++++++++++++++++++++++++++++=
+++++
include/asm-powerpc/firmware.h | 3 +
2 files changed, 73 insertions(+), 1 deletion(-)
Index: b/arch/powerpc/platforms/pseries/setup.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
From: Robert Jennings <hidden> Date: 2008-06-12 22:14:21
=46rom: Brian King [off-list ref]
Newer versions of firmware support page states, which are used by the
collaborative memory manager (future patch) to "loan" pages to the
hypervisor for use by other partitions.
Signed-off-by: Brian King <redacted>
---
arch/powerpc/platforms/pseries/plpar_wrappers.h | 10 ++++++++++
include/asm-powerpc/hvcall.h | 5 +++++
2 files changed, 15 insertions(+)
Index: b/arch/powerpc/platforms/pseries/plpar_wrappers.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
@@ -92,6 +92,11 @@#define H_EXACT (1UL<<(63-24)) /* Use exact PTE or return H_PTEG_FULL */#define H_R_XLATE (1UL<<(63-25)) /* include a valid logical page num in t=
he pte if the valid bit is set */
#define H_READ_4 (1UL<<(63-26)) /* Return 4 PTEs */
+#define H_PAGE_STATE_CHANGE (1UL<<(63-28))
+#define H_PAGE_UNUSED ((1UL<<(63-29)) | (1UL<<(63-30)))
+#define H_PAGE_SET_UNUSED (H_PAGE_STATE_CHANGE | H_PAGE_UNUSED)
+#define H_PAGE_SET_LOANED (H_PAGE_SET_UNUSED | (1UL<<(63-31)))
+#define H_PAGE_SET_ACTIVE H_PAGE_STATE_CHANGE
#define H_AVPN (1UL<<(63-32)) /* An avpn is provided as a sanity test */
#define H_ANDCOND (1UL<<(63-33))
#define H_ICACHE_INVALIDATE (1UL<<(63-40)) /* icbi, etc. (ignored for IO =
pages) */
From: Robert Jennings <hidden> Date: 2008-06-12 22:15:11
=46rom: Brian King [off-list ref]
Adds a collaborative memory manager, which acts as a simple balloon driver
for System p machines that support cooperative memory overcommitment
(CMO).
Signed-off-by: Brian King <redacted>
---
arch/powerpc/platforms/pseries/Kconfig | 11 +
arch/powerpc/platforms/pseries/Makefile | 1 +
arch/powerpc/platforms/pseries/cmm.c | 470 +++++++++++++++++++++++++++=
+++++
3 files changed, 482 insertions(+)
Index: b/arch/powerpc/platforms/pseries/Kconfig
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
From: Robert Jennings <hidden> Date: 2008-06-12 22:15:29
=46rom: Brian King [off-list ref]
The Cooperative Memory Overcommit (CMO) on System p does not currently
support native PCI devices or eBus devices when enabled. Prevent
PCI bus probe and eBus device probe if the feature is enabled.
Signed-off-by: Brian King <redacted>
---
arch/powerpc/kernel/ibmebus.c | 6 ++++++
arch/powerpc/platforms/pseries/setup.c | 4 ++++
2 files changed, 10 insertions(+)
Index: b/arch/powerpc/kernel/ibmebus.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
From: Robert Jennings <hidden> Date: 2008-06-12 22:16:05
=46rom: Brian King [off-list ref]
With the addition of Cooperative Memory Overcommitment (CMO) support
for IBM Power Systems, two fields have been added to the VPA to report
paging statistics. Add support in lparcfg to report them to userspace.
Signed-off-by: Brian King <redacted>
---
arch/powerpc/kernel/lparcfg.c | 20 ++++++++++++++++++++
include/asm-powerpc/lppaca.h | 5 ++++-
2 files changed, 24 insertions(+), 1 deletion(-)
Index: b/arch/powerpc/kernel/lparcfg.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
@@ -125,7 +125,10 @@ struct lppaca {// NOTE: This value will ALWAYS be zero for dedicated processors and// will NEVER be zero for shared processors (ie, initialized to a 1).volatileu32yield_count;// PLIC increments each dispatchx00-x03-u8reserved6[124];// Reserved x04-x7F+u32reserved6;+volatileu64cmo_faults;// CMO page fault count x08-x0F+volatileu64cmo_fault_time;// CMO page fault time x10-x17+u8reserved7[104];// Reserved x18-x7F
From: Robert Jennings <hidden> Date: 2008-06-12 22:17:09
=46rom: Robert Jennings [off-list ref]
In support of Cooperative Memory Overcommitment (CMO) this moves
get_longbusy_msecs() out of the ehca and ehea drivers and into the=20
architecture's hvcall header as plpar_get_longbusy_msecs. Some firmware
calls made in pSeries platform iommu code will need to share this
functionality.
Signed-off-by: Robert Jennings <redacted>
---
drivers/infiniband/hw/ehca/hcp_if.c | 24 ++----------------------
drivers/net/ehea/ehea_phyp.c | 4 ++--
drivers/net/ehea/ehea_phyp.h | 20 --------------------
include/asm-powerpc/hvcall.h | 27 +++++++++++++++++++++++++++
4 files changed, 31 insertions(+), 44 deletions(-)
Index: b/drivers/infiniband/hw/ehca/hcp_if.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
=20
/**
+ * plpar_get_longbusy_msecs: - Return number of msecs for H_LONG_BUSY* res=
ponse
+ * @long_busy_ret_code: The H_LONG_BUSY_* constant to process
+ *
+ * This returns the number of msecs that corresponds to an H_LONG_BUSY_*
+ * response from a plpar_hcall. If there is no match 1 is returned.
+ */
+static inline u32 plpar_get_longbusy_msecs(int long_busy_ret_code)
+{
+ switch (long_busy_ret_code) {
+ case H_LONG_BUSY_ORDER_1_MSEC:
+ return 1;
+ case H_LONG_BUSY_ORDER_10_MSEC:
+ return 10;
+ case H_LONG_BUSY_ORDER_100_MSEC:
+ return 100;
+ case H_LONG_BUSY_ORDER_1_SEC:
+ return 1000;
+ case H_LONG_BUSY_ORDER_10_SEC:
+ return 10000;
+ case H_LONG_BUSY_ORDER_100_SEC:
+ return 100000;
+ default:
+ return 1;
+ }
+}
+
+/**
* plpar_hcall_norets: - Make a pseries hypervisor call with no return arg=
uments
* @opcode: The hypervisor call to make.
*
From: Robert Jennings <hidden> Date: 2008-06-12 22:20:22
=46rom: Robert Jennings [off-list ref]
In support of Cooperative Memory Overcommitment (CMO) this moves
get_longbusy_msecs() out of the ehca and ehea drivers and into the=20
architecture's hvcall header as plpar_get_longbusy_msecs. Some firmware
calls made in pSeries platform iommu code will need to share this
functionality.
Signed-off-by: Robert Jennings <redacted>
---
I missed copying netdev on this patch the first time.
drivers/infiniband/hw/ehca/hcp_if.c | 24 ++----------------------
drivers/net/ehea/ehea_phyp.c | 4 ++--
drivers/net/ehea/ehea_phyp.h | 20 --------------------
include/asm-powerpc/hvcall.h | 27 +++++++++++++++++++++++++++
4 files changed, 31 insertions(+), 44 deletions(-)
Index: b/drivers/infiniband/hw/ehca/hcp_if.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
=20
/**
+ * plpar_get_longbusy_msecs: - Return number of msecs for H_LONG_BUSY* res=
ponse
+ * @long_busy_ret_code: The H_LONG_BUSY_* constant to process
+ *
+ * This returns the number of msecs that corresponds to an H_LONG_BUSY_*
+ * response from a plpar_hcall. If there is no match 1 is returned.
+ */
+static inline u32 plpar_get_longbusy_msecs(int long_busy_ret_code)
+{
+ switch (long_busy_ret_code) {
+ case H_LONG_BUSY_ORDER_1_MSEC:
+ return 1;
+ case H_LONG_BUSY_ORDER_10_MSEC:
+ return 10;
+ case H_LONG_BUSY_ORDER_100_MSEC:
+ return 100;
+ case H_LONG_BUSY_ORDER_1_SEC:
+ return 1000;
+ case H_LONG_BUSY_ORDER_10_SEC:
+ return 10000;
+ case H_LONG_BUSY_ORDER_100_SEC:
+ return 100000;
+ default:
+ return 1;
+ }
+}
+
+/**
* plpar_hcall_norets: - Make a pseries hypervisor call with no return arg=
uments
* @opcode: The hypervisor call to make.
*
From: Brian King <hidden> Date: 2008-06-13 18:24:33
Jeff,
Regarding the patches Rob just posted here, we'd like to just take them
through the powerpc tree with your sign off since they are part of a
Power platform feature we are enabling.
Thanks,
Brian
Robert Jennings wrote:
quoted hunk
From: Robert Jennings <redacted>
In support of Cooperative Memory Overcommitment (CMO) this moves
get_longbusy_msecs() out of the ehca and ehea drivers and into the
architecture's hvcall header as plpar_get_longbusy_msecs. Some firmware
calls made in pSeries platform iommu code will need to share this
functionality.
Signed-off-by: Robert Jennings <redacted>
---
I missed copying netdev on this patch the first time.
drivers/infiniband/hw/ehca/hcp_if.c | 24 ++----------------------
drivers/net/ehea/ehea_phyp.c | 4 ++--
drivers/net/ehea/ehea_phyp.h | 20 --------------------
include/asm-powerpc/hvcall.h | 27 +++++++++++++++++++++++++++
4 files changed, 31 insertions(+), 44 deletions(-)
Index: b/drivers/infiniband/hw/ehca/hcp_if.c
===================================================================
@@ -40,26 +40,6 @@*hcp_*-structures,variablesandfunctionsreleatedtoHypervisorCalls*/-staticinlineu32get_longbusy_msecs(intlong_busy_ret_code)-{-switch(long_busy_ret_code){-caseH_LONG_BUSY_ORDER_1_MSEC:-return1;-caseH_LONG_BUSY_ORDER_10_MSEC:-return10;-caseH_LONG_BUSY_ORDER_100_MSEC:-return100;-caseH_LONG_BUSY_ORDER_1_SEC:-return1000;-caseH_LONG_BUSY_ORDER_10_SEC:-return10000;-caseH_LONG_BUSY_ORDER_100_SEC:-return100000;-default:-return1;-}-}-/* Number of pages which can be registered at once by H_REGISTER_HEA_RPAGES */#define EHEA_MAX_RPAGE 512
From: Jeff Garzik <hidden> Date: 2008-06-13 19:56:02
Brian King wrote:
Jeff,
Regarding the patches Rob just posted here, we'd like to just take them
through the powerpc tree with your sign off since they are part of a
Power platform feature we are enabling.
Thanks,
Brian
Robert Jennings wrote:
quoted
From: Robert Jennings <redacted>
In support of Cooperative Memory Overcommitment (CMO) this moves
get_longbusy_msecs() out of the ehca and ehea drivers and into the
architecture's hvcall header as plpar_get_longbusy_msecs. Some firmware
calls made in pSeries platform iommu code will need to share this
functionality.
Signed-off-by: Robert Jennings <redacted>
---
I missed copying netdev on this patch the first time.
drivers/infiniband/hw/ehca/hcp_if.c | 24 ++----------------------
drivers/net/ehea/ehea_phyp.c | 4 ++--
drivers/net/ehea/ehea_phyp.h | 20 --------------------
include/asm-powerpc/hvcall.h | 27 +++++++++++++++++++++++++++
4 files changed, 31 insertions(+), 44 deletions(-)
From: Robert Jennings <hidden> Date: 2008-06-12 22:21:12
=46rom: Robert Jennings [off-list ref]
To support Cooperative Memory Overcommitment (CMO), we need to check
for failure and busy responses from some of the tce hcalls.
These changes for the pseries platform affect the powerpc architecture;
patches for the other affected platforms are included in this patch.
pSeries platform IOMMU code changes:
* platform TCE functions must handle H_NOT_ENOUGH_RESOURCES errors.
* platform TCE functions must retry when H_LONG_BUSY_* is returned.
* platform TCE functions must return error when H_NOT_ENOUGH_RESOURCES
encountered.
Architecture IOMMU code changes:
* Calls to ppc_md.tce_build need to check return values and return=20
DMA_MAPPING_ERROR
Architecture changes:
* struct machdep_calls for tce_build*_pSeriesLP functions need to change
to indicate failure
* all other platforms will need updates to iommu functions to match the new
calling semantics; they will return 0 on success. The other platforms
default configs have been built, but no further testing was performed.
Signed-off-by: Robert Jennings <redacted>
---
arch/powerpc/kernel/iommu.c | 71 ++++++++++++++++++++++++++++=
+--
arch/powerpc/platforms/cell/iommu.c | 3 +
arch/powerpc/platforms/iseries/iommu.c | 3 +
arch/powerpc/platforms/pasemi/iommu.c | 3 +
arch/powerpc/platforms/pseries/iommu.c | 76 ++++++++++++++++++++++++++++=
-----
arch/powerpc/sysdev/dart_iommu.c | 3 +
include/asm-powerpc/machdep.h | 2=20
7 files changed, 139 insertions(+), 22 deletions(-)
Index: b/arch/powerpc/kernel/iommu.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
@@ -204,9 +248,20 @@ static dma_addr_t iommu_alloc(struct dev ret =3D entry << IOMMU_PAGE_SHIFT; /* Set the return dma address */
=20
/* Put the TCEs in the HW table */
- ppc_md.tce_build(tbl, entry, npages, (unsigned long)page & IOMMU_PAGE_MAS=
K,
- direction);
+ rc =3D ppc_md.tce_build(tbl, entry, npages,
+ (unsigned long)page & IOMMU_PAGE_MASK, direction);
=20
+ /* ppc_md.tce_build() only returns non-zero for transient errors.
+ * Clean up the table bitmap in this case and return
+ * DMA_ERROR_CODE. For all other errors the functionality is
+ * not altered.
+ */
+ if (unlikely(rc)) {
+ iommu_undo(tbl, ret, npages);
+
+ spin_unlock_irqrestore(&(tbl->it_lock), flags);
+ return DMA_ERROR_CODE;
+ }
=20
/* Flush/invalidate TLB caches if necessary */
if (ppc_md.tce_flush)
@@ -275,7 +330,7 @@ int iommu_map_sg(struct device *dev, str dma_addr_t dma_next =3D 0, dma_addr; unsigned long flags; struct scatterlist *s, *outs, *segstart;- int outcount, incount, i;+ int outcount, incount, i, rc =3D 0; unsigned int align; unsigned long handle; unsigned int max_seg_size;
=20
-static void tce_build_cell(struct iommu_table *tbl, long index, long npage=
s,
+static int tce_build_cell(struct iommu_table *tbl, long index, long npages,
unsigned long uaddr, enum dma_data_direction direction)
{
int i;
=20
-static void tce_build_iSeries(struct iommu_table *tbl, long index, long np=
ages,
+static int tce_build_iSeries(struct iommu_table *tbl, long index, long npa=
ges,
unsigned long uaddr, enum dma_data_direction direction)
{
u64 rc;
=20
-static void iobmap_build(struct iommu_table *tbl, long index,
+static int iobmap_build(struct iommu_table *tbl, long index,
long npages, unsigned long uaddr,
enum dma_data_direction direction)
{
=20
=20
-static void tce_build_pSeries(struct iommu_table *tbl, long index,
+static int tce_build_pSeries(struct iommu_table *tbl, long index,
long npages, unsigned long uaddr,
enum dma_data_direction direction)
{
=20
-static void dart_build(struct iommu_table *tbl, long index,
+static int dart_build(struct iommu_table *tbl, long index,
long npages, unsigned long uaddr,
enum dma_data_direction direction)
{
@@ -183,6 +183,49 @@ static unsigned long iommu_range_alloc(sreturnn;}+/** iommu_undo - Clear iommu_table bits without calling platform tce_free.+*+*@tbl-structiommu_tabletoalter+*@dma_addr-DMAaddresstofreeentriesfor+*@npages-numberofpagestofreeentriesfor+*+*Thisisthesameas__iommu_freewithoutthecalltoppc_md.tce_free();
__iommu_free has the __ prepended to indicate that it's not locking.
Since this does the same, please keep the __. Also see comments below.
+ *
+ * To clean up after ppc_md.tce_build() errors we need to clear bits
+ * in the table without calling the ppc_md.tce_free() method; calling
+ * ppc_md.tce_free() could alter entries that were not touched due to a
+ * premature failure in ppc_md.tce_build().
+ *
+ * The ppc_md.tce_build() needs to perform its own clean up prior to
+ * returning its error.
+ */
+static void iommu_undo(struct iommu_table *tbl, dma_addr_t dma_addr,
+ unsigned int npages)
+{
+ unsigned long entry, free_entry;
+
+ entry = dma_addr >> IOMMU_PAGE_SHIFT;
+ free_entry = entry - tbl->it_offset;
+
+ if (((free_entry + npages) > tbl->it_size) ||
+ (entry < tbl->it_offset)) {
+ if (printk_ratelimit()) {
+ printk(KERN_INFO "iommu_undo: invalid entry\n");
+ printk(KERN_INFO "\tentry = 0x%lx\n", entry);
+ printk(KERN_INFO "\tdma_addr = 0x%lx\n", (u64)dma_addr);
+ printk(KERN_INFO "\tTable = 0x%lx\n", (u64)tbl);
+ printk(KERN_INFO "\tbus# = 0x%lx\n", tbl->it_busno);
+ printk(KERN_INFO "\tsize = 0x%lx\n", tbl->it_size);
+ printk(KERN_INFO "\tstartOff = 0x%lx\n", tbl->it_offset);
+ printk(KERN_INFO "\tindex = 0x%lx\n", tbl->it_index);
+ WARN_ON(1);
+ }
+ return;
+ }
+
+ iommu_area_free(tbl->it_map, free_entry, npages);
+}
Ick, This should just be refactored to reuse code together with
iommu_free() instead of duplicating it. Also, the error checking
shouldn't be needed here.
Actually, is there harm in calling tce_free for these cases anyway? I'm
guessing it's not a performance critical path.
quoted hunk
@@ -275,7 +330,7 @@ int iommu_map_sg(struct device *dev, str dma_addr_t dma_next = 0, dma_addr; unsigned long flags; struct scatterlist *s, *outs, *segstart;- int outcount, incount, i;+ int outcount, incount, i, rc = 0; unsigned int align; unsigned long handle; unsigned int max_seg_size;
@@ -336,7 +391,10 @@ int iommu_map_sg(struct device *dev, str npages, entry, dma_addr); /* Insert into HW table */- ppc_md.tce_build(tbl, entry, npages, vaddr & IOMMU_PAGE_MASK, direction);+ rc = ppc_md.tce_build(tbl, entry, npages,+ vaddr & IOMMU_PAGE_MASK, direction);+ if(unlikely(rc))+ goto failure; /* If we are in an open segment, try merging */ if (segstart != s) {
'rc' is a quite generic name to carry state this far away from where
it's set. Either a more descriptive name (build_fail, whatever), or if
the above is true, just call __iommu_free here as well.
quoted hunk
-static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum,
+static void tce_free_pSeriesLP(struct iommu_table*, long, long);
+static void tce_freemulti_pSeriesLP(struct iommu_table*, long, long);
+
+static int tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum,
long npages, unsigned long uaddr,
enum dma_data_direction direction)
{
- u64 rc;
+ u64 rc = 0;
u64 proto_tce, tce;
u64 rpn;
+ int sleep_msecs, ret = 0;
+ long tcenum_start = tcenum, npages_start = npages;
rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
proto_tce = TCE_PCI_READ;
@@ -187,14 +222,23 @@ static void tce_buildmulti_pSeriesLP(str printk("\ttce[0] val = 0x%lx\n", tcep[0]); show_stack(current, (unsigned long *)__get_SP()); }+ return ret; } static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) {+ int sleep_msecs; u64 rc; while (npages--) {- rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, 0);+ do {+ rc = plpar_tce_put((u64)tbl->it_index,+ (u64)tcenum << 12, 0);+ if (unlikely(H_IS_LONG_BUSY(rc))) {+ sleep_msecs = plpar_get_longbusy_msecs(rc);+ mdelay(sleep_msecs);+ }+ } while (unlikely(H_IS_LONG_BUSY(rc)));
Can this ever happen? I would hope that any entry that's got an active
mapping is actually pinned in memory, what other than paging in from
disk can result in long busy?
quoted hunk
@@ -210,9 +254,17 @@ static void tce_free_pSeriesLP(struct io static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) {+ int sleep_msecs; u64 rc;- rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages);+ do {+ rc = plpar_tce_stuff((u64)tbl->it_index,+ (u64)tcenum << 12, 0, npages);+ if (unlikely(H_IS_LONG_BUSY(rc))) {+ sleep_msecs = plpar_get_longbusy_msecs(rc);+ mdelay(sleep_msecs);+ }+ } while (unlikely(H_IS_LONG_BUSY(rc))); if (rc && printk_ratelimit()) { printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n");
@@ -183,6 +183,49 @@ static unsigned long iommu_range_alloc(sreturnn;}+/** iommu_undo - Clear iommu_table bits without calling platform tce_free.+*+*@tbl-structiommu_tabletoalter+*@dma_addr-DMAaddresstofreeentriesfor+*@npages-numberofpagestofreeentriesfor+*+*Thisisthesameas__iommu_freewithoutthecalltoppc_md.tce_free();
__iommu_free has the __ prepended to indicate that it's not locking.
Since this does the same, please keep the __. Also see comments below.
quoted
+ *
+ * To clean up after ppc_md.tce_build() errors we need to clear bits
+ * in the table without calling the ppc_md.tce_free() method; calling
+ * ppc_md.tce_free() could alter entries that were not touched due to a
+ * premature failure in ppc_md.tce_build().
+ *
+ * The ppc_md.tce_build() needs to perform its own clean up prior to
+ * returning its error.
+ */
+static void iommu_undo(struct iommu_table *tbl, dma_addr_t dma_addr,
+ unsigned int npages)
+{
+ unsigned long entry, free_entry;
+
+ entry = dma_addr >> IOMMU_PAGE_SHIFT;
+ free_entry = entry - tbl->it_offset;
+
+ if (((free_entry + npages) > tbl->it_size) ||
+ (entry < tbl->it_offset)) {
+ if (printk_ratelimit()) {
+ printk(KERN_INFO "iommu_undo: invalid entry\n");
+ printk(KERN_INFO "\tentry = 0x%lx\n", entry);
+ printk(KERN_INFO "\tdma_addr = 0x%lx\n", (u64)dma_addr);
+ printk(KERN_INFO "\tTable = 0x%lx\n", (u64)tbl);
+ printk(KERN_INFO "\tbus# = 0x%lx\n", tbl->it_busno);
+ printk(KERN_INFO "\tsize = 0x%lx\n", tbl->it_size);
+ printk(KERN_INFO "\tstartOff = 0x%lx\n", tbl->it_offset);
+ printk(KERN_INFO "\tindex = 0x%lx\n", tbl->it_index);
+ WARN_ON(1);
+ }
+ return;
+ }
+
+ iommu_area_free(tbl->it_map, free_entry, npages);
+}
Ick, This should just be refactored to reuse code together with
iommu_free() instead of duplicating it. Also, the error checking
shouldn't be needed here.
Actually, is there harm in calling tce_free for these cases anyway? I'm
guessing it's not a performance critical path.
There is no harm and I will get rid of this and just call __iommu_free.
quoted
@@ -275,7 +330,7 @@ int iommu_map_sg(struct device *dev, str dma_addr_t dma_next = 0, dma_addr; unsigned long flags; struct scatterlist *s, *outs, *segstart;- int outcount, incount, i;+ int outcount, incount, i, rc = 0; unsigned int align; unsigned long handle; unsigned int max_seg_size;
@@ -336,7 +391,10 @@ int iommu_map_sg(struct device *dev, str npages, entry, dma_addr); /* Insert into HW table */- ppc_md.tce_build(tbl, entry, npages, vaddr & IOMMU_PAGE_MASK, direction);+ rc = ppc_md.tce_build(tbl, entry, npages,+ vaddr & IOMMU_PAGE_MASK, direction);+ if(unlikely(rc))+ goto failure; /* If we are in an open segment, try merging */ if (segstart != s) {
'rc' is a quite generic name to carry state this far away from where
it's set. Either a more descriptive name (build_fail, whatever), or if
the above is true, just call __iommu_free here as well.
I'll fix this.
quoted
-static void tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum,
+static void tce_free_pSeriesLP(struct iommu_table*, long, long);
+static void tce_freemulti_pSeriesLP(struct iommu_table*, long, long);
+
+static int tce_build_pSeriesLP(struct iommu_table *tbl, long tcenum,
long npages, unsigned long uaddr,
enum dma_data_direction direction)
{
- u64 rc;
+ u64 rc = 0;
u64 proto_tce, tce;
u64 rpn;
+ int sleep_msecs, ret = 0;
+ long tcenum_start = tcenum, npages_start = npages;
rpn = (virt_to_abs(uaddr)) >> TCE_SHIFT;
proto_tce = TCE_PCI_READ;
@@ -187,14 +222,23 @@ static void tce_buildmulti_pSeriesLP(str printk("\ttce[0] val = 0x%lx\n", tcep[0]); show_stack(current, (unsigned long *)__get_SP()); }+ return ret; } static void tce_free_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) {+ int sleep_msecs; u64 rc; while (npages--) {- rc = plpar_tce_put((u64)tbl->it_index, (u64)tcenum << 12, 0);+ do {+ rc = plpar_tce_put((u64)tbl->it_index,+ (u64)tcenum << 12, 0);+ if (unlikely(H_IS_LONG_BUSY(rc))) {+ sleep_msecs = plpar_get_longbusy_msecs(rc);+ mdelay(sleep_msecs);+ }+ } while (unlikely(H_IS_LONG_BUSY(rc)));
Can this ever happen? I would hope that any entry that's got an active
mapping is actually pinned in memory, what other than paging in from
disk can result in long busy?
This won't happen, I'll remove it.
quoted
@@ -210,9 +254,17 @@ static void tce_free_pSeriesLP(struct io static void tce_freemulti_pSeriesLP(struct iommu_table *tbl, long tcenum, long npages) {+ int sleep_msecs; u64 rc;- rc = plpar_tce_stuff((u64)tbl->it_index, (u64)tcenum << 12, 0, npages);+ do {+ rc = plpar_tce_stuff((u64)tbl->it_index,+ (u64)tcenum << 12, 0, npages);+ if (unlikely(H_IS_LONG_BUSY(rc))) {+ sleep_msecs = plpar_get_longbusy_msecs(rc);+ mdelay(sleep_msecs);+ }+ } while (unlikely(H_IS_LONG_BUSY(rc))); if (rc && printk_ratelimit()) { printk("tce_freemulti_pSeriesLP: plpar_tce_stuff failed\n");
From: Robert Jennings <hidden> Date: 2008-06-20 15:12:53
To support Cooperative Memory Overcommitment (CMO), we need to check
for failure from some of the tce hcalls.
These changes for the pseries platform affect the powerpc architecture;
patches for the other affected platforms are included in this patch.
pSeries platform IOMMU code changes:
* platform TCE functions must handle H_NOT_ENOUGH_RESOURCES errors and
return an error.
Architecture IOMMU code changes:
* Calls to ppc_md.tce_build need to check return values and return
DMA_MAPPING_ERROR for transient errors.
Architecture changes:
* struct machdep_calls for tce_build*_pSeriesLP functions need to change
to indicate failure.
* all other platforms will need updates to iommu functions to match the new
calling semantics; they will return 0 on success. The other platforms
default configs have been built, but no further testing was performed.
Signed-off-by: Robert Jennings <redacted>
---
arch/powerpc/kernel/iommu.c | 26 +++++++++++++++++++++----
arch/powerpc/platforms/cell/iommu.c | 3 ++-
arch/powerpc/platforms/iseries/iommu.c | 3 ++-
arch/powerpc/platforms/pasemi/iommu.c | 3 ++-
arch/powerpc/platforms/pseries/iommu.c | 34 ++++++++++++++++++++++++++++-----
arch/powerpc/sysdev/dart_iommu.c | 3 ++-
include/asm-powerpc/machdep.h | 2 +-
7 files changed, 60 insertions(+), 14 deletions(-)
Index: b/arch/powerpc/kernel/iommu.c
===================================================================
@@ -204,9 +207,21 @@ static dma_addr_t iommu_alloc(struct devret=entry<<IOMMU_PAGE_SHIFT;/* Set the return dma address *//* Put the TCEs in the HW table */-ppc_md.tce_build(tbl,entry,npages,(unsignedlong)page&IOMMU_PAGE_MASK,-direction);+build_fail=ppc_md.tce_build(tbl,entry,npages,+(unsignedlong)page&IOMMU_PAGE_MASK,+direction);++/* ppc_md.tce_build() only returns non-zero for transient errors.+*Cleanupthetablebitmapinthiscaseandreturn+*DMA_ERROR_CODE.Forallothererrorsthefunctionalityis+*notaltered.+*/+if(unlikely(build_fail)){+__iommu_free(tbl,ret,npages);+spin_unlock_irqrestore(&(tbl->it_lock),flags);+returnDMA_ERROR_CODE;+}/* Flush/invalidate TLB caches if necessary */if(ppc_md.tce_flush)
@@ -275,7 +290,7 @@ int iommu_map_sg(struct device *dev, strdma_addr_tdma_next=0,dma_addr;unsignedlongflags;structscatterlist*s,*outs,*segstart;-intoutcount,incount,i;+intoutcount,incount,i,build_fail=0;unsignedintalign;unsignedlonghandle;unsignedintmax_seg_size;
@@ -336,7 +351,10 @@ int iommu_map_sg(struct device *dev, strnpages,entry,dma_addr);/* Insert into HW table */-ppc_md.tce_build(tbl,entry,npages,vaddr&IOMMU_PAGE_MASK,direction);+build_fail=ppc_md.tce_build(tbl,entry,npages,+vaddr&IOMMU_PAGE_MASK,direction);+if(unlikely(build_fail))+gotofailure;/* If we are in an open segment, try merging */if(segstart!=s){
From: Robert Jennings <hidden> Date: 2008-06-12 22:21:38
=46rom: Robert Jennings [off-list ref]
Enable bus level entitled memory accounting for Cooperative Memory
Overcommitment (CMO) environments. The normal code path should not
be affected.
The following changes are made that the VIO bus layer for CMO:
* add IO memory accounting per device structure.
* add IO memory entitlement query function to driver structure.
* during vio bus probe, if CMO is enabled, check that driver has
memory entitlement query function defined. Fail if function not defined.
* fail to register driver if io entitlement function not defined.
* create set of dma_ops at vio level for CMO that will track allocations
and return DMA failures once entitlement is reached. Entitlement will
limited by overall system entitlement. Devices will have a reserved
quanity of memory that is guaranteed, the rest can be used as available.
* expose entitlement, current allocation, desired allocation, and the
allocation error counter for devices to the user through sysfs
* provide mechanism for changing a device's desired entitlement at run time
for devices as an exported function and sysfs tunable
* track any DMA failures for entitled IO memory for each vio device.
* check entitlement against available system entitlement on device add
* track entitlement metrics (high water mark, current usage)
* provide function to reset high water mark
* provide minimum and desired entitlement numbers at a bus level
* provide drivers with a minimum guaranteed entitlement
* balance available entitlement between devices to satisfy their needs
* handle system entitlement changes and device hotplug
Signed-off-by: Robert Jennings <redacted>
---
arch/powerpc/kernel/vio.c | 958 +++++++++++++++++++++++++++++++++++++++++=
+++++
include/asm-powerpc/vio.h | 30 +
2 files changed, 981 insertions(+), 7 deletions(-)
Index: b/arch/powerpc/kernel/vio.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
=20
if (!viodrv->probe)
return error;
=20
+ memset(&viodev->cmo, 0, sizeof(viodev->cmo));
+
+ /*
+ * Determine the devices IO memory entitlement needs, attempting
+ * to satisfy the system minimum entitlement at first and scheduling
+ * a balance operation to take care of the rest at a later time.
+ */
+ if (firmware_has_feature(FW_FEATURE_CMO)) {
+ /* Check that the driver is CMO enabled and get entitlement */
+ if (!viodrv->get_io_entitlement) {
+ dev_err(dev, "%s: device driver does not support CMO\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * Check to see that device has a DMA window and configure
+ * entitlement for the device.
+ */
+ if (of_get_property(viodev->dev.archdata.of_node,
+ "ibm,my-dma-window", NULL)) {
+ viodev->cmo.desired =3D viodrv->get_io_entitlement(viodev);
+ if (viodev->cmo.desired < VIO_CMO_MIN_ENT)
+ viodev->cmo.desired =3D VIO_CMO_MIN_ENT;
+ size =3D VIO_CMO_MIN_ENT;
+
+ dev_ent =3D kmalloc(sizeof(struct vio_cmo_dev_entry),
+ GFP_KERNEL);
+ if (!dev_ent)
+ return -ENOMEM;
+
+ dev_ent->viodev =3D viodev;
+ spin_lock_irqsave(&vio_cmo.lock, flags);
+ list_add(&dev_ent->list, &vio_cmo.device_list);
+ } else {
+ viodev->cmo.desired =3D 0;
+ size =3D 0;
+ spin_lock_irqsave(&vio_cmo.lock, flags);
+ }
+
+ /*
+ * If the needs for vio_cmo.min have not changed since they
+ * were last set, the number of devices in the OF tree has
+ * been constant and the IO memory for this is already in
+ * the reserve pool.
+ */
+ if (vio_cmo.min =3D=3D ((vio_cmo_num_OF_devs() + 1) *
+ VIO_CMO_MIN_ENT)) {
+ /* Updated desired entitlement if device requires it */
+ if (size)
+ vio_cmo.desired +=3D (viodev->cmo.desired -
+ VIO_CMO_MIN_ENT);
+ } else {
+ size_t tmp;
+
+ tmp =3D vio_cmo.spare + vio_cmo.excess.free;
+ if (tmp < size) {
+ dev_err(dev, "%s: insufficient free "
+ "entitlement to add device. "
+ "Need %lu, have %lu\n", __func__,
+ size, (vio_cmo.spare + tmp));
+ error =3D -ENOMEM;
+ goto out_unlock;
+ }
+
+ /* Use excess pool first to fulfill request */
+ tmp =3D min(size, vio_cmo.excess.free);
+ vio_cmo.excess.free -=3D tmp;
+ vio_cmo.excess.size -=3D tmp;
+ vio_cmo.reserve.size +=3D tmp;
+
+ /* Use spare if excess pool was insufficient */
+ vio_cmo.spare -=3D size - tmp;
+
+ /* Update bus accounting */
+ vio_cmo.min +=3D size;
+ vio_cmo.desired +=3D viodev->cmo.desired;
+ }
+
+ /* Give the device the minimum system entitlement */
+ viodev->cmo.entitled =3D size;
+
+ /* Balance IO usage if needed */
+ if (viodev->cmo.entitled < viodev->cmo.desired)
+ schedule_delayed_work(&vio_cmo.balance_q,
+ VIO_CMO_BALANCE_DELAY);
+
+ spin_unlock_irqrestore(&vio_cmo.lock, flags);
+ }
+
id =3D vio_match_device(viodrv->id_table, viodev);
if (id)
error =3D viodrv->probe(viodev, id);
=20
return error;
+
+out_unlock:
+ spin_unlock_irqrestore(&vio_cmo.lock, flags);
+ return error;
}
=20
/* convert from struct device to struct vio_dev and pass to driver. */
@@ -125,12 +778,89 @@ static int vio_bus_remove(struct device=20 { struct vio_dev *viodev =3D to_vio_dev(dev); struct vio_driver *viodrv =3D to_vio_driver(dev->driver);+ struct vio_cmo_dev_entry *dev_ent;+ struct device *devptr;+ unsigned long flags;+ size_t tmp;+ int ret =3D 1;++ /*+ * Hold a reference to the device after the remove function is called+ * to allow for CMO accounting cleanup for the device.+ */+ devptr =3D get_device(dev);
=20
if (viodrv->remove)
- return viodrv->remove(viodev);
+ ret =3D viodrv->remove(viodev);
+
+ if (firmware_has_feature(FW_FEATURE_CMO)) {
+ spin_lock_irqsave(&vio_cmo.lock, flags);
+ if (viodev->cmo.allocated) {
+ dev_err(dev, "%s: device had %lu bytes of IO "
+ "allocated after remove operation.\n",
+ __func__, viodev->cmo.allocated);
+ BUG();
+ }
+
+ /*
+ * Remove the device from the device list being maintained for
+ * CMO enabled devices.
+ */
+ list_for_each_entry(dev_ent, &vio_cmo.device_list, list)
+ if (viodev =3D=3D dev_ent->viodev) {
+ list_del(&dev_ent->list);
+ kfree(dev_ent);
+ break;
+ }
=20
- /* driver can't remove */
- return 1;
+ /*
+ * Devices may not require any entitlement and they do not need
+ * to be processed. Otherwise, return the device's entitlement
+ * back to the pools.
+ */
+ if (viodev->cmo.entitled) {
+ /*
+ * This device has not yet left the OF tree, it's
+ * minimum entitlement remains in vio_cmo.min and
+ * vio_cmo.desired
+ */
+ vio_cmo.desired -=3D (viodev->cmo.desired - VIO_CMO_MIN_ENT);
+
+ /*
+ * Save min allocation for device in reserve as long
+ * as it exists in OF tree as determined by later
+ * balance operation
+ */
+ viodev->cmo.entitled -=3D VIO_CMO_MIN_ENT;
+
+ /* Replenish spare from freed reserve pool */
+ if (viodev->cmo.entitled && (vio_cmo.spare < VIO_CMO_MIN_ENT)) {
+ tmp =3D min(viodev->cmo.entitled, (VIO_CMO_MIN_ENT -
+ vio_cmo.spare));
+ vio_cmo.spare +=3D tmp;
+ viodev->cmo.entitled -=3D tmp;
+ }
+
+ /* Remaining reserve goes to excess pool */
+ vio_cmo.excess.size +=3D viodev->cmo.entitled;
+ vio_cmo.excess.free +=3D viodev->cmo.entitled;
+ vio_cmo.reserve.size -=3D viodev->cmo.entitled;
+
+ /*
+ * Until the device is removed it will keep a
+ * minimum entitlemet; this will guarantee that
+ * a module unload/load will result in a success.
+ */
+ viodev->cmo.entitled =3D VIO_CMO_MIN_ENT;
+ viodev->cmo.desired =3D VIO_CMO_MIN_ENT;
+ atomic_set(&viodev->cmo.allocs_failed, 0);
+ }
+
+ spin_unlock_irqrestore(&vio_cmo.lock, flags);
+ }
+
+ put_device(devptr);
+ return ret;
}
=20
/**
=20
err =3D bus_register(&vio_bus_type);
if (err) {
@@ -263,6 +1009,44 @@ static int __init vio_bus_init(void) }
=20
node_vroot =3D of_find_node_by_name(NULL, "vdevice");
+
+ /* Set the reserve pool based on the number of virtual devices in OF */
+ if (firmware_has_feature(FW_FEATURE_CMO)) {
+ INIT_DELAYED_WORK(&vio_cmo.balance_q, vio_cmo_balance);
+
+ /* Get current system entitlement */
+ err =3D h_get_mpp(&mpp_data);
+
+ /*
+ * On failure, continue with entitlement set to 0, will panic()
+ * later when spare is reserved and lights will be set.
+ */
+ if (err !=3D H_SUCCESS) {
+ printk(KERN_ERR "%s: unable to determine system IO "\
+ "entitlement. (%d)\n", __func__, err);
+ vio_cmo.entitled =3D 0;
+ } else {
+ vio_cmo.entitled =3D mpp_data.entitled_mem;
+ }
+
+ /* Set reservation and check against entitlement */
+ vio_cmo.spare =3D VIO_CMO_MIN_ENT;
+ vio_cmo.reserve.size =3D vio_cmo.spare;
+ vio_cmo.reserve.size +=3D (vio_cmo_num_OF_devs() *
+ VIO_CMO_MIN_ENT);
+ if (vio_cmo.reserve.size > vio_cmo.entitled) {
+ printk(KERN_ERR "%s: insufficient system entitlement\n",
+ __func__);
+ panic("%s: Insufficient system entitlement", __func__);
+ }
+
+ /* Set the remaining accounting variables */
+ vio_cmo.excess.size =3D vio_cmo.entitled - vio_cmo.reserve.size;
+ vio_cmo.excess.free =3D vio_cmo.excess.size;
+ vio_cmo.min =3D vio_cmo.reserve.size;
+ vio_cmo.desired =3D vio_cmo.reserve.size;
+ }
+
if (node_vroot) {
struct device_node *of_node;
=20
@@ -280,6 +1064,71 @@ static int __init vio_bus_init(void) } __initcall(vio_bus_init);
=20
+/**
+ * vio_cmo_set_dev_desired - Set desired entitlement for a device
+ *
+ * @viodev: struct vio_dev for device to alter
+ * @new_desired: new desired entitlement level in bytes
+ *
+ * For use by devices to request a change to their entitlement at runtime =
or
+ * through sysfs. The desired entitlement level is changed and a balancing
+ * of system resources is scheduled to run in the future.
+ */
+void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired)
+{
+ unsigned long flags;
+ struct vio_cmo_dev_entry *dev_ent;
+
+ if (!firmware_has_feature(FW_FEATURE_CMO))
+ return;
+
+ spin_lock_irqsave(&vio_cmo.lock, flags);
+ if (desired < VIO_CMO_MIN_ENT)
+ desired =3D VIO_CMO_MIN_ENT;
+
+ /*
+ * Changes will not be made for devices not in the device list.
+ * If it is not in the device list, then no driver is loaded
+ * for the device and it can not receive entitlement.
+ */
+ list_for_each_entry(dev_ent, &vio_cmo.device_list, list)
+ if (viodev =3D=3D dev_ent->viodev)
+ break;
+ if (!dev_ent)
+ return;
+
+ /* Increase/decrease in desired device entitlement */
+ if (desired >=3D viodev->cmo.desired) {
+ /* Just bump the bus and device values prior to a balance*/
+ vio_cmo.desired +=3D desired - viodev->cmo.desired;
+ viodev->cmo.desired =3D desired;
+ } else {
+ /* Decrease bus and device values for desired entitlement */
+ vio_cmo.desired -=3D viodev->cmo.desired - desired;
+ viodev->cmo.desired =3D desired;
+ /*
+ * If less entitlement is desired than current entitlement, move
+ * any reserve memory in the change region to the excess pool.
+ */
+ if (viodev->cmo.entitled > desired) {
+ vio_cmo.reserve.size -=3D viodev->cmo.entitled - desired;
+ vio_cmo.excess.size +=3D viodev->cmo.entitled - desired;
+ /*
+ * If entitlement moving from the reserve pool to the
+ * excess pool is currently unused, add to the excess
+ * free counter.
+ */
+ if (viodev->cmo.allocated < viodev->cmo.entitled)
+ vio_cmo.excess.free +=3D viodev->cmo.entitled -
+ max(viodev->cmo.allocated, desired);
+ viodev->cmo.entitled =3D desired;
+ }
+ }
+ schedule_delayed_work(&vio_cmo.balance_q, 0);
+ spin_unlock_irqrestore(&vio_cmo.lock, flags);
+}
+EXPORT_SYMBOL(vio_cmo_set_dev_desired);
+
static ssize_t name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
=20
+/*
+ * VIO CMO minimum entitlement for all devices and spare entitlement
+ */
+#define VIO_CMO_MIN_ENT 1562624
+
struct iommu_table;
=20
-/*
- * The vio_dev structure is used to describe virtual I/O devices.
+/**
+ * vio_dev - This structure is used to describe virtual I/O devices.
+ *
+ * @desired: set from return of driver's get_io_entitlement() function
+ * @entitled: bytes of IO data that has been reserved for this device.
+ * @entitled_target: Target IO data allocation for device. This may be set
+ * lower than entitled to enable balancing; can not be larger than entit=
led.
+ * @allocated: bytes of IO data currently in use by the device.
+ * @allocs_failed: number of DMA failures due to insufficient entitlement.
*/
struct vio_dev {
const char *name;
const char *type;
uint32_t unit_address;
unsigned int irq;
+ struct {
+ size_t desired;
+ size_t entitled;
+ size_t allocated;
+ atomic_t allocs_failed;
+ } cmo;
struct device dev;
};
=20
@@ -56,12 +74,20 @@ struct vio_driver { const struct vio_device_id *id_table; int (*probe)(struct vio_dev *dev, const struct vio_device_id *id); int (*remove)(struct vio_dev *dev);+ /* A driver must have a get_io_entitlement() function to+ * be loaded in a CMO environment, it may return 0 if no I/O+ * entitlement is needed.+ */+ unsigned long (*get_io_entitlement)(struct vio_dev *dev); struct device_driver driver; };
From: Stephen Rothwell <hidden> Date: 2008-06-13 05:12:30
Hi Robert,
Firstly, can all this new stuff be ifdef'ed out if not needed as the
vio infrastructure is also used on legacy iSeries and this adds quite a
bit of stuff that won't ever be used there.
On Thu, 12 Jun 2008 17:19:59 -0500 Robert Jennings [off-list ref] wrote:
+static int vio_cmo_num_OF_devs(void)
+{
+ struct device_node *node_vroot;
+ int count = 0;
+
+ /*
+ * Count the number of vdevice entries with an
+ * ibm,my-dma-window OF property
+ */
+ node_vroot = of_find_node_by_name(NULL, "vdevice");
+ if (node_vroot) {
+ struct device_node *of_node;
+ struct property *prop;
+
+ for (of_node = node_vroot->child; of_node != NULL;
+ of_node = of_node->sibling) {
Use:
for_each_child_of_node(node_vroot, of_node) {
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
From: Robert Jennings <hidden> Date: 2008-06-23 20:24:05
* Stephen Rothwell (sfr@canb.auug.org.au) wrote:
Hi Robert,
Firstly, can all this new stuff be ifdef'ed out if not needed as the
vio infrastructure is also used on legacy iSeries and this adds quite a
bit of stuff that won't ever be used there.
I've changed the patch to ifdef out CMO for legacy iSeries. This should
keep things cleaner.
On Thu, 12 Jun 2008 17:19:59 -0500 Robert Jennings [off-list ref] wrote:
quoted
+static int vio_cmo_num_OF_devs(void)
+{
+ struct device_node *node_vroot;
+ int count = 0;
+
+ /*
+ * Count the number of vdevice entries with an
+ * ibm,my-dma-window OF property
+ */
+ node_vroot = of_find_node_by_name(NULL, "vdevice");
+ if (node_vroot) {
+ struct device_node *of_node;
+ struct property *prop;
+
+ for (of_node = node_vroot->child; of_node != NULL;
+ of_node = of_node->sibling) {
From: Robert Jennings <hidden> Date: 2008-06-23 20:25:26
=46rom: Robert Jennings [off-list ref]
Enable bus level entitled memory accounting for Cooperative Memory
Overcommitment (CMO) environments. The normal code path should not
be affected.
The following changes are made that the VIO bus layer for CMO:
* add IO memory accounting per device structure.
* add IO memory entitlement query function to driver structure.
* during vio bus probe, if CMO is enabled, check that driver has
memory entitlement query function defined. Fail if function not defined.
* fail to register driver if io entitlement function not defined.
* create set of dma_ops at vio level for CMO that will track allocations
and return DMA failures once entitlement is reached. Entitlement will
limited by overall system entitlement. Devices will have a reserved
quanity of memory that is guaranteed, the rest can be used as available.
* expose entitlement, current allocation, desired allocation, and the
allocation error counter for devices to the user through sysfs
* provide mechanism for changing a device's desired entitlement at run time
for devices as an exported function and sysfs tunable
* track any DMA failures for entitled IO memory for each vio device.
* check entitlement against available system entitlement on device add
* track entitlement metrics (high water mark, current usage)
* provide function to reset high water mark
* provide minimum and desired entitlement numbers at a bus level
* provide drivers with a minimum guaranteed entitlement
* balance available entitlement between devices to satisfy their needs
* handle system entitlement changes and device hotplug
Signed-off-by: Robert Jennings <redacted>
---
arch/powerpc/kernel/vio.c | 1030 +++++++++++++++++++++++++++++++++++++++++=
+++++
include/asm-powerpc/vio.h | 30 +
2 files changed, 1052 insertions(+), 8 deletions(-)
Index: b/arch/powerpc/kernel/vio.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
=20
id =3D vio_match_device(viodrv->id_table, viodev);
- if (id)
+ if (id) {
+ memset(&viodev->cmo, 0, sizeof(viodev->cmo));
+ if (firmware_has_feature(FW_FEATURE_CMO)) {
+ error =3D vio_cmo_bus_probe(viodev);
+ if (error)
+ return error;
+ }
error =3D viodrv->probe(viodev, id);
+ if (error)
+ vio_cmo_bus_remove(viodev);
+ }
=20
return error;
}
@@ -125,12 +1115,23 @@ static int vio_bus_remove(struct device=20 { struct vio_dev *viodev =3D to_vio_dev(dev); struct vio_driver *viodrv =3D to_vio_driver(dev->driver);+ struct device *devptr;+ int ret =3D 1;++ /*+ * Hold a reference to the device after the remove function is called+ * to allow for CMO accounting cleanup for the device.+ */+ devptr =3D get_device(dev);
=20
+/*
+ * VIO CMO minimum entitlement for all devices and spare entitlement
+ */
+#define VIO_CMO_MIN_ENT 1562624
+
struct iommu_table;
=20
-/*
- * The vio_dev structure is used to describe virtual I/O devices.
+/**
+ * vio_dev - This structure is used to describe virtual I/O devices.
+ *
+ * @desired: set from return of driver's get_io_entitlement() function
+ * @entitled: bytes of IO data that has been reserved for this device.
+ * @entitled_target: Target IO data allocation for device. This may be set
+ * lower than entitled to enable balancing; can not be larger than entit=
led.
+ * @allocated: bytes of IO data currently in use by the device.
+ * @allocs_failed: number of DMA failures due to insufficient entitlement.
*/
struct vio_dev {
const char *name;
const char *type;
uint32_t unit_address;
unsigned int irq;
+ struct {
+ size_t desired;
+ size_t entitled;
+ size_t allocated;
+ atomic_t allocs_failed;
+ } cmo;
struct device dev;
};
=20
@@ -56,12 +74,20 @@ struct vio_driver { const struct vio_device_id *id_table; int (*probe)(struct vio_dev *dev, const struct vio_device_id *id); int (*remove)(struct vio_dev *dev);+ /* A driver must have a get_io_entitlement() function to+ * be loaded in a CMO environment, it may return 0 if no I/O+ * entitlement is needed.+ */+ unsigned long (*get_io_entitlement)(struct vio_dev *dev); struct device_driver driver; };
=20
+ if (entitlement) {
+ /* Check with vio to ensure the new memory entitlement
+ * can be handled.
+ */
+ rc =3D vio_cmo_entitlement_update(*entitlement);
+ if (rc)
+ return rc;
+ }
+
rc =3D h_get_mpp(&mpp_data);
if (rc)
return rc;
From: Robert Jennings <hidden> Date: 2008-06-12 22:23:31
=46rom: Robert Jennings [off-list ref]
Define a get_io_entitlement function so that it can function in a
Cooperative Memory Overcommitment (CMO) environment (it returns 0 to
indicate that no IO entitlement is required, as the driver does not
perform DMA operations).
Signed-off-by: Robert Jennings <redacted>
---
drivers/char/hvc_vio.c | 6 ++++++
1 file changed, 6 insertions(+)
Index: b/drivers/char/hvc_vio.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
From: Robert Jennings <hidden> Date: 2008-06-12 22:24:09
=46rom: Robert Jennings [off-list ref]
Define a get_io_entitlement function so that it can function in a
Cooperative Memory Overcommitment (CMO) environment (it returns 0 to
indicate that no IO entitlement is required, as the driver does not
perform DMA operations).
Signed-off-by: Robert Jennings <redacted>
---
drivers/char/hvcs.c | 6 ++++++
1 file changed, 6 insertions(+)
Index: b/drivers/char/hvcs.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
From: Robert Jennings <hidden> Date: 2008-06-12 22:24:24
=46rom: Santiago Leon [off-list ref]
Activates larger rx buffer pools when the MTU is changed to a larger
value. This patch de-activates the large rx buffer pools when the MTU
changes to a smaller value.
Signed-off-by: Santiago Leon <redacted>
---
drivers/net/ibmveth.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
Index: b/drivers/net/ibmveth.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
@@ -1054,7 +1054,6 @@ static int ibmveth_change_mtu(struct net{structibmveth_adapter*adapter=3Ddev->priv;intnew_mtu_oh=3Dnew_mtu+IBMVETH_BUFF_OH;-intreinit=3D0;inti,rc;
=20
if (new_mtu < IBMVETH_MAX_MTU)
@@ -1067,15 +1066,21 @@ static int ibmveth_change_mtu(struct net if (i =3D=3D IbmVethNumBufferPools) return -EINVAL;
=20
+ /* Deactivate all the buffer pools so that the next loop can activate
+ only the buffer pools necessary to hold the new MTU */
+ for(i =3D 0; i<IbmVethNumBufferPools; i++)
+ if (adapter->rx_buff_pool[i].active) {
+ ibmveth_free_buffer_pool(adapter,
+ &adapter->rx_buff_pool[i]);
+ adapter->rx_buff_pool[i].active =3D 0;
+ }
+
/* Look for an active buffer pool that can hold the new MTU */
for(i =3D 0; i<IbmVethNumBufferPools; i++) {
- if (!adapter->rx_buff_pool[i].active) {
- adapter->rx_buff_pool[i].active =3D 1;
- reinit =3D 1;
- }
+ adapter->rx_buff_pool[i].active =3D 1;
=20
if (new_mtu_oh < adapter->rx_buff_pool[i].buff_size) {
- if (reinit && netif_running(adapter->netdev)) {
+ if (netif_running(adapter->netdev)) {
adapter->pool_config =3D 1;
ibmveth_close(adapter->netdev);
adapter->pool_config =3D 0;
From: Stephen Rothwell <hidden> Date: 2008-06-13 05:18:39
Hi Robert,
On Thu, 12 Jun 2008 17:22:49 -0500 Robert Jennings [off-list ref] wrote:
+ /* Deactivate all the buffer pools so that the next loop can activate
+ only the buffer pools necessary to hold the new MTU */
+ for(i = 0; i<IbmVethNumBufferPools; i++)
Please uses spaces after "for" and around binary operators.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
From: Robert Jennings <hidden> Date: 2008-06-23 20:21:57
=46rom: Santiago Leon [off-list ref]
Fixed patch formatting.
Activates larger rx buffer pools when the MTU is changed to a larger
value. This patch de-activates the large rx buffer pools when the MTU
changes to a smaller value.
Signed-off-by: Santiago Leon <redacted>
Signed-off-by: Robert Jennings <redacted>
---
drivers/net/ibmveth.c | 20 +++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)
Index: b/drivers/net/ibmveth.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
@@ -1054,7 +1054,6 @@ static int ibmveth_change_mtu(struct net{structibmveth_adapter*adapter=3Ddev->priv;intnew_mtu_oh=3Dnew_mtu+IBMVETH_BUFF_OH;-intreinit=3D0;inti,rc;
=20
if (new_mtu < IBMVETH_MAX_MTU)
@@ -1067,15 +1066,21 @@ static int ibmveth_change_mtu(struct net if (i =3D=3D IbmVethNumBufferPools) return -EINVAL;
=20
+ /* Deactivate all the buffer pools so that the next loop can activate
+ only the buffer pools necessary to hold the new MTU */
+ for (i =3D 0; i < IbmVethNumBufferPools; i++)
+ if (adapter->rx_buff_pool[i].active) {
+ ibmveth_free_buffer_pool(adapter,
+ &adapter->rx_buff_pool[i]);
+ adapter->rx_buff_pool[i].active =3D 0;
+ }
+
/* Look for an active buffer pool that can hold the new MTU */
for(i =3D 0; i<IbmVethNumBufferPools; i++) {
- if (!adapter->rx_buff_pool[i].active) {
- adapter->rx_buff_pool[i].active =3D 1;
- reinit =3D 1;
- }
+ adapter->rx_buff_pool[i].active =3D 1;
=20
if (new_mtu_oh < adapter->rx_buff_pool[i].buff_size) {
- if (reinit && netif_running(adapter->netdev)) {
+ if (netif_running(adapter->netdev)) {
adapter->pool_config =3D 1;
ibmveth_close(adapter->netdev);
adapter->pool_config =3D 0;
From: Robert Jennings <hidden> Date: 2008-06-12 22:24:46
=46rom: Robert Jennings [off-list ref]
Enable ibmveth for Cooperative Memory Overcommitment (CMO). For this driver
it means calculating a desired amount of IO memory based on the current MTU
and updating this value with the bus when MTU changes occur. Because DMA
mappings can fail, we have added a bounce buffer for temporary cases where
the driver can not map IO memory for the buffer pool.
The following changes are made to enable the driver for CMO:
* DMA mapping errors will not result in error messages if entitlement has
been exceeded and resources were not available.
* DMA mapping errors are handled gracefully, ibmveth_replenish_buffer_pool=
()
is corrected to check the return from dma_map_single and fail gracefully.
* The driver will have a get_io_entitlement function defined to function
in a CMO environment.
* When the MTU is changed, the driver will update the device IO entitlement
Signed-off-by: Robert Jennings <redacted>
Signed-off-by: Brian King <redacted>
Signed-off-by: Santiago Leon <redacted>
---
drivers/net/ibmveth.c | 169 ++++++++++++++++++++++++++++++++++++++++-----=
-----
drivers/net/ibmveth.h | 5 +
2 files changed, 140 insertions(+), 34 deletions(-)
Index: b/drivers/net/ibmveth.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
@@ -853,10 +898,12 @@ static int ibmveth_start_xmit(struct sk_ unsigned int tx_packets =3D 0; unsigned int tx_send_failed =3D 0; unsigned int tx_map_failed =3D 0;+ int used_bounce =3D 0;+ unsigned long data_dma_addr;
=20
+/**
+ * ibmveth_get_io_entitlement - Calculate IO entitlement needed by the dri=
ver
+ *
+ * @vdev: struct vio_dev for the device whose entitlement is to be returned
+ *
+ * Return value:
+ * Number of bytes of IO data the driver will need to perform well.
+ */
+static unsigned long ibmveth_get_io_entitlement(struct vio_dev *vdev)
+{
+ struct net_device *netdev =3D dev_get_drvdata(&vdev->dev);
+ struct ibmveth_adapter *adapter;
+ unsigned long ret;
+ int i;
+ int rxqentries =3D 1;
+
+ /* netdev inits at probe time along with the structures we need below*/
+ if (netdev =3D=3D NULL)
+ return IOMMU_PAGE_ALIGN(IBMVETH_IO_ENTITLEMENT_DEFAULT);
+
+ adapter =3D netdev_priv(netdev);
+
+ ret =3D IBMVETH_BUFF_LIST_SIZE + IBMVETH_FILT_LIST_SIZE;
+ ret +=3D IOMMU_PAGE_ALIGN(netdev->mtu);
+
+ for (i =3D 0; i < IbmVethNumBufferPools; i++) {
+ /* add the size of the active receive buffers */
+ if (adapter->rx_buff_pool[i].active)
+ ret +=3D
+ adapter->rx_buff_pool[i].size *
+ IOMMU_PAGE_ALIGN(adapter->rx_buff_pool[i].
+ buff_size);
+ rxqentries +=3D adapter->rx_buff_pool[i].size;
+ }
+ /* add the size of the receive queue entries */
+ ret +=3D IOMMU_PAGE_ALIGN(rxqentries * sizeof(struct ibmveth_rx_q_entry));
+
+ return ret;
+}
+
static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_d=
evice_id *id)
{
int rc, i;
@@ -1247,6 +1345,8 @@ static int __devexit ibmveth_remove(stru ibmveth_proc_unregister_adapter(adapter);
From: Robert Jennings <hidden> Date: 2008-06-23 20:20:42
Fixed patch formatting.
Enable ibmveth for Cooperative Memory Overcommitment (CMO). For this driver
it means calculating a desired amount of IO memory based on the current MTU
and updating this value with the bus when MTU changes occur. Because DMA
mappings can fail, we have added a bounce buffer for temporary cases where
the driver can not map IO memory for the buffer pool.
The following changes are made to enable the driver for CMO:
* DMA mapping errors will not result in error messages if entitlement has
been exceeded and resources were not available.
* DMA mapping errors are handled gracefully, ibmveth_replenish_buffer_pool()
is corrected to check the return from dma_map_single and fail gracefully.
* The driver will have a get_io_entitlement function defined to function
in a CMO environment.
* When the MTU is changed, the driver will update the device IO entitlement
Signed-off-by: Robert Jennings <redacted>
Signed-off-by: Brian King <redacted>
Signed-off-by: Santiago Leon <redacted>
---
drivers/net/ibmveth.c | 169 ++++++++++++++++++++++++++++++++++++++++----------
drivers/net/ibmveth.h | 5 +
2 files changed, 140 insertions(+), 34 deletions(-)
Index: b/drivers/net/ibmveth.c
===================================================================
@@ -607,6 +634,24 @@ static int ibmveth_open(struct net_devicreturnrc;}+adapter->bounce_buffer=+kmalloc(netdev->mtu+IBMVETH_BUFF_OH,GFP_KERNEL);+if(!adapter->bounce_buffer){+ibmveth_error_printk("unable to allocate bounce buffer\n");+ibmveth_cleanup(adapter);+napi_disable(&adapter->napi);+return-ENOMEM;+}+adapter->bounce_buffer_dma=+dma_map_single(&adapter->vdev->dev,adapter->bounce_buffer,+netdev->mtu+IBMVETH_BUFF_OH,DMA_BIDIRECTIONAL);+if(dma_mapping_error(adapter->bounce_buffer_dma)){+ibmveth_error_printk("unable to map bounce buffer\n");+ibmveth_cleanup(adapter);+napi_disable(&adapter->napi);+return-ENOMEM;+}+ibmveth_debug_printk("initial replenish cycle\n");ibmveth_interrupt(netdev->irq,netdev);
@@ -853,10 +898,12 @@ static int ibmveth_start_xmit(struct sk_unsignedinttx_packets=0;unsignedinttx_send_failed=0;unsignedinttx_map_failed=0;+intused_bounce=0;+unsignedlongdata_dma_addr;desc.fields.flags_len=IBMVETH_BUF_VALID|skb->len;-desc.fields.address=dma_map_single(&adapter->vdev->dev,skb->data,-skb->len,DMA_TO_DEVICE);+data_dma_addr=dma_map_single(&adapter->vdev->dev,skb->data,+skb->len,DMA_TO_DEVICE);if(skb->ip_summed==CHECKSUM_PARTIAL&&ip_hdr(skb)->protocol!=IPPROTO_TCP&&skb_checksum_help(skb)){
@@ -875,12 +922,16 @@ static int ibmveth_start_xmit(struct sk_buf[1]=0;}-if(dma_mapping_error(desc.fields.address)){-ibmveth_error_printk("tx: unable to map xmit buffer\n");+if(dma_mapping_error(data_dma_addr)){+if(!firmware_has_feature(FW_FEATURE_CMO))+ibmveth_error_printk("tx: unable to map xmit buffer\n");+skb_copy_from_linear_data(skb,adapter->bounce_buffer,+skb->len);+desc.fields.address=adapter->bounce_buffer_dma;tx_map_failed++;-tx_dropped++;-gotoout;-}+used_bounce=1;+}else+desc.fields.address=data_dma_addr;/* send the frame. Arbitrarily set retrycount to 1024 */correlator=0;
@@ -904,8 +955,9 @@ static int ibmveth_start_xmit(struct sk_netdev->trans_start=jiffies;}-dma_unmap_single(&adapter->vdev->dev,desc.fields.address,-skb->len,DMA_TO_DEVICE);+if(!used_bounce)+dma_unmap_single(&adapter->vdev->dev,data_dma_addr,+skb->len,DMA_TO_DEVICE);out:spin_lock_irqsave(&adapter->stats_lock,flags);netdev->stats.tx_dropped+=tx_dropped;
@@ -1085,10 +1138,15 @@ static int ibmveth_change_mtu(struct netibmveth_close(adapter->netdev);adapter->pool_config=0;dev->mtu=new_mtu;-if((rc=ibmveth_open(adapter->netdev)))-returnrc;-}else-dev->mtu=new_mtu;+vio_cmo_set_dev_desired(viodev,+ibmveth_get_io_entitlement+(viodev));+returnibmveth_open(adapter->netdev);+}+dev->mtu=new_mtu;+vio_cmo_set_dev_desired(viodev,+ibmveth_get_io_entitlement+(viodev));return0;}}
@@ -1103,6 +1161,46 @@ static void ibmveth_poll_controller(stru}#endif+/**+*ibmveth_get_io_entitlement-CalculateIOentitlementneededbythedriver+*+*@vdev:structvio_devforthedevicewhoseentitlementistobereturned+*+*Returnvalue:+*NumberofbytesofIOdatathedriverwillneedtoperformwell.+*/+staticunsignedlongibmveth_get_io_entitlement(structvio_dev*vdev)+{+structnet_device*netdev=dev_get_drvdata(&vdev->dev);+structibmveth_adapter*adapter;+unsignedlongret;+inti;+intrxqentries=1;++/* netdev inits at probe time along with the structures we need below*/+if(netdev==NULL)+returnIOMMU_PAGE_ALIGN(IBMVETH_IO_ENTITLEMENT_DEFAULT);++adapter=netdev_priv(netdev);++ret=IBMVETH_BUFF_LIST_SIZE+IBMVETH_FILT_LIST_SIZE;+ret+=IOMMU_PAGE_ALIGN(netdev->mtu);++for(i=0;i<IbmVethNumBufferPools;i++){+/* add the size of the active receive buffers */+if(adapter->rx_buff_pool[i].active)+ret+=+adapter->rx_buff_pool[i].size*+IOMMU_PAGE_ALIGN(adapter->rx_buff_pool[i].+buff_size);+rxqentries+=adapter->rx_buff_pool[i].size;+}+/* add the size of the receive queue entries */+ret+=IOMMU_PAGE_ALIGN(rxqentries*sizeof(structibmveth_rx_q_entry));++returnret;+}+staticint__devinitibmveth_probe(structvio_dev*dev,conststructvio_device_id*id){intrc,i;
@@ -1247,6 +1345,8 @@ static int __devexit ibmveth_remove(struibmveth_proc_unregister_adapter(adapter);free_netdev(netdev);+dev_set_drvdata(&dev->dev,NULL);+return0;}
From: Robert Jennings <hidden> Date: 2008-06-12 22:26:02
=46rom: Robert Jennings [off-list ref]
Enable the driver to function in a Cooperative Memory Overcommitment (CMO)
environment.
The following changes are made to enable the driver for CMO:
* DMA mapping errors will not result in error messages if entitlement has
been exceeded and resources were not available.
* The driver has a get_io_entitlement function defined to function
in a CMO environment. It will indicate how much IO memory it would like
to function.
Signed-off-by: Robert Jennings <redacted>
---
drivers/scsi/ibmvscsi/ibmvscsi.c | 46 +++++++++++++++++++++++++++++++++-=
-----
drivers/scsi/ibmvscsi/ibmvscsi.h | 2 ++
2 files changed, 41 insertions(+), 7 deletions(-)
Index: b/drivers/scsi/ibmvscsi/ibmvscsi.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
=20
/**
+ * ibmvscsi_get_io_entitlement - Calculate IO entitlement needed by the dr=
iver
+ *
+ * @vdev: struct vio_dev for the device whose entitlement is to be returned
+ *
+ * Return value:
+ * Number of bytes of IO data the driver will need to perform well.
+ */
+static unsigned long ibmvscsi_get_io_entitlement(struct vio_dev *vdev)
+{
+ /* iu_storage data allocated in initialize_event_pool */
+ unsigned long io_entitlement =3D max_requests * sizeof(union viosrp_iu);
+
+ /* add io space for sg data */
+ io_entitlement +=3D (IBMVSCSI_MAX_SECTORS_DEFAULT *
+ IBMVSCSI_CMDS_PER_LUN_DEFAULT);
+
+ return IOMMU_PAGE_ALIGN(io_entitlement);
+}
+
+/**
* Called by bus code for each adapter
*/
static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id=
*id)
From: Brian King <hidden> Date: 2008-06-13 18:31:41
CC'ing linux-scsi, although we'd like to take this through the powerpc tree since it
is part of a patch set to enable a Power platform feature.
-Brian
Robert Jennings wrote:
quoted hunk
From: Robert Jennings <redacted>
Enable the driver to function in a Cooperative Memory Overcommitment (CMO)
environment.
The following changes are made to enable the driver for CMO:
* DMA mapping errors will not result in error messages if entitlement has
been exceeded and resources were not available.
* The driver has a get_io_entitlement function defined to function
in a CMO environment. It will indicate how much IO memory it would like
to function.
Signed-off-by: Robert Jennings <redacted>
---
drivers/scsi/ibmvscsi/ibmvscsi.c | 46 +++++++++++++++++++++++++++++++++------
drivers/scsi/ibmvscsi/ibmvscsi.h | 2 ++
2 files changed, 41 insertions(+), 7 deletions(-)
Index: b/drivers/scsi/ibmvscsi/ibmvscsi.c
===================================================================
@@ -426,8 +428,10 @@ static int map_sg_data(struct scsi_cmnd SG_ALL*sizeof(structsrp_direct_buf),&evt_struct->ext_list_token,0);if(!evt_struct->ext_list){-sdev_printk(KERN_ERR,cmd->device,-"Can't allocate memory for indirect table\n");+if(!firmware_has_feature(FW_FEATURE_CMO))+sdev_printk(KERN_ERR,cmd->device,+"Can't allocate memory "+"for indirect table\n");return0;}}
@@ -743,7 +747,9 @@ static int ibmvscsi_queuecommand(struct srp_cmd->lun=((u64)lun)<<48;if(!map_data_for_srp_cmd(cmnd,evt_struct,srp_cmd,hostdata->dev)){-sdev_printk(KERN_ERR,cmnd->device,"couldn't convert cmd to srp_cmd\n");+if(!firmware_has_feature(FW_FEATURE_CMO))+sdev_printk(KERN_ERR,cmnd->device,+"couldn't convert cmd to srp_cmd\n");free_event_struct(&hostdata->pool,evt_struct);returnSCSI_MLQUEUE_HOST_BUSY;}
@@ -855,7 +861,10 @@ static void send_mad_adapter_info(structDMA_BIDIRECTIONAL);if(dma_mapping_error(req->buffer)){-dev_err(hostdata->dev,"Unable to map request_buffer for adapter_info!\n");+if(!firmware_has_feature(FW_FEATURE_CMO))+dev_err(hostdata->dev,+"Unable to map request_buffer for "+"adapter_info!\n");free_event_struct(&hostdata->pool,evt_struct);return;}
@@ -1613,6 +1624,26 @@ static struct scsi_host_template driver_};/**+*ibmvscsi_get_io_entitlement-CalculateIOentitlementneededbythedriver+*+*@vdev:structvio_devforthedevicewhoseentitlementistobereturned+*+*Returnvalue:+*NumberofbytesofIOdatathedriverwillneedtoperformwell.+*/+staticunsignedlongibmvscsi_get_io_entitlement(structvio_dev*vdev)+{+/* iu_storage data allocated in initialize_event_pool */+unsignedlongio_entitlement=max_requests*sizeof(unionviosrp_iu);++/* add io space for sg data */+io_entitlement+=(IBMVSCSI_MAX_SECTORS_DEFAULT*+IBMVSCSI_CMDS_PER_LUN_DEFAULT);++returnIOMMU_PAGE_ALIGN(io_entitlement);+}++/***Calledbybuscodeforeachadapter*/staticintibmvscsi_probe(structvio_dev*vdev,conststructvio_device_id*id)
@@ -1641,7 +1672,7 @@ static int ibmvscsi_probe(struct vio_devhostdata->host=host;hostdata->dev=dev;atomic_set(&hostdata->request_limit,-1);-hostdata->host->max_sectors=32*8;/* default max I/O 32 pages */+hostdata->host->max_sectors=IBMVSCSI_MAX_SECTORS_DEFAULT;rc=ibmvscsi_ops->init_crq_queue(&hostdata->queue,hostdata,max_requests);if(rc!=0&&rc!=H_RESOURCE){
From: Robert Jennings <hidden> Date: 2008-06-12 22:33:30
=46rom: Nathan Fontenot [off-list ref]
Update the architecture vector to indicate that Cooperative Memory
Overcommitment is supported.
This is the last patch in the series. Committing it will signal to=20
the platform firmware is CMO enabled.
Signed-off-by: Nathan Fontenot <redacted>
---
arch/powerpc/kernel/prom_init.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
Index: b/arch/powerpc/kernel/prom_init.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D