for (i = 0, offset = 0; i < desc->out_num; i++) {
                u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i, buf,
-                               (u32 *) out_obj->buffer.pointer);
+                               (u32 *) out_obj->buffer.pointer,
+                               out_obj->buffer.length - offset);
 
                if (offset + out_size > out_obj->buffer.length) {
                        dev_dbg(dev, "%s:%s output object underflow cmd: %s field: %d\n",
 
 
 u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
                const struct nd_cmd_desc *desc, int idx, const u32 *in_field,
-               const u32 *out_field)
+               const u32 *out_field, unsigned long remainder)
 {
        if (idx >= desc->out_num)
                return UINT_MAX;
                return in_field[1];
        else if (nvdimm && cmd == ND_CMD_VENDOR && idx == 2)
                return out_field[1];
-       else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 2)
-               return out_field[1] - 8;
-       else if (cmd == ND_CMD_CALL) {
+       else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 2) {
+               /*
+                * Per table 9-276 ARS Data in ACPI 6.1, out_field[1] is
+                * "Size of Output Buffer in bytes, including this
+                * field."
+                */
+               if (out_field[1] < 4)
+                       return 0;
+               /*
+                * ACPI 6.1 is ambiguous if 'status' is included in the
+                * output size. If we encounter an output size that
+                * overshoots the remainder by 4 bytes, assume it was
+                * including 'status'.
+                */
+               if (out_field[1] - 8 == remainder)
+                       return remainder;
+               return out_field[1] - 4;
+       } else if (cmd == ND_CMD_CALL) {
                struct nd_cmd_pkg *pkg = (struct nd_cmd_pkg *) in_field;
 
                return pkg->nd_size_out;
        /* process an output envelope */
        for (i = 0; i < desc->out_num; i++) {
                u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i,
-                               (u32 *) in_env, (u32 *) out_env);
+                               (u32 *) in_env, (u32 *) out_env, 0);
                u32 copy;
 
                if (out_size == UINT_MAX) {
 
                const struct nd_cmd_desc *desc, int idx, void *buf);
 u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
                const struct nd_cmd_desc *desc, int idx, const u32 *in_field,
-               const u32 *out_field);
+               const u32 *out_field, unsigned long remainder);
 int nvdimm_bus_check_dimm_count(struct nvdimm_bus *nvdimm_bus, int dimm_count);
 struct nd_region *nvdimm_pmem_region_create(struct nvdimm_bus *nvdimm_bus,
                struct nd_region_desc *ndr_desc);