Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 1 | /** |
Jon Medhurst | b1d0744 | 2015-05-08 12:04:18 +0100 | [diff] [blame] | 2 | * Copyright (C) ARM Limited 2010-2015. All rights reserved. |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License version 2 as |
| 6 | * published by the Free Software Foundation. |
| 7 | * |
| 8 | */ |
| 9 | |
| 10 | static void marshal_frame(int cpu, int buftype) |
| 11 | { |
| 12 | int frame; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 13 | bool write_cpu; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 14 | |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 15 | if (!per_cpu(gator_buffer, cpu)[buftype]) |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 16 | return; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 17 | |
| 18 | switch (buftype) { |
| 19 | case SUMMARY_BUF: |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 20 | write_cpu = false; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 21 | frame = FRAME_SUMMARY; |
| 22 | break; |
| 23 | case BACKTRACE_BUF: |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 24 | write_cpu = true; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 25 | frame = FRAME_BACKTRACE; |
| 26 | break; |
| 27 | case NAME_BUF: |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 28 | write_cpu = true; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 29 | frame = FRAME_NAME; |
| 30 | break; |
| 31 | case COUNTER_BUF: |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 32 | write_cpu = false; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 33 | frame = FRAME_COUNTER; |
| 34 | break; |
| 35 | case BLOCK_COUNTER_BUF: |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 36 | write_cpu = true; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 37 | frame = FRAME_BLOCK_COUNTER; |
| 38 | break; |
| 39 | case ANNOTATE_BUF: |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 40 | write_cpu = false; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 41 | frame = FRAME_ANNOTATE; |
| 42 | break; |
| 43 | case SCHED_TRACE_BUF: |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 44 | write_cpu = true; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 45 | frame = FRAME_SCHED_TRACE; |
| 46 | break; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 47 | case IDLE_BUF: |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 48 | write_cpu = false; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 49 | frame = FRAME_IDLE; |
| 50 | break; |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 51 | case ACTIVITY_BUF: |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 52 | write_cpu = false; |
Jon Medhurst | e31266f | 2014-08-04 15:47:44 +0100 | [diff] [blame] | 53 | frame = FRAME_ACTIVITY; |
| 54 | break; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 55 | default: |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 56 | write_cpu = false; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 57 | frame = -1; |
| 58 | break; |
| 59 | } |
| 60 | |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 61 | /* add response type */ |
| 62 | if (gator_response_type > 0) |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 63 | gator_buffer_write_packed_int(cpu, buftype, gator_response_type); |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 64 | |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 65 | /* leave space for 4-byte unpacked length */ |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 66 | per_cpu(gator_buffer_write, cpu)[buftype] = (per_cpu(gator_buffer_write, cpu)[buftype] + sizeof(s32)) & gator_buffer_mask[buftype]; |
| 67 | |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 68 | /* add frame type and core number */ |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 69 | gator_buffer_write_packed_int(cpu, buftype, frame); |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 70 | if (write_cpu) |
| 71 | gator_buffer_write_packed_int(cpu, buftype, cpu); |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 72 | } |
| 73 | |
| 74 | static int buffer_bytes_available(int cpu, int buftype) |
| 75 | { |
| 76 | int remaining, filled; |
| 77 | |
| 78 | filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_read, cpu)[buftype]; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 79 | if (filled < 0) |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 80 | filled += gator_buffer_size[buftype]; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 81 | |
| 82 | remaining = gator_buffer_size[buftype] - filled; |
| 83 | |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 84 | if (per_cpu(buffer_space_available, cpu)[buftype]) |
| 85 | /* Give some extra room; also allows space to insert the overflow error packet */ |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 86 | remaining -= 200; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 87 | else |
| 88 | /* Hysteresis, prevents multiple overflow messages */ |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 89 | remaining -= 2000; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 90 | |
| 91 | return remaining; |
| 92 | } |
| 93 | |
| 94 | static bool buffer_check_space(int cpu, int buftype, int bytes) |
| 95 | { |
| 96 | int remaining = buffer_bytes_available(cpu, buftype); |
| 97 | |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 98 | if (remaining < bytes) |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 99 | per_cpu(buffer_space_available, cpu)[buftype] = false; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 100 | else |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 101 | per_cpu(buffer_space_available, cpu)[buftype] = true; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 102 | |
| 103 | return per_cpu(buffer_space_available, cpu)[buftype]; |
| 104 | } |
| 105 | |
| 106 | static int contiguous_space_available(int cpu, int buftype) |
| 107 | { |
| 108 | int remaining = buffer_bytes_available(cpu, buftype); |
| 109 | int contiguous = gator_buffer_size[buftype] - per_cpu(gator_buffer_write, cpu)[buftype]; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 110 | |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 111 | if (remaining < contiguous) |
| 112 | return remaining; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 113 | return contiguous; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 114 | } |
| 115 | |
| 116 | static void gator_commit_buffer(int cpu, int buftype, u64 time) |
| 117 | { |
| 118 | int type_length, commit, length, byte; |
| 119 | unsigned long flags; |
| 120 | |
| 121 | if (!per_cpu(gator_buffer, cpu)[buftype]) |
| 122 | return; |
| 123 | |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 124 | /* post-populate the length, which does not include the response type length nor the length itself, i.e. only the length of the payload */ |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 125 | local_irq_save(flags); |
| 126 | type_length = gator_response_type ? 1 : 0; |
| 127 | commit = per_cpu(gator_buffer_commit, cpu)[buftype]; |
| 128 | length = per_cpu(gator_buffer_write, cpu)[buftype] - commit; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 129 | if (length < 0) |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 130 | length += gator_buffer_size[buftype]; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 131 | length = length - type_length - sizeof(s32); |
| 132 | |
| 133 | if (length <= FRAME_HEADER_SIZE) { |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 134 | /* Nothing to write, only the frame header is present */ |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 135 | local_irq_restore(flags); |
| 136 | return; |
| 137 | } |
| 138 | |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 139 | for (byte = 0; byte < sizeof(s32); byte++) |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 140 | per_cpu(gator_buffer, cpu)[buftype][(commit + type_length + byte) & gator_buffer_mask[buftype]] = (length >> byte * 8) & 0xFF; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 141 | |
| 142 | per_cpu(gator_buffer_commit, cpu)[buftype] = per_cpu(gator_buffer_write, cpu)[buftype]; |
| 143 | |
| 144 | if (gator_live_rate > 0) { |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 145 | while (time > per_cpu(gator_buffer_commit_time, cpu)) |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 146 | per_cpu(gator_buffer_commit_time, cpu) += gator_live_rate; |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 147 | } |
| 148 | |
| 149 | marshal_frame(cpu, buftype); |
| 150 | local_irq_restore(flags); |
| 151 | |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 152 | /* had to delay scheduling work as attempting to schedule work during the context switch is illegal in kernel versions 3.5 and greater */ |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 153 | if (per_cpu(in_scheduler_context, cpu)) { |
| 154 | #ifndef CONFIG_PREEMPT_RT_FULL |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 155 | /* mod_timer can not be used in interrupt context in RT-Preempt full */ |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 156 | mod_timer(&gator_buffer_wake_up_timer, jiffies + 1); |
| 157 | #endif |
| 158 | } else { |
| 159 | up(&gator_buffer_wake_sem); |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | static void buffer_check(int cpu, int buftype, u64 time) |
| 164 | { |
| 165 | int filled = per_cpu(gator_buffer_write, cpu)[buftype] - per_cpu(gator_buffer_commit, cpu)[buftype]; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 166 | |
| 167 | if (filled < 0) |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 168 | filled += gator_buffer_size[buftype]; |
Jon Medhurst | 96b5615 | 2014-10-30 18:01:15 +0000 | [diff] [blame] | 169 | if (filled >= ((gator_buffer_size[buftype] * 3) / 4)) |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 170 | gator_commit_buffer(cpu, buftype, time); |
Jon Medhurst | 15ce78d | 2014-04-10 09:02:02 +0100 | [diff] [blame] | 171 | } |