msm: kgsl: Clean up snapshot GPU object output
Use a iterator to cleanup how snapshot GPU objects are printed.
This removes a ton of ugly math, and allows us to do subtle
silly things like add padding at the end of a non dword
aligned object.
Change-Id: Ic0dedbadabeee50f42fe9be62ea0b7dfc1f333da
Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
diff --git a/drivers/gpu/msm/kgsl_snapshot.c b/drivers/gpu/msm/kgsl_snapshot.c
index 8935b29..6f0eaeb 100644
--- a/drivers/gpu/msm/kgsl_snapshot.c
+++ b/drivers/gpu/msm/kgsl_snapshot.c
@@ -35,6 +35,56 @@
struct list_head node;
};
+struct snapshot_obj_itr {
+ void *buf; /* Buffer pointer to write to */
+ int pos; /* Current position in the sequence */
+ loff_t offset; /* file offset to start writing from */
+ size_t remain; /* Bytes remaining in buffer */
+ size_t write; /* Bytes written so far */
+};
+
+static void obj_itr_init(struct snapshot_obj_itr *itr, void *buf,
+ loff_t offset, size_t remain)
+{
+ itr->buf = buf;
+ itr->offset = offset;
+ itr->remain = remain;
+ itr->pos = 0;
+ itr->write = 0;
+}
+
+static int obj_itr_out(struct snapshot_obj_itr *itr, void *src, int size)
+{
+ if (itr->remain == 0)
+ return 0;
+
+ if ((itr->pos + size) <= itr->offset)
+ goto done;
+
+ /* Handle the case that offset is in the middle of the buffer */
+
+ if (itr->offset > itr->pos) {
+ src += (itr->offset - itr->pos);
+ size -= (itr->offset - itr->pos);
+
+ /* Advance pos to the offset start */
+ itr->pos = itr->offset;
+ }
+
+ if (size > itr->remain)
+ size = itr->remain;
+
+ memcpy(itr->buf, src, size);
+
+ itr->buf += size;
+ itr->write += size;
+ itr->remain -= size;
+
+done:
+ itr->pos += size;
+ return size;
+}
+
/* idr_for_each function to count the number of contexts */
static int snapshot_context_count(int id, void *ptr, void *data)
@@ -182,76 +232,46 @@
(sizeof(struct kgsl_snapshot_section_header) + \
sizeof(struct kgsl_snapshot_gpu_object))
-#define GPU_OBJ_SECTION_SIZE(_o) \
- (GPU_OBJ_HEADER_SZ + ((_o)->size))
-
static int kgsl_snapshot_dump_object(struct kgsl_device *device,
- struct kgsl_snapshot_object *obj, void *buf,
- unsigned int off, unsigned int count)
+ struct kgsl_snapshot_object *obj, struct snapshot_obj_itr *itr)
{
- unsigned char headers[GPU_OBJ_HEADER_SZ];
- struct kgsl_snapshot_section_header *sect =
- (struct kgsl_snapshot_section_header *) headers;
- struct kgsl_snapshot_gpu_object *header =
- (struct kgsl_snapshot_gpu_object *) (headers + sizeof(*sect));
- int ret = 0;
+ struct kgsl_snapshot_section_header sect;
+ struct kgsl_snapshot_gpu_object header;
+ int ret;
- /* Construct a local copy of the headers */
+ sect.magic = SNAPSHOT_SECTION_MAGIC;
+ sect.id = KGSL_SNAPSHOT_SECTION_GPU_OBJECT;
- sect->magic = SNAPSHOT_SECTION_MAGIC;
- sect->id = KGSL_SNAPSHOT_SECTION_GPU_OBJECT;
- sect->size = GPU_OBJ_SECTION_SIZE(obj);
+ /*
+ * Header size is in dwords, object size is in bytes -
+ * round up if the object size isn't dword aligned
+ */
- header->type = obj->type;
+ sect.size = GPU_OBJ_HEADER_SZ + ALIGN(obj->size, 4);
- /* Header size is in dwords, object size is in bytes */
- header->size = obj->size >> 2;
- header->gpuaddr = obj->gpuaddr;
- header->ptbase = obj->ptbase;
+ ret = obj_itr_out(itr, §, sizeof(sect));
+ if (ret == 0)
+ return 0;
- /* Copy out any part of the header block that is needed */
+ header.size = ALIGN(obj->size, 4) >> 2;
+ header.gpuaddr = obj->gpuaddr;
+ header.ptbase = obj->ptbase;
+ header.type = obj->type;
- if (off < GPU_OBJ_HEADER_SZ) {
- int size = count < GPU_OBJ_HEADER_SZ - off ?
- count : GPU_OBJ_HEADER_SZ - off;
+ ret = obj_itr_out(itr, &header, sizeof(header));
+ if (ret == 0)
+ return 0;
- memcpy(buf, headers + off, size);
+ ret = obj_itr_out(itr, obj->entry->memdesc.hostptr + obj->offset,
+ obj->size);
+ if (ret == 0)
+ return 0;
- count -= size;
- ret += size;
- }
+ /* Pad the end to a dword boundary if we need to */
- /* Now copy whatever part of the data is needed */
-
- if (off < (GPU_OBJ_HEADER_SZ + obj->size)) {
- int offset;
- int size = count < obj->size ? count : obj->size;
-
- /*
- * If the desired gpuaddr isn't at the beginning of the region,
- * then offset the source pointer
- */
-
- offset = obj->offset;
-
- /*
- * Then adjust it to account for the offset for the output
- * buffer.
- */
-
- if (off > GPU_OBJ_HEADER_SZ) {
- int loff = (off - GPU_OBJ_HEADER_SZ);
-
- /* Adjust the size so we don't walk off the end */
-
- if ((loff + size) > obj->size)
- size = obj->size - loff;
-
- offset += loff;
- }
-
- memcpy(buf + ret, obj->entry->memdesc.hostptr + offset, size);
- ret += size;
+ if (obj->size % 4) {
+ unsigned int dummy = 0;
+ ret = obj_itr_out(itr, &dummy, obj->size % 4);
}
return ret;
@@ -539,7 +559,9 @@
{
struct kgsl_device *device = kobj_to_device(kobj);
struct kgsl_snapshot_object *obj, *tmp;
- unsigned int size, src, dst = 0;
+ struct kgsl_snapshot_section_header head;
+ struct snapshot_obj_itr itr;
+ int ret;
if (device == NULL)
return 0;
@@ -551,80 +573,46 @@
/* Get the mutex to keep things from changing while we are dumping */
mutex_lock(&device->mutex);
- if (off < device->snapshot_size) {
- size = count < (device->snapshot_size - off) ?
- count : device->snapshot_size - off;
+ obj_itr_init(&itr, buf, off, count);
- memcpy(buf, device->snapshot + off, size);
+ ret = obj_itr_out(&itr, device->snapshot, device->snapshot_size);
- count -= size;
- dst += size;
- }
-
- if (count == 0)
+ if (ret == 0)
goto done;
- src = device->snapshot_size;
+ list_for_each_entry(obj, &device->snapshot_obj_list, node)
+ kgsl_snapshot_dump_object(device, obj, &itr);
- list_for_each_entry(obj, &device->snapshot_obj_list, node) {
+ {
+ head.magic = SNAPSHOT_SECTION_MAGIC;
+ head.id = KGSL_SNAPSHOT_SECTION_END;
+ head.size = sizeof(head);
- int objsize = GPU_OBJ_SECTION_SIZE(obj);
- int offset;
-
- /* If the offset is beyond this object, then move on */
-
- if (off >= (src + objsize)) {
- src += objsize;
- continue;
- }
-
- /* Adjust the offset to be relative to the object */
- offset = (off >= src) ? (off - src) : 0;
-
- size = kgsl_snapshot_dump_object(device, obj, buf + dst,
- offset, count);
-
- count -= size;
- dst += size;
-
- if (count == 0)
- goto done;
-
- /* Move on to the next object - update src accordingly */
- src += objsize;
+ obj_itr_out(&itr, &head, sizeof(head));
}
- /* Add the end section */
+ /*
+ * Make sure everything has been written out before destroying things.
+ * The best way to confirm this is to go all the way through without
+ * writing any bytes - so only release if we get this far and
+ * itr->write is 0
+ */
- if (off < (src + sizeof(struct kgsl_snapshot_section_header))) {
- if (count >= sizeof(struct kgsl_snapshot_section_header)) {
- struct kgsl_snapshot_section_header *head =
- (void *) (buf + dst);
+ if (itr.write == 0) {
+ list_for_each_entry_safe(obj, tmp, &device->snapshot_obj_list,
+ node)
+ kgsl_snapshot_put_object(device, obj);
- head->magic = SNAPSHOT_SECTION_MAGIC;
- head->id = KGSL_SNAPSHOT_SECTION_END;
- head->size = sizeof(*head);
+ if (device->snapshot_frozen)
+ KGSL_DRV_ERR(device, "Snapshot objects released\n");
- dst += sizeof(*head);
- } else {
- goto done;
- }
+ device->snapshot_frozen = 0;
}
- /* Release the buffers and unfreeze the snapshot */
-
- list_for_each_entry_safe(obj, tmp, &device->snapshot_obj_list, node)
- kgsl_snapshot_put_object(device, obj);
-
- if (device->snapshot_frozen)
- KGSL_DRV_ERR(device, "Snapshot objects released\n");
-
- device->snapshot_frozen = 0;
-
done:
mutex_unlock(&device->mutex);
- return dst;
+ return itr.write;
}
/* Show the timestamp of the last collected snapshot */