1/*- 2 * Copyright (c) 2001 Wind River Systems, Inc. 3 * All rights reserved. 4 * Written by: John Baldwin <jhb@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 4. Neither the name of the author nor the names of any co-contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD: releng/10.3/sys/sys/pcpu.h 290741 2015-11-13 02:16:08Z markj $ 31 */ 32 33#ifndef _SYS_PCPU_H_ 34#define _SYS_PCPU_H_ 35 36#ifdef LOCORE 37#error "no assembler-serviceable parts inside" 38#endif 39 40#include <sys/_cpuset.h> 41#include <sys/_lock.h> 42#include <sys/_mutex.h> 43#include <sys/_sx.h> 44#include <sys/queue.h> 45#include <sys/_rmlock.h> 46#include <sys/vmmeter.h> 47#include <sys/resource.h> 48#include <machine/pcpu.h> 49 50#define DPCPU_SETNAME "set_pcpu" 51#define DPCPU_SYMPREFIX "pcpu_entry_" 52 53#ifdef _KERNEL 54 55/* 56 * Define a set for pcpu data. 57 */ 58extern uintptr_t *__start_set_pcpu; 59__GLOBL(__start_set_pcpu); 60extern uintptr_t *__stop_set_pcpu; 61__GLOBL(__stop_set_pcpu); 62 63/* 64 * Array of dynamic pcpu base offsets. Indexed by id. 65 */ 66extern uintptr_t dpcpu_off[]; 67 68/* 69 * Convenience defines. 70 */ 71#define DPCPU_START ((uintptr_t)&__start_set_pcpu) 72#define DPCPU_STOP ((uintptr_t)&__stop_set_pcpu) 73#define DPCPU_BYTES (DPCPU_STOP - DPCPU_START) 74#define DPCPU_MODMIN 2048 75#define DPCPU_SIZE roundup2(DPCPU_BYTES, PAGE_SIZE) 76#define DPCPU_MODSIZE (DPCPU_SIZE - (DPCPU_BYTES - DPCPU_MODMIN)) 77 78/* 79 * Declaration and definition. 80 */ 81#define DPCPU_NAME(n) pcpu_entry_##n 82#define DPCPU_DECLARE(t, n) extern t DPCPU_NAME(n) 83#define DPCPU_DEFINE(t, n) t DPCPU_NAME(n) __section(DPCPU_SETNAME) __used 84 85/* 86 * Accessors with a given base. 87 */ 88#define _DPCPU_PTR(b, n) \ 89 (__typeof(DPCPU_NAME(n))*)((b) + (uintptr_t)&DPCPU_NAME(n)) 90#define _DPCPU_GET(b, n) (*_DPCPU_PTR(b, n)) 91#define _DPCPU_SET(b, n, v) (*_DPCPU_PTR(b, n) = v) 92 93/* 94 * Accessors for the current cpu. 95 */ 96#define DPCPU_PTR(n) _DPCPU_PTR(PCPU_GET(dynamic), n) 97#define DPCPU_GET(n) (*DPCPU_PTR(n)) 98#define DPCPU_SET(n, v) (*DPCPU_PTR(n) = v) 99 100/* 101 * Accessors for remote cpus. 102 */ 103#define DPCPU_ID_PTR(i, n) _DPCPU_PTR(dpcpu_off[(i)], n) 104#define DPCPU_ID_GET(i, n) (*DPCPU_ID_PTR(i, n)) 105#define DPCPU_ID_SET(i, n, v) (*DPCPU_ID_PTR(i, n) = v) 106 107/* 108 * Utility macros. 109 */ 110#define DPCPU_SUM(n) __extension__ \ 111({ \ 112 u_int _i; \ 113 __typeof(*DPCPU_PTR(n)) sum; \ 114 \ 115 sum = 0; \ 116 CPU_FOREACH(_i) { \ 117 sum += *DPCPU_ID_PTR(_i, n); \ 118 } \ 119 sum; \ 120}) 121 122#define DPCPU_VARSUM(n, var) __extension__ \ 123({ \ 124 u_int _i; \ 125 __typeof((DPCPU_PTR(n))->var) sum; \ 126 \ 127 sum = 0; \ 128 CPU_FOREACH(_i) { \ 129 sum += (DPCPU_ID_PTR(_i, n))->var; \ 130 } \ 131 sum; \ 132}) 133 134#define DPCPU_ZERO(n) do { \ 135 u_int _i; \ 136 \ 137 CPU_FOREACH(_i) { \ 138 bzero(DPCPU_ID_PTR(_i, n), sizeof(*DPCPU_PTR(n))); \ 139 } \ 140} while(0) 141 142#endif /* _KERNEL */ 143 144/* 145 * This structure maps out the global data that needs to be kept on a 146 * per-cpu basis. The members are accessed via the PCPU_GET/SET/PTR 147 * macros defined in <machine/pcpu.h>. Machine dependent fields are 148 * defined in the PCPU_MD_FIELDS macro defined in <machine/pcpu.h>. 149 */ 150struct pcpu { 151 struct thread *pc_curthread; /* Current thread */ 152 struct thread *pc_idlethread; /* Idle thread */ 153 struct thread *pc_fpcurthread; /* Fp state owner */ 154 struct thread *pc_deadthread; /* Zombie thread or NULL */ 155 struct pcb *pc_curpcb; /* Current pcb */ 156 uint64_t pc_switchtime; /* cpu_ticks() at last csw */ 157 int pc_switchticks; /* `ticks' at last csw */ 158 u_int pc_cpuid; /* This cpu number */ 159 STAILQ_ENTRY(pcpu) pc_allcpu; 160 struct lock_list_entry *pc_spinlocks; 161 struct vmmeter pc_cnt; /* VM stats counters */ 162 long pc_cp_time[CPUSTATES]; /* statclock ticks */ 163 struct device *pc_device; 164 void *pc_netisr; /* netisr SWI cookie */ 165 int pc_unused1; /* unused field */ 166 int pc_domain; /* Memory domain. */ 167 struct rm_queue pc_rm_queue; /* rmlock list of trackers */ 168 uintptr_t pc_dynamic; /* Dynamic per-cpu data area */ 169 170 /* 171 * Keep MD fields last, so that CPU-specific variations on a 172 * single architecture don't result in offset variations of 173 * the machine-independent fields of the pcpu. Even though 174 * the pcpu structure is private to the kernel, some ports 175 * (e.g., lsof, part of gtop) define _KERNEL and include this 176 * header. While strictly speaking this is wrong, there's no 177 * reason not to keep the offsets of the MI fields constant 178 * if only to make kernel debugging easier. 179 */ 180 PCPU_MD_FIELDS; 181} __aligned(CACHE_LINE_SIZE); 182 183#ifdef CTASSERT 184/* 185 * To minimize memory waste in per-cpu UMA zones, size of struct pcpu 186 * should be denominator of PAGE_SIZE. 187 */ 188CTASSERT((PAGE_SIZE / sizeof(struct pcpu)) * sizeof(struct pcpu) == PAGE_SIZE); 189#endif 190 191#ifdef _KERNEL 192 193STAILQ_HEAD(cpuhead, pcpu); 194 195extern struct cpuhead cpuhead; 196extern struct pcpu *cpuid_to_pcpu[]; 197 198#define curcpu PCPU_GET(cpuid) 199#define curproc (curthread->td_proc) 200#ifndef curthread 201#define curthread PCPU_GET(curthread) 202#endif 203#define curvidata PCPU_GET(vidata) 204 205/* Accessor to elements allocated via UMA_ZONE_PCPU zone. */ 206static inline void * 207zpcpu_get(void *base) 208{ 209 210 return ((char *)(base) + sizeof(struct pcpu) * curcpu); 211} 212 213static inline void * 214zpcpu_get_cpu(void *base, int cpu) 215{ 216 217 return ((char *)(base) + sizeof(struct pcpu) * cpu); 218} 219 220/* 221 * Machine dependent callouts. cpu_pcpu_init() is responsible for 222 * initializing machine dependent fields of struct pcpu, and 223 * db_show_mdpcpu() is responsible for handling machine dependent 224 * fields for the DDB 'show pcpu' command. 225 */ 226void cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t size); 227void db_show_mdpcpu(struct pcpu *pcpu); 228 229void *dpcpu_alloc(int size); 230void dpcpu_copy(void *s, int size); 231void dpcpu_free(void *s, int size); 232void dpcpu_init(void *dpcpu, int cpuid); 233void pcpu_destroy(struct pcpu *pcpu); 234struct pcpu *pcpu_find(u_int cpuid); 235void pcpu_init(struct pcpu *pcpu, int cpuid, size_t size); 236 237#endif /* _KERNEL */ 238 239#endif /* !_SYS_PCPU_H_ */ 240