1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <unistd.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <stdint.h> 38 #include <signal.h> 39 #include <errno.h> 40 #include <string.h> 41 #include <sys/types.h> 42 #include <sys/epoll.h> 43 #include <sys/queue.h> 44 45 #include <rte_log.h> 46 #include <rte_memory.h> 47 #include <rte_malloc.h> 48 #include <rte_atomic.h> 49 50 51 #include "channel_monitor.h" 52 #include "channel_commands.h" 53 #include "channel_manager.h" 54 #include "power_manager.h" 55 56 #define RTE_LOGTYPE_CHANNEL_MONITOR RTE_LOGTYPE_USER1 57 58 #define MAX_EVENTS 256 59 60 61 static volatile unsigned run_loop = 1; 62 static int global_event_fd; 63 static struct epoll_event *global_events_list; 64 65 void channel_monitor_exit(void) 66 { 67 run_loop = 0; 68 rte_free(global_events_list); 69 } 70 71 static int 72 process_request(struct channel_packet *pkt, struct channel_info *chan_info) 73 { 74 uint64_t core_mask; 75 76 if (chan_info == NULL) 77 return -1; 78 79 if (rte_atomic32_cmpset(&(chan_info->status), CHANNEL_MGR_CHANNEL_CONNECTED, 80 CHANNEL_MGR_CHANNEL_PROCESSING) == 0) 81 return -1; 82 83 if (pkt->command == CPU_POWER) { 84 core_mask = get_pcpus_mask(chan_info, pkt->resource_id); 85 if (core_mask == 0) { 86 RTE_LOG(ERR, CHANNEL_MONITOR, "Error get physical CPU mask for " 87 "channel '%s' using vCPU(%u)\n", chan_info->channel_path, 88 (unsigned)pkt->unit); 89 return -1; 90 } 91 if (__builtin_popcountll(core_mask) == 1) { 92 93 unsigned core_num = __builtin_ffsll(core_mask) - 1; 94 95 switch (pkt->unit) { 96 case(CPU_POWER_SCALE_MIN): 97 power_manager_scale_core_min(core_num); 98 break; 99 case(CPU_POWER_SCALE_MAX): 100 power_manager_scale_core_max(core_num); 101 break; 102 case(CPU_POWER_SCALE_DOWN): 103 power_manager_scale_core_down(core_num); 104 break; 105 case(CPU_POWER_SCALE_UP): 106 power_manager_scale_core_up(core_num); 107 break; 108 case(CPU_POWER_ENABLE_TURBO): 109 power_manager_enable_turbo_core(core_num); 110 break; 111 case(CPU_POWER_DISABLE_TURBO): 112 power_manager_disable_turbo_core(core_num); 113 break; 114 default: 115 break; 116 } 117 } else { 118 switch (pkt->unit) { 119 case(CPU_POWER_SCALE_MIN): 120 power_manager_scale_mask_min(core_mask); 121 break; 122 case(CPU_POWER_SCALE_MAX): 123 power_manager_scale_mask_max(core_mask); 124 break; 125 case(CPU_POWER_SCALE_DOWN): 126 power_manager_scale_mask_down(core_mask); 127 break; 128 case(CPU_POWER_SCALE_UP): 129 power_manager_scale_mask_up(core_mask); 130 break; 131 case(CPU_POWER_ENABLE_TURBO): 132 power_manager_enable_turbo_mask(core_mask); 133 break; 134 case(CPU_POWER_DISABLE_TURBO): 135 power_manager_disable_turbo_mask(core_mask); 136 break; 137 default: 138 break; 139 } 140 141 } 142 } 143 /* Return is not checked as channel status may have been set to DISABLED 144 * from management thread 145 */ 146 rte_atomic32_cmpset(&(chan_info->status), CHANNEL_MGR_CHANNEL_PROCESSING, 147 CHANNEL_MGR_CHANNEL_CONNECTED); 148 return 0; 149 150 } 151 152 int 153 add_channel_to_monitor(struct channel_info **chan_info) 154 { 155 struct channel_info *info = *chan_info; 156 struct epoll_event event; 157 158 event.events = EPOLLIN; 159 event.data.ptr = info; 160 if (epoll_ctl(global_event_fd, EPOLL_CTL_ADD, info->fd, &event) < 0) { 161 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to add channel '%s' " 162 "to epoll\n", info->channel_path); 163 return -1; 164 } 165 return 0; 166 } 167 168 int 169 remove_channel_from_monitor(struct channel_info *chan_info) 170 { 171 if (epoll_ctl(global_event_fd, EPOLL_CTL_DEL, chan_info->fd, NULL) < 0) { 172 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to remove channel '%s' " 173 "from epoll\n", chan_info->channel_path); 174 return -1; 175 } 176 return 0; 177 } 178 179 int 180 channel_monitor_init(void) 181 { 182 global_event_fd = epoll_create1(0); 183 if (global_event_fd == 0) { 184 RTE_LOG(ERR, CHANNEL_MONITOR, "Error creating epoll context with " 185 "error %s\n", strerror(errno)); 186 return -1; 187 } 188 global_events_list = rte_malloc("epoll_events", sizeof(*global_events_list) 189 * MAX_EVENTS, RTE_CACHE_LINE_SIZE); 190 if (global_events_list == NULL) { 191 RTE_LOG(ERR, CHANNEL_MONITOR, "Unable to rte_malloc for " 192 "epoll events\n"); 193 return -1; 194 } 195 return 0; 196 } 197 198 void 199 run_channel_monitor(void) 200 { 201 while (run_loop) { 202 int n_events, i; 203 204 n_events = epoll_wait(global_event_fd, global_events_list, 205 MAX_EVENTS, 1); 206 if (!run_loop) 207 break; 208 for (i = 0; i < n_events; i++) { 209 struct channel_info *chan_info = (struct channel_info *) 210 global_events_list[i].data.ptr; 211 if ((global_events_list[i].events & EPOLLERR) || 212 (global_events_list[i].events & EPOLLHUP)) { 213 RTE_LOG(DEBUG, CHANNEL_MONITOR, "Remote closed connection for " 214 "channel '%s'\n", chan_info->channel_path); 215 remove_channel(&chan_info); 216 continue; 217 } 218 if (global_events_list[i].events & EPOLLIN) { 219 220 int n_bytes, err = 0; 221 struct channel_packet pkt; 222 void *buffer = &pkt; 223 int buffer_len = sizeof(pkt); 224 225 while (buffer_len > 0) { 226 n_bytes = read(chan_info->fd, buffer, buffer_len); 227 if (n_bytes == buffer_len) 228 break; 229 if (n_bytes == -1) { 230 err = errno; 231 RTE_LOG(DEBUG, CHANNEL_MONITOR, "Received error on " 232 "channel '%s' read: %s\n", 233 chan_info->channel_path, strerror(err)); 234 remove_channel(&chan_info); 235 break; 236 } 237 buffer = (char *)buffer + n_bytes; 238 buffer_len -= n_bytes; 239 } 240 if (!err) 241 process_request(&pkt, chan_info); 242 } 243 } 244 } 245 } 246